Merge pull request #171 from hummingbot/development

sync / Dashboard development -> main
This commit is contained in:
nikspz
2024-08-28 22:47:04 +07:00
committed by GitHub
108 changed files with 696 additions and 117030 deletions

View File

@@ -1,47 +1,80 @@
name: Build and Push Docker image
name: Dashboard Docker Buildx Workflow
on:
pull_request:
types: [closed]
branches:
- main
- development
release:
types: [published, edited]
jobs:
build:
build_pr:
if: github.event_name == 'pull_request' && github.event.pull_request.merged == true
runs-on: ubuntu-latest
if: github.event.pull_request.merged == true
steps:
- name: Checkout code
uses: actions/checkout@v3.5.3
uses: actions/checkout@v4.1.1
- name: Set up QEMU
uses: docker/setup-qemu-action@v2.2.0
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2.9.1
with:
version: latest
uses: docker/setup-buildx-action@v3.1.0
- name: Login to DockerHub
uses: docker/login-action@v2.2.0
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Build and push
id: docker_build
uses: docker/build-push-action@v4.1.1
- name: Build and push Development Image
if: github.base_ref == 'development'
uses: docker/build-push-action@v5
with:
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: hummingbot/dashboard:development
- name: Build and push Latest Image
if: github.base_ref == 'main'
uses: docker/build-push-action@v5
with:
context: .
file: ./Dockerfile
platforms: linux/amd64,linux/arm64
push: true
tags: hummingbot/dashboard:latest
platforms: linux/amd64,linux/arm64
build-args: |
BRANCH=${{ github.ref }}
COMMIT=${{ github.sha }}
BUILD_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ')
cache-from: type=registry,ref=hummingbot/dashboard:latest
cache-to: type=inline
- name: Image digest
run: echo ${{ steps.docker_build.outputs.digest }}
build_release:
if: github.event_name == 'release'
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4.1.1
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3.1.0
- name: Login to DockerHub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Extract tag name
id: get_tag
run: echo ::set-output name=VERSION::${GITHUB_REF#refs/tags/}
- name: Build and push
uses: docker/build-push-action@v5
with:
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: hummingbot/dashboard:${{ steps.get_tag.outputs.VERSION }}

33
.pre-commit-config.yaml Normal file
View File

@@ -0,0 +1,33 @@
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v2.3.0
hooks:
- id: detect-private-key
- repo: https://github.com/pre-commit/mirrors-eslint
rev: v8.10.0
hooks:
- id: eslint
files: \.[jt]sx?$ # *.js, *.jsx, *.ts and *.tsx
types: [file]
- repo: https://github.com/CoinAlpha/git-hooks
rev: 78f0683233a09c68a072fd52740d32c0376d4f0f
hooks:
- id: detect-wallet-private-key
types: [file]
exclude: .json
- repo: https://github.com/pycqa/isort
rev: 5.12.0
hooks:
- id: isort
files: "\\.(py)$"
args: [--settings-path=pyproject.toml]
- repo: https://github.com/pycqa/flake8
rev: 3.9.2
hooks:
- id: flake8
additional_dependencies: ['flake8']
args: [--max-line-length=130]

View File

@@ -2,12 +2,11 @@ import os
from dotenv import load_dotenv
load_dotenv()
MINER_COINS = ["Algorand", "Avalanche", "DAO Maker", "Faith Tribe", "Fear", "Frontier",
"Harmony", "Hot Cross", "HUMAN Protocol", "Oddz", "Shera", "Firo",
"Vesper Finance", "Youclout", "Nimiq"]
"Harmony", "Hot Cross", "HUMAN Protocol", "Oddz", "Shera", "Firo",
"Vesper Finance", "Youclout", "Nimiq"]
MINER_EXCHANGES = ["Binance", "FTX", "Coinbase Exchange", "Huobi Global", "OKX", "KuCoin",
"Kraken", "Bybit (Spot)", "FTX.US", "Crypto.com Exchange", "Binance US",
"MEXC Global", "Gate.io", "BitMart", "Bitfinex", "AscendEX (BitMax)",
@@ -18,7 +17,7 @@ DEFAULT_MINER_COINS = ["Avalanche"]
CERTIFIED_EXCHANGES = ["ascendex", "binance", "bybit", "gate.io", "hitbtc", "huobi", "kucoin", "okx", "gateway"]
CERTIFIED_STRATEGIES = ["xemm", "cross exchange market making", "pmm", "pure market making"]
AUTH_SYSTEM_ENABLED = False
AUTH_SYSTEM_ENABLED = os.getenv("AUTH_SYSTEM_ENABLED", "False").lower() in ("true", "1", "t")
BACKEND_API_HOST = os.getenv("BACKEND_API_HOST", "127.0.0.1")
BACKEND_API_PORT = os.getenv("BACKEND_API_PORT", 8000)

View File

@@ -1,19 +1,49 @@
.ONESHELL:
.SHELLFLAGS := -c
.PHONY: run
.PHONY: uninstall
.PHONY: install
.PHONY: install-pre-commit
.PHONY: docker_build
.PHONY: docker_run
detect_conda_bin := $(shell bash -c 'if [ "${CONDA_EXE} " == " " ]; then \
CONDA_EXE=$$((find /opt/conda/bin/conda || find ~/anaconda3/bin/conda || \
find /usr/local/anaconda3/bin/conda || find ~/miniconda3/bin/conda || \
find /root/miniconda/bin/conda || find ~/Anaconda3/Scripts/conda || \
find $$CONDA/bin/conda) 2>/dev/null); fi; \
if [ "${CONDA_EXE}_" == "_" ]; then \
echo "Please install Anaconda w/ Python 3.10+ first"; \
echo "See: https://www.anaconda.com/distribution/"; \
exit 1; fi; \
echo $$(dirname $${CONDA_EXE})')
CONDA_BIN := $(detect_conda_bin)
run:
streamlit run main.py
streamlit run main.py --server.headless true
uninstall:
conda env remove -n dashboard
install:
conda env create -f environment_conda.yml
if conda env list | grep -q '^dashboard '; then \
echo "Environment already exists."; \
else \
conda env create -f environment_conda.yml; \
fi
$(MAKE) install-pre-commit
install-pre-commit:
/bin/bash -c 'source "${CONDA_BIN}/activate" dashboard && \
if ! conda list pre-commit | grep pre-commit &> /dev/null; then \
pip install pre-commit; \
fi && pre-commit install'
docker_build:
docker build -t hummingbot/dashboard:latest .
docker_run:
docker run -p 8501:8501 dashboard:latest
docker run -p 8501:8501 hummingbot/dashboard:latest

View File

@@ -1,4 +1,4 @@
from typing import Optional, Dict
from typing import Dict, Optional
import pandas as pd
import requests
@@ -115,7 +115,8 @@ class BackendAPIClient:
def stop_bot(self, bot_name: str, skip_order_cancellation: bool = False, async_backend: bool = True):
"""Stop a Hummingbot bot."""
endpoint = "stop-bot"
return self.post(endpoint, payload={"bot_name": bot_name, "skip_order_cancellation": skip_order_cancellation, "async_backend": async_backend})
return self.post(endpoint, payload={"bot_name": bot_name, "skip_order_cancellation": skip_order_cancellation,
"async_backend": async_backend})
def import_strategy(self, strategy_config: dict):
"""Import a trading strategy to a bot."""

View File

@@ -1,8 +1,8 @@
import re
import time
from pycoingecko import CoinGeckoAPI
import pandas as pd
import re
from pycoingecko import CoinGeckoAPI
class CoinGeckoClient:

View File

@@ -1,6 +1,6 @@
import pandas as pd
import requests
from glom import *
from glom import glom
class MinerClient:

View File

@@ -1,5 +1,5 @@
import os
import json
import os
from typing import Optional
import pandas as pd
@@ -102,18 +102,6 @@ class OptunaDBManager:
except Exception as e:
return f"Error: {str(e)}"
@property
def trial_system_attributes(self):
return self._get_trial_system_attributes_table()
def _get_trial_system_attributes_table(self):
try:
with self.session_maker() as session:
df = pd.read_sql_query(text("SELECT * FROM trial_system_attributes"), session.connection())
return df
except Exception as e:
return f"Error: {str(e)}"
@property
def version_info(self):
return self._get_version_info_table()

View File

@@ -1,14 +1,19 @@
import glob
import subprocess
import importlib.util
import inspect
import os
import subprocess
import pandas as pd
import yaml
from hummingbot.strategy_v2.controllers.directional_trading_controller_base import DirectionalTradingControllerBase, DirectionalTradingControllerConfigBase
from hummingbot.strategy_v2.controllers.market_making_controller_base import MarketMakingControllerBase, MarketMakingControllerConfigBase
from hummingbot.strategy_v2.controllers.directional_trading_controller_base import (
DirectionalTradingControllerBase,
DirectionalTradingControllerConfigBase,
)
from hummingbot.strategy_v2.controllers.market_making_controller_base import (
MarketMakingControllerBase,
MarketMakingControllerConfigBase,
)
def remove_files_from_directory(directory: str):

View File

@@ -1,13 +1,14 @@
cookie:
expiry_days: 30
key: random_signature_key
name: random_cookie_name
credentials:
usernames:
admin:
email: admin@gmail.com
name: Admin User
password: abc # To be replaced with hashed password: hashed_passwords = stauth.Hasher(['abc', 'def']).generate()
preauthorized: # the preferred way to add users since there is no need for manual hashing of passwords
logged_in: False
password: abc
cookie:
expiry_days: 0
key: some_signature_key # Must be string
name: some_cookie_name
pre-authorized:
emails:
- admin@admin.com

View File

@@ -27,3 +27,6 @@ dependencies:
- streamlit-elements==0.1.*
- streamlit-authenticator
- pydantic==1.10.4
- flake8
- isort
- pre-commit

View File

@@ -1,6 +1,7 @@
import streamlit as st
from datetime import datetime, timedelta
import streamlit as st
def backtesting_section(inputs, backend_api_client):
st.write("### Backtesting")
@@ -13,7 +14,8 @@ def backtesting_section(inputs, backend_api_client):
end_date = st.date_input("End Date", default_end_time,
help="End date is inclusive, make sure that you are not including the current date.")
with c3:
backtesting_resolution = st.selectbox("Backtesting Resolution", options=["1m", "3m", "5m", "15m", "30m", "1h", "1s"], index=0)
backtesting_resolution = st.selectbox("Backtesting Resolution",
options=["1m", "3m", "5m", "15m", "30m", "1h", "1s"], index=0)
with c4:
trade_cost = st.number_input("Trade Cost (%)", min_value=0.0, value=0.06, step=0.01, format="%.2f")
with c5:
@@ -24,8 +26,8 @@ def backtesting_section(inputs, backend_api_client):
end_datetime = datetime.combine(end_date, datetime.max.time())
try:
backtesting_results = backend_api_client.run_backtesting(
start_time=int(start_datetime.timestamp()) * 1000,
end_time=int(end_datetime.timestamp()) * 1000,
start_time=int(start_datetime.timestamp()),
end_time=int(end_datetime.timestamp()),
backtesting_resolution=backtesting_resolution,
trade_cost=trade_cost / 100,
config=inputs,
@@ -33,7 +35,6 @@ def backtesting_section(inputs, backend_api_client):
except Exception as e:
st.error(e)
return None
if len(backtesting_results["processed_data"]) == 0:
st.error("No trades were executed during the backtesting period.")
return None

View File

@@ -1,10 +1,7 @@
import pandas as pd
import streamlit as st
from hummingbot.strategy_v2.models.executors import CloseType
from streamlit_elements import mui
from frontend.components.dashboard import Dashboard
from frontend.st_utils import get_backend_api_client
TRADES_TO_SHOW = 5
@@ -31,10 +28,12 @@ class BotPerformanceCardV2(Dashboard.Item):
{"field": 'connector', "headerName": 'Connector', "width": SMALL_COL_WIDTH, "editable": False},
{"field": 'trading_pair', "headerName": 'Trading Pair', "width": SMALL_COL_WIDTH, "editable": False},
{"field": 'realized_pnl_quote', "headerName": 'Realized PNL ($)', "width": MEDIUM_COL_WIDTH, "editable": False},
{"field": 'unrealized_pnl_quote', "headerName": 'Unrealized PNL ($)', "width": MEDIUM_COL_WIDTH, "editable": False},
{"field": 'unrealized_pnl_quote', "headerName": 'Unrealized PNL ($)', "width": MEDIUM_COL_WIDTH,
"editable": False},
{"field": 'global_pnl_quote', "headerName": 'NET PNL ($)', "width": MEDIUM_COL_WIDTH, "editable": False},
{"field": 'volume_traded', "headerName": 'Volume ($)', "width": SMALL_COL_WIDTH, "editable": False},
{"field": 'open_order_volume', "headerName": 'Liquidity Placed ($)', "width": MEDIUM_COL_WIDTH, "editable": False},
{"field": 'open_order_volume', "headerName": 'Liquidity Placed ($)', "width": MEDIUM_COL_WIDTH,
"editable": False},
{"field": 'imbalance', "headerName": 'Imbalance ($)', "width": SMALL_COL_WIDTH, "editable": False},
{"field": 'close_types', "headerName": 'Close Types', "width": ULTRA_WIDE_COL_WIDTH, "editable": False}
]
@@ -88,7 +87,9 @@ class BotPerformanceCardV2(Dashboard.Item):
subheader="Not Available",
avatar=mui.Avatar("🤖", sx={"bgcolor": "red"}),
className=self._draggable_class)
mui.Alert(f"An error occurred while fetching bot status of the bot {bot_name}. Please check the bot client.", severity="error")
mui.Alert(
f"An error occurred while fetching bot status of the bot {bot_name}. Please check the bot client.",
severity="error")
else:
bot_data = bot_status.get("data")
is_running = bot_data.get("status") == "running"
@@ -103,7 +104,8 @@ class BotPerformanceCardV2(Dashboard.Item):
{"id": controller, "error": inner_dict.get("error")})
continue
controller_performance = inner_dict.get("performance")
controller_config = next((config for config in controller_configs if config.get("id") == controller), {})
controller_config = next(
(config for config in controller_configs if config.get("id") == controller), {})
controller_name = controller_config.get("controller_name", controller)
connector_name = controller_config.get("connector_name", "NaN")
trading_pair = controller_config.get("trading_pair", "NaN")
@@ -159,7 +161,9 @@ class BotPerformanceCardV2(Dashboard.Item):
title=bot_name,
subheader=status,
avatar=mui.Avatar("🤖", sx={"bgcolor": color}),
action=mui.IconButton(mui.icon.Stop, onClick=lambda: stop_bot(bot_name)) if is_running else mui.IconButton(mui.icon.Archive, onClick=lambda: archive_bot(bot_name)),
action=mui.IconButton(mui.icon.Stop,
onClick=lambda: stop_bot(bot_name)) if is_running else mui.IconButton(
mui.icon.Archive, onClick=lambda: archive_bot(bot_name)),
className=self._draggable_class)
if is_running:
with mui.CardContent(sx={"flex": 1}):
@@ -171,7 +175,8 @@ class BotPerformanceCardV2(Dashboard.Item):
elevation=1):
with self.title_bar(padding="10px 15px 10px 15px", dark_switcher=False):
mui.Typography("🏦 NET PNL", variant="h6")
mui.Typography(f"$ {total_global_pnl_quote:.3f}", variant="h6", sx={"padding": "10px 15px 10px 15px"})
mui.Typography(f"$ {total_global_pnl_quote:.3f}", variant="h6",
sx={"padding": "10px 15px 10px 15px"})
with mui.Grid(item=True, xs=2):
with mui.Paper(key=self._key,
sx={"display": "flex", "flexDirection": "column", "borderRadius": 3,
@@ -179,7 +184,8 @@ class BotPerformanceCardV2(Dashboard.Item):
elevation=1):
with self.title_bar(padding="10px 15px 10px 15px", dark_switcher=False):
mui.Typography("📊 NET PNL (%)", variant="h6")
mui.Typography(f"{total_global_pnl_pct:.3%}", variant="h6", sx={"padding": "10px 15px 10px 15px"})
mui.Typography(f"{total_global_pnl_pct:.3%}", variant="h6",
sx={"padding": "10px 15px 10px 15px"})
with mui.Grid(item=True, xs=2):
with mui.Paper(key=self._key,
sx={"display": "flex", "flexDirection": "column", "borderRadius": 3,
@@ -187,7 +193,8 @@ class BotPerformanceCardV2(Dashboard.Item):
elevation=1):
with self.title_bar(padding="10px 15px 10px 15px", dark_switcher=False):
mui.Typography("💸 Volume Traded", variant="h6")
mui.Typography(f"$ {total_volume_traded:.2f}", variant="h6", sx={"padding": "10px 15px 10px 15px"})
mui.Typography(f"$ {total_volume_traded:.2f}", variant="h6",
sx={"padding": "10px 15px 10px 15px"})
with mui.Grid(item=True, xs=2):
with mui.Paper(key=self._key,
sx={"display": "flex", "flexDirection": "column", "borderRadius": 3,
@@ -195,7 +202,8 @@ class BotPerformanceCardV2(Dashboard.Item):
elevation=1):
with self.title_bar(padding="10px 15px 10px 15px", dark_switcher=False):
mui.Typography("📖 Liquidity Placed", variant="h6")
mui.Typography(f"$ {total_open_order_volume:.2f}", variant="h6", sx={"padding": "10px 15px 10px 15px"})
mui.Typography(f"$ {total_open_order_volume:.2f}", variant="h6",
sx={"padding": "10px 15px 10px 15px"})
with mui.Grid(item=True, xs=2):
with mui.Paper(key=self._key,
sx={"display": "flex", "flexDirection": "column", "borderRadius": 3,
@@ -203,7 +211,8 @@ class BotPerformanceCardV2(Dashboard.Item):
elevation=1):
with self.title_bar(padding="10px 15px 10px 15px", dark_switcher=False):
mui.Typography("💹 Unrealized PNL", variant="h6")
mui.Typography(f"$ {total_unrealized_pnl_quote:.2f}", variant="h6", sx={"padding": "10px 15px 10px 15px"})
mui.Typography(f"$ {total_unrealized_pnl_quote:.2f}", variant="h6",
sx={"padding": "10px 15px 10px 15px"})
with mui.Grid(item=True, xs=2):
with mui.Paper(key=self._key,
sx={"display": "flex", "flexDirection": "column", "borderRadius": 3,
@@ -211,7 +220,8 @@ class BotPerformanceCardV2(Dashboard.Item):
elevation=1):
with self.title_bar(padding="10px 15px 10px 15px", dark_switcher=False):
mui.Typography("📊 Imbalance", variant="h6")
mui.Typography(f"$ {total_imbalance:.2f}", variant="h6", sx={"padding": "10px 15px 10px 15px"})
mui.Typography(f"$ {total_imbalance:.2f}", variant="h6",
sx={"padding": "10px 15px 10px 15px"})
with mui.Grid(container=True, spacing=1, sx={"padding": "10px 15px 10px 15px"}):
with mui.Grid(item=True, xs=11):
@@ -242,7 +252,8 @@ class BotPerformanceCardV2(Dashboard.Item):
with mui.Grid(container=True, spacing=1, sx={"padding": "10px 15px 10px 15px"}):
with mui.Grid(item=True, xs=11):
with mui.Paper(key=self._key,
sx={"display": "flex", "flexDirection": "column", "borderRadius": 3,
sx={"display": "flex", "flexDirection": "column",
"borderRadius": 3,
"overflow": "hidden"},
elevation=1):
with self.title_bar(padding="10px 15px 10px 15px", dark_switcher=False):
@@ -268,7 +279,8 @@ class BotPerformanceCardV2(Dashboard.Item):
with mui.Grid(container=True, spacing=1, sx={"padding": "10px 15px 10px 15px"}):
with mui.Grid(item=True, xs=11):
with mui.Paper(key=self._key,
sx={"display": "flex", "flexDirection": "column", "borderRadius": 3,
sx={"display": "flex", "flexDirection": "column",
"borderRadius": 3,
"overflow": "hidden"},
elevation=1):
with self.title_bar(padding="10px 15px 10px 15px", dark_switcher=False):
@@ -326,5 +338,6 @@ class BotPerformanceCardV2(Dashboard.Item):
action=mui.IconButton(mui.icon.Stop, onClick=lambda: stop_bot(bot_name)),
className=self._draggable_class)
with mui.CardContent(sx={"flex": 1}):
mui.Typography("An error occurred while fetching bot status.", sx={"padding": "10px 15px 10px 15px"})
mui.Typography(str(e), sx={"padding": "10px 15px 10px 15px"})
mui.Typography("An error occurred while fetching bot status.",
sx={"padding": "10px 15px 10px 15px"})
mui.Typography(str(e), sx={"padding": "10px 15px 10px 15px"})

View File

@@ -1,8 +1,12 @@
from streamlit_elements import mui
import constants
from backend.utils.os_utils import get_directories_from_directory, get_python_files_from_directory, \
get_yml_files_from_directory, get_log_files_from_directory
from backend.utils.os_utils import (
get_directories_from_directory,
get_log_files_from_directory,
get_python_files_from_directory,
get_yml_files_from_directory,
)
from frontend.components.file_explorer_base import FileExplorerBase

View File

@@ -1,9 +1,9 @@
from streamlit_elements import mui
from frontend.components.dashboard import Dashboard
class Card(Dashboard.Item):
DEFAULT_CONTENT = (
"This impressive paella is a perfect party dish and a fun meal to cook "
"together with your guests. Add 1 cup of frozen peas along with the mussels, "
@@ -11,7 +11,9 @@ class Card(Dashboard.Item):
)
def __call__(self, content):
with mui.Card(key=self._key, sx={"display": "flex", "flexDirection": "column", "borderRadius": 3, "overflow": "hidden"}, elevation=1):
with mui.Card(key=self._key,
sx={"display": "flex", "flexDirection": "column", "borderRadius": 3, "overflow": "hidden"},
elevation=1):
mui.CardHeader(
title="Shrimp and Chorizo Paella",
subheader="September 14, 2016",

View File

@@ -23,9 +23,8 @@ def get_default_config_loader(controller_name: str):
configs = [config for config in all_configs if config["controller_name"] == controller_name]
if len(configs) > 0:
default_config = st.selectbox("Select a config", [config["id"] for config in configs])
st.session_state["default_config"] = next((config for config in all_configs if config["id"] == default_config), None)
st.session_state["default_config"] = next(
(config for config in all_configs if config["id"] == default_config), None)
st.session_state["default_config"]["id"] = st.session_state["default_config"]["id"].split("_")[0]
else:
st.warning("No existing configs found for this controller.")

View File

@@ -11,11 +11,13 @@ class ControllersFileExplorer(FileExplorerBase):
onNodeSelect=lambda event, node_id: self.set_selected_file(event, node_id),
defaultExpanded=["directional_strategies"]):
available_controllers = load_controllers(constants.CONTROLLERS_PATH)
with mui.lab.TreeItem(nodeId="directional_strategies", label=f"Directional Strategies"):
with mui.lab.TreeItem(nodeId="directional_strategies", label="Directional Strategies"):
for controller in available_controllers:
if available_controllers[controller]["type"] == "directional_trading":
mui.lab.TreeItem(nodeId=constants.CONTROLLERS_PATH + "/" + controller + ".py", label=f"🐍{controller}")
with mui.lab.TreeItem(nodeId="market_making_strategies", label=f"🪙Market Making Strategies"):
mui.lab.TreeItem(nodeId=constants.CONTROLLERS_PATH + "/" + controller + ".py",
label=f"🐍{controller}")
with mui.lab.TreeItem(nodeId="market_making_strategies", label="🪙Market Making Strategies"):
for controller in available_controllers:
if available_controllers[controller]["type"] == "market_making":
mui.lab.TreeItem(nodeId=constants.CONTROLLERS_PATH + "/" + controller + ".py", label=f"🐍{controller}")
mui.lab.TreeItem(nodeId=constants.CONTROLLERS_PATH + "/" + controller + ".py",
label=f"🐍{controller}")

View File

@@ -1,11 +1,11 @@
from uuid import uuid4
from abc import ABC, abstractmethod
from streamlit_elements import dashboard, mui
from contextlib import contextmanager
from uuid import uuid4
from streamlit_elements import dashboard, mui
class Dashboard:
DRAGGABLE_CLASS = "draggable"
def __init__(self):
@@ -36,15 +36,15 @@ class Dashboard:
@contextmanager
def title_bar(self, padding="5px 15px 5px 15px", dark_switcher=True):
with mui.Stack(
className=self._draggable_class,
alignItems="center",
direction="row",
spacing=1,
sx={
"padding": padding,
"borderBottom": 1,
"borderColor": "divider",
},
className=self._draggable_class,
alignItems="center",
direction="row",
spacing=1,
sx={
"padding": padding,
"borderBottom": 1,
"borderColor": "divider",
},
):
yield

View File

@@ -1,6 +1,7 @@
import json
from streamlit_elements import mui
from .dashboard import Dashboard

View File

@@ -1,6 +1,6 @@
import streamlit as st
from frontend.components.st_inputs import get_distribution, normalize, distribution_inputs
from frontend.components.st_inputs import distribution_inputs, get_distribution, normalize
def get_dca_distribution_inputs():
@@ -28,11 +28,13 @@ def get_dca_distribution_inputs():
dca_amounts = dca_amounts[:buy_order_levels]
col_spreads, col_amounts = st.columns(2)
with col_spreads:
buy_spread_dist_type, buy_spread_start, buy_spread_base, buy_spread_scaling, buy_spread_step, buy_spread_ratio, buy_manual_spreads = distribution_inputs(
col_spreads, "Spread", buy_order_levels, dca_spreads)
buy_spread_dist_type, buy_spread_start, buy_spread_base, buy_spread_scaling, buy_spread_step, \
buy_spread_ratio, buy_manual_spreads = distribution_inputs(col_spreads,
"Spread", buy_order_levels, dca_spreads)
with col_amounts:
buy_amount_dist_type, buy_amount_start, buy_amount_base, buy_amount_scaling, buy_amount_step, buy_amount_ratio, buy_manual_amounts = distribution_inputs(
col_amounts, "Amount", buy_order_levels, dca_amounts)
buy_amount_dist_type, buy_amount_start, buy_amount_base, buy_amount_scaling, buy_amount_step, \
buy_amount_ratio, buy_manual_amounts = distribution_inputs(col_amounts, "Amount",
buy_order_levels, dca_amounts)
# Generate distributions
spread_distributions = get_distribution(buy_spread_dist_type, buy_order_levels, buy_spread_start,
@@ -63,7 +65,8 @@ def get_dca_distribution_inputs():
step=0.1,
help="Enter the tr ailing stop activation price as a percentage (e.g., 1.0 for 1%).") / 100
# with c5:
ts_delta = st.number_input("Trailing Stop Delta (%)", min_value=0.0, max_value=100.0, value=ts_delta, step=0.1,
ts_delta = st.number_input("Trailing Stop Delta (%)", min_value=0.0, max_value=100.0, value=ts_delta,
step=0.1,
help="Enter the trailing stop delta as a percentage (e.g., 0.3 for 0.3%).") / 100
return {

View File

@@ -1,9 +1,8 @@
import time
import streamlit as st
import pandas as pd
from CONFIG import BACKEND_API_HOST, BACKEND_API_PORT
from backend.services.backend_api_client import BackendAPIClient
import pandas as pd
import streamlit as st
from frontend.st_utils import get_backend_api_client
@@ -93,7 +92,8 @@ class LaunchV2WithControllers:
edited_df = st.data_editor(df, hide_index=True)
self._controller_config_selected = [f"{config}.yml" for config in edited_df[edited_df["selected"]]["id"].tolist()]
self._controller_config_selected = [f"{config}.yml" for config in
edited_df[edited_df["selected"]]["id"].tolist()]
st.write(self._controller_config_selected)
c1, c2, c3, c4 = st.columns([1, 1, 1, 0.3])
with c1:
@@ -108,4 +108,4 @@ class LaunchV2WithControllers:
with c4:
deploy_button = st.button("Deploy Bot")
if deploy_button:
self.launch_new_bot()
self.launch_new_bot()

View File

@@ -22,7 +22,8 @@ def get_directional_trading_general_inputs():
connector_name = st.text_input("Connector", value=connector_name,
help="Enter the name of the exchange to trade on (e.g., binance_perpetual).")
candles_connector_name = st.text_input("Candles Connector", value=candles_connector_name,
help="Enter the name of the exchange to get candles from (e.g., binance_perpetual).")
help="Enter the name of the exchange to get candles from"
" (e.g., binance_perpetual).")
with c2:
trading_pair = st.text_input("Trading Pair", value=trading_pair,
help="Enter the trading pair to trade on (e.g., WLD-USDT).")
@@ -30,19 +31,22 @@ def get_directional_trading_general_inputs():
help="Enter the trading pair to get candles for (e.g., WLD-USDT).")
with c3:
leverage = st.number_input("Leverage", value=leverage,
help="Set the leverage to use for trading (e.g., 20 for 20x leverage). Set it to 1 for spot trading.")
interval = st.selectbox("Candles Interval", ("1m", "3m", "5m", "15m", "1h", "4h", "1d"), index=interval_index,
help="Set the leverage to use for trading (e.g., 20 for 20x leverage)."
"Set it to 1 for spot trading.")
interval = st.selectbox("Candles Interval", ("1m", "3m", "5m", "15m", "1h", "4h", "1d"),
index=interval_index,
help="Enter the interval for candles (e.g., 1m).")
with c4:
total_amount_quote = st.number_input("Total amount of quote", value=total_amount_quote,
help="Enter the total amount in quote asset to use for trading (e.g., 1000).")
with c5:
max_executors_per_side = st.number_input("Max Executors Per Side", value=max_executors_per_side,
help="Enter the maximum number of executors per side (e.g., 5).")
help="Enter the maximum number of executors per side (e.g., 5).")
with c6:
cooldown_time = st.number_input("Cooldown Time (minutes)", value=cooldown_time,
help="Time between accepting a new signal in minutes (e.g., 60).") * 60
with c7:
position_mode = st.selectbox("Position Mode", ("HEDGE", "ONEWAY"), index=position_mode,
help="Enter the position mode (HEDGE/ONEWAY).")
return connector_name, trading_pair, leverage, total_amount_quote, max_executors_per_side, cooldown_time, position_mode, candles_connector_name, candles_trading_pair, interval
return connector_name, trading_pair, leverage, total_amount_quote, max_executors_per_side, cooldown_time, \
position_mode, candles_connector_name, candles_trading_pair, interval

View File

@@ -1,8 +1,10 @@
from functools import partial
import streamlit as st
from streamlit_elements import mui, editor, sync, lazy, event
from streamlit_elements import editor, event, lazy, mui, sync
from backend.utils.os_utils import save_file
from .dashboard import Dashboard
@@ -37,7 +39,7 @@ class Editor(Dashboard.Item):
@property
def tabs(self):
return self._tabs
def update_content(self, label, content):
self._tabs[label]["content"] = content
@@ -54,7 +56,9 @@ class Editor(Dashboard.Item):
return self._tabs[label]["content"]
def __call__(self):
with mui.Paper(key=self._key, sx={"display": "flex", "flexDirection": "column", "borderRadius": 3, "overflow": "hidden"}, elevation=1):
with mui.Paper(key=self._key,
sx={"display": "flex", "flexDirection": "column", "borderRadius": 3, "overflow": "hidden"},
elevation=1):
with self.title_bar("0px 15px 0px 15px"):
with mui.Grid(container=True, spacing=4, sx={"display": "flex", "alignItems": "center"}):

View File

@@ -1,5 +1,6 @@
import streamlit as st
from frontend.components.st_inputs import get_distribution, normalize, distribution_inputs
from frontend.components.st_inputs import distribution_inputs, get_distribution, normalize
def get_executors_distribution_inputs(use_custom_spread_units=False):
@@ -40,17 +41,21 @@ def get_executors_distribution_inputs(use_custom_spread_units=False):
sell_amounts_pct = sell_amounts_pct[:sell_order_levels]
col_buy_spreads, col_buy_amounts, col_sell_spreads, col_sell_amounts = st.columns(4)
with col_buy_spreads:
buy_spread_dist_type, buy_spread_start, buy_spread_base, buy_spread_scaling, buy_spread_step, buy_spread_ratio, buy_manual_spreads = distribution_inputs(
col_buy_spreads, "Spread", buy_order_levels, buy_spreads)
buy_spread_dist_type, buy_spread_start, buy_spread_base, buy_spread_scaling, buy_spread_step, \
buy_spread_ratio, buy_manual_spreads = distribution_inputs(col_buy_spreads,
"Spread", buy_order_levels, buy_spreads)
with col_buy_amounts:
buy_amount_dist_type, buy_amount_start, buy_amount_base, buy_amount_scaling, buy_amount_step, buy_amount_ratio, buy_manual_amounts = distribution_inputs(
col_buy_amounts, "Amount", buy_order_levels, buy_amounts_pct)
buy_amount_dist_type, buy_amount_start, buy_amount_base, buy_amount_scaling, buy_amount_step, \
buy_amount_ratio, buy_manual_amounts = distribution_inputs(col_buy_amounts,
"Amount", buy_order_levels, buy_amounts_pct)
with col_sell_spreads:
sell_spread_dist_type, sell_spread_start, sell_spread_base, sell_spread_scaling, sell_spread_step, sell_spread_ratio, sell_manual_spreads = distribution_inputs(
col_sell_spreads, "Spread", sell_order_levels, sell_spreads)
sell_spread_dist_type, sell_spread_start, sell_spread_base, sell_spread_scaling, sell_spread_step, \
sell_spread_ratio, sell_manual_spreads = distribution_inputs(col_sell_spreads,
"Spread", sell_order_levels, sell_spreads)
with col_sell_amounts:
sell_amount_dist_type, sell_amount_start, sell_amount_base, sell_amount_scaling, sell_amount_step, sell_amount_ratio, sell_manual_amounts = distribution_inputs(
col_sell_amounts, "Amount", sell_order_levels, sell_amounts_pct)
sell_amount_dist_type, sell_amount_start, sell_amount_base, sell_amount_scaling, sell_amount_step, \
sell_amount_ratio, sell_manual_amounts = distribution_inputs(col_sell_amounts, "Amount",
sell_order_levels, sell_amounts_pct)
# Generate distributions
buy_spread_distributions = get_distribution(buy_spread_dist_type, buy_order_levels, buy_spread_start,
@@ -60,10 +65,13 @@ def get_executors_distribution_inputs(use_custom_spread_units=False):
sell_spread_base, sell_spread_scaling, sell_spread_step,
sell_spread_ratio, sell_manual_spreads)
buy_amount_distributions = get_distribution(buy_amount_dist_type, buy_order_levels, buy_amount_start, buy_amount_base, buy_amount_scaling,
buy_amount_step, buy_amount_ratio, buy_manual_amounts)
sell_amount_distributions = get_distribution(sell_amount_dist_type, sell_order_levels, sell_amount_start, sell_amount_base,
sell_amount_scaling, sell_amount_step, sell_amount_ratio, sell_manual_amounts)
buy_amount_distributions = get_distribution(buy_amount_dist_type, buy_order_levels, buy_amount_start,
buy_amount_base, buy_amount_scaling,
buy_amount_step, buy_amount_ratio, buy_manual_amounts)
sell_amount_distributions = get_distribution(sell_amount_dist_type, sell_order_levels, sell_amount_start,
sell_amount_base,
sell_amount_scaling, sell_amount_step, sell_amount_ratio,
sell_manual_amounts)
# Normalize and calculate order amounts
all_orders_amount_normalized = normalize(buy_amount_distributions + sell_amount_distributions)

View File

@@ -1,44 +0,0 @@
from docker_manager import DockerManager
from streamlit_elements import mui
from frontend.components.dashboard import Dashboard
from backend.utils import os_utils
class ExitedBotCard(Dashboard.Item):
def __init__(self, board, x, y, w, h, **item_props):
super().__init__(board, x, y, w, h, **item_props)
@staticmethod
def remove_container(bot_name):
DockerManager().remove_container(bot_name)
os_utils.remove_directory(f"./hummingbot_files/bot_configs/{bot_name}")
def __call__(self, bot_name: str):
with mui.Card(key=self._key,
sx={"display": "flex", "flexDirection": "column", "borderRadius": 2, "overflow": "auto"},
elevation=2):
mui.CardHeader(
title=bot_name,
subheader="Stopped",
avatar=mui.Avatar("💀", sx={"bgcolor": "black"}),
className=self._draggable_class,
)
with mui.CardActions():
with mui.Grid(container=True, spacing=2):
with mui.Grid(item=True, xs=6):
with mui.Button(onClick=lambda: DockerManager().start_container(bot_name),
variant="outlined",
color="success",
sx={"width": "100%"}):
mui.icon.PlayCircle()
mui.Typography("Start Instance")
with mui.Grid(item=True, xs=6):
with mui.Button(onClick=lambda: self.remove_container(bot_name),
variant="outlined",
color="error",
sx={"width": "100%"}):
mui.icon.DeleteForever()
mui.Typography("Delete Instance")

View File

@@ -1,7 +1,8 @@
import streamlit as st
from streamlit_elements import mui
from backend.utils.os_utils import remove_file, load_file
from backend.utils.os_utils import load_file, remove_file
from .dashboard import Dashboard
@@ -61,4 +62,3 @@ class FileExplorerBase(Dashboard.Item):
mui.IconButton(mui.icon.Close, onClick=self.remove_file_from_tab, sx={"mx": 1})
with mui.Box(sx={"overflow": "auto"}):
self.add_tree_view()

View File

@@ -1,97 +0,0 @@
import os
import time
from docker_manager import DockerManager
import streamlit as st
from streamlit_elements import mui, lazy
import constants
from backend.utils.os_utils import get_directories_from_directory
from .dashboard import Dashboard
class LaunchBotCard(Dashboard.Item):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.is_master_bot_running = False
self._bot_name = None
self._image_name = "hummingbot/hummingbot:latest"
self._base_bot_config = "master_bot_conf"
def _set_bot_name(self, event):
self._bot_name = event.target.value
def _set_image_name(self, event):
self._image_name = event.target.value
def _set_base_bot_config(self, event):
self._base_bot_config = event.target.value
def launch_new_bot(self):
if self._bot_name and self._image_name:
bot_name = f"hummingbot-{self._bot_name}"
DockerManager().create_hummingbot_instance(instance_name=bot_name,
base_conf_folder=f"{constants.HUMMINGBOT_TEMPLATES}/{self._base_bot_config}/.",
target_conf_folder=f"{constants.BOTS_FOLDER}/{bot_name}/.",
controllers_folder=constants.CONTROLLERS_PATH,
controllers_config_folder=constants.CONTROLLERS_CONFIG_PATH,
image=self._image_name)
with st.spinner('Starting Master Configs instance... This process may take a few seconds'):
time.sleep(3)
else:
st.warning("You need to define the bot name and image in order to create one.")
def __call__(self):
active_containers = DockerManager.get_active_containers()
self.is_master_bot_running = "hummingbot-master_bot_conf" in active_containers
password_file_path = os.path.join(constants.HUMMINGBOT_TEMPLATES + "/master_bot_conf/conf",
'.password_verification')
is_master_password_set = os.path.isfile(password_file_path)
with mui.Paper(key=self._key,
sx={"display": "flex", "flexDirection": "column", "borderRadius": 3, "overflow": "hidden"},
elevation=1):
with self.title_bar(padding="10px 15px 10px 15px", dark_switcher=False):
mui.Typography("🚀 Create Instance", variant="h5")
with mui.Grid(container=True, spacing=2, sx={"padding": "10px 15px 10px 15px"}):
with mui.Grid(item=True, xs=8):
if not is_master_password_set:
base_warning = "You need to set a master password in order to use the dashboard."
if self.is_master_bot_running:
mui.Alert(f"{base_warning} The Master Configs instance is running."
f" Attach to it in Terminal to set the master password.", severity="success")
else:
mui.Alert(f"{base_warning} Master Configs instance isn't running. Start it and"
f" set the master password to continue.", severity="error")
else:
mui.Alert("The new instance will contain the credentials configured in the following base instance:",
severity="info")
with mui.Grid(item=True, xs=4):
master_configs = [conf.split("/")[-2] for conf in
get_directories_from_directory(constants.HUMMINGBOT_TEMPLATES) if
"bot_conf" in conf]
with mui.FormControl(variant="standard", sx={"width": "100%"}):
mui.FormHelperText("Base Configs")
with mui.Select(label="Base Configs", defaultValue=master_configs[0],
variant="standard", onChange=lazy(self._set_base_bot_config)):
for master_config in master_configs:
mui.MenuItem(master_config, value=master_config)
with mui.Grid(item=True, xs=4):
mui.TextField(label="Instance Name", variant="outlined", onChange=lazy(self._set_bot_name),
sx={"width": "100%"})
with mui.Grid(item=True, xs=4):
mui.TextField(label="Hummingbot Image",
defaultValue="hummingbot/hummingbot:latest",
variant="outlined",
placeholder="hummingbot-[name]",
onChange=lazy(self._set_image_name),
sx={"width": "100%"})
with mui.Grid(item=True, xs=4):
with mui.Button(onClick=self.launch_new_bot,
variant="outlined",
color="success",
sx={"width": "100%", "height": "100%"}):
mui.icon.AddCircleOutline()
mui.Typography("Create")

View File

@@ -1,54 +0,0 @@
import os
import time
from docker_manager import DockerManager
import streamlit as st
from streamlit_elements import mui, sync
import constants
from .dashboard import Dashboard
class LaunchBrokerCard(Dashboard.Item):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.is_broker_running = False
def manage_broker_container(self):
if self.is_broker_running:
DockerManager().stop_container("hummingbot-broker")
with st.spinner('Stopping Hummingbot Broker... This process may take a few seconds...'):
time.sleep(5)
else:
DockerManager().create_broker()
with st.spinner('Starting Hummingbot Broker... This process may take a few seconds...'):
time.sleep(20)
def __call__(self):
active_containers = DockerManager.get_active_containers()
self.is_broker_running = "hummingbot-broker" in active_containers
with mui.Paper(key=self._key,
sx={"display": "flex", "flexDirection": "column", "borderRadius": 3, "overflow": "hidden"},
elevation=1):
with self.title_bar(padding="10px 15px 10px 15px", dark_switcher=False):
mui.Typography("🐙 Manage Broker", variant="h5")
with mui.Grid(container=True, spacing=2, sx={"padding": "10px 15px 10px 15px"}):
with mui.Grid(item=True, xs=8):
if self.is_broker_running:
mui.Alert("Hummingbot Broker is running - control your bots now!", severity="success")
else:
mui.Alert("Hummingbot Broker is not running - start it to control your bots.",
severity="error")
with mui.Grid(item=True, xs=4):
button_text = "Stop" if self.is_broker_running else "Start"
color = "error" if self.is_broker_running else "success"
icon = mui.icon.Stop if self.is_broker_running else mui.icon.PlayCircle
with mui.Button(onClick=self.manage_broker_container,
color=color,
variant="outlined",
sx={"width": "100%", "height": "100%"}):
icon()
mui.Typography(button_text)

View File

@@ -1,81 +0,0 @@
import os
import time
from docker_manager import DockerManager
import streamlit as st
from streamlit_elements import mui
import constants
from .dashboard import Dashboard
class LaunchMasterBotCard(Dashboard.Item):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.is_master_bot_running = False
def manage_master_bot_container(self):
if self.is_master_bot_running:
DockerManager().stop_container("hummingbot-master_bot_conf")
with st.spinner('Stopping Master Configs instance... This process may take a few seconds.'):
time.sleep(5)
else:
DockerManager().remove_container("hummingbot-master_bot_conf")
time.sleep(2)
DockerManager().create_hummingbot_instance(instance_name="hummingbot-master_bot_conf",
base_conf_folder="hummingbot_files/templates/master_bot_conf/.",
target_conf_folder="hummingbot_files/templates/master_bot_conf/."
)
with st.spinner('Starting Master Configs instance... This process may take a few seconds.'):
time.sleep(3)
def __call__(self):
active_containers = DockerManager.get_active_containers()
self.is_master_bot_running = "hummingbot-master_bot_conf" in active_containers
password_file_path = os.path.join(constants.HUMMINGBOT_TEMPLATES + "/master_bot_conf/conf",
'.password_verification')
is_master_password_set = os.path.isfile(password_file_path)
with mui.Paper(key=self._key,
sx={"display": "flex", "flexDirection": "column", "borderRadius": 3, "overflow": "hidden"},
elevation=1):
with self.title_bar(padding="10px 15px 10px 15px", dark_switcher=False):
mui.icon.Key()
mui.Typography("Master Configs", variant="h6", sx={"marginLeft": 1})
with mui.Grid(container=True, spacing=2, sx={"padding": "10px 15px 10px 15px"}):
with mui.Grid(item=True, xs=8):
if not is_master_password_set:
base_warning = "You need to set a master password in order to use the dashboard."
if self.is_master_bot_running:
mui.Alert(f"{base_warning} The Master Configs instance is running."
f" Attach to it in Terminal to set the master password.", severity="success")
else:
mui.Alert(f"{base_warning} Master Configs instance isn't running. Start it and"
f" set the master password to continue.", severity="error")
else:
if self.is_master_bot_running:
mui.Alert("The Master Configs instance is running."
" Attach to it in Terminal to add credentials.",
severity="success",
sx={"margin": 2})
else:
mui.Alert("Master Configs instance isn't running. Start it to add credentials.",
severity="error")
with mui.Grid(item=True, xs=4):
button_text = "Stop" if self.is_master_bot_running else "Start"
color = "error" if self.is_master_bot_running else "success"
icon = mui.icon.Stop if self.is_master_bot_running else mui.icon.PlayCircle
with mui.Button(onClick=self.manage_master_bot_container,
color=color,
variant="outlined",
sx={"width": "100%", "height": "100%"}):
icon()
mui.Typography(button_text)
with mui.Grid(item=True, xs=8):
if self.is_master_bot_running:
mui.TextField(InputProps={"readOnly": True},
label="Attach to Master Configs instance",
value="docker attach hummingbot-master_bot_conf",
sx={"width": "100%"})

View File

@@ -1,12 +1,10 @@
import time
import streamlit as st
from streamlit_elements import mui, lazy
from streamlit_elements import lazy, mui
from CONFIG import BACKEND_API_HOST, BACKEND_API_PORT
from backend.services.backend_api_client import BackendAPIClient
from .dashboard import Dashboard
from ..st_utils import get_backend_api_client
from .dashboard import Dashboard
class LaunchStrategyV2(Dashboard.Item):
@@ -134,14 +132,14 @@ class LaunchStrategyV2(Dashboard.Item):
else:
config_base = config["id"]
version = "NaN"
ts_text = str(trailing_stop["activation_price"]) + " / " + str(trailing_stop["trailing_delta"])
data.append({
"id": config["id"], "config_base": config_base, "version": version,
"controller_name": config["controller_name"], "controller_type": config["controller_type"],
"connector_name": connector_name, "trading_pair": trading_pair,
"total_amount_quote": total_amount_quote, "max_loss_quote": total_amount_quote * stop_loss / 2,
"stop_loss": stop_loss, "take_profit": take_profit,
"trailing_stop": str(trailing_stop["activation_price"]) + " / " +
str(trailing_stop["trailing_delta"]),
"trailing_stop": ts_text,
"time_limit": time_limit})
with mui.Grid(item=True, xs=12):

View File

@@ -23,16 +23,19 @@ def get_market_making_general_inputs(custom_candles=False):
help="Enter the trading pair to trade on (e.g., WLD-USDT).")
with c3:
leverage = st.number_input("Leverage", value=leverage,
help="Set the leverage to use for trading (e.g., 20 for 20x leverage). Set it to 1 for spot trading.")
help="Set the leverage to use for trading (e.g., 20 for 20x leverage). "
"Set it to 1 for spot trading.")
with c4:
total_amount_quote = st.number_input("Total amount of quote", value=total_amount_quote,
help="Enter the total amount in quote asset to use for trading (e.g., 1000).")
help="Enter the total amount in quote asset to use for "
"trading (e.g., 1000).")
with c5:
position_mode = st.selectbox("Position Mode", ("HEDGE", "ONEWAY"), index=position_mode,
help="Enter the position mode (HEDGE/ONEWAY).")
with c6:
cooldown_time = st.number_input("Stop Loss Cooldown Time (minutes)", value=cooldown_time,
help="Specify the cooldown time in minutes after having a stop loss (e.g., 60).") * 60
help="Specify the cooldown time in minutes after having a"
"stop loss (e.g., 60).") * 60
with c7:
executor_refresh_time = st.number_input("Executor Refresh Time (minutes)", value=executor_refresh_time,
help="Enter the refresh time in minutes for executors (e.g., 60).") * 60
@@ -44,11 +47,13 @@ def get_market_making_general_inputs(custom_candles=False):
interval_index = intervals.index(interval)
with c1:
candles_connector = st.text_input("Candles Connector", value=candles_connector,
help="Enter the name of the exchange to get candles from (e.g., binance_perpetual).")
help="Enter the name of the exchange to get candles from"
"(e.g., binance_perpetual).")
with c2:
candles_trading_pair = st.text_input("Candles Trading Pair", value=candles_trading_pair,
help="Enter the trading pair to get candles for (e.g., WLD-USDT).")
help="Enter the trading pair to get candles for (e.g., WLD-USDT).")
with c3:
interval = st.selectbox("Candles Interval", intervals, index=interval_index,
help="Enter the interval for candles (e.g., 1m).")
return connector_name, trading_pair, leverage, total_amount_quote, position_mode, cooldown_time, executor_refresh_time, candles_connector, candles_trading_pair, interval
return connector_name, trading_pair, leverage, total_amount_quote, position_mode, cooldown_time, \
executor_refresh_time, candles_connector, candles_trading_pair, interval

