position history with fees
This commit is contained in:
@ -152,8 +152,8 @@ class TradingDashboard:
|
||||
# Check if trading is enabled and not in dry run mode
|
||||
if not self.trading_executor.trading_enabled:
|
||||
logger.warning("MEXC: Trading not enabled - using default balance")
|
||||
elif self.trading_executor.dry_run:
|
||||
logger.warning("MEXC: Dry run mode enabled - using default balance")
|
||||
elif self.trading_executor.simulation_mode:
|
||||
logger.warning(f"MEXC: {self.trading_executor.trading_mode.upper()} mode enabled - using default balance")
|
||||
else:
|
||||
# Get USDT balance from MEXC
|
||||
balance_info = self.trading_executor.get_account_balance()
|
||||
@ -188,7 +188,7 @@ class TradingDashboard:
|
||||
html.I(className="fas fa-chart-line me-2"),
|
||||
"Live Trading Dashboard"
|
||||
], className="text-white mb-1"),
|
||||
html.P(f"Ultra-Fast Updates • Portfolio: ${self.starting_balance:,.0f} • {'MEXC Live' if (self.trading_executor and self.trading_executor.trading_enabled and not self.trading_executor.dry_run) else 'Demo Mode'}",
|
||||
html.P(f"Ultra-Fast Updates • Portfolio: ${self.starting_balance:,.0f} • {'MEXC Live' if (self.trading_executor and self.trading_executor.trading_enabled and not self.trading_executor.simulation_mode) else 'Demo Mode'}",
|
||||
className="text-light mb-0 opacity-75 small")
|
||||
], className="bg-dark p-2 mb-2"),
|
||||
|
||||
@ -219,6 +219,13 @@ class TradingDashboard:
|
||||
], className="card-body text-center p-2")
|
||||
], className="card bg-light", style={"height": "60px"}),
|
||||
|
||||
html.Div([
|
||||
html.Div([
|
||||
html.H5(id="total-fees", className="text-warning mb-0 small"),
|
||||
html.P("Total Fees", className="text-muted mb-0 tiny")
|
||||
], className="card-body text-center p-2")
|
||||
], className="card bg-light", style={"height": "60px"}),
|
||||
|
||||
html.Div([
|
||||
html.Div([
|
||||
html.H5(id="current-position", className="text-info mb-0 small"),
|
||||
@ -246,7 +253,7 @@ class TradingDashboard:
|
||||
html.P("MEXC API", className="text-muted mb-0 tiny")
|
||||
], className="card-body text-center p-2")
|
||||
], className="card bg-light", style={"height": "60px"}),
|
||||
], style={"display": "grid", "gridTemplateColumns": "repeat(3, 1fr)", "gap": "8px", "width": "50%"}),
|
||||
], style={"display": "grid", "gridTemplateColumns": "repeat(4, 1fr)", "gap": "8px", "width": "60%"}),
|
||||
|
||||
# Right side - Recent Signals & Executions
|
||||
html.Div([
|
||||
@ -350,6 +357,7 @@ class TradingDashboard:
|
||||
Output('current-price', 'children'),
|
||||
Output('session-pnl', 'children'),
|
||||
Output('session-pnl', 'className'),
|
||||
Output('total-fees', 'children'),
|
||||
Output('current-position', 'children'),
|
||||
Output('current-position', 'className'),
|
||||
Output('trade-count', 'children'),
|
||||
@ -511,6 +519,9 @@ class TradingDashboard:
|
||||
pnl_text = f"${total_session_pnl:.2f}"
|
||||
pnl_class = "text-success mb-0 small" if total_session_pnl >= 0 else "text-danger mb-0 small"
|
||||
|
||||
# Total fees formatting
|
||||
fees_text = f"${self.total_fees:.2f}"
|
||||
|
||||
# Position info with real-time unrealized PnL and proper color coding
|
||||
if self.current_position:
|
||||
pos_side = self.current_position['side']
|
||||
@ -540,8 +551,8 @@ class TradingDashboard:
|
||||
|
||||
# MEXC status with detailed information
|
||||
if self.trading_executor and self.trading_executor.trading_enabled:
|
||||
if self.trading_executor.dry_run:
|
||||
mexc_status = "DRY RUN"
|
||||
if self.trading_executor.simulation_mode:
|
||||
mexc_status = f"{self.trading_executor.trading_mode.upper()} MODE"
|
||||
else:
|
||||
mexc_status = "LIVE"
|
||||
else:
|
||||
@ -597,7 +608,7 @@ class TradingDashboard:
|
||||
closed_trades_table = [html.P("Closed trades data unavailable", className="text-muted")]
|
||||
|
||||
return (
|
||||
price_text, pnl_text, pnl_class, position_text, position_class, trade_count_text, portfolio_text, mexc_status,
|
||||
price_text, pnl_text, pnl_class, fees_text, position_text, position_class, trade_count_text, portfolio_text, mexc_status,
|
||||
price_chart, training_metrics, decisions_list, session_perf, closed_trades_table,
|
||||
system_status['icon_class'], system_status['title'], system_status['details']
|
||||
)
|
||||
@ -608,7 +619,7 @@ class TradingDashboard:
|
||||
empty_fig = self._create_empty_chart("Error", "Dashboard error - check logs")
|
||||
|
||||
return (
|
||||
"Error", "$0.00", "text-muted mb-0 small", "None", "text-muted", "0", "$10,000.00", "OFFLINE",
|
||||
"Error", "$0.00", "text-muted mb-0 small", "$0.00", "None", "text-muted", "0", "$10,000.00", "OFFLINE",
|
||||
empty_fig,
|
||||
[html.P("Error loading training metrics", className="text-danger")],
|
||||
[html.P("Error loading decisions", className="text-danger")],
|
||||
@ -1414,6 +1425,7 @@ class TradingDashboard:
|
||||
decision['mexc_executed'] = mexc_success
|
||||
|
||||
# Calculate position size based on confidence and configuration
|
||||
current_price = decision.get('price', 0)
|
||||
if current_price and current_price > 0:
|
||||
# Get position sizing from trading executor configuration
|
||||
if self.trading_executor:
|
||||
@ -1756,9 +1768,12 @@ class TradingDashboard:
|
||||
if not self.closed_trades:
|
||||
return [html.P("No closed trades yet", className="text-muted text-center")]
|
||||
|
||||
# Create table rows for recent closed trades
|
||||
# Create table rows for recent closed trades (newest first)
|
||||
table_rows = []
|
||||
for trade in self.closed_trades[-20:]: # Show last 20 trades
|
||||
recent_trades = self.closed_trades[-20:] # Get last 20 trades
|
||||
recent_trades.reverse() # Newest first
|
||||
|
||||
for trade in recent_trades:
|
||||
# Determine row color based on P&L
|
||||
row_class = "table-success" if trade['net_pnl'] >= 0 else "table-danger"
|
||||
|
||||
@ -1768,12 +1783,18 @@ class TradingDashboard:
|
||||
# Format side color
|
||||
side_color = "text-success" if trade['side'] == 'LONG' else "text-danger"
|
||||
|
||||
# Format position size
|
||||
position_size = trade.get('size', 0)
|
||||
size_display = f"{position_size:.4f}" if position_size < 1 else f"{position_size:.2f}"
|
||||
|
||||
table_rows.append(
|
||||
html.Tr([
|
||||
html.Td(f"#{trade['trade_id']}", className="small"),
|
||||
html.Td(trade['side'], className=f"small fw-bold {side_color}"),
|
||||
html.Td(size_display, className="small text-info"),
|
||||
html.Td(f"${trade['entry_price']:.2f}", className="small"),
|
||||
html.Td(f"${trade['exit_price']:.2f}", className="small"),
|
||||
html.Td(f"${trade.get('fees', 0):.2f}", className="small text-warning"),
|
||||
html.Td(f"${trade['net_pnl']:.2f}", className="small fw-bold"),
|
||||
html.Td(duration_str, className="small"),
|
||||
html.Td("✓" if trade.get('mexc_executed', False) else "SIM",
|
||||
@ -1787,8 +1808,10 @@ class TradingDashboard:
|
||||
html.Tr([
|
||||
html.Th("ID", className="small"),
|
||||
html.Th("Side", className="small"),
|
||||
html.Th("Size", className="small"),
|
||||
html.Th("Entry", className="small"),
|
||||
html.Th("Exit", className="small"),
|
||||
html.Th("Fees", className="small"),
|
||||
html.Th("P&L", className="small"),
|
||||
html.Th("Duration", className="small"),
|
||||
html.Th("MEXC", className="small")
|
||||
@ -1801,12 +1824,14 @@ class TradingDashboard:
|
||||
total_trades = len(self.closed_trades)
|
||||
winning_trades = len([t for t in self.closed_trades if t['net_pnl'] > 0])
|
||||
total_pnl = sum(t['net_pnl'] for t in self.closed_trades)
|
||||
total_fees_closed = sum(t.get('fees', 0) for t in self.closed_trades)
|
||||
win_rate = (winning_trades / total_trades * 100) if total_trades > 0 else 0
|
||||
|
||||
summary = html.Div([
|
||||
html.Small([
|
||||
html.Strong(f"Total: {total_trades} | "),
|
||||
html.Span(f"Win Rate: {win_rate:.1f}% | ", className="text-info"),
|
||||
html.Span(f"Fees: ${total_fees_closed:.2f} | ", className="text-warning"),
|
||||
html.Span(f"Total P&L: ${total_pnl:.2f}",
|
||||
className="text-success" if total_pnl >= 0 else "text-danger")
|
||||
], className="d-block mb-2")
|
||||
|
Reference in New Issue
Block a user