fix 1s 1m chart less candles ;

fix vertical zoom
This commit is contained in:
Dobromir Popov
2025-11-22 18:23:04 +02:00
parent 26cbfd771b
commit 4b93b6fd42
4 changed files with 664 additions and 11 deletions

View File

@@ -2430,13 +2430,14 @@ class RealTrainingAdapter:
if not hasattr(self, 'inference_sessions'):
self.inference_sessions = {}
# Create inference session
# Create inference session with position tracking
self.inference_sessions[inference_id] = {
'model_name': model_name,
'symbol': symbol,
'status': 'running',
'start_time': time.time(),
'signals': [],
'signals': [], # All signals (including rejected ones)
'executed_trades': [], # Only executed trades (open/close positions)
'stop_flag': False,
'live_training_enabled': enable_live_training,
'train_every_candle': train_every_candle,
@@ -2447,7 +2448,13 @@ class RealTrainingAdapter:
'loss': 0.0,
'steps': 0
},
'last_candle_time': None
'last_candle_time': None,
# Position tracking
'position': None, # {'type': 'long/short', 'entry_price': float, 'entry_time': str, 'entry_id': str}
'total_pnl': 0.0,
'win_count': 0,
'loss_count': 0,
'total_trades': 0
}
training_mode = "per-candle" if train_every_candle else ("pivot-based" if enable_live_training else "inference-only")
@@ -3211,13 +3218,39 @@ class RealTrainingAdapter:
'predicted_candle': prediction.get('predicted_candle')
}
# Store signal (all signals, including rejected ones)
session['signals'].append(signal)
# Keep only last 100 signals
if len(session['signals']) > 100:
session['signals'] = session['signals'][-100:]
logger.info(f"Live Signal: {signal['action']} @ {signal['price']:.2f} (conf: {signal['confidence']:.2f})")
# Execute trade logic (only if confidence is high enough and position logic allows)
executed_trade = self._execute_realtime_trade(session, signal, current_price)
if executed_trade:
logger.info(f"Live Trade EXECUTED: {executed_trade['action']} @ {executed_trade['price']:.2f} (conf: {signal['confidence']:.2f})")
# Send executed trade to frontend via WebSocket
if hasattr(self, 'socketio') and self.socketio:
self.socketio.emit('executed_trade', {
'trade': executed_trade,
'position_state': {
'has_position': session['position'] is not None,
'position_type': session['position']['type'] if session['position'] else None,
'entry_price': session['position']['entry_price'] if session['position'] else None,
'unrealized_pnl': self._calculate_unrealized_pnl(session, current_price) if session['position'] else 0.0
},
'session_metrics': {
'total_pnl': session['total_pnl'],
'total_trades': session['total_trades'],
'win_count': session['win_count'],
'loss_count': session['loss_count'],
'win_rate': (session['win_count'] / session['total_trades'] * 100) if session['total_trades'] > 0 else 0
}
})
else:
logger.info(f"Live Signal (NOT executed): {signal['action']} @ {signal['price']:.2f} (conf: {signal['confidence']:.2f}) - {self._get_rejection_reason(session, signal)}")
# Store prediction for visualization
if self.orchestrator and hasattr(self.orchestrator, 'store_transformer_prediction'):
@@ -3250,3 +3283,173 @@ class RealTrainingAdapter:
logger.error(f"Fatal error in inference loop: {e}")
session['status'] = 'error'
session['error'] = str(e)
def _execute_realtime_trade(self, session: Dict, signal: Dict, current_price: float) -> Optional[Dict]:
"""
Execute trade based on signal, respecting position management rules
Rules:
1. Only execute if confidence >= 0.6
2. Only open new position if no position is currently open
3. Close position on opposite signal
4. Track all executed trades for visualization
Returns:
Dict with executed trade info, or None if signal was rejected
"""
action = signal['action']
confidence = signal['confidence']
timestamp = signal['timestamp']
# Rule 1: Confidence threshold
if confidence < 0.6:
return None # Rejected: low confidence
# Rule 2 & 3: Position management
position = session.get('position')
if action == 'BUY':
if position is None:
# Open long position
trade_id = str(uuid.uuid4())[:8]
session['position'] = {
'type': 'long',
'entry_price': current_price,
'entry_time': timestamp,
'entry_id': trade_id,
'signal_confidence': confidence
}
executed_trade = {
'trade_id': trade_id,
'action': 'OPEN_LONG',
'price': current_price,
'timestamp': timestamp,
'confidence': confidence
}
session['executed_trades'].append(executed_trade)
return executed_trade
elif position['type'] == 'short':
# Close short position
entry_price = position['entry_price']
pnl = entry_price - current_price # Short profit
pnl_pct = (pnl / entry_price) * 100
executed_trade = {
'trade_id': position['entry_id'],
'action': 'CLOSE_SHORT',
'price': current_price,
'timestamp': timestamp,
'confidence': confidence,
'entry_price': entry_price,
'entry_time': position['entry_time'],
'pnl': pnl,
'pnl_pct': pnl_pct
}
# Update session metrics
session['total_pnl'] += pnl
session['total_trades'] += 1
if pnl > 0:
session['win_count'] += 1
else:
session['loss_count'] += 1
session['position'] = None
session['executed_trades'].append(executed_trade)
logger.info(f"Position CLOSED: SHORT @ {current_price:.2f}, PnL=${pnl:.2f} ({pnl_pct:+.2f}%)")
return executed_trade
elif action == 'SELL':
if position is None:
# Open short position
trade_id = str(uuid.uuid4())[:8]
session['position'] = {
'type': 'short',
'entry_price': current_price,
'entry_time': timestamp,
'entry_id': trade_id,
'signal_confidence': confidence
}
executed_trade = {
'trade_id': trade_id,
'action': 'OPEN_SHORT',
'price': current_price,
'timestamp': timestamp,
'confidence': confidence
}
session['executed_trades'].append(executed_trade)
return executed_trade
elif position['type'] == 'long':
# Close long position
entry_price = position['entry_price']
pnl = current_price - entry_price # Long profit
pnl_pct = (pnl / entry_price) * 100
executed_trade = {
'trade_id': position['entry_id'],
'action': 'CLOSE_LONG',
'price': current_price,
'timestamp': timestamp,
'confidence': confidence,
'entry_price': entry_price,
'entry_time': position['entry_time'],
'pnl': pnl,
'pnl_pct': pnl_pct
}
# Update session metrics
session['total_pnl'] += pnl
session['total_trades'] += 1
if pnl > 0:
session['win_count'] += 1
else:
session['loss_count'] += 1
session['position'] = None
session['executed_trades'].append(executed_trade)
logger.info(f"Position CLOSED: LONG @ {current_price:.2f}, PnL=${pnl:.2f} ({pnl_pct:+.2f}%)")
return executed_trade
# HOLD or position already open in same direction
return None
def _get_rejection_reason(self, session: Dict, signal: Dict) -> str:
"""Get reason why a signal was not executed"""
action = signal['action']
confidence = signal['confidence']
position = session.get('position')
if confidence < 0.6:
return f"Low confidence ({confidence:.2f} < 0.6)"
if action == 'HOLD':
return "HOLD signal (no trade)"
if position:
if action == 'BUY' and position['type'] == 'long':
return "Already in LONG position"
elif action == 'SELL' and position['type'] == 'short':
return "Already in SHORT position"
return "Unknown reason"
def _calculate_unrealized_pnl(self, session: Dict, current_price: float) -> float:
"""Calculate unrealized PnL for open position"""
position = session.get('position')
if not position or not current_price:
return 0.0
entry_price = position['entry_price']
if position['type'] == 'long':
return ((current_price - entry_price) / entry_price) * 100 # Percentage
else: # short
return ((entry_price - current_price) / entry_price) * 100 # Percentage