View File

@@ -1,6 +1,8 @@
from streamlit_elements import media, mui, sync, lazy
from streamlit_elements import lazy, media, mui, sync
from .dashboard import Dashboard
class Player(Dashboard.Item):
def __init__(self, *args, **kwargs):
@@ -11,13 +13,17 @@ class Player(Dashboard.Item):
self._url = event.target.value
def __call__(self):
with mui.Paper(key=self._key, sx={"display": "flex", "flexDirection": "column", "borderRadius": 3, "overflow": "hidden"}, elevation=1):
with mui.Paper(key=self._key,
sx={"display": "flex", "flexDirection": "column", "borderRadius": 3, "overflow": "hidden"},
elevation=1):
with self.title_bar(padding="10px 15px 10px 15px", dark_switcher=False):
mui.icon.OndemandVideo()
mui.Typography("Media player")
with mui.Stack(direction="row", spacing=2, justifyContent="space-evenly", alignItems="center", sx={"padding": "10px"}):
mui.TextField(defaultValue=self._url, label="URL", variant="standard", sx={"flex": 0.97}, onChange=lazy(self._set_url))
with mui.Stack(direction="row", spacing=2, justifyContent="space-evenly", alignItems="center",
sx={"padding": "10px"}):
mui.TextField(defaultValue=self._url, label="URL", variant="standard", sx={"flex": 0.97},
onChange=lazy(self._set_url))
mui.IconButton(mui.icon.PlayCircleFilled, onClick=sync(), sx={"color": "primary.main"})
media.Player(self._url, controls=True, width="100%", height="100%")

