lines between trade actions

This commit is contained in:
Dobromir Popov 2025-05-30 17:25:53 +03:00
parent 774debbf75
commit c6386a3718

View File

@ -1415,6 +1415,193 @@ class TradingDashboard:
row=1, col=1
)
# Add closed trades markers with profit/loss styling and connecting lines
if self.closed_trades and not df.empty:
# Get the timeframe of displayed chart
chart_start_time = df.index.min()
chart_end_time = df.index.max()
# Convert chart times to UTC for comparison
if isinstance(chart_start_time, pd.Timestamp):
chart_start_utc = chart_start_time.tz_localize(None) if chart_start_time.tz is None else chart_start_time.tz_convert('UTC').tz_localize(None)
chart_end_utc = chart_end_time.tz_localize(None) if chart_end_time.tz is None else chart_end_time.tz_convert('UTC').tz_localize(None)
else:
chart_start_utc = pd.to_datetime(chart_start_time).tz_localize(None)
chart_end_utc = pd.to_datetime(chart_end_time).tz_localize(None)
# Filter closed trades to only those within chart timeframe
chart_trades = []
for trade in self.closed_trades:
if not isinstance(trade, dict):
continue
entry_time = trade.get('entry_time')
exit_time = trade.get('exit_time')
if not entry_time or not exit_time:
continue
# Convert times to UTC for comparison
if isinstance(entry_time, datetime):
entry_time_utc = entry_time.astimezone(timezone.utc).replace(tzinfo=None) if entry_time.tzinfo else entry_time
else:
continue
if isinstance(exit_time, datetime):
exit_time_utc = exit_time.astimezone(timezone.utc).replace(tzinfo=None) if exit_time.tzinfo else exit_time
else:
continue
# Check if trade overlaps with chart timeframe
entry_time_pd = pd.to_datetime(entry_time_utc)
exit_time_pd = pd.to_datetime(exit_time_utc)
if (chart_start_utc <= entry_time_pd <= chart_end_utc) or (chart_start_utc <= exit_time_pd <= chart_end_utc):
chart_trades.append(trade)
logger.debug(f"[CHART] Showing {len(chart_trades)} closed trades on chart")
# Plot closed trades with profit/loss styling
profitable_entries_x = []
profitable_entries_y = []
profitable_exits_x = []
profitable_exits_y = []
losing_entries_x = []
losing_entries_y = []
losing_exits_x = []
losing_exits_y = []
# Collect trade points for display
for trade in chart_trades:
entry_price = trade.get('entry_price', 0)
exit_price = trade.get('exit_price', 0)
entry_time = trade.get('entry_time')
exit_time = trade.get('exit_time')
net_pnl = trade.get('net_pnl', 0)
side = trade.get('side', 'LONG')
if not all([entry_price, exit_price, entry_time, exit_time]):
continue
# Convert times to local timezone for display
entry_time_local = self._to_local_timezone(entry_time)
exit_time_local = self._to_local_timezone(exit_time)
# Determine if trade was profitable
is_profitable = net_pnl > 0
if is_profitable:
profitable_entries_x.append(entry_time_local)
profitable_entries_y.append(entry_price)
profitable_exits_x.append(exit_time_local)
profitable_exits_y.append(exit_price)
else:
losing_entries_x.append(entry_time_local)
losing_entries_y.append(entry_price)
losing_exits_x.append(exit_time_local)
losing_exits_y.append(exit_price)
# Add connecting dash line between entry and exit
line_color = '#00ff88' if is_profitable else '#ff6b6b'
fig.add_trace(
go.Scatter(
x=[entry_time_local, exit_time_local],
y=[entry_price, exit_price],
mode='lines',
line=dict(
color=line_color,
width=2,
dash='dash'
),
name="Trade Path",
showlegend=False,
hoverinfo='skip'
),
row=1, col=1
)
# Add profitable trade markers (filled triangles)
if profitable_entries_x:
# Entry markers (triangle-up for LONG, triangle-down for SHORT - filled)
fig.add_trace(
go.Scatter(
x=profitable_entries_x,
y=profitable_entries_y,
mode='markers',
marker=dict(
color='#00ff88', # Green fill for profitable
size=12,
symbol='triangle-up',
line=dict(color='white', width=1)
),
name="Profitable Entry",
showlegend=True,
hovertemplate="<b>PROFITABLE ENTRY</b><br>Price: $%{y:.2f}<br>Time: %{x}<extra></extra>"
),
row=1, col=1
)
if profitable_exits_x:
# Exit markers (triangle-down for LONG, triangle-up for SHORT - filled)
fig.add_trace(
go.Scatter(
x=profitable_exits_x,
y=profitable_exits_y,
mode='markers',
marker=dict(
color='#00ff88', # Green fill for profitable
size=12,
symbol='triangle-down',
line=dict(color='white', width=1)
),
name="Profitable Exit",
showlegend=True,
hovertemplate="<b>PROFITABLE EXIT</b><br>Price: $%{y:.2f}<br>Time: %{x}<extra></extra>"
),
row=1, col=1
)
# Add losing trade markers (border only triangles)
if losing_entries_x:
# Entry markers (triangle-up for LONG, triangle-down for SHORT - border only)
fig.add_trace(
go.Scatter(
x=losing_entries_x,
y=losing_entries_y,
mode='markers',
marker=dict(
color='rgba(255, 107, 107, 0)', # Transparent fill
size=12,
symbol='triangle-up',
line=dict(color='#ff6b6b', width=2) # Red border for losing
),
name="Losing Entry",
showlegend=True,
hovertemplate="<b>LOSING ENTRY</b><br>Price: $%{y:.2f}<br>Time: %{x}<extra></extra>"
),
row=1, col=1
)
if losing_exits_x:
# Exit markers (triangle-down for LONG, triangle-up for SHORT - border only)
fig.add_trace(
go.Scatter(
x=losing_exits_x,
y=losing_exits_y,
mode='markers',
marker=dict(
color='rgba(255, 107, 107, 0)', # Transparent fill
size=12,
symbol='triangle-down',
line=dict(color='#ff6b6b', width=2) # Red border for losing
),
name="Losing Exit",
showlegend=True,
hovertemplate="<b>LOSING EXIT</b><br>Price: $%{y:.2f}<br>Time: %{x}<extra></extra>"
),
row=1, col=1
)
# Update layout with current timestamp and streaming status
current_time = datetime.now().strftime("%H:%M:%S.%f")[:-3]
latest_price = df['close'].iloc[-1] if not df.empty else 0