diff --git a/frontend/components/bot_performance_card.py b/frontend/components/bot_performance_card.py index fcddf5d..fb3be1f 100644 --- a/frontend/components/bot_performance_card.py +++ b/frontend/components/bot_performance_card.py @@ -1,17 +1,17 @@ -import time - +import pandas as pd +import streamlit as st +from hummingbot.strategy_v2.models.executors import CloseType from streamlit_elements import mui -from CONFIG import BACKEND_API_HOST, BACKEND_API_PORT from frontend.components.dashboard import Dashboard -from backend.services.backend_api_client import BackendAPIClient from frontend.st_utils import get_backend_api_client TRADES_TO_SHOW = 5 -WIDE_COL_WIDTH = 250 -MEDIUM_COL_WIDTH = 170 -SMALL_COL_WIDTH = 100 +ULTRA_WIDE_COL_WIDTH = 300 +WIDE_COL_WIDTH = 160 +MEDIUM_COL_WIDTH = 140 +SMALL_COL_WIDTH = 110 backend_api_client = get_backend_api_client() @@ -27,12 +27,16 @@ def archive_bot(bot_name): class BotPerformanceCardV2(Dashboard.Item): DEFAULT_COLUMNS = [ {"field": 'id', "headerName": 'ID', "width": WIDE_COL_WIDTH}, + {"field": 'controller', "headerName": 'Controller', "width": SMALL_COL_WIDTH, "editable": False}, + {"field": 'connector', "headerName": 'Connector', "width": SMALL_COL_WIDTH, "editable": False}, + {"field": 'trading_pair', "headerName": 'Trading Pair', "width": SMALL_COL_WIDTH, "editable": False}, {"field": 'realized_pnl_quote', "headerName": 'Realized PNL ($)', "width": MEDIUM_COL_WIDTH, "editable": False}, {"field": 'unrealized_pnl_quote', "headerName": 'Unrealized PNL ($)', "width": MEDIUM_COL_WIDTH, "editable": False}, {"field": 'global_pnl_quote', "headerName": 'NET PNL ($)', "width": MEDIUM_COL_WIDTH, "editable": False}, - {"field": 'volume_traded', "headerName": 'Volume ($)', "width": MEDIUM_COL_WIDTH, "editable": False}, - {"field": 'open_order_volume', "headerName": 'Open Order Volume ($)', "width": MEDIUM_COL_WIDTH, "editable": False}, - {"field": 'imbalance', "headerName": 'Imbalance ($)', "width": MEDIUM_COL_WIDTH, "editable": False}, + {"field": 'volume_traded', "headerName": 'Volume ($)', "width": SMALL_COL_WIDTH, "editable": False}, + {"field": 'open_order_volume', "headerName": 'Liquidity Placed ($)', "width": MEDIUM_COL_WIDTH, "editable": False}, + {"field": 'imbalance', "headerName": 'Imbalance ($)', "width": SMALL_COL_WIDTH, "editable": False}, + {"field": 'close_types', "headerName": 'Close Types', "width": ULTRA_WIDE_COL_WIDTH, "editable": False} ] _active_controller_config_selected = [] _stopped_controller_config_selected = [] @@ -89,6 +93,8 @@ class BotPerformanceCardV2(Dashboard.Item): bot_data = bot_status.get("data") is_running = bot_data.get("status") == "running" performance = bot_data.get("performance") + error_logs = bot_data.get("error_logs") + general_logs = bot_data.get("general_logs") if is_running: for controller, inner_dict in performance.items(): controller_status = inner_dict.get("status") @@ -98,6 +104,9 @@ class BotPerformanceCardV2(Dashboard.Item): continue controller_performance = inner_dict.get("performance") controller_config = next((config for config in controller_configs if config.get("id") == controller), {}) + controller_name = controller_config.get("controller_name", controller) + connector_name = controller_config.get("connector_name", "NaN") + trading_pair = controller_config.get("trading_pair", "NaN") kill_switch_status = True if controller_config.get("manual_kill_switch") is True else False realized_pnl_quote = controller_performance.get("realized_pnl_quote", 0) unrealized_pnl_quote = controller_performance.get("unrealized_pnl_quote", 0) @@ -105,14 +114,25 @@ class BotPerformanceCardV2(Dashboard.Item): volume_traded = controller_performance.get("volume_traded", 0) open_order_volume = controller_performance.get("open_order_volume", 0) imbalance = controller_performance.get("imbalance", 0) + close_types = controller_performance.get("close_type_counts", {}) + tp = close_types.get("CloseType.TAKE_PROFIT", 0) + sl = close_types.get("CloseType.STOP_LOSS", 0) + time_limit = close_types.get("CloseType.TIME_LIMIT", 0) + ts = close_types.get("CloseType.TRAILING_STOP", 0) + refreshed = close_types.get("CloseType.EARLY_STOP", 0) + close_types_str = f"TP: {tp} | SL: {sl} | TS: {ts} | TL: {time_limit} | RS: {refreshed}" controller_info = { "id": controller, - "realized_pnl_quote": realized_pnl_quote, - "unrealized_pnl_quote": unrealized_pnl_quote, - "global_pnl_quote": global_pnl_quote, - "volume_traded": volume_traded, - "open_order_volume": open_order_volume, - "imbalance": imbalance, + "controller": controller_name, + "connector": connector_name, + "trading_pair": trading_pair, + "realized_pnl_quote": round(realized_pnl_quote, 2), + "unrealized_pnl_quote": round(unrealized_pnl_quote, 2), + "global_pnl_quote": round(global_pnl_quote, 2), + "volume_traded": round(volume_traded, 2), + "open_order_volume": round(open_order_volume, 2), + "imbalance": round(imbalance, 2), + "close_types": close_types_str, } if kill_switch_status: stopped_controllers_list.append(controller_info) @@ -270,6 +290,30 @@ class BotPerformanceCardV2(Dashboard.Item): sx={"width": "100%", "height": "100%"}): mui.icon.AddCircleOutline() mui.Typography("Stop") + with mui.Accordion(sx={"padding": "10px 15px 10px 15px"}): + with mui.AccordionSummary(expandIcon=mui.icon.ExpandMoreIcon()): + mui.Typography("Error Logs") + with mui.AccordionDetails(sx={"display": "flex", "flexDirection": "column"}): + if len(error_logs) > 0: + for log in error_logs: + timestamp = log.get("timestamp") + message = log.get("msg") + logger_name = log.get("logger_name") + mui.Typography(f"{timestamp} - {logger_name}: {message}") + else: + mui.Typography("No error logs available.") + with mui.Accordion(sx={"padding": "10px 15px 10px 15px"}): + with mui.AccordionSummary(expandIcon=mui.icon.ExpandMoreIcon()): + mui.Typography("General Logs") + with mui.AccordionDetails(sx={"display": "flex", "flexDirection": "column"}): + if len(general_logs) > 0: + for log in general_logs: + timestamp = pd.to_datetime(int(log.get("timestamp")), unit="s") + message = log.get("msg") + logger_name = log.get("logger_name") + mui.Typography(f"{timestamp} - {logger_name}: {message}") + else: + mui.Typography("No general logs available.") except Exception as e: print(e) with mui.Card(key=self._key,