maneshtrader/web_core/chart_overlays.py

113 lines
3.8 KiB
Python

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]])