from __future__ import annotations import pandas as pd import plotly.graph_objects as go def add_example_trade_markers(fig: go.Figure, example_trades: pd.DataFrame) -> None: if example_trades.empty: return long_entries = example_trades[example_trades["direction"] == "LONG"] short_entries = example_trades[example_trades["direction"] == "SHORT"] win_exits = example_trades[example_trades["outcome"] == "Win"] non_win_exits = example_trades[example_trades["outcome"] != "Win"] if not long_entries.empty: fig.add_trace( go.Scatter( x=long_entries["entry_timestamp"], y=long_entries["entry_price"], mode="markers", name="Example Entry (Long)", marker=dict(color="#1565C0", size=9, symbol="circle"), ), row=1, col=1, ) if not short_entries.empty: fig.add_trace( go.Scatter( x=short_entries["entry_timestamp"], y=short_entries["entry_price"], mode="markers", name="Example Entry (Short)", marker=dict(color="#EF6C00", size=9, symbol="diamond"), ), row=1, col=1, ) if not win_exits.empty: fig.add_trace( go.Scatter( x=win_exits["exit_timestamp"], y=win_exits["exit_price"], mode="markers", name="Example Exit (Win)", marker=dict(color="#2E7D32", size=10, symbol="x"), ), row=1, col=1, ) if not non_win_exits.empty: fig.add_trace( go.Scatter( x=non_win_exits["exit_timestamp"], y=non_win_exits["exit_price"], mode="markers", name="Example Exit (Loss/Flat)", marker=dict(color="#C62828", size=10, symbol="x"), ), row=1, col=1, ) def highlight_selected_trade( fig: go.Figure, analyzed: pd.DataFrame, selected_trade: pd.Series | None, focus_chart_on_selected_example: bool, ) -> None: if selected_trade is None: return selected_entry_ts = pd.Timestamp(selected_trade["entry_timestamp"]) selected_exit_ts = pd.Timestamp(selected_trade["exit_timestamp"]) selected_entry_price = float(selected_trade["entry_price"]) selected_exit_price = float(selected_trade["exit_price"]) selected_direction = str(selected_trade["direction"]) selected_outcome = str(selected_trade["outcome"]) path_color = "#43A047" if selected_outcome == "Win" else ("#EF6C00" if selected_outcome == "Flat" else "#E53935") window_fill = "#BBDEFB" if selected_direction == "LONG" else "#FFE0B2" fig.add_vrect( x0=selected_entry_ts, x1=selected_exit_ts, fillcolor=window_fill, opacity=0.18, line_width=0, row=1, col=1, ) fig.add_trace( go.Scatter( x=[selected_entry_ts, selected_exit_ts], y=[selected_entry_price, selected_exit_price], mode="lines+markers", name="Selected Example Path", line=dict(color=path_color, width=3, dash="dot"), marker=dict(color=path_color, size=11, symbol="star"), ), row=1, col=1, ) if focus_chart_on_selected_example: entry_pos = int(analyzed.index.get_indexer([selected_entry_ts], method="nearest")[0]) exit_pos = int(analyzed.index.get_indexer([selected_exit_ts], method="nearest")[0]) left_pos = max(0, min(entry_pos, exit_pos) - 4) right_pos = min(len(analyzed) - 1, max(entry_pos, exit_pos) + 4) fig.update_xaxes(range=[analyzed.index[left_pos], analyzed.index[right_pos]])