View File

@@ -1,9 +1,11 @@
from streamlit_elements import mui, lazy
import datetime
from streamlit_elements import lazy, mui
import constants
from backend.utils.file_templates import strategy_optimization_template
from backend.utils.os_utils import load_controllers, save_file
from .dashboard import Dashboard
@@ -28,7 +30,8 @@ class OptimizationCreationCard(Dashboard.Item):
def __call__(self):
available_strategies = load_controllers(constants.CONTROLLERS_PATH)
strategy_names = [strategy for strategy, strategy_info in available_strategies.items() if strategy_info["type"] == "directional_trading"]
strategy_names = [strategy for strategy, strategy_info in available_strategies.items() if
strategy_info["type"] == "directional_trading"]
with mui.Paper(key=self._key,
sx={"display": "flex", "flexDirection": "column", "borderRadius": 3, "overflow": "hidden"},
elevation=1):

View File

@@ -1,10 +1,11 @@
import threading
import optuna
from streamlit_elements import mui, lazy
from streamlit_elements import lazy, mui
import constants
from backend.utils.os_utils import get_function_from_file, get_python_files_from_directory
from .dashboard import Dashboard
@@ -36,7 +37,9 @@ class OptimizationRunCard(Dashboard.Item):
def __call__(self):
optimizations = get_python_files_from_directory(constants.OPTIMIZATIONS_PATH)
with mui.Paper(key=self._key, sx={"display": "flex", "flexDirection": "column", "borderRadius": 3, "overflow": "hidden"}, elevation=1):
with mui.Paper(key=self._key,
sx={"display": "flex", "flexDirection": "column", "borderRadius": 3, "overflow": "hidden"},
elevation=1):
with self.title_bar(padding="10px 15px 10px 15px", dark_switcher=False):
mui.icon.AutoFixHigh()
mui.Typography("Run a optimization", variant="h6")
@@ -58,7 +61,7 @@ class OptimizationRunCard(Dashboard.Item):
with mui.Grid(item=True, xs=4):
with mui.FormControl(variant="standard", sx={"width": "100%"}):
mui.TextField(defaultValue=self._optimization_name, label="Number of trials", type="number",
variant="standard", onChange=lazy(self._set_number_of_trials))
variant="standard", onChange=lazy(self._set_number_of_trials))
with mui.Grid(item=True, xs=4):
with mui.Button(variant="contained", onClick=self._run_optimization, sx={"width": "100%"}):
mui.icon.PlayCircleFilled()

View File

@@ -29,7 +29,8 @@ def get_risk_management_inputs():
step=0.1,
help="Enter the tr ailing stop activation price as a percentage (e.g., 1.0 for 1%).") / 100
with c5:
ts_delta = st.number_input("Trailing Stop Delta (%)", min_value=0.0, max_value=100.0, value=ts_delta, step=0.1,
ts_delta = st.number_input("Trailing Stop Delta (%)", min_value=0.0, max_value=100.0, value=ts_delta,
step=0.1,
help="Enter the trailing stop delta as a percentage (e.g., 0.3 for 0.3%).") / 100
with c6:
take_profit_order_type = st.selectbox("Take Profit Order Type", (OrderType.LIMIT, OrderType.MARKET),

View File

@@ -1,7 +1,5 @@
import streamlit as st
from CONFIG import BACKEND_API_HOST, BACKEND_API_PORT
from backend.services.backend_api_client import BackendAPIClient
from frontend.st_utils import get_backend_api_client

View File

@@ -1,6 +1,6 @@
from _decimal import Decimal
from math import exp
from _decimal import Decimal
from hummingbot.strategy_v2.utils.distributions import Distributions
@@ -45,7 +45,7 @@ def distribution_inputs(column, dist_type_name, levels=3, default_values=None):
key=f"{column}_{dist_type_name.lower()}_ratio")
elif dist_type == "Linear":
step = column.number_input(f"{dist_type_name} End", value=1.0,
key=f"{column}_{dist_type_name.lower()}_end")
key=f"{column}_{dist_type_name.lower()}_end")
else:
if default_values:
manual_values = [column.number_input(f"{dist_type_name} for level {i + 1}", value=value * 100.0,
@@ -53,7 +53,8 @@ def distribution_inputs(column, dist_type_name, levels=3, default_values=None):
enumerate(default_values)]
else:
manual_values = [column.number_input(f"{dist_type_name} for level {i + 1}", value=i + 1.0,
key=f"{column}_{dist_type_name.lower()}_{i}") for i, value in range(levels)]
key=f"{column}_{dist_type_name.lower()}_{i}") for i, value in
range(levels)]
start = None # As start is not relevant for Manual type
return dist_type, start, base, scaling_factor, step, ratio, manual_values

View File

