mirror of
https://github.com/aljazceru/hummingbot-dashboard.git
synced 2026-02-23 14:06:56 +01:00
Merge pull request #171 from hummingbot/development
sync / Dashboard development -> main
This commit is contained in:
75
.github/workflows/main.yml
vendored
75
.github/workflows/main.yml
vendored
@@ -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
33
.pre-commit-config.yaml
Normal 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]
|
||||
@@ -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)
|
||||
|
||||
36
Makefile
36
Makefile
@@ -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
|
||||
|
||||
@@ -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."""
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import re
|
||||
import time
|
||||
|
||||
from pycoingecko import CoinGeckoAPI
|
||||
import pandas as pd
|
||||
import re
|
||||
from pycoingecko import CoinGeckoAPI
|
||||
|
||||
|
||||
class CoinGeckoClient:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import pandas as pd
|
||||
import requests
|
||||
from glom import *
|
||||
from glom import glom
|
||||
|
||||
|
||||
class MinerClient:
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -27,3 +27,6 @@ dependencies:
|
||||
- streamlit-elements==0.1.*
|
||||
- streamlit-authenticator
|
||||
- pydantic==1.10.4
|
||||
- flake8
|
||||
- isort
|
||||
- pre-commit
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"})
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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.")
|
||||
|
||||
|
||||
|
||||
@@ -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}")
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import json
|
||||
|
||||
from streamlit_elements import mui
|
||||
|
||||
from .dashboard import Dashboard
|
||||
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"}):
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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")
|
||||
@@ -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()
|
||||
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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%"})
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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%")
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.")
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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.
|
||||
@@ -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!")
|
||||
@@ -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!")
|
||||
|
||||
@@ -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"])
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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!")
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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:",
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
from types import SimpleNamespace
|
||||
|
||||
import streamlit as st
|
||||
from streamlit_elements import elements, mui
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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="🙌")
|
||||
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
Inspect and analyze the orders and trades data contained in a Hummingbot strategy database
|
||||
@@ -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))
|
||||
@@ -1 +0,0 @@
|
||||
This page helps you load the database file of a Hummingbot strategy and analyze its performance.
|
||||
@@ -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")
|
||||
33
frontend/pages/permissions.py
Normal file
33
frontend/pages/permissions.py
Normal 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", "💰"),
|
||||
]
|
||||
@@ -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())
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
143
main.py
@@ -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
23
pyproject.toml
Normal 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" }] }
|
||||
]
|
||||
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
@@ -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
@@ -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
|
||||
}
|
||||
@@ -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
Reference in New Issue
Block a user