From 24617500d15619445386ce1b443675e7a239883f Mon Sep 17 00:00:00 2001 From: cardosofede Date: Thu, 9 May 2024 10:32:21 -0300 Subject: [PATCH] (feat) refactor file structure --- Makefile | 6 +- {ui_components => backend}/__init__.py | 0 environment_conda.yml | 2 +- .../README.md => frontend/__init__.py | 0 frontend/components/__init__.py | 0 .../components}/bot_performance_card.py | 2 +- .../components}/bot_performance_card_v2.py | 6 +- .../components}/bots_file_explorer.py | 2 +- .../components}/card.py | 2 +- .../components}/controllers_file_explorer.py | 4 +- .../components}/dashboard.py | 0 .../components}/datagrid.py | 0 .../directional_strategy_creation_card.py | 0 .../components}/editor.py | 0 .../components}/exited_bot_card.py | 7 +- .../components}/file_explorer_base.py | 0 .../components}/launch_bot_card.py | 0 .../components}/launch_broker_card.py | 0 .../components}/launch_master_bot_card.py | 0 .../components}/launch_strategy_v2.py | 0 .../components}/master_conf_file_explorer.py | 2 +- .../components}/media_player.py | 0 .../components}/optimization_creation_card.py | 0 .../components}/optimization_run_card.py | 0 .../optimizations_file_explorer.py | 2 +- .../components}/st_inputs.py | 0 frontend/pages/__init__.py | 0 .../pages}/backtest_analyze/README.md | 0 frontend/pages/backtest_analyze/__init__.py | 0 .../pages}/backtest_analyze/analyze.py | 0 .../pages}/backtest_create/README.md | 0 frontend/pages/backtest_create/__init__.py | 0 .../pages}/backtest_create/create.py | 8 +- .../pages}/backtest_optimize/README.md | 0 frontend/pages/backtest_optimize/__init__.py | 0 .../pages}/backtest_optimize/optimize.py | 10 +- .../pages}/bollinger_v1/README.md | 0 frontend/pages/bollinger_v1/__init__.py | 0 {pages => frontend/pages}/bollinger_v1/app.py | 0 .../pages}/bot_orchestration/README.md | 0 frontend/pages/bot_orchestration/__init__.py | 0 .../pages}/bot_orchestration/app.py | 4 +- .../pages}/data_download_candles/README.md | 0 .../pages/data_download_candles/__init__.py | 0 .../pages}/data_download_candles/app.py | 0 .../pages}/db_inspector/README.md | 0 frontend/pages/db_inspector/__init__.py | 0 {pages => frontend/pages}/db_inspector/app.py | 0 .../pages}/dman_maker_v2/README.md | 0 frontend/pages/dman_maker_v2/__init__.py | 0 .../pages}/dman_maker_v2/app.py | 2 +- {pages => frontend/pages}/dman_v5/README.md | 0 frontend/pages/dman_v5/__init__.py | 0 frontend/pages/dman_v5/app.py | 149 ++++++++ .../pages/dynamic_position_builder/README.md | 0 .../dynamic_position_builder/__init__.py | 0 .../pages/dynamic_position_builder/app.py | 220 +++++++++++ .../pages}/file_manager/README.md | 0 frontend/pages/file_manager/__init__.py | 0 {pages => frontend/pages}/file_manager/app.py | 6 +- .../pages/kalman_filter_v1}/README.md | 0 frontend/pages/kalman_filter_v1/__init__.py | 0 frontend/pages/kalman_filter_v1/app.py | 226 ++++++++++++ .../pages}/launch_bot/README.md | 0 frontend/pages/launch_bot/__init__.py | 0 {pages => frontend/pages}/launch_bot/app.py | 4 +- .../pages/macd_bb_v1}/README.md | 0 frontend/pages/macd_bb_v1/__init__.py | 0 {pages => frontend/pages}/macd_bb_v1/app.py | 0 .../pages}/master_conf/README.md | 0 frontend/pages/master_conf/__init__.py | 0 {pages => frontend/pages}/master_conf/app.py | 12 +- .../pages/pmm_simple}/README.md | 0 frontend/pages/pmm_simple/__init__.py | 0 {pages => frontend/pages}/pmm_simple/app.py | 7 +- frontend/pages/position_builder/README.md | 0 frontend/pages/position_builder/__init__.py | 0 .../pages}/position_builder/app.py | 6 +- .../pages}/reference_data/7_📋_Data.py | 0 frontend/pages/reference_data/__init__.py | 0 .../pages}/strategy_performance/README.md | 0 .../pages/strategy_performance/__init__.py | 0 .../pages}/strategy_performance/app.py | 0 .../pages}/token_spreads/README.md | 0 frontend/pages/token_spreads/__init__.py | 0 .../pages}/token_spreads/app.py | 0 .../pages/trend_follower_v1}/README.md | 0 frontend/pages/trend_follower_v1/__init__.py | 0 .../pages}/trend_follower_v1/app.py | 0 .../pages}/tvl_vs_mcap/README.md | 0 frontend/pages/tvl_vs_mcap/__init__.py | 0 {pages => frontend/pages}/tvl_vs_mcap/app.py | 0 frontend/pages/xemm_controller/README.md | 19 + frontend/pages/xemm_controller/__init__.py | 0 .../pages}/xemm_controller/app.py | 0 helpers/add_authemail.py | 27 -- helpers/edit_authadmin_password.py | 26 -- hummingbot_files/bots/.gitignore | 1 - .../conf/.password_verification | 1 - .../bots/data_downloader/conf/conf_client.yml | 199 ---------- .../conf/conf_fee_overrides.yml | 340 ----------------- .../data_downloader/conf/hummingbot_logs.yml | 83 ----- .../bots/data_downloader/conf_client.yml | 194 ---------- .../scripts/download_candles.py | 61 ---- .../compose_files/broker-compose.yml | 43 --- .../compose_files/data-downloader-compose.yml | 23 -- .../controller_configs/.gitignore | 1 - .../data_downloader_config.yml | 4 - .../conf/.password_verification | 1 - .../master_bot_conf/conf/conf_client.yml | 199 ---------- .../conf/conf_fee_overrides.yml | 340 ----------------- .../master_bot_conf/conf/hummingbot_logs.yml | 83 ----- .../scripts/download_candles.py | 61 ---- .../scripts/download_order_book_and_trades.py | 99 ----- .../master_bot_conf/scripts/fixed_grid.py | 341 ------------------ .../scripts/simple_arbitrage_example.py | 193 ---------- .../scripts/simple_pmm_example.py | 77 ---- .../scripts/simple_rsi_example.py | 259 ------------- .../scripts/simple_vwap_example.py | 184 ---------- .../scripts/simple_xemm_example.py | 204 ----------- .../scripts/strategy_v2_launcher.py | 110 ------ .../v2_directional-trading_macd_bb_v1.py | 91 ----- .../scripts/v2_market-making_dman_composed.py | 145 -------- ...v2_market-making_dman_v1_multiple_pairs.py | 133 ------- ...v2_market-making_dman_v2_multiple_pairs.py | 139 ------- ...v2_market-making_dman_v3_multiple_pairs.py | 141 -------- main.py | 40 +- .../01_strategy_design_dman_maker.ipynb | 48 +-- .../strategy/directional_strategy_base.py | 94 ----- utils/hummingbot_processes.py | 4 +- 130 files changed, 701 insertions(+), 3996 deletions(-) rename {ui_components => backend}/__init__.py (100%) rename pages/position_builder/README.md => frontend/__init__.py (100%) create mode 100644 frontend/components/__init__.py rename {ui_components => frontend/components}/bot_performance_card.py (99%) rename {ui_components => frontend/components}/bot_performance_card_v2.py (98%) rename {ui_components => frontend/components}/bots_file_explorer.py (95%) rename {ui_components => frontend/components}/card.py (95%) rename {ui_components => frontend/components}/controllers_file_explorer.py (90%) rename {ui_components => frontend/components}/dashboard.py (100%) rename {ui_components => frontend/components}/datagrid.py (100%) rename {ui_components => frontend/components}/directional_strategy_creation_card.py (100%) rename {ui_components => frontend/components}/editor.py (100%) rename {ui_components => frontend/components}/exited_bot_card.py (89%) rename {ui_components => frontend/components}/file_explorer_base.py (100%) rename {ui_components => frontend/components}/launch_bot_card.py (100%) rename {ui_components => frontend/components}/launch_broker_card.py (100%) rename {ui_components => frontend/components}/launch_master_bot_card.py (100%) rename {ui_components => frontend/components}/launch_strategy_v2.py (100%) rename {ui_components => frontend/components}/master_conf_file_explorer.py (97%) rename {ui_components => frontend/components}/media_player.py (100%) rename {ui_components => frontend/components}/optimization_creation_card.py (100%) rename {ui_components => frontend/components}/optimization_run_card.py (100%) rename {ui_components => frontend/components}/optimizations_file_explorer.py (92%) rename {ui_components => frontend/components}/st_inputs.py (100%) create mode 100644 frontend/pages/__init__.py rename {pages => frontend/pages}/backtest_analyze/README.md (100%) create mode 100644 frontend/pages/backtest_analyze/__init__.py rename {pages => frontend/pages}/backtest_analyze/analyze.py (100%) rename {pages => frontend/pages}/backtest_create/README.md (100%) create mode 100644 frontend/pages/backtest_create/__init__.py rename {pages => frontend/pages}/backtest_create/create.py (84%) rename {pages => frontend/pages}/backtest_optimize/README.md (100%) create mode 100644 frontend/pages/backtest_optimize/__init__.py rename {pages => frontend/pages}/backtest_optimize/optimize.py (85%) rename {pages => frontend/pages}/bollinger_v1/README.md (100%) create mode 100644 frontend/pages/bollinger_v1/__init__.py rename {pages => frontend/pages}/bollinger_v1/app.py (100%) rename {pages => frontend/pages}/bot_orchestration/README.md (100%) create mode 100644 frontend/pages/bot_orchestration/__init__.py rename {pages => frontend/pages}/bot_orchestration/app.py (93%) rename {pages => frontend/pages}/data_download_candles/README.md (100%) create mode 100644 frontend/pages/data_download_candles/__init__.py rename {pages => frontend/pages}/data_download_candles/app.py (100%) rename {pages => frontend/pages}/db_inspector/README.md (100%) create mode 100644 frontend/pages/db_inspector/__init__.py rename {pages => frontend/pages}/db_inspector/app.py (100%) rename {pages => frontend/pages}/dman_maker_v2/README.md (100%) create mode 100644 frontend/pages/dman_maker_v2/__init__.py rename {pages => frontend/pages}/dman_maker_v2/app.py (99%) rename {pages => frontend/pages}/dman_v5/README.md (100%) create mode 100644 frontend/pages/dman_v5/__init__.py create mode 100644 frontend/pages/dman_v5/app.py create mode 100644 frontend/pages/dynamic_position_builder/README.md create mode 100644 frontend/pages/dynamic_position_builder/__init__.py create mode 100644 frontend/pages/dynamic_position_builder/app.py rename {pages => frontend/pages}/file_manager/README.md (100%) create mode 100644 frontend/pages/file_manager/__init__.py rename {pages => frontend/pages}/file_manager/app.py (87%) rename {pages/macd_bb_v1 => frontend/pages/kalman_filter_v1}/README.md (100%) create mode 100644 frontend/pages/kalman_filter_v1/__init__.py create mode 100644 frontend/pages/kalman_filter_v1/app.py rename {pages => frontend/pages}/launch_bot/README.md (100%) create mode 100644 frontend/pages/launch_bot/__init__.py rename {pages => frontend/pages}/launch_bot/app.py (90%) rename {pages/pmm_simple => frontend/pages/macd_bb_v1}/README.md (100%) create mode 100644 frontend/pages/macd_bb_v1/__init__.py rename {pages => frontend/pages}/macd_bb_v1/app.py (100%) rename {pages => frontend/pages}/master_conf/README.md (100%) create mode 100644 frontend/pages/master_conf/__init__.py rename {pages => frontend/pages}/master_conf/app.py (80%) rename {pages/trend_follower_v1 => frontend/pages/pmm_simple}/README.md (100%) create mode 100644 frontend/pages/pmm_simple/__init__.py rename {pages => frontend/pages}/pmm_simple/app.py (97%) create mode 100644 frontend/pages/position_builder/README.md create mode 100644 frontend/pages/position_builder/__init__.py rename {pages => frontend/pages}/position_builder/app.py (98%) rename {pages => frontend/pages}/reference_data/7_📋_Data.py (100%) create mode 100644 frontend/pages/reference_data/__init__.py rename {pages => frontend/pages}/strategy_performance/README.md (100%) create mode 100644 frontend/pages/strategy_performance/__init__.py rename {pages => frontend/pages}/strategy_performance/app.py (100%) rename {pages => frontend/pages}/token_spreads/README.md (100%) create mode 100644 frontend/pages/token_spreads/__init__.py rename {pages => frontend/pages}/token_spreads/app.py (100%) rename {pages/xemm_controller => frontend/pages/trend_follower_v1}/README.md (100%) create mode 100644 frontend/pages/trend_follower_v1/__init__.py rename {pages => frontend/pages}/trend_follower_v1/app.py (100%) rename {pages => frontend/pages}/tvl_vs_mcap/README.md (100%) create mode 100644 frontend/pages/tvl_vs_mcap/__init__.py rename {pages => frontend/pages}/tvl_vs_mcap/app.py (100%) create mode 100644 frontend/pages/xemm_controller/README.md create mode 100644 frontend/pages/xemm_controller/__init__.py rename {pages => frontend/pages}/xemm_controller/app.py (100%) delete mode 100755 helpers/add_authemail.py delete mode 100644 helpers/edit_authadmin_password.py delete mode 100644 hummingbot_files/bots/.gitignore delete mode 100644 hummingbot_files/bots/data_downloader/conf/.password_verification delete mode 100644 hummingbot_files/bots/data_downloader/conf/conf_client.yml delete mode 100644 hummingbot_files/bots/data_downloader/conf/conf_fee_overrides.yml delete mode 100755 hummingbot_files/bots/data_downloader/conf/hummingbot_logs.yml delete mode 100644 hummingbot_files/bots/data_downloader/conf_client.yml delete mode 100644 hummingbot_files/bots/data_downloader/scripts/download_candles.py delete mode 100644 hummingbot_files/compose_files/broker-compose.yml delete mode 100644 hummingbot_files/compose_files/data-downloader-compose.yml delete mode 100644 hummingbot_files/controller_configs/.gitignore delete mode 100644 hummingbot_files/scripts_configs/data_downloader_config.yml delete mode 100644 hummingbot_files/templates/master_bot_conf/conf/.password_verification delete mode 100644 hummingbot_files/templates/master_bot_conf/conf/conf_client.yml delete mode 100644 hummingbot_files/templates/master_bot_conf/conf/conf_fee_overrides.yml delete mode 100755 hummingbot_files/templates/master_bot_conf/conf/hummingbot_logs.yml delete mode 100644 hummingbot_files/templates/master_bot_conf/scripts/download_candles.py delete mode 100644 hummingbot_files/templates/master_bot_conf/scripts/download_order_book_and_trades.py delete mode 100644 hummingbot_files/templates/master_bot_conf/scripts/fixed_grid.py delete mode 100644 hummingbot_files/templates/master_bot_conf/scripts/simple_arbitrage_example.py delete mode 100644 hummingbot_files/templates/master_bot_conf/scripts/simple_pmm_example.py delete mode 100644 hummingbot_files/templates/master_bot_conf/scripts/simple_rsi_example.py delete mode 100644 hummingbot_files/templates/master_bot_conf/scripts/simple_vwap_example.py delete mode 100644 hummingbot_files/templates/master_bot_conf/scripts/simple_xemm_example.py delete mode 100644 hummingbot_files/templates/master_bot_conf/scripts/strategy_v2_launcher.py delete mode 100644 hummingbot_files/templates/master_bot_conf/scripts/v2_directional-trading_macd_bb_v1.py delete mode 100644 hummingbot_files/templates/master_bot_conf/scripts/v2_market-making_dman_composed.py delete mode 100644 hummingbot_files/templates/master_bot_conf/scripts/v2_market-making_dman_v1_multiple_pairs.py delete mode 100644 hummingbot_files/templates/master_bot_conf/scripts/v2_market-making_dman_v2_multiple_pairs.py delete mode 100644 hummingbot_files/templates/master_bot_conf/scripts/v2_market-making_dman_v3_multiple_pairs.py delete mode 100644 quants_lab/strategy/directional_strategy_base.py diff --git a/Makefile b/Makefile index 14be7c3..20683ea 100644 --- a/Makefile +++ b/Makefile @@ -6,14 +6,14 @@ run: streamlit run main.py -env_remove: +uninstall: conda env remove -n dashboard -env_create: +install: conda env create -f environment_conda.yml docker_build: - docker build -t dashboard:latest . + docker build -t hummingbot/dashboard:latest . docker_run: docker run -p 8501:8501 dashboard:latest \ No newline at end of file diff --git a/ui_components/__init__.py b/backend/__init__.py similarity index 100% rename from ui_components/__init__.py rename to backend/__init__.py diff --git a/environment_conda.yml b/environment_conda.yml index d31bbbb..6cabb9a 100644 --- a/environment_conda.yml +++ b/environment_conda.yml @@ -8,7 +8,7 @@ dependencies: - pydantic=1.9.* - pip - pip: - - hummingbot + - /Users/dardonacci/Documents/work/hummingbot/dist/hummingbot-20240429-cp310-cp310-macosx_11_0_arm64.whl - streamlit - watchdog - python-dotenv diff --git a/pages/position_builder/README.md b/frontend/__init__.py similarity index 100% rename from pages/position_builder/README.md rename to frontend/__init__.py diff --git a/frontend/components/__init__.py b/frontend/components/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ui_components/bot_performance_card.py b/frontend/components/bot_performance_card.py similarity index 99% rename from ui_components/bot_performance_card.py rename to frontend/components/bot_performance_card.py index 9941428..83ebb6d 100644 --- a/ui_components/bot_performance_card.py +++ b/frontend/components/bot_performance_card.py @@ -1,6 +1,6 @@ from docker_manager import DockerManager from streamlit_elements import mui, lazy -from ui_components.dashboard import Dashboard +from frontend.components.dashboard import Dashboard import streamlit as st import time from utils.os_utils import get_python_files_from_directory, get_yml_files_from_directory diff --git a/ui_components/bot_performance_card_v2.py b/frontend/components/bot_performance_card_v2.py similarity index 98% rename from ui_components/bot_performance_card_v2.py rename to frontend/components/bot_performance_card_v2.py index 27901f3..6466d9d 100644 --- a/ui_components/bot_performance_card_v2.py +++ b/frontend/components/bot_performance_card_v2.py @@ -1,9 +1,7 @@ -from streamlit_elements import mui, lazy +from streamlit_elements import mui from CONFIG import BACKEND_API_HOST, BACKEND_API_PORT -from ui_components.dashboard import Dashboard -import streamlit as st -import time +from frontend.components.dashboard import Dashboard import pandas as pd from utils.backend_api_client import BackendAPIClient diff --git a/ui_components/bots_file_explorer.py b/frontend/components/bots_file_explorer.py similarity index 95% rename from ui_components/bots_file_explorer.py rename to frontend/components/bots_file_explorer.py index 6b9da2e..9816122 100644 --- a/ui_components/bots_file_explorer.py +++ b/frontend/components/bots_file_explorer.py @@ -1,7 +1,7 @@ from streamlit_elements import mui import constants -from ui_components.file_explorer_base import FileExplorerBase +from frontend.components.file_explorer_base import FileExplorerBase from utils.os_utils import get_directories_from_directory, get_python_files_from_directory, \ get_yml_files_from_directory, get_log_files_from_directory diff --git a/ui_components/card.py b/frontend/components/card.py similarity index 95% rename from ui_components/card.py rename to frontend/components/card.py index 10b9a90..557a290 100644 --- a/ui_components/card.py +++ b/frontend/components/card.py @@ -1,5 +1,5 @@ from streamlit_elements import mui -from ui_components.dashboard import Dashboard +from frontend.components.dashboard import Dashboard class Card(Dashboard.Item): diff --git a/ui_components/controllers_file_explorer.py b/frontend/components/controllers_file_explorer.py similarity index 90% rename from ui_components/controllers_file_explorer.py rename to frontend/components/controllers_file_explorer.py index 3940c77..6fe4d88 100644 --- a/ui_components/controllers_file_explorer.py +++ b/frontend/components/controllers_file_explorer.py @@ -1,8 +1,8 @@ from streamlit_elements import mui import constants -from ui_components.file_explorer_base import FileExplorerBase -from utils.os_utils import get_python_files_from_directory, load_controllers +from frontend.components.file_explorer_base import FileExplorerBase +from utils.os_utils import load_controllers class ControllersFileExplorer(FileExplorerBase): diff --git a/ui_components/dashboard.py b/frontend/components/dashboard.py similarity index 100% rename from ui_components/dashboard.py rename to frontend/components/dashboard.py diff --git a/ui_components/datagrid.py b/frontend/components/datagrid.py similarity index 100% rename from ui_components/datagrid.py rename to frontend/components/datagrid.py diff --git a/ui_components/directional_strategy_creation_card.py b/frontend/components/directional_strategy_creation_card.py similarity index 100% rename from ui_components/directional_strategy_creation_card.py rename to frontend/components/directional_strategy_creation_card.py diff --git a/ui_components/editor.py b/frontend/components/editor.py similarity index 100% rename from ui_components/editor.py rename to frontend/components/editor.py diff --git a/ui_components/exited_bot_card.py b/frontend/components/exited_bot_card.py similarity index 89% rename from ui_components/exited_bot_card.py rename to frontend/components/exited_bot_card.py index 6d4c253..eb020f3 100644 --- a/ui_components/exited_bot_card.py +++ b/frontend/components/exited_bot_card.py @@ -1,11 +1,8 @@ from docker_manager import DockerManager -from streamlit_elements import mui, lazy -from ui_components.dashboard import Dashboard -import streamlit as st -import time +from streamlit_elements import mui +from frontend.components.dashboard import Dashboard from utils import os_utils -from utils.os_utils import get_python_files_from_directory, get_yml_files_from_directory class ExitedBotCard(Dashboard.Item): diff --git a/ui_components/file_explorer_base.py b/frontend/components/file_explorer_base.py similarity index 100% rename from ui_components/file_explorer_base.py rename to frontend/components/file_explorer_base.py diff --git a/ui_components/launch_bot_card.py b/frontend/components/launch_bot_card.py similarity index 100% rename from ui_components/launch_bot_card.py rename to frontend/components/launch_bot_card.py diff --git a/ui_components/launch_broker_card.py b/frontend/components/launch_broker_card.py similarity index 100% rename from ui_components/launch_broker_card.py rename to frontend/components/launch_broker_card.py diff --git a/ui_components/launch_master_bot_card.py b/frontend/components/launch_master_bot_card.py similarity index 100% rename from ui_components/launch_master_bot_card.py rename to frontend/components/launch_master_bot_card.py diff --git a/ui_components/launch_strategy_v2.py b/frontend/components/launch_strategy_v2.py similarity index 100% rename from ui_components/launch_strategy_v2.py rename to frontend/components/launch_strategy_v2.py diff --git a/ui_components/master_conf_file_explorer.py b/frontend/components/master_conf_file_explorer.py similarity index 97% rename from ui_components/master_conf_file_explorer.py rename to frontend/components/master_conf_file_explorer.py index e395f48..a4cf8eb 100644 --- a/ui_components/master_conf_file_explorer.py +++ b/frontend/components/master_conf_file_explorer.py @@ -1,7 +1,7 @@ from streamlit_elements import mui import constants -from ui_components.file_explorer_base import FileExplorerBase +from frontend.components.file_explorer_base import FileExplorerBase from utils.os_utils import get_directories_from_directory, get_python_files_from_directory, \ get_yml_files_from_directory, get_log_files_from_directory diff --git a/ui_components/media_player.py b/frontend/components/media_player.py similarity index 100% rename from ui_components/media_player.py rename to frontend/components/media_player.py diff --git a/ui_components/optimization_creation_card.py b/frontend/components/optimization_creation_card.py similarity index 100% rename from ui_components/optimization_creation_card.py rename to frontend/components/optimization_creation_card.py diff --git a/ui_components/optimization_run_card.py b/frontend/components/optimization_run_card.py similarity index 100% rename from ui_components/optimization_run_card.py rename to frontend/components/optimization_run_card.py diff --git a/ui_components/optimizations_file_explorer.py b/frontend/components/optimizations_file_explorer.py similarity index 92% rename from ui_components/optimizations_file_explorer.py rename to frontend/components/optimizations_file_explorer.py index c0354ab..c207d62 100644 --- a/ui_components/optimizations_file_explorer.py +++ b/frontend/components/optimizations_file_explorer.py @@ -1,7 +1,7 @@ from streamlit_elements import mui import constants -from ui_components.file_explorer_base import FileExplorerBase +from frontend.components.file_explorer_base import FileExplorerBase from utils.os_utils import get_python_files_from_directory diff --git a/ui_components/st_inputs.py b/frontend/components/st_inputs.py similarity index 100% rename from ui_components/st_inputs.py rename to frontend/components/st_inputs.py diff --git a/frontend/pages/__init__.py b/frontend/pages/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pages/backtest_analyze/README.md b/frontend/pages/backtest_analyze/README.md similarity index 100% rename from pages/backtest_analyze/README.md rename to frontend/pages/backtest_analyze/README.md diff --git a/frontend/pages/backtest_analyze/__init__.py b/frontend/pages/backtest_analyze/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pages/backtest_analyze/analyze.py b/frontend/pages/backtest_analyze/analyze.py similarity index 100% rename from pages/backtest_analyze/analyze.py rename to frontend/pages/backtest_analyze/analyze.py diff --git a/pages/backtest_create/README.md b/frontend/pages/backtest_create/README.md similarity index 100% rename from pages/backtest_create/README.md rename to frontend/pages/backtest_create/README.md diff --git a/frontend/pages/backtest_create/__init__.py b/frontend/pages/backtest_create/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pages/backtest_create/create.py b/frontend/pages/backtest_create/create.py similarity index 84% rename from pages/backtest_create/create.py rename to frontend/pages/backtest_create/create.py index 4e6322a..754ee4a 100644 --- a/pages/backtest_create/create.py +++ b/frontend/pages/backtest_create/create.py @@ -3,10 +3,10 @@ from types import SimpleNamespace import streamlit as st from streamlit_elements import elements, mui -from ui_components.dashboard import Dashboard -from ui_components.controllers_file_explorer import ControllersFileExplorer -from ui_components.directional_strategy_creation_card import DirectionalStrategyCreationCard -from ui_components.editor import Editor +from frontend.components.dashboard import Dashboard +from frontend.components.controllers_file_explorer import ControllersFileExplorer +from frontend.components.directional_strategy_creation_card import DirectionalStrategyCreationCard +from frontend.components.editor import Editor from utils.st_utils import initialize_st_page diff --git a/pages/backtest_optimize/README.md b/frontend/pages/backtest_optimize/README.md similarity index 100% rename from pages/backtest_optimize/README.md rename to frontend/pages/backtest_optimize/README.md diff --git a/frontend/pages/backtest_optimize/__init__.py b/frontend/pages/backtest_optimize/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pages/backtest_optimize/optimize.py b/frontend/pages/backtest_optimize/optimize.py similarity index 85% rename from pages/backtest_optimize/optimize.py rename to frontend/pages/backtest_optimize/optimize.py index f601d75..861b862 100644 --- a/pages/backtest_optimize/optimize.py +++ b/frontend/pages/backtest_optimize/optimize.py @@ -5,11 +5,11 @@ from types import SimpleNamespace import streamlit as st from streamlit_elements import elements, mui -from ui_components.dashboard import Dashboard -from ui_components.editor import Editor -from ui_components.optimization_creation_card import OptimizationCreationCard -from ui_components.optimization_run_card import OptimizationRunCard -from ui_components.optimizations_file_explorer import OptimizationsStrategiesFileExplorer +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 utils import os_utils from utils.st_utils import initialize_st_page diff --git a/pages/bollinger_v1/README.md b/frontend/pages/bollinger_v1/README.md similarity index 100% rename from pages/bollinger_v1/README.md rename to frontend/pages/bollinger_v1/README.md diff --git a/frontend/pages/bollinger_v1/__init__.py b/frontend/pages/bollinger_v1/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pages/bollinger_v1/app.py b/frontend/pages/bollinger_v1/app.py similarity index 100% rename from pages/bollinger_v1/app.py rename to frontend/pages/bollinger_v1/app.py diff --git a/pages/bot_orchestration/README.md b/frontend/pages/bot_orchestration/README.md similarity index 100% rename from pages/bot_orchestration/README.md rename to frontend/pages/bot_orchestration/README.md diff --git a/frontend/pages/bot_orchestration/__init__.py b/frontend/pages/bot_orchestration/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pages/bot_orchestration/app.py b/frontend/pages/bot_orchestration/app.py similarity index 93% rename from pages/bot_orchestration/app.py rename to frontend/pages/bot_orchestration/app.py index a7289da..177243d 100644 --- a/pages/bot_orchestration/app.py +++ b/frontend/pages/bot_orchestration/app.py @@ -2,8 +2,8 @@ import streamlit as st from streamlit_elements import elements, mui from CONFIG import BACKEND_API_HOST, BACKEND_API_PORT -from ui_components.bot_performance_card_v2 import BotPerformanceCardV2 -from ui_components.dashboard import Dashboard +from frontend.components.bot_performance_card_v2 import BotPerformanceCardV2 +from frontend.components.dashboard import Dashboard from utils.backend_api_client import BackendAPIClient from utils.st_utils import initialize_st_page diff --git a/pages/data_download_candles/README.md b/frontend/pages/data_download_candles/README.md similarity index 100% rename from pages/data_download_candles/README.md rename to frontend/pages/data_download_candles/README.md diff --git a/frontend/pages/data_download_candles/__init__.py b/frontend/pages/data_download_candles/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pages/data_download_candles/app.py b/frontend/pages/data_download_candles/app.py similarity index 100% rename from pages/data_download_candles/app.py rename to frontend/pages/data_download_candles/app.py diff --git a/pages/db_inspector/README.md b/frontend/pages/db_inspector/README.md similarity index 100% rename from pages/db_inspector/README.md rename to frontend/pages/db_inspector/README.md diff --git a/frontend/pages/db_inspector/__init__.py b/frontend/pages/db_inspector/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pages/db_inspector/app.py b/frontend/pages/db_inspector/app.py similarity index 100% rename from pages/db_inspector/app.py rename to frontend/pages/db_inspector/app.py diff --git a/pages/dman_maker_v2/README.md b/frontend/pages/dman_maker_v2/README.md similarity index 100% rename from pages/dman_maker_v2/README.md rename to frontend/pages/dman_maker_v2/README.md diff --git a/frontend/pages/dman_maker_v2/__init__.py b/frontend/pages/dman_maker_v2/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pages/dman_maker_v2/app.py b/frontend/pages/dman_maker_v2/app.py similarity index 99% rename from pages/dman_maker_v2/app.py rename to frontend/pages/dman_maker_v2/app.py index 013c829..86a7af1 100644 --- a/pages/dman_maker_v2/app.py +++ b/frontend/pages/dman_maker_v2/app.py @@ -7,7 +7,7 @@ import yaml from CONFIG import BACKEND_API_HOST, BACKEND_API_PORT from utils.backend_api_client import BackendAPIClient from utils.st_utils import initialize_st_page -from ui_components.st_inputs import normalize, distribution_inputs, get_distribution +from frontend.components.st_inputs import normalize, distribution_inputs, get_distribution # Initialize the Streamlit page initialize_st_page(title="D-Man Maker V2", icon="🧙‍♂️", initial_sidebar_state="collapsed") diff --git a/pages/dman_v5/README.md b/frontend/pages/dman_v5/README.md similarity index 100% rename from pages/dman_v5/README.md rename to frontend/pages/dman_v5/README.md diff --git a/frontend/pages/dman_v5/__init__.py b/frontend/pages/dman_v5/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/frontend/pages/dman_v5/app.py b/frontend/pages/dman_v5/app.py new file mode 100644 index 0000000..2cdfecc --- /dev/null +++ b/frontend/pages/dman_v5/app.py @@ -0,0 +1,149 @@ +import streamlit as st +import pandas as pd +import pandas_ta as ta +import plotly.graph_objects as go +import yaml +from hummingbot.connector.connector_base import OrderType +from plotly.subplots import make_subplots + +from CONFIG import BACKEND_API_HOST, BACKEND_API_PORT +from utils.backend_api_client import BackendAPIClient +from utils.st_utils import initialize_st_page + +# 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='ms') +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 = BackendAPIClient.get_instance(host=BACKEND_API_HOST, port=BACKEND_API_PORT) + backend_api_client.add_controller_config(config) + st.success("Config uploaded successfully!") diff --git a/frontend/pages/dynamic_position_builder/README.md b/frontend/pages/dynamic_position_builder/README.md new file mode 100644 index 0000000..e69de29 diff --git a/frontend/pages/dynamic_position_builder/__init__.py b/frontend/pages/dynamic_position_builder/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/frontend/pages/dynamic_position_builder/app.py b/frontend/pages/dynamic_position_builder/app.py new file mode 100644 index 0000000..3130f07 --- /dev/null +++ b/frontend/pages/dynamic_position_builder/app.py @@ -0,0 +1,220 @@ +import streamlit as st +from plotly.subplots import make_subplots +import plotly.graph_objects as go +from decimal import Decimal +import yaml + +from utils.st_utils import initialize_st_page +from frontend.components.st_inputs import normalize, distribution_inputs, get_distribution + +# Initialize the Streamlit page +initialize_st_page(title="Dynamic Spread Generator", icon="🚀", initial_sidebar_state="collapsed") + + +# 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) + +# Assuming get_distribution function returns a list of Decimal values for spreads and amounts +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] + +# Initialize lists to store values per level +take_profit_values = [] +dynamic_spreads = [] +break_even_values = [] +spread_adjustment_factor = Decimal(0.01) # Spread adjustment factor + +for level in range(n_levels): + if level > 0: + # Recompute spread for current level based on the previous level's break-even price + previous_break_even = break_even_values[level - 1] + new_spread = previous_break_even + Decimal(spread_distribution[level]) # Dynamic spread adjustment + dynamic_spreads.append(new_spread) + total_amount = sum(order_amounts[:level + 1]) + break_even_values.append(Decimal(sum([spread * amount for spread, amount in zip(dynamic_spreads, order_amounts[:level + 1])]) / total_amount)) + else: + dynamic_spreads = [Decimal(spread_distribution[0])] # Initialize with the first spread value + break_even_values = [Decimal(spread_distribution[0])] + +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(dynamic_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(dynamic_spreads))), y=dynamic_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(dynamic_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}
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(dynamic_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) +# Export Button +if st.button('Export as YAML'): + yaml_data = convert_to_yaml(spread_distribution, order_amounts) + st.download_button( + label="Download YAML", + data=yaml_data, + file_name='config.yaml', + mime='text/yaml' + ) diff --git a/pages/file_manager/README.md b/frontend/pages/file_manager/README.md similarity index 100% rename from pages/file_manager/README.md rename to frontend/pages/file_manager/README.md diff --git a/frontend/pages/file_manager/__init__.py b/frontend/pages/file_manager/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pages/file_manager/app.py b/frontend/pages/file_manager/app.py similarity index 87% rename from pages/file_manager/app.py rename to frontend/pages/file_manager/app.py index 059f472..1c731cc 100644 --- a/pages/file_manager/app.py +++ b/frontend/pages/file_manager/app.py @@ -2,9 +2,9 @@ from types import SimpleNamespace import streamlit as st from streamlit_elements import elements, mui -from ui_components.bots_file_explorer import BotsFileExplorer -from ui_components.dashboard import Dashboard -from ui_components.editor import Editor +from frontend.components.bots_file_explorer import BotsFileExplorer +from frontend.components.dashboard import Dashboard +from frontend.components.editor import Editor from utils.st_utils import initialize_st_page diff --git a/pages/macd_bb_v1/README.md b/frontend/pages/kalman_filter_v1/README.md similarity index 100% rename from pages/macd_bb_v1/README.md rename to frontend/pages/kalman_filter_v1/README.md diff --git a/frontend/pages/kalman_filter_v1/__init__.py b/frontend/pages/kalman_filter_v1/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/frontend/pages/kalman_filter_v1/app.py b/frontend/pages/kalman_filter_v1/app.py new file mode 100644 index 0000000..3e34269 --- /dev/null +++ b/frontend/pages/kalman_filter_v1/app.py @@ -0,0 +1,226 @@ +import streamlit as st +import pandas as pd +import plotly.graph_objects as go +import pandas_ta as ta +import yaml +from hummingbot.connector.connector_base import OrderType +from pykalman import KalmanFilter + +from CONFIG import BACKEND_API_HOST, BACKEND_API_PORT +from utils.backend_api_client import BackendAPIClient +from utils.st_utils import initialize_st_page + +# Initialize the Streamlit page +initialize_st_page(title="Kalman Filter V1", icon="📈", initial_sidebar_state="expanded") + + +@st.cache_data +def get_candles(connector_name="binance", trading_pair="BTC-USDT", interval="1m", max_records=5000): + 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 + # Construct a Kalman filter + kf = KalmanFilter(transition_matrices=[1], + observation_matrices=[1], + initial_state_mean=df["close"].values[0], + initial_state_covariance=initial_state_covariance, + observation_covariance=observation_covariance, + transition_covariance=transition_covariance) + mean, cov = kf.filter(df["close"].values) + df["kf"] = pd.Series(mean.flatten(), index=df["close"].index) + df["kf_upper"] = pd.Series(mean.flatten() + 1.96 * cov.flatten(), index=df["close"].index) + df["kf_lower"] = pd.Series(mean.flatten() - 1.96 * cov.flatten(), index=df["close"].index) + + # Generate signal + long_condition = df["close"] < df["kf_lower"] + short_condition = df["close"] > df["kf_upper"] + + # Generate signal + df["signal"] = 0 + df.loc[long_condition, "signal"] = 1 + df.loc[short_condition, "signal"] = -1 + return df + + +st.text("This tool will let you create a config for Kalman Filter V1 and visualize the strategy.") +st.write("---") + +# Inputs for Kalman Filter configuration +st.write("## Candles Configuration") +c1, c2, c3, c4 = st.columns(4) +with c1: + connector_name = st.text_input("Connector Name", value="binance_perpetual") + candles_connector = st.text_input("Candles Connector", value="binance_perpetual") +with c2: + trading_pair = st.text_input("Trading Pair", value="WLD-USDT") + candles_trading_pair = st.text_input("Candles Trading Pair", value="WLD-USDT") +with c3: + interval = st.selectbox("Candle Interval", options=["1m", "3m", "5m", "15m", "30m"], index=1) +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: + sl = st.number_input("Stop Loss (%)", min_value=0.0, max_value=100.0, value=2.0, step=0.1) + tp = st.number_input("Take Profit (%)", min_value=0.0, max_value=100.0, value=3.0, step=0.1) + take_profit_order_type = st.selectbox("Take Profit Order Type", (OrderType.LIMIT, OrderType.MARKET)) +with c2: + ts_ap = st.number_input("Trailing Stop Activation Price (%)", min_value=0.0, max_value=100.0, value=1.0, step=0.1) + ts_delta = st.number_input("Trailing Stop Delta (%)", min_value=0.0, max_value=100.0, value=0.3, step=0.1) + time_limit = st.number_input("Time Limit (minutes)", min_value=0, value=60 * 6) +with c3: + executor_amount_quote = st.number_input("Executor Amount Quote", min_value=10.0, value=100.0, step=1.0) + max_executors_per_side = st.number_input("Max Executors Per Side", min_value=1, value=2) + cooldown_time = st.number_input("Cooldown Time (seconds)", min_value=0, value=300) +with c4: + leverage = st.number_input("Leverage", min_value=1, value=20) + position_mode = st.selectbox("Position Mode", ("HEDGE", "ONEWAY")) + +st.write("## Kalman Filter Configuration") +c1, c2 = st.columns(2) +with c1: + observation_covariance = st.number_input("Observation Covariance", value=1.0) +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) +df = pd.DataFrame(candle_data) +df.index = pd.to_datetime(df['timestamp'], unit='ms') +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 + '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 + 'sell_signal': '#FF0000', # Red for Sell Signals +} + +# Create a subplot with 2 rows +fig = make_subplots(rows=2, cols=1, shared_xaxes=True, + vertical_spacing=0.02, subplot_titles=('Candlestick with Kalman Filter', 'Trading Signals'), + row_heights=[0.7, 0.3]) + +# Candlestick plot +fig.add_trace(go.Candlestick(x=candles_processed.index, + open=candles_processed['open'], + high=candles_processed['high'], + low=candles_processed['low'], + close=candles_processed['close'], + name="Candlesticks", increasing_line_color='#2ECC71', decreasing_line_color='#E74C3C'), + 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) + +# 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) + +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), + showlegend=False), row=2, col=1) + +# Update layout +fig.update_layout( + height=1000, # Increased height for better visibility + title="Kalman Filter and Trading Signals", + xaxis_title="Time", + yaxis_title="Price", + template="plotly_dark", + showlegend=False +) + +# Update xaxis properties +fig.update_xaxes( + rangeslider_visible=False, # Disable range slider for all + row=1, col=1 +) +fig.update_xaxes( + row=2, col=1 +) + +# Update yaxis properties +fig.update_yaxes( + title_text="Price", row=1, col=1 +) +fig.update_yaxes( + title_text="Signal", row=2, col=1 +) + +# Use Streamlit's functionality to display the plot +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"bollinger_v1-{connector_name}-{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, + "controller_name": "bollinger_v1", + "controller_type": "directional_trading", + "manual_kill_switch": None, + "candles_config": [], + "connector_name": connector_name, + "trading_pair": trading_pair, + "executor_amount_quote": executor_amount_quote, + "max_executors_per_side": max_executors_per_side, + "cooldown_time": cooldown_time, + "leverage": leverage, + "position_mode": position_mode, + "stop_loss": sl / 100, + "take_profit": tp / 100, + "time_limit": time_limit, + "take_profit_order_type": take_profit_order_type.value, + "trailing_stop": { + "activation_price": ts_ap / 100, + "trailing_delta": ts_delta / 100 + }, + "candles_connector": candles_connector, + "candles_trading_pair": candles_trading_pair, + "interval": interval, +} + +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 = BackendAPIClient.get_instance(host=BACKEND_API_HOST, port=BACKEND_API_PORT) + backend_api_client.add_controller_config(config) + st.success("Config uploaded successfully!") \ No newline at end of file diff --git a/pages/launch_bot/README.md b/frontend/pages/launch_bot/README.md similarity index 100% rename from pages/launch_bot/README.md rename to frontend/pages/launch_bot/README.md diff --git a/frontend/pages/launch_bot/__init__.py b/frontend/pages/launch_bot/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pages/launch_bot/app.py b/frontend/pages/launch_bot/app.py similarity index 90% rename from pages/launch_bot/app.py rename to frontend/pages/launch_bot/app.py index 70b661b..99dd0a7 100644 --- a/pages/launch_bot/app.py +++ b/frontend/pages/launch_bot/app.py @@ -3,8 +3,8 @@ from types import SimpleNamespace import streamlit as st from streamlit_elements import elements, mui -from ui_components.dashboard import Dashboard -from ui_components.launch_strategy_v2 import LaunchStrategyV2 +from frontend.components.dashboard import Dashboard +from frontend.components.launch_strategy_v2 import LaunchStrategyV2 from utils.st_utils import initialize_st_page CARD_WIDTH = 6 diff --git a/pages/pmm_simple/README.md b/frontend/pages/macd_bb_v1/README.md similarity index 100% rename from pages/pmm_simple/README.md rename to frontend/pages/macd_bb_v1/README.md diff --git a/frontend/pages/macd_bb_v1/__init__.py b/frontend/pages/macd_bb_v1/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pages/macd_bb_v1/app.py b/frontend/pages/macd_bb_v1/app.py similarity index 100% rename from pages/macd_bb_v1/app.py rename to frontend/pages/macd_bb_v1/app.py diff --git a/pages/master_conf/README.md b/frontend/pages/master_conf/README.md similarity index 100% rename from pages/master_conf/README.md rename to frontend/pages/master_conf/README.md diff --git a/frontend/pages/master_conf/__init__.py b/frontend/pages/master_conf/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pages/master_conf/app.py b/frontend/pages/master_conf/app.py similarity index 80% rename from pages/master_conf/app.py rename to frontend/pages/master_conf/app.py index c5b1758..c92ae53 100644 --- a/pages/master_conf/app.py +++ b/frontend/pages/master_conf/app.py @@ -1,15 +1,11 @@ -import glob -import os from types import SimpleNamespace import streamlit as st -from docker_manager import DockerManager from streamlit_elements import elements, mui -import constants -from ui_components.dashboard import Dashboard -from ui_components.editor import Editor -from ui_components.launch_master_bot_card import LaunchMasterBotCard -from ui_components.master_conf_file_explorer import MasterConfFileExplorer +from frontend.components.dashboard import Dashboard +from frontend.components.editor import Editor +from frontend.components.launch_master_bot_card import LaunchMasterBotCard +from frontend.components.master_conf_file_explorer import MasterConfFileExplorer from utils.st_utils import initialize_st_page diff --git a/pages/trend_follower_v1/README.md b/frontend/pages/pmm_simple/README.md similarity index 100% rename from pages/trend_follower_v1/README.md rename to frontend/pages/pmm_simple/README.md diff --git a/frontend/pages/pmm_simple/__init__.py b/frontend/pages/pmm_simple/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pages/pmm_simple/app.py b/frontend/pages/pmm_simple/app.py similarity index 97% rename from pages/pmm_simple/app.py rename to frontend/pages/pmm_simple/app.py index dcd7a8b..6b0bd03 100644 --- a/pages/pmm_simple/app.py +++ b/frontend/pages/pmm_simple/app.py @@ -9,7 +9,7 @@ import yaml from CONFIG import BACKEND_API_HOST, BACKEND_API_PORT from utils.backend_api_client import BackendAPIClient from utils.st_utils import initialize_st_page -from ui_components.st_inputs import normalize, distribution_inputs, get_distribution +from frontend.components.st_inputs import normalize, distribution_inputs, get_distribution # Initialize the Streamlit page initialize_st_page(title="PMM Simple", icon="👨‍🏫", initial_sidebar_state="collapsed") @@ -178,8 +178,8 @@ sell_orders_df = pd.DataFrame({ "Take Profit ($)": [float(amount) * (tp / 100) for amount in sell_order_amounts_quote], "Stop Loss ($)": [float(amount) * (sl / 100) for amount in sell_order_amounts_quote], "Min Trailing Stop ($)": [float(amount) * ((ts_ap - ts_delta) / 100) for amount in sell_order_amounts_quote], - "TP/SL Ratio": [tp / sl] * buy_order_levels, - "TS/SL Ratio": [(ts_ap - ts_delta) / sl] * buy_order_levels, + "TP/SL Ratio": [tp / sl] * sell_order_levels, + "TS/SL Ratio": [(ts_ap - ts_delta) / sl] * sell_order_levels, }) # Display the DataFrames in Streamlit @@ -219,7 +219,6 @@ config = { "trailing_stop": { "activation_price": ts_ap / 100, "trailing_delta": ts_delta / 100}, - "top_executor_refresh_time": None, } yaml_config = yaml.dump(config, default_flow_style=False) diff --git a/frontend/pages/position_builder/README.md b/frontend/pages/position_builder/README.md new file mode 100644 index 0000000..e69de29 diff --git a/frontend/pages/position_builder/__init__.py b/frontend/pages/position_builder/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pages/position_builder/app.py b/frontend/pages/position_builder/app.py similarity index 98% rename from pages/position_builder/app.py rename to frontend/pages/position_builder/app.py index 475c6f8..146719c 100644 --- a/pages/position_builder/app.py +++ b/frontend/pages/position_builder/app.py @@ -5,7 +5,7 @@ from decimal import Decimal import yaml from utils.st_utils import initialize_st_page -from ui_components.st_inputs import normalize, distribution_inputs, get_distribution +from frontend.components.st_inputs import normalize, distribution_inputs, get_distribution # Initialize the Streamlit page initialize_st_page(title="Position Generator", icon="🔭", initial_sidebar_state="collapsed") @@ -37,8 +37,8 @@ with col_levels: # 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") -amount_dist_type, amount_start, amount_base, amount_scaling, amount_step, amount_ratio, manual_amounts = distribution_inputs(col_amount_dist, "Amount") +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)) diff --git a/pages/reference_data/7_📋_Data.py b/frontend/pages/reference_data/7_📋_Data.py similarity index 100% rename from pages/reference_data/7_📋_Data.py rename to frontend/pages/reference_data/7_📋_Data.py diff --git a/frontend/pages/reference_data/__init__.py b/frontend/pages/reference_data/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pages/strategy_performance/README.md b/frontend/pages/strategy_performance/README.md similarity index 100% rename from pages/strategy_performance/README.md rename to frontend/pages/strategy_performance/README.md diff --git a/frontend/pages/strategy_performance/__init__.py b/frontend/pages/strategy_performance/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pages/strategy_performance/app.py b/frontend/pages/strategy_performance/app.py similarity index 100% rename from pages/strategy_performance/app.py rename to frontend/pages/strategy_performance/app.py diff --git a/pages/token_spreads/README.md b/frontend/pages/token_spreads/README.md similarity index 100% rename from pages/token_spreads/README.md rename to frontend/pages/token_spreads/README.md diff --git a/frontend/pages/token_spreads/__init__.py b/frontend/pages/token_spreads/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pages/token_spreads/app.py b/frontend/pages/token_spreads/app.py similarity index 100% rename from pages/token_spreads/app.py rename to frontend/pages/token_spreads/app.py diff --git a/pages/xemm_controller/README.md b/frontend/pages/trend_follower_v1/README.md similarity index 100% rename from pages/xemm_controller/README.md rename to frontend/pages/trend_follower_v1/README.md diff --git a/frontend/pages/trend_follower_v1/__init__.py b/frontend/pages/trend_follower_v1/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pages/trend_follower_v1/app.py b/frontend/pages/trend_follower_v1/app.py similarity index 100% rename from pages/trend_follower_v1/app.py rename to frontend/pages/trend_follower_v1/app.py diff --git a/pages/tvl_vs_mcap/README.md b/frontend/pages/tvl_vs_mcap/README.md similarity index 100% rename from pages/tvl_vs_mcap/README.md rename to frontend/pages/tvl_vs_mcap/README.md diff --git a/frontend/pages/tvl_vs_mcap/__init__.py b/frontend/pages/tvl_vs_mcap/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pages/tvl_vs_mcap/app.py b/frontend/pages/tvl_vs_mcap/app.py similarity index 100% rename from pages/tvl_vs_mcap/app.py rename to frontend/pages/tvl_vs_mcap/app.py diff --git a/frontend/pages/xemm_controller/README.md b/frontend/pages/xemm_controller/README.md new file mode 100644 index 0000000..2fa8d53 --- /dev/null +++ b/frontend/pages/xemm_controller/README.md @@ -0,0 +1,19 @@ +# 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. \ No newline at end of file diff --git a/frontend/pages/xemm_controller/__init__.py b/frontend/pages/xemm_controller/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pages/xemm_controller/app.py b/frontend/pages/xemm_controller/app.py similarity index 100% rename from pages/xemm_controller/app.py rename to frontend/pages/xemm_controller/app.py diff --git a/helpers/add_authemail.py b/helpers/add_authemail.py deleted file mode 100755 index a7c6897..0000000 --- a/helpers/add_authemail.py +++ /dev/null @@ -1,27 +0,0 @@ -import streamlit_authenticator as stauth -from ruamel.yaml import YAML -import os - -yaml = YAML(typ='safe', pure=True) - -# enter email address -new_email = input("Enter dashboard email >> ") - -# if user enter no email address, exit setup! -if len(new_email) == 0: - print("\nNo email added, please try again!\n") - exit() - -# load the YAML file -yaml_file = "../credentials.yml" -with open(yaml_file, "r") as file: - data = yaml.load(file) - -# append the email address to credentials.yml -data["preauthorized"]["emails"].append(new_email) - -# write the updated data back to the file -with open(yaml_file, "w") as file: - yaml.dump(data, file) - -print("Email has been successfully added!") diff --git a/helpers/edit_authadmin_password.py b/helpers/edit_authadmin_password.py deleted file mode 100644 index 35113e2..0000000 --- a/helpers/edit_authadmin_password.py +++ /dev/null @@ -1,26 +0,0 @@ -import streamlit_authenticator as stauth -from ruamel.yaml import YAML -import os - -yaml = YAML(typ='safe', pure=True) - -# enter admin password or use default t3st01 -new_password = input("Enter dashboard password >> ") -new_password = new_password or "t3st01" - -# extract the hash password from the List -hash_password = stauth.Hasher([new_password]).generate()[0] - -# load the YAML file -yaml_file = "../credentials.yml" -with open(yaml_file, "r") as file: - data = yaml.load(file) - -# update the admin password on credentials.yml -data["credentials"]["usernames"]["admin"]["password"] = hash_password - -# write the updated data back to the file -with open(yaml_file, "w") as file: - yaml.dump(data, file) - -print("Admin password has been updated! ") diff --git a/hummingbot_files/bots/.gitignore b/hummingbot_files/bots/.gitignore deleted file mode 100644 index 359db62..0000000 --- a/hummingbot_files/bots/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/hummingbot* \ No newline at end of file diff --git a/hummingbot_files/bots/data_downloader/conf/.password_verification b/hummingbot_files/bots/data_downloader/conf/.password_verification deleted file mode 100644 index b8c7618..0000000 --- a/hummingbot_files/bots/data_downloader/conf/.password_verification +++ /dev/null @@ -1 +0,0 @@ -7b2263727970746f223a207b22636970686572223a20226165732d3132382d637472222c2022636970686572706172616d73223a207b226976223a20223864336365306436393461623131396334363135663935366464653839363063227d2c202263697068657274657874223a20223836333266323430613563306131623665353664222c20226b6466223a202270626b646632222c20226b6466706172616d73223a207b2263223a20313030303030302c2022646b6c656e223a2033322c2022707266223a2022686d61632d736861323536222c202273616c74223a20226566373330376531636464373964376132303338323534656139343433663930227d2c20226d6163223a202266393439383534613530633138363633386363353962336133363665633962353333386633613964373266636635343066313034333361353431636232306438227d2c202276657273696f6e223a20337d \ No newline at end of file diff --git a/hummingbot_files/bots/data_downloader/conf/conf_client.yml b/hummingbot_files/bots/data_downloader/conf/conf_client.yml deleted file mode 100644 index ab2880c..0000000 --- a/hummingbot_files/bots/data_downloader/conf/conf_client.yml +++ /dev/null @@ -1,199 +0,0 @@ -#################################### -### client_config_map config ### -#################################### - -instance_id: 039758736d451914503a45ff596e168902d62557 - -log_level: INFO - -debug_console: false - -strategy_report_interval: 900.0 - -logger_override_whitelist: -- hummingbot.strategy.arbitrage -- hummingbot.strategy.cross_exchange_market_making -- conf - -log_file_path: /home/hummingbot/logs - -kill_switch_mode: {} - -# What to auto-fill in the prompt after each import command (start/config) -autofill_import: disabled - -telegram_mode: {} - -# MQTT Bridge configuration. -mqtt_bridge: - mqtt_host: localhost - mqtt_port: 1883 - mqtt_username: '' - mqtt_password: '' - mqtt_namespace: hbot - mqtt_ssl: false - mqtt_logger: true - mqtt_notifier: true - mqtt_commands: true - mqtt_events: true - mqtt_external_events: true - mqtt_autostart: true - -# Error log sharing -send_error_logs: true - -# Can store the previous strategy ran for quick retrieval. -previous_strategy: null - -# Advanced database options, currently supports SQLAlchemy's included dialects -# Reference: https://docs.sqlalchemy.org/en/13/dialects/ -# To use an instance of SQLite DB the required configuration is -# db_engine: sqlite -# To use a DBMS the required configuration is -# db_host: 127.0.0.1 -# db_port: 3306 -# db_username: username -# db_password: password -# db_name: dbname -db_mode: - db_engine: sqlite - -pmm_script_mode: {} - -# Balance Limit Configurations -# e.g. Setting USDT and BTC limits on Binance. -# balance_asset_limit: -# binance: -# BTC: 0.1 -# USDT: 1000 -balance_asset_limit: - bybit_testnet: {} - lbank: {} - binance_us: {} - crypto_com: {} - ascend_ex_paper_trade: {} - hotbit: {} - gate_io_paper_trade: {} - bitmex_testnet: {} - ndax_testnet: {} - huobi: {} - probit_kr: {} - altmarkets: {} - hitbtc: {} - foxbit: {} - ascend_ex: {} - binance: {} - okx: {} - ciex: {} - bitmex: {} - bitfinex: {} - probit: {} - kraken: {} - kucoin: {} - bitmart: {} - bybit: {} - bittrex: {} - btc_markets: {} - mock_paper_exchange: {} - kucoin_paper_trade: {} - ndax: {} - loopring: {} - mexc: {} - whitebit: {} - coinbase_pro: {} - binance_paper_trade: {} - gate_io: {} - -# Fixed gas price (in Gwei) for Ethereum transactions -manual_gas_price: 50.0 - -# Gateway API Configurations -# default host to only use localhost -# Port need to match the final installation port for Gateway -gateway: - gateway_api_host: localhost - gateway_api_port: '15888' - -certs_path: /home/hummingbot/certs - -# Whether to enable aggregated order and trade data collection -anonymized_metrics_mode: - anonymized_metrics_interval_min: 15.0 - -# Command Shortcuts -# Define abbreviations for often used commands -# or batch grouped commands together -command_shortcuts: -- command: spreads - help: Set bid and ask spread - arguments: - - Bid Spread - - Ask Spread - output: - - config bid_spread $1 - - config ask_spread $2 - -# A source for rate oracle, currently ascend_ex, binance, coin_gecko, coin_cap, kucoin, gate_io -rate_oracle_source: - name: binance - -# A universal token which to display tokens values in, e.g. USD,EUR,BTC -global_token: - global_token_name: USD - global_token_symbol: $ - -# Percentage of API rate limits (on any exchange and any end point) allocated to this bot instance. -# Enter 50 to indicate 50%. E.g. if the API rate limit is 100 calls per second, and you allocate -# 50% to this setting, the bot will have a maximum (limit) of 50 calls per second -rate_limits_share_pct: 100.0 - -commands_timeout: - create_command_timeout: 10.0 - other_commands_timeout: 30.0 - -# Tabulate table format style (https://github.com/astanin/python-tabulate#table-format) -tables_format: psql - -paper_trade: - paper_trade_exchanges: - - binance - - kucoin - - ascend_ex - - gate_io - paper_trade_account_balance: - BTC: 1.0 - USDT: 1000.0 - ONE: 1000.0 - USDQ: 1000.0 - TUSD: 1000.0 - ETH: 10.0 - WETH: 10.0 - USDC: 1000.0 - DAI: 1000.0 - -color: - top_pane: '#000000' - bottom_pane: '#000000' - output_pane: '#262626' - input_pane: '#1C1C1C' - logs_pane: '#121212' - terminal_primary: '#5FFFD7' - primary_label: '#5FFFD7' - secondary_label: '#FFFFFF' - success_label: '#5FFFD7' - warning_label: '#FFFF00' - info_label: '#5FD7FF' - error_label: '#FF0000' - gold_label: '#FFD700' - silver_label: '#C0C0C0' - bronze_label: '#CD7F32' - -# The tick size is the frequency with which the clock notifies the time iterators by calling the -# c_tick() method, that means for example that if the tick size is 1, the logic of the strategy -# will run every second. -tick_size: 1.0 - -market_data_collection: - market_data_collection_enabled: true - market_data_collection_interval: 60 - market_data_collection_depth: 20 diff --git a/hummingbot_files/bots/data_downloader/conf/conf_fee_overrides.yml b/hummingbot_files/bots/data_downloader/conf/conf_fee_overrides.yml deleted file mode 100644 index f295650..0000000 --- a/hummingbot_files/bots/data_downloader/conf/conf_fee_overrides.yml +++ /dev/null @@ -1,340 +0,0 @@ -######################################## -### Fee overrides configurations ### -######################################## - -# For more detailed information: https://docs.hummingbot.io -template_version: 14 - -# Example of the fields that can be specified to override the `TradeFeeFactory` default settings. -# If the field is missing or the value is left blank, the default value will be used. -# The percentage values are specified as 0.1 for 0.1%. -# -# [exchange name]_percent_fee_token: -# [exchange name]_maker_percent_fee: -# [exchange name]_taker_percent_fee: -# [exchange name]_buy_percent_fee_deducted_from_returns: # if False, the buy fee is added to the order costs -# [exchange name]_maker_fixed_fees: # a list of lists of token-fee pairs (e.g. [["ETH", 1]]) -# [exchange name]_taker_fixed_fees: # a list of lists of token-fee pairs (e.g. [["ETH", 1]]) - -binance_percent_fee_token: # BNB -binance_maker_percent_fee: # 0.75 -binance_taker_percent_fee: # 0.75 -binance_buy_percent_fee_deducted_from_returns: # True - -# List of supported Exchanges for which the user's data_downloader/conf_fee_override.yml -# will work. This file currently needs to be in sync with hummingbot list of -# supported exchanges -altmarkets_buy_percent_fee_deducted_from_returns: -altmarkets_maker_fixed_fees: -altmarkets_maker_percent_fee: -altmarkets_percent_fee_token: -altmarkets_taker_fixed_fees: -altmarkets_taker_percent_fee: -ascend_ex_buy_percent_fee_deducted_from_returns: -ascend_ex_maker_fixed_fees: -ascend_ex_maker_percent_fee: -ascend_ex_percent_fee_token: -ascend_ex_taker_fixed_fees: -ascend_ex_taker_percent_fee: -binance_maker_fixed_fees: -binance_perpetual_buy_percent_fee_deducted_from_returns: -binance_perpetual_maker_fixed_fees: -binance_perpetual_maker_percent_fee: -binance_perpetual_percent_fee_token: -binance_perpetual_taker_fixed_fees: -binance_perpetual_taker_percent_fee: -binance_perpetual_testnet_buy_percent_fee_deducted_from_returns: -binance_perpetual_testnet_maker_fixed_fees: -binance_perpetual_testnet_maker_percent_fee: -binance_perpetual_testnet_percent_fee_token: -binance_perpetual_testnet_taker_fixed_fees: -binance_perpetual_testnet_taker_percent_fee: -binance_taker_fixed_fees: -binance_us_buy_percent_fee_deducted_from_returns: -binance_us_maker_fixed_fees: -binance_us_maker_percent_fee: -binance_us_percent_fee_token: -binance_us_taker_fixed_fees: -binance_us_taker_percent_fee: -bitfinex_buy_percent_fee_deducted_from_returns: -bitfinex_maker_fixed_fees: -bitfinex_maker_percent_fee: -bitfinex_percent_fee_token: -bitfinex_taker_fixed_fees: -bitfinex_taker_percent_fee: -bitmart_buy_percent_fee_deducted_from_returns: -bitmart_maker_fixed_fees: -bitmart_maker_percent_fee: -bitmart_percent_fee_token: -bitmart_taker_fixed_fees: -bitmart_taker_percent_fee: -bittrex_buy_percent_fee_deducted_from_returns: -bittrex_maker_fixed_fees: -bittrex_maker_percent_fee: -bittrex_percent_fee_token: -bittrex_taker_fixed_fees: -bittrex_taker_percent_fee: -btc_markets_percent_fee_token: -btc_markets_maker_percent_fee: -btc_markets_taker_percent_fee: -btc_markets_buy_percent_fee_deducted_from_returns: -bybit_perpetual_buy_percent_fee_deducted_from_returns: -bybit_perpetual_maker_fixed_fees: -bybit_perpetual_maker_percent_fee: -bybit_perpetual_percent_fee_token: -bybit_perpetual_taker_fixed_fees: -bybit_perpetual_taker_percent_fee: -bybit_perpetual_testnet_buy_percent_fee_deducted_from_returns: -bybit_perpetual_testnet_maker_fixed_fees: -bybit_perpetual_testnet_maker_percent_fee: -bybit_perpetual_testnet_percent_fee_token: -bybit_perpetual_testnet_taker_fixed_fees: -bybit_perpetual_testnet_taker_percent_fee: -coinbase_pro_buy_percent_fee_deducted_from_returns: -coinbase_pro_maker_fixed_fees: -coinbase_pro_maker_percent_fee: -coinbase_pro_percent_fee_token: -coinbase_pro_taker_fixed_fees: -coinbase_pro_taker_percent_fee: -crypto_com_buy_percent_fee_deducted_from_returns: -crypto_com_maker_fixed_fees: -crypto_com_maker_percent_fee: -crypto_com_percent_fee_token: -crypto_com_taker_fixed_fees: -crypto_com_taker_percent_fee: -dydx_perpetual_buy_percent_fee_deducted_from_returns: -dydx_perpetual_maker_fixed_fees: -dydx_perpetual_maker_percent_fee: -dydx_perpetual_percent_fee_token: -dydx_perpetual_taker_fixed_fees: -dydx_perpetual_taker_percent_fee: -gate_io_buy_percent_fee_deducted_from_returns: -gate_io_maker_fixed_fees: -gate_io_maker_percent_fee: -gate_io_percent_fee_token: -gate_io_taker_fixed_fees: -gate_io_taker_percent_fee: -hitbtc_buy_percent_fee_deducted_from_returns: -hitbtc_maker_fixed_fees: -hitbtc_maker_percent_fee: -hitbtc_percent_fee_token: -hitbtc_taker_fixed_fees: -hitbtc_taker_percent_fee: -huobi_buy_percent_fee_deducted_from_returns: -huobi_maker_fixed_fees: -huobi_maker_percent_fee: -huobi_percent_fee_token: -huobi_taker_fixed_fees: -huobi_taker_percent_fee: -kraken_buy_percent_fee_deducted_from_returns: -kraken_maker_fixed_fees: -kraken_maker_percent_fee: -kraken_percent_fee_token: -kraken_taker_fixed_fees: -kraken_taker_percent_fee: -kucoin_buy_percent_fee_deducted_from_returns: -kucoin_maker_fixed_fees: -kucoin_maker_percent_fee: -kucoin_percent_fee_token: -kucoin_taker_fixed_fees: -kucoin_taker_percent_fee: -loopring_buy_percent_fee_deducted_from_returns: -loopring_maker_fixed_fees: -loopring_maker_percent_fee: -loopring_percent_fee_token: -loopring_taker_fixed_fees: -loopring_taker_percent_fee: -mexc_buy_percent_fee_deducted_from_returns: -mexc_maker_fixed_fees: -mexc_maker_percent_fee: -mexc_percent_fee_token: -mexc_taker_fixed_fees: -mexc_taker_percent_fee: -ndax_buy_percent_fee_deducted_from_returns: -ndax_maker_fixed_fees: -ndax_maker_percent_fee: -ndax_percent_fee_token: -ndax_taker_fixed_fees: -ndax_taker_percent_fee: -ndax_testnet_buy_percent_fee_deducted_from_returns: -ndax_testnet_maker_fixed_fees: -ndax_testnet_maker_percent_fee: -ndax_testnet_percent_fee_token: -ndax_testnet_taker_fixed_fees: -ndax_testnet_taker_percent_fee: -okx_buy_percent_fee_deducted_from_returns: -okx_maker_fixed_fees: -okx_maker_percent_fee: -okx_percent_fee_token: -okx_taker_fixed_fees: -okx_taker_percent_fee: -probit_buy_percent_fee_deducted_from_returns: -probit_kr_buy_percent_fee_deducted_from_returns: -probit_kr_maker_fixed_fees: -probit_kr_maker_percent_fee: -probit_kr_percent_fee_token: -probit_kr_taker_fixed_fees: -probit_kr_taker_percent_fee: -probit_maker_fixed_fees: -probit_maker_percent_fee: -probit_percent_fee_token: -probit_taker_fixed_fees: -probit_taker_percent_fee: -bitmex_perpetual_percent_fee_token: -bitmex_perpetual_maker_percent_fee: -bitmex_perpetual_taker_percent_fee: -bitmex_perpetual_buy_percent_fee_deducted_from_returns: -bitmex_perpetual_maker_fixed_fees: -bitmex_perpetual_taker_fixed_fees: -bitmex_perpetual_testnet_percent_fee_token: -bitmex_perpetual_testnet_maker_percent_fee: -bitmex_perpetual_testnet_taker_percent_fee: -bitmex_perpetual_testnet_buy_percent_fee_deducted_from_returns: -bitmex_perpetual_testnet_maker_fixed_fees: -bitmex_perpetual_testnet_taker_fixed_fees: -kucoin_perpetual_percent_fee_token: -kucoin_perpetual_maker_percent_fee: -kucoin_perpetual_taker_percent_fee: -kucoin_perpetual_buy_percent_fee_deducted_from_returns: -kucoin_perpetual_maker_fixed_fees: -kucoin_perpetual_taker_fixed_fees: -kucoin_perpetual_testnet_percent_fee_token: -kucoin_perpetual_testnet_maker_percent_fee: -kucoin_perpetual_testnet_taker_percent_fee: -kucoin_perpetual_testnet_buy_percent_fee_deducted_from_returns: -kucoin_perpetual_testnet_maker_fixed_fees: -kucoin_perpetual_testnet_taker_fixed_fees: -gate_io_perpetual_percent_fee_token: -gate_io_perpetual_maker_percent_fee: -gate_io_perpetual_taker_percent_fee: -gate_io_perpetual_buy_percent_fee_deducted_from_returns: -gate_io_perpetual_maker_fixed_fees: -gate_io_perpetual_taker_fixed_fees: -phemex_perpetual_percent_fee_token: -phemex_perpetual_maker_percent_fee: -phemex_perpetual_taker_percent_fee: -phemex_perpetual_buy_percent_fee_deducted_from_returns: -phemex_perpetual_maker_fixed_fees: -phemex_perpetual_taker_fixed_fees: -phemex_perpetual_testnet_percent_fee_token: -phemex_perpetual_testnet_maker_percent_fee: -phemex_perpetual_testnet_taker_percent_fee: -phemex_perpetual_testnet_buy_percent_fee_deducted_from_returns: -phemex_perpetual_testnet_maker_fixed_fees: -phemex_perpetual_testnet_taker_fixed_fees: -bitget_perpetual_percent_fee_token: -bitget_perpetual_maker_percent_fee: -bitget_perpetual_taker_percent_fee: -bitget_perpetual_buy_percent_fee_deducted_from_returns: -bitget_perpetual_maker_fixed_fees: -bitget_perpetual_taker_fixed_fees: -bit_com_perpetual_percent_fee_token: -bit_com_perpetual_maker_percent_fee: -bit_com_perpetual_taker_percent_fee: -bit_com_perpetual_buy_percent_fee_deducted_from_returns: -bit_com_perpetual_maker_fixed_fees: -bit_com_perpetual_taker_fixed_fees: -bit_com_perpetual_testnet_percent_fee_token: -bit_com_perpetual_testnet_maker_percent_fee: -bit_com_perpetual_testnet_taker_percent_fee: -bit_com_perpetual_testnet_buy_percent_fee_deducted_from_returns: -bit_com_perpetual_testnet_maker_fixed_fees: -bit_com_perpetual_testnet_taker_fixed_fees: -whitebit_percent_fee_token: -whitebit_maker_percent_fee: -whitebit_taker_percent_fee: -whitebit_buy_percent_fee_deducted_from_returns: -whitebit_maker_fixed_fees: -whitebit_taker_fixed_fees: -bitmex_percent_fee_token: -bitmex_maker_percent_fee: -bitmex_taker_percent_fee: -bitmex_buy_percent_fee_deducted_from_returns: -bitmex_maker_fixed_fees: -bitmex_taker_fixed_fees: -bitmex_testnet_percent_fee_token: -bitmex_testnet_maker_percent_fee: -bitmex_testnet_taker_percent_fee: -bitmex_testnet_buy_percent_fee_deducted_from_returns: -bitmex_testnet_maker_fixed_fees: -bitmex_testnet_taker_fixed_fees: -ciex_percent_fee_token: -ciex_maker_percent_fee: -ciex_taker_percent_fee: -ciex_buy_percent_fee_deducted_from_returns: -ciex_maker_fixed_fees: -ciex_taker_fixed_fees: -foxbit_percent_fee_token: -foxbit_maker_percent_fee: -foxbit_taker_percent_fee: -foxbit_buy_percent_fee_deducted_from_returns: -foxbit_maker_fixed_fees: -foxbit_taker_fixed_fees: -lbank_percent_fee_token: -lbank_maker_percent_fee: -lbank_taker_percent_fee: -lbank_buy_percent_fee_deducted_from_returns: -lbank_maker_fixed_fees: -lbank_taker_fixed_fees: -bybit_percent_fee_token: -bybit_maker_percent_fee: -bybit_taker_percent_fee: -bybit_buy_percent_fee_deducted_from_returns: -bybit_maker_fixed_fees: -bybit_taker_fixed_fees: -bybit_testnet_percent_fee_token: -bybit_testnet_maker_percent_fee: -bybit_testnet_taker_percent_fee: -bybit_testnet_buy_percent_fee_deducted_from_returns: -bybit_testnet_maker_fixed_fees: -bybit_testnet_taker_fixed_fees: -hotbit_percent_fee_token: -hotbit_maker_percent_fee: -hotbit_taker_percent_fee: -hotbit_buy_percent_fee_deducted_from_returns: -hotbit_maker_fixed_fees: -hotbit_taker_fixed_fees: -btc_markets_maker_fixed_fees: -btc_markets_taker_fixed_fees: -polkadex_percent_fee_token: -polkadex_maker_percent_fee: -polkadex_taker_percent_fee: -polkadex_buy_percent_fee_deducted_from_returns: -polkadex_maker_fixed_fees: -polkadex_taker_fixed_fees: -woo_x_percent_fee_token: -woo_x_maker_percent_fee: -woo_x_taker_percent_fee: -woo_x_buy_percent_fee_deducted_from_returns: -woo_x_maker_fixed_fees: -woo_x_taker_fixed_fees: -woo_x_testnet_percent_fee_token: -woo_x_testnet_maker_percent_fee: -woo_x_testnet_taker_percent_fee: -woo_x_testnet_buy_percent_fee_deducted_from_returns: -woo_x_testnet_maker_fixed_fees: -woo_x_testnet_taker_fixed_fees: -vertex_percent_fee_token: -vertex_maker_percent_fee: -vertex_taker_percent_fee: -vertex_buy_percent_fee_deducted_from_returns: -vertex_maker_fixed_fees: -vertex_taker_fixed_fees: -vertex_testnet_percent_fee_token: -vertex_testnet_maker_percent_fee: -vertex_testnet_taker_percent_fee: -vertex_testnet_buy_percent_fee_deducted_from_returns: -vertex_testnet_maker_fixed_fees: -vertex_testnet_taker_fixed_fees: -injective_v2_percent_fee_token: -injective_v2_maker_percent_fee: -injective_v2_taker_percent_fee: -injective_v2_buy_percent_fee_deducted_from_returns: -injective_v2_maker_fixed_fees: -injective_v2_taker_fixed_fees: -injective_v2_perpetual_percent_fee_token: -injective_v2_perpetual_maker_percent_fee: -injective_v2_perpetual_taker_percent_fee: -injective_v2_perpetual_buy_percent_fee_deducted_from_returns: -injective_v2_perpetual_maker_fixed_fees: -injective_v2_perpetual_taker_fixed_fees: diff --git a/hummingbot_files/bots/data_downloader/conf/hummingbot_logs.yml b/hummingbot_files/bots/data_downloader/conf/hummingbot_logs.yml deleted file mode 100755 index 8e65271..0000000 --- a/hummingbot_files/bots/data_downloader/conf/hummingbot_logs.yml +++ /dev/null @@ -1,83 +0,0 @@ ---- -version: 1 -template_version: 12 - -formatters: - simple: - format: "%(asctime)s - %(process)d - %(name)s - %(levelname)s - %(message)s" - -handlers: - console: - class: hummingbot.logger.cli_handler.CLIHandler - level: DEBUG - formatter: simple - stream: ext://sys.stdout - console_warning: - class: hummingbot.logger.cli_handler.CLIHandler - level: WARNING - formatter: simple - stream: ext://sys.stdout - console_info: - class: hummingbot.logger.cli_handler.CLIHandler - level: INFO - formatter: simple - stream: ext://sys.stdout - file_handler: - class: logging.handlers.TimedRotatingFileHandler - level: DEBUG - formatter: simple - filename: $PROJECT_DIR/logs/logs_$STRATEGY_FILE_PATH.log - encoding: utf8 - when: "D" - interval: 1 - backupCount: 7 - "null": - class: logging.NullHandler - level: DEBUG - -loggers: - hummingbot.core.utils.eth_gas_station_lookup: - level: NETWORK - propagate: false - handlers: [console, file_handler] - mqtt: true - hummingbot.logger.log_server_client: - level: WARNING - propagate: false - handlers: [console, file_handler] - mqtt: true - hummingbot.logger.reporting_proxy_handler: - level: WARNING - propagate: false - handlers: [console, file_handler] - mqtt: true - hummingbot.strategy: - level: NETWORK - propagate: false - handlers: [console, file_handler] - mqtt: true - hummingbot.connector: - level: NETWORK - propagate: false - handlers: [console, file_handler] - mqtt: true - hummingbot.client: - level: NETWORK - propagate: false - handlers: [console, file_handler] - mqtt: true - hummingbot.core.event.event_reporter: - level: EVENT_LOG - propagate: false - handlers: [file_handler] - mqtt: false - conf: - level: NETWORK - handlers: ["null"] - propagate: false - mqtt: false - -root: - level: INFO - handlers: [console, file_handler] - mqtt: true diff --git a/hummingbot_files/bots/data_downloader/conf_client.yml b/hummingbot_files/bots/data_downloader/conf_client.yml deleted file mode 100644 index 5bc6b61..0000000 --- a/hummingbot_files/bots/data_downloader/conf_client.yml +++ /dev/null @@ -1,194 +0,0 @@ -#################################### -### client_config_map config ### -#################################### - -instance_id: e90c0d6f2b1e2d54fa0c0a69612b07174320963b - -log_level: INFO - -debug_console: false - -strategy_report_interval: 900.0 - -logger_override_whitelist: -- hummingbot.strategy.arbitrage -- hummingbot.strategy.cross_exchange_market_making -- conf - -log_file_path: /home/hummingbot/logs - -kill_switch_mode: {} - -# What to auto-fill in the prompt after each import command (start/config) -autofill_import: disabled - -telegram_mode: {} - -# MQTT Bridge configuration. -mqtt_bridge: - mqtt_host: localhost - mqtt_port: 1883 - mqtt_username: '' - mqtt_password: '' - mqtt_namespace: hbot - mqtt_ssl: false - mqtt_logger: true - mqtt_notifier: true - mqtt_commands: true - mqtt_events: true - mqtt_external_events: true - mqtt_autostart: true - -# Error log sharing -send_error_logs: true - -# Can store the previous strategy ran for quick retrieval. -previous_strategy: null - -# Advanced database options, currently supports SQLAlchemy's included dialects -# Reference: https://docs.sqlalchemy.org/en/13/dialects/ -# To use an instance of SQLite DB the required configuration is -# db_engine: sqlite -# To use a DBMS the required configuration is -# db_host: 127.0.0.1 -# db_port: 3306 -# db_username: username -# db_password: password -# db_name: dbname -db_mode: - db_engine: sqlite - -pmm_script_mode: {} - -# Balance Limit Configurations -# e.g. Setting USDT and BTC limits on Binance. -# balance_asset_limit: -# binance: -# BTC: 0.1 -# USDT: 1000 -balance_asset_limit: - kucoin: {} - ciex: {} - ascend_ex_paper_trade: {} - crypto_com: {} - mock_paper_exchange: {} - btc_markets: {} - bitmart: {} - hitbtc: {} - loopring: {} - mexc: {} - polkadex: {} - bybit: {} - foxbit: {} - gate_io_paper_trade: {} - kucoin_paper_trade: {} - altmarkets: {} - ascend_ex: {} - bittrex: {} - probit_kr: {} - binance: {} - bybit_testnet: {} - okx: {} - bitmex: {} - binance_us: {} - probit: {} - gate_io: {} - lbank: {} - whitebit: {} - bitmex_testnet: {} - kraken: {} - huobi: {} - binance_paper_trade: {} - ndax_testnet: {} - coinbase_pro: {} - ndax: {} - bitfinex: {} - -# Fixed gas price (in Gwei) for Ethereum transactions -manual_gas_price: 50.0 - -# Gateway API Configurations -# default host to only use localhost -# Port need to match the final installation port for Gateway -gateway: - gateway_api_host: localhost - gateway_api_port: '15888' - -certs_path: /home/hummingbot/certs - -# Whether to enable aggregated order and trade data collection -anonymized_metrics_mode: - anonymized_metrics_interval_min: 15.0 - -# Command Shortcuts -# Define abbreviations for often used commands -# or batch grouped commands together -command_shortcuts: -- command: spreads - help: Set bid and ask spread - arguments: - - Bid Spread - - Ask Spread - output: - - config bid_spread $1 - - config ask_spread $2 - -# A source for rate oracle, currently ascend_ex, binance, coin_gecko, kucoin, gate_io -rate_oracle_source: - name: binance - -# A universal token which to display tokens values in, e.g. USD,EUR,BTC -global_token: - global_token_name: USD - global_token_symbol: $ - -# Percentage of API rate limits (on any exchange and any end point) allocated to this bot instance. -# Enter 50 to indicate 50%. E.g. if the API rate limit is 100 calls per second, and you allocate -# 50% to this setting, the bot will have a maximum (limit) of 50 calls per second -rate_limits_share_pct: 100.0 - -commands_timeout: - create_command_timeout: 10.0 - other_commands_timeout: 30.0 - -# Tabulate table format style (https://github.com/astanin/python-tabulate#table-format) -tables_format: psql - -paper_trade: - paper_trade_exchanges: - - binance - - kucoin - - ascend_ex - - gate_io - paper_trade_account_balance: - BTC: 1.0 - USDT: 1000.0 - ONE: 1000.0 - USDQ: 1000.0 - TUSD: 1000.0 - ETH: 10.0 - WETH: 10.0 - USDC: 1000.0 - DAI: 1000.0 - -color: - top_pane: '#000000' - bottom_pane: '#000000' - output_pane: '#262626' - input_pane: '#1C1C1C' - logs_pane: '#121212' - terminal_primary: '#5FFFD7' - primary_label: '#5FFFD7' - secondary_label: '#FFFFFF' - success_label: '#5FFFD7' - warning_label: '#FFFF00' - info_label: '#5FD7FF' - error_label: '#FF0000' - gold_label: '#FFD700' - silver_label: '#C0C0C0' - bronze_label: '#CD7F32' - -# The tick size is the frequency with which the clock notifies the time iterators by calling the -# c_tick() method, that means for example that if the tick size is 1, the logic of the strategy -# will run every second. -tick_size: 1.0 diff --git a/hummingbot_files/bots/data_downloader/scripts/download_candles.py b/hummingbot_files/bots/data_downloader/scripts/download_candles.py deleted file mode 100644 index bfb5d10..0000000 --- a/hummingbot_files/bots/data_downloader/scripts/download_candles.py +++ /dev/null @@ -1,61 +0,0 @@ -import os -from typing import Dict - -from hummingbot import data_path -from hummingbot.client.hummingbot_application import HummingbotApplication -from hummingbot.connector.connector_base import ConnectorBase -from hummingbot.data_feed.candles_feed.candles_factory import CandlesConfig, CandlesFactory -from hummingbot.strategy.script_strategy_base import ScriptStrategyBase - - -class DownloadCandles(ScriptStrategyBase): - """ - This script provides an example of how to use the Candles Feed to download and store historical data. - It downloads 3-minute candles for 3 Binance trading pairs ["APE-USDT", "BTC-USDT", "BNB-USDT"] and stores them in - CSV files in the /data directory. The script stops after it has downloaded 50,000 max_records records for each pair. - Is important to notice that the component will fail if all the candles are not available since the idea of it is to - use it in production based on candles needed to compute technical indicators. - """ - exchange = os.getenv("EXCHANGE", "binance_perpetual") - trading_pairs = os.getenv("TRADING_PAIRS", "DODO-BUSD,LTC-USDT").split(",") - intervals = os.getenv("INTERVALS", "1m,3m,5m,1h").split(",") - days_to_download = int(os.getenv("DAYS_TO_DOWNLOAD", "3")) - # we can initialize any trading pair since we only need the candles - markets = {"binance_paper_trade": {"BTC-USDT"}} - - @staticmethod - def get_max_records(days_to_download: int, interval: str) -> int: - conversion = {"s": 1 / 60, "m": 1, "h": 60, "d": 1440} - unit = interval[-1] - quantity = int(interval[:-1]) - return int(days_to_download * 24 * 60 / (quantity * conversion[unit])) - - def __init__(self, connectors: Dict[str, ConnectorBase]): - super().__init__(connectors) - combinations = [(trading_pair, interval) for trading_pair in self.trading_pairs for interval in self.intervals] - - self.candles = {f"{combinations[0]}_{combinations[1]}": {} for combinations in combinations} - # we need to initialize the candles for each trading pair - for combination in combinations: - - candle = CandlesFactory.get_candle(CandlesConfig(connector=self.exchange, trading_pair=combination[0], interval=combination[1], max_records=self.get_max_records(self.days_to_download, combination[1]))) - candle.start() - # we are storing the candles object and the csv path to save the candles - self.candles[f"{combination[0]}_{combination[1]}"]["candles"] = candle - self.candles[f"{combination[0]}_{combination[1]}"][ - "csv_path"] = data_path() + f"/candles_{self.exchange}_{combination[0]}_{combination[1]}.csv" - - def on_tick(self): - for trading_pair, candles_info in self.candles.items(): - if not candles_info["candles"].ready: - self.logger().info(f"Candles not ready yet for {trading_pair}! Missing {candles_info['candles']._candles.maxlen - len(candles_info['candles']._candles)}") - pass - else: - df = candles_info["candles"].candles_df - df.to_csv(candles_info["csv_path"], index=False) - if all(candles_info["candles"].ready for candles_info in self.candles.values()): - HummingbotApplication.main_application().stop() - - def on_stop(self): - for candles_info in self.candles.values(): - candles_info["candles"].stop() diff --git a/hummingbot_files/compose_files/broker-compose.yml b/hummingbot_files/compose_files/broker-compose.yml deleted file mode 100644 index e4aad77..0000000 --- a/hummingbot_files/compose_files/broker-compose.yml +++ /dev/null @@ -1,43 +0,0 @@ -version: '3.9' - -services: - emqx: - container_name: hummingbot-broker - image: emqx:5 - restart: unless-stopped - environment: - - EMQX_NAME=emqx - - EMQX_HOST=node1.emqx.local - - EMQX_CLUSTER__DISCOVERY_STRATEGY=static - - EMQX_CLUSTER__STATIC__SEEDS=[emqx@node1.emqx.local] - - EMQX_LOADED_PLUGINS="emqx_recon,emqx_retainer,emqx_management,emqx_dashboard" - volumes: - - emqx-data:/opt/emqx/data - - emqx-log:/opt/emqx/log - - emqx-etc:/opt/emqx/etc - ports: - - "1883:1883" # mqtt:tcp - - "8883:8883" # mqtt:tcp:ssl - - "8083:8083" # mqtt:ws - - "8084:8084" # mqtt:ws:ssl - - "8081:8081" # http:management - - "18083:18083" # http:dashboard - - "61613:61613" # web-stomp gateway - networks: - emqx-bridge: - aliases: - - node1.emqx.local - healthcheck: - test: [ "CMD", "/opt/emqx/bin/emqx_ctl", "status" ] - interval: 5s - timeout: 25s - retries: 5 - -networks: - emqx-bridge: - driver: bridge - -volumes: - emqx-data: { } - emqx-log: { } - emqx-etc: { } \ No newline at end of file diff --git a/hummingbot_files/compose_files/data-downloader-compose.yml b/hummingbot_files/compose_files/data-downloader-compose.yml deleted file mode 100644 index 468220b..0000000 --- a/hummingbot_files/compose_files/data-downloader-compose.yml +++ /dev/null @@ -1,23 +0,0 @@ -version: "3.9" -services: - bot: - container_name: candles_downloader - image: hummingbot/hummingbot:development - volumes: - - "../../data/candles:/home/hummingbot/data" - - "../bots/data_downloader/conf:/home/hummingbot/conf" - - "../bots/data_downloader/conf/connectors:/home/hummingbot/conf/connectors" - - "../bots/data_downloader/scripts:/home/hummingbot/scripts" - environment: - - CONFIG_PASSWORD=a - - CONFIG_FILE_NAME=download_candles.py - env_file: - - ../scripts_configs/data_downloader_config.yml - logging: - driver: "json-file" - options: - max-size: "10m" - max-file: 5 - tty: true - stdin_open: true - network_mode: host diff --git a/hummingbot_files/controller_configs/.gitignore b/hummingbot_files/controller_configs/.gitignore deleted file mode 100644 index 42780ec..0000000 --- a/hummingbot_files/controller_configs/.gitignore +++ /dev/null @@ -1 +0,0 @@ - * \ No newline at end of file diff --git a/hummingbot_files/scripts_configs/data_downloader_config.yml b/hummingbot_files/scripts_configs/data_downloader_config.yml deleted file mode 100644 index 7fefb6e..0000000 --- a/hummingbot_files/scripts_configs/data_downloader_config.yml +++ /dev/null @@ -1,4 +0,0 @@ -DAYS_TO_DOWNLOAD: 30 -EXCHANGE: binance_perpetual -INTERVALS: 1m,3m,1h -TRADING_PAIRS: BTC-USDT,ETH-USDT diff --git a/hummingbot_files/templates/master_bot_conf/conf/.password_verification b/hummingbot_files/templates/master_bot_conf/conf/.password_verification deleted file mode 100644 index b8c7618..0000000 --- a/hummingbot_files/templates/master_bot_conf/conf/.password_verification +++ /dev/null @@ -1 +0,0 @@ -7b2263727970746f223a207b22636970686572223a20226165732d3132382d637472222c2022636970686572706172616d73223a207b226976223a20223864336365306436393461623131396334363135663935366464653839363063227d2c202263697068657274657874223a20223836333266323430613563306131623665353664222c20226b6466223a202270626b646632222c20226b6466706172616d73223a207b2263223a20313030303030302c2022646b6c656e223a2033322c2022707266223a2022686d61632d736861323536222c202273616c74223a20226566373330376531636464373964376132303338323534656139343433663930227d2c20226d6163223a202266393439383534613530633138363633386363353962336133363665633962353333386633613964373266636635343066313034333361353431636232306438227d2c202276657273696f6e223a20337d \ No newline at end of file diff --git a/hummingbot_files/templates/master_bot_conf/conf/conf_client.yml b/hummingbot_files/templates/master_bot_conf/conf/conf_client.yml deleted file mode 100644 index 9e2b6e1..0000000 --- a/hummingbot_files/templates/master_bot_conf/conf/conf_client.yml +++ /dev/null @@ -1,199 +0,0 @@ -#################################### -### client_config_map config ### -#################################### - -instance_id: hummingbot-master_bot_conf - -log_level: INFO - -debug_console: false - -strategy_report_interval: 900.0 - -logger_override_whitelist: -- hummingbot.strategy.arbitrage -- hummingbot.strategy.cross_exchange_market_making -- conf - -log_file_path: /home/hummingbot/logs - -kill_switch_mode: {} - -# What to auto-fill in the prompt after each import command (start/config) -autofill_import: disabled - -telegram_mode: {} - -# MQTT Bridge configuration. -mqtt_bridge: - mqtt_host: localhost - mqtt_port: 1883 - mqtt_username: '' - mqtt_password: '' - mqtt_namespace: hbot - mqtt_ssl: false - mqtt_logger: true - mqtt_notifier: true - mqtt_commands: true - mqtt_events: true - mqtt_external_events: true - mqtt_autostart: true - -# Error log sharing -send_error_logs: true - -# Can store the previous strategy ran for quick retrieval. -previous_strategy: null - -# Advanced database options, currently supports SQLAlchemy's included dialects -# Reference: https://docs.sqlalchemy.org/en/13/dialects/ -# To use an instance of SQLite DB the required configuration is -# db_engine: sqlite -# To use a DBMS the required configuration is -# db_host: 127.0.0.1 -# db_port: 3306 -# db_username: username -# db_password: password -# db_name: dbname -db_mode: - db_engine: sqlite - -pmm_script_mode: {} - -# Balance Limit Configurations -# e.g. Setting USDT and BTC limits on Binance. -# balance_asset_limit: -# binance: -# BTC: 0.1 -# USDT: 1000 -balance_asset_limit: - altmarkets: {} - ascend_ex: {} - ascend_ex_paper_trade: {} - binance: {} - binance_paper_trade: {} - binance_us: {} - bitfinex: {} - bitmart: {} - bitmex: {} - bitmex_testnet: {} - bittrex: {} - btc_markets: {} - bybit: {} - bybit_testnet: {} - ciex: {} - coinbase_pro: {} - crypto_com: {} - foxbit: {} - gate_io: {} - gate_io_paper_trade: {} - hitbtc: {} - hotbit: {} - huobi: {} - kraken: {} - kucoin: {} - kucoin_paper_trade: {} - lbank: {} - loopring: {} - mexc: {} - mock_paper_exchange: {} - ndax: {} - ndax_testnet: {} - okx: {} - probit: {} - probit_kr: {} - whitebit: {} - -# Fixed gas price (in Gwei) for Ethereum transactions -manual_gas_price: 50.0 - -# Gateway API Configurations -# default host to only use localhost -# Port need to match the final installation port for Gateway -gateway: - gateway_api_host: localhost - gateway_api_port: '15888' - -certs_path: /home/hummingbot/certs - -# Whether to enable aggregated order and trade data collection -anonymized_metrics_mode: - anonymized_metrics_interval_min: 15.0 - -# Command Shortcuts -# Define abbreviations for often used commands -# or batch grouped commands together -command_shortcuts: -- command: spreads - help: Set bid and ask spread - arguments: - - Bid Spread - - Ask Spread - output: - - config bid_spread $1 - - config ask_spread $2 - -# A source for rate oracle, currently ascend_ex, binance, coin_gecko, coin_cap, kucoin, gate_io -rate_oracle_source: - name: binance - -# A universal token which to display tokens values in, e.g. USD,EUR,BTC -global_token: - global_token_name: USD - global_token_symbol: $ - -# Percentage of API rate limits (on any exchange and any end point) allocated to this bot instance. -# Enter 50 to indicate 50%. E.g. if the API rate limit is 100 calls per second, and you allocate -# 50% to this setting, the bot will have a maximum (limit) of 50 calls per second -rate_limits_share_pct: 100.0 - -commands_timeout: - create_command_timeout: 10.0 - other_commands_timeout: 30.0 - -# Tabulate table format style (https://github.com/astanin/python-tabulate#table-format) -tables_format: psql - -paper_trade: - paper_trade_exchanges: - - binance - - kucoin - - ascend_ex - - gate_io - paper_trade_account_balance: - BTC: 1.0 - DAI: 1000.0 - ETH: 10.0 - ONE: 1000.0 - TUSD: 1000.0 - USDC: 1000.0 - USDQ: 1000.0 - USDT: 1000.0 - WETH: 10.0 - -color: - top_pane: '#000000' - bottom_pane: '#000000' - output_pane: '#262626' - input_pane: '#1C1C1C' - logs_pane: '#121212' - terminal_primary: '#5FFFD7' - primary_label: '#5FFFD7' - secondary_label: '#FFFFFF' - success_label: '#5FFFD7' - warning_label: '#FFFF00' - info_label: '#5FD7FF' - error_label: '#FF0000' - gold_label: '#FFD700' - silver_label: '#C0C0C0' - bronze_label: '#CD7F32' - -# The tick size is the frequency with which the clock notifies the time iterators by calling the -# c_tick() method, that means for example that if the tick size is 1, the logic of the strategy -# will run every second. -tick_size: 1.0 - -market_data_collection: - market_data_collection_enabled: true - market_data_collection_interval: 60 - market_data_collection_depth: 20 diff --git a/hummingbot_files/templates/master_bot_conf/conf/conf_fee_overrides.yml b/hummingbot_files/templates/master_bot_conf/conf/conf_fee_overrides.yml deleted file mode 100644 index 8648bb5..0000000 --- a/hummingbot_files/templates/master_bot_conf/conf/conf_fee_overrides.yml +++ /dev/null @@ -1,340 +0,0 @@ -######################################## -### Fee overrides configurations ### -######################################## - -# For more detailed information: https://docs.hummingbot.io -template_version: 14 - -# Example of the fields that can be specified to override the `TradeFeeFactory` default settings. -# If the field is missing or the value is left blank, the default value will be used. -# The percentage values are specified as 0.1 for 0.1%. -# -# [exchange name]_percent_fee_token: -# [exchange name]_maker_percent_fee: -# [exchange name]_taker_percent_fee: -# [exchange name]_buy_percent_fee_deducted_from_returns: # if False, the buy fee is added to the order costs -# [exchange name]_maker_fixed_fees: # a list of lists of token-fee pairs (e.g. [["ETH", 1]]) -# [exchange name]_taker_fixed_fees: # a list of lists of token-fee pairs (e.g. [["ETH", 1]]) - -binance_percent_fee_token: # BNB -binance_maker_percent_fee: # 0.75 -binance_taker_percent_fee: # 0.75 -binance_buy_percent_fee_deducted_from_returns: # True - -# List of supported Exchanges for which the user's data_downloader/conf_fee_override.yml -# will work. This file currently needs to be in sync with hummingbot list of -# supported exchanges -altmarkets_buy_percent_fee_deducted_from_returns: -altmarkets_maker_fixed_fees: -altmarkets_maker_percent_fee: -altmarkets_percent_fee_token: -altmarkets_taker_fixed_fees: -altmarkets_taker_percent_fee: -ascend_ex_buy_percent_fee_deducted_from_returns: -ascend_ex_maker_fixed_fees: -ascend_ex_maker_percent_fee: -ascend_ex_percent_fee_token: -ascend_ex_taker_fixed_fees: -ascend_ex_taker_percent_fee: -binance_maker_fixed_fees: -binance_perpetual_buy_percent_fee_deducted_from_returns: -binance_perpetual_maker_fixed_fees: -binance_perpetual_maker_percent_fee: -binance_perpetual_percent_fee_token: -binance_perpetual_taker_fixed_fees: -binance_perpetual_taker_percent_fee: -binance_perpetual_testnet_buy_percent_fee_deducted_from_returns: -binance_perpetual_testnet_maker_fixed_fees: -binance_perpetual_testnet_maker_percent_fee: -binance_perpetual_testnet_percent_fee_token: -binance_perpetual_testnet_taker_fixed_fees: -binance_perpetual_testnet_taker_percent_fee: -binance_taker_fixed_fees: -binance_us_buy_percent_fee_deducted_from_returns: -binance_us_maker_fixed_fees: -binance_us_maker_percent_fee: -binance_us_percent_fee_token: -binance_us_taker_fixed_fees: -binance_us_taker_percent_fee: -bitfinex_buy_percent_fee_deducted_from_returns: -bitfinex_maker_fixed_fees: -bitfinex_maker_percent_fee: -bitfinex_percent_fee_token: -bitfinex_taker_fixed_fees: -bitfinex_taker_percent_fee: -bitmart_buy_percent_fee_deducted_from_returns: -bitmart_maker_fixed_fees: -bitmart_maker_percent_fee: -bitmart_percent_fee_token: -bitmart_taker_fixed_fees: -bitmart_taker_percent_fee: -bittrex_buy_percent_fee_deducted_from_returns: -bittrex_maker_fixed_fees: -bittrex_maker_percent_fee: -bittrex_percent_fee_token: -bittrex_taker_fixed_fees: -bittrex_taker_percent_fee: -btc_markets_percent_fee_token: -btc_markets_maker_percent_fee: -btc_markets_taker_percent_fee: -btc_markets_buy_percent_fee_deducted_from_returns: -bybit_perpetual_buy_percent_fee_deducted_from_returns: -bybit_perpetual_maker_fixed_fees: -bybit_perpetual_maker_percent_fee: -bybit_perpetual_percent_fee_token: -bybit_perpetual_taker_fixed_fees: -bybit_perpetual_taker_percent_fee: -bybit_perpetual_testnet_buy_percent_fee_deducted_from_returns: -bybit_perpetual_testnet_maker_fixed_fees: -bybit_perpetual_testnet_maker_percent_fee: -bybit_perpetual_testnet_percent_fee_token: -bybit_perpetual_testnet_taker_fixed_fees: -bybit_perpetual_testnet_taker_percent_fee: -coinbase_pro_buy_percent_fee_deducted_from_returns: -coinbase_pro_maker_fixed_fees: -coinbase_pro_maker_percent_fee: -coinbase_pro_percent_fee_token: -coinbase_pro_taker_fixed_fees: -coinbase_pro_taker_percent_fee: -crypto_com_buy_percent_fee_deducted_from_returns: -crypto_com_maker_fixed_fees: -crypto_com_maker_percent_fee: -crypto_com_percent_fee_token: -crypto_com_taker_fixed_fees: -crypto_com_taker_percent_fee: -dydx_perpetual_buy_percent_fee_deducted_from_returns: -dydx_perpetual_maker_fixed_fees: -dydx_perpetual_maker_percent_fee: -dydx_perpetual_percent_fee_token: -dydx_perpetual_taker_fixed_fees: -dydx_perpetual_taker_percent_fee: -gate_io_buy_percent_fee_deducted_from_returns: -gate_io_maker_fixed_fees: -gate_io_maker_percent_fee: -gate_io_percent_fee_token: -gate_io_taker_fixed_fees: -gate_io_taker_percent_fee: -hitbtc_buy_percent_fee_deducted_from_returns: -hitbtc_maker_fixed_fees: -hitbtc_maker_percent_fee: -hitbtc_percent_fee_token: -hitbtc_taker_fixed_fees: -hitbtc_taker_percent_fee: -huobi_buy_percent_fee_deducted_from_returns: -huobi_maker_fixed_fees: -huobi_maker_percent_fee: -huobi_percent_fee_token: -huobi_taker_fixed_fees: -huobi_taker_percent_fee: -kraken_buy_percent_fee_deducted_from_returns: -kraken_maker_fixed_fees: -kraken_maker_percent_fee: -kraken_percent_fee_token: -kraken_taker_fixed_fees: -kraken_taker_percent_fee: -kucoin_buy_percent_fee_deducted_from_returns: -kucoin_maker_fixed_fees: -kucoin_maker_percent_fee: -kucoin_percent_fee_token: -kucoin_taker_fixed_fees: -kucoin_taker_percent_fee: -loopring_buy_percent_fee_deducted_from_returns: -loopring_maker_fixed_fees: -loopring_maker_percent_fee: -loopring_percent_fee_token: -loopring_taker_fixed_fees: -loopring_taker_percent_fee: -mexc_buy_percent_fee_deducted_from_returns: -mexc_maker_fixed_fees: -mexc_maker_percent_fee: -mexc_percent_fee_token: -mexc_taker_fixed_fees: -mexc_taker_percent_fee: -ndax_buy_percent_fee_deducted_from_returns: -ndax_maker_fixed_fees: -ndax_maker_percent_fee: -ndax_percent_fee_token: -ndax_taker_fixed_fees: -ndax_taker_percent_fee: -ndax_testnet_buy_percent_fee_deducted_from_returns: -ndax_testnet_maker_fixed_fees: -ndax_testnet_maker_percent_fee: -ndax_testnet_percent_fee_token: -ndax_testnet_taker_fixed_fees: -ndax_testnet_taker_percent_fee: -okx_buy_percent_fee_deducted_from_returns: -okx_maker_fixed_fees: -okx_maker_percent_fee: -okx_percent_fee_token: -okx_taker_fixed_fees: -okx_taker_percent_fee: -probit_buy_percent_fee_deducted_from_returns: -probit_kr_buy_percent_fee_deducted_from_returns: -probit_kr_maker_fixed_fees: -probit_kr_maker_percent_fee: -probit_kr_percent_fee_token: -probit_kr_taker_fixed_fees: -probit_kr_taker_percent_fee: -probit_maker_fixed_fees: -probit_maker_percent_fee: -probit_percent_fee_token: -probit_taker_fixed_fees: -probit_taker_percent_fee: -bitmex_perpetual_percent_fee_token: -bitmex_perpetual_maker_percent_fee: -bitmex_perpetual_taker_percent_fee: -bitmex_perpetual_buy_percent_fee_deducted_from_returns: -bitmex_perpetual_maker_fixed_fees: -bitmex_perpetual_taker_fixed_fees: -bitmex_perpetual_testnet_percent_fee_token: -bitmex_perpetual_testnet_maker_percent_fee: -bitmex_perpetual_testnet_taker_percent_fee: -bitmex_perpetual_testnet_buy_percent_fee_deducted_from_returns: -bitmex_perpetual_testnet_maker_fixed_fees: -bitmex_perpetual_testnet_taker_fixed_fees: -kucoin_perpetual_percent_fee_token: -kucoin_perpetual_maker_percent_fee: -kucoin_perpetual_taker_percent_fee: -kucoin_perpetual_buy_percent_fee_deducted_from_returns: -kucoin_perpetual_maker_fixed_fees: -kucoin_perpetual_taker_fixed_fees: -kucoin_perpetual_testnet_percent_fee_token: -kucoin_perpetual_testnet_maker_percent_fee: -kucoin_perpetual_testnet_taker_percent_fee: -kucoin_perpetual_testnet_buy_percent_fee_deducted_from_returns: -kucoin_perpetual_testnet_maker_fixed_fees: -kucoin_perpetual_testnet_taker_fixed_fees: -gate_io_perpetual_percent_fee_token: -gate_io_perpetual_maker_percent_fee: -gate_io_perpetual_taker_percent_fee: -gate_io_perpetual_buy_percent_fee_deducted_from_returns: -gate_io_perpetual_maker_fixed_fees: -gate_io_perpetual_taker_fixed_fees: -phemex_perpetual_percent_fee_token: -phemex_perpetual_maker_percent_fee: -phemex_perpetual_taker_percent_fee: -phemex_perpetual_buy_percent_fee_deducted_from_returns: -phemex_perpetual_maker_fixed_fees: -phemex_perpetual_taker_fixed_fees: -phemex_perpetual_testnet_percent_fee_token: -phemex_perpetual_testnet_maker_percent_fee: -phemex_perpetual_testnet_taker_percent_fee: -phemex_perpetual_testnet_buy_percent_fee_deducted_from_returns: -phemex_perpetual_testnet_maker_fixed_fees: -phemex_perpetual_testnet_taker_fixed_fees: -bitget_perpetual_percent_fee_token: -bitget_perpetual_maker_percent_fee: -bitget_perpetual_taker_percent_fee: -bitget_perpetual_buy_percent_fee_deducted_from_returns: -bitget_perpetual_maker_fixed_fees: -bitget_perpetual_taker_fixed_fees: -bit_com_perpetual_percent_fee_token: -bit_com_perpetual_maker_percent_fee: -bit_com_perpetual_taker_percent_fee: -bit_com_perpetual_buy_percent_fee_deducted_from_returns: -bit_com_perpetual_maker_fixed_fees: -bit_com_perpetual_taker_fixed_fees: -bit_com_perpetual_testnet_percent_fee_token: -bit_com_perpetual_testnet_maker_percent_fee: -bit_com_perpetual_testnet_taker_percent_fee: -bit_com_perpetual_testnet_buy_percent_fee_deducted_from_returns: -bit_com_perpetual_testnet_maker_fixed_fees: -bit_com_perpetual_testnet_taker_fixed_fees: -whitebit_percent_fee_token: -whitebit_maker_percent_fee: -whitebit_taker_percent_fee: -whitebit_buy_percent_fee_deducted_from_returns: -whitebit_maker_fixed_fees: -whitebit_taker_fixed_fees: -bitmex_percent_fee_token: -bitmex_maker_percent_fee: -bitmex_taker_percent_fee: -bitmex_buy_percent_fee_deducted_from_returns: -bitmex_maker_fixed_fees: -bitmex_taker_fixed_fees: -bitmex_testnet_percent_fee_token: -bitmex_testnet_maker_percent_fee: -bitmex_testnet_taker_percent_fee: -bitmex_testnet_buy_percent_fee_deducted_from_returns: -bitmex_testnet_maker_fixed_fees: -bitmex_testnet_taker_fixed_fees: -ciex_percent_fee_token: -ciex_maker_percent_fee: -ciex_taker_percent_fee: -ciex_buy_percent_fee_deducted_from_returns: -ciex_maker_fixed_fees: -ciex_taker_fixed_fees: -foxbit_percent_fee_token: -foxbit_maker_percent_fee: -foxbit_taker_percent_fee: -foxbit_buy_percent_fee_deducted_from_returns: -foxbit_maker_fixed_fees: -foxbit_taker_fixed_fees: -lbank_percent_fee_token: -lbank_maker_percent_fee: -lbank_taker_percent_fee: -lbank_buy_percent_fee_deducted_from_returns: -lbank_maker_fixed_fees: -lbank_taker_fixed_fees: -bybit_percent_fee_token: -bybit_maker_percent_fee: -bybit_taker_percent_fee: -bybit_buy_percent_fee_deducted_from_returns: -bybit_maker_fixed_fees: -bybit_taker_fixed_fees: -bybit_testnet_percent_fee_token: -bybit_testnet_maker_percent_fee: -bybit_testnet_taker_percent_fee: -bybit_testnet_buy_percent_fee_deducted_from_returns: -bybit_testnet_maker_fixed_fees: -bybit_testnet_taker_fixed_fees: -hotbit_percent_fee_token: -hotbit_maker_percent_fee: -hotbit_taker_percent_fee: -hotbit_buy_percent_fee_deducted_from_returns: -hotbit_maker_fixed_fees: -hotbit_taker_fixed_fees: -btc_markets_maker_fixed_fees: -btc_markets_taker_fixed_fees: -polkadex_percent_fee_token: -polkadex_maker_percent_fee: -polkadex_taker_percent_fee: -polkadex_buy_percent_fee_deducted_from_returns: -polkadex_maker_fixed_fees: -polkadex_taker_fixed_fees: -vertex_percent_fee_token: -vertex_maker_percent_fee: -vertex_taker_percent_fee: -vertex_buy_percent_fee_deducted_from_returns: -vertex_maker_fixed_fees: -vertex_taker_fixed_fees: -vertex_testnet_percent_fee_token: -vertex_testnet_maker_percent_fee: -vertex_testnet_taker_percent_fee: -vertex_testnet_buy_percent_fee_deducted_from_returns: -vertex_testnet_maker_fixed_fees: -vertex_testnet_taker_fixed_fees: -woo_x_percent_fee_token: -woo_x_maker_percent_fee: -woo_x_taker_percent_fee: -woo_x_buy_percent_fee_deducted_from_returns: -woo_x_maker_fixed_fees: -woo_x_taker_fixed_fees: -woo_x_testnet_percent_fee_token: -woo_x_testnet_maker_percent_fee: -woo_x_testnet_taker_percent_fee: -woo_x_testnet_buy_percent_fee_deducted_from_returns: -woo_x_testnet_maker_fixed_fees: -woo_x_testnet_taker_fixed_fees: -injective_v2_percent_fee_token: -injective_v2_maker_percent_fee: -injective_v2_taker_percent_fee: -injective_v2_buy_percent_fee_deducted_from_returns: -injective_v2_maker_fixed_fees: -injective_v2_taker_fixed_fees: -injective_v2_perpetual_percent_fee_token: -injective_v2_perpetual_maker_percent_fee: -injective_v2_perpetual_taker_percent_fee: -injective_v2_perpetual_buy_percent_fee_deducted_from_returns: -injective_v2_perpetual_maker_fixed_fees: -injective_v2_perpetual_taker_fixed_fees: diff --git a/hummingbot_files/templates/master_bot_conf/conf/hummingbot_logs.yml b/hummingbot_files/templates/master_bot_conf/conf/hummingbot_logs.yml deleted file mode 100755 index 8e65271..0000000 --- a/hummingbot_files/templates/master_bot_conf/conf/hummingbot_logs.yml +++ /dev/null @@ -1,83 +0,0 @@ ---- -version: 1 -template_version: 12 - -formatters: - simple: - format: "%(asctime)s - %(process)d - %(name)s - %(levelname)s - %(message)s" - -handlers: - console: - class: hummingbot.logger.cli_handler.CLIHandler - level: DEBUG - formatter: simple - stream: ext://sys.stdout - console_warning: - class: hummingbot.logger.cli_handler.CLIHandler - level: WARNING - formatter: simple - stream: ext://sys.stdout - console_info: - class: hummingbot.logger.cli_handler.CLIHandler - level: INFO - formatter: simple - stream: ext://sys.stdout - file_handler: - class: logging.handlers.TimedRotatingFileHandler - level: DEBUG - formatter: simple - filename: $PROJECT_DIR/logs/logs_$STRATEGY_FILE_PATH.log - encoding: utf8 - when: "D" - interval: 1 - backupCount: 7 - "null": - class: logging.NullHandler - level: DEBUG - -loggers: - hummingbot.core.utils.eth_gas_station_lookup: - level: NETWORK - propagate: false - handlers: [console, file_handler] - mqtt: true - hummingbot.logger.log_server_client: - level: WARNING - propagate: false - handlers: [console, file_handler] - mqtt: true - hummingbot.logger.reporting_proxy_handler: - level: WARNING - propagate: false - handlers: [console, file_handler] - mqtt: true - hummingbot.strategy: - level: NETWORK - propagate: false - handlers: [console, file_handler] - mqtt: true - hummingbot.connector: - level: NETWORK - propagate: false - handlers: [console, file_handler] - mqtt: true - hummingbot.client: - level: NETWORK - propagate: false - handlers: [console, file_handler] - mqtt: true - hummingbot.core.event.event_reporter: - level: EVENT_LOG - propagate: false - handlers: [file_handler] - mqtt: false - conf: - level: NETWORK - handlers: ["null"] - propagate: false - mqtt: false - -root: - level: INFO - handlers: [console, file_handler] - mqtt: true diff --git a/hummingbot_files/templates/master_bot_conf/scripts/download_candles.py b/hummingbot_files/templates/master_bot_conf/scripts/download_candles.py deleted file mode 100644 index 4e56cc2..0000000 --- a/hummingbot_files/templates/master_bot_conf/scripts/download_candles.py +++ /dev/null @@ -1,61 +0,0 @@ -import os -from typing import Dict - -from hummingbot import data_path -from hummingbot.client.hummingbot_application import HummingbotApplication -from hummingbot.connector.connector_base import ConnectorBase -from hummingbot.data_feed.candles_feed.candles_factory import CandlesConfig, CandlesFactory -from hummingbot.strategy.script_strategy_base import ScriptStrategyBase - - -class DownloadCandles(ScriptStrategyBase): - """ - This script provides an example of how to use the Candles Feed to download and store historical data. - It downloads 3-minute candles for 3 Binance trading pairs ["APE-USDT", "BTC-USDT", "BNB-USDT"] and stores them in - CSV files in the /data directory. The script stops after it has downloaded 50,000 max_records records for each pair. - Is important to notice that the component will fail if all the candles are not available since the idea of it is to - use it in production based on candles needed to compute technical indicators. - """ - exchange = os.getenv("EXCHANGE", "binance_perpetual") - trading_pairs = os.getenv("TRADING_PAIRS", "DODO-BUSD,LTC-USDT").split(",") - intervals = os.getenv("INTERVALS", "1m,3m,5m,1h").split(",") - days_to_download = int(os.getenv("DAYS_TO_DOWNLOAD", "3")) - # we can initialize any trading pair since we only need the candles - markets = {"binance_paper_trade": {"BTC-USDT"}} - - @staticmethod - def get_max_records(days_to_download: int, interval: str) -> int: - conversion = {"m": 1, "h": 60, "d": 1440} - unit = interval[-1] - quantity = int(interval[:-1]) - return int(days_to_download * 24 * 60 / (quantity * conversion[unit])) - - def __init__(self, connectors: Dict[str, ConnectorBase]): - super().__init__(connectors) - combinations = [(trading_pair, interval) for trading_pair in self.trading_pairs for interval in self.intervals] - - self.candles = {f"{combinations[0]}_{combinations[1]}": {} for combinations in combinations} - # we need to initialize the candles for each trading pair - for combination in combinations: - - candle = CandlesFactory.get_candle(CandlesConfig(connector=self.exchange, trading_pair=combination[0], interval=combination[1], max_records=self.get_max_records(self.days_to_download, combination[1]))) - candle.start() - # we are storing the candles object and the csv path to save the candles - self.candles[f"{combination[0]}_{combination[1]}"]["candles"] = candle - self.candles[f"{combination[0]}_{combination[1]}"][ - "csv_path"] = data_path() + f"/candles_{self.exchange}_{combination[0]}_{combination[1]}.csv" - - def on_tick(self): - for trading_pair, candles_info in self.candles.items(): - if not candles_info["candles"].is_ready: - self.logger().info(f"Candles not ready yet for {trading_pair}! Missing {candles_info['candles']._candles.maxlen - len(candles_info['candles']._candles)}") - pass - else: - df = candles_info["candles"].candles_df - df.to_csv(candles_info["csv_path"], index=False) - if all(candles_info["candles"].is_ready for candles_info in self.candles.values()): - HummingbotApplication.main_application().stop() - - def on_stop(self): - for candles_info in self.candles.values(): - candles_info["candles"].stop() diff --git a/hummingbot_files/templates/master_bot_conf/scripts/download_order_book_and_trades.py b/hummingbot_files/templates/master_bot_conf/scripts/download_order_book_and_trades.py deleted file mode 100644 index d9c754f..0000000 --- a/hummingbot_files/templates/master_bot_conf/scripts/download_order_book_and_trades.py +++ /dev/null @@ -1,99 +0,0 @@ -import json -import os -from datetime import datetime -from typing import Dict - -from hummingbot import data_path -from hummingbot.connector.connector_base import ConnectorBase -from hummingbot.core.event.event_forwarder import SourceInfoEventForwarder -from hummingbot.core.event.events import OrderBookEvent, OrderBookTradeEvent -from hummingbot.strategy.script_strategy_base import ScriptStrategyBase - - -class DownloadTradesAndOrderBookSnapshots(ScriptStrategyBase): - exchange = os.getenv("EXCHANGE", "binance_paper_trade") - trading_pairs = os.getenv("TRADING_PAIRS", "ETH-USDT,BTC-USDT") - depth = int(os.getenv("DEPTH", 50)) - trading_pairs = [pair for pair in trading_pairs.split(",")] - last_dump_timestamp = 0 - time_between_csv_dumps = 10 - - ob_temp_storage = {trading_pair: [] for trading_pair in trading_pairs} - trades_temp_storage = {trading_pair: [] for trading_pair in trading_pairs} - current_date = None - ob_file_paths = {} - trades_file_paths = {} - markets = {exchange: set(trading_pairs)} - subscribed_to_order_book_trade_event: bool = False - - def __init__(self, connectors: Dict[str, ConnectorBase]): - super().__init__(connectors) - self.create_order_book_and_trade_files() - self.order_book_trade_event = SourceInfoEventForwarder(self._process_public_trade) - - def on_tick(self): - if not self.subscribed_to_order_book_trade_event: - self.subscribe_to_order_book_trade_event() - self.check_and_replace_files() - for trading_pair in self.trading_pairs: - order_book_data = self.get_order_book_dict(self.exchange, trading_pair, self.depth) - self.ob_temp_storage[trading_pair].append(order_book_data) - if self.last_dump_timestamp < self.current_timestamp: - self.dump_and_clean_temp_storage() - - def get_order_book_dict(self, exchange: str, trading_pair: str, depth: int = 50): - order_book = self.connectors[exchange].get_order_book(trading_pair) - snapshot = order_book.snapshot - return { - "ts": self.current_timestamp, - "bids": snapshot[0].loc[:(depth - 1), ["price", "amount"]].values.tolist(), - "asks": snapshot[1].loc[:(depth - 1), ["price", "amount"]].values.tolist(), - } - - def dump_and_clean_temp_storage(self): - for trading_pair, order_book_info in self.ob_temp_storage.items(): - file = self.ob_file_paths[trading_pair] - json_strings = [json.dumps(obj) for obj in order_book_info] - json_data = '\n'.join(json_strings) - file.write(json_data) - self.ob_temp_storage[trading_pair] = [] - for trading_pair, trades_info in self.trades_temp_storage.items(): - file = self.trades_file_paths[trading_pair] - json_strings = [json.dumps(obj) for obj in trades_info] - json_data = '\n'.join(json_strings) - file.write(json_data) - self.trades_temp_storage[trading_pair] = [] - self.last_dump_timestamp = self.current_timestamp + self.time_between_csv_dumps - - def check_and_replace_files(self): - current_date = datetime.now().strftime("%Y-%m-%d") - if current_date != self.current_date: - for file in self.ob_file_paths.values(): - file.close() - self.create_order_book_and_trade_files() - - def create_order_book_and_trade_files(self): - self.current_date = datetime.now().strftime("%Y-%m-%d") - self.ob_file_paths = {trading_pair: self.get_file(self.exchange, trading_pair, "order_book_snapshots", self.current_date) for - trading_pair in self.trading_pairs} - self.trades_file_paths = {trading_pair: self.get_file(self.exchange, trading_pair, "trades", self.current_date) for - trading_pair in self.trading_pairs} - - @staticmethod - def get_file(exchange: str, trading_pair: str, source_type: str, current_date: str): - file_path = data_path() + f"/{exchange}_{trading_pair}_{source_type}_{current_date}.txt" - return open(file_path, "a") - - def _process_public_trade(self, event_tag: int, market: ConnectorBase, event: OrderBookTradeEvent): - self.trades_temp_storage[event.trading_pair].append({ - "ts": event.timestamp, - "price": event.price, - "q_base": event.amount, - "side": event.type.name.lower(), - }) - - def subscribe_to_order_book_trade_event(self): - for market in self.connectors.values(): - for order_book in market.order_books.values(): - order_book.add_listener(OrderBookEvent.TradeEvent, self.order_book_trade_event) - self.subscribed_to_order_book_trade_event = True diff --git a/hummingbot_files/templates/master_bot_conf/scripts/fixed_grid.py b/hummingbot_files/templates/master_bot_conf/scripts/fixed_grid.py deleted file mode 100644 index 09cfc4a..0000000 --- a/hummingbot_files/templates/master_bot_conf/scripts/fixed_grid.py +++ /dev/null @@ -1,341 +0,0 @@ -import logging -from decimal import Decimal -from typing import Dict, List - -import numpy as np -import pandas as pd - -from hummingbot.connector.connector_base import ConnectorBase -from hummingbot.core.data_type.common import OrderType, PriceType, TradeType -from hummingbot.core.data_type.order_candidate import OrderCandidate -from hummingbot.core.event.events import BuyOrderCompletedEvent, OrderFilledEvent, SellOrderCompletedEvent -from hummingbot.core.utils import map_df_to_str -from hummingbot.strategy.script_strategy_base import ScriptStrategyBase - - -class FixedGrid(ScriptStrategyBase): - # Parameters to modify ----------------------------------------- - trading_pair = "ENJ-USDT" - exchange = "ascend_ex" - n_levels = 8 - grid_price_ceiling = Decimal(0.33) - grid_price_floor = Decimal(0.3) - order_amount = Decimal(18.0) - # Optional ---------------------- - spread_scale_factor = Decimal(1.0) - amount_scale_factor = Decimal(1.0) - rebalance_order_type = "limit" - rebalance_order_spread = Decimal(0.02) - rebalance_order_refresh_time = 60.0 - grid_orders_refresh_time = 3600000.0 - price_source = PriceType.MidPrice - # ---------------------------------------------------------------- - - markets = {exchange: {trading_pair}} - create_timestamp = 0 - price_levels = [] - base_inv_levels = [] - quote_inv_levels = [] - order_amount_levels = [] - quote_inv_levels_current_price = [] - current_level = -100 - grid_spread = (grid_price_ceiling - grid_price_floor) / (n_levels - 1) - inv_correct = True - rebalance_order_amount = Decimal(0.0) - rebalance_order_buy = True - - def __init__(self, connectors: Dict[str, ConnectorBase]): - super().__init__(connectors) - - self.minimum_spread = (self.grid_price_ceiling - self.grid_price_floor) / (1 + 2 * sum([pow(self.spread_scale_factor, n) for n in range(1, int(self.n_levels / 2))])) - self.price_levels.append(self.grid_price_floor) - for i in range(2, int(self.n_levels / 2) + 1): - price = self.grid_price_floor + self.minimum_spread * sum([pow(self.spread_scale_factor, int(self.n_levels / 2) - n) for n in range(1, i)]) - self.price_levels.append(price) - for i in range(1, int(self.n_levels / 2) + 1): - self.order_amount_levels.append(self.order_amount * pow(self.amount_scale_factor, int(self.n_levels / 2) - i)) - - for i in range(int(self.n_levels / 2) + 1, self.n_levels + 1): - price = self.price_levels[int(self.n_levels / 2) - 1] + self.minimum_spread * sum([pow(self.spread_scale_factor, n) for n in range(0, i - int(self.n_levels / 2))]) - self.price_levels.append(price) - self.order_amount_levels.append(self.order_amount * pow(self.amount_scale_factor, i - int(self.n_levels / 2) - 1)) - - for i in range(1, self.n_levels + 1): - self.base_inv_levels.append(sum(self.order_amount_levels[i:self.n_levels])) - self.quote_inv_levels.append(sum([self.price_levels[n] * self.order_amount_levels[n] for n in range(0, i - 1)])) - for i in range(self.n_levels): - self.quote_inv_levels_current_price.append(self.quote_inv_levels[i] / self.price_levels[i]) - - def on_tick(self): - proposal = None - if self.create_timestamp <= self.current_timestamp: - # If grid level not yet set, find it. - if self.current_level == -100: - price = self.connectors[self.exchange].get_price_by_type(self.trading_pair, self.price_source) - # Find level closest to market - min_diff = 1e8 - for i in range(self.n_levels): - if min(min_diff, abs(self.price_levels[i] - price)) < min_diff: - min_diff = abs(self.price_levels[i] - price) - self.current_level = i - - msg = (f"Current price {price}, Initial level {self.current_level+1}") - self.log_with_clock(logging.INFO, msg) - self.notify_hb_app_with_timestamp(msg) - - if price > self.grid_price_ceiling: - msg = ("WARNING: Current price is above grid ceiling") - self.log_with_clock(logging.WARNING, msg) - self.notify_hb_app_with_timestamp(msg) - elif price < self.grid_price_floor: - msg = ("WARNING: Current price is below grid floor") - self.log_with_clock(logging.WARNING, msg) - self.notify_hb_app_with_timestamp(msg) - - market, trading_pair, base_asset, quote_asset = self.get_market_trading_pair_tuples()[0] - base_balance = float(market.get_balance(base_asset)) - quote_balance = float(market.get_balance(quote_asset) / self.price_levels[self.current_level]) - - if base_balance < self.base_inv_levels[self.current_level]: - self.inv_correct = False - msg = (f"WARNING: Insuffient {base_asset} balance for grid bot. Will attempt to rebalance") - self.log_with_clock(logging.WARNING, msg) - self.notify_hb_app_with_timestamp(msg) - if base_balance + quote_balance < self.base_inv_levels[self.current_level] + self.quote_inv_levels_current_price[self.current_level]: - msg = (f"WARNING: Insuffient {base_asset} and {quote_asset} balance for grid bot. Unable to rebalance." - f"Please add funds or change grid parameters") - self.log_with_clock(logging.WARNING, msg) - self.notify_hb_app_with_timestamp(msg) - return - else: - # Calculate additional base required with 5% tolerance - base_required = (Decimal(self.base_inv_levels[self.current_level]) - Decimal(base_balance)) * Decimal(1.05) - self.rebalance_order_buy = True - self.rebalance_order_amount = Decimal(base_required) - elif quote_balance < self.quote_inv_levels_current_price[self.current_level]: - self.inv_correct = False - msg = (f"WARNING: Insuffient {quote_asset} balance for grid bot. Will attempt to rebalance") - self.log_with_clock(logging.WARNING, msg) - self.notify_hb_app_with_timestamp(msg) - if base_balance + quote_balance < self.base_inv_levels[self.current_level] + self.quote_inv_levels_current_price[self.current_level]: - msg = (f"WARNING: Insuffient {base_asset} and {quote_asset} balance for grid bot. Unable to rebalance." - f"Please add funds or change grid parameters") - self.log_with_clock(logging.WARNING, msg) - self.notify_hb_app_with_timestamp(msg) - return - else: - # Calculate additional quote required with 5% tolerance - quote_required = (Decimal(self.quote_inv_levels_current_price[self.current_level]) - Decimal(quote_balance)) * Decimal(1.05) - self.rebalance_order_buy = False - self.rebalance_order_amount = Decimal(quote_required) - else: - self.inv_correct = True - - if self.inv_correct is True: - # Create proposals for Grid - proposal = self.create_grid_proposal() - else: - # Create rebalance proposal - proposal = self.create_rebalance_proposal() - - self.cancel_active_orders() - if proposal is not None: - self.execute_orders_proposal(proposal) - - def create_grid_proposal(self) -> List[OrderCandidate]: - buys = [] - sells = [] - - # Proposal will be created according to grid price levels - for i in range(self.current_level): - price = self.price_levels[i] - size = self.order_amount_levels[i] - if size > 0: - buy_order = OrderCandidate(trading_pair=self.trading_pair, is_maker=True, order_type=OrderType.LIMIT, - order_side=TradeType.BUY, amount=size, price=price) - buys.append(buy_order) - - for i in range(self.current_level + 1, self.n_levels): - price = self.price_levels[i] - size = self.order_amount_levels[i] - if size > 0: - sell_order = OrderCandidate(trading_pair=self.trading_pair, is_maker=True, order_type=OrderType.LIMIT, - order_side=TradeType.SELL, amount=size, price=price) - sells.append(sell_order) - - return buys + sells - - def create_rebalance_proposal(self): - buys = [] - sells = [] - - # Proposal will be created according to start order spread. - if self.rebalance_order_buy is True: - ref_price = self.connectors[self.exchange].get_price_by_type(self.trading_pair, self.price_source) - price = ref_price * (Decimal("100") - self.rebalance_order_spread) / Decimal("100") - size = self.rebalance_order_amount - - msg = (f"Placing buy order to rebalance; amount: {size}, price: {price}") - self.log_with_clock(logging.INFO, msg) - self.notify_hb_app_with_timestamp(msg) - if size > 0: - if self.rebalance_order_type == "limit": - buy_order = OrderCandidate(trading_pair=self.trading_pair, is_maker=True, order_type=OrderType.LIMIT, - order_side=TradeType.BUY, amount=size, price=price) - elif self.rebalance_order_type == "market": - buy_order = OrderCandidate(trading_pair=self.trading_pair, is_maker=True, order_type=OrderType.MARKET, - order_side=TradeType.BUY, amount=size, price=price) - buys.append(buy_order) - - if self.rebalance_order_buy is False: - ref_price = self.connectors[self.exchange].get_price_by_type(self.trading_pair, self.price_source) - price = ref_price * (Decimal("100") + self.rebalance_order_spread) / Decimal("100") - size = self.rebalance_order_amount - msg = (f"Placing sell order to rebalance; amount: {size}, price: {price}") - self.log_with_clock(logging.INFO, msg) - self.notify_hb_app_with_timestamp(msg) - if size > 0: - if self.rebalance_order_type == "limit": - sell_order = OrderCandidate(trading_pair=self.trading_pair, is_maker=True, order_type=OrderType.LIMIT, - order_side=TradeType.SELL, amount=size, price=price) - elif self.rebalance_order_type == "market": - sell_order = OrderCandidate(trading_pair=self.trading_pair, is_maker=True, order_type=OrderType.MARKET, - order_side=TradeType.SELL, amount=size, price=price) - sells.append(sell_order) - - return buys + sells - - def did_fill_order(self, event: OrderFilledEvent): - msg = (f"{event.trade_type.name} {round(event.amount, 2)} {event.trading_pair} {self.exchange} at {round(event.price, 2)}") - self.log_with_clock(logging.INFO, msg) - self.notify_hb_app_with_timestamp(msg) - - def did_complete_buy_order(self, event: BuyOrderCompletedEvent): - if self.inv_correct is False: - self.create_timestamp = self.current_timestamp + float(1.0) - - if self.inv_correct is True: - # Set the new level - self.current_level -= 1 - # Add sell order above current level - price = self.price_levels[self.current_level + 1] - size = self.order_amount_levels[self.current_level + 1] - proposal = [OrderCandidate(trading_pair=self.trading_pair, is_maker=True, order_type=OrderType.LIMIT, - order_side=TradeType.SELL, amount=size, price=price)] - self.execute_orders_proposal(proposal) - - def did_complete_sell_order(self, event: SellOrderCompletedEvent): - if self.inv_correct is False: - self.create_timestamp = self.current_timestamp + float(1.0) - - if self.inv_correct is True: - # Set the new level - self.current_level += 1 - # Add buy order above current level - price = self.price_levels[self.current_level - 1] - size = self.order_amount_levels[self.current_level - 1] - proposal = [OrderCandidate(trading_pair=self.trading_pair, is_maker=True, order_type=OrderType.LIMIT, - order_side=TradeType.BUY, amount=size, price=price)] - self.execute_orders_proposal(proposal) - - def execute_orders_proposal(self, proposal: List[OrderCandidate]) -> None: - for order in proposal: - self.place_order(connector_name=self.exchange, order=order) - if self.inv_correct is False: - next_cycle = self.current_timestamp + self.rebalance_order_refresh_time - if self.create_timestamp <= self.current_timestamp: - self.create_timestamp = next_cycle - else: - next_cycle = self.current_timestamp + self.grid_orders_refresh_time - if self.create_timestamp <= self.current_timestamp: - self.create_timestamp = next_cycle - - def place_order(self, connector_name: str, order: OrderCandidate): - if order.order_side == TradeType.SELL: - self.sell(connector_name=connector_name, trading_pair=order.trading_pair, amount=order.amount, - order_type=order.order_type, price=order.price) - elif order.order_side == TradeType.BUY: - self.buy(connector_name=connector_name, trading_pair=order.trading_pair, amount=order.amount, - order_type=order.order_type, price=order.price) - - def grid_assets_df(self) -> pd.DataFrame: - market, trading_pair, base_asset, quote_asset = self.get_market_trading_pair_tuples()[0] - price = self.connectors[self.exchange].get_price_by_type(self.trading_pair, self.price_source) - base_balance = float(market.get_balance(base_asset)) - quote_balance = float(market.get_balance(quote_asset)) - available_base_balance = float(market.get_available_balance(base_asset)) - available_quote_balance = float(market.get_available_balance(quote_asset)) - base_value = base_balance * float(price) - total_in_quote = base_value + quote_balance - base_ratio = base_value / total_in_quote if total_in_quote > 0 else 0 - quote_ratio = quote_balance / total_in_quote if total_in_quote > 0 else 0 - data = [ - ["", base_asset, quote_asset], - ["Total Balance", round(base_balance, 4), round(quote_balance, 4)], - ["Available Balance", round(available_base_balance, 4), round(available_quote_balance, 4)], - [f"Current Value ({quote_asset})", round(base_value, 4), round(quote_balance, 4)] - ] - data.append(["Current %", f"{base_ratio:.1%}", f"{quote_ratio:.1%}"]) - df = pd.DataFrame(data=data) - return df - - def grid_status_data_frame(self) -> pd.DataFrame: - grid_data = [] - grid_columns = ["Parameter", "Value"] - - market, trading_pair, base_asset, quote_asset = self.get_market_trading_pair_tuples()[0] - base_balance = float(market.get_balance(base_asset)) - quote_balance = float(market.get_balance(quote_asset) / self.price_levels[self.current_level]) - - grid_data.append(["Grid spread", round(self.grid_spread, 4)]) - grid_data.append(["Current grid level", self.current_level + 1]) - grid_data.append([f"{base_asset} required", round(self.base_inv_levels[self.current_level], 4)]) - grid_data.append([f"{quote_asset} required in {base_asset}", round(self.quote_inv_levels_current_price[self.current_level], 4)]) - grid_data.append([f"{base_asset} balance", round(base_balance, 4)]) - grid_data.append([f"{quote_asset} balance in {base_asset}", round(quote_balance, 4)]) - grid_data.append(["Correct inventory balance", self.inv_correct]) - - return pd.DataFrame(data=grid_data, columns=grid_columns).replace(np.nan, '', regex=True) - - def format_status(self) -> str: - """ - Displays the status of the fixed grid strategy - Returns status of the current strategy on user balances and current active orders. - """ - if not self.ready_to_trade: - return "Market connectors are not ready." - - lines = [] - warning_lines = [] - warning_lines.extend(self.network_warning(self.get_market_trading_pair_tuples())) - - balance_df = self.get_balance_df() - lines.extend(["", " Balances:"] + [" " + line for line in balance_df.to_string(index=False).split("\n")]) - - grid_df = map_df_to_str(self.grid_status_data_frame()) - lines.extend(["", " Grid:"] + [" " + line for line in grid_df.to_string(index=False).split("\n")]) - - assets_df = map_df_to_str(self.grid_assets_df()) - - first_col_length = max(*assets_df[0].apply(len)) - df_lines = assets_df.to_string(index=False, header=False, - formatters={0: ("{:<" + str(first_col_length) + "}").format}).split("\n") - lines.extend(["", " Assets:"] + [" " + line for line in df_lines]) - - try: - df = self.active_orders_df() - lines.extend(["", " Orders:"] + [" " + line for line in df.to_string(index=False).split("\n")]) - except ValueError: - lines.extend(["", " No active maker orders."]) - - warning_lines.extend(self.balance_warning(self.get_market_trading_pair_tuples())) - if len(warning_lines) > 0: - lines.extend(["", "*** WARNINGS ***"] + warning_lines) - return "\n".join(lines) - - def cancel_active_orders(self): - """ - Cancels active orders - """ - for order in self.get_active_orders(connector_name=self.exchange): - self.cancel(self.exchange, order.trading_pair, order.client_order_id) diff --git a/hummingbot_files/templates/master_bot_conf/scripts/simple_arbitrage_example.py b/hummingbot_files/templates/master_bot_conf/scripts/simple_arbitrage_example.py deleted file mode 100644 index fb478ab..0000000 --- a/hummingbot_files/templates/master_bot_conf/scripts/simple_arbitrage_example.py +++ /dev/null @@ -1,193 +0,0 @@ -import logging -from decimal import Decimal -from typing import Any, Dict - -import pandas as pd - -from hummingbot.core.data_type.common import OrderType, TradeType -from hummingbot.core.data_type.order_candidate import OrderCandidate -from hummingbot.core.event.events import OrderFilledEvent -from hummingbot.strategy.script_strategy_base import ScriptStrategyBase - - -class SimpleArbitrage(ScriptStrategyBase): - """ - BotCamp Cohort: Sept 2022 - Design Template: https://hummingbot-foundation.notion.site/Simple-Arbitrage-51b2af6e54b6493dab12e5d537798c07 - Video: TBD - Description: - A simplified version of Hummingbot arbitrage strategy, this bot checks the Volume Weighted Average Price for - bid and ask in two exchanges and if it finds a profitable opportunity, it will trade the tokens. - """ - order_amount = Decimal("0.01") # in base asset - min_profitability = Decimal("0.002") # in percentage - base = "ETH" - quote = "USDT" - trading_pair = f"{base}-{quote}" - exchange_A = "binance_paper_trade" - exchange_B = "kucoin_paper_trade" - - markets = {exchange_A: {trading_pair}, - exchange_B: {trading_pair}} - - def on_tick(self): - vwap_prices = self.get_vwap_prices_for_amount(self.order_amount) - proposal = self.check_profitability_and_create_proposal(vwap_prices) - if len(proposal) > 0: - proposal_adjusted: Dict[str, OrderCandidate] = self.adjust_proposal_to_budget(proposal) - self.place_orders(proposal_adjusted) - - def get_vwap_prices_for_amount(self, amount: Decimal): - bid_ex_a = self.connectors[self.exchange_A].get_vwap_for_volume(self.trading_pair, False, amount) - ask_ex_a = self.connectors[self.exchange_A].get_vwap_for_volume(self.trading_pair, True, amount) - bid_ex_b = self.connectors[self.exchange_B].get_vwap_for_volume(self.trading_pair, False, amount) - ask_ex_b = self.connectors[self.exchange_B].get_vwap_for_volume(self.trading_pair, True, amount) - vwap_prices = { - self.exchange_A: { - "bid": bid_ex_a.result_price, - "ask": ask_ex_a.result_price - }, - self.exchange_B: { - "bid": bid_ex_b.result_price, - "ask": ask_ex_b.result_price - } - } - return vwap_prices - - def get_fees_percentages(self, vwap_prices: Dict[str, Any]) -> Dict: - # We assume that the fee percentage for buying or selling is the same - a_fee = self.connectors[self.exchange_A].get_fee( - base_currency=self.base, - quote_currency=self.quote, - order_type=OrderType.MARKET, - order_side=TradeType.BUY, - amount=self.order_amount, - price=vwap_prices[self.exchange_A]["ask"], - is_maker=False - ).percent - - b_fee = self.connectors[self.exchange_B].get_fee( - base_currency=self.base, - quote_currency=self.quote, - order_type=OrderType.MARKET, - order_side=TradeType.BUY, - amount=self.order_amount, - price=vwap_prices[self.exchange_B]["ask"], - is_maker=False - ).percent - - return { - self.exchange_A: a_fee, - self.exchange_B: b_fee - } - - def get_profitability_analysis(self, vwap_prices: Dict[str, Any]) -> Dict: - fees = self.get_fees_percentages(vwap_prices) - buy_a_sell_b_quote = vwap_prices[self.exchange_A]["ask"] * (1 - fees[self.exchange_A]) * self.order_amount - \ - vwap_prices[self.exchange_B]["bid"] * (1 + fees[self.exchange_B]) * self.order_amount - buy_a_sell_b_base = buy_a_sell_b_quote / ( - (vwap_prices[self.exchange_A]["ask"] + vwap_prices[self.exchange_B]["bid"]) / 2) - - buy_b_sell_a_quote = vwap_prices[self.exchange_B]["ask"] * (1 - fees[self.exchange_B]) * self.order_amount - \ - vwap_prices[self.exchange_A]["bid"] * (1 + fees[self.exchange_A]) * self.order_amount - - buy_b_sell_a_base = buy_b_sell_a_quote / ( - (vwap_prices[self.exchange_B]["ask"] + vwap_prices[self.exchange_A]["bid"]) / 2) - - return { - "buy_a_sell_b": - { - "quote_diff": buy_a_sell_b_quote, - "base_diff": buy_a_sell_b_base, - "profitability_pct": buy_a_sell_b_base / self.order_amount - }, - "buy_b_sell_a": - { - "quote_diff": buy_b_sell_a_quote, - "base_diff": buy_b_sell_a_base, - "profitability_pct": buy_b_sell_a_base / self.order_amount - }, - } - - def check_profitability_and_create_proposal(self, vwap_prices: Dict[str, Any]) -> Dict: - proposal = {} - profitability_analysis = self.get_profitability_analysis(vwap_prices) - if profitability_analysis["buy_a_sell_b"]["profitability_pct"] > self.min_profitability: - # This means that the ask of the first exchange is lower than the bid of the second one - proposal[self.exchange_A] = OrderCandidate(trading_pair=self.trading_pair, is_maker=False, - order_type=OrderType.MARKET, - order_side=TradeType.BUY, amount=self.order_amount, - price=vwap_prices[self.exchange_A]["ask"]) - proposal[self.exchange_B] = OrderCandidate(trading_pair=self.trading_pair, is_maker=False, - order_type=OrderType.MARKET, - order_side=TradeType.SELL, amount=Decimal(self.order_amount), - price=vwap_prices[self.exchange_B]["bid"]) - elif profitability_analysis["buy_b_sell_a"]["profitability_pct"] > self.min_profitability: - # This means that the ask of the second exchange is lower than the bid of the first one - proposal[self.exchange_B] = OrderCandidate(trading_pair=self.trading_pair, is_maker=False, - order_type=OrderType.MARKET, - order_side=TradeType.BUY, amount=self.order_amount, - price=vwap_prices[self.exchange_B]["ask"]) - proposal[self.exchange_A] = OrderCandidate(trading_pair=self.trading_pair, is_maker=False, - order_type=OrderType.MARKET, - order_side=TradeType.SELL, amount=Decimal(self.order_amount), - price=vwap_prices[self.exchange_A]["bid"]) - - return proposal - - def adjust_proposal_to_budget(self, proposal: Dict[str, OrderCandidate]) -> Dict[str, OrderCandidate]: - for connector, order in proposal.items(): - proposal[connector] = self.connectors[connector].budget_checker.adjust_candidate(order, all_or_none=True) - return proposal - - def place_orders(self, proposal: Dict[str, OrderCandidate]) -> None: - for connector, order in proposal.items(): - self.place_order(connector_name=connector, order=order) - - def place_order(self, connector_name: str, order: OrderCandidate): - if order.order_side == TradeType.SELL: - self.sell(connector_name=connector_name, trading_pair=order.trading_pair, amount=order.amount, - order_type=order.order_type, price=order.price) - elif order.order_side == TradeType.BUY: - self.buy(connector_name=connector_name, trading_pair=order.trading_pair, amount=order.amount, - order_type=order.order_type, price=order.price) - - def format_status(self) -> str: - """ - Returns status of the current strategy on user balances and current active orders. This function is called - when status command is issued. Override this function to create custom status display output. - """ - if not self.ready_to_trade: - return "Market connectors are not ready." - lines = [] - warning_lines = [] - warning_lines.extend(self.network_warning(self.get_market_trading_pair_tuples())) - - balance_df = self.get_balance_df() - lines.extend(["", " Balances:"] + [" " + line for line in balance_df.to_string(index=False).split("\n")]) - - vwap_prices = self.get_vwap_prices_for_amount(self.order_amount) - lines.extend(["", " VWAP Prices for amount"] + [" " + line for line in - pd.DataFrame(vwap_prices).to_string().split("\n")]) - profitability_analysis = self.get_profitability_analysis(vwap_prices) - lines.extend(["", " Profitability (%)"] + [ - f" Buy A: {self.exchange_A} --> Sell B: {self.exchange_B}"] + [ - f" Quote Diff: {profitability_analysis['buy_a_sell_b']['quote_diff']:.7f}"] + [ - f" Base Diff: {profitability_analysis['buy_a_sell_b']['base_diff']:.7f}"] + [ - f" Percentage: {profitability_analysis['buy_a_sell_b']['profitability_pct'] * 100:.4f} %"] + [ - f" Buy B: {self.exchange_B} --> Sell A: {self.exchange_A}"] + [ - f" Quote Diff: {profitability_analysis['buy_b_sell_a']['quote_diff']:.7f}"] + [ - f" Base Diff: {profitability_analysis['buy_b_sell_a']['base_diff']:.7f}"] + [ - f" Percentage: {profitability_analysis['buy_b_sell_a']['profitability_pct'] * 100:.4f} %" - ]) - - warning_lines.extend(self.balance_warning(self.get_market_trading_pair_tuples())) - if len(warning_lines) > 0: - lines.extend(["", "*** WARNINGS ***"] + warning_lines) - return "\n".join(lines) - - def did_fill_order(self, event: OrderFilledEvent): - msg = ( - f"{event.trade_type.name} {round(event.amount, 2)} {event.trading_pair} at {round(event.price, 2)}") - self.log_with_clock(logging.INFO, msg) - self.notify_hb_app_with_timestamp(msg) \ No newline at end of file diff --git a/hummingbot_files/templates/master_bot_conf/scripts/simple_pmm_example.py b/hummingbot_files/templates/master_bot_conf/scripts/simple_pmm_example.py deleted file mode 100644 index 8370819..0000000 --- a/hummingbot_files/templates/master_bot_conf/scripts/simple_pmm_example.py +++ /dev/null @@ -1,77 +0,0 @@ -import logging -from decimal import Decimal -from typing import List - -from hummingbot.core.data_type.common import OrderType, PriceType, TradeType -from hummingbot.core.data_type.order_candidate import OrderCandidate -from hummingbot.core.event.events import OrderFilledEvent -from hummingbot.strategy.script_strategy_base import ScriptStrategyBase - - -class SimplePMM(ScriptStrategyBase): - """ - BotCamp Cohort: Sept 2022 - Design Template: https://hummingbot-foundation.notion.site/Simple-PMM-63cc765486dd42228d3da0b32537fc92 - Video: - - Description: - The bot will place two orders around the price_source (mid price or last traded price) in a trading_pair on - exchange, with a distance defined by the ask_spread and bid_spread. Every order_refresh_time in seconds, - the bot will cancel and replace the orders. - """ - bid_spread = 0.0001 - ask_spread = 0.0001 - order_refresh_time = 15 - order_amount = 0.01 - create_timestamp = 0 - trading_pair = "ETH-USDT" - exchange = "binance_paper_trade" - # Here you can use for example the LastTrade price to use in your strategy - price_source = PriceType.MidPrice - - markets = {exchange: {trading_pair}} - - def on_tick(self): - if self.create_timestamp <= self.current_timestamp: - self.cancel_all_orders() - proposal: List[OrderCandidate] = self.create_proposal() - proposal_adjusted: List[OrderCandidate] = self.adjust_proposal_to_budget(proposal) - self.place_orders(proposal_adjusted) - self.create_timestamp = self.order_refresh_time + self.current_timestamp - - def create_proposal(self) -> List[OrderCandidate]: - ref_price = self.connectors[self.exchange].get_price_by_type(self.trading_pair, self.price_source) - buy_price = ref_price * Decimal(1 - self.bid_spread) - sell_price = ref_price * Decimal(1 + self.ask_spread) - - buy_order = OrderCandidate(trading_pair=self.trading_pair, is_maker=True, order_type=OrderType.LIMIT, - order_side=TradeType.BUY, amount=Decimal(self.order_amount), price=buy_price) - - sell_order = OrderCandidate(trading_pair=self.trading_pair, is_maker=True, order_type=OrderType.LIMIT, - order_side=TradeType.SELL, amount=Decimal(self.order_amount), price=sell_price) - - return [buy_order, sell_order] - - def adjust_proposal_to_budget(self, proposal: List[OrderCandidate]) -> List[OrderCandidate]: - proposal_adjusted = self.connectors[self.exchange].budget_checker.adjust_candidates(proposal, all_or_none=True) - return proposal_adjusted - - def place_orders(self, proposal: List[OrderCandidate]) -> None: - for order in proposal: - self.place_order(connector_name=self.exchange, order=order) - - def place_order(self, connector_name: str, order: OrderCandidate): - if order.order_side == TradeType.SELL: - self.sell(connector_name=connector_name, trading_pair=order.trading_pair, amount=order.amount, - order_type=order.order_type, price=order.price) - elif order.order_side == TradeType.BUY: - self.buy(connector_name=connector_name, trading_pair=order.trading_pair, amount=order.amount, - order_type=order.order_type, price=order.price) - - def cancel_all_orders(self): - for order in self.get_active_orders(connector_name=self.exchange): - self.cancel(self.exchange, order.trading_pair, order.client_order_id) - - def did_fill_order(self, event: OrderFilledEvent): - msg = (f"{event.trade_type.name} {round(event.amount, 2)} {event.trading_pair} {self.exchange} at {round(event.price, 2)}") - self.log_with_clock(logging.INFO, msg) - self.notify_hb_app_with_timestamp(msg) diff --git a/hummingbot_files/templates/master_bot_conf/scripts/simple_rsi_example.py b/hummingbot_files/templates/master_bot_conf/scripts/simple_rsi_example.py deleted file mode 100644 index 7f8fa59..0000000 --- a/hummingbot_files/templates/master_bot_conf/scripts/simple_rsi_example.py +++ /dev/null @@ -1,259 +0,0 @@ -import math -import os -from decimal import Decimal -from typing import Optional - -import pandas as pd - -from hummingbot.client.hummingbot_application import HummingbotApplication -from hummingbot.connector.connector_base import ConnectorBase -from hummingbot.connector.utils import combine_to_hb_trading_pair -from hummingbot.core.data_type.common import OrderType, TradeType -from hummingbot.core.data_type.order_candidate import OrderCandidate -from hummingbot.core.event.event_forwarder import SourceInfoEventForwarder -from hummingbot.core.event.events import OrderBookEvent, OrderBookTradeEvent, OrderFilledEvent -from hummingbot.core.rate_oracle.rate_oracle import RateOracle -from hummingbot.strategy.script_strategy_base import ScriptStrategyBase - - -class SimpleRSIScript(ScriptStrategyBase): - """ - The strategy is to buy on overbought signal and sell on oversold. - """ - connector_name = os.getenv("CONNECTOR_NAME", "binance_paper_trade") - base = os.getenv("BASE", "BTC") - quote = os.getenv("QUOTE", "USDT") - timeframe = os.getenv("TIMEFRAME", "1s") - - position_amount_usd = Decimal(os.getenv("POSITION_AMOUNT_USD", "50")) - - rsi_length = int(os.getenv("RSI_LENGTH", "14")) - - # If true - uses Exponential Moving Average, if false - Simple Moving Average. - rsi_is_ema = os.getenv("RSI_IS_EMA", 'True').lower() in ('true', '1', 't') - - buy_rsi = int(os.getenv("BUY_RSI", "30")) - sell_rsi = int(os.getenv("SELL_RSI", "70")) - - # It depends on a timeframe. Make sure you have enough trades to calculate rsi_length number of candlesticks. - trade_count_limit = int(os.getenv("TRADE_COUNT_LIMIT", "100000")) - - trading_pair = combine_to_hb_trading_pair(base, quote) - markets = {connector_name: {trading_pair}} - - subscribed_to_order_book_trade_event: bool = False - position: Optional[OrderFilledEvent] = None - - _trades: 'list[OrderBookTradeEvent]' = [] - _cumulative_price_change_pct = Decimal(0) - _filling_position: bool = False - - def on_tick(self): - """ - On every tick calculate OHLCV candlesticks, calculate RSI, react on overbought or oversold signal with creating, - adjusting and sending an order. - """ - if not self.subscribed_to_order_book_trade_event: - # Set pandas resample rule for a timeframe - self._set_resample_rule(self.timeframe) - self.subscribe_to_order_book_trade_event() - elif len(self._trades) > 0: - df = self.calculate_candlesticks() - df = self.calculate_rsi(df, self.rsi_length, self.rsi_is_ema) - should_open_position = self.should_open_position(df) - should_close_position = self.should_close_position(df) - if should_open_position or should_close_position: - order_side = TradeType.BUY if should_open_position else TradeType.SELL - order_candidate = self.create_order_candidate(order_side) - # Adjust OrderCandidate - order_adjusted = self.connectors[self.connector_name].budget_checker.adjust_candidate(order_candidate, all_or_none=False) - if math.isclose(order_adjusted.amount, Decimal("0"), rel_tol=1E-5): - self.logger().info(f"Order adjusted: {order_adjusted.amount}, too low to place an order") - else: - self.send_order(order_adjusted) - else: - self._rsi = df.iloc[-1]['rsi'] - self.logger().info(f"RSI is {self._rsi:.0f}") - - def _set_resample_rule(self, timeframe): - """ - Convert timeframe to pandas resample rule value. - https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.resample.html - """ - timeframe_to_rule = { - "1s": "1S", - "10s": "10S", - "30s": "30S", - "1m": "1T", - "15m": "15T" - } - if timeframe not in timeframe_to_rule.keys(): - self.logger().error(f"{timeframe} timeframe is not mapped to resample rule.") - HummingbotApplication.main_application().stop() - self._resample_rule = timeframe_to_rule[timeframe] - - def should_open_position(self, df: pd.DataFrame) -> bool: - """ - If overbought and not in the position. - """ - rsi: float = df.iloc[-1]['rsi'] - rsi_is_calculated = pd.notna(rsi) - time_to_buy = rsi_is_calculated and rsi <= self.buy_rsi - can_buy = self.position is None and not self._filling_position - return can_buy and time_to_buy - - def should_close_position(self, df: pd.DataFrame) -> bool: - """ - If oversold and in the position. - """ - rsi: float = df.iloc[-1]['rsi'] - rsi_is_calculated = pd.notna(rsi) - time_to_sell = rsi_is_calculated and rsi >= self.sell_rsi - can_sell = self.position is not None and not self._filling_position - return can_sell and time_to_sell - - def create_order_candidate(self, order_side: bool) -> OrderCandidate: - """ - Create and quantize order candidate. - """ - connector: ConnectorBase = self.connectors[self.connector_name] - is_buy = order_side == TradeType.BUY - price = connector.get_price(self.trading_pair, is_buy) - if is_buy: - conversion_rate = RateOracle.get_instance().get_pair_rate(self.trading_pair) - amount = self.position_amount_usd / conversion_rate - else: - amount = self.position.amount - - amount = connector.quantize_order_amount(self.trading_pair, amount) - price = connector.quantize_order_price(self.trading_pair, price) - return OrderCandidate( - trading_pair=self.trading_pair, - is_maker = False, - order_type = OrderType.LIMIT, - order_side = order_side, - amount = amount, - price = price) - - def send_order(self, order: OrderCandidate): - """ - Send order to the exchange, indicate that position is filling, and send log message with a trade. - """ - is_buy = order.order_side == TradeType.BUY - place_order = self.buy if is_buy else self.sell - place_order( - connector_name=self.connector_name, - trading_pair=self.trading_pair, - amount=order.amount, - order_type=order.order_type, - price=order.price - ) - self._filling_position = True - if is_buy: - msg = f"RSI is below {self.buy_rsi:.2f}, buying {order.amount:.5f} {self.base} with limit order at {order.price:.2f} ." - else: - msg = (f"RSI is above {self.sell_rsi:.2f}, selling {self.position.amount:.5f} {self.base}" - f" with limit order at ~ {order.price:.2f}, entry price was {self.position.price:.2f}.") - self.notify_hb_app_with_timestamp(msg) - self.logger().info(msg) - - def calculate_candlesticks(self) -> pd.DataFrame: - """ - Convert raw trades to OHLCV dataframe. - """ - df = pd.DataFrame(self._trades) - df['timestamp'] = pd.to_datetime(df['timestamp'], unit='s') - df["timestamp"] = pd.to_datetime(df["timestamp"]) - df.drop(columns=[df.columns[0]], axis=1, inplace=True) - df = df.set_index('timestamp') - df = df.resample(self._resample_rule).agg({ - 'price': ['first', 'max', 'min', 'last'], - 'amount': 'sum', - }) - df.columns = df.columns.to_flat_index().map(lambda x: x[1]) - df.rename(columns={'first': 'open', 'max': 'high', 'min': 'low', 'last': 'close', 'sum': 'volume'}, inplace=True) - return df - - def did_fill_order(self, event: OrderFilledEvent): - """ - Indicate that position is filled, save position properties on enter, calculate cumulative price change on exit. - """ - if event.trade_type == TradeType.BUY: - self.position = event - self._filling_position = False - elif event.trade_type == TradeType.SELL: - delta_price = (event.price - self.position.price) / self.position.price - self._cumulative_price_change_pct += delta_price - self.position = None - self._filling_position = False - else: - self.logger().warn(f"Unsupported order type filled: {event.trade_type}") - - @staticmethod - def calculate_rsi(df: pd.DataFrame, length: int = 14, is_ema: bool = True): - """ - Calculate relative strength index and add it to the dataframe. - """ - close_delta = df['close'].diff() - up = close_delta.clip(lower=0) - down = close_delta.clip(upper=0).abs() - - if is_ema: - # Exponential Moving Average - ma_up = up.ewm(com = length - 1, adjust=True, min_periods = length).mean() - ma_down = down.ewm(com = length - 1, adjust=True, min_periods = length).mean() - else: - # Simple Moving Average - ma_up = up.rolling(window = length, adjust=False).mean() - ma_down = down.rolling(window = length, adjust=False).mean() - - rs = ma_up / ma_down - df["rsi"] = 100 - (100 / (1 + rs)) - return df - - def subscribe_to_order_book_trade_event(self): - """ - Subscribe to raw trade event. - """ - self.order_book_trade_event = SourceInfoEventForwarder(self._process_public_trade) - for market in self.connectors.values(): - for order_book in market.order_books.values(): - order_book.add_listener(OrderBookEvent.TradeEvent, self.order_book_trade_event) - self.subscribed_to_order_book_trade_event = True - - def _process_public_trade(self, event_tag: int, market: ConnectorBase, event: OrderBookTradeEvent): - """ - Add new trade to list, remove old trade event, if count greater than trade_count_limit. - """ - if len(self._trades) >= self.trade_count_limit: - self._trades.pop(0) - self._trades.append(event) - - def format_status(self) -> str: - """ - Returns status of the current strategy on user balances and current active orders. This function is called - when status command is issued. Override this function to create custom status display output. - """ - if not self.ready_to_trade: - return "Market connectors are not ready." - lines = [] - warning_lines = [] - warning_lines.extend(self.network_warning(self.get_market_trading_pair_tuples())) - - balance_df = self.get_balance_df() - lines.extend(["", " Balances:"] + [" " + line for line in balance_df.to_string(index=False).split("\n")]) - - try: - df = self.active_orders_df() - lines.extend(["", " Orders:"] + [" " + line for line in df.to_string(index=False).split("\n")]) - except ValueError: - lines.extend(["", " No active maker orders."]) - - # Strategy specific info - lines.extend(["", " Current RSI:"] + [" " + f"{self._rsi:.0f}"]) - lines.extend(["", " Simple RSI strategy total price change with all trades:"] + [" " + f"{self._cumulative_price_change_pct:.5f}" + " %"]) - - warning_lines.extend(self.balance_warning(self.get_market_trading_pair_tuples())) - if len(warning_lines) > 0: - lines.extend(["", "*** WARNINGS ***"] + warning_lines) - return "\n".join(lines) diff --git a/hummingbot_files/templates/master_bot_conf/scripts/simple_vwap_example.py b/hummingbot_files/templates/master_bot_conf/scripts/simple_vwap_example.py deleted file mode 100644 index 89dcf08..0000000 --- a/hummingbot_files/templates/master_bot_conf/scripts/simple_vwap_example.py +++ /dev/null @@ -1,184 +0,0 @@ -import logging -import math -from decimal import Decimal -from typing import Dict - -from hummingbot.connector.utils import split_hb_trading_pair -from hummingbot.core.data_type.order_candidate import OrderCandidate -from hummingbot.core.event.events import OrderFilledEvent, OrderType, TradeType -from hummingbot.core.rate_oracle.rate_oracle import RateOracle -from hummingbot.strategy.script_strategy_base import ScriptStrategyBase - - -class VWAPExample(ScriptStrategyBase): - """ - BotCamp Cohort: Sept 2022 - Design Template: https://hummingbot-foundation.notion.site/Simple-VWAP-Example-d43a929cc5bd45c6b1a72f63e6635618 - Video: - - Description: - This example lets you create one VWAP in a market using a percentage of the sum volume of the order book - until a spread from the mid price. - This example demonstrates: - - How to get the account balance - - How to get the bids and asks of a market - - How to code a "utility" strategy - """ - last_ordered_ts = 0 - vwap: Dict = {"connector_name": "binance_paper_trade", "trading_pair": "ETH-USDT", "is_buy": True, - "total_volume_usd": 100000, "price_spread": 0.001, "volume_perc": 0.001, "order_delay_time": 10} - markets = {vwap["connector_name"]: {vwap["trading_pair"]}} - - def on_tick(self): - """ - Every order delay time the strategy will buy or sell the base asset. It will compute the cumulative order book - volume until the spread and buy a percentage of that. - The input of the strategy is in USD, but we will use the rate oracle to get a target base that will be static. - - Use the Rate Oracle to get a conversion rate - - Create proposal (a list of order candidates) - - Check the account balance and adjust the proposal accordingly (lower order amount if needed) - - Lastly, execute the proposal on the exchange - """ - if self.last_ordered_ts < (self.current_timestamp - self.vwap["order_delay_time"]): - if self.vwap.get("status") is None: - self.init_vwap_stats() - elif self.vwap.get("status") == "ACTIVE": - vwap_order: OrderCandidate = self.create_order() - vwap_order_adjusted = self.vwap["connector"].budget_checker.adjust_candidate(vwap_order, - all_or_none=False) - if math.isclose(vwap_order_adjusted.amount, Decimal("0"), rel_tol=1E-5): - self.logger().info(f"Order adjusted: {vwap_order_adjusted.amount}, too low to place an order") - else: - self.place_order( - connector_name=self.vwap["connector_name"], - trading_pair=self.vwap["trading_pair"], - is_buy=self.vwap["is_buy"], - amount=vwap_order_adjusted.amount, - order_type=vwap_order_adjusted.order_type) - self.last_ordered_ts = self.current_timestamp - - def init_vwap_stats(self): - # General parameters - vwap = self.vwap.copy() - vwap["connector"] = self.connectors[vwap["connector_name"]] - vwap["delta"] = 0 - vwap["trades"] = [] - vwap["status"] = "ACTIVE" - vwap["trade_type"] = TradeType.BUY if self.vwap["is_buy"] else TradeType.SELL - base_asset, quote_asset = split_hb_trading_pair(vwap["trading_pair"]) - - # USD conversion to quote and base asset - conversion_base_asset = f"{base_asset}-USD" - conversion_quote_asset = f"{quote_asset}-USD" - base_conversion_rate = RateOracle.get_instance().get_pair_rate(conversion_base_asset) - quote_conversion_rate = RateOracle.get_instance().get_pair_rate(conversion_quote_asset) - vwap["start_price"] = vwap["connector"].get_price(vwap["trading_pair"], vwap["is_buy"]) - vwap["target_base_volume"] = vwap["total_volume_usd"] / base_conversion_rate - vwap["ideal_quote_volume"] = vwap["total_volume_usd"] / quote_conversion_rate - - # Compute market order scenario - orderbook_query = vwap["connector"].get_quote_volume_for_base_amount(vwap["trading_pair"], vwap["is_buy"], - vwap["target_base_volume"]) - vwap["market_order_base_volume"] = orderbook_query.query_volume - vwap["market_order_quote_volume"] = orderbook_query.result_volume - vwap["volume_remaining"] = vwap["target_base_volume"] - vwap["real_quote_volume"] = Decimal(0) - self.vwap = vwap - - def create_order(self) -> OrderCandidate: - """ - Retrieves the cumulative volume of the order book until the price spread is reached, then takes a percentage - of that to use as order amount. - """ - # Compute the new price using the max spread allowed - mid_price = float(self.vwap["connector"].get_mid_price(self.vwap["trading_pair"])) - price_multiplier = 1 + self.vwap["price_spread"] if self.vwap["is_buy"] else 1 - self.vwap["price_spread"] - price_affected_by_spread = mid_price * price_multiplier - - # Query the cumulative volume until the price affected by spread - orderbook_query = self.vwap["connector"].get_volume_for_price( - trading_pair=self.vwap["trading_pair"], - is_buy=self.vwap["is_buy"], - price=price_affected_by_spread) - volume_for_price = orderbook_query.result_volume - - # Check if the volume available is higher than the remaining - amount = min(volume_for_price * Decimal(self.vwap["volume_perc"]), Decimal(self.vwap["volume_remaining"])) - - # Quantize the order amount and price - amount = self.vwap["connector"].quantize_order_amount(self.vwap["trading_pair"], amount) - price = self.vwap["connector"].quantize_order_price(self.vwap["trading_pair"], - Decimal(price_affected_by_spread)) - # Create the Order Candidate - vwap_order = OrderCandidate( - trading_pair=self.vwap["trading_pair"], - is_maker=False, - order_type=OrderType.MARKET, - order_side=self.vwap["trade_type"], - amount=amount, - price=price) - return vwap_order - - def place_order(self, - connector_name: str, - trading_pair: str, - is_buy: bool, - amount: Decimal, - order_type: OrderType, - price=Decimal("NaN"), - ): - if is_buy: - self.buy(connector_name, trading_pair, amount, order_type, price) - else: - self.sell(connector_name, trading_pair, amount, order_type, price) - - def did_fill_order(self, event: OrderFilledEvent): - """ - Listens to fill order event to log it and notify the Hummingbot application. - If you set up Telegram bot, you will get notification there as well. - """ - if event.trading_pair == self.vwap["trading_pair"] and event.trade_type == self.vwap["trade_type"]: - self.vwap["volume_remaining"] -= event.amount - self.vwap["delta"] = (self.vwap["target_base_volume"] - self.vwap["volume_remaining"]) / self.vwap[ - "target_base_volume"] - self.vwap["real_quote_volume"] += event.price * event.amount - self.vwap["trades"].append(event) - if math.isclose(self.vwap["delta"], 1, rel_tol=1e-5): - self.vwap["status"] = "COMPLETE" - msg = (f"({event.trading_pair}) {event.trade_type.name} order (price: {round(event.price, 2)}) of " - f"{round(event.amount, 2)} " - f"{split_hb_trading_pair(event.trading_pair)[0]} is filled.") - - self.log_with_clock(logging.INFO, msg) - self.notify_hb_app_with_timestamp(msg) - - def format_status(self) -> str: - """ - Returns status of the current strategy on user balances and current active orders. This function is called - when status command is issued. Override this function to create custom status display output. - """ - if not self.ready_to_trade: - return "Market connectors are not ready." - lines = [] - warning_lines = [] - warning_lines.extend(self.network_warning(self.get_market_trading_pair_tuples())) - - balance_df = self.get_balance_df() - lines.extend(["", " Balances:"] + [" " + line for line in balance_df.to_string(index=False).split("\n")]) - - try: - df = self.active_orders_df() - lines.extend(["", " Orders:"] + [" " + line for line in df.to_string(index=False).split("\n")]) - except ValueError: - lines.extend(["", " No active maker orders."]) - lines.extend(["", "VWAP Info:"] + [" " + key + ": " + value - for key, value in self.vwap.items() - if type(value) == str]) - - lines.extend(["", "VWAP Stats:"] + [" " + key + ": " + str(round(value, 4)) - for key, value in self.vwap.items() - if type(value) in [int, float, Decimal]]) - - warning_lines.extend(self.balance_warning(self.get_market_trading_pair_tuples())) - if len(warning_lines) > 0: - lines.extend(["", "*** WARNINGS ***"] + warning_lines) - return "\n".join(lines) diff --git a/hummingbot_files/templates/master_bot_conf/scripts/simple_xemm_example.py b/hummingbot_files/templates/master_bot_conf/scripts/simple_xemm_example.py deleted file mode 100644 index 3c8244b..0000000 --- a/hummingbot_files/templates/master_bot_conf/scripts/simple_xemm_example.py +++ /dev/null @@ -1,204 +0,0 @@ -from decimal import Decimal - -import pandas as pd - -from hummingbot.core.data_type.common import OrderType, TradeType -from hummingbot.core.data_type.order_candidate import OrderCandidate -from hummingbot.core.event.events import OrderFilledEvent -from hummingbot.strategy.script_strategy_base import ScriptStrategyBase - - -class SimpleXEMM(ScriptStrategyBase): - """ - BotCamp Cohort: Sept 2022 - Design Template: https://hummingbot-foundation.notion.site/Simple-XEMM-Example-f08cf7546ea94a44b389672fd21bb9ad - Video: https://www.loom.com/share/ca08fe7bc3d14ba68ae704305ac78a3a - Description: - A simplified version of Hummingbot cross-exchange market making strategy, this bot makes a market on - the maker pair and hedges any filled trades in the taker pair. If the spread (difference between maker order price - and taker hedge price) dips below min_spread, the bot refreshes the order - """ - - maker_exchange = "kucoin_paper_trade" - maker_pair = "ETH-USDT" - taker_exchange = "gate_io_paper_trade" - taker_pair = "ETH-USDT" - - order_amount = 0.1 # amount for each order - spread_bps = 10 # bot places maker orders at this spread to taker price - min_spread_bps = 0 # bot refreshes order if spread is lower than min-spread - slippage_buffer_spread_bps = 100 # buffer applied to limit taker hedging trades on taker exchange - max_order_age = 120 # bot refreshes orders after this age - - markets = {maker_exchange: {maker_pair}, taker_exchange: {taker_pair}} - - buy_order_placed = False - sell_order_placed = False - - def on_tick(self): - taker_buy_result = self.connectors[self.taker_exchange].get_price_for_volume(self.taker_pair, True, self.order_amount) - taker_sell_result = self.connectors[self.taker_exchange].get_price_for_volume(self.taker_pair, False, self.order_amount) - - if not self.buy_order_placed: - maker_buy_price = taker_sell_result.result_price * Decimal(1 - self.spread_bps / 10000) - buy_order_amount = min(self.order_amount, self.buy_hedging_budget()) - buy_order = OrderCandidate(trading_pair=self.maker_pair, is_maker=True, order_type=OrderType.LIMIT, order_side=TradeType.BUY, amount=Decimal(buy_order_amount), price=maker_buy_price) - buy_order_adjusted = self.connectors[self.maker_exchange].budget_checker.adjust_candidate(buy_order, all_or_none=False) - self.buy(self.maker_exchange, self.maker_pair, buy_order_adjusted.amount, buy_order_adjusted.order_type, buy_order_adjusted.price) - self.buy_order_placed = True - - if not self.sell_order_placed: - maker_sell_price = taker_buy_result.result_price * Decimal(1 + self.spread_bps / 10000) - sell_order_amount = min(self.order_amount, self.sell_hedging_budget()) - sell_order = OrderCandidate(trading_pair=self.maker_pair, is_maker=True, order_type=OrderType.LIMIT, order_side=TradeType.SELL, amount=Decimal(sell_order_amount), price=maker_sell_price) - sell_order_adjusted = self.connectors[self.maker_exchange].budget_checker.adjust_candidate(sell_order, all_or_none=False) - self.sell(self.maker_exchange, self.maker_pair, sell_order_adjusted.amount, sell_order_adjusted.order_type, sell_order_adjusted.price) - self.sell_order_placed = True - - for order in self.get_active_orders(connector_name=self.maker_exchange): - cancel_timestamp = order.creation_timestamp / 1000000 + self.max_order_age - if order.is_buy: - buy_cancel_threshold = taker_sell_result.result_price * Decimal(1 - self.min_spread_bps / 10000) - if order.price > buy_cancel_threshold or cancel_timestamp < self.current_timestamp: - self.logger().info(f"Cancelling buy order: {order.client_order_id}") - self.cancel(self.maker_exchange, order.trading_pair, order.client_order_id) - self.buy_order_placed = False - else: - sell_cancel_threshold = taker_buy_result.result_price * Decimal(1 + self.min_spread_bps / 10000) - if order.price < sell_cancel_threshold or cancel_timestamp < self.current_timestamp: - self.logger().info(f"Cancelling sell order: {order.client_order_id}") - self.cancel(self.maker_exchange, order.trading_pair, order.client_order_id) - self.sell_order_placed = False - return - - def buy_hedging_budget(self) -> Decimal: - balance = self.connectors[self.taker_exchange].get_available_balance("ETH") - return balance - - def sell_hedging_budget(self) -> Decimal: - balance = self.connectors[self.taker_exchange].get_available_balance("USDT") - taker_buy_result = self.connectors[self.taker_exchange].get_price_for_volume(self.taker_pair, True, self.order_amount) - return balance / taker_buy_result.result_price - - def is_active_maker_order(self, event: OrderFilledEvent): - """ - Helper function that checks if order is an active order on the maker exchange - """ - for order in self.get_active_orders(connector_name=self.maker_exchange): - if order.client_order_id == event.order_id: - return True - return False - - def did_fill_order(self, event: OrderFilledEvent): - - mid_price = self.connectors[self.maker_exchange].get_mid_price(self.maker_pair) - if event.trade_type == TradeType.BUY and self.is_active_maker_order(event): - taker_sell_result = self.connectors[self.taker_exchange].get_price_for_volume(self.taker_pair, False, self.order_amount) - sell_price_with_slippage = taker_sell_result.result_price * Decimal(1 - self.slippage_buffer_spread_bps / 10000) - self.logger().info(f"Filled maker buy order with price: {event.price}") - sell_spread_bps = (taker_sell_result.result_price - event.price) / mid_price * 10000 - self.logger().info(f"Sending taker sell order at price: {taker_sell_result.result_price} spread: {int(sell_spread_bps)} bps") - sell_order = OrderCandidate(trading_pair=self.taker_pair, is_maker=False, order_type=OrderType.LIMIT, order_side=TradeType.SELL, amount=Decimal(event.amount), price=sell_price_with_slippage) - sell_order_adjusted = self.connectors[self.taker_exchange].budget_checker.adjust_candidate(sell_order, all_or_none=False) - self.sell(self.taker_exchange, self.taker_pair, sell_order_adjusted.amount, sell_order_adjusted.order_type, sell_order_adjusted.price) - self.buy_order_placed = False - else: - if event.trade_type == TradeType.SELL and self.is_active_maker_order(event): - taker_buy_result = self.connectors[self.taker_exchange].get_price_for_volume(self.taker_pair, True, self.order_amount) - buy_price_with_slippage = taker_buy_result.result_price * Decimal(1 + self.slippage_buffer_spread_bps / 10000) - buy_spread_bps = (event.price - taker_buy_result.result_price) / mid_price * 10000 - self.logger().info(f"Filled maker sell order at price: {event.price}") - self.logger().info(f"Sending taker buy order: {taker_buy_result.result_price} spread: {int(buy_spread_bps)}") - buy_order = OrderCandidate(trading_pair=self.taker_pair, is_maker=False, order_type=OrderType.LIMIT, order_side=TradeType.BUY, amount=Decimal(event.amount), price=buy_price_with_slippage) - buy_order_adjusted = self.connectors[self.taker_exchange].budget_checker.adjust_candidate(buy_order, all_or_none=False) - self.buy(self.taker_exchange, self.taker_pair, buy_order_adjusted.amount, buy_order_adjusted.order_type, buy_order_adjusted.price) - self.sell_order_placed = False - - def exchanges_df(self) -> pd.DataFrame: - """ - Return a custom data frame of prices on maker vs taker exchanges for display purposes - """ - mid_price = self.connectors[self.maker_exchange].get_mid_price(self.maker_pair) - maker_buy_result = self.connectors[self.maker_exchange].get_price_for_volume(self.taker_pair, True, self.order_amount) - maker_sell_result = self.connectors[self.maker_exchange].get_price_for_volume(self.taker_pair, False, self.order_amount) - taker_buy_result = self.connectors[self.taker_exchange].get_price_for_volume(self.taker_pair, True, self.order_amount) - taker_sell_result = self.connectors[self.taker_exchange].get_price_for_volume(self.taker_pair, False, self.order_amount) - maker_buy_spread_bps = (maker_buy_result.result_price - taker_buy_result.result_price) / mid_price * 10000 - maker_sell_spread_bps = (taker_sell_result.result_price - maker_sell_result.result_price) / mid_price * 10000 - columns = ["Exchange", "Market", "Mid Price", "Buy Price", "Sell Price", "Buy Spread", "Sell Spread"] - data = [] - data.append([ - self.maker_exchange, - self.maker_pair, - float(self.connectors[self.maker_exchange].get_mid_price(self.maker_pair)), - float(maker_buy_result.result_price), - float(maker_sell_result.result_price), - int(maker_buy_spread_bps), - int(maker_sell_spread_bps) - ]) - data.append([ - self.taker_exchange, - self.taker_pair, - float(self.connectors[self.taker_exchange].get_mid_price(self.maker_pair)), - float(taker_buy_result.result_price), - float(taker_sell_result.result_price), - int(-maker_buy_spread_bps), - int(-maker_sell_spread_bps) - ]) - df = pd.DataFrame(data=data, columns=columns) - return df - - def active_orders_df(self) -> pd.DataFrame: - """ - Returns a custom data frame of all active maker orders for display purposes - """ - columns = ["Exchange", "Market", "Side", "Price", "Amount", "Spread Mid", "Spread Cancel", "Age"] - data = [] - mid_price = self.connectors[self.maker_exchange].get_mid_price(self.maker_pair) - taker_buy_result = self.connectors[self.taker_exchange].get_price_for_volume(self.taker_pair, True, self.order_amount) - taker_sell_result = self.connectors[self.taker_exchange].get_price_for_volume(self.taker_pair, False, self.order_amount) - buy_cancel_threshold = taker_sell_result.result_price * Decimal(1 - self.min_spread_bps / 10000) - sell_cancel_threshold = taker_buy_result.result_price * Decimal(1 + self.min_spread_bps / 10000) - for connector_name, connector in self.connectors.items(): - for order in self.get_active_orders(connector_name): - age_txt = "n/a" if order.age() <= 0. else pd.Timestamp(order.age(), unit='s').strftime('%H:%M:%S') - spread_mid_bps = (mid_price - order.price) / mid_price * 10000 if order.is_buy else (order.price - mid_price) / mid_price * 10000 - spread_cancel_bps = (buy_cancel_threshold - order.price) / buy_cancel_threshold * 10000 if order.is_buy else (order.price - sell_cancel_threshold) / sell_cancel_threshold * 10000 - data.append([ - self.maker_exchange, - order.trading_pair, - "buy" if order.is_buy else "sell", - float(order.price), - float(order.quantity), - int(spread_mid_bps), - int(spread_cancel_bps), - age_txt - ]) - if not data: - raise ValueError - df = pd.DataFrame(data=data, columns=columns) - df.sort_values(by=["Market", "Side"], inplace=True) - return df - - def format_status(self) -> str: - """ - Returns status of the current strategy on user balances and current active orders. This function is called - when status command is issued. Override this function to create custom status display output. - """ - if not self.ready_to_trade: - return "Market connectors are not ready." - lines = [] - - balance_df = self.get_balance_df() - lines.extend(["", " Balances:"] + [" " + line for line in balance_df.to_string(index=False).split("\n")]) - - exchanges_df = self.exchanges_df() - lines.extend(["", " Exchanges:"] + [" " + line for line in exchanges_df.to_string(index=False).split("\n")]) - - try: - orders_df = self.active_orders_df() - lines.extend(["", " Active Orders:"] + [" " + line for line in orders_df.to_string(index=False).split("\n")]) - except ValueError: - lines.extend(["", " No active maker orders."]) - - return "\n".join(lines) diff --git a/hummingbot_files/templates/master_bot_conf/scripts/strategy_v2_launcher.py b/hummingbot_files/templates/master_bot_conf/scripts/strategy_v2_launcher.py deleted file mode 100644 index 392972b..0000000 --- a/hummingbot_files/templates/master_bot_conf/scripts/strategy_v2_launcher.py +++ /dev/null @@ -1,110 +0,0 @@ -import inspect -import os -import importlib.util - -from hummingbot.core.data_type.common import OrderType, PositionMode, TradeType, PositionSide, PositionAction -from hummingbot.smart_components.strategy_frameworks.data_types import ( - ExecutorHandlerStatus, -) -from hummingbot.smart_components.strategy_frameworks.directional_trading import DirectionalTradingControllerBase, \ - DirectionalTradingControllerConfigBase, DirectionalTradingExecutorHandler -from hummingbot.smart_components.utils.config_encoder_decoder import ConfigEncoderDecoder -from hummingbot.strategy.script_strategy_base import ScriptStrategyBase - - -def load_controllers(path): - controllers = {} - for filename in os.listdir(path): - if filename.endswith('.py') and "__init__" not in filename: - module_name = filename[:-3] # strip the .py to get the module name - controllers[module_name] = {"module": module_name} - file_path = os.path.join(path, filename) - spec = importlib.util.spec_from_file_location(module_name, file_path) - module = importlib.util.module_from_spec(spec) - spec.loader.exec_module(module) - for name, cls in inspect.getmembers(module, inspect.isclass): - if issubclass(cls, DirectionalTradingControllerBase) and cls is not DirectionalTradingControllerBase: - controllers[module_name]["class"] = cls - if issubclass(cls, DirectionalTradingControllerConfigBase) and cls is not DirectionalTradingControllerConfigBase: - controllers[module_name]["config"] = cls - return controllers - - -def initialize_controller_from_config(encoder_decoder: ConfigEncoderDecoder, - all_controllers_info: dict, - controller_config_file: str): - config = encoder_decoder.yaml_load(f"conf/controllers_config/{controller_config_file}") - controller_info = all_controllers_info[config["strategy_name"]] - config_instance = controller_info["config"](**config) - controller_class = controller_info["class"](config_instance) - return controller_class - - -class StrategyV2Launcher(ScriptStrategyBase): - controller_configs = os.getenv("controller_configs", "bollinger_8044.yml,bollinger_8546.yml,bollinger_8883.yml") - controllers = {} - markets = {} - executor_handlers = {} - encoder_decoder = ConfigEncoderDecoder(TradeType, PositionMode, OrderType) - controllers_info = load_controllers("hummingbot/smart_components/controllers") - - for controller_config in controller_configs.split(","): - controller = initialize_controller_from_config(encoder_decoder, controllers_info, controller_config) - markets = controller.update_strategy_markets_dict(markets) - controllers[controller_config] = controller - - def __init__(self, connectors): - super().__init__(connectors) - for controller_config, controller in self.controllers.items(): - self.executor_handlers[controller_config] = DirectionalTradingExecutorHandler(strategy=self, controller=controller) - - def on_stop(self): - for connector in self.connectors.keys(): - if self.is_perpetual(connector): - self.close_open_positions(connector) - for executor_handler in self.executor_handlers.values(): - executor_handler.stop() - - @staticmethod - def is_perpetual(exchange): - """ - Checks if the exchange is a perpetual market. - """ - return "perpetual" in exchange - - def close_open_positions(self, exchange): - connector = self.connectors[exchange] - for trading_pair, position in connector.account_positions.items(): - if position.position_side == PositionSide.LONG: - self.sell(connector_name=exchange, - trading_pair=position.trading_pair, - amount=abs(position.amount), - order_type=OrderType.MARKET, - price=connector.get_mid_price(position.trading_pair), - position_action=PositionAction.CLOSE) - elif position.position_side == PositionSide.SHORT: - self.buy(connector_name=exchange, - trading_pair=position.trading_pair, - amount=abs(position.amount), - order_type=OrderType.MARKET, - price=connector.get_mid_price(position.trading_pair), - position_action=PositionAction.CLOSE) - - def on_tick(self): - """ - This shows you how you can start meta controllers. You can run more than one at the same time and based on the - market conditions, you can orchestrate from this script when to stop or start them. - """ - for executor_handler in self.executor_handlers.values(): - if executor_handler.status == ExecutorHandlerStatus.NOT_STARTED: - executor_handler.start() - - def format_status(self) -> str: - if not self.ready_to_trade: - return "Market connectors are not ready." - lines = [] - for controller_config, executor_handler in self.executor_handlers.items(): - lines.extend(["\n------------------------------------------------------------------------------------------"]) - lines.extend([f"Strategy: {executor_handler.controller.config.strategy_name} | Config: {controller_config}", - executor_handler.to_format_status()]) - return "\n".join(lines) diff --git a/hummingbot_files/templates/master_bot_conf/scripts/v2_directional-trading_macd_bb_v1.py b/hummingbot_files/templates/master_bot_conf/scripts/v2_directional-trading_macd_bb_v1.py deleted file mode 100644 index 2e72ccd..0000000 --- a/hummingbot_files/templates/master_bot_conf/scripts/v2_directional-trading_macd_bb_v1.py +++ /dev/null @@ -1,91 +0,0 @@ -from decimal import Decimal -from typing import Dict - -from hummingbot.connector.connector_base import ConnectorBase, TradeType -from hummingbot.core.data_type.common import OrderType -from hummingbot.data_feed.candles_feed.candles_factory import CandlesConfig -from hummingbot.smart_components.controllers.macd_bb_v1 import MACDBBV1, MACDBBV1Config -from hummingbot.smart_components.strategy_frameworks.data_types import ( - ExecutorHandlerStatus, - OrderLevel, - TripleBarrierConf, -) -from hummingbot.smart_components.strategy_frameworks.directional_trading.directional_trading_executor_handler import ( - DirectionalTradingExecutorHandler, -) -from hummingbot.strategy.script_strategy_base import ScriptStrategyBase - - -class MarketMakingDmanComposed(ScriptStrategyBase): - trading_pairs = ["HBAR-USDT", "CYBER-USDT", "ETH-USDT", "LPT-USDT", "UNFI-USDT"] - leverage_by_trading_pair = { - "HBAR-USDT": 25, - "CYBER-USDT": 20, - "ETH-USDT": 100, - "LPT-USDT": 10, - "UNFI-USDT": 20, - } - triple_barrier_conf = TripleBarrierConf( - stop_loss=Decimal("0.01"), take_profit=Decimal("0.03"), - time_limit=60 * 60 * 6, - trailing_stop_activation_price_delta=Decimal("0.008"), - trailing_stop_trailing_delta=Decimal("0.004"), - open_order_type=OrderType.MARKET - ) - - order_levels = [ - OrderLevel(level=0, side=TradeType.BUY, order_amount_usd=Decimal("15"), - spread_factor=Decimal(0.5), order_refresh_time=60 * 5, - cooldown_time=15, triple_barrier_conf=triple_barrier_conf), - OrderLevel(level=0, side=TradeType.SELL, order_amount_usd=Decimal("15"), - spread_factor=Decimal(0.5), order_refresh_time=60 * 5, - cooldown_time=15, triple_barrier_conf=triple_barrier_conf), - ] - controllers = {} - markets = {} - executor_handlers = {} - - for trading_pair in trading_pairs: - config = MACDBBV1Config( - exchange="binance_perpetual", - trading_pair=trading_pair, - order_levels=order_levels, - candles_config=[ - CandlesConfig(connector="binance_perpetual", trading_pair=trading_pair, interval="3m", max_records=100), - ], - leverage=leverage_by_trading_pair[trading_pair], - macd_fast=21, macd_slow=42, macd_signal=9, - bb_length=100, bb_std=2.0, bb_long_threshold=0.3, bb_short_threshold=0.7, - ) - controller = MACDBBV1(config=config) - markets = controller.update_strategy_markets_dict(markets) - controllers[trading_pair] = controller - - def __init__(self, connectors: Dict[str, ConnectorBase]): - super().__init__(connectors) - for trading_pair, controller in self.controllers.items(): - self.executor_handlers[trading_pair] = DirectionalTradingExecutorHandler(strategy=self, controller=controller) - - def on_stop(self): - for executor_handler in self.executor_handlers.values(): - executor_handler.stop() - - def on_tick(self): - """ - This shows you how you can start meta controllers. You can run more than one at the same time and based on the - market conditions, you can orchestrate from this script when to stop or start them. - """ - for executor_handler in self.executor_handlers.values(): - if executor_handler.status == ExecutorHandlerStatus.NOT_STARTED: - executor_handler.start() - - def format_status(self) -> str: - if not self.ready_to_trade: - return "Market connectors are not ready." - lines = [] - for trading_pair, executor_handler in self.executor_handlers.items(): - if executor_handler.controller.all_candles_ready: - lines.extend( - [f"Strategy: {executor_handler.controller.config.strategy_name} | Trading Pair: {trading_pair}", - executor_handler.to_format_status()]) - return "\n".join(lines) diff --git a/hummingbot_files/templates/master_bot_conf/scripts/v2_market-making_dman_composed.py b/hummingbot_files/templates/master_bot_conf/scripts/v2_market-making_dman_composed.py deleted file mode 100644 index c539897..0000000 --- a/hummingbot_files/templates/master_bot_conf/scripts/v2_market-making_dman_composed.py +++ /dev/null @@ -1,145 +0,0 @@ -from decimal import Decimal -from typing import Dict - -from hummingbot.connector.connector_base import ConnectorBase, TradeType -from hummingbot.core.data_type.common import OrderType, PositionAction, PositionSide -from hummingbot.data_feed.candles_feed.candles_factory import CandlesConfig -from hummingbot.smart_components.controllers.dman_v1 import DManV1, DManV1Config -from hummingbot.smart_components.controllers.dman_v2 import DManV2, DManV2Config -from hummingbot.smart_components.strategy_frameworks.data_types import ( - ExecutorHandlerStatus, - OrderLevel, - TripleBarrierConf, -) -from hummingbot.smart_components.strategy_frameworks.market_making.market_making_executor_handler import ( - MarketMakingExecutorHandler, -) -from hummingbot.strategy.script_strategy_base import ScriptStrategyBase - - -class MarketMakingDmanComposed(ScriptStrategyBase): - trading_pair = "HBAR-USDT" - triple_barrier_conf_top = TripleBarrierConf( - stop_loss=Decimal("0.03"), take_profit=Decimal("0.02"), - time_limit=60 * 60 * 1, - trailing_stop_activation_price_delta=Decimal("0.002"), - trailing_stop_trailing_delta=Decimal("0.0005") - ) - triple_barrier_conf_bottom = TripleBarrierConf( - stop_loss=Decimal("0.03"), take_profit=Decimal("0.02"), - time_limit=60 * 60 * 3, - trailing_stop_activation_price_delta=Decimal("0.005"), - trailing_stop_trailing_delta=Decimal("0.001") - ) - - config_v1 = DManV1Config( - exchange="binance_perpetual", - trading_pair=trading_pair, - order_levels=[ - OrderLevel(level=0, side=TradeType.BUY, order_amount_usd=Decimal("15"), - spread_factor=Decimal(1.0), order_refresh_time=60 * 30, - cooldown_time=15, triple_barrier_conf=triple_barrier_conf_top), - OrderLevel(level=1, side=TradeType.BUY, order_amount_usd=Decimal("50"), - spread_factor=Decimal(5.0), order_refresh_time=60 * 30, - cooldown_time=15, triple_barrier_conf=triple_barrier_conf_bottom), - OrderLevel(level=2, side=TradeType.BUY, order_amount_usd=Decimal("50"), - spread_factor=Decimal(8.0), order_refresh_time=60 * 15, - cooldown_time=15, triple_barrier_conf=triple_barrier_conf_bottom), - OrderLevel(level=0, side=TradeType.SELL, order_amount_usd=Decimal("15"), - spread_factor=Decimal(1.0), order_refresh_time=60 * 30, - cooldown_time=15, triple_barrier_conf=triple_barrier_conf_top), - OrderLevel(level=1, side=TradeType.SELL, order_amount_usd=Decimal("50"), - spread_factor=Decimal(5.0), order_refresh_time=60 * 30, - cooldown_time=15, triple_barrier_conf=triple_barrier_conf_bottom), - OrderLevel(level=2, side=TradeType.SELL, order_amount_usd=Decimal("50"), - spread_factor=Decimal(8.0), order_refresh_time=60 * 15, - cooldown_time=15, triple_barrier_conf=triple_barrier_conf_bottom), - ], - candles_config=[ - CandlesConfig(connector="binance_perpetual", trading_pair=trading_pair, interval="3m", max_records=1000), - ], - leverage=25, - natr_length=21 - ) - config_v2 = DManV2Config( - exchange="binance_perpetual", - trading_pair=trading_pair, - order_levels=[ - OrderLevel(level=0, side=TradeType.BUY, order_amount_usd=Decimal(15), - spread_factor=Decimal(1.0), order_refresh_time=60 * 5, - cooldown_time=15, triple_barrier_conf=triple_barrier_conf_top), - OrderLevel(level=1, side=TradeType.BUY, order_amount_usd=Decimal(30), - spread_factor=Decimal(2.0), order_refresh_time=60 * 5, - cooldown_time=15, triple_barrier_conf=triple_barrier_conf_bottom), - OrderLevel(level=2, side=TradeType.BUY, order_amount_usd=Decimal(50), - spread_factor=Decimal(3.0), order_refresh_time=60 * 15, - cooldown_time=15, triple_barrier_conf=triple_barrier_conf_bottom), - OrderLevel(level=0, side=TradeType.SELL, order_amount_usd=Decimal(15), - spread_factor=Decimal(1.0), order_refresh_time=60 * 5, - cooldown_time=15, triple_barrier_conf=triple_barrier_conf_top), - OrderLevel(level=1, side=TradeType.SELL, order_amount_usd=Decimal(30), - spread_factor=Decimal(2.0), order_refresh_time=60 * 5, - cooldown_time=15, triple_barrier_conf=triple_barrier_conf_bottom), - OrderLevel(level=2, side=TradeType.SELL, order_amount_usd=Decimal(50), - spread_factor=Decimal(3.0), order_refresh_time=60 * 15, - cooldown_time=15, triple_barrier_conf=triple_barrier_conf_bottom), - ], - candles_config=[ - CandlesConfig(connector="binance_perpetual", trading_pair=trading_pair, interval="3m", max_records=1000), - ], - leverage=25, - natr_length=21, macd_fast=12, macd_slow=26, macd_signal=9 - ) - dman_v1 = DManV1(config=config_v1) - dman_v2 = DManV2(config=config_v2) - - empty_markets = {} - markets = dman_v1.update_strategy_markets_dict(empty_markets) - markets = dman_v2.update_strategy_markets_dict(markets) - - def __init__(self, connectors: Dict[str, ConnectorBase]): - super().__init__(connectors) - self.dman_v1_executor = MarketMakingExecutorHandler(strategy=self, controller=self.dman_v1) - self.dman_v2_executor = MarketMakingExecutorHandler(strategy=self, controller=self.dman_v2) - - def on_stop(self): - self.close_open_positions() - - def on_tick(self): - """ - This shows you how you can start meta controllers. You can run more than one at the same time and based on the - market conditions, you can orchestrate from this script when to stop or start them. - """ - if self.dman_v1_executor.status == ExecutorHandlerStatus.NOT_STARTED: - self.dman_v1_executor.start() - if self.dman_v2_executor.status == ExecutorHandlerStatus.NOT_STARTED: - self.dman_v2_executor.start() - - def format_status(self) -> str: - if not self.ready_to_trade: - return "Market connectors are not ready." - lines = [] - lines.extend(["DMAN V1", self.dman_v1_executor.to_format_status()]) - lines.extend(["\n-----------------------------------------\n"]) - lines.extend(["DMAN V2", self.dman_v2_executor.to_format_status()]) - return "\n".join(lines) - - def close_open_positions(self): - # we are going to close all the open positions when the bot stops - for connector_name, connector in self.connectors.items(): - for trading_pair, position in connector.account_positions.items(): - if trading_pair in self.markets[connector_name]: - if position.position_side == PositionSide.LONG: - self.sell(connector_name=connector_name, - trading_pair=position.trading_pair, - amount=abs(position.amount), - order_type=OrderType.MARKET, - price=connector.get_mid_price(position.trading_pair), - position_action=PositionAction.CLOSE) - elif position.position_side == PositionSide.SHORT: - self.buy(connector_name=connector_name, - trading_pair=position.trading_pair, - amount=abs(position.amount), - order_type=OrderType.MARKET, - price=connector.get_mid_price(position.trading_pair), - position_action=PositionAction.CLOSE) diff --git a/hummingbot_files/templates/master_bot_conf/scripts/v2_market-making_dman_v1_multiple_pairs.py b/hummingbot_files/templates/master_bot_conf/scripts/v2_market-making_dman_v1_multiple_pairs.py deleted file mode 100644 index 24189cf..0000000 --- a/hummingbot_files/templates/master_bot_conf/scripts/v2_market-making_dman_v1_multiple_pairs.py +++ /dev/null @@ -1,133 +0,0 @@ -from decimal import Decimal -from typing import Dict - -from hummingbot.connector.connector_base import ConnectorBase -from hummingbot.core.data_type.common import OrderType, PositionAction, PositionSide -from hummingbot.data_feed.candles_feed.candles_factory import CandlesConfig -from hummingbot.smart_components.controllers.dman_v1 import DManV1, DManV1Config -from hummingbot.smart_components.strategy_frameworks.data_types import ExecutorHandlerStatus, TripleBarrierConf -from hummingbot.smart_components.strategy_frameworks.market_making.market_making_executor_handler import ( - MarketMakingExecutorHandler, -) -from hummingbot.smart_components.utils.distributions import Distributions -from hummingbot.smart_components.utils.order_level_builder import OrderLevelBuilder -from hummingbot.strategy.script_strategy_base import ScriptStrategyBase - - -class DManV1MultiplePairs(ScriptStrategyBase): - # Account configuration - exchange = "binance_perpetual" - trading_pairs = ["ETH-USDT"] - leverage = 20 - - # Candles configuration - candles_exchange = "binance_perpetual" - candles_interval = "3m" - candles_max_records = 300 - - # Orders configuration - order_amount = Decimal("25") - n_levels = 5 - start_spread = 0.0006 - step_between_orders = 0.009 - order_refresh_time = 60 * 15 # 15 minutes - cooldown_time = 5 - - # Triple barrier configuration - stop_loss = Decimal("0.2") - take_profit = Decimal("0.06") - time_limit = 60 * 60 * 12 - trailing_stop_activation_price_delta = Decimal(str(step_between_orders / 2)) - trailing_stop_trailing_delta = Decimal(str(step_between_orders / 3)) - - # Advanced configurations - natr_length = 100 - - # Applying the configuration - order_level_builder = OrderLevelBuilder(n_levels=n_levels) - order_levels = order_level_builder.build_order_levels( - amounts=order_amount, - spreads=Distributions.arithmetic(n_levels=n_levels, start=start_spread, step=step_between_orders), - triple_barrier_confs=TripleBarrierConf( - stop_loss=stop_loss, take_profit=take_profit, time_limit=time_limit, - trailing_stop_activation_price_delta=trailing_stop_activation_price_delta, - trailing_stop_trailing_delta=trailing_stop_trailing_delta), - order_refresh_time=order_refresh_time, - cooldown_time=cooldown_time, - ) - controllers = {} - markets = {} - executor_handlers = {} - - for trading_pair in trading_pairs: - config = DManV1Config( - exchange=exchange, - trading_pair=trading_pair, - order_levels=order_levels, - candles_config=[ - CandlesConfig(connector=candles_exchange, trading_pair=trading_pair, - interval=candles_interval, max_records=candles_max_records), - ], - leverage=leverage, - natr_length=natr_length, - ) - controller = DManV1(config=config) - markets = controller.update_strategy_markets_dict(markets) - controllers[trading_pair] = controller - - def __init__(self, connectors: Dict[str, ConnectorBase]): - super().__init__(connectors) - for trading_pair, controller in self.controllers.items(): - self.executor_handlers[trading_pair] = MarketMakingExecutorHandler(strategy=self, controller=controller) - - @property - def is_perpetual(self): - """ - Checks if the exchange is a perpetual market. - """ - return "perpetual" in self.exchange - - def on_stop(self): - if self.is_perpetual: - self.close_open_positions() - for executor_handler in self.executor_handlers.values(): - executor_handler.stop() - - def close_open_positions(self): - # we are going to close all the open positions when the bot stops - for connector_name, connector in self.connectors.items(): - for trading_pair, position in connector.account_positions.items(): - if trading_pair in self.markets[connector_name]: - if position.position_side == PositionSide.LONG: - self.sell(connector_name=connector_name, - trading_pair=position.trading_pair, - amount=abs(position.amount), - order_type=OrderType.MARKET, - price=connector.get_mid_price(position.trading_pair), - position_action=PositionAction.CLOSE) - elif position.position_side == PositionSide.SHORT: - self.buy(connector_name=connector_name, - trading_pair=position.trading_pair, - amount=abs(position.amount), - order_type=OrderType.MARKET, - price=connector.get_mid_price(position.trading_pair), - position_action=PositionAction.CLOSE) - - def on_tick(self): - """ - This shows you how you can start meta controllers. You can run more than one at the same time and based on the - market conditions, you can orchestrate from this script when to stop or start them. - """ - for executor_handler in self.executor_handlers.values(): - if executor_handler.status == ExecutorHandlerStatus.NOT_STARTED: - executor_handler.start() - - def format_status(self) -> str: - if not self.ready_to_trade: - return "Market connectors are not ready." - lines = [] - for trading_pair, executor_handler in self.executor_handlers.items(): - lines.extend( - [f"Strategy: {executor_handler.controller.config.strategy_name} | Trading Pair: {trading_pair}", - executor_handler.to_format_status()]) - return "\n".join(lines) diff --git a/hummingbot_files/templates/master_bot_conf/scripts/v2_market-making_dman_v2_multiple_pairs.py b/hummingbot_files/templates/master_bot_conf/scripts/v2_market-making_dman_v2_multiple_pairs.py deleted file mode 100644 index a3d7af2..0000000 --- a/hummingbot_files/templates/master_bot_conf/scripts/v2_market-making_dman_v2_multiple_pairs.py +++ /dev/null @@ -1,139 +0,0 @@ -from decimal import Decimal -from typing import Dict - -from hummingbot.connector.connector_base import ConnectorBase -from hummingbot.core.data_type.common import OrderType, PositionAction, PositionSide -from hummingbot.data_feed.candles_feed.candles_factory import CandlesConfig -from hummingbot.smart_components.controllers.dman_v2 import DManV2, DManV2Config -from hummingbot.smart_components.strategy_frameworks.data_types import ExecutorHandlerStatus, TripleBarrierConf -from hummingbot.smart_components.strategy_frameworks.market_making.market_making_executor_handler import ( - MarketMakingExecutorHandler, -) -from hummingbot.smart_components.utils.distributions import Distributions -from hummingbot.smart_components.utils.order_level_builder import OrderLevelBuilder -from hummingbot.strategy.script_strategy_base import ScriptStrategyBase - - -class DManV2MultiplePairs(ScriptStrategyBase): - # Account configuration - exchange = "binance_perpetual" - trading_pairs = ["ETH-USDT"] - leverage = 20 - - # Candles configuration - candles_exchange = "binance_perpetual" - candles_interval = "3m" - candles_max_records = 300 - - # Orders configuration - order_amount = Decimal("25") - n_levels = 5 - start_spread = 0.0006 - step_between_orders = 0.009 - order_refresh_time = 60 * 15 # 15 minutes - cooldown_time = 5 - - # Triple barrier configuration - stop_loss = Decimal("0.2") - take_profit = Decimal("0.06") - time_limit = 60 * 60 * 12 - trailing_stop_activation_price_delta = Decimal(str(step_between_orders / 2)) - trailing_stop_trailing_delta = Decimal(str(step_between_orders / 3)) - - # Advanced configurations - macd_fast = 12 - macd_slow = 26 - macd_signal = 9 - natr_length = 100 - - # Applying the configuration - order_level_builder = OrderLevelBuilder(n_levels=n_levels) - order_levels = order_level_builder.build_order_levels( - amounts=order_amount, - spreads=Distributions.arithmetic(n_levels=n_levels, start=start_spread, step=step_between_orders), - triple_barrier_confs=TripleBarrierConf( - stop_loss=stop_loss, take_profit=take_profit, time_limit=time_limit, - trailing_stop_activation_price_delta=trailing_stop_activation_price_delta, - trailing_stop_trailing_delta=trailing_stop_trailing_delta), - order_refresh_time=order_refresh_time, - cooldown_time=cooldown_time, - ) - controllers = {} - markets = {} - executor_handlers = {} - - for trading_pair in trading_pairs: - config = DManV2Config( - exchange=exchange, - trading_pair=trading_pair, - order_levels=order_levels, - candles_config=[ - CandlesConfig(connector=candles_exchange, trading_pair=trading_pair, - interval=candles_interval, max_records=candles_max_records), - ], - leverage=leverage, - macd_fast=macd_fast, - macd_slow=macd_slow, - macd_signal=macd_signal, - natr_length=natr_length, - ) - controller = DManV2(config=config) - markets = controller.update_strategy_markets_dict(markets) - controllers[trading_pair] = controller - - def __init__(self, connectors: Dict[str, ConnectorBase]): - super().__init__(connectors) - for trading_pair, controller in self.controllers.items(): - self.executor_handlers[trading_pair] = MarketMakingExecutorHandler(strategy=self, controller=controller) - - @property - def is_perpetual(self): - """ - Checks if the exchange is a perpetual market. - """ - return "perpetual" in self.exchange - - def on_stop(self): - if self.is_perpetual: - self.close_open_positions() - for executor_handler in self.executor_handlers.values(): - executor_handler.stop() - - def close_open_positions(self): - # we are going to close all the open positions when the bot stops - for connector_name, connector in self.connectors.items(): - for trading_pair, position in connector.account_positions.items(): - if trading_pair in self.markets[connector_name]: - if position.position_side == PositionSide.LONG: - self.sell(connector_name=connector_name, - trading_pair=position.trading_pair, - amount=abs(position.amount), - order_type=OrderType.MARKET, - price=connector.get_mid_price(position.trading_pair), - position_action=PositionAction.CLOSE) - elif position.position_side == PositionSide.SHORT: - self.buy(connector_name=connector_name, - trading_pair=position.trading_pair, - amount=abs(position.amount), - order_type=OrderType.MARKET, - price=connector.get_mid_price(position.trading_pair), - position_action=PositionAction.CLOSE) - - def on_tick(self): - """ - This shows you how you can start meta controllers. You can run more than one at the same time and based on the - market conditions, you can orchestrate from this script when to stop or start them. - """ - for executor_handler in self.executor_handlers.values(): - if executor_handler.status == ExecutorHandlerStatus.NOT_STARTED: - executor_handler.start() - - def format_status(self) -> str: - if not self.ready_to_trade: - return "Market connectors are not ready." - lines = [] - for trading_pair, executor_handler in self.executor_handlers.items(): - lines.extend( - [f"Strategy: {executor_handler.controller.config.strategy_name} | Trading Pair: {trading_pair}", - executor_handler.to_format_status()]) - return "\n".join(lines) diff --git a/hummingbot_files/templates/master_bot_conf/scripts/v2_market-making_dman_v3_multiple_pairs.py b/hummingbot_files/templates/master_bot_conf/scripts/v2_market-making_dman_v3_multiple_pairs.py deleted file mode 100644 index dd58f6c..0000000 --- a/hummingbot_files/templates/master_bot_conf/scripts/v2_market-making_dman_v3_multiple_pairs.py +++ /dev/null @@ -1,141 +0,0 @@ -from decimal import Decimal -from typing import Dict - -from hummingbot.connector.connector_base import ConnectorBase -from hummingbot.core.data_type.common import OrderType, PositionAction, PositionSide -from hummingbot.data_feed.candles_feed.candles_factory import CandlesConfig -from hummingbot.smart_components.controllers.dman_v3 import DManV3, DManV3Config -from hummingbot.smart_components.strategy_frameworks.data_types import ExecutorHandlerStatus, TripleBarrierConf -from hummingbot.smart_components.strategy_frameworks.market_making.market_making_executor_handler import ( - MarketMakingExecutorHandler, -) -from hummingbot.smart_components.utils.distributions import Distributions -from hummingbot.smart_components.utils.order_level_builder import OrderLevelBuilder -from hummingbot.strategy.script_strategy_base import ScriptStrategyBase - - -class DManV3MultiplePairs(ScriptStrategyBase): - # Account configuration - exchange = "binance_perpetual" - trading_pairs = ["ETH-USDT"] - leverage = 20 - - # Candles configuration - candles_exchange = "binance_perpetual" - candles_interval = "1h" - candles_max_records = 300 - bollinger_band_length = 200 - bollinger_band_std = 3.0 - - # Orders configuration - order_amount = Decimal("25") - n_levels = 5 - start_spread = 0.5 # percentage of the bollinger band (0.5 means that the order will be between the bollinger mid-price and the upper band) - step_between_orders = 0.3 # percentage of the bollinger band (0.1 means that the next order will be 10% of the bollinger band away from the previous order) - - # Triple barrier configuration - stop_loss = Decimal("0.01") - take_profit = Decimal("0.03") - time_limit = 60 * 60 * 6 - trailing_stop_activation_price_delta = Decimal("0.008") - trailing_stop_trailing_delta = Decimal("0.004") - - # Advanced configurations - side_filter = True - dynamic_spread_factor = True - dynamic_target_spread = False - smart_activation = False - activation_threshold = Decimal("0.001") - - # Applying the configuration - order_level_builder = OrderLevelBuilder(n_levels=n_levels) - order_levels = order_level_builder.build_order_levels( - amounts=order_amount, - spreads=Distributions.arithmetic(n_levels=n_levels, start=start_spread, step=step_between_orders), - triple_barrier_confs=TripleBarrierConf( - stop_loss=stop_loss, take_profit=take_profit, time_limit=time_limit, - trailing_stop_activation_price_delta=trailing_stop_activation_price_delta, - trailing_stop_trailing_delta=trailing_stop_trailing_delta), - ) - controllers = {} - markets = {} - executor_handlers = {} - - for trading_pair in trading_pairs: - config = DManV3Config( - exchange=exchange, - trading_pair=trading_pair, - order_levels=order_levels, - candles_config=[ - CandlesConfig(connector=candles_exchange, trading_pair=trading_pair, - interval=candles_interval, max_records=candles_max_records), - ], - bb_length=bollinger_band_length, - bb_std=bollinger_band_std, - side_filter=side_filter, - dynamic_spread_factor=dynamic_spread_factor, - dynamic_target_spread=dynamic_target_spread, - smart_activation=smart_activation, - activation_threshold=activation_threshold, - leverage=leverage, - ) - controller = DManV3(config=config) - markets = controller.update_strategy_markets_dict(markets) - controllers[trading_pair] = controller - - def __init__(self, connectors: Dict[str, ConnectorBase]): - super().__init__(connectors) - for trading_pair, controller in self.controllers.items(): - self.executor_handlers[trading_pair] = MarketMakingExecutorHandler(strategy=self, controller=controller) - - @property - def is_perpetual(self): - """ - Checks if the exchange is a perpetual market. - """ - return "perpetual" in self.exchange - - def on_stop(self): - if self.is_perpetual: - self.close_open_positions() - for executor_handler in self.executor_handlers.values(): - executor_handler.stop() - - def close_open_positions(self): - # we are going to close all the open positions when the bot stops - for connector_name, connector in self.connectors.items(): - for trading_pair, position in connector.account_positions.items(): - if trading_pair in self.markets[connector_name]: - if position.position_side == PositionSide.LONG: - self.sell(connector_name=connector_name, - trading_pair=position.trading_pair, - amount=abs(position.amount), - order_type=OrderType.MARKET, - price=connector.get_mid_price(position.trading_pair), - position_action=PositionAction.CLOSE) - elif position.position_side == PositionSide.SHORT: - self.buy(connector_name=connector_name, - trading_pair=position.trading_pair, - amount=abs(position.amount), - order_type=OrderType.MARKET, - price=connector.get_mid_price(position.trading_pair), - position_action=PositionAction.CLOSE) - - def on_tick(self): - """ - This shows you how you can start meta controllers. You can run more than one at the same time and based on the - market conditions, you can orchestrate from this script when to stop or start them. - """ - for executor_handler in self.executor_handlers.values(): - if executor_handler.status == ExecutorHandlerStatus.NOT_STARTED: - executor_handler.start() - - def format_status(self) -> str: - if not self.ready_to_trade: - return "Market connectors are not ready." - lines = [] - for trading_pair, executor_handler in self.executor_handlers.items(): - lines.extend( - [f"Strategy: {executor_handler.controller.config.strategy_name} | Trading Pair: {trading_pair}", - executor_handler.to_format_status()]) - return "\n".join(lines) diff --git a/main.py b/main.py index 5d61dbf..728a8ae 100644 --- a/main.py +++ b/main.py @@ -11,31 +11,31 @@ def main_page(): [ Page("main.py", "Hummingbot Dashboard", "📊"), Section("Bot Orchestration", "🐙"), - Page("pages/bot_orchestration/app.py", "Instances", "🦅"), - Page("pages/launch_bot/app.py", "Deploy", "🚀"), + Page("frontend/pages/bot_orchestration/app.py", "Instances", "🦅"), + Page("frontend/pages/launch_bot/app.py", "Deploy", "🚀"), Section("Config Generator", "🎛️"), - Page("pages/pmm_simple/app.py", "PMM Simple", "👨‍🏫"), - Page("pages/dman_maker_v2/app.py", "D-Man Maker V2", "🤖"), - Page("pages/bollinger_v1/app.py", "Bollinger V1", "📈"), - Page("pages/trend_follower_v1/app.py", "Trend Follower V1", "📈"), - Page("pages/kalman_filter_v1/app.py", "Kalman Filter V1", "👨‍🔬"), - Page("pages/macd_bb_v1/app.py", "MACD_BB V1", "📊"), - Page("pages/dman_v5/app.py", "D-Man V5", "📊"), - Page("pages/xemm_controller/app.py", "XEMM Controller", "⚡️"), - Page("pages/position_builder/app.py", "Position Builder", "🔭"), - Page("pages/dynamic_position_builder/app.py", "Dynamic Position Builder", "🔭"), + Page("frontend/pages/pmm_simple/app.py", "PMM Simple", "👨‍🏫"), + Page("frontend/pages/dman_maker_v2/app.py", "D-Man Maker V2", "🤖"), + Page("frontend/pages/bollinger_v1/app.py", "Bollinger V1", "📈"), + Page("frontend/pages/trend_follower_v1/app.py", "Trend Follower V1", "📈"), + Page("frontend/pages/kalman_filter_v1/app.py", "Kalman Filter V1", "👨‍🔬"), + Page("frontend/pages/macd_bb_v1/app.py", "MACD_BB V1", "📊"), + Page("frontend/pages/dman_v5/app.py", "D-Man V5", "📊"), + Page("frontend/pages/xemm_controller/app.py", "XEMM Controller", "⚡️"), + Page("frontend/pages/position_builder/app.py", "Position Builder", "🔭"), + Page("frontend/pages/dynamic_position_builder/app.py", "Dynamic Position Builder", "🔭"), # Page("pages/master_conf/app.py", "Credentials", "🗝️"), # Page("pages/file_manager/app.py", "File Explorer", "🗂"), Section("Data", "💾"), - Page("pages/data_download_candles/app.py", "Download Candles", "💹"), + Page("frontend/pages/data_download_candles/app.py", "Download Candles", "💹"), # Page("pages/backtest_create/create.py", "Create", "⚔️"), # Page("pages/backtest_optimize/optimize.py", "Optimize", "🧪"), # Page("pages/backtest_analyze/analyze.py", "Analyze", "🔬"), Section("Community Pages", "👨‍👩‍👧‍👦"), - Page("pages/strategy_performance/app.py", "Strategy Performance", "🚀"), - Page("pages/db_inspector/app.py", "DB Inspector", "🔍"), - Page("pages/token_spreads/app.py", "Token Spreads", "🧙"), - Page("pages/tvl_vs_mcap/app.py", "TVL vs Market Cap", "🦉"), + Page("frontend/pages/strategy_performance/app.py", "Strategy Performance", "🚀"), + Page("frontend/pages/db_inspector/app.py", "DB Inspector", "🔍"), + Page("frontend/pages/token_spreads/app.py", "Token Spreads", "🧙"), + Page("frontend/pages/tvl_vs_mcap/app.py", "TVL vs Market Cap", "🦉"), ] ) @@ -96,11 +96,9 @@ def main_page(): 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("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).") + 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") diff --git a/quants_lab/research_notebooks/dman_maker/01_strategy_design_dman_maker.ipynb b/quants_lab/research_notebooks/dman_maker/01_strategy_design_dman_maker.ipynb index 6c5a876..befef71 100644 --- a/quants_lab/research_notebooks/dman_maker/01_strategy_design_dman_maker.ipynb +++ b/quants_lab/research_notebooks/dman_maker/01_strategy_design_dman_maker.ipynb @@ -11,18 +11,18 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 12, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "100%|██████████| 10080/10080 [00:09<00:00, 1117.51it/s]\n", + "100%|██████████| 10080/10080 [00:13<00:00, 772.37it/s]\n", "Unclosed client session\n", - "client_session: \n", + "client_session: \n", "Unclosed connector\n", - "connections: ['[(, 28635.105190041)]']\n", - "connector: \n" + "connections: ['[(, 127427.978703458)]']\n", + "connector: \n" ] } ], @@ -32,8 +32,8 @@ "from utils.hummingbot_processes import aget_candles_list\n", "\n", "exchange = \"binance_perpetual\"\n", - "symbols = [\"MATIC-USDT\"]\n", - "intervals = [\"1m\"]\n", + "symbols = [\"XRP-USDT\"]\n", + "intervals = [\"3m\"]\n", "max_records = 10080\n", "\n", "candles_config = [CandlesConfig(connector=exchange,\n", @@ -46,14 +46,14 @@ "metadata": { "collapsed": false, "ExecuteTime": { - "end_time": "2024-04-11T21:31:26.786920Z", - "start_time": "2024-04-11T21:31:17.744594Z" + "end_time": "2024-04-18T22:02:52.165106Z", + "start_time": "2024-04-18T22:02:39.073506Z" } } }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 13, "outputs": [], "source": [ "import pandas as pd\n", @@ -91,14 +91,14 @@ "metadata": { "collapsed": false, "ExecuteTime": { - "end_time": "2024-04-11T21:09:39.343126Z", - "start_time": "2024-04-11T21:09:39.339565Z" + "end_time": "2024-04-18T22:02:54.638744Z", + "start_time": "2024-04-18T22:02:54.635152Z" } } }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 14, "outputs": [], "source": [ "window_length = 240 # Replace with your desired\n", @@ -108,19 +108,19 @@ "metadata": { "collapsed": false, "ExecuteTime": { - "end_time": "2024-04-11T21:15:49.256567Z", - "start_time": "2024-04-11T21:15:48.820292Z" + "end_time": "2024-04-18T22:02:56.718508Z", + "start_time": "2024-04-18T22:02:56.321691Z" } } }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 15, "outputs": [ { "data": { "text/plain": "
", - "image/png": "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07x5c9Wq5fjP3YWOY0bnzp2VlZWl5cuXa+3atfr111/1/vvvl7slsmnTppfcV1ngaNOmzQXbHD58WEePHtU777xjD0JlX2XhuaCgoNJ1L1myRK+99prCwsL0r3/9q1y/ycnJ0YgRIxQeHm5/7un222+XJB07dsyhrb+/f7mweP77s3//fjVo0EABAQEO7Zo1a+bwes+ePTIMQ88880y583zuuecczjMtLU1Hjx5VixYt1LZtWz3++OP6/vvvL3kNAMAVeEYKAKrBgQMHdOzYsXJ/NJ6rTp06WrNmjVatWqUvv/xSS5Ys0bx589SzZ08tW7asUtNkm3muqbIu9KHBJSUl1TZ194WOY7jxEzyuvvpqxcXFXbKdq96TskD9wAMPVPhckSSH6fUv5Ny6ExIS1KpVK91555164403lJqaKunse9u7d28dOXJETz75pFq1aqXAwEAdPHhQI0aMKBfuXdkPyvY9btw4JSQkVNim7Ofotttu0969e/X5559r2bJl+tvf/qapU6dq1qxZevDBB11WEwBUhCAFANXggw8+kKQL/mFYplatWurVq5d69eqlKVOmaNKkSXrqqae0atUqxcXFXTDUOOv8W6IMw9CePXsc/iC/6qqrdPTo0XLb7t+/X9dee639tZnaoqOjtXz5ch0/ftxhVOrHH3+0r3eF6Ohoff/99yotLXUYlXL1cS5X2XX84YcfLtimXr16Cg4OVklJSaUCXGX169dPt99+uyZNmqQ//vGPCgwM1LZt27Rr1y699957Gj58uL3t5cyGFx0drVWrVtmn5C+zZ88eh3Zl18JqtVbqPMPDwzVy5EiNHDlSRUVFuu222zRhwgSCFIAqx619AFDFVq5cqeeff15NmzbV0KFDL9juyJEj5Za1b99eklRcXCxJCgwMlKQKg40z3n//fYfntj766CPl5uaqT58+9mXXXXed1q1bZ/9QX0lauHBhuWnSzdTWt29flZSU6C9/+YvD8qlTp8pisTgc/3L07dtXeXl5mjdvnn3ZmTNn9OabbyooKMh+q5q71atXT7fddpveffdd5eTkOKwrG3WrXbu2Bg4cqI8//rjCwHX48GGnj//kk0/qt99+01//+lf7sc49dtn3b7zxhtPHSEhIkM1msx9DOjv6NGPGDId29evXV/fu3fX2228rNze33H7OPc/ffvvNYV1QUJCaNWtm/3kBgKrEiBQAuNDixYv1448/6syZM8rPz9fKlSuVlZWl6OhoffHFFxf9ENa0tDStWbNG/fr1U3R0tAoKCvTWW2+pYcOG6tq1q6SzoSYsLEyzZs1ScHCwAgMD1blz50o9h1OR8PBwde3aVSNHjlR+fr6mTZumZs2aOUwI8OCDD+qjjz7SHXfcod///vfau3ev5syZ4zD5g9na+vfvrx49euipp57Szz//rBtuuEHLli3T559/rkcffbTcvp01evRovf322xoxYoQ2bdqkJk2a6KOPPtI333yjadOmXfSZteo2ffp0de3aVTfeeKNGjx6tpk2b6ueff9aXX36pLVu2SJJeeuklrVq1Sp07d9aoUaMUExOjI0eOaPPmzVq+fHmFYbwy+vTpozZt2mjKlClKSUlRq1atdN1112ncuHE6ePCgQkJC9PHHH1/ymbSLGTBggDp16qTHHntMe/bsUatWrfTFF1/Yaz53RHPGjBnq2rWr2rZtq1GjRunaa69Vfn6+srOzdeDAAW3dulWSFBMTo+7du6tjx44KDw/Xxo0b9dFHH2nMmDFO1wkAleau6QIB4EpSNv152Zevr68RGRlp9O7d23jjjTccptkuc/705ytWrDDuvvtuIyoqyvD19TWioqKM+++/39i1a5fDdp9//rkRExNj+Pj4OEwbffvttxvXX399hfVdaPrz//u//zPGjx9v1K9f36hTp47Rr1+/ctNvG4ZhvP7668Y111xj+Pn5GbfeequxcePGcvu8WG3nT39uGIZx/PhxY+zYsUZUVJRhtVqN5s2bG6+++qrDdN+GYVQ4NbdhXHha9vPl5+cbI0eONK6++mrD19fXaNu2bYVTtJud/vxSbcumOH/11VcvuO78On744QfjnnvuMcLCwgx/f3+jZcuWxjPPPFPufFJSUoxGjRoZVqvViIyMNHr16mW88847l1V3RkaGQ007duww4uLijKCgIOPqq682Ro0aZZ92/ty6ExMTjcDAwHL7O79/G4ZhHD582BgyZIgRHBxshIaGGiNGjDC++eYbQ5Ixd+5ch7Z79+41hg8fbkRGRhpWq9W45pprjDvvvNP46KOP7G1eeOEFo1OnTkZYWJhRp04do1WrVsaLL75onD59+pLXAgAul8Uw3PikLgAAqNE+++wz3XPPPfr666916623urscAKg0ghQAAKgW//73vx1m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" + "image/png": "iVBORw0KGgoAAAANSUhEUgAAA1sAAAIjCAYAAAD1OgEdAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/H5lhTAAAACXBIWXMAAA9hAAAPYQGoP6dpAABPnklEQVR4nO3dfXyP9f////trvHZiNjMnO3Eyc5KTnBXRclrGnCSkIiujRR9tFdKJdxEqSjnPO/V+v6MTSjoRisxJVOS0IZWzZBXbRMwm87Id3z/89vr1spnt5XXstZfdrpeLS47jeB7H8TheD8e4d5y8LIZhGAIAAAAAuJSXuwsAAAAAgGsRYQsAAAAATEDYAgAAAAATELYAAAAAwASELQAAAAAwAWELAAAAAExA2AIAAAAAExC2AAAAAMAEhC0AAAAAMAFhCwBKqQkTJshisZTIvjp37qzOnTvbp7/66itZLBZ99NFHJbL/IUOGqE6dOiWyL2dlZmbqwQcfVGhoqCwWi0aOHGnavn799VdZLBYtWLDAtH0AAMxH2AKAErBgwQJZLBb7L19fX4WHhysmJkazZ8/WmTNnXLKfo0ePasKECUpOTnbJ9lypNNdWFJMnT9aCBQs0YsQIvfvuu7r//vsvO7ZOnToO/a5evbo6dOigTz/9tAQrLr5L6/b391ebNm30zjvvuLs0APBIFsMwDHcXAQDXugULFmjo0KGaNGmSIiMjZbPZlJqaqq+++kpJSUmqXbu2li1bpubNm9vXuXDhgi5cuCBfX98i72f79u266aabNH/+fA0ZMqTI650/f16S5O3tLenila1bb71VS5Ys0V133VXk7Thbm81mU25urnx8fFyyLzPcfPPNKl++vL755psrjq1Tp44qV66sxx9/XNLFoPnGG2/ol19+0euvv67/+7//K3R9wzCUnZ0tq9WqcuXKuaT+ori07mPHjum///2v9u/frzfffFPDhg0rsVoA4FpQ3t0FAEBZ0qNHD7Vu3do+PXbsWK1bt06333677rjjDv3000/y8/OTJJUvX17ly5v7Y/rs2bOqUKGCPWS5i9Vqdev+iyI9PV1NmjQp8vgaNWrovvvus08PHjxY9evX14wZMy4bti5cuKDc3Fx5e3sXK2S70qV1DxkyRHXr1tWMGTMIWwBQTNxGCABudtttt2ncuHE6cuSI3nvvPfv8gp7ZSkpKUvv27RUUFKSKFSuqYcOG+te//iXp4tWom266SZI0dOhQ+61gec/9dO7cWU2bNtWOHTvUsWNHVahQwb7upc9s5cnJydG//vUvhYaGyt/fX3fccYd+++03hzF16tQp8CraP7d5pdoKemYrKytLjz/+uGrVqiUfHx81bNhQr776qi69IcNisSgxMVFLly5V06ZN5ePjo+uvv16rVq0q+AO/RHp6uuLj4xUSEiJfX1+1aNFCb7/9tn153vNrhw8f1ueff26v/ddffy3S9vOEhoaqcePGOnz4sKT//7msV199VTNnzlS9evXk4+OjH3/88bLPbP3888+65557VK1aNfn5+alhw4Z65plnHMb88ccfeuCBBxQSEmL/LN56661i1fpP1apVU6NGjXTo0CGH+V9//bXuvvtu1a5dWz4+PqpVq5ZGjRqlv//+22HckCFDVLFiRf3xxx/q27evKlasqGrVqmnMmDHKyclxGHvixAndf//9CgwMVFBQkOLi4rRr167LfhZ33XWXgoOD5evrq9atW2vZsmUOY2w2myZOnKgGDRrI19dXVapUUfv27ZWUlOT05wEAxcGVLQAoBe6//37961//0urVqy979WDv3r26/fbb1bx5c02aNEk+Pj46ePCgvv32W0lS48aNNWnSJI0fP17Dhw9Xhw4dJEm33HKLfRsnTpxQjx49NHDgQN13330KCQkptK4XX3xRFotFTz31lNLT0zVz5kxFR0crOTnZfgWuKIpS2z8ZhqE77rhD69evV3x8vFq2bKkvv/xSTzzxhP744w/NmDHDYfw333yjTz75RA8//LACAgI0e/Zs9e/fXykpKapSpcpl6/r777/VuXNnHTx4UImJiYqMjNSSJUs0ZMgQnTp1So899pgaN26sd999V6NGjVLNmjXtt9hVq1atyMcvXfyH/2+//Zavnvnz5+vcuXMaPny4fHx8FBwcrNzc3Hzr7969Wx06dJDVatXw4cNVp04dHTp0SMuXL9eLL74oSUpLS9PNN99sD6DVqlXTypUrFR8fr4yMDKde6nHhwgX9/vvvqly5ssP8JUuW6OzZsxoxYoSqVKmirVu3as6cOfr999+1ZMkSh7E5OTmKiYlR27Zt9eqrr2rNmjWaNm2a6tWrpxEjRkiScnNz1bt3b23dulUjRoxQo0aN9NlnnykuLi5fTXv37lW7du1Uo0YNPf300/L399eHH36ovn376uOPP1a/fv0kXfwfFlOmTNGDDz6oNm3aKCMjQ9u3b9fOnTvVtWvXYn8WAFBsBgDAdPPnzzckGdu2bbvsmEqVKhk33HCDffq5554z/vljesaMGYYk4/jx45fdxrZt2wxJxvz58/Mt69SpkyHJmDdvXoHLOnXqZJ9ev369IcmoUaOGkZGRYZ//4YcfGpKMWbNm2edFREQYcXFxV9xmYbXFxcUZERER9umlS5cakowXXnjBYdxdd91lWCwW4+DBg/Z5kgxvb2+Hebt27TIkGXPmzMm3r3+aOXOmIcl477337PPOnz9vREVFGRUrVnQ49oiICKNXr16Fbu+fY7t162YcP37cOH78uLFr1y5j4MCBhiTjkUceMQzDMA4fPmxIMgIDA4309HSH9fOW/fOz6tixoxEQEGAcOXLEYWxubq799/Hx8UZYWJjx559/OowZOHCgUalSJePs2bPFqnvPnj3G/fffb0gyEhISHMYWtK0pU6YYFovFoca4uDhDkjFp0iSHsTfccIPRqlUr+/THH39sSDJmzpxpn5eTk2Pcdttt+T6LLl26GM2aNTPOnTvn8DnccsstRoMGDezzWrRoUeSeAYAZuI0QAEqJihUrFvpWwqCgIEnSZ599VuCVj6Lw8fHR0KFDizx+8ODBCggIsE/fddddCgsL0xdffOHU/ovqiy++ULly5fToo486zH/88cdlGIZWrlzpMD86Olr16tWzTzdv3lyBgYH65Zdfrrif0NBQ3XvvvfZ5VqtVjz76qDIzM7Vhwwanj2H16tWqVq2aqlWrphYtWmjJkiW6//779fLLLzuM69+//xWvkh0/flwbN27UAw88oNq1azssy7vV1DAMffzxx+rdu7cMw9Cff/5p/xUTE6PTp09r586dxaq7WbNmevfddzV06FC98sorDuP+eWUzKytLf/75p2655RYZhqHvv/8+33YvfU6tQ4cODv1ZtWqVrFarw5VdLy8vJSQkOKx38uRJrVu3Tvfcc4/OnDljP8YTJ04oJiZGBw4c0B9//CHp4jmzd+9eHThw4IrHDQBmIGwBQCmRmZnpEGwuNWDAALVr104PPvigQkJCNHDgQH344YfFCl41atQo1sswGjRo4DBtsVhUv379Yj+vVFxHjhxReHh4vs+jcePG9uX/dGkAkaTKlSvrr7/+uuJ+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HHXr1k3bt29XamqqKW/TBAAz8cwWAAAoFR555BH9/fffioqKUnZ2tj755BNt2rRJkydPJmgB8Ehc2QIAAKXCokWLNG3aNB08eFDnzp1T/fr1NWLECF5oAcBjEbYAAAAAwAR8zxYAAAAAmICwBQAAAAAm4AUZRZCbm6ujR48qICDA4UsVAQAAAJQthmHozJkzCg8Pl5dX4deuCFtFcPToUdWqVcvdZQAAAAAoJX777TfVrFmz0DGErSIICAiQdPEDDQwMdMk2bTabVq9erW7duslqtbpkm3A9+uQ56JVnoE+eg155BvrkOeiVZyhKnzIyMlSrVi17RigMYasI8m4dDAwMdGnYqlChggIDAznhSjH65DnolWegT56DXnkG+uQ56JVnKE6fivJ4ES/IAAAAAAATELYAAAAAwASELQAAAAAwAWELAAAAAExA2AIAAAAAExC2AAAAAMAEhC0AAAAAMAFhCwAAAABMQNgCAAAAABMQtgAAAADABIQtAAAAADABYQsAAAAATEDYAgAAAAATELYAAAAAwASELQAAAAAwAWELAAAAAExA2AIAAAAAExC2AAAAAMAEhC0AAAAAMEF5dxeAktW7t3PrLV/u2joAAACAax1XtgAAAADABIQtAAAAADABYQsAAAAATEDYAgAAAAATELYAAAAAwASELQAAAAAwAWELAAAAAEzg1rC1ceNG9e7dW+Hh4bJYLFq6dKl9mc1m01NPPaVmzZrJ399f4eHhGjx4sI4ePeqwjZMnTyo2NlaBgYEKCgpSfHy8MjMzHcbs3r1bHTp0kK+vr2rVqqWpU6eWxOEBAAAAKMPcGraysrLUokULzZ07N9+ys2fPaufOnRo3bpx27typTz75RPv27dMdd9zhMC42NlZ79+5VUlKSVqxYoY0bN2r48OH25RkZGerWrZsiIiK0Y8cOvfLKK5owYYLefPNN048PAAAAQNlV3p0779Gjh3r06FHgskqVKikpKclh3muvvaY2bdooJSVFtWvX1k8//aRVq1Zp27Ztat26tSRpzpw56tmzp1599VWFh4dr4cKFOn/+vN566y15e3vr+uuvV3JysqZPn+4QygAAAADAldwatorr9OnTslgsCgoKkiRt3rxZQUFB9qAlSdHR0fLy8tKWLVvUr18/bd68WR07dpS3t7d9TExMjF5++WX99ddfqly5cr79ZGdnKzs72z6dkZEh6eKtjTabzSXHkrcdV22vqKxW59Yr4TJLDXf1CcVHrzwDffIc9Moz0CfPQa88Q1H6VJweekzYOnfunJ566inde++9CgwMlCSlpqaqevXqDuPKly+v4OBgpaam2sdERkY6jAkJCbEvKyhsTZkyRRMnTsw3f/Xq1apQoYJLjifPpVfvzBYX59x6X3zh2jo8TUn3Cc6jV56BPnkOeuUZ6JPnoFeeobA+nT17tsjb8YiwZbPZdM8998gwDL3++uum72/s2LEaPXq0fTojI0O1atVSt27d7EHvatlsNiUlJalr166yOnu5yQkDBji33uLFrq3DU7irTyg+euUZ6JPnoFeegT55DnrlGYrSp7y73oqi1IetvKB15MgRrVu3ziHshIaGKj093WH8hQsXdPLkSYWGhtrHpKWlOYzJm84bcykfHx/5+Pjkm2+1Wl1+cpixzcI4e+W6rP9MKOk+wXn0yjPQJ89BrzwDffIc9MozFNan4vSvVH/PVl7QOnDggNasWaMqVao4LI+KitKpU6e0Y8cO+7x169YpNzdXbdu2tY/ZuHGjw72VSUlJatiwYYG3EAIAAACAK7g1bGVmZio5OVnJycmSpMOHDys5OVkpKSmy2Wy66667tH37di1cuFA5OTlKTU1Vamqqzp8/L0lq3LixunfvrmHDhmnr1q369ttvlZiYqIEDByo8PFySNGjQIHl7eys+Pl579+7V4sWLNWvWLIfbBAEAAADA1dx6G+H27dt166232qfzAlBcXJwmTJigZcuWSZJatmzpsN769evVuXNnSdLChQuVmJioLl26yMvLS/3799fs2bPtYytVqqTVq1crISFBrVq1UtWqVTV+/Hhe+w4AAADAVG4NW507d5ZhGJddXtiyPMHBwVq0aFGhY5o3b66vv/662PUBAAAAgLNK9TNbAAAAAOCpCFsAAAAAYALCFgAAAACYgLAFAAAAACYgbAEAAACACQhbAAAAAGACwhYAAAAAmICwBQAAAAAmIGwBAAAAgAkIWwAAAABgAsIWAAAAAJiAsAUAAAAAJijv7gJwbevd27n1li93bR0AAABASePKFgAAAACYgLAFAAAAACYgbAEAAACACQhbAAAAAGACwhYAAAAAmICwBQAAAAAmIGwBAAAAgAkIWwAAAABgAsIWAAAAAJigvLsLAFypd2/n1lu+3LV1AAAAAIQtlErOhiYAAACgtOA2QgAAAAAwAWELAAAAAExA2AIAAAAAExC2AAAAAMAEhC0AAAAAMAFhCwAAAABMQNgCAAAAABMQtgAAAADABIQtAAAAADABYQsAAAAATEDYAgAAAAATELYAAAAAwASELQAAAAAwAWELAAAAAExA2AIAAAAAExC2AAAAAMAEhC0AAAAAMAFhCwAAAABMQNgCAAAAABMQtgAAAADABIQtAAAAADABYQsAAAAATEDYAgAAAAATELYAAAAAwASELQAAAAAwAWELAAAAAExA2AIAAAAAExC2AAAAAMAEhC0AAAAAMAFhCwAAAABMQNgCAAAAABMQtgAAAADABIQtAAAAADABYQsAAAAATEDYAgAAAAATELYAAAAAwARuDVsbN25U7969FR4eLovFoqVLlzosNwxD48ePV1hYmPz8/BQdHa0DBw44jDl58qRiY2MVGBiooKAgxcfHKzMz02HM7t271aFDB/n6+qpWrVqaOnWq2YcGAAAAoIxza9jKyspSixYtNHfu3AKXT506VbNnz9a8efO0ZcsW+fv7KyYmRufOnbOPiY2N1d69e5WUlKQVK1Zo48aNGj58uH15RkaGunXrpoiICO3YsUOvvPKKJkyYoDfffNP04wMAAABQdpV358579OihHj16FLjMMAzNnDlTzz77rPr06SNJeueddxQSEqKlS5dq4MCB+umnn7Rq1Spt27ZNrVu3liTNmTNHPXv21Kuvvqrw8HAtXLhQ58+f11tvvSVvb29df/31Sk5O1vTp0x1CGQAAAAC4klvDVmEOHz6s1NRURUdH2+dVqlRJbdu21ebNmzVw4EBt3rxZQUFB9qAlSdHR0fLy8tKWLVvUr18/bd68WR07dpS3t7d9TExMjF5++WX99ddfqly5cr59Z2dnKzs72z6dkZEhSbLZbLLZbC45vrztuGp7RWW1Orees2U6u7+Sdrnjc1efUHz0yjPQJ89BrzwDffIc9MozFKVPxelhqQ1bqampkqSQkBCH+SEhIfZlqampql69usPy8uXLKzg42GFMZGRkvm3kLSsobE2ZMkUTJ07MN3/16tWqUKGCk0dUsKSkJJdu70ri4pxb74svSnZ/Je1Kx1fSfYLz6JVnoE+eg155BvrkOeiVZyisT2fPni3ydkpt2HKnsWPHavTo0fbpjIwM1apVS926dVNg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MDVp0sRhXuPGjfXxxx9LkkJDQyVJaWlpDle20tLS1LJlS/uY9PR0h21cuHBBJ0+etK9/KR8fH/n4+OSbb7VaXX5ymLHNwnDl2jk2m7XAsFXStwPys/nKSvqcgnPok+egV56BPnkOeuUZCutTcfrn1NsIR40aJavVqpSUFIfb6gYMGKBVq1Y5s8kCtWvXLt/tf/v371dERISkiy/LCA0N1dq1a+3LMzIytGXLFkVFRUmSoqKidOrUKe3YscM+Zt26dcrNzVXbtm1dVisAAAAA/JNTV7ZWr16tL7/8UjVr1nSY36BBAx05csQlhUkXQ90tt9yiyZMn65577tHWrVv15ptv6s0335QkWSwWjRw5Ui+88IIaNGigyMhIjRs3TuHh4erbt6+ki1fCunfvrmHDhmnevHmy2WxKTEzUwIEDPfpNhL17u7sCAAAAAIVxKmxlZWUV+KKIkydPFnj7nbNuuukmffrppxo7dqwmTZqkyMhIzZw5U7GxsfYxTz75pLKysjR8+HCdOnVK7du316pVq+wv15CkhQsXKjExUV26dJGXl5f69++v2bNnu6xOAAAAALiUU2GrQ4cOeuedd/T8889LuniFKTc3V1OnTtWtt97q0gJvv/123X777ZddbrFYNGnSJE2aNOmyY4KDg7Vo0SKX1gUAAAAAhXEqbE2dOlVdunTR9u3bdf78eT355JPau3evTp48qW+//dbVNQIAAACAx3HqBRlNmzbV/v371b59e/Xp00dZWVm688479f3336tevXqurhEAAAAAPE6xr2zZbDZ1795d8+bN0zPPPGNGTQAAAADg8Yp9ZctqtWr37t1m1AIAAAAA1wynbiO877779L///c/VtQAAAADANcOpF2RcuHBBb731ltasWaNWrVrJ39/fYfn06dNdUhwAAAAAeKpiha1ffvlFderU0Q8//KAbb7xRkrR//36HMRaLxXXVAQAAAICHKlbYatCggY4dO6b169dLkgYMGKDZs2crJCTElOIAAAAAwFMV65ktwzAcpleuXKmsrCyXFgQAAAAA1wKnXpCR59LwBQAAAAC4qFhhy2Kx5Hsmi2e0AAAAACC/Yj2zZRiGhgwZIh8fH0nSuXPn9H//93/53kb4ySefuK5CAHa9ezu/7vLlrqsDAAAAV1assBUXF+cwfd9997m0GAAAAAC4VhQrbM2fP9+sOgAAAADgmnJVL8gAAAAAABSMsAUAAAAAJiBsAQAAAIAJCFsAAAAAYALCFgAAAACYgLAFAAAAACYgbAEAAACACYr1PVsAHPXu7e4KAAAAUFpxZQsAAAAATEDYAgAAAAATELYAAAAAwASELQAAAAAwAWELAAAAAExA2AIAAAAAExC2AAAAAMAEhC0AAAAAMAFhCwAAAABMQNgCAAAAABMQtgAAAADABIQtAAAAADABYQsAAAAATEDYAgAAAAATELYAAAAAwASELQAAAAAwAWELAAAAAExA2AIAAAAAExC2AAAAAMAEhC0AAAAAMAFhCwAAAABMQNgCAAAAABMQtgAAAADABIQtAAAAADABYQsAAAAATEDYAgAAAAATELYAAAAAwASELQAAAAAwAWELAAAAAExA2AIAAAAAExC2AAAAAMAEhC0AAAAAMAFhCwAAAABMQNgCAAAAABMQtgAAAADABIQtAAAAADABYQsAAAAATEDYAgAAAAATeFTYeumll2SxWDRy5Ej7vHPnzikhIUFVqlRRxYoV1b9/f6WlpTmsl5KSol69eqlChQqqXr26nnjiCV24cKGEqwcAAABQlnhM2Nq2bZveeOMNNW/e3GH+qFGjtHz5ci1ZskQbNmzQ0aNHdeedd9qX5+TkqFevXjp//rw2bdqkt99+WwsWLND48eNL+hAAAAAAlCEeEbYyMzMVGxur//znP6pcubJ9/unTp/W///1P06dP12233aZWrVpp/vz52rRpk7777jtJ0urVq/Xjjz/qvffeU8uWLdWjRw89//zzmjt3rs6fP++uQwIAAABwjSvv7gKKIiEhQb169VJ0dLReeOEF+/wdO3bIZrMpOjraPq9Ro0aqXbu2Nm/erJtvvlmbN29Ws2bNFBISYh8TExOjESNGaO/evbrhhhvy7S87O1vZ2dn26YyMDEmSzWaTzWZzyTHlbcfZ7VmtLikDV2C12hz+68lc9Ee31Lracwolgz55DnrlGeiT56BXnqEofSpOD0t92Prggw+0c+dObdu2Ld+y1NRUeXt7KygoyGF+SEiIUlNT7WP+GbTyluctK8iUKVM0ceLEfPNXr16tChUqOHMYl5WUlOTUenFxLi0DVzBokHN9Kk2++MLdFZQMZ88plCz65DnolWegT56DXnmGwvp09uzZIm+nVIet3377TY899piSkpLk6+tbYvsdO3asRo8ebZ/OyMhQrVq11K1bNwUGBrpkHzabTUlJSeratausTlymGjDAJWXgCqxWmwYNStKiRV1ls3n25cTFi91dgbmu9pxCyaBPnoNeeQb65DnolWcoSp/y7norilIdtnbs2KH09HTdeOON9nk5OTnauHGjXnvtNX355Zc6f/68Tp065XB1Ky0tTaGhoZKk0NBQbd261WG7eW8rzBtzKR8fH/n4+OSbb7VaXX5yOLtNrkCXLJvN6vFhq6z8XDfjPIXr0SfPQa88A33yHPTKMxTWp+L0r1S/IKNLly7as2ePkpOT7b9at26t2NhY+++tVqvWrl1rX2ffvn1KSUlRVFSUJCkqKkp79uxRenq6fUxSUpICAwPVpEmTEj8mAAAAAGVDqb6yFRAQoKZNmzrM8/f3V5UqVezz4+PjNXr0aAUHByswMFCPPPKIoqKidPPNN0uSunXrpiZNmuj+++/X1KlTlZqaqmeffVYJCQkFXr0CAAAAAFco1WGrKGbMmCEvLy/1799f2dnZiomJ0b///W/78nLlymnFihUaMWKEoqKi5O/vr7i4OE2aNMmNVQMAAAC41nlc2Prqq68cpn19fTV37lzNnTv3sutEREToi7LyKjYAAAAApUKpfmYLAAAAADwVYQsAAAAATEDYAgAAAAATELYAAAAAwASELQAAAAAwAWELAAAAAExA2AIAAAAAE3jc92wBcE7v3s6tt3y5a+sAAAAoK7iyBQAAAAAmIGwBAAAAgAkIWwAAAABgAsIWAAAAAJiAsAUAAAAAJiBsAQAAAIAJCFsAAAAAYALCFgAAAACYgLAFAAAAACYgbAEAAACACQhbAAAAAGACwhYAAAAAmICwBQAAAAAmIGwBAAAAgAkIWwAAAABgAsIWAAAAAJiAsAUAAAAAJiBsAQAAAIAJCFsAAAAAYALCFgAAAACYgLAFAAAAACYgbAEAAACACQhbAAAAAGACwhYAAAAAmICwBQAAAAAmIGwBAAAAgAkIWwAAAABgAsIWAAAAAJiAsAUAAAAAJiBsAQAAAIAJCFsAAAAAYALCFgAAAACYgLAFAAAAACYgbAEAAACACQhbAAAAAGACwhYAAAAAmICwBQAAAAAmIGwBAAAAgAkIWwAAAABgAsIWAAAAAJiAsAUAAAAAJiBsAQAAAIAJCFsAAAAAYALCFgAAAACYgLAFAAAAACYgbAEAAACACQhbAAAAAGACwhYAAAAAmICwBQAAAAAmIGwBAAAAgAkIWwAAAABgAsIWAAAAAJiAsAUAAAAAJijVYWvKlCm66aabFBAQoOrVq6tv377at2+fw5hz584pISFBVapUUcWKFdW/f3+lpaU5jElJSVGvXr1UoUIFVa9eXU888YQuXLhQkocCAAAAoIwp1WFrw4YNSkhI0HfffaekpCTZbDZ169ZNWVlZ9jGjRo3S8uXLtWTJEm3YsEFHjx7VnXfeaV+ek5OjXr166fz589q0aZPefvttLViwQOPHj3fHIQEAAAAoI8q7u4DCrFq1ymF6wYIFql69unbs2KGOHTvq9OnT+t///qdFixbptttukyTNnz9fjRs31nfffaebb75Zq1ev1o8//qg1a9YoJCRELVu21PPPP6+nnnpKEyZMkLe3d779ZmdnKzs72z6dkZEhSbLZbLLZbC45trztOLs9q9UlZeAKrFabw3/LIhf9kTfd1Z5TKBn0yXPQK89AnzwHvfIMRelTcXpoMQzDuOqqSsjBgwfVoEED7dmzR02bNtW6devUpUsX/fXXXwoKCrKPi4iI0MiRIzVq1CiNHz9ey5YtU3Jysn354cOHVbduXe3cuVM33HBDvv1MmDBBEydOzDd/0aJFqlChghmHBgAAAMADnD17VoMGDdLp06cVGBhY6NhSfWXrn3JzczVy5Ei1a9dOTZs2lSSlpqbK29vbIWhJUkhIiFJTU+1jQkJC8i3PW1aQsWPHavTo0fbpjIwM1apVS926dbviB1pUNptNSUlJ6tq1q6xOXKYaMMAlZeAKrFabBg1K0qJFXWWzlc3LiYsXu7uCornacwolgz55DnrlGeiT56BXnqEofcq7660oPCZsJSQk6IcfftA333xj+r58fHzk4+OTb77VanX5yeHsNrkCXbJsNmuZDVue9veBGecpXI8+eQ565Rnok+egV56hsD4Vp3+l+gUZeRITE7VixQqtX79eNWvWtM8PDQ3V+fPnderUKYfxaWlpCg0NtY+59O2EedN5YwAAAADA1Up12DIMQ4mJifr000+1bt06RUZGOixv1aqVrFar1q5da5+3b98+paSkKCoqSpIUFRWlPXv2KD093T4mKSlJgYGBatKkSckcCAAAAIAyp1TfRpiQkKBFixbps88+U0BAgP0Zq0qVKsnPz0+VKlVSfHy8Ro8ereDgYAUGBuqRRx5RVFSUbr75ZklSt27d1KRJE91///2aOnWqUlNT9eyzzyohIaHAWwUBAAAAwBVKddh6/fXXJUmdO3d2mD9//nwNGTJEkjRjxgx5eXmpf//+ys7OVkxMjP7973/bx5YrV04rVqzQiBEjFBUVJX9/f8XFxWnSpEkldRgAAAAAyqBSHbaK8lZ6X19fzZ07V3Pnzr3smIiICH3xxReuLA0AAAAAClWqn9kCAAAAAE9F2AIAAAAAExC2AAAAAMAEhC0AAAAAMAFhCwAAAABMQNgCAAAAABMQtgAAAADABIQtAAAAADABYQsAAAAATEDYAgAAAAATlHd3AQAAAADKjt69nVtv+XLX1lESuLIFAAAAACYgbAEAAACACQhbAAAAAGACwhYAAAAAmICwBQAAAAAmIGwBAAAAgAkIWwAAAABgAsIWAAAAAJiAsAUAAAAAJiBsAQAAAIAJCFsAAAAAYALCFgAAAACYgLAFAAAAACYgbAEAAACACQhbAAAAAGACwhYAAAAAmICwBQAAAAAmIGwBAAAAgAkIWwAAAABgAsIWAAAAAJiAsAUAAAAAJiBsAQAAAIAJCFsAAAAAYALCFgAAAACYgLAFAAAAACYo7+4CAABA2dW7t/PrLl/uujoAwAxc2QIAAAAAE3BlC0Cp4uz/5f7kE9fWAQAAcLW4sgUAAAAAJiBsAQAAAIAJCFsAAAAAYALCFgAAAACYgLAFAAAAACYgbAEAAACACQhbAAAAAGACvmcLAACgFCrK9w5arVJcnDRggGSzXZy3fLm5dQEoOsIWgEI5+yXD/GUPAADKOsIWAACAiZz9n1YAPB9hCwAAACgEd3nAWbwgAwAAAABMQNgCAAAAABMQtgAAAADABIQtAAAAADABL8gAYArevgUAAMo6rmwBAAAAgAm4sgUAKJN4lTOuVfzZBkoPrmwBAAAAgAkIWwAAAABgAsIWAAAAAJigTD2zNXfuXL3yyitKTU1VixYtNGfOHLVp08bdZQHANaWw50WsVikuThowQLLZHJfxvAiKq6TfesqfUQDFVWbC1uLFizV69GjNmzdPbdu21cyZMxUTE6N9+/apevXq7i4PAOAh+Ad+2cVXWpQOvADk8vhsSp8yE7amT5+uYcOGaejQoZKkefPm6fPPP9dbb72lp59+2s3VAbhaAwZc/oqJGfiLqfTgH8AAisIdPyv+uc/CruxfqqT/juHnqHnKRNg6f/68duzYobFjx9rneXl5KTo6Wps3b843Pjs7W9nZ2fbp06dPS5JOnjwpm4v+FWez2XT27FmdOHFCVqvVJduEGS72STohiT6VbiXbq5L+i2nBgpLdn3ku3yf+si/YiRPOrTdkyNXt12q16e67z2rAgBOy2fj5V3q57mcf56DZit4relEwZ38eFkdR/o1+5swZSZJhGFfcnsUoyigPd/ToUdWoUUObNm1SVFSUff6TTz6pDRs2aMuWLQ7jJ0yYoIkTJ5Z0mQAAAAA8xG+//aaaNWsWOqZMXNkqrrFjx2r06NH26dzcXJ08eVJVqlSRxWJxyT4yMjJUq1Yt/fbbbwoMDHTJNuF69Mlz0CvPQJ88B73yDPTJc9Arz1CUPhmGoTNnzig8PPyK2ysTYatq1aoqV66c0tLSHOanpaUpNDQ033gfHx/5+Pg4zAsKCjKltsDAQE44D0CfPAe98gz0yXPQK89AnzwHvfIMV+pTpUqVirSdMvE9W97e3mrVqpXWrl1rn5ebm6u1a9c63FYIAAAAAK5SJq5sSdLo0aMVFxen1q1bq02bNpo5c6aysrLsbycEAAAAAFcqM2FrwIABOn78uMaPH6/U1FS1bNlSq1atUkhIiFvq8fHx0XPPPZfvdkWULvTJc9Arz0CfPAe98gz0yXPQK8/g6j6VibcRAgAAAEBJKxPPbAEAAABASSNsAQAAAIAJCFsAAAAAYALCFgAAAACYgLDlBnPnzlWdOnXk6+urtm3bauvWre4uCZeYMGGCLBaLw69GjRq5uyxI2rhxo3r37q3w8HBZLBYtXbrUYblhGBo/frzCwsLk5+en6OhoHThwwD3FlmFX6tOQIUPynWPdu3d3T7Fl2JQpU3TTTTcpICBA1atXV9++fbVv3z6HMefOnVNCQoKqVKmiihUrqn///kpLS3NTxWVTUfrUuXPnfOfU//3f/7mp4rLr9ddfV/Pmze1fiBsVFaWVK1fal3M+lQ5X6pMrzyfCVglbvHixRo8ereeee047d+5UixYtFBMTo/T0dHeXhktcf/31OnbsmP3XN9984+6SICkrK0stWrTQ3LlzC1w+depUzZ49W/PmzdOWLVvk7++vmJgYnTt3roQrLduu1CdJ6t69u8M59v7775dghZCkDRs2KCEhQd99952SkpJks9nUrVs3ZWVl2ceMGjVKy5cv15IlS7RhwwYdPXpUd955pxurLnuK0idJGjZsmMM5NXXqVDdVXHbVrFlTL730knbs2KHt27frtttuU58+fbR3715JnE+lxZX6JLnwfDJQotq0aWMkJCTYp3Nycozw8HBjypQpbqwKl3ruueeMFi1auLsMXIEk49NPP7VP5+bmGqGhocYrr7xin3fq1CnDx8fHeP/9991QIQwjf58MwzDi4uKMPn36uKUeXF56erohydiwYYNhGBfPH6vVaixZssQ+5qeffjIkGZs3b3ZXmWXepX0yDMPo1KmT8dhjj7mvKFxW5cqVjf/+97+cT6VcXp8Mw7XnE1e2StD58+e1Y8cORUdH2+d5eXkpOjpamzdvdmNlKMiBAwcUHh6uunXrKjY2VikpKe4uCVdw+PBhpaamOpxjlSpVUtu2bTnHSqGvvvpK1atXV8OGDTVixAidOHHC3SWVeadPn5YkBQcHS5J27Nghm83mcE41atRItWvX5pxyo0v7lGfhwoWqWrWqmjZtqrFjx+rs2bPuKA//n5ycHH3wwQfKyspSVFQU51MpdWmf8rjqfCrvqkJxZX/++adycnIUEhLiMD8kJEQ///yzm6pCQdq2basFCxaoYcOGOnbsmCZOnKgOHTrohx9+UEBAgLvLw2WkpqZKUoHnWN4ylA7du3fXnXfeqcjISB06dEj/+te/1KNHD23evFnlypVzd3llUm5urkaOHKl27dqpadOmki6eU97e3goKCnIYyznlPgX1SZIGDRqkiIgIhYeHa/fu3Xrqqae0b98+ffLJJ26stmzas2ePoqKidO7cOVWsWFGffvqpmjRpouTkZM6nUuRyfZJcez4RtoAC9OjRw/775s2bq23btoqIiNCHH36o+Ph4N1YGXBsGDhxo/32zZs3UvHlz1atXT1999ZW6dOnixsrKroSEBP3www88n1rKXa5Pw4cPt/++WbNmCgsLU5cuXXTo0CHVq1evpMss0xo2bKjk5GSdPn1aH330keLi4rRhwwZ3l4VLXK5PTZo0cen5xG2EJahq1aoqV65cvrfOpKWlKTQ01E1VoSiCgoJ03XXX6eDBg+4uBYXIO484xzxP3bp1VbVqVc4xN0lMTNSKFSu0fv161axZ0z4/NDRU58+f16lTpxzGc065x+X6VJC2bdtKEueUG3h7e6t+/fpq1aqVpkyZohYtWmjWrFmcT6XM5fpUkKs5nwhbJcjb21utWrXS2rVr7fNyc3O1du1ah3tEUfpkZmbq0KFDCgsLc3cpKERkZKRCQ0MdzrGMjAxt2bKFc6yU+/3333XixAnOsRJmGIYSExP16aefat26dYqMjHRY3qpVK1mtVodzat++fUpJSeGcKkFX6lNBkpOTJYlzqhTIzc1VdnY251Mpl9englzN+cRthCVs9OjRiouLU+vWrdWmTRvNnDlTWVlZGjp0qLtLwz+MGTNGvXv3VkREhI4eParnnntO5cqV07333uvu0sq8zMxMh/+zdPjwYSUnJys4OFi1a9fWyJEj9cILL6hBgwaKjIzUuHHjFB4err59+7qv6DKosD4FBwdr4sSJ6t+/v0JDQ3Xo0CE9+eSTql+/vmJiYtxYddmTkJCgRYsW6bPPPlNAQID9uZFKlSrJz89PlSpVUnx8vEaPHq3g4GAFBgbqkUceUVRUlG6++WY3V192XKlPhw4d0qJFi9SzZ09VqVJFu3fv1qhRo9SxY0c1b97czdWXLWPHjlWPHj1Uu3ZtnTlzRosWLdJXX32lL7/8kvOpFCmsTy4/n1zyTkMUy5w5c4zatWsb3t7eRps2bYzvvvvO3SXhEgMGDDDCwsIMb29vo0aNGsaAAQOMgwcPurssGIaxfv16Q1K+X3FxcYZhXHz9+7hx44yQkBDDx8fH6NKli7Fv3z73Fl0GFdans2fPGt26dTOqVatmWK1WIyIiwhg2bJiRmprq7rLLnIJ6JMmYP3++fczff/9tPPzww0blypWNChUqGP369TOOHTvmvqLLoCv1KSUlxejYsaMRHBxs+Pj4GPXr1zeeeOIJ4/Tp0+4tvAx64IEHjIiICMPb29uoVq2a0aVLF2P16tX25ZxPpUNhfXL1+WQxDMO4mmQIAAAAAMiPZ7YAAAAAwASELQAAAAAwAWELAAAAAExA2AIAAAAAExC2AAAAAMAEhC0AAAAAMAFhCwAAAABMQNgCAAAAABMQtgAA14Q6depo5syZ7i4DAAA7whYAoFQZMmSILBaLLBaLvL29Vb9+fU2aNEkXLlwodL1t27Zp+PDhptW1YMECe11eXl4KCwvTgAEDlJKSYto+AQCejbAFACh1unfvrmPHjunAgQN6/PHHNWHCBL3yyisFjj1//rwkqVq1aqpQoYKpdQUGBurYsWP6448/9PHHH2vfvn26++67Td0nAMBzEbYAAKWOj4+PQkNDFRERoREjRig6OlrLli2TdPHKV9++ffXiiy8qPDxcDRs2lJT/NsJTp07poYceUkhIiHx9fdW0aVOtWLHCvvybb75Rhw4d5Ofnp1q1aunRRx9VVlZWoXVZLBaFhoYqLCxMt9xyi+Lj47V161ZlZGTYxzz11FO67rrrVKFCBdWtW1fjxo2TzWazL58wYYJatmypd999V3Xq1FGlSpU0cOBAnTlzxj7mzJkzio2Nlb+/v8LCwjRjxgx17txZI0eOtI/Jzs7WmDFjVKNGDfn7+6tt27b66quvnPm4AQAmIWwBAEo9Pz8/+xUsSVq7dq327dunpKQkhwCVJzc3Vz169NC3336r9957Tz/++KNeeukllStXTpJ06NAhde/eXf3799fu3bu1ePFiffPNN0pMTCxyTenp6fr0009Vrlw5+3YlKSAgQAsWLNCPP/6oWbNm6T//+Y9mzJjhsO6hQ4e0dOlSrVixQitWrNCGDRv00ksv2ZePHj1a3377rZYtW6akpCR9/fXX2rlzp8M2EhMTtXnzZn3wwQfavXu37r77bnXv3l0HDhwo8jEAAMxV3t0FAABwOYZhaO3atfryyy/1yCOP2Of7+/vrv//9r7y9vQtcb82aNdq6dat++uknXXfddZKkunXr2pdPmTJFsbGx9itFDRo00OzZs9WpUye9/vrr8vX1LXC7p0+fVsWKFWUYhs6ePStJevTRR+Xv728f8+yzz9p/X6dOHY0ZM0YffPCBnnzySfv83NxcLViwQAEBAZKk+++/X2vXrtWLL76oM2fO6O2339aiRYvUpUsXSdL8+fMVHh5uXz8lJUXz589XSkqKff6YMWO0atUqzZ8/X5MnT77CJwsAKAmELQBAqbNixQpVrFhRNptNubm5GjRokCZMmGBf3qxZs8sGLUlKTk5WzZo17UHrUrt27dLu3bu1cOFC+zzDMJSbm6vDhw+rcePGBa4XEBCgnTt3ymazaeXKlVq4cKFefPFFhzGLFy/W7NmzdejQIWVmZurChQsKDAx0GFOnTh170JKksLAwpaenS5J++eUX2Ww2tWnTxr68UqVK9tslJWnPnj3KycnJd3zZ2dmqUqXKZT8XAEDJImwBAEqdW2+9Va+//rq8vb0VHh6u8uUd/7r655Wkgvj5+RW6PDMzUw899JAeffTRfMtq16592fW8vLxUv359SVLjxo116NAhjRgxQu+++64kafPmzYqNjdXEiRMVExOjSpUq6YMPPtC0adMctmO1Wh2mLRaLcnNzC6350vrLlSunHTt2ONzCKEkVK1Ys8nYAAOYibAEASh1/f397qHFG8+bN9fvvv2v//v0FXt268cYb9eOPP17VPiTp6aefVr169TRq1CjdeOON2rRpkyIiIvTMM8/Yxxw5cqRY26xbt66sVqu2bdtmD36nT5/W/v371bFjR0nSDTfcoJycHKWnp6tDhw5XdQwAAPPwggwAwDWnU6dO6tixo/r376+kpCQdPnxYK1eu1KpVqyRdfGPgpk2blJiYqOTkZB04cECfffZZsV6QIUm1atVSv379NH78eEkXn/1KSUnRBx98oEOHDmn27Nn69NNPi7XNgIAAxcXF6YknntD69eu1d+9excfHy8vLSxaLRZJ03XXXKTY2VoMHD9Ynn3yiw4cPa+vWrZoyZYo+//zzYu0PAGAewhYA4Jr08ccf66abbtK9996rJk2a6Mknn1ROTo6ki1e+NmzYoP3796tDhw664YYbNH78eIeXUBTVqFGj9Pnnn2vr1q264447NGrUKCUmJqply5batGmTxo0bV+xtTp8+XVFRUbr99tsVHR2tdu3aqXHjxg4v7pg/f74GDx6sxx9/XA0bNlTfvn0droYBANzPYhiG4e4iAADA5WVlZalGjRqaNm2a4uPj3V0OAKCIeGYLAIBS5vvvv9fPP/+sNm3a6PTp05o0aZIkqU+fPm6uDABQHIQtAABKoVdffVX79u2Tt7e3WrVqpa+//lpVq1Z1d1kAgGLgNkIAAAAAMAEvyAAAAAAAExC2AAAAAMAEhC0AAAAAMAFhCwAAAABMQNgCAAAAABMQtgAAAADABIQtAAAAADABYQsAAAAATPD/AKj1Ta49MNZKAAAAAElFTkSuQmCC" }, "metadata": {}, "output_type": "display_data" @@ -141,19 +141,19 @@ "metadata": { "collapsed": false, "ExecuteTime": { - "end_time": "2024-04-11T21:15:49.347509Z", - "start_time": "2024-04-11T21:15:49.262675Z" + "end_time": "2024-04-18T22:03:04.360281Z", + "start_time": "2024-04-18T22:03:04.258530Z" } } }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 16, "outputs": [ { "data": { "text/plain": "
", - "image/png": "iVBORw0KGgoAAAANSUhEUgAABIQAAAJwCAYAAAD4AboDAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/H5lhTAAAACXBIWXMAAA9hAAAPYQGoP6dpAAEAAElEQVR4nOzdeXgT1foH8G+aLlAKZZG9ZRFwQ3BBUMAquIDiUgy44IJcl6sCCqLwA+/iLsqOV/EqXkVxQcFQrooKKmCviqCCF/WqgCBQKCBLS6F0SfL74zhknzkzmaSZzPfzPH2aTM9MTttMZuad97zH4fP5fCAiIiIiIiIiIttIq+sOEBERERERERFRYjEgRERERERERERkMwwIERERERERERHZDANCREREREREREQ2w4AQEREREREREZHNMCBERERERERERGQzDAgREREREREREdkMA0JERERERERERDbDgBARERERERERkc0wIERERES6jBgxAh06dKjrbpDFPPTQQ3A4HHXdDSIiIvoDA0JEREQ2Mm/ePDgcjmNf9erVwwknnIDRo0dj9+7ddd29qEL7nZ6ejrZt22LEiBEoKSmp6+6Z7vPPP8dVV12Fli1bIisrCx06dMAdd9yBbdu21XXXgnTo0CHo/xLta968eXXdVSIiIgrh8Pl8vrruBBERESXGvHnz8Kc//QmPPPIIOnbsiKNHj+I///kP5s+fj/bt2+P7779Hdna26jZqamrg9XqRlZWVoF5H7vfq1asxb948dOjQAd9//z3q1auXsP7E0z/+8Q+MGTMGxx9/PEaMGIHWrVvjf//7H1588UUAwNKlS9GnT5867qVQVFSEioqKY8+XLl2KN998EzNnzsRxxx13bHmfPn3Qrl071NbWpsz/iYiIyOrS67oDRERElHiXXnopzjrrLADAbbfdhmbNmmHGjBlYsmQJhg0bFnGdw4cPo0GDBsjIyEhkV4OE9vu4447DU089hX//+9+45ppr6qxfZvn8888xduxYnHvuufjwww+DgnN33XUX+vbti6FDh+KHH35AkyZNEtYv5X8favDgwUHPS0tL8eabb2Lw4MERhxWmp/PUk4iIKFlwyBgRERHhggsuAABs2bIFgKgTlJOTg82bN2PQoEFo2LAhbrjhhmM/C73Y93q9mD17Nrp164Z69eqhefPmuOSSS/D1118HtXvttdfQo0cP1K9fH02bNsV1112H7du3G+53QUEBAGDz5s3HllVXV+Pvf/87evTogdzcXDRo0AAFBQVYsWJF0Lpbt26Fw+HAtGnT8MILL6BTp07IyspCz549sXbt2rDXWrhwIU455RTUq1cPp556KhYvXhz1bzFr1ix07doV9erVQ8uWLXHHHXfgwIEDmr/Po48+CofDgVdeeSUsU6tTp06YMmUKdu3aheeffx4AMG3aNDgcDvz2229h25o0aRIyMzODXverr77CJZdcgtzcXGRnZ+P888/H559/HrSeUuvnxx9/xPXXX48mTZrg3HPP1ey7lkg1hBwOB0aPHn3sb1u/fn307t0bGzZsAAA8//zz6Ny5M+rVq4d+/fph69atYduV+Z2IiIgoHANCREREdCyg0qxZs2PLamtrMXDgQLRo0QLTpk3DkCFDoq5/6623YuzYscjPz8dTTz2FiRMnol69eli9evWxNo8//jiGDx+OLl26YMaMGRg7diw++eQTnHfeeTh48KChfisBgsBsmfLycrz44ovo168fnnrqKTz00EPYu3cvBg4ciPXr14dt44033sDUqVNxxx134LHHHsPWrVvhcrlQU1NzrM3777+Pa6+9FhkZGZg8eTJcLhduvfVWfPPNN2Hbu+OOOzB+/Hj07dsXs2fPxp/+9Ce8/vrrGDhwYNA2Qx05cgSffPIJCgoK0LFjx4htrr32WmRlZeG9994DAFxzzTVwOBx4++23w9q+/fbbGDBgwLG/zaefforzzjsP5eXlePDBB/HEE0/g4MGDuOCCC7BmzZqw9a+++mocOXIETzzxBG6//fao/Y5VcXEx7rvvPtx888146KGH8L///Q+XX345nn32WTz99NMYOXIkxo8fjy+//BK33HJL0Lp6fyciIiIK4CMiIiLbePnll30AfB9//LFv7969vu3bt/sWLFjga9asma9+/fq+HTt2+Hw+n+/mm2/2AfBNnDgxbBs333yzr3379seef/rppz4AvnvuuSesrdfr9fl8Pt/WrVt9TqfT9/jjjwf9fMOGDb709PSw5TL9XrRoka958+a+rKws3/bt24+1ra2t9VVVVQWtf+DAAV/Lli19t9xyy7FlW7Zs8QHwNWvWzLd///5jy5csWeID4Hv33XePLevWrZsvLy/Pd+jQoWPLVq5c6QMQ9LcoLi72AfC9/vrrQa//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v/wl4lAyQAwb+/jjj9GwYUMMGjQo7Of9+vXDl19+iUcffRTPPPMMKioq0KpVK5x99tlhGUdWkYq/ExERUaI4fEYqJhIRERERTj/9dDRv3hzLly+v664QERER6cIaQkREREQaampqUFtbG7Rs5cqV+O6779CvX7+66RQRERFRDJghRERERKRh69atuOiii3DjjTeiTZs2+Omnn/DPf/4Tubm5+P7779GsWbO67iIRERGRLqwhRERERKShSZMm6NGjB1588UXs3bsXDRo0wGWXXYYnn3ySwSAiIiKyJGYIERERERERERHZDGsIERERERERERHZDANCREREREREREQ2Y7saQl6vFzt37kTDhg3hcDjqujtERERERERERKbw+Xw4dOgQ2rRpg7Q09Rwg2wWEdu7cifz8/LruBhERERERERFRXGzfvh15eXmqbWwXEGrYsCEA8cdp1KhRHffGuJqaGixbtgwDBgxARkZGXXeHKClwvyAKx/2CKBz3C6Jw3C+IwllxvygvL0d+fv6x2Ica2wWElGFijRo1snxAKDs7G40aNbLMG5Mo3rhfEIXjfkEUjvsFUTjuF0ThrLxfyJTIYVFpIiIiIiIiIiKbYUCIiIiIiIiIiMhmGBAiIiIiIiIiIrIZBoSIiIiIiIiIiGyGASEiIiIiIiIiIpthQIiIiIiIiIiIyGYYECIiIiIiIiIishkGhIiIiIiIiIiIbIYBISIiIiIiIiIim2FAiIiIiIiIiIjIZhgQIiIiIiIiIiKyGQaEiIiIiIiIiIhshgEhIiIiIiIiIiKbYUCIiIiIiIiIiMhmGBAiIiIiIiIiIrIZBoSIiIiIiIiIiGyGASEiIiIiIhsrKwPOPhvIzBRf55wjlhERUWpLr+sOEBERERFR3ejcGdi8OXjZV18BjRsDnToBmzbVSbeIiCgBmCFERERERGRDkYJBgTZvFm2IiCg1MSBERERERGQzZWXqwSDF5s0cPkZElKoYECIiIiIispnLLotPWyIisg4GhIiIiIiIbGbbtvi0JSIi62BAiIiIiIjIZtq1i09bIiKyDgaEiIiIiIhs5v3349OWiIisgwEhIiIiIiKbyc0V08pr6dRJtCUiotTDgBARERERkQ1t2qQeFOrUSbQhIqLUxIAQEREREZFNbdoEHDwYvOzss8UyBoOIiFJbel13gIiIiIiI6k7okLDV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w4fry5Yt01977TW9qKhIf/rpp1P6eQlChAceeEBv0aKF/t577+mrVq3S33zzTb1Ro0b6Y489tq8MtQsiF5g2bZp+xx136GVlZToA/e233054P1Xt4PPPP9c1TdPHjRunf//99/qdd96p5+fn60uXLg38OxCFDEJZRq9evfRrr7123/NoNKq3bdtWf/DBB9NYK4IIhk2bNukA9E8++UTXdV2vqKjQ8/Pz9TfffHNfmR9++EEHoH/55Ze6rrMBIBwO6+Xl5fvK/Pvf/9abNGmi7927V9d1XR8zZox++OGHJ1zrwgsv1E8//fSgPxJBeGbnzp36gQceqM+cOVM/6aST9hmEqF0Qucitt96q9+3b1/b9WCyml5aW6g899NC+1yoqKvTCwkL9tdde03Vd17///nsdgL5w4cJ9ZT744AM9FArp69ev13Vd15966im9WbNm+9oJv/bBBx+s+iMRhG8GDRqkX3nllQmvRSIRffjw4bquU7sgchOzQSiV7eCCCy7QBw0alFCf4447Tv/zn/+s9DP6gULGsoiamhosXrwYAwcO3PdaOBzGwIED8eWXX6axZgQRDJWVlQCA5s2bAwAWL16M2trahDZwyCGHoGPHjvvawJdffokjjzwSrVu33lfm9NNPx44dO/Ddd9/tK2M8By9D7YjIZK699loMGjQo6d6ldkHkIu+88w569OiB888/H/vttx+6deuGZ599dt/7q1atQnl5ecI93bRpUxx33HEJ7aKkpAQ9evTYV2bgwIEIh8OYP3/+vjInnngiCgoK9pU5/fTT8dNPP2H79u1Bf0yCkKJPnz6YNWsWfv75ZwDAN998g88++wxnnHEGAGoXBAGkth1kw9yKDEJZxJYtWxCNRhMm9ADQunVrlJeXp6lWBBEMsVgMN9xwA0444QQcccQRAIDy8nIUFBSgpKQkoayxDZSXl1u2Ef6eU5kdO3aguro6iI9DEL6YPHkyvvrqKzz44INJ71G7IHKRlStX4t///jcOPPBATJ8+HX/5y19w/fXX47///S+A+H3tNGcqLy/Hfvvtl/B+Xl4emjdvLtV2CCJTuO2223DRRRfhkEMOQX5+Prp164YbbrgBw4cPB0DtgiCA1LYDuzKZ1E7y0l0BgiAIK6699losW7YMn332WbqrQhBpZe3atRg1ahRmzpyJBg0apLs6BJERxGIx9OjRA//8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" + "image/png": "iVBORw0KGgoAAAANSUhEUgAABH8AAAJwCAYAAAAQrc1tAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/H5lhTAAAACXBIWXMAAA9hAAAPYQGoP6dpAAC5IklEQVR4nOzdeXxU1f3/8fdkskBYgqwJJCiCS1WsiqCoUVDAoiI04F632tZWbUFUqv1al7oWFaE/16rVuuBGI7gLbogLgihVu1iIIIsEQUogBLJM5vfH7ZBtlnvvnDtbXs/HIw8yM2fuPQm5M3fe95zP8QWDwaAAAAAAAACQkbKS3QEAAAAAAAB4h/AHAAAAAAAggxH+AAAAAAAAZDDCHwAAAAAAgAxG+AMAAAAAAJDBCH8AAAAAAAAyGOEPAAAAAABABiP8AQAAAAAAyGCEPwAAAAAAABmM8AcAAER0wQUXaK+99kp2N5BmbrjhBvl8vmR3AwAA/A/hDwAAGeqxxx6Tz+fb/dWhQwftu+++uuyyy7Rx48Zkdy+i1v3Ozs5Wv379dMEFF2j9+vXJ7p5xH3zwgX784x+rT58+ysvL01577aWLL75Ya9asSXbXWthrr71a/L9E+nrssceS3VUAANCKLxgMBpPdCQAAYN5jjz2mCy+8UH/4wx80YMAA7dq1S++//76eeOIJ7bnnnvryyy+Vn58fdRv19fVqbGxUXl5egnodvt+LFy/WY489pr322ktffvmlOnTokLD+eOn//b//p8mTJ2vvvffWBRdcoKKiIv3rX//Sww8/LEl69dVXddRRRyW5l5a5c+equrp69+1XX31VTz/9tO6++2717Nlz9/1HHXWU+vfvr4aGhoz5fwIAIN1lJ7sDAADAW2PHjtXhhx8uSfrZz36mHj16aMaMGZo3b57OOuussM/ZsWOHOnXqpJycnER2tYXW/e7Zs6f++Mc/6sUXX9Tpp5+etH6Z8sEHH2jKlCk65phj9Prrr7cI4n71q1/p6KOP1qRJk/SPf/xDe+yxR8L6Ffq/b23ChAktbldWVurpp5/WhAkTwk4NzM7mNBMAgFTBtC8AANqZ448/XpK0atUqSVZdn86dO6uiokInnXSSunTponPOOWf3Y60/2Dc2NmrWrFkaPHiwOnTooF69eulHP/qRPvnkkxbtnnzySQ0ZMkQdO3ZU9+7ddeaZZ2rt2rWu+11aWipJqqio2H1fXV2drrvuOg0ZMkQFBQXq1KmTSktL9c4777R47urVq+Xz+XTnnXfqz3/+swYOHKi8vDwNHTpUS5cubbOv559/XgcccIA6dOiggw46SC+88ELE38XMmTN14IEHqkOHDurTp48uvvhi/fe//43589x0003y+Xz661//2mYE1sCBAzV9+nRt2LBBDz74oCTpzjvvlM/n0zfffNNmW9dcc41yc3Nb7Pfjjz/Wj370IxUUFCg/P1/HHXecPvjggxbPC9Xm+ec//6mzzz5be+yxh4455piYfY8lXM0fn8+nyy67bPfvtmPHjho+fLi++OILSdKDDz6oQYMGqUOHDhoxYoRWr17dZrt2fiYAANAW4Q8AAO1MKDzp0aPH7vsaGhp04oknqnfv3rrzzjs1ceLEiM+/6KKLNGXKFJWUlOiPf/yjrr76anXo0EGLFy/e3eaWW27Reeedp3322UczZszQlClT9NZbb+nYY4/V1q1bXfU7FAY0HwWzbds2PfzwwxoxYoT++Mc/6oYbbtCmTZt04oknavny5W22MXv2bN1xxx26+OKLdfPNN2v16tUqKytTfX397javvPKKzjjjDOXk5Oi2225TWVmZLrroIi1btqzN9i6++GJdddVVOvroozVr1ixdeOGFeuqpp3TiiSe22GZrNTU1euutt1RaWqoBAwaEbXPGGWcoLy9PL7/8siTp9NNPl8/n03PPPdem7XPPPacxY8bs/t28/fbbOvbYY7Vt2zZdf/31uvXWW7V161Ydf/zxWrJkSZvnn3baaaqpqdGtt96qn//85xH7Ha9Fixbpiiuu0Pnnn68bbrhB//rXv3TKKafo3nvv1Z/+9Cddcskluuqqq/TRRx/ppz/9aYvnOv2ZAABAM0EAAJCRHn300aCk4JtvvhnctGlTcO3atcFnnnkm2KNHj2DHjh2D69atCwaDweD5558flBS8+uqr22zj/PPPD+655567b7/99ttBScHf/OY3bdo2NjYGg8FgcPXq1UG/3x+85ZZbWjz+xRdfBLOzs9vcb6ffc+bMCfbq1SuYl5cXXLt27e62DQ0Nwdra2hbP/+9//xvs06dP8Kc//enu+1atWhWUFOzRo0dwy5Ytu++fN29eUFLwpZde2n3f4MGDg8XFxcHt27fvvu/dd98NSmrxu1i0aFFQUvCpp55qsf/XX3897P3NLV++PCgpOHny5Ki/i4MPPjjYvXv33beHDx8eHDJkSIs2S5YsCUoKPv7448Fg0Pp/2GeffYInnnji7v+TYDAYrKmpCQ4YMCA4evTo3fddf/31QUnBs846K2o/wrnjjjuCkoKrVq1q81hou81JCubl5bVo/+CDDwYlBQsLC4Pbtm3bff8111zTYttOfiYAANAWI38AAMhwo0aNUq9evVRSUqIzzzxTnTt31gsvvKB+/fq1aPerX/0q5rb+9re/yefz6frrr2/zWGiaT3l5uRobG3X66adr8+bNu78KCwu1zz77tJmSZaffkyZNUqdOnfTiiy+quLh4dxu/36/c3FxJ1hSsLVu2qKGhQYcffrg+/fTTNts844wzWowcCk0l+/rrryVJ3377rb744gudd9556ty58+52xx13nAYPHtxiW88//7wKCgo0evToFj/nkCFD1Llz56g/5/bt2yVJXbp0ifo76NKli7Zt29ai/8uWLWsx9e3ZZ59VXl6exo8fL0lavny5VqxYobPPPlvff//97n7t2LFDJ5xwgt577z01Nja22M8vf/nLqP0w5YQTTmgxde6II46QJE2cOLHF7yJ0f+j/xc3PBAAAmlCJDwCADHfvvfdq3333VXZ2tvr06aP99ttPWVktr/9kZ2e3CFUiqaioUN++fdW9e/eIbVasWKFgMKh99tkn7ON2i0iH+l1VVaW//OUveu+998KuOvbXv/5Vd911l/7973+3mGoVbjpV//79W9wOBUGhWjmhejqDBg1q89xBgwa1CJRWrFihqqoq9e7dO2z/v/vuu4g/WyjoCIVAkWzfvr1FKHLaaadp6tSpevbZZ/W73/1OwWBQzz//vMaOHauuXbvu7pcknX/++RG3W1VV1SIEizT1zLTWv/+CggJJUklJSdj7Q/8vbn4mAADQhPAHAIAMN2zYsN2rZkWSl5fXJhByq7GxUT6fT6+99pr8fn+bx5uPqImmeb8nTJigY445Rmeffba++uqr3dt48skndcEFF2jChAm66qqr1Lt3b/n9ft12220tRseEhOuPJAWDQbs/3m6NjY3q3bu3nnrqqbCP9+rVK+JzBw0apOzsbH3++ecR29TW1uqrr75q8X/Xt29flZaW6rnnntPvfvc7LV68WGvWrNEf//jHFv2SpDvuuEOHHHJI2G23/j/o2LFjxH6YFOn3H+v/xc3PBAAAmhD+AAAA2wYOHKg33nhDW7ZsiTj6Z+DAgQoGgxowYID23XdfI/sNBTojR47UPffco6uvvlqSNGfOHO29994qLy9vsbpUuGlpduy5556SpJUrV7Z5rPV9AwcO1Jtvvqmjjz7acXjSqVMnjRw5Um+//ba++eab3ftt7rnnnlNtba1OOeWUFvefccYZuuSSS/TVV1/p2WefVX5+vsaNG9eiX5LUtWtXjRo1ylG/UlUm/kwAACQSNX8AAIBtEydOVDAY1I033tjmsdAojbKyMvn9ft14441tRtQEg0F9//33rvY9YsQIDRs2TDNnztSuXbskNY0Yab6fjz/+WB999JGrffTt21cHHXSQHn/8cVVXV+++f+HChbuXJA85/fTTFQgEdNNNN7XZTkNDQ8xVza699loFg0FdcMEF2rlzZ4vHVq1apWnTpqmoqEgXX3xxi8cmTpwov9+vp59+Ws8//7xOOeUUderUaffjQ4YM0cCBA3XnnXe2+BlCNm3aFLVfqSgTfyYAABKJkT8AAMC2kSNH6txzz9Wf/vQnrVixQj/60Y/U2NioRYsWaeTIkbrssss0cOBA3Xzzzbrmmmu0evVqTZgwQV26dNGqVav0wgsv6Be/+IWuvPJKV/u/6qqrdNppp+mxxx7TL3/5S51yyikqLy/Xj3/8Y5188slatWqVHnjgAR1wwAFhQwI7br31Vo0fP15HH320LrzwQv33v//VPffco4MOOqjFNo877jhdfPHFuu2227R8+XKNGTNGOTk5WrFihZ5//nnNmjVLkyZNirifY489VnfeeaemTp2qgw8+WBdccIGKior073//Ww899JAaGxv16quvtqlj07t3b40cOVIzZszQ9u3bdcYZZ7R4PCsrSw8//LDGjh2rAw88UBdeeKH69eun9evX65133lHXrl310ksvufrdJEsm/kwAACQS4Q8AAHDk0Ucf1cEHH6xHHnlEV111lQoKCnT44YfrqKOO2t3m6quv1r777qu777579yihkpISjRkzRqeeeqrrfZeVle0eAfLzn/9cF1xwgSorK/Xggw/qjTfe0AEHHKAnn3xSzz//vN59911X+xg3bpyefvpp3XDDDbr66qu1zz776LHHHtNf//pX/eMf/2jR9oEHHtCQIUP04IMP6ne/+52ys7O111576Sc/+YmOPvromPu6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" }, "metadata": {}, "output_type": "display_data" @@ -161,7 +161,7 @@ ], "source": [ "plt.figure(figsize=(14, 7))\n", - "plt.plot(range_analysis_df['Start_Index'], range_analysis_df['Price_Range'] * 100, marker='o', linestyle='-', color='blue')\n", + "plt.plot(range_analysis_df['Start_Index'], range_analysis_df['Price_Range_Pct'] * 100, marker='o', linestyle='-', color='blue')\n", "plt.title('Price Range Over Time')\n", "plt.xlabel('Index')\n", "plt.ylabel('Price Range')\n", @@ -171,8 +171,8 @@ "metadata": { "collapsed": false, "ExecuteTime": { - "end_time": "2024-04-11T21:15:35.060071Z", - "start_time": "2024-04-11T21:15:34.953227Z" + "end_time": "2024-04-18T22:03:34.608164Z", + "start_time": "2024-04-18T22:03:34.504796Z" } } }, diff --git a/quants_lab/strategy/directional_strategy_base.py b/quants_lab/strategy/directional_strategy_base.py deleted file mode 100644 index 224e5dc..0000000 --- a/quants_lab/strategy/directional_strategy_base.py +++ /dev/null @@ -1,94 +0,0 @@ -import os -from datetime import datetime -from typing import Optional, TypeVar, Generic -import pandas as pd -from pydantic import BaseModel - -from quants_lab.labeling.triple_barrier_method import triple_barrier_method - -ConfigType = TypeVar("ConfigType", bound=BaseModel) - - -class DirectionalStrategyBase(Generic[ConfigType]): - # TODO: - # * Add a data structure to request candles from CSV files as part of the config - # * Evaluate to move the get data outside the backtesting to optimize the performance. - def __init__(self, config: ConfigType): - self.config = config - - def get_data(self, start: Optional[str] = None, end: Optional[str] = None): - df = self.get_raw_data() - return self.filter_df_by_time(df, start, end) - - def get_raw_data(self): - raise NotImplemented - - def preprocessing(self, df): - raise NotImplemented - - def predict(self, df): - raise NotImplemented - - @staticmethod - def get_candles(exchange: str, trading_pair: str, interval: str) -> pd.DataFrame: - """ - Get a dataframe of market data from the database. - :param exchange: Exchange name - :param trading_pair: Trading pair - :param interval: Interval of the data - :return: Dataframe of market data - """ - script_dir = os.path.dirname(os.path.abspath(__file__)) - data_dir = os.path.join(script_dir, "../../data/candles") - filename = f"candles_{exchange}_{trading_pair.upper()}_{interval}.csv" - file_path = os.path.join(data_dir, filename) - if not os.path.exists(file_path): - raise FileNotFoundError(f"File '{file_path}' does not exist.") - df = pd.read_csv(file_path) - df["timestamp"] = pd.to_datetime(df["timestamp"], unit="ms") - return df - - @staticmethod - def filter_df_by_time(df, start: Optional[str] = None, end: Optional[str] = None): - if start is not None: - start_condition = df["timestamp"] >= datetime.strptime(start, "%Y-%m-%d") - else: - start_condition = pd.Series([True]*len(df)) - if end is not None: - end_condition = df["timestamp"] <= datetime.strptime(end, "%Y-%m-%d") - else: - end_condition = pd.Series([True]*len(df)) - return df[start_condition & end_condition] - - def run_backtesting(self, - take_profit_multiplier, stop_loss_multiplier, time_limit, - std_span, order_amount=100, leverage=20, initial_portfolio=1000, - taker_fee=0.0003, maker_fee=0.00012, - start: Optional[str] = None, end: Optional[str] = None): - df = self.get_data(start=start, end=end) - df = self.preprocessing(df) - df = self.predict(df) - df = triple_barrier_method( - df=df, - std_span=std_span, - tp=take_profit_multiplier, - sl=stop_loss_multiplier, - tl=time_limit, - trade_cost=taker_fee * 2, - max_executors=1, - ) - - first_row = df.iloc[0].tolist() - first_row.extend([0, 0, 0, 0, 0, initial_portfolio]) - active_signals = df[df["active_signal"] == 1].copy() - active_signals.loc[:, "amount"] = order_amount - active_signals.loc[:, "margin_used"] = order_amount / leverage - active_signals.loc[:, "fee_pct"] = active_signals["close_type"].apply( - lambda x: maker_fee + taker_fee if x == "tp" else taker_fee * 2) - active_signals.loc[:, "fee_usd"] = active_signals["fee_pct"] * active_signals["amount"] - active_signals.loc[:, "ret_usd"] = active_signals.apply(lambda x: (x["ret"] - x["fee_pct"]) * x["amount"], - axis=1) - active_signals.loc[:, "current_portfolio"] = initial_portfolio + active_signals["ret_usd"].cumsum() - active_signals.loc[:, "current_portfolio"].fillna(method='ffill', inplace=True) - positions = pd.concat([pd.DataFrame([first_row], columns=active_signals.columns), active_signals]) - return df, positions.reset_index(drop=True) diff --git a/utils/hummingbot_processes.py b/utils/hummingbot_processes.py index 7a8e501..4ceb001 100644 --- a/utils/hummingbot_processes.py +++ b/utils/hummingbot_processes.py @@ -18,7 +18,7 @@ async def aget_candles(connector_name: str, trading_pair: str, interval: str, ma candles.start() pbar = tqdm(total=candles._candles.maxlen) - while not candles.is_ready: + while not candles.ready: await asyncio.sleep(1) awaited_records = candles._candles.maxlen - len(candles._candles) pbar.update(candles._candles.maxlen - awaited_records - pbar.n) @@ -32,7 +32,7 @@ async def aget_candles(connector_name: str, trading_pair: str, interval: str, ma async def adownload_candles(connector_name: str, trading_pair: str, interval: str, max_records: int, download_path: str): candles = CandlesFactory.get_candle(CandlesConfig(connector_name, trading_pair, interval, max_records)) candles.start() - while not candles.is_ready: + while not candles.ready: print(f"Candles not ready yet! Missing {candles._candles.maxlen - len(candles._candles)}") await asyncio.sleep(1) df = candles.candles_df