training fixes

This commit is contained in:
Dobromir Popov
2025-06-26 14:18:04 +03:00
parent b7ccd0f97b
commit 1f47576723
5 changed files with 291 additions and 36 deletions

View File

@ -40,6 +40,7 @@ from threading import Lock
import warnings
from dataclasses import asdict
import math
import subprocess
# Setup logger
logger = logging.getLogger(__name__)
@ -258,18 +259,19 @@ class CleanTradingDashboard:
def _setup_callbacks(self):
"""Setup dashboard callbacks"""
# Callbacks setup - no process killing needed
@self.app.callback(
[Output('current-price', 'children'),
Output('session-pnl', 'children'),
Output('current-position', 'children'),
# Output('leverage-info', 'children'),
Output('trade-count', 'children'),
Output('portfolio-value', 'children'),
Output('mexc-status', 'children')],
[Input('interval-component', 'n_intervals')]
)
def update_metrics(n):
"""Update key metrics"""
"""Update key metrics - FIXED callback mismatch"""
try:
# Sync position from trading executor first
symbol = 'ETH/USDT'
@ -712,27 +714,44 @@ class CleanTradingDashboard:
buy_trades = []
sell_trades = []
for signal in executed_signals[-20:]: # Last 20 executed trades
signal_time = self._get_signal_attribute(signal, 'timestamp')
for signal in executed_signals[-50:]: # Last 50 executed trades (increased from 20)
# Try to get full timestamp first, fall back to string timestamp
signal_time = self._get_signal_attribute(signal, 'full_timestamp')
if not signal_time:
signal_time = self._get_signal_attribute(signal, 'timestamp')
signal_price = self._get_signal_attribute(signal, 'price', 0)
signal_action = self._get_signal_attribute(signal, 'action', 'HOLD')
signal_confidence = self._get_signal_attribute(signal, 'confidence', 0)
if signal_time and signal_price and signal_confidence > 0:
# Convert timestamp if needed
# FIXED: Better timestamp conversion to prevent race conditions
if isinstance(signal_time, str):
try:
# Handle time-only format
# Handle time-only format with current date
if ':' in signal_time and len(signal_time.split(':')) == 3:
signal_time = datetime.now().replace(
hour=int(signal_time.split(':')[0]),
minute=int(signal_time.split(':')[1]),
second=int(signal_time.split(':')[2]),
now = datetime.now()
time_parts = signal_time.split(':')
signal_time = now.replace(
hour=int(time_parts[0]),
minute=int(time_parts[1]),
second=int(time_parts[2]),
microsecond=0
)
# Handle day boundary issues - if signal seems from future, subtract a day
if signal_time > now + timedelta(minutes=5):
signal_time -= timedelta(days=1)
else:
signal_time = pd.to_datetime(signal_time)
except:
except Exception as e:
logger.debug(f"Error parsing timestamp {signal_time}: {e}")
continue
elif not isinstance(signal_time, datetime):
# Convert other timestamp formats to datetime
try:
signal_time = pd.to_datetime(signal_time)
except Exception as e:
logger.debug(f"Error converting timestamp to datetime: {e}")
continue
if signal_action == 'BUY':
@ -797,34 +816,51 @@ class CleanTradingDashboard:
if not self.recent_decisions:
return
# Show ALL signals on the mini chart
all_signals = self.recent_decisions[-50:] # Last 50 signals
# Show ALL signals on the mini chart - MORE SIGNALS for better visibility
all_signals = self.recent_decisions[-100:] # Last 100 signals (increased from 50)
buy_signals = []
sell_signals = []
for signal in all_signals:
signal_time = self._get_signal_attribute(signal, 'timestamp')
# Try to get full timestamp first, fall back to string timestamp
signal_time = self._get_signal_attribute(signal, 'full_timestamp')
if not signal_time:
signal_time = self._get_signal_attribute(signal, 'timestamp')
signal_price = self._get_signal_attribute(signal, 'price', 0)
signal_action = self._get_signal_attribute(signal, 'action', 'HOLD')
signal_confidence = self._get_signal_attribute(signal, 'confidence', 0)
is_executed = self._get_signal_attribute(signal, 'executed', False)
if signal_time and signal_price and signal_confidence and signal_confidence > 0:
# Convert timestamp if needed
# FIXED: Same timestamp conversion as main chart
if isinstance(signal_time, str):
try:
# Handle time-only format
# Handle time-only format with current date
if ':' in signal_time and len(signal_time.split(':')) == 3:
signal_time = datetime.now().replace(
hour=int(signal_time.split(':')[0]),
minute=int(signal_time.split(':')[1]),
second=int(signal_time.split(':')[2]),
now = datetime.now()
time_parts = signal_time.split(':')
signal_time = now.replace(
hour=int(time_parts[0]),
minute=int(time_parts[1]),
second=int(time_parts[2]),
microsecond=0
)
# Handle day boundary issues
if signal_time > now + timedelta(minutes=5):
signal_time -= timedelta(days=1)
else:
signal_time = pd.to_datetime(signal_time)
except:
except Exception as e:
logger.debug(f"Error parsing mini chart timestamp {signal_time}: {e}")
continue
elif not isinstance(signal_time, datetime):
# Convert other timestamp formats to datetime
try:
signal_time = pd.to_datetime(signal_time)
except Exception as e:
logger.debug(f"Error converting mini chart timestamp to datetime: {e}")
continue
signal_data = {
@ -1543,7 +1579,7 @@ class CleanTradingDashboard:
next_pivot_price = recent_low + (price_range * 0.5) # Mid-range target
confidence = base_confidence + cob_confidence_boost
# Calculate time prediction (in minutes)
# Calculate time prediction (in minutes)
try:
recent_closes = [float(x) for x in closes[-20:]]
if len(recent_closes) > 1:
@ -1659,12 +1695,14 @@ class CleanTradingDashboard:
# Don't generate HOLD signals - return None instead
return None
now = datetime.now()
return {
'action': action,
'symbol': symbol,
'price': current_price,
'confidence': confidence,
'timestamp': datetime.now().strftime('%H:%M:%S'),
'timestamp': now.strftime('%H:%M:%S'),
'full_timestamp': now, # Add full timestamp for chart persistence
'size': 0.005,
'reason': f'Momentum signal (s={short_momentum:.4f}, m={medium_momentum:.4f})',
'model': 'Momentum'
@ -1937,9 +1975,11 @@ class CleanTradingDashboard:
logger.warning(f"Failed to capture model inputs with COB data: {e}")
model_inputs = {}
# Create manual trading decision
# Create manual trading decision with FULL TIMESTAMP for chart persistence
now = datetime.now()
decision = {
'timestamp': datetime.now().strftime('%H:%M:%S'),
'timestamp': now.strftime('%H:%M:%S'),
'full_timestamp': now, # Store full datetime for better chart positioning
'action': action,
'confidence': 1.0, # Manual trades have 100% confidence
'price': current_price,
@ -3124,12 +3164,14 @@ class CleanTradingDashboard:
logger.debug(f"Ignoring BTC signal: {symbol}")
return
# Convert orchestrator decision to dashboard format
# Convert orchestrator decision to dashboard format with FULL TIMESTAMP
# Handle both TradingDecision objects and dictionary formats
now = datetime.now()
if hasattr(decision, 'action'):
# This is a TradingDecision object (dataclass)
dashboard_decision = {
'timestamp': datetime.now().strftime('%H:%M:%S'),
'timestamp': now.strftime('%H:%M:%S'),
'full_timestamp': now, # Add full timestamp for chart persistence
'action': decision.action,
'confidence': decision.confidence,
'price': decision.price,
@ -3141,7 +3183,8 @@ class CleanTradingDashboard:
else:
# This is a dictionary format
dashboard_decision = {
'timestamp': datetime.now().strftime('%H:%M:%S'),
'timestamp': now.strftime('%H:%M:%S'),
'full_timestamp': now, # Add full timestamp for chart persistence
'action': decision.get('action', 'UNKNOWN'),
'confidence': decision.get('confidence', 0),
'price': decision.get('price', 0),
@ -3359,7 +3402,7 @@ class CleanTradingDashboard:
if not self.orchestrator:
logger.warning("No orchestrator available for training")
return
# Check if DQN needs training
dqn_status = self._is_model_actually_training('dqn')
if not dqn_status['is_training'] and hasattr(self.orchestrator, 'rl_agent') and self.orchestrator.rl_agent: