execution and training fixes
This commit is contained in:
@ -4716,8 +4716,50 @@ class CleanTradingDashboard:
|
||||
return 0
|
||||
|
||||
def _get_trading_statistics(self) -> Dict[str, Any]:
|
||||
"""Calculate trading statistics from closed trades"""
|
||||
"""Get trading statistics from trading executor"""
|
||||
try:
|
||||
# Try to get statistics from trading executor first
|
||||
if self.trading_executor:
|
||||
executor_stats = self.trading_executor.get_daily_stats()
|
||||
closed_trades = self.trading_executor.get_closed_trades()
|
||||
|
||||
if executor_stats and executor_stats.get('total_trades', 0) > 0:
|
||||
# Calculate largest win/loss from closed trades
|
||||
largest_win = 0.0
|
||||
largest_loss = 0.0
|
||||
|
||||
if closed_trades:
|
||||
for trade in closed_trades:
|
||||
try:
|
||||
# Handle both dictionary and object formats
|
||||
if isinstance(trade, dict):
|
||||
pnl = trade.get('pnl', 0)
|
||||
else:
|
||||
pnl = getattr(trade, 'pnl', 0)
|
||||
|
||||
if pnl > 0:
|
||||
largest_win = max(largest_win, pnl)
|
||||
elif pnl < 0:
|
||||
largest_loss = max(largest_loss, abs(pnl))
|
||||
|
||||
except Exception as e:
|
||||
logger.debug(f"Error processing trade for statistics: {e}")
|
||||
continue
|
||||
|
||||
# Map executor stats to dashboard format
|
||||
return {
|
||||
'total_trades': executor_stats.get('total_trades', 0),
|
||||
'winning_trades': executor_stats.get('winning_trades', 0),
|
||||
'losing_trades': executor_stats.get('losing_trades', 0),
|
||||
'win_rate': executor_stats.get('win_rate', 0.0) * 100, # Convert to percentage
|
||||
'avg_win_size': executor_stats.get('avg_winning_trade', 0.0), # Correct mapping
|
||||
'avg_loss_size': abs(executor_stats.get('avg_losing_trade', 0.0)), # Make positive for display
|
||||
'largest_win': largest_win,
|
||||
'largest_loss': largest_loss,
|
||||
'total_pnl': executor_stats.get('total_pnl', 0.0)
|
||||
}
|
||||
|
||||
# Fallback to dashboard's own trade list if no trading executor
|
||||
if not self.closed_trades:
|
||||
return {
|
||||
'total_trades': 0,
|
||||
|
@ -96,6 +96,8 @@ class DashboardComponentManager:
|
||||
total_trades = trading_stats.get('total_trades', 0)
|
||||
winning_trades = trading_stats.get('winning_trades', 0)
|
||||
losing_trades = trading_stats.get('losing_trades', 0)
|
||||
total_fees = trading_stats.get('total_fees', 0)
|
||||
breakeven_trades = trading_stats.get('breakeven_trades', 0)
|
||||
|
||||
win_rate_class = "text-success" if win_rate >= 50 else "text-warning" if win_rate >= 30 else "text-danger"
|
||||
|
||||
@ -106,16 +108,20 @@ class DashboardComponentManager:
|
||||
html.Div([
|
||||
html.Span("Win Rate: ", className="small text-muted"),
|
||||
html.Span(f"{win_rate:.1f}%", className=f"fw-bold {win_rate_class}"),
|
||||
html.Span(f" ({winning_trades}W/{losing_trades}L)", className="small text-muted")
|
||||
], className="col-4"),
|
||||
html.Span(f" ({winning_trades}W/{losing_trades}L/{breakeven_trades}B)", className="small text-muted")
|
||||
], className="col-3"),
|
||||
html.Div([
|
||||
html.Span("Avg Win: ", className="small text-muted"),
|
||||
html.Span(f"${avg_win:.2f}", className="fw-bold text-success")
|
||||
], className="col-4"),
|
||||
], className="col-3"),
|
||||
html.Div([
|
||||
html.Span("Avg Loss: ", className="small text-muted"),
|
||||
html.Span(f"${avg_loss:.2f}", className="fw-bold text-danger")
|
||||
], className="col-4")
|
||||
], className="col-3"),
|
||||
html.Div([
|
||||
html.Span("Total Fees: ", className="small text-muted"),
|
||||
html.Span(f"${total_fees:.2f}", className="fw-bold text-warning")
|
||||
], className="col-3")
|
||||
], className="row"),
|
||||
html.Hr(className="my-2")
|
||||
], className="mb-3")
|
||||
@ -135,6 +141,7 @@ class DashboardComponentManager:
|
||||
html.Th("Size", className="small"),
|
||||
html.Th("Entry", className="small"),
|
||||
html.Th("Exit", className="small"),
|
||||
html.Th("Hold (s)", className="small"),
|
||||
html.Th("P&L", className="small"),
|
||||
html.Th("Fees", className="small")
|
||||
])
|
||||
@ -142,7 +149,7 @@ class DashboardComponentManager:
|
||||
|
||||
# Create table rows
|
||||
rows = []
|
||||
for trade in closed_trades[-20:]: # Last 20 trades
|
||||
for trade in closed_trades: # Removed [-20:] to show all trades
|
||||
# Handle both trade objects and dictionary formats
|
||||
if hasattr(trade, 'entry_time'):
|
||||
# This is a trade object
|
||||
@ -153,15 +160,17 @@ class DashboardComponentManager:
|
||||
exit_price = getattr(trade, 'exit_price', 0)
|
||||
pnl = getattr(trade, 'pnl', 0)
|
||||
fees = getattr(trade, 'fees', 0)
|
||||
hold_time_seconds = getattr(trade, 'hold_time_seconds', 0.0)
|
||||
else:
|
||||
# This is a dictionary format
|
||||
entry_time = trade.get('entry_time', 'Unknown')
|
||||
side = trade.get('side', 'UNKNOWN')
|
||||
size = trade.get('size', 0)
|
||||
size = trade.get('quantity', trade.get('size', 0)) # Try 'quantity' first, then 'size'
|
||||
entry_price = trade.get('entry_price', 0)
|
||||
exit_price = trade.get('exit_price', 0)
|
||||
pnl = trade.get('pnl', 0)
|
||||
fees = trade.get('fees', 0)
|
||||
hold_time_seconds = trade.get('hold_time_seconds', 0.0)
|
||||
|
||||
# Format time
|
||||
if isinstance(entry_time, datetime):
|
||||
@ -179,6 +188,7 @@ class DashboardComponentManager:
|
||||
html.Td(f"{size:.3f}", className="small"),
|
||||
html.Td(f"${entry_price:.2f}", className="small"),
|
||||
html.Td(f"${exit_price:.2f}", className="small"),
|
||||
html.Td(f"{hold_time_seconds:.0f}", className="small text-info"),
|
||||
html.Td(f"${pnl:.2f}", className=f"small {pnl_class}"),
|
||||
html.Td(f"${fees:.3f}", className="small text-muted")
|
||||
])
|
||||
@ -188,11 +198,17 @@ class DashboardComponentManager:
|
||||
|
||||
table = html.Table([headers, tbody], className="table table-sm table-striped")
|
||||
|
||||
# Wrap the table in a scrollable div
|
||||
scrollable_table_container = html.Div(
|
||||
table,
|
||||
style={'maxHeight': '300px', 'overflowY': 'scroll', 'overflowX': 'hidden'}
|
||||
)
|
||||
|
||||
# Combine statistics header with table
|
||||
if stats_header:
|
||||
return html.Div(stats_header + [table])
|
||||
return html.Div(stats_header + [scrollable_table_container])
|
||||
else:
|
||||
return table
|
||||
return scrollable_table_container
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error formatting closed trades: {e}")
|
||||
|
Reference in New Issue
Block a user