@@ -1,20 +1,20 @@
from hummingbot.core.data_type.common import PositionMode, TradeType, OrderType
import json
import os
from decimal import Decimal
import streamlit as st
from hummingbot.core.data_type.common import OrderType, PositionMode, TradeType
from hummingbot.data_feed.candles_feed.candles_factory import CandlesConfig
from hummingbot.strategy_v2.strategy_frameworks.data_types import OrderLevel, TripleBarrierConf
from hummingbot.strategy_v2.strategy_frameworks.directional_trading import DirectionalTradingBacktestingEngine
from hummingbot.strategy_v2.utils.config_encoder_decoder import ConfigEncoderDecoder
import constants
import os
import json
import streamlit as st
from decimal import Decimal
from backend.utils.optuna_database_manager import OptunaDBManager
from backend.utils.os_utils import load_controllers
from frontend.st_utils import initialize_st_page
from frontend.visualization.graphs import BacktestingGraphs
from frontend.visualization.strategy_analysis import StrategyAnalysis
from frontend.st_utils import initialize_st_page
initialize_st_page(title="Analyze", icon="🔬")
@@ -56,18 +56,26 @@ else:
filters_column, scatter_column = st.columns([1, 6])
with filters_column:
accuracy = st.slider("Accuracy", min_value=0.0, max_value=1.0, value=[0.4, 1.0], step=0.01)
net_profit = st.slider("Net PNL (%)", min_value=merged_df["net_pnl_pct"].min(), max_value=merged_df["net_pnl_pct"].max(),
net_profit = st.slider("Net PNL (%)", min_value=merged_df["net_pnl_pct"].min(),
max_value=merged_df["net_pnl_pct"].max(),
value=[merged_df["net_pnl_pct"].min(), merged_df["net_pnl_pct"].max()], step=0.01)
max_drawdown = st.slider("Max Drawdown (%)", min_value=merged_df["max_drawdown_pct"].min(), max_value=merged_df["max_drawdown_pct"].max(),
value=[merged_df["max_drawdown_pct"].min(), merged_df["max_drawdown_pct"].max()], step=0.01)
total_positions = st.slider("Total Positions", min_value=merged_df["total_positions"].min(), max_value=merged_df["total_positions"].max(),
value=[merged_df["total_positions"].min(), merged_df["total_positions"].max()], step=1)
max_drawdown = st.slider("Max Drawdown (%)", min_value=merged_df["max_drawdown_pct"].min(),
max_value=merged_df["max_drawdown_pct"].max(),
value=[merged_df["max_drawdown_pct"].min(), merged_df["max_drawdown_pct"].max()],
step=0.01)
total_positions = st.slider("Total Positions", min_value=merged_df["total_positions"].min(),
max_value=merged_df["total_positions"].max(),
value=[merged_df["total_positions"].min(), merged_df["total_positions"].max()],
step=1)
net_profit_filter = (merged_df["net_pnl_pct"] >= net_profit[0]) & (merged_df["net_pnl_pct"] <= net_profit[1])
accuracy_filter = (merged_df["accuracy"] >= accuracy[0]) & (merged_df["accuracy"] <= accuracy[1])
max_drawdown_filter = (merged_df["max_drawdown_pct"] >= max_drawdown[0]) & (merged_df["max_drawdown_pct"] <= max_drawdown[1])
total_positions_filter = (merged_df["total_positions"] >= total_positions[0]) & (merged_df["total_positions"] <= total_positions[1])
max_drawdown_filter = (merged_df["max_drawdown_pct"] >= max_drawdown[0]) & (
merged_df["max_drawdown_pct"] <= max_drawdown[1])
total_positions_filter = (merged_df["total_positions"] >= total_positions[0]) & (
merged_df["total_positions"] <= total_positions[1])
with scatter_column:
bt_graphs = BacktestingGraphs(merged_df[net_profit_filter & accuracy_filter & max_drawdown_filter & total_positions_filter])
bt_graphs = BacktestingGraphs(
merged_df[net_profit_filter & accuracy_filter & max_drawdown_filter & total_positions_filter])
# Show and compare all of the study trials
st.plotly_chart(bt_graphs.pnl_vs_maxdrawdown(), use_container_width=True)
# Get study trials
@@ -107,11 +115,11 @@ else:
# TODO: Add support for boolean fields in optimize tab
field_value = st.checkbox(field_name, value=field_value)
else:
raise ValueError(f"Field type {field_type} not supported")
raise ValueError("Field type {field_type} not supported")
else:
if field_name == "candles_config":
st.write("---")
st.write(f"## Candles Config:")
st.write("## Candles Config:")
candles = []
for i, candles_config in enumerate(field_value):
st.write(f"#### Candle {i}:")
@@ -130,7 +138,7 @@ else:
field_value = candles
elif field_name == "order_levels":
new_levels = []
st.write(f"## Order Levels:")
st.write("## Order Levels:")
for order_level in field_value:
st.write(f"### Level {order_level['level']} {order_level['side'].name}")
ol_c1, ol_c2 = st.columns([5, 1])
@@ -139,30 +147,38 @@ else:
c21, c22, c23, c24, c25 = st.columns(5)
triple_barrier_conf_level = order_level["triple_barrier_conf"]
with c21:
take_profit = st.number_input("Take profit", value=float(triple_barrier_conf_level["take_profit"]),
take_profit = st.number_input("Take profit",
value=float(triple_barrier_conf_level["take_profit"]),
key=f"{order_level['level']}_{order_level['side'].name}_tp")
with c22:
stop_loss = st.number_input("Stop Loss", value=float(triple_barrier_conf_level["stop_loss"]),
stop_loss = st.number_input("Stop Loss",
value=float(triple_barrier_conf_level["stop_loss"]),
key=f"{order_level['level']}_{order_level['side'].name}_sl")
with c23:
time_limit = st.number_input("Time Limit", value=triple_barrier_conf_level["time_limit"],
key=f"{order_level['level']}_{order_level['side'].name}_tl")
with c24:
ts_ap = st.number_input("Trailing Stop Activation Price", value=float(triple_barrier_conf_level["trailing_stop_activation_price_delta"]),
key=f"{order_level['level']}_{order_level['side'].name}_tsap", format="%.4f")
ts_ap = st.number_input("Trailing Stop Activation Price", value=float(
triple_barrier_conf_level["trailing_stop_activation_price_delta"]),
key=f"{order_level['level']}_{order_level['side'].name}_tsap",
format="%.4f")
with c25:
ts_td = st.number_input("Trailing Stop Trailing Delta", value=float(triple_barrier_conf_level["trailing_stop_trailing_delta"]),
key=f"{order_level['level']}_{order_level['side'].name}_tstd", format="%.4f")
ts_td = st.number_input("Trailing Stop Trailing Delta", value=float(
triple_barrier_conf_level["trailing_stop_trailing_delta"]),
key=f"{order_level['level']}_{order_level['side'].name}_tstd",
format="%.4f")
with ol_c2:
st.write("#### Position config:")
c31, c32 = st.columns(2)
with c31:
order_amount = st.number_input("Order amount USD", value=float(order_level["order_amount_usd"]),
order_amount = st.number_input("Order amount USD",
value=float(order_level["order_amount_usd"]),
key=f"{order_level['level']}_{order_level['side'].name}_oa")
with c32:
cooldown_time = st.number_input("Cooldown time", value=order_level["cooldown_time"],
key=f"{order_level['level']}_{order_level['side'].name}_cd")
triple_barrier_conf = TripleBarrierConf(stop_loss=Decimal(stop_loss), take_profit=Decimal(take_profit),
triple_barrier_conf = TripleBarrierConf(stop_loss=Decimal(stop_loss),
take_profit=Decimal(take_profit),
time_limit=time_limit,
trailing_stop_activation_price_delta=Decimal(ts_ap),
trailing_stop_trailing_delta=Decimal(ts_td),
@@ -225,4 +241,4 @@ else:
add_volume=add_volume)
except FileNotFoundError:
st.warning(f"The requested candles could not be found.")
st.warning("The requested candles could not be found.")

View File

@@ -3,8 +3,8 @@ from types import SimpleNamespace
import streamlit as st
from streamlit_elements import elements, mui
from frontend.components.dashboard import Dashboard
from frontend.components.controllers_file_explorer import ControllersFileExplorer
from frontend.components.dashboard import Dashboard
from frontend.components.directional_strategy_creation_card import DirectionalStrategyCreationCard
from frontend.components.editor import Editor
from frontend.st_utils import initialize_st_page

View File

@@ -5,18 +5,19 @@ from types import SimpleNamespace
import streamlit as st
from streamlit_elements import elements, mui
from backend.utils import os_utils
from frontend.components.dashboard import Dashboard
from frontend.components.editor import Editor
from frontend.components.optimization_creation_card import OptimizationCreationCard
from frontend.components.optimization_run_card import OptimizationRunCard
from frontend.components.optimizations_file_explorer import OptimizationsStrategiesFileExplorer
from backend.utils import os_utils
from frontend.st_utils import initialize_st_page
initialize_st_page(title="Optimize", icon="🧪")
def run_optuna_dashboard():
os_utils.execute_bash_command(f"optuna-dashboard sqlite:///data/backtesting/backtesting_report.db")
os_utils.execute_bash_command("optuna-dashboard sqlite:///data/backtesting/backtesting_report.db")
time.sleep(5)
webbrowser.open("http://127.0.0.1:8080/dashboard", new=2)

View File

@@ -1,18 +1,16 @@
import streamlit as st
import pandas_ta as ta # noqa: F401
import streamlit as st
from plotly.subplots import make_subplots
from frontend.components.backtesting import backtesting_section
from frontend.components.config_loader import get_default_config_loader
from frontend.components.save_config import render_save_config
from frontend.pages.config.utils import get_candles
from frontend.st_utils import initialize_st_page, get_backend_api_client
from frontend.pages.config.bollinger_v1.user_inputs import user_inputs
from plotly.subplots import make_subplots
from frontend.pages.config.utils import get_candles
from frontend.st_utils import get_backend_api_client, initialize_st_page
from frontend.visualization import theme
from frontend.visualization.backtesting import create_backtesting_figure
from frontend.visualization.backtesting_metrics import render_backtesting_metrics, render_accuracy_metrics, \
render_close_types
from frontend.visualization.backtesting_metrics import render_accuracy_metrics, render_backtesting_metrics, render_close_types
from frontend.visualization.candles import get_candlestick_trace
from frontend.visualization.indicators import get_bbands_traces, get_volume_trace
from frontend.visualization.signals import get_bollinger_v1_signal_traces
@@ -22,7 +20,6 @@ from frontend.visualization.utils import add_traces_to_fig
initialize_st_page(title="Bollinger V1", icon="📈", initial_sidebar_state="expanded")
backend_api_client = get_backend_api_client()
st.text("This tool will let you create a config for Bollinger V1 and visualize the strategy.")
get_default_config_loader("bollinger_v1")
@@ -32,7 +29,8 @@ st.session_state["default_config"].update(inputs)
st.write("### Visualizing Bollinger Bands and Trading Signals")
days_to_visualize = st.number_input("Days to Visualize", min_value=1, max_value=365, value=7)
# Load candle data
candles = get_candles(connector_name=inputs["candles_connector"], trading_pair=inputs["candles_trading_pair"], interval=inputs["interval"], days=days_to_visualize)
candles = get_candles(connector_name=inputs["candles_connector"], trading_pair=inputs["candles_trading_pair"],
interval=inputs["interval"], days=days_to_visualize)
# Create a subplot with 2 rows
fig = make_subplots(rows=2, cols=1, shared_xaxes=True,
@@ -41,7 +39,9 @@ fig = make_subplots(rows=2, cols=1, shared_xaxes=True,
add_traces_to_fig(fig, [get_candlestick_trace(candles)], row=1, col=1)
add_traces_to_fig(fig, get_bbands_traces(candles, inputs["bb_length"], inputs["bb_std"]), row=1, col=1)
add_traces_to_fig(fig, get_bollinger_v1_signal_traces(candles, inputs["bb_length"], inputs["bb_std"], inputs["bb_long_threshold"], inputs["bb_short_threshold"]), row=1, col=1)
add_traces_to_fig(fig, get_bollinger_v1_signal_traces(candles, inputs["bb_length"], inputs["bb_std"],
inputs["bb_long_threshold"], inputs["bb_short_threshold"]), row=1,
col=1)
add_traces_to_fig(fig, [get_volume_trace(candles)], row=2, col=1)
fig.update_layout(**theme.get_default_layout())

View File

@@ -1,4 +1,5 @@
import streamlit as st
from frontend.components.directional_trading_general_inputs import get_directional_trading_general_inputs
from frontend.components.risk_management import get_risk_management_inputs
@@ -9,7 +10,8 @@ def user_inputs():
bb_std = default_config.get("bb_std", 2.0)
bb_long_threshold = default_config.get("bb_long_threshold", 0.0)
bb_short_threshold = default_config.get("bb_short_threshold", 1.0)
connector_name, trading_pair, leverage, total_amount_quote, max_executors_per_side, cooldown_time, position_mode, candles_connector_name, candles_trading_pair, interval = get_directional_trading_general_inputs()
connector_name, trading_pair, leverage, total_amount_quote, max_executors_per_side, cooldown_time, position_mode, \
candles_connector_name, candles_trading_pair, interval = get_directional_trading_general_inputs()
sl, tp, time_limit, ts_ap, ts_delta, take_profit_order_type = get_risk_management_inputs()
with st.expander("Bollinger Bands Configuration", expanded=True):
c1, c2, c3, c4 = st.columns(4)

View File

@@ -1,16 +1,13 @@
import streamlit as st
from CONFIG import BACKEND_API_HOST, BACKEND_API_PORT
from backend.services.backend_api_client import BackendAPIClient
from frontend.components.backtesting import backtesting_section
from frontend.components.config_loader import get_default_config_loader
from frontend.components.dca_distribution import get_dca_distribution_inputs
from frontend.components.save_config import render_save_config
from frontend.pages.config.dman_maker_v2.user_inputs import user_inputs
from frontend.st_utils import initialize_st_page, get_backend_api_client
from frontend.st_utils import get_backend_api_client, initialize_st_page
from frontend.visualization.backtesting import create_backtesting_figure
from frontend.visualization.backtesting_metrics import render_backtesting_metrics, render_accuracy_metrics, \
render_close_types
from frontend.visualization.backtesting_metrics import render_accuracy_metrics, render_backtesting_metrics, render_close_types
from frontend.visualization.dca_builder import create_dca_graph
from frontend.visualization.executors_distribution import create_executors_distribution_traces
@@ -18,14 +15,14 @@ from frontend.visualization.executors_distribution import create_executors_distr
initialize_st_page(title="D-Man Maker V2", icon="🧙‍♂️")
backend_api_client = get_backend_api_client()
# Page content
st.text("This tool will let you create a config for D-Man Maker V2 and upload it to the BackendAPI.")
get_default_config_loader("dman_maker_v2")
inputs = user_inputs()
with st.expander("Executor Distribution:", expanded=True):
fig = create_executors_distribution_traces(inputs["buy_spreads"], inputs["sell_spreads"], inputs["buy_amounts_pct"], inputs["sell_amounts_pct"], inputs["total_amount_quote"])
fig = create_executors_distribution_traces(inputs["buy_spreads"], inputs["sell_spreads"], inputs["buy_amounts_pct"],
inputs["sell_amounts_pct"], inputs["total_amount_quote"])
st.plotly_chart(fig, use_container_width=True)
dca_inputs = get_dca_distribution_inputs()

View File

@@ -5,8 +5,10 @@ from frontend.components.market_making_general_inputs import get_market_making_g
def user_inputs():
connector_name, trading_pair, leverage, total_amount_quote, position_mode, cooldown_time, executor_refresh_time, _, _, _ = get_market_making_general_inputs()
buy_spread_distributions, sell_spread_distributions, buy_order_amounts_pct, sell_order_amounts_pct = get_executors_distribution_inputs()
connector_name, trading_pair, leverage, total_amount_quote, position_mode, cooldown_time,\
executor_refresh_time, _, _, _ = get_market_making_general_inputs()
buy_spread_distributions, sell_spread_distributions, buy_order_amounts_pct, \
sell_order_amounts_pct = get_executors_distribution_inputs()
with st.expander("Custom D-Man Maker V2 Settings"):
c1, c2 = st.columns(2)
with c1:

View File

@@ -1,19 +0,0 @@
# D-Man Maker V2
## Features
- **Interactive Configuration**: Configure market making parameters such as spreads, amounts, and order levels through an intuitive web interface.
- **Visual Feedback**: Visualize order spread and amount distributions using dynamic Plotly charts.
- **Backend Integration**: Save and deploy configurations directly to a backend system for active management and execution.
### Using the Tool
1. **Configure Parameters**: Use the Streamlit interface to input parameters such as connector type, trading pair, and leverage.
2. **Set Distributions**: Define distributions for buy and sell orders, including spread and amount, either manually or through predefined distribution types like Geometric or Fibonacci.
3. **Visualize Orders**: View the configured order distributions on a Plotly graph, which illustrates the relationship between spread and amount.
4. **Export Configuration**: Once the configuration is set, export it as a YAML file or directly upload it to the Backend API.
5. **Upload**: Use the "Upload Config to BackendAPI" button to send your configuration to the backend system. Then can be used to deploy a new bot.
## Troubleshooting
- **UI Not Loading**: Ensure all Python dependencies are installed and that the Streamlit server is running correctly.
- **API Errors**: Check the console for any error messages that may indicate issues with the backend connection.
For more detailed documentation on the backend API and additional configurations, please refer to the project's documentation or contact the development team.

View File

@@ -1,147 +0,0 @@
import streamlit as st
import pandas as pd
import plotly.graph_objects as go
import yaml
from plotly.subplots import make_subplots
from CONFIG import BACKEND_API_HOST, BACKEND_API_PORT
from backend.services.backend_api_client import BackendAPIClient
from frontend.st_utils import initialize_st_page, get_backend_api_client
# Initialize the Streamlit page
initialize_st_page(title="D-Man V5", icon="📊", initial_sidebar_state="expanded")
@st.cache_data
def get_candles(connector_name, trading_pair, interval, max_records):
backend_client = BackendAPIClient(BACKEND_API_HOST, BACKEND_API_PORT)
return backend_client.get_real_time_candles(connector_name, trading_pair, interval, max_records)
@st.cache_data
def add_indicators(df, macd_fast, macd_slow, macd_signal, diff_lookback):
# MACD
df.ta.macd(fast=macd_fast, slow=macd_slow, signal=macd_signal, append=True)
# Decision Logic
macdh = df[f"MACDh_{macd_fast}_{macd_slow}_{macd_signal}"]
macdh_diff = df[f"MACDh_{macd_fast}_{macd_slow}_{macd_signal}"].diff(diff_lookback)
long_condition = (macdh > 0) & (macdh_diff > 0)
short_condition = (macdh < 0) & (macdh_diff < 0)
df["signal"] = 0
df.loc[long_condition, "signal"] = 1
df.loc[short_condition, "signal"] = -1
return df
st.write("## Configuration")
c1, c2, c3 = st.columns(3)
with c1:
connector_name = st.text_input("Connector Name", value="binance_perpetual")
trading_pair = st.text_input("Trading Pair", value="WLD-USDT")
with c2:
interval = st.selectbox("Candle Interval", ["1m", "3m", "5m", "15m", "30m"], index=1)
max_records = st.number_input("Max Records", min_value=100, max_value=10000, value=1000)
with c3:
macd_fast = st.number_input("MACD Fast", min_value=1, value=21)
macd_slow = st.number_input("MACD Slow", min_value=1, value=42)
macd_signal = st.number_input("MACD Signal", min_value=1, value=9)
diff_lookback = st.number_input("MACD Diff Lookback", min_value=1, value=5)
# Fetch and process data
candle_data = get_candles(connector_name, trading_pair, interval, max_records)
df = pd.DataFrame(candle_data)
df.index = pd.to_datetime(df['timestamp'], unit='s')
df = add_indicators(df, macd_fast, macd_slow, macd_signal, diff_lookback)
# Prepare data for signals
signals = df[df['signal'] != 0]
buy_signals = signals[signals['signal'] == 1]
sell_signals = signals[signals['signal'] == -1]
# Define your color palette
tech_colors = {
'upper_band': '#4682B4',
'middle_band': '#FFD700',
'lower_band': '#32CD32',
'buy_signal': '#1E90FF',
'sell_signal': '#FF0000',
}
# Create a subplot with 3 rows
fig = make_subplots(rows=3, cols=1, shared_xaxes=True,
vertical_spacing=0.05, # Adjust spacing to make the plot look better
subplot_titles=('Candlestick', 'MACD Line and Histogram', 'Trading Signals'),
row_heights=[0.5, 0.3, 0.2]) # Adjust heights to give more space to candlestick and MACD
# Candlestick and Bollinger Bands
fig.add_trace(go.Candlestick(x=df.index,
open=df['open'],
high=df['high'],
low=df['low'],
close=df['close'],
name="Candlesticks", increasing_line_color='#2ECC71', decreasing_line_color='#E74C3C'),
row=1, col=1)
# MACD Line and Histogram
fig.add_trace(go.Scatter(x=df.index, y=df[f"MACD_{macd_fast}_{macd_slow}_{macd_signal}"], line=dict(color='orange'), name='MACD Line'), row=2, col=1)
fig.add_trace(go.Scatter(x=df.index, y=df[f"MACDs_{macd_fast}_{macd_slow}_{macd_signal}"], line=dict(color='purple'), name='MACD Signal'), row=2, col=1)
fig.add_trace(go.Bar(x=df.index, y=df[f"MACDh_{macd_fast}_{macd_slow}_{macd_signal}"], name='MACD Histogram', marker_color=df[f"MACDh_{macd_fast}_{macd_slow}_{macd_signal}"].apply(lambda x: '#FF6347' if x < 0 else '#32CD32')), row=2, col=1)
# Signals plot
fig.add_trace(go.Scatter(x=buy_signals.index, y=buy_signals['close'], mode='markers',
marker=dict(color=tech_colors['buy_signal'], size=10, symbol='triangle-up'),
name='Buy Signal'), row=1, col=1)
fig.add_trace(go.Scatter(x=sell_signals.index, y=sell_signals['close'], mode='markers',
marker=dict(color=tech_colors['sell_signal'], size=10, symbol='triangle-down'),
name='Sell Signal'), row=1, col=1)
# Trading Signals
fig.add_trace(go.Scatter(x=signals.index, y=signals['signal'], mode='markers', marker=dict(color=signals['signal'].map({1: '#1E90FF', -1: '#FF0000'}), size=10), name='Trading Signals'), row=3, col=1)
# Update layout settings for a clean look
fig.update_layout(height=1000, title="MACD and Bollinger Bands Strategy", xaxis_title="Time", yaxis_title="Price", template="plotly_dark", showlegend=True)
fig.update_xaxes(rangeslider_visible=False, row=1, col=1)
fig.update_xaxes(rangeslider_visible=False, row=2, col=1)
fig.update_xaxes(rangeslider_visible=False, row=3, col=1)
# Display the chart
st.plotly_chart(fig, use_container_width=True)
c1, c2, c3 = st.columns([2, 2, 1])
with c1:
config_base = st.text_input("Config Base", value=f"macd_bb_v1-{connector_name}-{trading_pair.split('-')[0]}")
with c2:
config_tag = st.text_input("Config Tag", value="1.1")
# Save the configuration
id = f"{config_base}-{config_tag}"
config = {
"id": id,
"connector_name": connector_name,
"trading_pair": trading_pair,
"interval": interval,
"macd_fast": macd_fast,
"macd_slow": macd_slow,
"macd_signal": macd_signal,
}
yaml_config = yaml.dump(config, default_flow_style=False)
with c3:
download_config = st.download_button(
label="Download YAML",
data=yaml_config,
file_name=f'{id.lower()}.yml',
mime='text/yaml'
)
upload_config_to_backend = st.button("Upload Config to BackendAPI")
if upload_config_to_backend:
backend_api_client = get_backend_api_client()
backend_api_client.add_controller_config(config)
st.success("Config uploaded successfully!")

View File

@@ -1,13 +1,14 @@
import streamlit as st
import pandas as pd
import plotly.graph_objects as go
import streamlit as st
import yaml
from hummingbot.connector.connector_base import OrderType
from plotly.subplots import make_subplots
from pykalman import KalmanFilter
from CONFIG import BACKEND_API_HOST, BACKEND_API_PORT
from backend.services.backend_api_client import BackendAPIClient
from frontend.st_utils import initialize_st_page, get_backend_api_client
from CONFIG import BACKEND_API_HOST, BACKEND_API_PORT
from frontend.st_utils import get_backend_api_client, initialize_st_page
# Initialize the Streamlit page
initialize_st_page(title="Kalman Filter V1", icon="📈", initial_sidebar_state="expanded")
@@ -18,6 +19,7 @@ def get_candles(connector_name="binance", trading_pair="BTC-USDT", interval="1m"
backend_client = BackendAPIClient(BACKEND_API_HOST, BACKEND_API_PORT)
return backend_client.get_real_time_candles(connector_name, trading_pair, interval, max_records)
@st.cache_data
def add_indicators(df, observation_covariance=1, transition_covariance=0.01, initial_state_covariance=0.001):
# Add Bollinger Bands
@@ -61,7 +63,6 @@ with c3:
with c4:
max_records = st.number_input("Max Records", min_value=100, max_value=10000, value=1000)
st.write("## Positions Configuration")
c1, c2, c3, c4 = st.columns(4)
with c1:
@@ -87,28 +88,25 @@ with c1:
with c2:
transition_covariance = st.number_input("Transition Covariance", value=0.001, step=0.0001, format="%.4f")
# Load candle data
candle_data = get_candles(connector_name=candles_connector, trading_pair=candles_trading_pair, interval=interval, max_records=max_records)
candle_data = get_candles(connector_name=candles_connector, trading_pair=candles_trading_pair, interval=interval,
max_records=max_records)
df = pd.DataFrame(candle_data)
df.index = pd.to_datetime(df['timestamp'], unit='s')
candles_processed = add_indicators(df, observation_covariance, transition_covariance)
# Prepare data for signals
signals = candles_processed[candles_processed['signal'] != 0]
buy_signals = signals[signals['signal'] == 1]
sell_signals = signals[signals['signal'] == -1]
from plotly.subplots import make_subplots
# Define your color palette
tech_colors = {
'upper_band': '#4682B4', # Steel Blue for the Upper Bollinger Band
'upper_band': '#4682B4', # Steel Blue for the Upper Bollinger Band
'middle_band': '#FFD700', # Gold for the Middle Bollinger Band
'lower_band': '#32CD32', # Green for the Lower Bollinger Band
'buy_signal': '#1E90FF', # Dodger Blue for Buy Signals
'lower_band': '#32CD32', # Green for the Lower Bollinger Band
'buy_signal': '#1E90FF', # Dodger Blue for Buy Signals
'sell_signal': '#FF0000', # Red for Sell Signals
}
@@ -127,9 +125,15 @@ fig.add_trace(go.Candlestick(x=candles_processed.index,
row=1, col=1)
# Bollinger Bands
fig.add_trace(go.Scatter(x=candles_processed.index, y=candles_processed['kf_upper'], line=dict(color=tech_colors['upper_band']), name='Upper Band'), row=1, col=1)
fig.add_trace(go.Scatter(x=candles_processed.index, y=candles_processed['kf'], line=dict(color=tech_colors['middle_band']), name='Middle Band'), row=1, col=1)
fig.add_trace(go.Scatter(x=candles_processed.index, y=candles_processed['kf_lower'], line=dict(color=tech_colors['lower_band']), name='Lower Band'), row=1, col=1)
fig.add_trace(
go.Scatter(x=candles_processed.index, y=candles_processed['kf_upper'], line=dict(color=tech_colors['upper_band']),
name='Upper Band'), row=1, col=1)
fig.add_trace(
go.Scatter(x=candles_processed.index, y=candles_processed['kf'], line=dict(color=tech_colors['middle_band']),
name='Middle Band'), row=1, col=1)
fig.add_trace(
go.Scatter(x=candles_processed.index, y=candles_processed['kf_lower'], line=dict(color=tech_colors['lower_band']),
name='Lower Band'), row=1, col=1)
# Signals plot
fig.add_trace(go.Scatter(x=buy_signals.index, y=buy_signals['close'], mode='markers',
@@ -140,7 +144,8 @@ fig.add_trace(go.Scatter(x=sell_signals.index, y=sell_signals['close'], mode='ma
name='Sell Signal'), row=1, col=1)
fig.add_trace(go.Scatter(x=signals.index, y=signals['signal'], mode='markers',
marker=dict(color=signals['signal'].map({1: tech_colors['buy_signal'], -1: tech_colors['sell_signal']}), size=10),
marker=dict(color=signals['signal'].map(
{1: tech_colors['buy_signal'], -1: tech_colors['sell_signal']}), size=10),
showlegend=False), row=2, col=1)
# Update layout
@@ -218,8 +223,7 @@ with c3:
)
upload_config_to_backend = st.button("Upload Config to BackendAPI")
if upload_config_to_backend:
backend_api_client = get_backend_api_client()
backend_api_client.add_controller_config(config)
st.success("Config uploaded successfully!")
st.success("Config uploaded successfully!")

View File

@@ -6,11 +6,10 @@ from frontend.components.config_loader import get_default_config_loader
from frontend.components.save_config import render_save_config
from frontend.pages.config.macd_bb_v1.user_inputs import user_inputs
from frontend.pages.config.utils import get_candles
from frontend.st_utils import initialize_st_page, get_backend_api_client
from frontend.st_utils import get_backend_api_client, initialize_st_page
from frontend.visualization import theme
from frontend.visualization.backtesting import create_backtesting_figure
from frontend.visualization.backtesting_metrics import render_backtesting_metrics, render_accuracy_metrics, \
render_close_types
from frontend.visualization.backtesting_metrics import render_accuracy_metrics, render_backtesting_metrics, render_close_types
from frontend.visualization.candles import get_candlestick_trace
from frontend.visualization.indicators import get_bbands_traces, get_macd_traces
from frontend.visualization.signals import get_macdbb_v1_signal_traces
@@ -25,11 +24,11 @@ get_default_config_loader("macd_bb_v1")
inputs = user_inputs()
st.session_state["default_config"].update(inputs)
st.write("### Visualizing MACD Bollinger Trading Signals")
days_to_visualize = st.number_input("Days to Visualize", min_value=1, max_value=365, value=7)
# Load candle data
candles = get_candles(connector_name=inputs["candles_connector"], trading_pair=inputs["candles_trading_pair"], interval=inputs["interval"], days=days_to_visualize)
candles = get_candles(connector_name=inputs["candles_connector"], trading_pair=inputs["candles_trading_pair"],
interval=inputs["interval"], days=days_to_visualize)
# Create a subplot with 2 rows
fig = make_subplots(rows=2, cols=1, shared_xaxes=True,
@@ -38,9 +37,12 @@ fig = make_subplots(rows=2, cols=1, shared_xaxes=True,
add_traces_to_fig(fig, [get_candlestick_trace(candles)], row=1, col=1)
add_traces_to_fig(fig, get_bbands_traces(candles, inputs["bb_length"], inputs["bb_std"]), row=1, col=1)
add_traces_to_fig(fig, get_macdbb_v1_signal_traces(df=candles, bb_length=inputs["bb_length"], bb_std=inputs["bb_std"],
bb_long_threshold=inputs["bb_long_threshold"], bb_short_threshold=inputs["bb_short_threshold"],
macd_fast=inputs["macd_fast"], macd_slow=inputs["macd_slow"], macd_signal=inputs["macd_signal"]), row=1, col=1)
add_traces_to_fig(fig, get_macd_traces(df=candles, macd_fast=inputs["macd_fast"], macd_slow=inputs["macd_slow"], macd_signal=inputs["macd_signal"]), row=2, col=1)
bb_long_threshold=inputs["bb_long_threshold"],
bb_short_threshold=inputs["bb_short_threshold"],
macd_fast=inputs["macd_fast"], macd_slow=inputs["macd_slow"],
macd_signal=inputs["macd_signal"]), row=1, col=1)
add_traces_to_fig(fig, get_macd_traces(df=candles, macd_fast=inputs["macd_fast"], macd_slow=inputs["macd_slow"],
macd_signal=inputs["macd_signal"]), row=2, col=1)
fig.update_layout(**theme.get_default_layout())
# Use Streamlit's functionality to display the plot
@@ -61,4 +63,3 @@ if bt_results:
render_close_types(bt_results["results"])
st.write("---")
render_save_config(st.session_state["default_config"]["id"], st.session_state["default_config"])

View File

@@ -1,4 +1,5 @@
import streamlit as st
from frontend.components.directional_trading_general_inputs import get_directional_trading_general_inputs
from frontend.components.risk_management import get_risk_management_inputs
@@ -12,7 +13,8 @@ def user_inputs():
macd_fast = default_config.get("macd_fast", 21)
macd_slow = default_config.get("macd_slow", 42)
macd_signal = default_config.get("macd_signal", 9)
connector_name, trading_pair, leverage, total_amount_quote, max_executors_per_side, cooldown_time, position_mode, candles_connector_name, candles_trading_pair, interval = get_directional_trading_general_inputs()
connector_name, trading_pair, leverage, total_amount_quote, max_executors_per_side, cooldown_time, position_mode,\
candles_connector_name, candles_trading_pair, interval = get_directional_trading_general_inputs()
sl, tp, time_limit, ts_ap, ts_delta, take_profit_order_type = get_risk_management_inputs()
with st.expander("MACD Bollinger Configuration", expanded=True):
c1, c2, c3, c4, c5, c6, c7 = st.columns(7)

View File

@@ -1,23 +1,21 @@
import streamlit as st
import plotly.graph_objects as go
import streamlit as st
from plotly.subplots import make_subplots
from frontend.components.config_loader import get_default_config_loader
from frontend.components.executors_distribution import get_executors_distribution_inputs
from frontend.components.save_config import render_save_config
# Import submodules
from frontend.components.backtesting import backtesting_section
from frontend.components.config_loader import get_default_config_loader
from frontend.components.executors_distribution import get_executors_distribution_inputs
from frontend.components.save_config import render_save_config
from frontend.pages.config.pmm_dynamic.spread_and_price_multipliers import get_pmm_dynamic_multipliers
from frontend.pages.config.pmm_dynamic.user_inputs import user_inputs
from frontend.pages.config.utils import get_candles
from frontend.st_utils import initialize_st_page, get_backend_api_client
from frontend.st_utils import get_backend_api_client, initialize_st_page
from frontend.visualization import theme
from frontend.visualization.backtesting import create_backtesting_figure
from frontend.visualization.backtesting_metrics import render_accuracy_metrics, render_backtesting_metrics, render_close_types
from frontend.visualization.candles import get_candlestick_trace
from frontend.visualization.executors_distribution import create_executors_distribution_traces
from frontend.visualization.backtesting_metrics import render_backtesting_metrics, render_close_types, \
render_accuracy_metrics
from frontend.visualization.indicators import get_macd_traces
from frontend.visualization.utils import add_traces_to_fig
@@ -35,16 +33,25 @@ st.text("The MACD is used to shift the mid price and the NATR to make the spread
"In the order distributions graph, we are going to see the values of the orders affected by the average NATR")
days_to_visualize = st.number_input("Days to Visualize", min_value=1, max_value=365, value=7)
# Load candle data
candles = get_candles(connector_name=inputs["candles_connector"], trading_pair=inputs["candles_trading_pair"], interval=inputs["interval"], days=days_to_visualize)
candles = get_candles(connector_name=inputs["candles_connector"], trading_pair=inputs["candles_trading_pair"],
interval=inputs["interval"], days=days_to_visualize)
with st.expander("Visualizing PMM Dynamic Indicators", expanded=True):
fig = make_subplots(rows=4, cols=1, shared_xaxes=True,
vertical_spacing=0.02, subplot_titles=('Candlestick with Bollinger Bands', 'MACD', "Price Multiplier", "Spreads Multiplier"),
vertical_spacing=0.02, subplot_titles=("Candlestick with Bollinger Bands", "MACD",
"Price Multiplier", "Spreads Multiplier"),
row_heights=[0.8, 0.2, 0.2, 0.2])
add_traces_to_fig(fig, [get_candlestick_trace(candles)], row=1, col=1)
add_traces_to_fig(fig, get_macd_traces(df=candles, macd_fast=inputs["macd_fast"], macd_slow=inputs["macd_slow"], macd_signal=inputs["macd_signal"]), row=2, col=1)
price_multiplier, spreads_multiplier = get_pmm_dynamic_multipliers(candles, inputs["macd_fast"], inputs["macd_slow"], inputs["macd_signal"], inputs["natr_length"])
add_traces_to_fig(fig, [go.Scatter(x=candles.index, y=price_multiplier, name="Price Multiplier", line=dict(color="blue"))], row=3, col=1)
add_traces_to_fig(fig, [go.Scatter(x=candles.index, y=spreads_multiplier, name="Base Spread", line=dict(color="red"))], row=4, col=1)
add_traces_to_fig(fig, get_macd_traces(df=candles, macd_fast=inputs["macd_fast"], macd_slow=inputs["macd_slow"],
macd_signal=inputs["macd_signal"]), row=2, col=1)
price_multiplier, spreads_multiplier = get_pmm_dynamic_multipliers(candles, inputs["macd_fast"],
inputs["macd_slow"], inputs["macd_signal"],
inputs["natr_length"])
add_traces_to_fig(fig, [
go.Scatter(x=candles.index, y=price_multiplier, name="Price Multiplier", line=dict(color="blue"))], row=3,
col=1)
add_traces_to_fig(fig,
[go.Scatter(x=candles.index, y=spreads_multiplier, name="Base Spread", line=dict(color="red"))],
row=4, col=1)
fig.update_layout(**theme.get_default_layout(height=1000))
fig.update_yaxes(tickformat=".2%", row=3, col=1)
fig.update_yaxes(tickformat=".2%", row=4, col=1)
@@ -53,7 +60,8 @@ with st.expander("Visualizing PMM Dynamic Indicators", expanded=True):
st.write("### Executors Distribution")
st.write("The order distributions are affected by the average NATR. This means that if the first order has a spread of "
"1 and the NATR is 0.005, the first order will have a spread of 0.5% of the mid price.")
buy_spread_distributions, sell_spread_distributions, buy_order_amounts_pct, sell_order_amounts_pct = get_executors_distribution_inputs(use_custom_spread_units=True)
buy_spread_distributions, sell_spread_distributions, buy_order_amounts_pct, \
sell_order_amounts_pct = get_executors_distribution_inputs(use_custom_spread_units=True)
inputs["buy_spreads"] = [spread * 100 for spread in buy_spread_distributions]
inputs["sell_spreads"] = [spread * 100 for spread in sell_spread_distributions]
inputs["buy_amounts_pct"] = buy_order_amounts_pct
@@ -64,7 +72,8 @@ with st.expander("Executor Distribution:", expanded=True):
buy_spreads = [spread * natr_avarage for spread in inputs["buy_spreads"]]
sell_spreads = [spread * natr_avarage for spread in inputs["sell_spreads"]]
st.write(f"Average NATR: {natr_avarage:.2%}")
fig = create_executors_distribution_traces(buy_spreads, sell_spreads, inputs["buy_amounts_pct"], inputs["sell_amounts_pct"], inputs["total_amount_quote"])
fig = create_executors_distribution_traces(buy_spreads, sell_spreads, inputs["buy_amounts_pct"],
inputs["sell_amounts_pct"], inputs["total_amount_quote"])
st.plotly_chart(fig, use_container_width=True)
bt_results = backtesting_section(inputs, backend_api_client)

View File

@@ -1,4 +1,4 @@
import pandas_ta as ta # noqa: F401
import pandas_ta as ta # noqa: F401
def get_pmm_dynamic_multipliers(df, macd_fast, macd_slow, macd_signal, natr_length):

View File

@@ -10,7 +10,8 @@ def user_inputs():
macd_slow = default_config.get("macd_slow", 42)
macd_signal = default_config.get("macd_signal", 9)
natr_length = default_config.get("natr_length", 14)
connector_name, trading_pair, leverage, total_amount_quote, position_mode, cooldown_time, executor_refresh_time, candles_connector, candles_trading_pair, interval = get_market_making_general_inputs(custom_candles=True)
connector_name, trading_pair, leverage, total_amount_quote, position_mode, cooldown_time, executor_refresh_time, \
candles_connector, candles_trading_pair, interval = get_market_making_general_inputs(custom_candles=True)
sl, tp, time_limit, ts_ap, ts_delta, take_profit_order_type = get_risk_management_inputs()
with st.expander("PMM Dynamic Configuration", expanded=True):
c1, c2, c3, c4 = st.columns(4)

View File

@@ -1,23 +1,20 @@
import streamlit as st
from backend.services.backend_api_client import BackendAPIClient
from CONFIG import BACKEND_API_HOST, BACKEND_API_PORT
from frontend.components.backtesting import backtesting_section
from frontend.components.config_loader import get_default_config_loader
from frontend.components.save_config import render_save_config
# Import submodules
from frontend.pages.config.pmm_simple.user_inputs import user_inputs
from frontend.components.backtesting import backtesting_section
from frontend.st_utils import initialize_st_page, get_backend_api_client
from frontend.st_utils import get_backend_api_client, initialize_st_page
from frontend.visualization.backtesting import create_backtesting_figure
from frontend.visualization.backtesting_metrics import render_accuracy_metrics, render_backtesting_metrics, render_close_types
from frontend.visualization.executors_distribution import create_executors_distribution_traces
from frontend.visualization.backtesting_metrics import render_backtesting_metrics, render_close_types, \
render_accuracy_metrics
# Initialize the Streamlit page
initialize_st_page(title="PMM Simple", icon="👨‍🏫")
backend_api_client = get_backend_api_client()
# Page content
st.text("This tool will let you create a config for PMM Simple, backtest and upload it to the Backend API.")
get_default_config_loader("pmm_simple")
@@ -26,7 +23,8 @@ inputs = user_inputs()
st.session_state["default_config"].update(inputs)
with st.expander("Executor Distribution:", expanded=True):
fig = create_executors_distribution_traces(inputs["buy_spreads"], inputs["sell_spreads"], inputs["buy_amounts_pct"], inputs["sell_amounts_pct"], inputs["total_amount_quote"])
fig = create_executors_distribution_traces(inputs["buy_spreads"], inputs["sell_spreads"], inputs["buy_amounts_pct"],
inputs["sell_amounts_pct"], inputs["total_amount_quote"])
st.plotly_chart(fig, use_container_width=True)
bt_results = backtesting_section(inputs, backend_api_client)

View File

@@ -1,13 +1,13 @@
import streamlit as st
from frontend.components.executors_distribution import get_executors_distribution_inputs
from frontend.components.market_making_general_inputs import get_market_making_general_inputs
from frontend.components.risk_management import get_risk_management_inputs
def user_inputs():
connector_name, trading_pair, leverage, total_amount_quote, position_mode, cooldown_time, executor_refresh_time, _, _, _ = get_market_making_general_inputs()
buy_spread_distributions, sell_spread_distributions, buy_order_amounts_pct, sell_order_amounts_pct = get_executors_distribution_inputs()
connector_name, trading_pair, leverage, total_amount_quote, position_mode, cooldown_time, \
executor_refresh_time, _, _, _ = get_market_making_general_inputs()
buy_spread_distributions, sell_spread_distributions, buy_order_amounts_pct, \
sell_order_amounts_pct = get_executors_distribution_inputs()
sl, tp, time_limit, ts_ap, ts_delta, take_profit_order_type = get_risk_management_inputs()
# Create the config
config = {

View File

@@ -1,207 +0,0 @@
import streamlit as st
from plotly.subplots import make_subplots
import plotly.graph_objects as go
from decimal import Decimal
import yaml
from frontend.components.st_inputs import normalize, distribution_inputs, get_distribution
from frontend.st_utils import initialize_st_page
# Initialize the Streamlit page
initialize_st_page(title="Position Generator", icon="🔭")
# Page content
st.text("This tool will help you analyze and generate a position config.")
st.write("---")
# Layout in columns
col_quote, col_tp_sl, col_levels, col_spread_dist, col_amount_dist = st.columns([1, 1, 1, 2, 2])
def convert_to_yaml(spreads, order_amounts):
data = {
'dca_spreads': [float(spread)/100 for spread in spreads],
'dca_amounts': [float(amount) for amount in order_amounts]
}
return yaml.dump(data, default_flow_style=False)
with col_quote:
total_amount_quote = st.number_input("Total amount of quote", value=1000)
with col_tp_sl:
tp = st.number_input("Take Profit (%)", min_value=0.0, max_value=100.0, value=2.0, step=0.1)
sl = st.number_input("Stop Loss (%)", min_value=0.0, max_value=100.0, value=8.0, step=0.1)
with col_levels:
n_levels = st.number_input("Number of Levels", min_value=1, value=5)
# Spread and Amount Distributions
spread_dist_type, spread_start, spread_base, spread_scaling, spread_step, spread_ratio, manual_spreads = distribution_inputs(col_spread_dist, "Spread", n_levels)
amount_dist_type, amount_start, amount_base, amount_scaling, amount_step, amount_ratio, manual_amounts = distribution_inputs(col_amount_dist, "Amount", n_levels)
spread_distribution = get_distribution(spread_dist_type, n_levels, spread_start, spread_base, spread_scaling, spread_step, spread_ratio, manual_spreads)
amount_distribution = normalize(get_distribution(amount_dist_type, n_levels, amount_start, amount_base, amount_scaling, amount_step, amount_ratio, manual_amounts))
order_amounts = [Decimal(amount_dist * total_amount_quote) for amount_dist in amount_distribution]
spreads = [Decimal(spread - spread_distribution[0]) for spread in spread_distribution]
# Export Button
if st.button('Export as YAML'):
yaml_data = convert_to_yaml(spreads, order_amounts)
st.download_button(
label="Download YAML",
data=yaml_data,
file_name='config.yaml',
mime='text/yaml'
)
break_even_values = []
take_profit_values = []
for level in range(n_levels):
spreads_normalized = [Decimal(spread) + Decimal(0.01) for spread in spreads[:level+1]]
amounts = order_amounts[:level+1]
break_even = (sum([spread * amount for spread, amount in zip(spreads_normalized, amounts)]) / sum(amounts)) - Decimal(0.01)
break_even_values.append(break_even)
take_profit_values.append(break_even - Decimal(tp))
accumulated_amount = [sum(order_amounts[:i+1]) for i in range(len(order_amounts))]
def calculate_unrealized_pnl(spreads, break_even_values, accumulated_amount):
unrealized_pnl = []
for i in range(len(spreads)):
distance = abs(spreads[i] - break_even_values[i])
pnl = accumulated_amount[i] * distance / 100 # PNL calculation
unrealized_pnl.append(pnl)
return unrealized_pnl
# Calculate unrealized PNL
cum_unrealized_pnl = calculate_unrealized_pnl(spreads, break_even_values, accumulated_amount)
tech_colors = {
'spread': '#00BFFF', # Deep Sky Blue
'break_even': '#FFD700', # Gold
'take_profit': '#32CD32', # Green
'order_amount': '#1E90FF', # Dodger Blue
'cum_amount': '#4682B4', # Steel Blue
'stop_loss': '#FF0000', # Red
}
# Create Plotly figure with secondary y-axis and a dark theme
fig = make_subplots(specs=[[{"secondary_y": True}]])
fig.update_layout(template="plotly_dark")
# Update the Scatter Plots and Horizontal Lines
fig.add_trace(go.Scatter(x=list(range(len(spreads))), y=spreads, name='Spread (%)', mode='lines+markers', line=dict(width=3, color=tech_colors['spread'])), secondary_y=False)
fig.add_trace(go.Scatter(x=list(range(len(break_even_values))), y=break_even_values, name='Break Even (%)', mode='lines+markers', line=dict(width=3, color=tech_colors['break_even'])), secondary_y=False)
fig.add_trace(go.Scatter(x=list(range(len(take_profit_values))), y=take_profit_values, name='Take Profit (%)', mode='lines+markers', line=dict(width=3, color=tech_colors['take_profit'])), secondary_y=False)
# Add the new Bar Plot for Cumulative Unrealized PNL
fig.add_trace(go.Bar(
x=list(range(len(cum_unrealized_pnl))),
y=cum_unrealized_pnl,
text=[f"{pnl:.2f}" for pnl in cum_unrealized_pnl],
textposition='auto',
textfont=dict(color='white', size=12),
name='Cum Unrealized PNL',
marker=dict(color='#FFA07A', opacity=0.6) # Light Salmon color, adjust as needed
), secondary_y=True)
fig.add_trace(go.Bar(
x=list(range(len(order_amounts))),
y=order_amounts,
text=[f"{amt:.2f}" for amt in order_amounts], # List comprehension to format text labels
textposition='auto',
textfont=dict(
color='white',
size=12
),
name='Order Amount',
marker=dict(color=tech_colors['order_amount'], opacity=0.5),
), secondary_y=True)
# Modify the Bar Plot for Accumulated Amount
fig.add_trace(go.Bar(
x=list(range(len(accumulated_amount))),
y=accumulated_amount,
text=[f"{amt:.2f}" for amt in accumulated_amount], # List comprehension to format text labels
textposition='auto',
textfont=dict(
color='white',
size=12
),
name='Cum Amount',
marker=dict(color=tech_colors['cum_amount'], opacity=0.5),
), secondary_y=True)
# Add Horizontal Lines for Last Breakeven Price and Stop Loss Level
last_break_even = break_even_values[-1]
stop_loss_value = last_break_even + Decimal(sl)
# Horizontal Lines for Last Breakeven and Stop Loss
fig.add_hline(y=last_break_even, line_dash="dash", annotation_text=f"Global Break Even: {last_break_even:.2f} (%)", annotation_position="top left", line_color=tech_colors['break_even'])
fig.add_hline(y=stop_loss_value, line_dash="dash", annotation_text=f"Stop Loss: {stop_loss_value:.2f} (%)", annotation_position="bottom right", line_color=tech_colors['stop_loss'])
# Update Annotations for Spread and Break Even
for i, (spread, be_value, tp_value) in enumerate(zip(spreads, break_even_values, take_profit_values)):
fig.add_annotation(x=i, y=spread, text=f"{spread:.2f}%", showarrow=True, arrowhead=1, yshift=10, xshift=-2, font=dict(color=tech_colors['spread']))
fig.add_annotation(x=i, y=be_value, text=f"{be_value:.2f}%", showarrow=True, arrowhead=1, yshift=5, xshift=-2, font=dict(color=tech_colors['break_even']))
fig.add_annotation(x=i, y=tp_value, text=f"{tp_value:.2f}%", showarrow=True, arrowhead=1, yshift=10, xshift=-2, font=dict(color=tech_colors['take_profit']))
# Update Layout with a Dark Theme
fig.update_layout(
title="Spread, Accumulated Amount, Break Even, and Take Profit by Order Level",
xaxis_title="Order Level",
yaxis_title="Spread (%)",
yaxis2_title="Amount (Quote)",
height=800,
width=1800,
plot_bgcolor='rgba(0, 0, 0, 0)', # Transparent background
paper_bgcolor='rgba(0, 0, 0, 0.1)', # Lighter shade for the paper
font=dict(color='white') # Font color
)
# Calculate metrics
max_loss = total_amount_quote * Decimal(sl / 100)
profit_per_level = [cum_amount * Decimal(tp / 100) for cum_amount in accumulated_amount]
loots_to_recover = [max_loss / profit for profit in profit_per_level]
# Define a consistent annotation size and maximum value for the secondary y-axis
circle_text = "" # Unicode character for a circle
max_secondary_value = max(max(accumulated_amount), max(order_amounts), max(cum_unrealized_pnl)) # Adjust based on your secondary y-axis data
# Determine an appropriate y-offset for annotations
y_offset_secondary = max_secondary_value * Decimal(0.1) # Adjusts the height relative to the maximum value on the secondary y-axis
# Add annotations to the Plotly figure for the secondary y-axis
for i, loot in enumerate(loots_to_recover):
fig.add_annotation(
x=i,
y=max_secondary_value + y_offset_secondary, # Position above the maximum value using the offset
text=f"{circle_text}<br>LTR: {round(loot, 2)}", # Circle symbol and loot value in separate lines
showarrow=False,
font=dict(size=16, color='purple'),
xanchor="center", # Centers the text above the x coordinate
yanchor="bottom", # Anchors the text at its bottom to avoid overlapping
align="center",
yref="y2" # Reference the secondary y-axis
)
# Add Max Loss Metric as an Annotation
max_loss_annotation_text = f"Max Loss (Quote): {max_loss:.2f}"
fig.add_annotation(
x=max(len(spreads), len(break_even_values)) - 1, # Positioning the annotation to the right
text=max_loss_annotation_text,
showarrow=False,
font=dict(size=20, color='white'),
bgcolor='red', # Red background for emphasis
xanchor="left",
yanchor="top",
yref="y2" # Reference the secondary y-axis
)
st.write("---")
# Display in Streamlit
st.plotly_chart(fig)

View File

@@ -6,13 +6,12 @@ from frontend.components.config_loader import get_default_config_loader
from frontend.components.save_config import render_save_config
from frontend.pages.config.supertrend_v1.user_inputs import user_inputs
from frontend.pages.config.utils import get_candles
from frontend.st_utils import initialize_st_page, get_backend_api_client
from frontend.st_utils import get_backend_api_client, initialize_st_page
from frontend.visualization import theme
from frontend.visualization.backtesting import create_backtesting_figure
from frontend.visualization.backtesting_metrics import render_backtesting_metrics, render_accuracy_metrics, \
render_close_types
from frontend.visualization.backtesting_metrics import render_accuracy_metrics, render_backtesting_metrics, render_close_types
from frontend.visualization.candles import get_candlestick_trace
from frontend.visualization.indicators import get_volume_trace, get_supertrend_traces
from frontend.visualization.indicators import get_supertrend_traces, get_volume_trace
from frontend.visualization.signals import get_supertrend_v1_signal_traces
from frontend.visualization.utils import add_traces_to_fig
@@ -28,7 +27,8 @@ st.session_state["default_config"].update(inputs)
st.write("### Visualizing Supertrend Trading Signals")
days_to_visualize = st.number_input("Days to Visualize", min_value=1, max_value=365, value=7)
# Load candle data
candles = get_candles(connector_name=inputs["candles_connector"], trading_pair=inputs["candles_trading_pair"], interval=inputs["interval"], days=days_to_visualize)
candles = get_candles(connector_name=inputs["candles_connector"], trading_pair=inputs["candles_trading_pair"],
interval=inputs["interval"], days=days_to_visualize)
# Create a subplot with 2 rows
fig = make_subplots(rows=2, cols=1, shared_xaxes=True,
@@ -36,7 +36,8 @@ fig = make_subplots(rows=2, cols=1, shared_xaxes=True,
row_heights=[0.8, 0.2])
add_traces_to_fig(fig, [get_candlestick_trace(candles)], row=1, col=1)
add_traces_to_fig(fig, get_supertrend_traces(candles, inputs["length"], inputs["multiplier"]), row=1, col=1)
add_traces_to_fig(fig, get_supertrend_v1_signal_traces(candles, inputs["length"], inputs["multiplier"], inputs["percentage_threshold"]), row=1, col=1)
add_traces_to_fig(fig, get_supertrend_v1_signal_traces(candles, inputs["length"], inputs["multiplier"],
inputs["percentage_threshold"]), row=1, col=1)
add_traces_to_fig(fig, [get_volume_trace(candles)], row=2, col=1)
layout_settings = theme.get_default_layout()

View File

@@ -1,4 +1,5 @@
import streamlit as st
from frontend.components.directional_trading_general_inputs import get_directional_trading_general_inputs
from frontend.components.risk_management import get_risk_management_inputs
@@ -8,7 +9,8 @@ def user_inputs():
length = default_config.get("length", 20)
multiplier = default_config.get("multiplier", 3.0)
percentage_threshold = default_config.get("percentage_threshold", 0.5)
connector_name, trading_pair, leverage, total_amount_quote, max_executors_per_side, cooldown_time, position_mode, candles_connector_name, candles_trading_pair, interval = get_directional_trading_general_inputs()
connector_name, trading_pair, leverage, total_amount_quote, max_executors_per_side, cooldown_time, position_mode, \
candles_connector_name, candles_trading_pair, interval = get_directional_trading_general_inputs()
sl, tp, time_limit, ts_ap, ts_delta, take_profit_order_type = get_risk_management_inputs()
with st.expander("SuperTrend Configuration", expanded=True):

View File

@@ -1,10 +1,10 @@
import datetime
import streamlit as st
import pandas as pd
import streamlit as st
from CONFIG import BACKEND_API_HOST, BACKEND_API_PORT
from backend.services.backend_api_client import BackendAPIClient
from CONFIG import BACKEND_API_HOST, BACKEND_API_PORT
def get_max_records(days_to_download: int, interval: str) -> int:
@@ -21,8 +21,7 @@ def get_candles(connector_name="binance", trading_pair="BTC-USDT", interval="1m"
start_time = end_time - datetime.timedelta(days=days)
df = pd.DataFrame(backend_client.get_historical_candles(connector_name, trading_pair, interval,
start_time=int(start_time.timestamp() * 1000),
end_time=int(end_time.timestamp() * 1000)))
start_time=int(start_time.timestamp()),
end_time=int(end_time.timestamp())))
df.index = pd.to_datetime(df.timestamp, unit='s')
return df

View File

@@ -1,10 +1,8 @@
import streamlit as st
import plotly.graph_objects as go
import streamlit as st
import yaml
from CONFIG import BACKEND_API_HOST, BACKEND_API_PORT
from backend.services.backend_api_client import BackendAPIClient
from frontend.st_utils import initialize_st_page, get_backend_api_client
from frontend.st_utils import get_backend_api_client, initialize_st_page
# Initialize the Streamlit page
initialize_st_page(title="XEMM Multiple Levels", icon="⚡️")
@@ -29,9 +27,9 @@ with c4:
c41, c42 = st.columns([1, 1])
for i in range(buy_maker_levels):
with c41:
target_profitability = st.number_input(f"Target Profitability {i+1} B% ", value=0.3, step=0.01)
target_profitability = st.number_input(f"Target Profitability {i + 1} B% ", value=0.3, step=0.01)
with c42:
amount = st.number_input(f"Amount {i+1}B Quote", value=10, step=1)
amount = st.number_input(f"Amount {i + 1}B Quote", value=10, step=1)
buy_targets_amounts.append([target_profitability / 100, amount])
with c5:
sell_maker_levels = st.number_input("Sell Maker Levels", value=1, step=1)
@@ -39,9 +37,9 @@ with c5:
c51, c52 = st.columns([1, 1])
for i in range(sell_maker_levels):
with c51:
target_profitability = st.number_input(f"Target Profitability {i+1}S %", value=0.3, step=0.001)
target_profitability = st.number_input(f"Target Profitability {i + 1}S %", value=0.3, step=0.001)
with c52:
amount = st.number_input(f"Amount {i+1} S Quote", value=10, step=1)
amount = st.number_input(f"Amount {i + 1} S Quote", value=10, step=1)
sell_targets_amounts.append([target_profitability / 100, amount])
@@ -82,7 +80,8 @@ def create_order_graph(order_type, targets, min_profit, max_profit):
title=f"{order_type.capitalize()} Order Distribution with Profitability Targets",
xaxis=dict(
title="Profitability (%)",
range=[0, max(max(x_values + [min_profit_percent, max_profit_percent]) + 0.1, 1)] # Adjust range to include a buffer
range=[0, max(max(x_values + [min_profit_percent, max_profit_percent]) + 0.1, 1)]
# Adjust range to include a buffer
),
yaxis=dict(
title="Order Amount"
@@ -93,6 +92,7 @@ def create_order_graph(order_type, targets, min_profit, max_profit):
return fig
# Use the function for both buy and sell orders
buy_order_fig = create_order_graph('buy', buy_targets_amounts, min_profitability, max_profitability)
sell_order_fig = create_order_graph('sell', sell_targets_amounts, min_profitability, max_profitability)
@@ -104,31 +104,31 @@ st.plotly_chart(sell_order_fig, use_container_width=True)
# Display in Streamlit
c1, c2, c3 = st.columns([2, 2, 1])
with c1:
config_base = st.text_input("Config Base", value=f"xemm-{maker_connector}-{taker_connector}-{maker_trading_pair.split('-')[0]}")
config_base = st.text_input("Config Base",
value=f"xemm-{maker_connector}-{taker_connector}-{maker_trading_pair.split('-')[0]}")
with c2:
config_tag = st.text_input("Config Tag", value="1.1")
id = f"{config_base}_{config_tag}"
config = {
"id": id.lower(),
"controller_name": "xemm_multiple_levels",
"controller_type": "generic",
"maker_connector": maker_connector,
"maker_trading_pair": maker_trading_pair,
"taker_connector": taker_connector,
"taker_trading_pair": taker_trading_pair,
"min_profitability": min_profitability,
"max_profitability": max_profitability,
"buy_levels_targets_amount": buy_targets_amounts,
"sell_levels_targets_amount": sell_targets_amounts
"id": id.lower(),
"controller_name": "xemm_multiple_levels",
"controller_type": "generic",
"maker_connector": maker_connector,
"maker_trading_pair": maker_trading_pair,
"taker_connector": taker_connector,
"taker_trading_pair": taker_trading_pair,
"min_profitability": min_profitability,
"max_profitability": max_profitability,
"buy_levels_targets_amount": buy_targets_amounts,
"sell_levels_targets_amount": sell_targets_amounts
}
yaml_config = yaml.dump(config, default_flow_style=False)
with c3:
upload_config_to_backend = st.button("Upload Config to BackendAPI")
if upload_config_to_backend:
backend_api_client = get_backend_api_client()
backend_api_client.add_controller_config(config)
st.success("Config uploaded successfully!")
st.success("Config uploaded successfully!")

View File

@@ -1,9 +1,10 @@
import streamlit as st
from datetime import datetime, time
import pandas as pd
import plotly.graph_objects as go
import streamlit as st
from frontend.st_utils import initialize_st_page, get_backend_api_client
from frontend.st_utils import get_backend_api_client, initialize_st_page
# Initialize Streamlit page
initialize_st_page(title="Download Candles", icon="💾")
@@ -11,7 +12,9 @@ backend_api_client = get_backend_api_client()
c1, c2, c3, c4 = st.columns([2, 2, 2, 0.5])
with c1:
connector = st.selectbox("Exchange", ["binance_perpetual", "binance", "gate_io", "gate_io_perpetual", "kucoin", "ascend_ex"], index=0)
connector = st.selectbox("Exchange",
["binance_perpetual", "binance", "gate_io", "gate_io_perpetual", "kucoin", "ascend_ex"],
index=0)
trading_pair = st.text_input("Trading Pair", value="BTC-USDT")
with c2:
interval = st.selectbox("Interval", options=["1m", "3m", "5m", "15m", "1h", "4h", "1d", "1s"])
@@ -29,8 +32,8 @@ if get_data_button:
connector=connector,
trading_pair=trading_pair,
interval=interval,
start_time=int(start_datetime.timestamp()) * 1000,
end_time=int(end_datetime.timestamp()) * 1000
start_time=int(start_datetime.timestamp()),
end_time=int(end_datetime.timestamp())
)
candles_df = pd.DataFrame(candles)

View File

@@ -1,5 +1,6 @@
import streamlit as st
import plotly.express as px
import streamlit as st
import CONFIG
from backend.services.coingecko_client import CoinGeckoClient
from backend.services.miner_client import MinerClient
@@ -11,22 +12,27 @@ initialize_st_page(title="Token Spreads", icon="🧙")
cg_utils = CoinGeckoClient()
miner_utils = MinerClient()
@st.cache_data
def get_all_coins_df():
return cg_utils.get_all_coins_df()
@st.cache_data
def get_all_exchanges_df():
return cg_utils.get_all_exchanges_df()
@st.cache_data
def get_miner_stats_df():
return miner_utils.get_miner_stats_df()
@st.cache_data
def get_coin_tickers_by_id_list(coins_id: list):
return cg_utils.get_coin_tickers_by_id_list(coins_id)
with st.spinner(text='In progress'):
exchanges_df = get_all_exchanges_df()
coins_df = get_all_coins_df()
@@ -43,7 +49,8 @@ tokens = st.multiselect(
coins_id = coins_df.loc[coins_df["name"].isin(tokens), "id"].tolist()
coin_tickers_df = get_coin_tickers_by_id_list(coins_id)
coin_tickers_df["coin_name"] = coin_tickers_df.apply(lambda x: coins_df.loc[coins_df["id"] == x.token_id, "name"].item(), axis=1)
coin_tickers_df["coin_name"] = coin_tickers_df.apply(
lambda x: coins_df.loc[coins_df["id"] == x.token_id, "name"].item(), axis=1)
exchanges = st.multiselect(
"Select the exchanges to analyze:",

View File

@@ -1,7 +1,7 @@
import numpy as np
import streamlit as st
import pandas as pd
import plotly.express as px
import streamlit as st
from defillama import DefiLlama
from frontend.st_utils import initialize_st_page
@@ -12,16 +12,21 @@ initialize_st_page(title="TVL vs Market Cap", icon="🦉")
MIN_TVL = 1000000.
MIN_MCAP = 1000000.
@st.cache_data
def get_tvl_mcap_data():
llama = DefiLlama()
df = pd.DataFrame(llama.get_all_protocols())
tvl_mcap_df = df.loc[(df["tvl"]>0) & (df["mcap"]>0), ["name", "tvl", "mcap", "chain", "category", "slug"]].sort_values(by=["mcap"], ascending=False)
return tvl_mcap_df[(tvl_mcap_df["tvl"] > MIN_TVL) & (tvl_mcap_df["mcap"]> MIN_MCAP)]
tvl_mcap_df = df.loc[
(df["tvl"] > 0) & (df["mcap"] > 0), ["name", "tvl", "mcap", "chain", "category", "slug"]].sort_values(
by=["mcap"], ascending=False)
return tvl_mcap_df[(tvl_mcap_df["tvl"] > MIN_TVL) & (tvl_mcap_df["mcap"] > MIN_MCAP)]
def get_protocols_by_chain_category(protocols: pd.DataFrame, group_by: list, nth: list):
return protocols.sort_values('tvl', ascending=False).groupby(group_by).nth(nth).reset_index()
with st.spinner(text='In progress'):
tvl_mcap_df = get_tvl_mcap_data()
@@ -57,7 +62,8 @@ st.write("### SunBurst 🌞")
groupby = st.selectbox('Group by:', [['chain', 'category'], ['category', 'chain']])
nth = st.slider('Top protocols by Category', min_value=1, max_value=5)
proto_agg = get_protocols_by_chain_category(tvl_mcap_df[tvl_mcap_df["chain"].isin(chains)], groupby, np.arange(0, nth, 1).tolist())
proto_agg = get_protocols_by_chain_category(tvl_mcap_df[tvl_mcap_df["chain"].isin(chains)],
groupby, np.arange(0, nth, 1).tolist())
groupby.append("slug")
sunburst = px.sunburst(
proto_agg,
@@ -65,6 +71,6 @@ sunburst = px.sunburst(
values='tvl',
height=800,
title="SunBurst",
template="plotly_dark",)
template="plotly_dark", )
st.plotly_chart(sunburst, use_container_width=True)
st.plotly_chart(sunburst, use_container_width=True)

View File

@@ -1,8 +1,6 @@
from CONFIG import BACKEND_API_HOST, BACKEND_API_PORT
from backend.services.backend_api_client import BackendAPIClient
from frontend.st_utils import initialize_st_page, get_backend_api_client
import streamlit as st
from frontend.st_utils import get_backend_api_client, initialize_st_page
initialize_st_page(title="Credentials", icon="🔑")
@@ -15,6 +13,7 @@ NUM_COLUMNS = 4
def get_all_connectors_config_map():
return client.get_all_connectors_config_map()
# Section to display available accounts and credentials
accounts = client.get_accounts()
all_connector_config_map = get_all_connectors_config_map()
@@ -58,7 +57,8 @@ with c1:
with c2:
# Section to delete an existing account
st.header("Delete an Account")
delete_account_name = st.selectbox("Select Account to Delete", options=accounts if accounts else ["No accounts available"], )
delete_account_name = st.selectbox("Select Account to Delete",
options=accounts if accounts else ["No accounts available"], )
if st.button("Delete Account"):
if delete_account_name and delete_account_name != "No accounts available":
response = client.delete_account(delete_account_name)
@@ -69,11 +69,14 @@ with c2:
with c3:
# Section to delete a credential from an existing account
st.header("Delete Credential")
delete_account_cred_name = st.selectbox("Select the credentials account", options=accounts if accounts else ["No accounts available"],)
delete_account_cred_name = st.selectbox("Select the credentials account",
options=accounts if accounts else ["No accounts available"], )
creds_for_account = [credential.split(".")[0] for credential in client.get_credentials(delete_account_cred_name)]
delete_cred_name = st.selectbox("Select a Credential to Delete", options=creds_for_account if creds_for_account else ["No credentials available"])
delete_cred_name = st.selectbox("Select a Credential to Delete",
options=creds_for_account if creds_for_account else ["No credentials available"])
if st.button("Delete Credential"):
if (delete_account_cred_name and delete_account_cred_name != "No accounts available") and (delete_cred_name and delete_cred_name != "No credentials available"):
if (delete_account_cred_name and delete_account_cred_name != "No accounts available") and \
(delete_cred_name and delete_cred_name != "No credentials available"):
response = client.delete_credential(delete_account_cred_name, delete_cred_name)
st.warning(response)
else:
@@ -88,7 +91,8 @@ with c1:
account_name = st.selectbox("Select Account", options=accounts if accounts else ["No accounts available"])
with c2:
all_connectors = list(all_connector_config_map.keys())
binance_perpetual_index = all_connectors.index("binance_perpetual") if "binance_perpetual" in all_connectors else None
binance_perpetual_index = all_connectors.index(
"binance_perpetual") if "binance_perpetual" in all_connectors else None
connector_name = st.selectbox("Select Connector", options=all_connectors, index=binance_perpetual_index)
config_map = all_connector_config_map[connector_name]
@@ -103,4 +107,4 @@ with cols[-1]:
if st.button("Submit Credentials"):
response = client.add_connector_keys(account_name, connector_name, config_inputs)
if response:
st.success(response)
st.success(response)

View File

@@ -1,4 +1,5 @@
from types import SimpleNamespace
import streamlit as st
from streamlit_elements import elements, mui

View File

@@ -1,20 +1,19 @@
import time
from types import SimpleNamespace
import streamlit as st
from streamlit_elements import elements, mui
from types import SimpleNamespace
from CONFIG import BACKEND_API_HOST, BACKEND_API_PORT
from frontend.components.bot_performance_card import BotPerformanceCardV2
from frontend.components.dashboard import Dashboard
from backend.services.backend_api_client import BackendAPIClient
from frontend.st_utils import initialize_st_page, get_backend_api_client
from frontend.st_utils import get_backend_api_client, initialize_st_page
# Constants for UI layout
CARD_WIDTH = 12
CARD_HEIGHT = 4
NUM_CARD_COLS = 1
def get_grid_positions(n_cards: int, cols: int = NUM_CARD_COLS, card_width: int = CARD_WIDTH, card_height: int = CARD_HEIGHT):
rows = n_cards // cols + 1
x_y = [(x * card_width, y * card_height) for x in range(cols) for y in range(rows)]
@@ -30,7 +29,9 @@ def update_active_bots(api_client):
new_bots = set(current_active_bots.keys()) - set(stored_bots.keys())
removed_bots = set(stored_bots.keys()) - set(current_active_bots.keys())
for bot in removed_bots:
st.session_state.active_instances_board.bot_cards = [card for card in st.session_state.active_instances_board.bot_cards if card[1] != bot]
st.session_state.active_instances_board.bot_cards = [card for card in
st.session_state.active_instances_board.bot_cards
if card[1] != bot]
positions = get_grid_positions(len(current_active_bots), NUM_CARD_COLS, CARD_WIDTH, CARD_HEIGHT)
for bot, (x, y) in zip(new_bots, positions[:len(new_bots)]):
card = BotPerformanceCardV2(st.session_state.active_instances_board.dashboard, x, y, CARD_WIDTH, CARD_HEIGHT)
@@ -72,4 +73,4 @@ with elements("active_instances_board"):
while True:
time.sleep(10)
st.rerun()
st.rerun()

View File

@@ -1,7 +1,6 @@
from frontend.components.deploy_v2_with_controllers import LaunchV2WithControllers
from frontend.st_utils import initialize_st_page
initialize_st_page(title="Launch Bot ST", icon="🙌")

View File

@@ -1,8 +1,8 @@
from frontend.st_utils import initialize_st_page, get_backend_api_client
import streamlit as st
import pandas as pd
import plotly.graph_objects as go
import plotly.express as px
import streamlit as st
from frontend.st_utils import get_backend_api_client, initialize_st_page
initialize_st_page(title="Portfolio", icon="💰")
@@ -91,7 +91,8 @@ for account in accounts:
filtered_account_state[account] = {}
for exchange in exchanges:
if exchange in account_state[account]:
filtered_account_state[account][exchange] = [token_info for token_info in account_state[account][exchange] if token_info["token"] in tokens_available]
filtered_account_state[account][exchange] = [token_info for token_info in account_state[account][exchange]
if token_info["token"] in tokens_available]
filtered_account_history = []
for record in account_history:
@@ -101,7 +102,9 @@ for record in account_history:
filtered_record["state"][account] = {}
for exchange in exchanges:
if exchange in record["state"][account]:
filtered_record["state"][account][exchange] = [token_info for token_info in record["state"][account][exchange] if token_info["token"] in tokens_available]
filtered_record["state"][account][exchange] = [token_info for token_info in
record["state"][account][exchange] if
token_info["token"] in tokens_available]
filtered_account_history.append(filtered_record)
if len(filtered_account_state) > 0:

View File

@@ -1 +0,0 @@
Inspect and analyze the orders and trades data contained in a Hummingbot strategy database

View File

@@ -1,34 +0,0 @@
import streamlit as st
import sqlite3
import pandas as pd
from frontend.st_utils import initialize_st_page
initialize_st_page(title="DB Inspector", icon="🔍")
# Start content here
@st.cache_data
def get_table_data(database_name: str, table_name: str):
conn = sqlite3.connect(database_name)
orders = pd.read_sql_query(f"SELECT * FROM '{table_name}'", conn)
return orders
@st.cache_data
def get_all_tables(database_name: str):
con = sqlite3.connect(database_name)
cursor = con.cursor()
cursor.execute("SELECT name FROM sqlite_master WHERE type='table';")
tables = [table_row[0] for table_row in cursor.fetchall()]
return tables
uploaded_file = st.file_uploader("Add your database")
if uploaded_file is not None:
with open(f"{uploaded_file.name}", "wb") as f:
f.write(uploaded_file.getbuffer())
tables = get_all_tables(uploaded_file.name)
st.subheader("Tables of the database:")
for table in tables:
st.write(table)
st.dataframe(get_table_data(uploaded_file.name, table))

View File

@@ -1 +0,0 @@
This page helps you load the database file of a Hummingbot strategy and analyze its performance.

View File

@@ -1,235 +0,0 @@
import os
import pandas as pd
import streamlit as st
import math
from backend.utils.os_utils import get_databases
from frontend.visualization.graphs import PerformanceGraphs
from frontend.st_utils import initialize_st_page, style_metric_cards
initialize_st_page(title="Strategy Performance", icon="🚀")
style_metric_cards()
UPLOAD_FOLDER = "data"
# Start content here
intervals = {
"1m": 60,
"3m": 60 * 3,
"5m": 60 * 5,
"15m": 60 * 15,
"30m": 60 * 30,
"1h": 60 * 60,
"6h": 60 * 60 * 6,
"1d": 60 * 60 * 24,
}
# Data source section
st.subheader("🔫 Data source")
# Upload database
with st.expander("⬆️ Upload"):
uploaded_db = st.file_uploader("Select a Hummingbot SQLite Database", type=["sqlite", "db"])
if uploaded_db is not None:
file_contents = uploaded_db.read()
with open(os.path.join(UPLOAD_FOLDER, uploaded_db.name), "wb") as f:
f.write(file_contents)
st.success("File uploaded and saved successfully!")
selected_db = DatabaseManager(uploaded_db.name)
# Find and select existing databases
dbs = get_databases()
if dbs is not None:
bot_source = st.selectbox("Choose your database source:", dbs.keys())
db_names = [x for x in dbs[bot_source]]
selected_db_name = st.selectbox("Select a database to start:", db_names)
selected_db = DatabaseManager(db_name=dbs[bot_source][selected_db_name])
else:
st.warning("Ups! No databases were founded. Start uploading one")
selected_db = None
st.stop()
# Load strategy data
strategy_data = selected_db.get_strategy_data()
main_performance_charts = PerformanceGraphs(strategy_data)
# Strategy summary section
st.divider()
st.subheader("📝 Strategy summary")
if not main_performance_charts.has_summary_table:
db_error_message(db=selected_db,
error_message="Inaccesible summary table. Please try uploading a new database.")
st.stop()
else:
main_tab, chart_tab = st.tabs(["Main", "Chart"])
with chart_tab:
st.plotly_chart(main_performance_charts.summary_chart(), use_container_width=True)
with main_tab:
selection = main_performance_charts.strategy_summary_table()
if selection is None:
st.info("💡 Choose a trading pair and start analyzing!")
st.stop()
elif len(selection) > 1:
st.warning("This version doesn't support multiple selections. Please try selecting only one.")
st.stop()
else:
selected_exchange = selection["Exchange"].values[0]
selected_trading_pair = selection["Trading Pair"].values[0]
# Explore Trading Pair section
st.divider()
st.subheader("🔍 Explore Trading Pair")
if any("Error" in status for status in [selected_db.status["trade_fill"], selected_db.status["orders"]]):
db_error_message(db=selected_db,
error_message="Database error. Check the status of your database.")
st.stop()
# Filter strategy data by time
date_array = pd.date_range(start=strategy_data.start_time, end=strategy_data.end_time, periods=60)
start_time, end_time = st.select_slider("Select a time range to analyze",
options=date_array.tolist(),
value=(date_array[0], date_array[-1]))
single_market_strategy_data = strategy_data.get_single_market_strategy_data(selected_exchange, selected_trading_pair)
time_filtered_strategy_data = single_market_strategy_data.get_filtered_strategy_data(start_time, end_time)
time_filtered_performance_charts = PerformanceGraphs(time_filtered_strategy_data)
# Header metrics
col1, col2, col3, col4, col5, col6, col7, col8 = st.columns(8)
with col1:
st.metric(label=f'Net PNL {time_filtered_strategy_data.quote_asset}',
value=round(time_filtered_strategy_data.net_pnl_quote, 2),
help="The overall profit or loss achieved in quote asset.")
with col2:
st.metric(label='Total Trades', value=time_filtered_strategy_data.total_orders,
help="The total number of closed trades, winning and losing.")
with col3:
st.metric(label='Accuracy',
value=f"{100 * time_filtered_strategy_data.accuracy:.2f} %",
help="The percentage of winning trades, the number of winning trades divided by the total number of closed trades.")
with col4:
st.metric(label="Profit Factor",
value=round(time_filtered_strategy_data.profit_factor, 2),
help="The amount of money the strategy made for every unit of money it lost, net profits divided by gross losses.")
with col5:
st.metric(label='Duration (Days)',
value=round(time_filtered_strategy_data.duration_seconds / (60 * 60 * 24), 2),
help="The number of days the strategy was running.")
with col6:
st.metric(label='Price change',
value=f"{round(time_filtered_strategy_data.price_change * 100, 2)} %",
help="The percentage change in price from the start to the end of the strategy.")
with col7:
buy_trades_amount = round(time_filtered_strategy_data.total_buy_amount, 2)
avg_buy_price = round(time_filtered_strategy_data.average_buy_price, 4)
st.metric(label="Total Buy Volume",
value=round(buy_trades_amount * avg_buy_price, 2),
help="The total amount of quote asset bought.")
with col8:
sell_trades_amount = round(time_filtered_strategy_data.total_sell_amount, 2)
avg_sell_price = round(time_filtered_strategy_data.average_sell_price, 4)
st.metric(label="Total Sell Volume",
value=round(sell_trades_amount * avg_sell_price, 2),
help="The total amount of quote asset sold.")
# Cummulative pnl chart
st.plotly_chart(time_filtered_performance_charts.pnl_over_time(), use_container_width=True)
# Market activity section
st.subheader("💱 Market activity")
if "Error" in selected_db.status["market_data"] or time_filtered_strategy_data.market_data.empty:
st.warning("Market data is not available so the candles graph is not going to be rendered."
"Make sure that you are using the latest version of Hummingbot and market data recorder activated.")
else:
col1, col2 = st.columns([3, 1])
with col2:
# Set custom configs
interval = st.selectbox("Candles Interval:", intervals.keys(), index=2)
rows_per_page = st.number_input("Candles per Page", value=1500, min_value=1, max_value=5000)
# Add pagination
total_rows = len(time_filtered_strategy_data.get_market_data_resampled(interval=f"{intervals[interval]}S"))
total_pages = math.ceil(total_rows / rows_per_page)
if total_pages > 1:
selected_page = st.select_slider("Select page", list(range(total_pages)), total_pages - 1, key="page_slider")
else:
selected_page = 0
start_idx = selected_page * rows_per_page
end_idx = start_idx + rows_per_page
candles_df = time_filtered_strategy_data.get_market_data_resampled(interval=f"{intervals[interval]}S").iloc[start_idx:end_idx]
start_time_page = candles_df.index.min()
end_time_page = candles_df.index.max()
# Get Page Filtered Strategy Data
page_filtered_strategy_data = single_market_strategy_data.get_filtered_strategy_data(start_time_page, end_time_page)
page_performance_charts = PerformanceGraphs(page_filtered_strategy_data)
candles_chart = page_performance_charts.candles_graph(candles_df, interval=interval)
# Show auxiliary charts
intraday_tab, returns_tab, returns_data_tab, positions_tab, other_metrics_tab = st.tabs(["Intraday", "Returns", "Returns Data", "Positions", "Other Metrics"])
with intraday_tab:
st.plotly_chart(time_filtered_performance_charts.intraday_performance(), use_container_width=True)
with returns_tab:
st.plotly_chart(time_filtered_performance_charts.returns_histogram(), use_container_width=True)
with returns_data_tab:
raw_returns_data = time_filtered_strategy_data.trade_fill[["timestamp", "gross_pnl", "trade_fee", "realized_pnl"]].dropna(subset="realized_pnl")
st.dataframe(raw_returns_data,
use_container_width=True,
hide_index=True,
height=(min(len(time_filtered_strategy_data.trade_fill) * 39, 600)))
download_csv_button(raw_returns_data, "raw_returns_data", "download-raw-returns")
with positions_tab:
positions_sunburst = page_performance_charts.position_executor_summary_sunburst()
if positions_sunburst:
st.plotly_chart(page_performance_charts.position_executor_summary_sunburst(), use_container_width=True)
else:
st.info("No position executor data found.")
with other_metrics_tab:
col3, col4 = st.columns(2)
with col3:
st.metric(label=f'Trade PNL {time_filtered_strategy_data.quote_asset}',
value=round(time_filtered_strategy_data.trade_pnl_quote, 2),
help="The overall profit or loss achieved in quote asset, without fees.")
st.metric(label='Total Buy Trades', value=time_filtered_strategy_data.total_buy_trades,
help="The total number of buy trades.")
st.metric(label='Total Buy Trades Amount',
value=round(time_filtered_strategy_data.total_buy_amount, 2),
help="The total amount of base asset bought.")
st.metric(label='Average Buy Price', value=round(time_filtered_strategy_data.average_buy_price, 4),
help="The average price of the base asset bought.")
with col4:
st.metric(label=f'Fees {time_filtered_strategy_data.quote_asset}',
value=round(time_filtered_strategy_data.cum_fees_in_quote, 2),
help="The overall fees paid in quote asset.")
st.metric(label='Total Sell Trades', value=time_filtered_strategy_data.total_sell_trades,
help="The total number of sell trades.")
st.metric(label='Total Sell Trades Amount',
value=round(time_filtered_strategy_data.total_sell_amount, 2),
help="The total amount of base asset sold.")
st.metric(label='Average Sell Price', value=round(time_filtered_strategy_data.average_sell_price, 4),
help="The average price of the base asset sold.")
with col1:
st.plotly_chart(candles_chart, use_container_width=True)
# Tables section
st.divider()
st.subheader("Tables")
with st.expander("💵 Trades"):
st.write(strategy_data.trade_fill)
download_csv_button(strategy_data.trade_fill, "trade_fill", "download-trades")
with st.expander("📩 Orders"):
st.write(strategy_data.orders)
download_csv_button(strategy_data.orders, "orders", "download-orders")
with st.expander("⌕ Order Status"):
st.write(strategy_data.order_status)
download_csv_button(strategy_data.order_status, "order_status", "download-order-status")
if not strategy_data.market_data.empty:
with st.expander("💱 Market Data"):
st.write(strategy_data.market_data)
download_csv_button(strategy_data.market_data, "market_data", "download-market-data")
if strategy_data.position_executor is not None and not strategy_data.position_executor.empty:
with st.expander("🤖 Position executor"):
st.write(strategy_data.position_executor)
download_csv_button(strategy_data.position_executor, "position_executor", "download-position-executor")

View File

@@ -0,0 +1,33 @@
from st_pages import Page, Section
def main_page():
return [Page("main.py", "Hummingbot Dashboard", "📊")]
def public_pages():
return [
Section("Config Generator", "🎛️"),
Page("frontend/pages/config/pmm_simple/app.py", "PMM Simple", "👨‍🏫"),
Page("frontend/pages/config/pmm_dynamic/app.py", "PMM Dynamic", "👩‍🏫"),
Page("frontend/pages/config/dman_maker_v2/app.py", "D-Man Maker V2", "🤖"),
Page("frontend/pages/config/bollinger_v1/app.py", "Bollinger V1", "📈"),
Page("frontend/pages/config/macd_bb_v1/app.py", "MACD_BB V1", "📊"),
Page("frontend/pages/config/supertrend_v1/app.py", "SuperTrend V1", "👨‍🔬"),
Page("frontend/pages/config/xemm_controller/app.py", "XEMM Controller", "⚡️"),
Section("Data", "💾"),
Page("frontend/pages/data/download_candles/app.py", "Download Candles", "💹"),
Section("Community Pages", "👨‍👩‍👧‍👦"),
Page("frontend/pages/data/token_spreads/app.py", "Token Spreads", "🧙"),
Page("frontend/pages/data/tvl_vs_mcap/app.py", "TVL vs Market Cap", "🦉"),
]
def private_pages():
return [
Section("Bot Orchestration", "🐙"),
Page("frontend/pages/orchestration/instances/app.py", "Instances", "🦅"),
Page("frontend/pages/orchestration/launch_bot_v2/app.py", "Deploy V2", "🚀"),
Page("frontend/pages/orchestration/credentials/app.py", "Credentials", "🔑"),
Page("frontend/pages/orchestration/portfolio/app.py", "Portfolio", "💰"),
]

View File

@@ -1,11 +1,16 @@
import inspect
import os.path
from pathlib import Path
import pandas as pd
from pathlib import Path
import inspect
import streamlit as st
from st_pages import add_page_title
import streamlit_authenticator as stauth
import yaml
from st_pages import add_page_title, show_pages
from yaml import SafeLoader
from CONFIG import AUTH_SYSTEM_ENABLED
from frontend.pages.permissions import main_page, private_pages, public_pages
def initialize_st_page(title: str, icon: str, layout="wide", initial_sidebar_state="expanded"):
@@ -28,23 +33,22 @@ def initialize_st_page(title: str, icon: str, layout="wide", initial_sidebar_sta
def download_csv_button(df: pd.DataFrame, filename: str, key: str):
csv = df.to_csv(index=False).encode('utf-8')
return st.download_button(
label="Download CSV",
data=csv,
file_name=f"{filename}.csv",
mime="text/csv",
key=key
)
label="Download CSV",
data=csv,
file_name=f"{filename}.csv",
mime="text/csv",
key=key
)
def style_metric_cards(
background_color: str = "rgba(255, 255, 255, 0)",
border_size_px: int = 1,
border_color: str = "rgba(255, 255, 255, 0.3)",
border_radius_px: int = 5,
border_left_color: str = "rgba(255, 255, 255, 0.5)",
box_shadow: bool = True,
background_color: str = "rgba(255, 255, 255, 0)",
border_size_px: int = 1,
border_color: str = "rgba(255, 255, 255, 0.3)",
border_radius_px: int = 5,
border_left_color: str = "rgba(255, 255, 255, 0.5)",
box_shadow: bool = True,
):
box_shadow_str = (
"box-shadow: 0 0.15rem 1.75rem 0 rgba(58, 59, 69, 0.15) !important;"
if box_shadow
@@ -68,16 +72,45 @@ def style_metric_cards(
def get_backend_api_client():
from CONFIG import BACKEND_API_HOST, BACKEND_API_PORT
from backend.services.backend_api_client import BackendAPIClient
from CONFIG import BACKEND_API_HOST, BACKEND_API_PORT
backend_api_client = BackendAPIClient.get_instance(host=BACKEND_API_HOST, port=BACKEND_API_PORT)
is_docker_running = False
try:
is_docker_running = backend_api_client.is_docker_running()
except Exception as e:
st.error(f"There was an error trying to connect to the Backend API: \n\n{str(e)} \n\nPlease make sure the Backend API is running.")
st.error(
f"There was an error trying to connect to the Backend API: "
f"\n\n{str(e)} \n\nPlease make sure the Backend API is running.")
st.stop()
if not is_docker_running:
st.error("Docker is not running. Please make sure Docker is running.")
st.stop()
return backend_api_client
def auth_system():
if not AUTH_SYSTEM_ENABLED:
show_pages(main_page() + private_pages() + public_pages())
else:
with open('credentials.yml') as file:
config = yaml.load(file, Loader=SafeLoader)
if "authenticator" not in st.session_state or "authentication_status" not in st.session_state or not st.session_state.get(
"authentication_status", False):
st.session_state.authenticator = stauth.Authenticate(
config['credentials'],
config['cookie']['name'],
config['cookie']['key'],
config['cookie']['expiry_days'],
config['pre-authorized']
)
show_pages(main_page() + public_pages())
st.session_state.authenticator.login()
if st.session_state["authentication_status"] is False:
st.error('Username/password is incorrect')
elif st.session_state["authentication_status"] is None:
st.warning('Please enter your username and password')
else:
st.session_state.authenticator.logout(location="sidebar")
st.sidebar.write(f'Welcome *{st.session_state["name"]}*')
show_pages(main_page() + private_pages() + public_pages())

View File

@@ -1,5 +1,6 @@
from plotly.subplots import make_subplots
from frontend.visualization.candles import get_bt_candlestick_trace, get_candlestick_trace
from frontend.visualization.candles import get_bt_candlestick_trace
from frontend.visualization.executors import add_executors_trace
from frontend.visualization.pnl import get_pnl_trace
from frontend.visualization.theme import get_default_layout

View File

@@ -38,6 +38,7 @@ def render_accuracy_metrics(summary_results):
st.metric(label="Accuracy Long", value=f"{accuracy_long:.2%}")
st.metric(label="Accuracy Short", value=f"{accuracy_short:.2%}")
def render_accuracy_metrics2(summary_results):
accuracy = summary_results.get('accuracy', 0)
total_long = summary_results.get('total_long', 0)

View File

@@ -1,5 +1,5 @@
import plotly.graph_objects as go
import pandas as pd
import plotly.graph_objects as go
from frontend.visualization import theme
@@ -11,7 +11,7 @@ def get_candlestick_trace(df):
low=df['low'],
close=df['close'],
name="Candlesticks",
increasing_line_color='#2ECC71', decreasing_line_color='#E74C3C',)
increasing_line_color='#2ECC71', decreasing_line_color='#E74C3C', )
def get_bt_candlestick_trace(df):

View File

@@ -1,6 +1,6 @@
from decimal import Decimal
import plotly.graph_objects as go
from plotly.subplots import make_subplots
import frontend.visualization.theme as theme

View File

@@ -1,7 +1,7 @@
import plotly.graph_objects as go
import pandas as pd
from decimal import Decimal
import pandas as pd
import plotly.graph_objects as go
from hummingbot.connector.connector_base import TradeType

View File

@@ -1,9 +1,11 @@
import numpy as np
import plotly.graph_objects as go
import frontend.visualization.theme as theme
def create_executors_distribution_traces(buy_spreads, sell_spreads, buy_amounts_pct, sell_amounts_pct, total_amount_quote):
def create_executors_distribution_traces(buy_spreads, sell_spreads, buy_amounts_pct, sell_amounts_pct,
total_amount_quote):
colors = theme.get_color_scheme()
buy_spread_distributions = [spread * 100 for spread in buy_spreads]

View File

@@ -24,7 +24,9 @@ def get_bbands_traces(df, bb_length, bb_std):
def get_volume_trace(df):
df.index = pd.to_datetime(df.timestamp, unit='s')
return go.Bar(x=df.index, y=df['volume'], name="Volume", marker_color=theme.get_color_scheme()["volume"], opacity=0.7)
return go.Bar(x=df.index, y=df['volume'], name="Volume", marker_color=theme.get_color_scheme()["volume"],
opacity=0.7)
def get_macd_traces(df, macd_fast, macd_slow, macd_signal):
tech_colors = theme.get_color_scheme()
@@ -38,7 +40,8 @@ def get_macd_traces(df, macd_fast, macd_slow, macd_signal):
go.Scatter(x=df.index, y=df[macd_s], line=dict(color=tech_colors['macd_signal']),
name='MACD Signal'),
go.Bar(x=df.index, y=df[macd_hist], name='MACD Histogram',
marker_color=df[f"MACDh_{macd_fast}_{macd_slow}_{macd_signal}"].apply(lambda x: '#FF6347' if x < 0 else '#32CD32'))
marker_color=df[f"MACDh_{macd_fast}_{macd_slow}_{macd_signal}"].apply(
lambda x: '#FF6347' if x < 0 else '#32CD32'))
]
return traces
@@ -79,4 +82,3 @@ def get_supertrend_traces(df, length, multiplier):
]
return traces

View File

@@ -1,6 +1,6 @@
import plotly.graph_objects as go
import numpy as np
import pandas as pd
import plotly.graph_objects as go
def get_pnl_trace(executors):

View File

@@ -1,6 +1,7 @@
from frontend.visualization import theme
import plotly.graph_objects as go
import pandas_ta as ta # noqa: F401
import plotly.graph_objects as go
from frontend.visualization import theme
def get_signal_traces(buy_signals, sell_signals):
@@ -15,6 +16,7 @@ def get_signal_traces(buy_signals, sell_signals):
]
return traces
def get_bollinger_v1_signal_traces(df, bb_length, bb_std, bb_long_threshold, bb_short_threshold):
# Add Bollinger Bands
candles = df.copy()
@@ -29,7 +31,6 @@ def get_bollinger_v1_signal_traces(df, bb_length, bb_std, bb_long_threshold, bb_
def get_macdbb_v1_signal_traces(df, bb_length, bb_std, bb_long_threshold, bb_short_threshold, macd_fast, macd_slow,
macd_signal):
tech_colors = theme.get_color_scheme()
# Add Bollinger Bands
df.ta.bbands(length=bb_length, std=bb_std, append=True)
# Add MACD

View File

@@ -1,3 +1,3 @@
def add_traces_to_fig(fig, traces, row=1, col=1):
for trace in traces:
fig.add_trace(trace, row=row, col=col)
fig.add_trace(trace, row=row, col=col)

143
main.py
View File

@@ -1,134 +1,25 @@
import streamlit as st
from st_pages import Page, Section, show_pages
from streamlit_authenticator import Authenticate
from CONFIG import AUTH_SYSTEM_ENABLED
from backend.utils.os_utils import read_yaml_file, dump_dict_to_yaml
from frontend.st_utils import auth_system
def main_page():
show_pages(
[
Page("main.py", "Hummingbot Dashboard", "📊"),
Section("Bot Orchestration", "🐙"),
Page("frontend/pages/orchestration/instances/app.py", "Instances", "🦅"),
Page("frontend/pages/orchestration/launch_bot_v2/app.py", "Deploy V2", "🚀"),
Page("frontend/pages/orchestration/credentials/app.py", "Credentials", "🔑"),
Page("frontend/pages/orchestration/portfolio/app.py", "Portfolio", "💰"),
# Page("frontend/pages/orchestration/launch_bot_v2_st/app.py", "Deploy ST", "🙌"),
# Page("pages/file_manager/app.py", "File Explorer", "🗂"),
Section("Config Generator", "🎛️"),
Page("frontend/pages/config/pmm_simple/app.py", "PMM Simple", "👨‍🏫"),
Page("frontend/pages/config/pmm_dynamic/app.py", "PMM Dynamic", "👩‍🏫"),
Page("frontend/pages/config/dman_maker_v2/app.py", "D-Man Maker V2", "🤖"),
Page("frontend/pages/config/bollinger_v1/app.py", "Bollinger V1", "📈"),
Page("frontend/pages/config/macd_bb_v1/app.py", "MACD_BB V1", "📊"),
Page("frontend/pages/config/supertrend_v1/app.py", "SuperTrend V1", "👨‍🔬"),
Page("frontend/pages/config/xemm_controller/app.py", "XEMM Controller", "⚡️"),
# Page("frontend/pages/config/position_builder/app.py", "Position Builder", "🔭"),
Section("Data", "💾"),
Page("frontend/pages/data/download_candles/app.py", "Download Candles", "💹"),
# Page("pages/create/create.py", "Create", "⚔️"),
# Page("pages/optimize/optimize.py", "Optimize", "🧪"),
# Page("pages/analyze/analyze.py", "Analyze", "🔬"),
Section("Community Pages", "👨‍👩‍👧‍👦"),
# Page("frontend/pages/performance/strategy_performance/app.py", "Strategy Performance", "🚀"),
Page("frontend/pages/data/token_spreads/app.py", "Token Spreads", "🧙"),
Page("frontend/pages/data/tvl_vs_mcap/app.py", "TVL vs Market Cap", "🦉"),
]
)
# Readme Section
readme_container = st.container()
with readme_container:
st.markdown("# 📊 Hummingbot Dashboard")
st.markdown("""
Hummingbot Dashboard is an open source application that helps you create, backtest, and optimize various
types of algo trading strategies. Afterwards, you can deploy them as [Hummingbot](http://hummingbot.org)
instances in either paper or live trading mode.""")
def main():
# readme section
st.markdown("# 📊 Hummingbot Dashboard")
st.markdown("Hummingbot Dashboard is an open source application that helps you create, backtest, and optimize "
"various types of algo trading strategies. Afterwards, you can deploy them as "
"[Hummingbot](http://hummingbot.org)")
st.write("---")
st.header("Getting Started")
st.header("Watch the Hummingbot Dashboard Tutorial!")
st.video("https://youtu.be/7eHiMPRBQLQ?si=PAvCq0D5QDZz1h1D")
st.header("Feedback and issues")
st.write(
"Watch the [Hummingbot Dashboard Tutorial playlist](https://www.youtube.com/watch?v=a-kenMqRB00) to get started!")
# Container for the videos
container = st.container()
video_titles = [
"1 - Introduction to Dashboard",
"2 - Setting up the Environment",
"3 - Managing Credentials",
"4 - Using the Master Bot Profile",
"5 - Deploying Bots and Running Strategies",
"7 - Controllers, Backtesting, and Optimization",
"8 - Deploying Best Strategies from Backtests",
"9 - Conclusions and Next Steps"
]
# List of YouTube video links
video_links = [
"https://www.youtube.com/embed/a-kenMqRB00",
"https://www.youtube.com/embed/AbezIhb6iJg",
"https://www.youtube.com/embed/VmlD_WQVe4M",
"https://www.youtube.com/embed/MPQTnlDXPno",
"https://www.youtube.com/embed/915E-C2LWdg",
"https://www.youtube.com/embed/bAi2ok7_boo",
"https://www.youtube.com/embed/BJf3ml-9JIQ",
"https://www.youtube.com/embed/ug_SSZb2HYE",
]
# Ensure the lists have the same length
assert len(video_titles) == len(video_links), "Mismatch between titles and links."
# Create a carousel-like feature
video_selection = st.selectbox("Choose a video:", options=video_titles)
# Get the index of the selected video title
selected_index = video_titles.index(video_selection)
# Display the selected video
st.video(video_links[selected_index])
st.write("---")
st.header("Feedback and Issues")
st.write("Please give us feedback in the **#dashboard** channel of the [Hummingbot Discord](https://discord.gg/hummingbot)! 🙏")
st.write("If you encounter any bugs or have suggestions for improvement, please create an issue in the [Hummingbot Dashboard Github](https://github.com/hummingbot/dashboard).")
"Please give us feedback in the **#dashboard** channel of the "
"[hummingbot discord](https://discord.gg/hummingbot)! 🙏")
st.write(
"If you encounter any bugs or have suggestions for improvement, please create an issue in the "
"[hummingbot dashboard github](https://github.com/hummingbot/dashboard).")
# config = read_yaml_file("credentials.yml")
#
# if "authenticator" not in st.session_state:
# st.session_state.authenticator = Authenticate(
# config['credentials'],
# config['cookie']['name'],
# config['cookie']['key'],
# config['cookie']['expiry_days'],
# config['preauthorized']
# )
# if not AUTH_SYSTEM_ENABLED:
main_page()
# elif st.session_state["authentication_status"]:
# config["credentials"] = st.session_state.authenticator_handler.credentials
# dump_dict_to_yaml(config, "credentials.yml")
# with st.sidebar:
# st.write(f'Welcome {st.session_state["name"]}!')
# st.session_state.authenticator.logout(location='sidebar') # Updated logout call
# main_page()
# else:
# show_pages([
# Page("main.py", "Hummingbot Dashboard", "📊"),
# ])
# name, authentication_status, username = st.session_state.authenticator.login(location='main') # Updated login call
# if st.session_state["authentication_status"] == False:
# st.error('Username/password is incorrect')
# elif st.session_state["authentication_status"] == None:
# st.warning('Please enter your username and password')
# st.write("---")
# st.write("If you are pre-authorized, you can login with your pre-authorized mail!")
# st.session_state.authenticator.register_user(location='main') # Updated register user call
auth_system()
main()

23
pyproject.toml Normal file
View File

@@ -0,0 +1,23 @@
[build-system]
requires = ["setuptools>=42", "wheel"]
build-backend = "setuptools.build_meta"
[tool.black]
line-length = 130
target-version = ["py38"]
[tool.isort]
line_length = 130
profile = "black"
multi_line_output = 3
include_trailing_comma = true
use_parentheses = true
ensure_newline_before_comments = true
combine_as_imports = true
[tool.pre-commit]
repos = [
{ repo = "https://github.com/pre-commit/pre-commit-hooks", rev = "v3.4.0", hooks = [{ id = "check-yaml" }, { id = "end-of-file-fixer" }] },
{ repo = "https://github.com/psf/black", rev = "21.6b0", hooks = [{ id = "black" }] },
{ repo = "https://github.com/pre-commit/mirrors-isort", rev = "v5.9.3", hooks = [{ id = "isort" }] }
]

View File

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,614 +0,0 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"outputs": [],
"source": [
"import os\n",
"import sys\n",
"\n",
"root_path = os.path.abspath(os.path.join(os.getcwd(), '../../..'))\n",
"sys.path.append(root_path)"
],
"metadata": {
"collapsed": false,
"ExecuteTime": {
"end_time": "2024-05-21T23:41:37.862880Z",
"start_time": "2024-05-21T23:41:37.861203Z"
}
}
},
{
"cell_type": "code",
"execution_count": 4,
"outputs": [],
"source": [
"from quants_lab.controllers.market_making.dman_maker_v2 import DManMakerV2Config\n",
"from hummingbot.strategy_v2.backtesting import MarketMakingBacktesting\n",
"import traceback\n",
"from decimal import Decimal\n",
"import pandas_ta as ta # noqa: F401\n",
"import pandas as pd\n",
"from optuna import TrialPruned\n",
"\n",
"backtesting_engine = MarketMakingBacktesting()\n",
"\n",
"async def objective(trial, start, end, backtesting_resolution):\n",
" try:\n",
" # Market configuration\n",
" connector_name = \"binance_perpetual\"\n",
" trading_pair = \"WLD-USDT\"\n",
"\n",
" # Account configuration\n",
" total_amount_quote = 1000\n",
" trade_cost = 0.0006\n",
" buy_spreads = [Decimal(\"0.002\")]\n",
" sell_spreads = [Decimal(\"0.002\")]\n",
" buy_amounts_pct = [Decimal(\"1\")]\n",
" sell_amounts_pct = [Decimal(\"1\")]\n",
" executor_refresh_time = 60\n",
" cooldown_time = 3600\n",
" top_executor_refresh_time = 60\n",
" executor_activation_bounds = [Decimal(\"0.01\")]\n",
" dca_spreads = [Decimal(\"0.\"), Decimal(\"0.002\"), Decimal(\"0.004\"), Decimal(\"0.006\"), Decimal(\"0.008\"), Decimal(\"0.01\")]\n",
" dca_amounts = [Decimal(\"0.1\"), Decimal(\"0.2\"), Decimal(\"0.3\"), Decimal(\"0.4\"), Decimal(\"0.5\"), Decimal(\"0.6\")]\n",
"\n",
" # Triple barrier configuration\n",
" stop_loss = trial.suggest_float('stop_loss', 0.01, 0.04, step=0.01)\n",
" take_profit = trial.suggest_float('take_profit', 0.01, 0.04, step=0.01)\n",
" time_limit = 60 * 60 * 12 # 12 hours\n",
" trailing_stop_activation_price_delta = Decimal(\"0.008\")\n",
" trailing_stop_trailing_delta = Decimal(\"0.004\")\n",
" config_dict = {\n",
" \"connector_name\": connector_name,\n",
" \"trading_pair\": trading_pair,\n",
" \"total_amount_quote\": total_amount_quote,\n",
" \"buy_spreads\": buy_spreads,\n",
" \"sell_spreads\": sell_spreads,\n",
" \"buy_amounts_pct\": buy_amounts_pct,\n",
" \"sell_amounts_pct\": sell_amounts_pct,\n",
" \"executor_refresh_time\": executor_refresh_time,\n",
" \"cooldown_time\": cooldown_time,\n",
" \"top_executor_refresh_time\": top_executor_refresh_time,\n",
" \"executor_activation_bounds\": executor_activation_bounds,\n",
" \"stop_loss\": stop_loss,\n",
" \"take_profit\": take_profit,\n",
" \"time_limit\": time_limit,\n",
" \"trailing_stop\": {\n",
" \"activation_price\": trailing_stop_activation_price_delta,\n",
" \"trailing_delta\": trailing_stop_trailing_delta\n",
" },\n",
" \"dca_spreads\": dca_spreads,\n",
" \"dca_amounts\": dca_amounts\n",
" }\n",
"\n",
"\n",
" config = DManMakerV2Config(**config_dict)\n",
" start_time = pd.to_datetime(start).timestamp() * 1e3\n",
" end_time = pd.to_datetime(end).timestamp() * 1e3\n",
" backtesting_results = await backtesting_engine.run_backtesting(\n",
" controller_config=config, trade_cost=trade_cost,\n",
" start=int(start_time), end=int(end_time),\n",
" backtesting_resolution=backtesting_resolution)\n",
"\n",
" strategy_analysis = backtesting_results[\"results\"]\n",
"\n",
" trial.set_user_attr(\"net_pnl_quote\", strategy_analysis[\"net_pnl_quote\"])\n",
" trial.set_user_attr(\"net_pnl_pct\", strategy_analysis[\"net_pnl\"])\n",
" trial.set_user_attr(\"max_drawdown_usd\", strategy_analysis[\"max_drawdown_usd\"])\n",
" trial.set_user_attr(\"max_drawdown_pct\", strategy_analysis[\"max_drawdown_pct\"])\n",
" trial.set_user_attr(\"sharpe_ratio\", strategy_analysis[\"sharpe_ratio\"])\n",
" trial.set_user_attr(\"accuracy\", strategy_analysis[\"accuracy\"])\n",
" trial.set_user_attr(\"total_positions\", strategy_analysis[\"total_positions\"])\n",
" trial.set_user_attr(\"profit_factor\", strategy_analysis[\"profit_factor\"])\n",
" trial.set_user_attr(\"win_signals\", strategy_analysis[\"win_signals\"])\n",
" trial.set_user_attr(\"loss_signals\", strategy_analysis[\"loss_signals\"])\n",
" trial.set_user_attr(\"close_types\", strategy_analysis[\"close_types\"])\n",
" trial.set_user_attr(\"config\", config_dict)\n",
" return strategy_analysis[\"net_pnl\"]\n",
" except Exception as e:\n",
" traceback.print_exc()\n",
" raise TrialPruned()\n"
],
"metadata": {
"collapsed": false,
"ExecuteTime": {
"end_time": "2024-05-22T00:12:09.348323Z",
"start_time": "2024-05-22T00:12:09.343772Z"
}
}
},
{
"cell_type": "code",
"execution_count": 6,
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"[I 2024-05-21 19:14:06,636] A new study created in RDB with name: dman_maker_v2_opt\n"
]
}
],
"source": [
"import optuna\n",
"\n",
"# Now let's configure the parameters for the optimization\n",
"study_name = \"dman_maker_v2_opt\"\n",
"storage= \"sqlite:///../../../data/backtesting/backtesting_report.db\"\n",
"\n",
"study = optuna.create_study(direction=\"maximize\", study_name=study_name,\n",
" storage=storage,\n",
" load_if_exists=True) # If the study already exists, we load it)"
],
"metadata": {
"collapsed": false,
"ExecuteTime": {
"end_time": "2024-05-22T00:14:06.642119Z",
"start_time": "2024-05-22T00:14:06.258703Z"
}
}
},
{
"cell_type": "code",
"execution_count": 7,
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"[W 2024-05-21 19:14:32,364] Trial 0 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:32,365] Trial 0 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"/Users/dardonacci/anaconda3/envs/dashboard/lib/python3.10/site-packages/optuna/study/_optimize.py:159: RuntimeWarning: coroutine 'objective' was never awaited\n",
" frozen_trial = _run_trial(study, func, catch)\n",
"RuntimeWarning: Enable tracemalloc to get the object allocation traceback\n",
"[W 2024-05-21 19:14:32,380] Trial 1 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:32,380] Trial 1 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:32,390] Trial 2 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:32,391] Trial 2 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:32,401] Trial 3 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:32,402] Trial 3 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:32,412] Trial 4 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:32,413] Trial 4 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:32,424] Trial 5 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:32,424] Trial 5 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:32,435] Trial 6 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:32,435] Trial 6 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:32,448] Trial 7 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:32,448] Trial 7 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:32,464] Trial 8 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:32,464] Trial 8 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:32,474] Trial 9 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:32,474] Trial 9 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:32,485] Trial 10 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:32,485] Trial 10 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:32,496] Trial 11 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:32,496] Trial 11 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:32,505] Trial 12 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:32,505] Trial 12 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:32,515] Trial 13 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:32,516] Trial 13 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:32,525] Trial 14 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:32,526] Trial 14 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:32,535] Trial 15 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:32,535] Trial 15 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:32,551] Trial 16 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:32,551] Trial 16 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:32,561] Trial 17 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:32,562] Trial 17 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:32,572] Trial 18 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:32,572] Trial 18 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:32,582] Trial 19 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:32,583] Trial 19 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:32,592] Trial 20 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:32,593] Trial 20 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:32,603] Trial 21 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:32,603] Trial 21 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:32,613] Trial 22 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:32,614] Trial 22 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:32,624] Trial 23 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:32,624] Trial 23 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:32,634] Trial 24 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:32,634] Trial 24 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:32,644] Trial 25 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:32,644] Trial 25 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:32,654] Trial 26 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:32,654] Trial 26 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:32,666] Trial 27 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:32,666] Trial 27 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:32,676] Trial 28 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:32,676] Trial 28 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:32,687] Trial 29 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:32,687] Trial 29 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:32,697] Trial 30 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:32,698] Trial 30 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:32,709] Trial 31 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:32,709] Trial 31 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:32,718] Trial 32 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:32,719] Trial 32 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:32,728] Trial 33 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:32,728] Trial 33 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:32,738] Trial 34 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:32,739] Trial 34 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:32,749] Trial 35 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:32,750] Trial 35 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:32,761] Trial 36 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:32,762] Trial 36 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:32,772] Trial 37 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:32,772] Trial 37 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:32,782] Trial 38 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:32,782] Trial 38 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:32,791] Trial 39 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:32,792] Trial 39 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:32,803] Trial 40 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:32,803] Trial 40 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:32,813] Trial 41 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:32,814] Trial 41 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:32,823] Trial 42 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:32,824] Trial 42 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:32,835] Trial 43 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:32,836] Trial 43 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:32,846] Trial 44 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:32,846] Trial 44 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:32,857] Trial 45 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:32,857] Trial 45 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:32,868] Trial 46 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:32,869] Trial 46 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:32,878] Trial 47 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:32,878] Trial 47 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:32,889] Trial 48 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:32,889] Trial 48 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:32,899] Trial 49 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:32,900] Trial 49 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:32,911] Trial 50 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:32,911] Trial 50 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:32,920] Trial 51 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:32,920] Trial 51 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:32,929] Trial 52 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:32,930] Trial 52 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:32,940] Trial 53 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:32,941] Trial 53 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:32,950] Trial 54 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:32,950] Trial 54 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:32,959] Trial 55 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:32,960] Trial 55 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:32,970] Trial 56 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:32,971] Trial 56 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:32,980] Trial 57 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:32,981] Trial 57 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:32,990] Trial 58 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:32,990] Trial 58 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:32,999] Trial 59 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:33,000] Trial 59 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:33,010] Trial 60 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:33,010] Trial 60 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:33,019] Trial 61 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:33,020] Trial 61 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:33,030] Trial 62 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:33,030] Trial 62 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:33,040] Trial 63 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:33,040] Trial 63 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:33,050] Trial 64 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:33,051] Trial 64 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:33,061] Trial 65 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:33,061] Trial 65 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:33,071] Trial 66 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:33,071] Trial 66 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:33,080] Trial 67 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:33,081] Trial 67 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:33,091] Trial 68 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:33,092] Trial 68 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:33,102] Trial 69 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:33,102] Trial 69 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:33,111] Trial 70 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:33,112] Trial 70 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:33,123] Trial 71 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:33,124] Trial 71 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:33,133] Trial 72 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:33,134] Trial 72 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:33,144] Trial 73 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:33,145] Trial 73 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:33,154] Trial 74 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:33,154] Trial 74 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:33,164] Trial 75 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:33,165] Trial 75 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:33,175] Trial 76 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:33,175] Trial 76 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:33,186] Trial 77 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:33,186] Trial 77 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:33,196] Trial 78 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:33,196] Trial 78 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:33,206] Trial 79 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:33,207] Trial 79 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:33,217] Trial 80 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:33,218] Trial 80 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:33,227] Trial 81 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:33,228] Trial 81 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:33,239] Trial 82 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:33,239] Trial 82 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:33,255] Trial 83 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:33,255] Trial 83 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:33,267] Trial 84 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:33,267] Trial 84 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:33,278] Trial 85 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:33,278] Trial 85 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:33,289] Trial 86 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:33,289] Trial 86 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:33,300] Trial 87 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:33,300] Trial 87 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:33,310] Trial 88 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:33,311] Trial 88 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:33,321] Trial 89 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:33,322] Trial 89 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:33,333] Trial 90 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:33,334] Trial 90 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:33,345] Trial 91 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:33,345] Trial 91 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:33,356] Trial 92 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:33,357] Trial 92 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:33,367] Trial 93 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:33,367] Trial 93 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:33,376] Trial 94 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:33,377] Trial 94 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:33,389] Trial 95 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:33,389] Trial 95 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:33,401] Trial 96 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:33,401] Trial 96 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:33,413] Trial 97 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:33,413] Trial 97 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:33,426] Trial 98 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:33,427] Trial 98 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:33,438] Trial 99 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:33,438] Trial 99 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:33,449] Trial 100 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:33,450] Trial 100 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:33,461] Trial 101 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:33,461] Trial 101 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:33,472] Trial 102 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:33,472] Trial 102 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:33,483] Trial 103 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:33,484] Trial 103 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:33,495] Trial 104 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:33,495] Trial 104 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:33,506] Trial 105 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:33,506] Trial 105 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:33,517] Trial 106 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:33,517] Trial 106 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:33,529] Trial 107 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:33,530] Trial 107 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:33,540] Trial 108 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:33,540] Trial 108 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:33,550] Trial 109 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:33,550] Trial 109 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:33,562] Trial 110 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:33,563] Trial 110 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:33,574] Trial 111 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:33,574] Trial 111 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:33,590] Trial 112 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:33,591] Trial 112 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:33,602] Trial 113 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:33,602] Trial 113 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:33,613] Trial 114 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:33,614] Trial 114 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:33,624] Trial 115 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:33,624] Trial 115 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:33,635] Trial 116 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:33,635] Trial 116 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:33,646] Trial 117 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:33,646] Trial 117 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:33,657] Trial 118 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:33,658] Trial 118 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:33,668] Trial 119 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:33,669] Trial 119 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:33,680] Trial 120 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:33,681] Trial 120 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:33,690] Trial 121 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:33,691] Trial 121 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:33,702] Trial 122 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:33,702] Trial 122 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:33,713] Trial 123 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:33,713] Trial 123 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:33,726] Trial 124 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:33,726] Trial 124 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:33,737] Trial 125 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:33,737] Trial 125 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:33,749] Trial 126 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:33,749] Trial 126 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:33,761] Trial 127 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:33,762] Trial 127 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:33,774] Trial 128 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:33,774] Trial 128 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:33,786] Trial 129 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:33,787] Trial 129 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:33,797] Trial 130 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:33,797] Trial 130 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:33,808] Trial 131 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:33,808] Trial 131 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:33,819] Trial 132 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:33,819] Trial 132 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:33,830] Trial 133 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:33,831] Trial 133 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:33,842] Trial 134 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:33,843] Trial 134 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:33,852] Trial 135 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:33,853] Trial 135 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:33,862] Trial 136 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:33,863] Trial 136 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:33,873] Trial 137 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:33,873] Trial 137 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:33,883] Trial 138 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:33,883] Trial 138 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:33,893] Trial 139 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:33,893] Trial 139 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:33,904] Trial 140 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:33,904] Trial 140 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:33,917] Trial 141 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:33,917] Trial 141 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:33,927] Trial 142 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:33,927] Trial 142 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:33,938] Trial 143 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:33,938] Trial 143 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:33,948] Trial 144 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:33,948] Trial 144 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:33,958] Trial 145 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:33,958] Trial 145 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:33,968] Trial 146 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:33,969] Trial 146 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:33,979] Trial 147 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:33,979] Trial 147 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:33,988] Trial 148 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:33,988] Trial 148 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:33,999] Trial 149 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:33,999] Trial 149 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:34,011] Trial 150 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:34,012] Trial 150 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:34,025] Trial 151 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:34,026] Trial 151 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:34,035] Trial 152 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:34,035] Trial 152 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:34,045] Trial 153 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:34,046] Trial 153 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:34,055] Trial 154 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:34,056] Trial 154 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:34,064] Trial 155 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:34,065] Trial 155 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:34,074] Trial 156 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:34,074] Trial 156 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:34,085] Trial 157 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:34,085] Trial 157 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:34,094] Trial 158 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:34,094] Trial 158 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:34,104] Trial 159 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:34,104] Trial 159 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:34,115] Trial 160 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:34,115] Trial 160 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:34,124] Trial 161 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:34,124] Trial 161 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:34,134] Trial 162 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:34,135] Trial 162 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:34,145] Trial 163 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:34,145] Trial 163 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:34,154] Trial 164 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:34,155] Trial 164 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:34,165] Trial 165 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:34,165] Trial 165 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:34,175] Trial 166 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:34,176] Trial 166 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:34,185] Trial 167 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:34,185] Trial 167 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:34,196] Trial 168 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:34,197] Trial 168 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:34,206] Trial 169 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:34,207] Trial 169 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:34,215] Trial 170 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:34,216] Trial 170 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:34,225] Trial 171 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:34,226] Trial 171 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:34,235] Trial 172 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:34,236] Trial 172 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:34,247] Trial 173 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:34,247] Trial 173 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:34,258] Trial 174 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:34,258] Trial 174 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:34,268] Trial 175 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:34,268] Trial 175 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:34,278] Trial 176 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:34,278] Trial 176 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:34,288] Trial 177 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:34,289] Trial 177 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:34,299] Trial 178 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:34,299] Trial 178 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:34,310] Trial 179 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:34,310] Trial 179 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:34,319] Trial 180 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:34,320] Trial 180 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:34,329] Trial 181 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:34,330] Trial 181 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:34,339] Trial 182 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:34,340] Trial 182 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:34,349] Trial 183 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:34,349] Trial 183 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:34,358] Trial 184 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:34,359] Trial 184 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:34,369] Trial 185 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:34,369] Trial 185 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:34,378] Trial 186 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:34,379] Trial 186 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:34,388] Trial 187 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:34,389] Trial 187 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:34,408] Trial 188 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:34,409] Trial 188 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:34,421] Trial 189 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:34,421] Trial 189 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:34,432] Trial 190 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:34,433] Trial 190 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:34,442] Trial 191 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:34,442] Trial 191 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:34,452] Trial 192 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:34,452] Trial 192 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:34,462] Trial 193 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:34,463] Trial 193 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:34,473] Trial 194 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:34,474] Trial 194 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:34,484] Trial 195 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:34,485] Trial 195 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:34,494] Trial 196 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:34,495] Trial 196 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:34,505] Trial 197 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:34,505] Trial 197 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:34,515] Trial 198 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:34,515] Trial 198 failed with value <coroutine object objective at 0x17fad5b60>.\n",
"[W 2024-05-21 19:14:34,524] Trial 199 failed with parameters: {} because of the following error: The value <coroutine object objective at 0x17fad5b60> could not be cast to float.\n",
"[W 2024-05-21 19:14:34,525] Trial 199 failed with value <coroutine object objective at 0x17fad5b60>.\n"
]
}
],
"source": [
"# Not let's run the optimization!\n",
"start = \"2024-05-01\"\n",
"end = \"2024-05-20\"\n",
"backtesting_resolution = \"1m\"\n",
"n_trials = 200\n",
"study.optimize(lambda trial: objective(trial, start, end, backtesting_resolution), n_trials=n_trials)\n"
],
"metadata": {
"collapsed": false,
"ExecuteTime": {
"end_time": "2024-05-22T00:14:34.527783Z",
"start_time": "2024-05-22T00:14:32.359422Z"
}
}
},
{
"cell_type": "code",
"execution_count": null,
"outputs": [],
"source": [],
"metadata": {
"collapsed": false
}
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 2
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython2",
"version": "2.7.6"
}
},
"nbformat": 4,
"nbformat_minor": 0
}

