minor UI changes

This commit is contained in:
Dobromir Popov
2025-07-02 00:17:18 +03:00
parent 88614bfd19
commit d269a1fe6e
2 changed files with 134 additions and 72 deletions

View File

@ -397,17 +397,26 @@ class CleanTradingDashboard:
@self.app.callback(
Output('price-chart', 'figure'),
[Input('interval-component', 'n_intervals')]
[Input('interval-component', 'n_intervals')],
[State('price-chart', 'relayoutData')]
)
def update_price_chart(n):
"""Update price chart every second (1000ms interval)"""
def update_price_chart(n, relayout_data):
"""Update price chart every second, persisting user zoom/pan"""
try:
return self._create_price_chart('ETH/USDT')
fig = self._create_price_chart('ETH/USDT')
if relayout_data:
if 'xaxis.range[0]' in relayout_data and 'xaxis.range[1]' in relayout_data:
fig.update_xaxes(range=[relayout_data['xaxis.range[0]'], relayout_data['xaxis.range[1]']])
if 'yaxis.range[0]' in relayout_data and 'yaxis.range[1]' in relayout_data:
fig.update_yaxes(range=[relayout_data['yaxis.range[0]'], relayout_data['yaxis.range[1]']])
return fig
except Exception as e:
logger.error(f"Error updating chart: {e}")
return go.Figure().add_annotation(text=f"Chart Error: {str(e)}",
xref="paper", yref="paper",
x=0.5, y=0.5, showarrow=False)
xref="paper", yref="paper",
x=0.5, y=0.5, showarrow=False)
@self.app.callback(
Output('closed-trades-table', 'children'),
@ -1059,7 +1068,7 @@ class CleanTradingDashboard:
mode='markers',
marker=dict(
symbol='diamond',
size=[15 + p['confidence'] * 20 for p in up_predictions],
size=[2 + p['confidence'] * 12 for p in up_predictions],
color=[f'rgba(0, 150, 255, {0.4 + p["confidence"] * 0.6})' for p in up_predictions],
line=dict(width=2, color='darkblue')
),
@ -1084,7 +1093,7 @@ class CleanTradingDashboard:
mode='markers',
marker=dict(
symbol='diamond',
size=[15 + p['confidence'] * 20 for p in down_predictions],
size=[2 + p['confidence'] * 12 for p in down_predictions],
color=[f'rgba(255, 140, 0, {0.4 + p["confidence"] * 0.6})' for p in down_predictions],
line=dict(width=2, color='darkorange')
),
@ -1109,7 +1118,7 @@ class CleanTradingDashboard:
mode='markers',
marker=dict(
symbol='diamond',
size=[12 + p['confidence'] * 15 for p in sideways_predictions],
size=[6 + p['confidence'] * 10 for p in sideways_predictions],
color=[f'rgba(128, 128, 128, {0.3 + p["confidence"] * 0.5})' for p in sideways_predictions],
line=dict(width=1, color='gray')
),
@ -2674,6 +2683,21 @@ class CleanTradingDashboard:
# Sync current position from trading executor first
self._sync_position_from_executor(symbol)
# DEBUG: Log current position state before trade
if self.current_position:
logger.info(f"MANUAL TRADE DEBUG: Current position before {action}: "
f"{self.current_position['side']} {self.current_position['size']:.3f} @ ${self.current_position['price']:.2f}")
else:
logger.info(f"MANUAL TRADE DEBUG: No current position before {action}")
# Log the trading executor's position state
if hasattr(self.trading_executor, 'get_current_position'):
executor_pos = self.trading_executor.get_current_position(symbol)
if executor_pos:
logger.info(f"MANUAL TRADE DEBUG: Executor position: {executor_pos}")
else:
logger.info(f"MANUAL TRADE DEBUG: No position in executor")
# CAPTURE ALL MODEL INPUTS INCLUDING COB DATA FOR RETROSPECTIVE TRAINING
try:
from core.trade_data_manager import TradeDataManager
@ -2727,7 +2751,10 @@ class CleanTradingDashboard:
# Execute through trading executor
try:
logger.info(f"MANUAL TRADE DEBUG: Attempting to execute {action} trade via executor...")
result = self.trading_executor.execute_trade(symbol, action, 0.01) # Small size for testing
logger.info(f"MANUAL TRADE DEBUG: Execute trade result: {result}")
if result:
decision['executed'] = True
decision['execution_time'] = datetime.now() # Track execution time
@ -2736,12 +2763,28 @@ class CleanTradingDashboard:
# Sync position from trading executor after execution
self._sync_position_from_executor(symbol)
# DEBUG: Log position state after trade
if self.current_position:
logger.info(f"MANUAL TRADE DEBUG: Position after {action}: "
f"{self.current_position['side']} {self.current_position['size']:.3f} @ ${self.current_position['price']:.2f}")
else:
logger.info(f"MANUAL TRADE DEBUG: No position after {action} - position was closed")
# Check trading executor's position after execution
if hasattr(self.trading_executor, 'get_current_position'):
executor_pos_after = self.trading_executor.get_current_position(symbol)
if executor_pos_after:
logger.info(f"MANUAL TRADE DEBUG: Executor position after trade: {executor_pos_after}")
else:
logger.info(f"MANUAL TRADE DEBUG: No position in executor after trade")
# Get trade history from executor for completed trades
executor_trades = self.trading_executor.get_trade_history() if hasattr(self.trading_executor, 'get_trade_history') else []
# Only add completed trades to closed_trades (not position opens)
if executor_trades:
latest_trade = executor_trades[-1]
logger.info(f"MANUAL TRADE DEBUG: Latest trade from executor: {latest_trade}")
# Check if this is a completed trade (has exit price/time)
if hasattr(latest_trade, 'exit_time') and latest_trade.exit_time:
trade_record = {
@ -2864,43 +2907,21 @@ class CleanTradingDashboard:
logger.warning(f"Failed to store opening trade as base case: {e}")
else:
decision['executed'] = False
decision['blocked'] = True
decision['block_reason'] = "Trading executor returned False"
logger.warning(f"Manual {action} failed - executor returned False")
decision['block_reason'] = "Trading executor failed"
logger.warning(f"BLOCKED manual {action}: executor returned False")
except Exception as e:
decision['executed'] = False
decision['blocked'] = True
decision['block_reason'] = str(e)
logger.error(f"Manual {action} failed with error: {e}")
logger.error(f"Error executing manual {action}: {e}")
# ENHANCED: Add to recent decisions with PRIORITY INSERTION for better persistence
# Add to recent decisions for dashboard display
self.recent_decisions.append(decision)
# CONSERVATIVE: Keep MORE decisions for longer history - extend to 300 decisions
if len(self.recent_decisions) > 300:
# When trimming, PRESERVE MANUAL TRADES at higher priority
manual_decisions = [d for d in self.recent_decisions if self._get_signal_attribute(d, 'manual', False)]
other_decisions = [d for d in self.recent_decisions if not self._get_signal_attribute(d, 'manual', False)]
# Keep all manual decisions + most recent other decisions
max_other_decisions = 300 - len(manual_decisions)
if max_other_decisions > 0:
trimmed_decisions = manual_decisions + other_decisions[-max_other_decisions:]
else:
# If too many manual decisions, keep most recent ones
trimmed_decisions = manual_decisions[-300:]
self.recent_decisions = trimmed_decisions
logger.debug(f"Trimmed decisions: kept {len(manual_decisions)} manual + {len(trimmed_decisions) - len(manual_decisions)} other")
# LOG the manual trade execution with enhanced details
status = "EXECUTED" if decision['executed'] else ("BLOCKED" if decision['blocked'] else "PENDING")
logger.info(f"[MANUAL-{status}] {action} trade at ${current_price:.2f} - Decision stored with enhanced persistence")
if len(self.recent_decisions) > 200:
self.recent_decisions = self.recent_decisions[-200:]
except Exception as e:
logger.error(f"Error executing manual {action}: {e}")
logger.error(f"Error in manual trade execution: {e}")
# Model input capture moved to core.trade_data_manager.TradeDataManager
@ -3599,6 +3620,7 @@ class CleanTradingDashboard:
if hasattr(self.orchestrator, '_on_cob_dashboard_data'):
try:
self.orchestrator._on_cob_dashboard_data(symbol, history_data)
logger.debug(f"COB data fed to orchestrator for {symbol}")
except Exception as e:
logger.debug(f"Error feeding COB data to orchestrator: {e}")
@ -3676,7 +3698,7 @@ class CleanTradingDashboard:
'training_steps': len(model.losses),
'last_update': datetime.now().isoformat()
})
except Exception as e:
logger.debug(f"Error updating training progress: {e}")
@ -3801,7 +3823,7 @@ class CleanTradingDashboard:
stats[name] = 0.0
return stats
def _connect_to_orchestrator(self):
"""Connect to orchestrator for real trading signals"""
try:
@ -3820,7 +3842,7 @@ class CleanTradingDashboard:
logger.warning("Orchestrator not available or doesn't support callbacks")
except Exception as e:
logger.error(f"Error initiating orchestrator connection: {e}")
async def _on_trading_decision(self, decision):
"""Handle trading decision from orchestrator."""
try:
@ -3839,7 +3861,7 @@ class CleanTradingDashboard:
logger.info(f"[ORCHESTRATOR SIGNAL] Received: {action} for {symbol}")
except Exception as e:
logger.error(f"Error handling trading decision: {e}")
def _initialize_streaming(self):
"""Initialize data streaming"""
try:
@ -3848,7 +3870,7 @@ class CleanTradingDashboard:
logger.info("Data streaming initialized")
except Exception as e:
logger.error(f"Error initializing streaming: {e}")
def _start_websocket_streaming(self):
"""Start WebSocket streaming for real-time data."""
ws_thread = threading.Thread(target=self._ws_worker, daemon=True)
@ -3894,7 +3916,7 @@ class CleanTradingDashboard:
except Exception as e:
logger.error(f"WebSocket worker error: {e}")
self.is_streaming = False
def _start_data_collection(self):
"""Start background data collection"""
data_thread = threading.Thread(target=self._data_worker, daemon=True)
@ -3935,7 +3957,7 @@ class CleanTradingDashboard:
self._start_real_training_system()
except Exception as e:
logger.error(f"Error starting comprehensive training system: {e}")
def _start_real_training_system(self):
"""Start real training system with data collection and actual model training"""
try:
@ -3969,7 +3991,7 @@ class CleanTradingDashboard:
logger.info("TRAINING: Real training system started successfully")
except Exception as e:
logger.error(f"Error starting real training system: {e}")
def _collect_training_data(self) -> List[Dict]:
"""Collect real market data for training"""
try:
@ -4001,7 +4023,7 @@ class CleanTradingDashboard:
except Exception as e:
logger.error(f"Error collecting training data: {e}")
return []
def _perform_real_dqn_training(self, market_data: List[Dict]):
"""Perform actual DQN training with real market experiences"""
try:
@ -4044,7 +4066,7 @@ class CleanTradingDashboard:
logger.info(f"DQN TRAINING: Added {training_samples} experiences, memory size: {len(agent.memory)}")
except Exception as e:
logger.error(f"Error in real DQN training: {e}")
def _perform_real_cnn_training(self, market_data: List[Dict]):
"""Perform actual CNN training with real price prediction"""
try:
@ -4088,7 +4110,7 @@ class CleanTradingDashboard:
logger.info(f"CNN TRAINING: Processed {training_samples} price prediction samples")
except Exception as e:
logger.error(f"Error in real CNN training: {e}")
def _update_training_progress(self, iteration: int):
"""Update training progress and metrics"""
try: