diff --git a/.gitignore b/.gitignore index 33620176..9d7dcf48 100644 --- a/.gitignore +++ b/.gitignore @@ -134,4 +134,7 @@ dmypy.json # Optimize studies and strategies quants_lab/optimizations/* -quants_lab/strategy/experiments/* \ No newline at end of file +quants_lab/strategy/experiments/* + +# Master bot template user-added configs +hummingbot_files/templates/master_bot_conf/conf/* \ No newline at end of file diff --git a/constants.py b/constants.py index dcc0d452..bdb8830b 100644 --- a/constants.py +++ b/constants.py @@ -3,3 +3,4 @@ BOTS_FOLDER = "hummingbot_files/bot_configs" DIRECTIONAL_STRATEGIES_PATH = "quants_lab/strategy/experiments" OPTIMIZATIONS_PATH = "quants_lab/optimizations" +HUMMINGBOT_TEMPLATES = "hummingbot_files/templates" diff --git a/hummingbot_files/bot_configs/master_bot_conf/conf/.password_verification b/hummingbot_files/templates/master_bot_conf/conf/.password_verification similarity index 100% rename from hummingbot_files/bot_configs/master_bot_conf/conf/.password_verification rename to hummingbot_files/templates/master_bot_conf/conf/.password_verification diff --git a/hummingbot_files/bot_configs/master_bot_conf/conf/conf_client.yml b/hummingbot_files/templates/master_bot_conf/conf/conf_client.yml similarity index 98% rename from hummingbot_files/bot_configs/master_bot_conf/conf/conf_client.yml rename to hummingbot_files/templates/master_bot_conf/conf/conf_client.yml index f6ec3421..c50c793d 100644 --- a/hummingbot_files/bot_configs/master_bot_conf/conf/conf_client.yml +++ b/hummingbot_files/templates/master_bot_conf/conf/conf_client.yml @@ -2,7 +2,7 @@ ### client_config_map config ### #################################### -instance_id: 039758736d451914503a45ff596e168902d62557 +instance_id: hummingbot-master_bot_conf log_level: INFO @@ -67,42 +67,42 @@ pmm_script_mode: {} # 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: {} + ascend_ex_paper_trade: {} binance: {} - okx: {} - ciex: {} - bitmex: {} + binance_paper_trade: {} + binance_us: {} bitfinex: {} - probit: {} - kraken: {} - kucoin: {} bitmart: {} - bybit: {} + bitmex: {} + bitmex_testnet: {} bittrex: {} btc_markets: {} - mock_paper_exchange: {} + bybit: {} + bybit_testnet: {} + ciex: {} + coinbase_pro: {} + crypto_com: {} + foxbit: {} + gate_io: {} + gate_io_paper_trade: {} + hitbtc: {} + hotbit: {} + huobi: {} + kraken: {} + kucoin: {} kucoin_paper_trade: {} - ndax: {} + lbank: {} loopring: {} mexc: {} + mock_paper_exchange: {} + ndax: {} + ndax_testnet: {} + okx: {} + probit: {} + probit_kr: {} whitebit: {} - coinbase_pro: {} - binance_paper_trade: {} - gate_io: {} # Fixed gas price (in Gwei) for Ethereum transactions manual_gas_price: 50.0 @@ -162,14 +162,14 @@ paper_trade: - gate_io paper_trade_account_balance: BTC: 1.0 - USDT: 1000.0 + DAI: 1000.0 + ETH: 10.0 ONE: 1000.0 - USDQ: 1000.0 TUSD: 1000.0 - ETH: 10.0 - WETH: 10.0 USDC: 1000.0 - DAI: 1000.0 + USDQ: 1000.0 + USDT: 1000.0 + WETH: 10.0 color: top_pane: '#000000' diff --git a/hummingbot_files/bot_configs/master_bot_conf/conf/conf_fee_overrides.yml b/hummingbot_files/templates/master_bot_conf/conf/conf_fee_overrides.yml similarity index 96% rename from hummingbot_files/bot_configs/master_bot_conf/conf/conf_fee_overrides.yml rename to hummingbot_files/templates/master_bot_conf/conf/conf_fee_overrides.yml index 76512b13..3345de57 100644 --- a/hummingbot_files/bot_configs/master_bot_conf/conf/conf_fee_overrides.yml +++ b/hummingbot_files/templates/master_bot_conf/conf/conf_fee_overrides.yml @@ -302,3 +302,15 @@ 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: diff --git a/hummingbot_files/bot_configs/master_bot_conf/conf/hummingbot_logs.yml b/hummingbot_files/templates/master_bot_conf/conf/hummingbot_logs.yml similarity index 100% rename from hummingbot_files/bot_configs/master_bot_conf/conf/hummingbot_logs.yml rename to hummingbot_files/templates/master_bot_conf/conf/hummingbot_logs.yml diff --git a/hummingbot_files/bot_configs/master_bot_conf/conf_client.yml b/hummingbot_files/templates/master_bot_conf/conf_client.yml similarity index 100% rename from hummingbot_files/bot_configs/master_bot_conf/conf_client.yml rename to hummingbot_files/templates/master_bot_conf/conf_client.yml diff --git a/hummingbot_files/bot_configs/master_bot_conf/scripts/1overN_portfolio.py b/hummingbot_files/templates/master_bot_conf/scripts/1overN_portfolio.py similarity index 100% rename from hummingbot_files/bot_configs/master_bot_conf/scripts/1overN_portfolio.py rename to hummingbot_files/templates/master_bot_conf/scripts/1overN_portfolio.py diff --git a/hummingbot_files/bot_configs/master_bot_conf/scripts/adjusted_mid_price.py b/hummingbot_files/templates/master_bot_conf/scripts/adjusted_mid_price.py similarity index 100% rename from hummingbot_files/bot_configs/master_bot_conf/scripts/adjusted_mid_price.py rename to hummingbot_files/templates/master_bot_conf/scripts/adjusted_mid_price.py diff --git a/hummingbot_files/bot_configs/master_bot_conf/scripts/amm_data_feed_example.py b/hummingbot_files/templates/master_bot_conf/scripts/amm_data_feed_example.py similarity index 100% rename from hummingbot_files/bot_configs/master_bot_conf/scripts/amm_data_feed_example.py rename to hummingbot_files/templates/master_bot_conf/scripts/amm_data_feed_example.py diff --git a/hummingbot_files/bot_configs/master_bot_conf/scripts/amm_price_example.py b/hummingbot_files/templates/master_bot_conf/scripts/amm_price_example.py similarity index 100% rename from hummingbot_files/bot_configs/master_bot_conf/scripts/amm_price_example.py rename to hummingbot_files/templates/master_bot_conf/scripts/amm_price_example.py diff --git a/hummingbot_files/bot_configs/master_bot_conf/scripts/amm_trade_example.py b/hummingbot_files/templates/master_bot_conf/scripts/amm_trade_example.py similarity index 100% rename from hummingbot_files/bot_configs/master_bot_conf/scripts/amm_trade_example.py rename to hummingbot_files/templates/master_bot_conf/scripts/amm_trade_example.py diff --git a/hummingbot_files/bot_configs/master_bot_conf/scripts/backtest_mm_example.py b/hummingbot_files/templates/master_bot_conf/scripts/backtest_mm_example.py similarity index 100% rename from hummingbot_files/bot_configs/master_bot_conf/scripts/backtest_mm_example.py rename to hummingbot_files/templates/master_bot_conf/scripts/backtest_mm_example.py diff --git a/hummingbot_files/bot_configs/master_bot_conf/scripts/batch_order_update.py b/hummingbot_files/templates/master_bot_conf/scripts/batch_order_update.py similarity index 100% rename from hummingbot_files/bot_configs/master_bot_conf/scripts/batch_order_update.py rename to hummingbot_files/templates/master_bot_conf/scripts/batch_order_update.py diff --git a/hummingbot_files/bot_configs/master_bot_conf/scripts/batch_order_update_market_orders.py b/hummingbot_files/templates/master_bot_conf/scripts/batch_order_update_market_orders.py similarity index 100% rename from hummingbot_files/bot_configs/master_bot_conf/scripts/batch_order_update_market_orders.py rename to hummingbot_files/templates/master_bot_conf/scripts/batch_order_update_market_orders.py diff --git a/hummingbot_files/bot_configs/master_bot_conf/scripts/buy_dip_example.py b/hummingbot_files/templates/master_bot_conf/scripts/buy_dip_example.py similarity index 100% rename from hummingbot_files/bot_configs/master_bot_conf/scripts/buy_dip_example.py rename to hummingbot_files/templates/master_bot_conf/scripts/buy_dip_example.py diff --git a/hummingbot_files/bot_configs/master_bot_conf/scripts/buy_low_sell_high.py b/hummingbot_files/templates/master_bot_conf/scripts/buy_low_sell_high.py similarity index 100% rename from hummingbot_files/bot_configs/master_bot_conf/scripts/buy_low_sell_high.py rename to hummingbot_files/templates/master_bot_conf/scripts/buy_low_sell_high.py diff --git a/hummingbot_files/bot_configs/master_bot_conf/scripts/buy_only_three_times_example.py b/hummingbot_files/templates/master_bot_conf/scripts/buy_only_three_times_example.py similarity index 100% rename from hummingbot_files/bot_configs/master_bot_conf/scripts/buy_only_three_times_example.py rename to hummingbot_files/templates/master_bot_conf/scripts/buy_only_three_times_example.py diff --git a/hummingbot_files/bot_configs/master_bot_conf/scripts/candles_example.py b/hummingbot_files/templates/master_bot_conf/scripts/candles_example.py similarity index 100% rename from hummingbot_files/bot_configs/master_bot_conf/scripts/candles_example.py rename to hummingbot_files/templates/master_bot_conf/scripts/candles_example.py diff --git a/hummingbot_files/bot_configs/master_bot_conf/scripts/clob_example.py b/hummingbot_files/templates/master_bot_conf/scripts/clob_example.py similarity index 100% rename from hummingbot_files/bot_configs/master_bot_conf/scripts/clob_example.py rename to hummingbot_files/templates/master_bot_conf/scripts/clob_example.py diff --git a/hummingbot_files/bot_configs/master_bot_conf/scripts/dca_example.py b/hummingbot_files/templates/master_bot_conf/scripts/dca_example.py similarity index 100% rename from hummingbot_files/bot_configs/master_bot_conf/scripts/dca_example.py rename to hummingbot_files/templates/master_bot_conf/scripts/dca_example.py diff --git a/hummingbot_files/bot_configs/master_bot_conf/scripts/directional_strategy_bb_rsi_multi_timeframe.py b/hummingbot_files/templates/master_bot_conf/scripts/directional_strategy_bb_rsi_multi_timeframe.py similarity index 100% rename from hummingbot_files/bot_configs/master_bot_conf/scripts/directional_strategy_bb_rsi_multi_timeframe.py rename to hummingbot_files/templates/master_bot_conf/scripts/directional_strategy_bb_rsi_multi_timeframe.py diff --git a/hummingbot_files/bot_configs/master_bot_conf/scripts/directional_strategy_macd_bb.py b/hummingbot_files/templates/master_bot_conf/scripts/directional_strategy_macd_bb.py similarity index 100% rename from hummingbot_files/bot_configs/master_bot_conf/scripts/directional_strategy_macd_bb.py rename to hummingbot_files/templates/master_bot_conf/scripts/directional_strategy_macd_bb.py diff --git a/hummingbot_files/bot_configs/master_bot_conf/scripts/directional_strategy_rsi.py b/hummingbot_files/templates/master_bot_conf/scripts/directional_strategy_rsi.py similarity index 100% rename from hummingbot_files/bot_configs/master_bot_conf/scripts/directional_strategy_rsi.py rename to hummingbot_files/templates/master_bot_conf/scripts/directional_strategy_rsi.py diff --git a/hummingbot_files/bot_configs/master_bot_conf/scripts/directional_strategy_rsi_spot.py b/hummingbot_files/templates/master_bot_conf/scripts/directional_strategy_rsi_spot.py similarity index 100% rename from hummingbot_files/bot_configs/master_bot_conf/scripts/directional_strategy_rsi_spot.py rename to hummingbot_files/templates/master_bot_conf/scripts/directional_strategy_rsi_spot.py diff --git a/hummingbot_files/bot_configs/master_bot_conf/scripts/directional_strategy_stat_arb.py b/hummingbot_files/templates/master_bot_conf/scripts/directional_strategy_stat_arb.py similarity index 100% rename from hummingbot_files/bot_configs/master_bot_conf/scripts/directional_strategy_stat_arb.py rename to hummingbot_files/templates/master_bot_conf/scripts/directional_strategy_stat_arb.py diff --git a/hummingbot_files/bot_configs/master_bot_conf/scripts/directional_strategy_trend_follower.py b/hummingbot_files/templates/master_bot_conf/scripts/directional_strategy_trend_follower.py similarity index 100% rename from hummingbot_files/bot_configs/master_bot_conf/scripts/directional_strategy_trend_follower.py rename to hummingbot_files/templates/master_bot_conf/scripts/directional_strategy_trend_follower.py diff --git a/hummingbot_files/bot_configs/master_bot_conf/scripts/directional_strategy_widening_ema_bands.py b/hummingbot_files/templates/master_bot_conf/scripts/directional_strategy_widening_ema_bands.py similarity index 100% rename from hummingbot_files/bot_configs/master_bot_conf/scripts/directional_strategy_widening_ema_bands.py rename to hummingbot_files/templates/master_bot_conf/scripts/directional_strategy_widening_ema_bands.py diff --git a/hummingbot_files/bot_configs/master_bot_conf/scripts/download_candles.py b/hummingbot_files/templates/master_bot_conf/scripts/download_candles.py similarity index 100% rename from hummingbot_files/bot_configs/master_bot_conf/scripts/download_candles.py rename to hummingbot_files/templates/master_bot_conf/scripts/download_candles.py diff --git a/hummingbot_files/bot_configs/master_bot_conf/scripts/external_events_example.py b/hummingbot_files/templates/master_bot_conf/scripts/external_events_example.py similarity index 100% rename from hummingbot_files/bot_configs/master_bot_conf/scripts/external_events_example.py rename to hummingbot_files/templates/master_bot_conf/scripts/external_events_example.py diff --git a/hummingbot_files/bot_configs/master_bot_conf/scripts/format_status_example.py b/hummingbot_files/templates/master_bot_conf/scripts/format_status_example.py similarity index 100% rename from hummingbot_files/bot_configs/master_bot_conf/scripts/format_status_example.py rename to hummingbot_files/templates/master_bot_conf/scripts/format_status_example.py diff --git a/hummingbot_files/bot_configs/master_bot_conf/scripts/log_price_example.py b/hummingbot_files/templates/master_bot_conf/scripts/log_price_example.py similarity index 100% rename from hummingbot_files/bot_configs/master_bot_conf/scripts/log_price_example.py rename to hummingbot_files/templates/master_bot_conf/scripts/log_price_example.py diff --git a/hummingbot_files/bot_configs/master_bot_conf/scripts/macd_bb_directional_strategy.py b/hummingbot_files/templates/master_bot_conf/scripts/macd_bb_directional_strategy.py similarity index 100% rename from hummingbot_files/bot_configs/master_bot_conf/scripts/macd_bb_directional_strategy.py rename to hummingbot_files/templates/master_bot_conf/scripts/macd_bb_directional_strategy.py diff --git a/hummingbot_files/bot_configs/master_bot_conf/scripts/market_buy.py b/hummingbot_files/templates/master_bot_conf/scripts/market_buy.py similarity index 100% rename from hummingbot_files/bot_configs/master_bot_conf/scripts/market_buy.py rename to hummingbot_files/templates/master_bot_conf/scripts/market_buy.py diff --git a/hummingbot_files/bot_configs/master_bot_conf/scripts/microprice_calculator.py b/hummingbot_files/templates/master_bot_conf/scripts/microprice_calculator.py similarity index 100% rename from hummingbot_files/bot_configs/master_bot_conf/scripts/microprice_calculator.py rename to hummingbot_files/templates/master_bot_conf/scripts/microprice_calculator.py diff --git a/hummingbot_files/bot_configs/master_bot_conf/scripts/pmm_with_position_executor.py b/hummingbot_files/templates/master_bot_conf/scripts/pmm_with_position_executor.py similarity index 100% rename from hummingbot_files/bot_configs/master_bot_conf/scripts/pmm_with_position_executor.py rename to hummingbot_files/templates/master_bot_conf/scripts/pmm_with_position_executor.py diff --git a/hummingbot_files/bot_configs/master_bot_conf/scripts/pmm_with_shifted_mid_dynamic_spreads.py b/hummingbot_files/templates/master_bot_conf/scripts/pmm_with_shifted_mid_dynamic_spreads.py similarity index 100% rename from hummingbot_files/bot_configs/master_bot_conf/scripts/pmm_with_shifted_mid_dynamic_spreads.py rename to hummingbot_files/templates/master_bot_conf/scripts/pmm_with_shifted_mid_dynamic_spreads.py diff --git a/hummingbot_files/bot_configs/master_bot_conf/scripts/simple_arbitrage_example.py b/hummingbot_files/templates/master_bot_conf/scripts/simple_arbitrage_example.py similarity index 100% rename from hummingbot_files/bot_configs/master_bot_conf/scripts/simple_arbitrage_example.py rename to hummingbot_files/templates/master_bot_conf/scripts/simple_arbitrage_example.py diff --git a/hummingbot_files/bot_configs/master_bot_conf/scripts/simple_pmm_example.py b/hummingbot_files/templates/master_bot_conf/scripts/simple_pmm_example.py similarity index 100% rename from hummingbot_files/bot_configs/master_bot_conf/scripts/simple_pmm_example.py rename to hummingbot_files/templates/master_bot_conf/scripts/simple_pmm_example.py diff --git a/hummingbot_files/bot_configs/master_bot_conf/scripts/simple_rsi_example.py b/hummingbot_files/templates/master_bot_conf/scripts/simple_rsi_example.py similarity index 100% rename from hummingbot_files/bot_configs/master_bot_conf/scripts/simple_rsi_example.py rename to hummingbot_files/templates/master_bot_conf/scripts/simple_rsi_example.py diff --git a/hummingbot_files/bot_configs/master_bot_conf/scripts/simple_vwap_example.py b/hummingbot_files/templates/master_bot_conf/scripts/simple_vwap_example.py similarity index 100% rename from hummingbot_files/bot_configs/master_bot_conf/scripts/simple_vwap_example.py rename to hummingbot_files/templates/master_bot_conf/scripts/simple_vwap_example.py diff --git a/hummingbot_files/bot_configs/master_bot_conf/scripts/simple_xemm_example.py b/hummingbot_files/templates/master_bot_conf/scripts/simple_xemm_example.py similarity index 100% rename from hummingbot_files/bot_configs/master_bot_conf/scripts/simple_xemm_example.py rename to hummingbot_files/templates/master_bot_conf/scripts/simple_xemm_example.py diff --git a/hummingbot_files/bot_configs/master_bot_conf/scripts/spot_perp_arb.py b/hummingbot_files/templates/master_bot_conf/scripts/spot_perp_arb.py similarity index 100% rename from hummingbot_files/bot_configs/master_bot_conf/scripts/spot_perp_arb.py rename to hummingbot_files/templates/master_bot_conf/scripts/spot_perp_arb.py diff --git a/hummingbot_files/bot_configs/master_bot_conf/scripts/stat_arb.py b/hummingbot_files/templates/master_bot_conf/scripts/stat_arb.py similarity index 100% rename from hummingbot_files/bot_configs/master_bot_conf/scripts/stat_arb.py rename to hummingbot_files/templates/master_bot_conf/scripts/stat_arb.py diff --git a/hummingbot_files/bot_configs/master_bot_conf/scripts/triangular_arbitrage.py b/hummingbot_files/templates/master_bot_conf/scripts/triangular_arbitrage.py similarity index 100% rename from hummingbot_files/bot_configs/master_bot_conf/scripts/triangular_arbitrage.py rename to hummingbot_files/templates/master_bot_conf/scripts/triangular_arbitrage.py diff --git a/hummingbot_files/bot_configs/master_bot_conf/scripts/wallet_hedge_example.py b/hummingbot_files/templates/master_bot_conf/scripts/wallet_hedge_example.py similarity index 100% rename from hummingbot_files/bot_configs/master_bot_conf/scripts/wallet_hedge_example.py rename to hummingbot_files/templates/master_bot_conf/scripts/wallet_hedge_example.py diff --git a/main.py b/main.py index 98b2e6fc..bf8b1402 100644 --- a/main.py +++ b/main.py @@ -3,22 +3,23 @@ from utils.st_utils import initialize_st_page -initialize_st_page(title="Hummingbot Dashboard", icon="πŸ“Š") +initialize_st_page(title="Hummingbot Dashboard", icon="πŸ“Š", initial_sidebar_state="expanded") show_pages( [ Page("main.py", "Hummingbot Dashboard", "πŸ“Š"), Section("Bot Orchestration", "πŸ™"), - Page("pages/bot_orchestration/app.py", "Bots Manager", "πŸ¦…"), - Page("pages/file_manager/app.py", "File Manager", "πŸ—‚"), + Page("pages/master_conf/app.py", "Credentials", "πŸ—οΈ"), + Page("pages/bot_orchestration/app.py", "Instances", "πŸ¦…"), + Page("pages/file_manager/app.py", "Strategy Configs", "πŸ—‚"), Section("Backtest Manager", "βš™οΈ"), + Page("pages/candles_downloader/app.py", "Get Data", "πŸ’Ύ"), Page("pages/backtest_manager/create.py", "Create", "βš”οΈ"), Page("pages/backtest_manager/optimize.py", "Optimize", "πŸ§ͺ"), Page("pages/backtest_manager/analyze.py", "Analyze", "πŸ”¬"), Page("pages/backtest_manager/simulate.py", "Simulate", "πŸ“ˆ"), Section("Community Pages", "πŸ‘¨β€πŸ‘©β€πŸ‘§β€πŸ‘¦"), Page("pages/strategy_performance/app.py", "Strategy Performance", "πŸš€"), - Page("pages/candles_downloader/app.py", "Candles Downloader", "πŸ—‚"), 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", "πŸ¦‰"), diff --git a/pages/bot_orchestration/app.py b/pages/bot_orchestration/app.py index b378f560..8fbd1079 100644 --- a/pages/bot_orchestration/app.py +++ b/pages/bot_orchestration/app.py @@ -13,9 +13,11 @@ from ui_components.bot_performance_card import BotPerformanceCard from ui_components.dashboard import Dashboard from ui_components.exited_bot_card import ExitedBotCard +from ui_components.launch_bot_card import LaunchBotCard +from ui_components.launch_broker_card import LaunchBrokerCard from utils.st_utils import initialize_st_page -initialize_st_page(title="Bots Manager", icon="πŸ¦…", initial_sidebar_state="collapsed") +initialize_st_page(title="Instances", icon="πŸ¦…", initial_sidebar_state="collapsed") if "is_broker_running" not in st.session_state: st.session_state.is_broker_running = False @@ -36,31 +38,14 @@ st.session_state.editor_tabs = {} -def manage_broker_container(): - if st.session_state.is_broker_running: - docker_manager.stop_container("hummingbot-broker") - with st.spinner('Stopping Hummingbot Broker... you will not going to be able to manage bots anymore.'): - time.sleep(5) - else: - docker_manager.create_broker() - with st.spinner('Starting Hummingbot Broker... This process may take a few seconds'): - time.sleep(20) - - -def launch_new_bot(): - bot_name = f"hummingbot-{st.session_state.new_bot_name.target.value}" - docker_manager.create_hummingbot_instance(instance_name=bot_name, - base_conf_folder=f"{constants.BOTS_FOLDER}/master_bot_conf/.", - target_conf_folder=f"{constants.BOTS_FOLDER}/{bot_name}/.") - - def update_containers_info(docker_manager): active_containers = docker_manager.get_active_containers() st.session_state.is_broker_running = "hummingbot-broker" in active_containers if st.session_state.is_broker_running: try: active_hbot_containers = [container for container in active_containers if - "hummingbot-" in container and "broker" not in container] + "hummingbot-" in container and "broker" not in container + and "master_bot_conf" not in container] previous_active_bots = st.session_state.active_bots.keys() # Remove bots that are no longer active @@ -117,40 +102,25 @@ def get_grid_positions(n_cards: int, cols: int = NUM_CARD_COLS, card_width: int return sorted(x_y, key=lambda x: (x[1], x[0])) +if "create_containers_board" not in st.session_state: + board = Dashboard() + create_containers_board = SimpleNamespace( + dashboard=board, + launch_bot=LaunchBotCard(board, 0, 0, 8, 1.5), + launch_broker=LaunchBrokerCard(board, 8, 0, 4, 1.5) + ) + st.session_state.create_containers_board = create_containers_board + +else: + create_containers_board = st.session_state.create_containers_board + + with elements("create_bot"): - with mui.Grid(container=True, spacing=2): - with mui.Grid(item=True, xs=6): - with mui.Paper(style={"padding": "2rem"}, variant="outlined"): - with mui.Grid(container=True, spacing=2): - with mui.Grid(item=True, xs=12): - mui.Typography("πŸš€ Create Instance", variant="h5") - with mui.Grid(item=True, xs=8): - mui.TextField(label="Bot Name", variant="outlined", onChange=lazy(sync("new_bot_name")), - sx={"width": "100%"}) - with mui.Grid(item=True, xs=4): - with mui.Button(onClick=launch_new_bot, - variant="outlined", - color="success", - sx={"width": "100%", "height": "100%"}): - mui.icon.AddCircleOutline() - mui.Typography("Create") - with mui.Grid(item=True, xs=6): - with mui.Paper(style={"padding": "2rem"}, variant="outlined"): - with mui.Grid(container=True, spacing=2): - with mui.Grid(item=True, xs=12): - mui.Typography("πŸ™ Manage Broker", variant="h5") - with mui.Grid(item=True, xs=8): - mui.Typography("Hummingbot Broker helps you control and monitor your bot instances.") - with mui.Grid(item=True, xs=4): - button_text = "Stop" if st.session_state.is_broker_running else "Start" - color = "error" if st.session_state.is_broker_running else "success" - icon = mui.icon.Stop if st.session_state.is_broker_running else mui.icon.PlayCircle - with mui.Button(onClick=manage_broker_container, - color=color, - variant="outlined", - sx={"width": "100%", "height": "100%"}): - icon() - mui.Typography(button_text) + with mui.Paper(elevation=3, style={"padding": "2rem"}, spacing=[2, 2], container=True): + with create_containers_board.dashboard(): + create_containers_board.launch_bot() + create_containers_board.launch_broker() + with elements("active_instances_board"): with mui.Paper(sx={"padding": "2rem"}, variant="outlined"): diff --git a/pages/candles_downloader/app.py b/pages/candles_downloader/app.py index ecc11cfd..6c381fc1 100644 --- a/pages/candles_downloader/app.py +++ b/pages/candles_downloader/app.py @@ -10,7 +10,7 @@ from utils.st_utils import initialize_st_page -initialize_st_page(title="Candles Downloader", icon="πŸ—‚οΈ") +initialize_st_page(title="Get Data", icon="πŸ’Ύ", initial_sidebar_state="collapsed") # Start content here docker_manager = DockerManager() diff --git a/pages/file_manager/app.py b/pages/file_manager/app.py index 56c81806..059f4724 100644 --- a/pages/file_manager/app.py +++ b/pages/file_manager/app.py @@ -8,7 +8,7 @@ from utils.st_utils import initialize_st_page -initialize_st_page(title="File Manager", icon="πŸ—‚οΈ", initial_sidebar_state="collapsed") +initialize_st_page(title="Strategy Configs", icon="πŸ—‚οΈ", initial_sidebar_state="collapsed") if "fe_board" not in st.session_state: diff --git a/pages/master_conf/README.md b/pages/master_conf/README.md new file mode 100644 index 00000000..18f4d94f --- /dev/null +++ b/pages/master_conf/README.md @@ -0,0 +1,19 @@ +### Description + +This page helps you deploy and manage Hummingbot instances: + +- Starting and stopping Hummingbot Broker +- Creating, starting and stopping bot instances +- Managing strategy and script files that instances run +- Fetching status of running instances + +### Maintainers + +This page is maintained by Hummingbot Foundation as a template other pages: + +* [cardosfede](https://github.com/cardosfede) +* [fengtality](https://github.com/fengtality) + +### Wiki + +See the [wiki](https://github.com/hummingbot/dashboard/wiki/%F0%9F%90%99-Bot-Orchestration) for more information. \ No newline at end of file diff --git a/pages/master_conf/app.py b/pages/master_conf/app.py new file mode 100644 index 00000000..fe9f6292 --- /dev/null +++ b/pages/master_conf/app.py @@ -0,0 +1,48 @@ +import glob +import os +from types import SimpleNamespace +import streamlit as st +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 utils.st_utils import initialize_st_page + + +initialize_st_page(title="Credentials", icon="πŸ—οΈ", initial_sidebar_state="collapsed") + + +if "mc_board" not in st.session_state: + board = Dashboard() + mc_board = SimpleNamespace( + dashboard=board, + launch_master_bot=LaunchMasterBotCard(board, 0, 0, 12, 2), + file_explorer=MasterConfFileExplorer(board, 0, 4, 3, 7), + editor=Editor(board, 4, 4, 9, 7), + ) + st.session_state.mc_board = mc_board + +else: + mc_board = st.session_state.mc_board + +# Add new tabs +for tab_name, content in mc_board.file_explorer.tabs.items(): + if tab_name not in mc_board.editor.tabs: + mc_board.editor.add_tab(tab_name, content["content"], content["language"]) + +# Remove deleted tabs +for tab_name in list(mc_board.editor.tabs.keys()): + if tab_name not in mc_board.file_explorer.tabs: + mc_board.editor.remove_tab(tab_name) + + + +with elements("file_manager"): + with mui.Paper(elevation=3, style={"padding": "2rem"}, spacing=[2, 2], container=True): + with mc_board.dashboard(): + mc_board.launch_master_bot() + mc_board.file_explorer() + mc_board.editor() diff --git a/ui_components/bot_performance_card.py b/ui_components/bot_performance_card.py index 6b936021..e077c189 100644 --- a/ui_components/bot_performance_card.py +++ b/ui_components/bot_performance_card.py @@ -89,7 +89,7 @@ def __call__(self, bot_config: dict): mui.icon.DeleteForever() mui.Typography("Stop Instance") with mui.Grid(item=True, xs=6): - mui.TextField(disabled=True, - label="Attach to bot instance", + mui.TextField(InputProps={"readOnly": True}, + label="Attach to instance", value="docker attach " + bot_name, sx={"width": "100%"}) diff --git a/ui_components/editor.py b/ui_components/editor.py index 5e825ede..538560ae 100644 --- a/ui_components/editor.py +++ b/ui_components/editor.py @@ -60,7 +60,7 @@ def __call__(self): with mui.Grid(container=True, spacing=4, sx={"display": "flex", "alignItems": "center"}): with mui.Grid(item=True, xs=10, sx={"display": "flex", "alignItems": "center"}): mui.icon.Terminal() - mui.Typography("Editor") + mui.Typography("Editor", variant="h6", sx={"marginLeft": 1}) with mui.Tabs(value=self._index, onChange=self._change_tab, scrollButtons=True, variant="scrollable", sx={"flex": 1}): for label in self._tabs.keys(): diff --git a/ui_components/file_explorer_base.py b/ui_components/file_explorer_base.py index 066b5ced..22d1b85b 100644 --- a/ui_components/file_explorer_base.py +++ b/ui_components/file_explorer_base.py @@ -53,7 +53,7 @@ def __call__(self): with mui.Grid(container=True, spacing=4, sx={"display": "flex", "alignItems": "center"}): with mui.Grid(item=True, xs=6, sx={"display": "flex", "alignItems": "center"}): mui.icon.Folder() - mui.Typography("File Explorer") + mui.Typography("File Explorer", variant="h6", sx={"marginLeft": 1}) with mui.Grid(item=True, xs=6, sx={"display": "flex", "justifyContent": "flex-end"}): mui.IconButton(mui.icon.Delete, onClick=self.delete_file, sx={"mx": 1}) mui.IconButton(mui.icon.Edit, onClick=self.add_file_to_tab, sx={"mx": 1}) diff --git a/ui_components/launch_bot_card.py b/ui_components/launch_bot_card.py new file mode 100644 index 00000000..34d42dde --- /dev/null +++ b/ui_components/launch_bot_card.py @@ -0,0 +1,95 @@ +import os +import time + +from docker_manager import DockerManager +import streamlit as st +from streamlit_elements import mui, lazy + +import constants +from utils.os_utils import get_directories_from_directory +from .dashboard import Dashboard + + +class LaunchBotCard(Dashboard.Item): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.is_master_bot_running = False + self._bot_name = None + self._image_name = "hummingbot/hummingbot:latest" + self._base_bot_config = "master_bot_conf" + + def _set_bot_name(self, event): + self._bot_name = event.target.value + + def _set_image_name(self, event): + self._image_name = event.target.value + + def _set_base_bot_config(self, event): + self._base_bot_config = event.target.value + + def launch_new_bot(self): + if self._bot_name and self._image_name: + bot_name = f"hummingbot-{self._bot_name}" + DockerManager().create_hummingbot_instance(instance_name=bot_name, + base_conf_folder=f"{constants.HUMMINGBOT_TEMPLATES}/{self._base_bot_config}/.", + target_conf_folder=f"{constants.BOTS_FOLDER}/{bot_name}/.", + image=self._image_name) + with st.spinner('Starting Master Configs instance... This process may take a few seconds'): + time.sleep(3) + else: + st.warning("You need to define the bot name and image in order to create one.") + + def __call__(self): + active_containers = DockerManager.get_active_containers() + self.is_master_bot_running = "hummingbot-master_bot_conf" in active_containers + password_file_path = os.path.join(constants.HUMMINGBOT_TEMPLATES + "/master_bot_conf/conf", + '.password_verification') + is_master_password_set = os.path.isfile(password_file_path) + with mui.Paper(key=self._key, + sx={"display": "flex", "flexDirection": "column", "borderRadius": 3, "overflow": "hidden"}, + elevation=1): + with self.title_bar(padding="10px 15px 10px 15px", dark_switcher=False): + mui.Typography("πŸš€ Create Instance", variant="h5") + + with mui.Grid(container=True, spacing=2, sx={"padding": "10px 15px 10px 15px"}): + with mui.Grid(item=True, xs=8): + if not is_master_password_set: + base_warning = "You need to set a master password in order to use the dashboard." + if self.is_master_bot_running: + mui.Alert(f"{base_warning} The Master Configs instance is running." + f" Attach to it in Terminal to set the master password.", severity="success") + else: + mui.Alert(f"{base_warning} Master Configs instance isn't running. Start it and" + f" set the master password to continue.", severity="error") + else: + mui.Alert("The new instance will contain the credentials configured in the following base instance:", + severity="info") + with mui.Grid(item=True, xs=4): + master_configs = [conf.split("/")[-2] for conf in + get_directories_from_directory(constants.HUMMINGBOT_TEMPLATES) if + "bot_conf" in conf] + with mui.FormControl(variant="standard", sx={"width": "100%"}): + mui.FormHelperText("Base Configs") + with mui.Select(label="Base Configs", defaultValue=master_configs[0], + variant="standard", onChange=lazy(self._set_base_bot_config)): + for master_config in master_configs: + mui.MenuItem(master_config, value=master_config) + with mui.Grid(item=True, xs=4): + mui.TextField(label="Instance Name", variant="outlined", onChange=lazy(self._set_bot_name), + sx={"width": "100%"}) + with mui.Grid(item=True, xs=4): + mui.TextField(label="Hummingbot Image", + defaultValue="hummingbot/hummingbot:latest", + variant="outlined", + placeholder="hummingbot-[name]", + onChange=lazy(self._set_image_name), + sx={"width": "100%"}) + + with mui.Grid(item=True, xs=4): + with mui.Button(onClick=self.launch_new_bot, + variant="outlined", + color="success", + sx={"width": "100%", "height": "100%"}): + mui.icon.AddCircleOutline() + mui.Typography("Create") + diff --git a/ui_components/launch_broker_card.py b/ui_components/launch_broker_card.py new file mode 100644 index 00000000..c842583a --- /dev/null +++ b/ui_components/launch_broker_card.py @@ -0,0 +1,54 @@ +import os +import time + +from docker_manager import DockerManager +import streamlit as st +from streamlit_elements import mui, sync + +import constants +from .dashboard import Dashboard + + +class LaunchBrokerCard(Dashboard.Item): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.is_broker_running = False + + def manage_broker_container(self): + if self.is_broker_running: + DockerManager().stop_container("hummingbot-broker") + with st.spinner('Stopping Hummingbot Broker... This process may take a few seconds...'): + time.sleep(5) + else: + DockerManager().create_broker() + with st.spinner('Starting Hummingbot Broker... This process may take a few seconds...'): + time.sleep(20) + + def __call__(self): + active_containers = DockerManager.get_active_containers() + self.is_broker_running = "hummingbot-broker" in active_containers + with mui.Paper(key=self._key, + sx={"display": "flex", "flexDirection": "column", "borderRadius": 3, "overflow": "hidden"}, + elevation=1): + with self.title_bar(padding="10px 15px 10px 15px", dark_switcher=False): + mui.Typography("πŸ™ Manage Broker", variant="h5") + with mui.Grid(container=True, spacing=2, sx={"padding": "10px 15px 10px 15px"}): + with mui.Grid(item=True, xs=8): + if self.is_broker_running: + mui.Alert("Hummingbot Broker is running - control your bots now!", severity="success") + else: + mui.Alert("Hummingbot Broker is not running - start it to control your bots.", + severity="error") + + with mui.Grid(item=True, xs=4): + button_text = "Stop" if self.is_broker_running else "Start" + color = "error" if self.is_broker_running else "success" + icon = mui.icon.Stop if self.is_broker_running else mui.icon.PlayCircle + with mui.Button(onClick=self.manage_broker_container, + color=color, + variant="outlined", + sx={"width": "100%", "height": "100%"}): + icon() + mui.Typography(button_text) + + diff --git a/ui_components/launch_master_bot_card.py b/ui_components/launch_master_bot_card.py new file mode 100644 index 00000000..6b6d1e58 --- /dev/null +++ b/ui_components/launch_master_bot_card.py @@ -0,0 +1,78 @@ +import os +import time + +from docker_manager import DockerManager +import streamlit as st +from streamlit_elements import mui + +import constants +from .dashboard import Dashboard + + +class LaunchMasterBotCard(Dashboard.Item): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.is_master_bot_running = False + + def manage_master_bot_container(self): + if self.is_master_bot_running: + DockerManager().stop_container("hummingbot-master_bot_conf") + with st.spinner('Stopping Master Configs instance... This process may take a few seconds.'): + time.sleep(5) + else: + DockerManager().create_hummingbot_instance(instance_name="hummingbot-master_bot_conf", + base_conf_folder="hummingbot_files/templates/master_bot_conf/.", + target_conf_folder="hummingbot_files/templates/master_bot_conf/." + ) + with st.spinner('Starting Master Configs instance... This process may take a few seconds.'): + time.sleep(3) + + def __call__(self): + active_containers = DockerManager.get_active_containers() + self.is_master_bot_running = "hummingbot-master_bot_conf" in active_containers + password_file_path = os.path.join(constants.HUMMINGBOT_TEMPLATES + "/master_bot_conf/conf", + '.password_verification') + is_master_password_set = os.path.isfile(password_file_path) + with mui.Paper(key=self._key, + sx={"display": "flex", "flexDirection": "column", "borderRadius": 3, "overflow": "hidden"}, + elevation=1): + with self.title_bar(padding="10px 15px 10px 15px", dark_switcher=False): + mui.icon.Key() + mui.Typography("Master Configs", variant="h6", sx={"marginLeft": 1}) + + with mui.Grid(container=True, spacing=2, sx={"padding": "10px 15px 10px 15px"}): + with mui.Grid(item=True, xs=12): + if not is_master_password_set: + base_warning = "You need to set a master password in order to use the dashboard." + if self.is_master_bot_running: + mui.Alert(f"{base_warning} The Master Configs instance is running." + f" Attach to it in Terminal to set the master password.", severity="success") + else: + mui.Alert(f"{base_warning} Master Configs instance isn't running. Start it and" + f" set the master password to continue.", severity="error") + else: + if self.is_master_bot_running: + mui.Alert("The Master Configs instance is running." + " Attach to it in Terminal to add credentials.", + severity="success", + sx={"margin": 2}) + else: + mui.Alert("Master Configs instance isn't running. Start it to add credentials.", + severity="error") + + with mui.Grid(item=True, xs=8): + if self.is_master_bot_running: + mui.TextField(InputProps={"readOnly": True}, + label="Attach to Master Configs instance", + value="docker attach hummingbot-master_bot_conf", + sx={"width": "100%"}) + with mui.Grid(item=True, xs=4): + button_text = "Stop" if self.is_master_bot_running else "Start" + color = "error" if self.is_master_bot_running else "success" + icon = mui.icon.Stop if self.is_master_bot_running else mui.icon.PlayCircle + with mui.Button(onClick=self.manage_master_bot_container, + color=color, + variant="outlined", + sx={"width": "100%", "height": "100%"}): + icon() + mui.Typography(button_text) \ No newline at end of file diff --git a/ui_components/master_conf_file_explorer.py b/ui_components/master_conf_file_explorer.py new file mode 100644 index 00000000..e395f48d --- /dev/null +++ b/ui_components/master_conf_file_explorer.py @@ -0,0 +1,32 @@ +from streamlit_elements import mui + +import constants +from ui_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 + + +class MasterConfFileExplorer(FileExplorerBase): + def add_tree_view(self): + directory = constants.HUMMINGBOT_TEMPLATES + configs = [conf.split("/")[-2] for conf in get_directories_from_directory(directory) if "master_bot_conf" in conf] + with mui.lab.TreeView(defaultExpandIcon=mui.icon.ChevronRight, defaultCollapseIcon=mui.icon.ExpandMore, + onNodeSelect=lambda event, node_id: self.set_selected_file(event, node_id), + defaultExpanded=["master_bot_conf"]): + for conf in configs: + with mui.lab.TreeItem(nodeId=conf, label=f"πŸ€–{conf}"): + with mui.lab.TreeItem(nodeId=f"scripts_{conf}", label="🐍Scripts"): + for file in get_python_files_from_directory(f"{directory}/{conf}/scripts"): + mui.lab.TreeItem(nodeId=file, label=f"πŸ“„{file.split('/')[-1]}") + with mui.lab.TreeItem(nodeId=f"strategies_{conf}", label="πŸ“œStrategies"): + for file in get_yml_files_from_directory(f"{directory}/{conf}/conf/strategies"): + mui.lab.TreeItem(nodeId=file, label=f"πŸ“„ {file.split('/')[-1]}") + with mui.lab.TreeItem(nodeId=f"configs_{conf}", label="πŸ”§Client Config"): + for file in get_yml_files_from_directory(f"{directory}/{conf}/conf"): + mui.lab.TreeItem(nodeId=file, label=f"πŸ“„ {file.split('/')[-1]}") + with mui.lab.TreeItem(nodeId=f"keys_{conf}", label="πŸ”‘Keys"): + for file in get_yml_files_from_directory(f"{directory}/{conf}/conf/connectors"): + mui.lab.TreeItem(nodeId=file, label=f"πŸ”‘ {file.split('/')[-1]}") + with mui.lab.TreeItem(nodeId=f"logs_{conf}", label="πŸ—„οΈLogs"): + for file in get_log_files_from_directory(f"{directory}/{conf}/logs"): + mui.lab.TreeItem(nodeId=file, label=f"πŸ“„ {file.split('/')[-1]}") diff --git a/utils/st_utils.py b/utils/st_utils.py index 5875109c..189f07b8 100644 --- a/utils/st_utils.py +++ b/utils/st_utils.py @@ -6,7 +6,7 @@ from st_pages import add_page_title -def initialize_st_page(title: str, icon: str, layout="wide", initial_sidebar_state="auto"): +def initialize_st_page(title: str, icon: str, layout="wide", initial_sidebar_state="collapsed"): st.set_page_config( page_title=title, page_icon=icon, @@ -15,7 +15,7 @@ def initialize_st_page(title: str, icon: str, layout="wide", initial_sidebar_sta ) caller_frame = inspect.currentframe().f_back - add_page_title(layout="wide") + add_page_title(layout=layout, initial_sidebar_state=initial_sidebar_state) current_directory = Path(os.path.dirname(inspect.getframeinfo(caller_frame).filename)) readme_path = current_directory / "README.md"