File diff suppressed because one or more lines are too long

View File

@@ -1,591 +0,0 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"import os\n",
"import sys\n",
"\n",
"root_path = os.path.abspath(os.path.join(os.getcwd(), '../../..'))\n",
"sys.path.append(root_path)"
]
},
{
"cell_type": "code",
"execution_count": null,
"outputs": [],
"source": [
"from decimal import Decimal\n",
"\n",
"# Market configuration\n",
"exchange = \"binance_perpetual\"\n",
"trading_pair = \"WLD-USDT\"\n",
"interval = \"3m\"\n",
"\n",
"# Account configuration\n",
"initial_portfolio_usd = 1000\n",
"order_amount = Decimal(\"25\")\n",
"n_levels = 1\n",
"leverage = 20\n",
"trade_cost = 0.0006\n",
"\n",
"# Backtest period\n",
"start = \"2023-01-01\"\n",
"end = \"2024-01-02\"\n",
"\n",
"# Triple barrier configuration\n",
"stop_loss = Decimal(\"0.015\")\n",
"take_profit = Decimal(\"0.03\")\n",
"time_limit = 60 * 60 * 12 # 12 hours\n",
"trailing_stop_activation_price_delta = Decimal(\"0.008\")\n",
"trailing_stop_trailing_delta = Decimal(\"0.004\")"
],
"metadata": {
"collapsed": false
}
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"from hummingbot.smart_components.utils.order_level_builder import OrderLevelBuilder\n",
"from hummingbot.smart_components.strategy_frameworks.data_types import (\n",
" TripleBarrierConf\n",
")\n",
"\n",
"# Building the order levels\n",
"order_level_builder = OrderLevelBuilder(n_levels=n_levels)\n",
"order_levels = order_level_builder.build_order_levels(\n",
" amounts=order_amount,\n",
" spreads=Decimal(\"0\"),\n",
" # for directional strategies we don't need spreads since we are going to use market orders to enter\n",
" triple_barrier_confs=TripleBarrierConf(\n",
" stop_loss=stop_loss, take_profit=take_profit, time_limit=time_limit,\n",
" trailing_stop_activation_price_delta=trailing_stop_activation_price_delta,\n",
" trailing_stop_trailing_delta=trailing_stop_trailing_delta),\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"# Let's inpect the order levels\n",
"order_levels"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"import sys\n",
"from hummingbot.data_feed.candles_feed.candles_factory import CandlesConfig\n",
"from quants_lab.controllers.supertrend import SuperTrend, SuperTrendConfig\n",
"\n",
"# Controller configuration\n",
"length = 100\n",
"multiplier = 3.0\n",
"percentage_threshold = 0.01\n",
"\n",
"# Creating the instance of the configuration and the controller\n",
"config = SuperTrendConfig(\n",
" exchange=exchange,\n",
" trading_pair=trading_pair,\n",
" order_levels=order_levels,\n",
" candles_config=[\n",
" CandlesConfig(connector=exchange, trading_pair=trading_pair, interval=interval, max_records=sys.maxsize),\n",
" ],\n",
" leverage=leverage,\n",
" length=length,\n",
" multiplier=multiplier,\n",
" percentage_threshold=percentage_threshold,\n",
")\n",
"controller = SuperTrend(config=config)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"from quants_lab.strategy.strategy_analysis import StrategyAnalysis\n",
"\n",
"from hummingbot.smart_components.strategy_frameworks.directional_trading.directional_trading_backtesting_engine import \\\n",
" DirectionalTradingBacktestingEngine\n",
"\n",
"# Creating the backtesting engine and loading the historical data\n",
"engine = DirectionalTradingBacktestingEngine(controller=controller)\n",
"engine.load_controller_data(\"../../../data/candles\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"# Let's see what is inside the candles of the controller\n",
"engine.controller.candles"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"engine.controller.candles[0].candles_df"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"# Let's understand what is inside the processed data since this is what we are going to use when generating the signal ;)\n",
"engine.controller.get_processed_data()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"# Let's run the backtesting\n",
"\n",
"backtesting_results = engine.run_backtesting(initial_portfolio_usd=initial_portfolio_usd,\n",
" trade_cost=trade_cost,\n",
" start=start, end=end)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"# Let's see what is inside the backtesting results\n",
"backtesting_results.keys()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"# now let's analyze each of the dataframes\n",
"\n",
"# 1. The processed data: this is the data that we are going to use to generate the signal\n",
"backtesting_results[\"processed_data\"]"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"# 2. The executors dataframe: this is the dataframe that contains the information of the orders that were executed\n",
"backtesting_results[\"executors_df\"]"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"# 3. The results dataframe: this is the dataframe that contains the information of the pnl of the strategy\n",
"backtesting_results[\"results\"]"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"# Now let's analyze the results using the StrategyAnalysis class\n",
"strategy_analysis = StrategyAnalysis(\n",
" positions=backtesting_results[\"executors_df\"],\n",
" candles_df=backtesting_results[\"processed_data\"],\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"# let's visualize the PNL over time of the strategy\n",
"strategy_analysis.pnl_over_time()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"strategy_analysis.create_base_figure(volume=False, positions=False, trade_pnl=True)\n",
"fig = strategy_analysis.figure()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"fig"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"# Now let's see how we can add the SuperTrend to the plot\n",
"\n",
"import plotly.graph_objects as go\n",
"\n",
"super_trend_long = strategy_analysis.candles_df[strategy_analysis.candles_df[f\"SUPERTd_{length}_{multiplier}\"] == 1]\n",
"super_trend_short = strategy_analysis.candles_df[strategy_analysis.candles_df[f\"SUPERTd_{length}_{multiplier}\"] == -1]\n",
"# Add the SuperTrend line\n",
"fig.add_trace(go.Scatter(x=super_trend_long.index, y=super_trend_long[f'SUPERT_{length}_{multiplier}'],\n",
" mode='markers',\n",
" name='SuperTrend Long',\n",
" line=dict(color=\"green\")),\n",
" row=1, col=1)\n",
"# Add the SuperTrend line\n",
"fig.add_trace(go.Scatter(x=super_trend_short.index, y=super_trend_short[f'SUPERT_{length}_{multiplier}'],\n",
" mode='markers',\n",
" name='SuperTrend Short',\n",
" line=dict(color=\"red\")),\n",
" row=1, col=1)\n",
"\n",
"fig"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"# To see the trades we will need to select a lower timeframe due the restrictions and speed of the plotly library\n",
"start_time = \"2023-11-03\"\n",
"end_time = \"2023-11-05\"\n",
"\n",
"processed_data_filtered = backtesting_results[\"processed_data\"][\n",
" (backtesting_results[\"processed_data\"][\"timestamp\"] >= start_time) &\n",
" (backtesting_results[\"processed_data\"][\"timestamp\"] <= end_time)\n",
"]\n",
"\n",
"executors_filtered = backtesting_results[\"executors_df\"][\n",
" (backtesting_results[\"executors_df\"][\"timestamp\"] >= start_time) &\n",
" (backtesting_results[\"executors_df\"][\"timestamp\"] <= end_time)\n",
"]"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"executors_filtered"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"\n",
"strategy_analysis = StrategyAnalysis(\n",
" positions=executors_filtered,\n",
" candles_df=processed_data_filtered,\n",
")\n",
"\n",
"strategy_analysis.create_base_figure(volume=False, positions=True, trade_pnl=True)\n",
"fig = strategy_analysis.figure()\n",
"super_trend_long = strategy_analysis.candles_df[strategy_analysis.candles_df[f\"SUPERTd_{length}_{multiplier}\"] == 1]\n",
"super_trend_short = strategy_analysis.candles_df[strategy_analysis.candles_df[f\"SUPERTd_{length}_{multiplier}\"] == -1]\n",
"# Add the SuperTrend line\n",
"fig.add_trace(go.Scatter(x=super_trend_long.index, y=super_trend_long[f'SUPERT_{length}_{multiplier}'],\n",
" mode='markers',\n",
" name='SuperTrend Long',\n",
" line=dict(color=\"green\")),\n",
" row=1, col=1)\n",
"# Add the SuperTrend line\n",
"fig.add_trace(go.Scatter(x=super_trend_short.index, y=super_trend_short[f'SUPERT_{length}_{multiplier}'],\n",
" mode='markers',\n",
" name='SuperTrend Short',\n",
" line=dict(color=\"red\")),\n",
" row=1, col=1)\n",
"fig"
]
},
{
"cell_type": "markdown",
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"source": [
"### Scatter of PNL per Trade\n",
"This bar chart illustrates the PNL for each individual trade. Positive PNLs are shown in green and negative PNLs in red, providing a clear view of profitable vs. unprofitable trades.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"import plotly.express as px\n",
"\n",
"executors_df = backtesting_results[\"executors_df\"]\n",
"\n",
"fig = px.scatter(executors_df, x=\"timestamp\", y='net_pnl_quote', title='PNL per Trade',\n",
" color='profitable', color_continuous_scale=['red', 'green'])\n",
"fig.show()"
]
},
{
"cell_type": "markdown",
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"source": [
"### Scatter Plot of Volume vs. PNL\n",
"This scatter plot explores the relationship between the trade volume and the PNL for each trade. It can reveal if larger volumes are associated with higher profits or losses.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"fig = px.scatter(executors_df, x='volume', y='net_pnl_quote', title='Trade Volume vs. PNL')\n",
"fig.show()"
]
},
{
"cell_type": "markdown",
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"source": [
"### Histogram of PNL Distribution\n",
"The histogram displays the distribution of PNL values across all trades. It helps in understanding the frequency and range of profit and loss outcomes.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"fig = px.histogram(executors_df, x='net_pnl_quote', title='PNL Distribution')\n",
"fig.show()\n"
]
},
{
"cell_type": "markdown",
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"source": [
"# Conclusion\n",
"We can see that the indicator has potential to bring good signals to trade and might be interesting to see how we can design a market maker that shifts the mid price based on this indicator.\n",
"A lot of the short signals are wrong but if we zoom in into the loss signals we can see that the losses are not that big and the wins are bigger and if we had implemented the trailing stop feature probably a lot of them are going to be profits."
]
},
{
"cell_type": "markdown",
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"source": [
"# Next steps\n",
"- Filter only the loss signals and understand what you can do to prevent them\n",
"- Try different configuration values for the indicator\n",
"- Test in multiple markets, pick mature markets like BTC-USDT or ETH-USDT and also volatile markets like DOGE-USDT or SHIB-USDT"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.13"
}
},
"nbformat": 4,
"nbformat_minor": 4
}

