diff --git a/ANNOTATE/core/real_training_adapter.py b/ANNOTATE/core/real_training_adapter.py index 8d2397d..4c051bf 100644 --- a/ANNOTATE/core/real_training_adapter.py +++ b/ANNOTATE/core/real_training_adapter.py @@ -316,7 +316,14 @@ class RealTrainingAdapter: return None def _create_pivot_training_batch(self, model_inputs: Dict, pivot_event, inference_ref) -> Optional[Dict]: - """Create training batch from inference inputs and pivot event""" + """ + Create training batch from inference inputs and pivot event + + Strategy: Train to execute trades on L2 pivots that align with upper trend + - L2L (support) in UPTREND → BUY + - L2H (resistance) in DOWNTREND → SELL + - Misaligned pivots → HOLD (don't trade against trend) + """ try: import torch @@ -327,15 +334,29 @@ class RealTrainingAdapter: # Get device device = next(iter(batch.values())).device if batch else torch.device('cpu') - # Determine action from pivot type - # L2L, L3L, etc. -> BUY (support levels) - # L2H, L3H, etc. -> SELL (resistance levels) - if pivot_event.pivot_type.endswith('L'): - action = 1 # BUY - elif pivot_event.pivot_type.endswith('H'): - action = 2 # SELL - else: - action = 0 # HOLD + # Get trend direction from pivot event (if available) + trend_direction = getattr(pivot_event, 'trend_direction', 'sideways') + pivot_type = pivot_event.pivot_type + + # Determine action based on pivot type AND trend alignment + # Only trade when pivot aligns with trend + action = 0 # Default: HOLD + + if pivot_type in ['L2L', 'L3L']: # Support levels (lows) + # BUY only if in UPTREND (buying at support in uptrend) + if trend_direction in ['up', 'uptrend', 'UPTREND']: + action = 1 # BUY + logger.info(f"Pivot training: BUY signal at {pivot_type} (aligned with {trend_direction})") + else: + logger.debug(f"Pivot training: HOLD at {pivot_type} (not aligned with {trend_direction})") + + elif pivot_type in ['L2H', 'L3H']: # Resistance levels (highs) + # SELL only if in DOWNTREND (selling at resistance in downtrend) + if trend_direction in ['down', 'downtrend', 'DOWNTREND']: + action = 2 # SELL + logger.info(f"Pivot training: SELL signal at {pivot_type} (aligned with {trend_direction})") + else: + logger.debug(f"Pivot training: HOLD at {pivot_type} (not aligned with {trend_direction})") batch['actions'] = torch.tensor([[action]], dtype=torch.long, device=device) @@ -4824,7 +4845,7 @@ class RealTrainingAdapter: Execute trade based on signal, respecting position management rules Rules: - 1. Only execute if confidence >= 0.6 + 1. Only execute if confidence >= 0.5 (lowered for more learning opportunities) 2. Only open new position if no position is currently open 3. Close position on opposite signal 4. Track all executed trades for visualization @@ -4836,8 +4857,8 @@ class RealTrainingAdapter: confidence = signal['confidence'] timestamp = signal['timestamp'] - # Rule 1: Confidence threshold - if confidence < 0.6: + # Rule 1: Confidence threshold (lowered to 0.5 for more learning opportunities) + if confidence < 0.5: return None # Rejected: low confidence # Rule 2 & 3: Position management @@ -4962,8 +4983,8 @@ class RealTrainingAdapter: confidence = signal['confidence'] position = session.get('position') - if confidence < 0.6: - return f"Low confidence ({confidence:.2f} < 0.6)" + if confidence < 0.5: + return f"Low confidence ({confidence:.2f} < 0.5)" if action == 'HOLD': return "HOLD signal (no trade)" diff --git a/ANNOTATE/web/static/js/chart_manager.js b/ANNOTATE/web/static/js/chart_manager.js index efdc89d..cad0d30 100644 --- a/ANNOTATE/web/static/js/chart_manager.js +++ b/ANNOTATE/web/static/js/chart_manager.js @@ -3863,7 +3863,7 @@ class ChartManager { // Update confidence const confPct = (confidence * 100).toFixed(0); signalConf.textContent = `${confPct}%`; - signalConf.style.color = confidence >= 0.6 ? '#10b981' : '#9ca3af'; + signalConf.style.color = confidence >= 0.5 ? '#10b981' : '#9ca3af'; } catch (error) { console.error(`Error updating signal banner for ${timeframe}:`, error); diff --git a/ANNOTATE/web/templates/components/training_panel.html b/ANNOTATE/web/templates/components/training_panel.html index 1f41a60..478d715 100644 --- a/ANNOTATE/web/templates/components/training_panel.html +++ b/ANNOTATE/web/templates/components/training_panel.html @@ -1135,53 +1135,82 @@ } function updatePnLTracking(action, currentPrice, timestamp) { - // Simple trading simulation: BUY opens long, SELL opens short, HOLD closes positions - if (action === 'BUY' && pnlTracker.positions.length === 0) { - // Open long position - pnlTracker.positions.push({ - action: 'BUY', - entryPrice: currentPrice, - entryTime: timestamp, - size: pnlTracker.positionSize - }); - } else if (action === 'SELL' && pnlTracker.positions.length === 0) { - // Open short position - pnlTracker.positions.push({ - action: 'SELL', - entryPrice: currentPrice, - entryTime: timestamp, - size: pnlTracker.positionSize - }); - } else if (action === 'HOLD' && pnlTracker.positions.length > 0) { - // Close all positions - pnlTracker.positions.forEach(pos => { - let pnl = 0; - if (pos.action === 'BUY') { - // Long: profit if price went up - pnl = (currentPrice - pos.entryPrice) / pos.entryPrice * pos.size; - } else if (pos.action === 'SELL') { - // Short: profit if price went down - pnl = (pos.entryPrice - currentPrice) / pos.entryPrice * pos.size; - } + // Paper trading simulation with proper position management + // Rules: + // 1. BUY: Close SHORT if exists, then open LONG + // 2. SELL: Close LONG if exists, then open SHORT + // 3. HOLD: Do nothing (keep existing positions) + + const currentPosition = pnlTracker.positions.length > 0 ? pnlTracker.positions[0] : null; + + if (action === 'BUY') { + // Close SHORT position if exists + if (currentPosition && currentPosition.action === 'SELL') { + const pnl = (currentPosition.entryPrice - currentPrice) / currentPosition.entryPrice * currentPosition.size; pnlTracker.closedTrades.push({ - entryPrice: pos.entryPrice, + entryPrice: currentPosition.entryPrice, exitPrice: currentPrice, pnl: pnl, - entryTime: pos.entryTime, - exitTime: timestamp + entryTime: currentPosition.entryTime, + exitTime: timestamp, + type: 'SHORT' }); pnlTracker.totalPnL += pnl; - }); + pnlTracker.positions = []; + + console.log(`[Paper Trading] Closed SHORT @ ${currentPrice.toFixed(2)}, PnL: ${pnl >= 0 ? '+' : ''}${pnl.toFixed(2)}`); + } - pnlTracker.positions = []; + // Open LONG position (if no position or just closed SHORT) + if (pnlTracker.positions.length === 0) { + pnlTracker.positions.push({ + action: 'BUY', + entryPrice: currentPrice, + entryTime: timestamp, + size: pnlTracker.positionSize + }); + console.log(`[Paper Trading] Opened LONG @ ${currentPrice.toFixed(2)}`); + } - // Calculate win rate + } else if (action === 'SELL') { + // Close LONG position if exists + if (currentPosition && currentPosition.action === 'BUY') { + const pnl = (currentPrice - currentPosition.entryPrice) / currentPosition.entryPrice * currentPosition.size; + + pnlTracker.closedTrades.push({ + entryPrice: currentPosition.entryPrice, + exitPrice: currentPrice, + pnl: pnl, + entryTime: currentPosition.entryTime, + exitTime: timestamp, + type: 'LONG' + }); + + pnlTracker.totalPnL += pnl; + pnlTracker.positions = []; + + console.log(`[Paper Trading] Closed LONG @ ${currentPrice.toFixed(2)}, PnL: ${pnl >= 0 ? '+' : ''}${pnl.toFixed(2)}`); + } + + // Open SHORT position (if no position or just closed LONG) + if (pnlTracker.positions.length === 0) { + pnlTracker.positions.push({ + action: 'SELL', + entryPrice: currentPrice, + entryTime: timestamp, + size: pnlTracker.positionSize + }); + console.log(`[Paper Trading] Opened SHORT @ ${currentPrice.toFixed(2)}`); + } + } + // HOLD: Do nothing, keep existing positions + + // Calculate win rate + if (pnlTracker.closedTrades.length > 0) { const wins = pnlTracker.closedTrades.filter(t => t.pnl > 0).length; - pnlTracker.winRate = pnlTracker.closedTrades.length > 0 - ? (wins / pnlTracker.closedTrades.length * 100) - : 0; + pnlTracker.winRate = (wins / pnlTracker.closedTrades.length * 100); } // Update PnL display @@ -1192,6 +1221,38 @@ const pnlColor = pnlTracker.totalPnL >= 0 ? 'text-success' : 'text-danger'; const pnlSign = pnlTracker.totalPnL >= 0 ? '+' : ''; + // Update position status in trading panel + const positionStatusEl = document.getElementById('position-status'); + if (positionStatusEl) { + if (pnlTracker.positions.length > 0) { + const pos = pnlTracker.positions[0]; + const posType = pos.action === 'BUY' ? 'LONG' : 'SHORT'; + const posColor = pos.action === 'BUY' ? 'text-success' : 'text-danger'; + positionStatusEl.textContent = posType; + positionStatusEl.className = `fw-bold ${posColor}`; + } else { + positionStatusEl.textContent = 'NO POSITION'; + positionStatusEl.className = 'fw-bold text-info'; + } + } + + // Update session PnL + const sessionPnlEl = document.getElementById('session-pnl'); + if (sessionPnlEl) { + sessionPnlEl.textContent = `${pnlSign}$${pnlTracker.totalPnL.toFixed(2)}`; + sessionPnlEl.className = `fw-bold ${pnlColor}`; + } + + // Update win rate + const winRateEl = document.getElementById('win-rate'); + if (winRateEl) { + const wins = pnlTracker.closedTrades.filter(t => t.pnl > 0).length; + const total = pnlTracker.closedTrades.length; + winRateEl.textContent = total > 0 + ? `${pnlTracker.winRate.toFixed(0)}% (${wins}/${total})` + : '0% (0/0)'; + } + // Update PnL metric const pnlElement = document.getElementById('metric-pnl'); if (pnlElement) {