diff --git a/pages/strategy_performance/app.py b/pages/strategy_performance/app.py index d79365b..d518d01 100644 --- a/pages/strategy_performance/app.py +++ b/pages/strategy_performance/app.py @@ -4,28 +4,8 @@ import streamlit as st import math from utils.os_utils import get_databases from utils.database_manager import DatabaseManager -from utils.graphs import CandlesGraph, PerformanceGraphs -from utils.st_utils import initialize_st_page, download_csv_button, style_metric_cards - - -def db_error_message(db: DatabaseManager, error_message: str): - container = st.container() - with container: - st.warning(error_message) - with st.expander("DB Status"): - status_df = pd.DataFrame([db.status]).transpose().reset_index() - status_df.columns = ["Attribute", "Value"] - st.table(status_df) - return container - - -def candles_graph(candles: pd.DataFrame, strat_data, show_volume=False, extra_rows=2): - cg = CandlesGraph(candles, show_volume=show_volume, extra_rows=extra_rows) - cg.add_buy_trades(strat_data.buys) - cg.add_sell_trades(strat_data.sells) - cg.add_pnl(strat_data, row=2) - cg.add_quote_inventory_change(strat_data, row=3) - return cg.figure() +from utils.graphs import PerformanceGraphs +from utils.st_utils import initialize_st_page, download_csv_button, style_metric_cards, db_error_message initialize_st_page(title="Strategy Performance", icon="🚀") @@ -45,7 +25,7 @@ intervals = { "1d": 60 * 60 * 24, } - +# Data source section st.subheader("🔫 Data source") # Upload database @@ -180,12 +160,12 @@ else: # Filter strategy data by page page_filtered_strategy_data = single_market_strategy_data.get_filtered_strategy_data(start_time_page, end_time_page) page_performance_charts = PerformanceGraphs(page_filtered_strategy_data) + candles_chart = page_performance_charts.candles_graph(candles_df) # Panel Metrics if show_panel_metrics: col1, col2 = st.columns([2, 1]) with col1: - candles_chart = candles_graph(candles_df, page_filtered_strategy_data) st.plotly_chart(candles_chart, use_container_width=True) with col2: chart_tab, table_tab = st.tabs(["Chart", "Table"]) @@ -198,16 +178,7 @@ else: hide_index=True, height=(min(len(page_filtered_strategy_data.trade_fill) * 39, candles_chart.layout.height - 180))) else: - st.plotly_chart(candles_graph(candles_df, page_filtered_strategy_data), use_container_width=True) - -# Position executor section -st.divider() -st.subheader("🤖 Position executor") -if "Error" in selected_db.status["position_executor"] or strategy_data.position_executor.empty: - st.warning("Position executor data is not available so position executor graphs are not going to be rendered." - "Make sure that you are using the latest version of Hummingbot.") -else: - st.dataframe(strategy_data.position_executor, use_container_width=True) + st.plotly_chart(candles_chart, use_container_width=True) # Community metrics section st.divider() diff --git a/utils/database_manager.py b/utils/database_manager.py index 1c0287a..f6aa8b3 100644 --- a/utils/database_manager.py +++ b/utils/database_manager.py @@ -198,5 +198,6 @@ class DatabaseManager: query = self._get_position_executor_query(start_date, end_date) position_executor = pd.read_sql_query(text(query), session.connection()) position_executor.set_index("timestamp", inplace=True) - position_executor["datetime"] = pd.to_datetime(position_executor.index, unit="ms") + position_executor["datetime"] = pd.to_datetime(position_executor.index, unit="s") + position_executor["level"] = position_executor["order_level"].apply(lambda x: x.split("_")[1]) return position_executor diff --git a/utils/graphs.py b/utils/graphs.py index 8f131fe..0fa1c91 100644 --- a/utils/graphs.py +++ b/utils/graphs.py @@ -346,6 +346,13 @@ class PerformanceGraphs: else: return False + @property + def has_position_executor_summary(self): + if isinstance(self.strategy_data, StrategyData): + return self.strategy_data.position_executor is not None + else: + return False + def strategy_summary_table(self): summary = st.data_editor(self.strategy_data.strategy_summary, column_config={"PnL Over Time": st.column_config.LineChartColumn("PnL Over Time", @@ -482,4 +489,39 @@ class PerformanceGraphs: xanchor="center", x=.48 )) - return fig \ No newline at end of file + return fig + + def position_executor_summary_sunburst(self): + df = self.strategy_data.position_executor.copy() + grouped_df = df.groupby(["trading_pair", "side", "close_type"]).size().reset_index(name="count") + + fig = px.sunburst(grouped_df, + path=['trading_pair', 'side', 'close_type'], + values="count", + color_continuous_scale='RdBu', + color_continuous_midpoint=0) + + fig.update_layout( + title=dict( + text='Position Executor Summary', + x=0.5, + xanchor="center", + ), + legend=dict( + orientation="h", + yanchor="bottom", + y=1.02, + xanchor="center", + x=.48 + ) + ) + + return fig + + def candles_graph(self, candles: pd.DataFrame, show_volume=False, extra_rows=2): + cg = CandlesGraph(candles, show_volume=show_volume, extra_rows=extra_rows) + cg.add_buy_trades(self.strategy_data.buys) + cg.add_sell_trades(self.strategy_data.sells) + cg.add_pnl(self.strategy_data, row=2) + cg.add_quote_inventory_change(self.strategy_data, row=3) + return cg.figure() diff --git a/utils/st_utils.py b/utils/st_utils.py index dff61ff..a89dcf5 100644 --- a/utils/st_utils.py +++ b/utils/st_utils.py @@ -6,6 +6,7 @@ import inspect import streamlit as st from st_pages import add_page_title +from utils.database_manager import DatabaseManager def initialize_st_page(title: str, icon: str, layout="wide", initial_sidebar_state="collapsed"): st.set_page_config( @@ -64,3 +65,14 @@ def style_metric_cards( """, unsafe_allow_html=True, ) + + +def db_error_message(db: DatabaseManager, error_message: str): + container = st.container() + with container: + st.warning(error_message) + with st.expander("DB Status"): + status_df = pd.DataFrame([db.status]).transpose().reset_index() + status_df.columns = ["Attribute", "Value"] + st.table(status_df) + return container