diff --git a/frontend/visualization/dca_builder.py b/frontend/visualization/dca_builder.py index 501b5fc..bfa3e7b 100644 --- a/frontend/visualization/dca_builder.py +++ b/frontend/visualization/dca_builder.py @@ -17,11 +17,12 @@ def create_dca_graph(dca_inputs, dca_amount): tech_colors = theme.get_color_scheme() dca_order_amounts = [amount_dist * dca_amount for amount_dist in dca_inputs["dca_amounts"]] n_levels = len(dca_inputs["dca_spreads"]) + dca_spreads = [spread * 100 for spread in dca_inputs["dca_spreads"]] break_even_values = [] take_profit_values = [] for level in range(n_levels): - dca_spreads_normalized = [spread + 0.01 for spread in dca_inputs["dca_spreads"][:level + 1]] + dca_spreads_normalized = [spread + 0.01 for spread in dca_spreads[:level + 1]] amounts = dca_order_amounts[:level + 1] break_even = (sum([spread * amount for spread, amount in zip(dca_spreads_normalized, amounts)]) / sum( amounts)) - 0.01 @@ -31,7 +32,7 @@ def create_dca_graph(dca_inputs, dca_amount): accumulated_amount = [sum(dca_order_amounts[:i + 1]) for i in range(len(dca_order_amounts))] # Calculate unrealized PNL - cum_unrealized_pnl = calculate_unrealized_pnl(dca_inputs["dca_spreads"], break_even_values, accumulated_amount) + cum_unrealized_pnl = calculate_unrealized_pnl(dca_spreads, break_even_values, accumulated_amount) # Create Plotly figure with secondary y-axis and a dark theme fig = make_subplots(specs=[[{"secondary_y": True}]]) @@ -39,7 +40,7 @@ def create_dca_graph(dca_inputs, dca_amount): # Update the Scatter Plots and Horizontal Lines fig.add_trace( - go.Scatter(x=list(range(len(dca_inputs["dca_spreads"]))), y=dca_inputs["dca_spreads"], name='Spread (%)', + go.Scatter(x=list(range(len(dca_spreads))), y=dca_spreads, name='Spread (%)', mode='lines+markers', line=dict(width=3, color=tech_colors['spread'])), secondary_y=False) fig.add_trace( @@ -99,7 +100,7 @@ def create_dca_graph(dca_inputs, dca_amount): # Update Annotations for Spread and Break Even for i, (spread, be_value, tp_value) in enumerate( - zip(dca_inputs["dca_spreads"], break_even_values, take_profit_values)): + zip(dca_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, diff --git a/frontend/visualization/executors.py b/frontend/visualization/executors.py index 42c0870..83fff4a 100644 --- a/frontend/visualization/executors.py +++ b/frontend/visualization/executors.py @@ -15,7 +15,7 @@ def add_executors_trace(fig, executors, row, col): if executor.filled_amount_quote == 0: fig.add_trace(go.Scatter(x=[entry_time, exit_time], y=[entry_price, entry_price], mode='lines', - line=dict(color='blue', width=2, dash="dash"), name=name), row=row, col=col) + line=dict(color='grey', width=2, dash="dash"), name=name), row=row, col=col) else: if executor.net_pnl_quote > Decimal(0): fig.add_trace(go.Scatter(x=[entry_time, exit_time], y=[entry_price, exit_price], mode='lines', diff --git a/frontend/visualization/executors_distribution.py b/frontend/visualization/executors_distribution.py index b41a26d..5f2220c 100644 --- a/frontend/visualization/executors_distribution.py +++ b/frontend/visualization/executors_distribution.py @@ -1,3 +1,4 @@ +import numpy as np import plotly.graph_objects as go import frontend.visualization.theme as theme @@ -12,6 +13,10 @@ def create_executors_distribution_traces(buy_spreads, sell_spreads, buy_amounts_ buy_order_levels = len(buy_spread_distributions) sell_order_levels = len(sell_spread_distributions) + # Calculate total volumes + total_buy_volume = sum(buy_order_amounts_quote) + total_sell_volume = sum(sell_order_amounts_quote) + # Create the figure with a dark theme and secondary y-axis fig = go.Figure() @@ -37,7 +42,7 @@ def create_executors_distribution_traces(buy_spreads, sell_spreads, buy_amounts_ for i, value in enumerate(buy_order_amounts_quote): fig.add_annotation( x=-buy_spread_distributions[i], - y=value + 0.01 * max(buy_order_amounts_quote), # Offset the text slightly above the bar + y=value + 0.03 * max(buy_order_amounts_quote), # Offset the text slightly above the bar text=str(round(value, 2)), showarrow=False, font=dict(color=colors['buy'], size=10) @@ -47,12 +52,55 @@ def create_executors_distribution_traces(buy_spreads, sell_spreads, buy_amounts_ for i, value in enumerate(sell_order_amounts_quote): fig.add_annotation( x=sell_spread_distributions[i], - y=value + 0.01 * max(sell_order_amounts_quote), # Offset the text slightly above the bar + y=value + 0.03 * max(sell_order_amounts_quote), # Offset the text slightly above the bar text=str(round(value, 2)), showarrow=False, font=dict(color=colors['sell'], size=10) ) + max_y = max(max(buy_order_amounts_quote), max(sell_order_amounts_quote)) + # Add annotations for total volumes + fig.add_annotation( + x=-np.mean(buy_spread_distributions), + y=max_y, + text=f'Total Buy\n{round(total_buy_volume, 2)}', + showarrow=False, + font=dict(color=colors['buy'], size=12, family="Arial Black"), + align='center' + ) + + fig.add_annotation( + x=np.mean(sell_spread_distributions), + y=max_y, + text=f'Total Sell\n{round(total_sell_volume, 2)}', + showarrow=False, + font=dict(color=colors['sell'], size=12, family="Arial Black"), + align='center' + ) + + # Draw circles around the total volume annotations + fig.add_shape( + type='circle', + xref='x', + yref='y', + x0=-np.mean(buy_spread_distributions) - 0.4, + y0=max_y - 0.05 * max_y, + x1=-np.mean(buy_spread_distributions) + 0.4, + y1=max_y + 0.05 * max_y, + line=dict(color=colors['buy']) + ) + + fig.add_shape( + type='circle', + xref='x', + yref='y', + x0=np.mean(sell_spread_distributions) - 0.4, + y0=max_y - 0.05 * max_y, + x1=np.mean(sell_spread_distributions) + 0.4, + y1=max_y + 0.05 * max_y, + line=dict(color=colors['sell']) + ) + # Apply the theme layout layout_settings = theme.get_default_layout("Market Maker Order Distribution") fig.update_layout(**layout_settings)