View File

@@ -1,183 +0,0 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"outputs": [],
"source": [
"import os\n",
"import sys\n",
"\n",
"root_path = os.path.abspath(os.path.join(os.getcwd(), '../../..'))\n",
"sys.path.append(root_path)"
],
"metadata": {
"collapsed": false
}
},
{
"cell_type": "code",
"execution_count": null,
"outputs": [],
"source": [
"import traceback\n",
"from decimal import Decimal\n",
"import pandas_ta as ta # noqa: F401\n",
"\n",
"from hummingbot.core.data_type.common import PositionMode, TradeType, OrderType\n",
"from hummingbot.data_feed.candles_feed.candles_factory import CandlesConfig\n",
"from hummingbot.smart_components.strategy_frameworks.data_types import TripleBarrierConf, OrderLevel\n",
"from hummingbot.smart_components.strategy_frameworks.directional_trading import DirectionalTradingBacktestingEngine\n",
"from hummingbot.smart_components.utils.config_encoder_decoder import ConfigEncoderDecoder\n",
"from optuna import TrialPruned\n",
"from hummingbot.smart_components.utils.order_level_builder import OrderLevelBuilder\n",
"\n",
"from quants_lab.controllers.supertrend import SuperTrend, SuperTrendConfig\n",
"\n",
"# To run an optimization with optuna we need to define the objective function that will be executed for each trial\n",
"\n",
"def objective(trial):\n",
" try:\n",
" # Market configuration\n",
" exchange = \"binance_perpetual\"\n",
" trading_pair = \"WLD-USDT\"\n",
" interval = \"3m\"\n",
"\n",
" # Account configuration\n",
" initial_portfolio_usd = 1000\n",
" order_amount = Decimal(\"25\")\n",
" n_levels = 1\n",
" leverage = 20\n",
" trade_cost = 0.0006\n",
"\n",
" # Backtest period\n",
" start = \"2023-01-01\"\n",
" end = \"2024-01-02\"\n",
"\n",
" # Triple barrier configuration\n",
" stop_loss = trial.suggest_float('stop_loss', 0.01, 0.02, step=0.01)\n",
" take_profit = trial.suggest_float('take_profit', 0.01, 0.04, step=0.01)\n",
" time_limit = 60 * 60 * 12 # 12 hours\n",
" trailing_stop_activation_price_delta = Decimal(\"0.008\")\n",
" trailing_stop_trailing_delta = Decimal(\"0.004\")\n",
"\n",
" length = trial.suggest_int('length', 20, 200, step=20)\n",
" multiplier = trial.suggest_float('multiplier', 2.0, 6.0, step=1.0)\n",
" percentage_threshold = trial.suggest_float('percentage_threshold', 0.01, 0.03, step=0.01)\n",
"\n",
" # Building the order levels\n",
" order_level_builder = OrderLevelBuilder(n_levels=n_levels)\n",
" order_levels = order_level_builder.build_order_levels(\n",
" amounts=order_amount,\n",
" spreads=Decimal(\"0\"),\n",
" triple_barrier_confs=TripleBarrierConf(\n",
" stop_loss=stop_loss, take_profit=take_profit, time_limit=time_limit,\n",
" trailing_stop_activation_price_delta=trailing_stop_activation_price_delta,\n",
" trailing_stop_trailing_delta=trailing_stop_trailing_delta),\n",
" )\n",
" config = SuperTrendConfig(\n",
" exchange=exchange,\n",
" trading_pair=trading_pair,\n",
" strategy_name='supertrend',\n",
" candles_config=[\n",
" CandlesConfig(connector=exchange, trading_pair=trading_pair,\n",
" interval=interval, max_records=sys.maxsize)\n",
" ],\n",
" order_levels=order_levels,\n",
" leverage=leverage,\n",
" position_mode=PositionMode.HEDGE,\n",
" length=length,\n",
" multiplier=multiplier,\n",
" percentage_threshold=percentage_threshold,\n",
"\n",
" )\n",
" controller = SuperTrend(config=config)\n",
" engine = DirectionalTradingBacktestingEngine(controller=controller)\n",
" engine.load_controller_data(\"../../../data/candles\")\n",
" backtesting_results = engine.run_backtesting(\n",
" initial_portfolio_usd=initial_portfolio_usd,\n",
" trade_cost=trade_cost,\n",
" start=start, end=end)\n",
"\n",
" strategy_analysis = backtesting_results[\"results\"]\n",
" encoder_decoder = ConfigEncoderDecoder(TradeType, OrderType, PositionMode)\n",
"\n",
" trial.set_user_attr(\"net_pnl_quote\", strategy_analysis[\"net_pnl_quote\"])\n",
" trial.set_user_attr(\"net_pnl_pct\", strategy_analysis[\"net_pnl\"])\n",
" trial.set_user_attr(\"max_drawdown_usd\", strategy_analysis[\"max_drawdown_usd\"])\n",
" trial.set_user_attr(\"max_drawdown_pct\", strategy_analysis[\"max_drawdown_pct\"])\n",
" trial.set_user_attr(\"sharpe_ratio\", strategy_analysis[\"sharpe_ratio\"])\n",
" trial.set_user_attr(\"accuracy\", strategy_analysis[\"accuracy\"])\n",
" trial.set_user_attr(\"total_positions\", strategy_analysis[\"total_positions\"])\n",
" trial.set_user_attr(\"profit_factor\", strategy_analysis[\"profit_factor\"])\n",
" trial.set_user_attr(\"duration_in_hours\", strategy_analysis[\"duration_minutes\"] / 60)\n",
" trial.set_user_attr(\"avg_trading_time_in_hours\", strategy_analysis[\"avg_trading_time_minutes\"] / 60)\n",
" trial.set_user_attr(\"win_signals\", strategy_analysis[\"win_signals\"])\n",
" trial.set_user_attr(\"loss_signals\", strategy_analysis[\"loss_signals\"])\n",
" trial.set_user_attr(\"config\", encoder_decoder.encode(config.dict()))\n",
" return strategy_analysis[\"net_pnl\"]\n",
" except Exception as e:\n",
" traceback.print_exc()\n",
" raise TrialPruned()\n"
],
"metadata": {
"collapsed": false
}
},
{
"cell_type": "code",
"execution_count": null,
"outputs": [],
"source": [
"import optuna\n",
"\n",
"# Now let's configure the parameters for the optimization\n",
"study_name = \"super_trend_optimization_1\"\n",
"storage= \"sqlite:///../../../data/backtesting/backtesting_report.db\"\n",
"\n",
"study = optuna.create_study(direction=\"maximize\", study_name=study_name,\n",
" storage=storage,\n",
" load_if_exists=True # If the study already exists, we load it\n",
" )"
],
"metadata": {
"collapsed": false
}
},
{
"cell_type": "code",
"execution_count": null,
"outputs": [],
"source": [
"# Not let's run the optimization!\n",
"\n",
"n_trials = 200\n",
"study.optimize(objective, n_trials=n_trials)"
],
"metadata": {
"collapsed": false
}
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 2
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython2",
"version": "2.7.6"
}
},
"nbformat": 4,
"nbformat_minor": 0
}

Some files were not shown because too many files have changed in this diff Show More