data capture implemented - needed for training
This commit is contained in:
@ -167,8 +167,8 @@ class EnhancedTradingOrchestrator(TradingOrchestrator):
|
|||||||
|
|
||||||
# Initialize Universal Data Adapter for 5 timeseries format
|
# Initialize Universal Data Adapter for 5 timeseries format
|
||||||
self.universal_adapter = UniversalDataAdapter(self.data_provider)
|
self.universal_adapter = UniversalDataAdapter(self.data_provider)
|
||||||
logger.info("🔗 Universal Data Adapter initialized - 5 timeseries format active")
|
logger.info(" Universal Data Adapter initialized - 5 timeseries format active")
|
||||||
logger.info("📊 Timeseries: ETH/USDT(ticks,1m,1h,1d) + BTC/USDT(ticks)")
|
logger.info(" Timeseries: ETH/USDT(ticks,1m,1h,1d) + BTC/USDT(ticks)")
|
||||||
|
|
||||||
# Missing attributes fix - Initialize position tracking and thresholds
|
# Missing attributes fix - Initialize position tracking and thresholds
|
||||||
self.current_positions = {} # Track current positions by symbol
|
self.current_positions = {} # Track current positions by symbol
|
||||||
@ -2597,7 +2597,6 @@ class EnhancedTradingOrchestrator(TradingOrchestrator):
|
|||||||
state_shape=(self.sensitivity_state_size,),
|
state_shape=(self.sensitivity_state_size,),
|
||||||
n_actions=self.sensitivity_action_space,
|
n_actions=self.sensitivity_action_space,
|
||||||
learning_rate=0.001,
|
learning_rate=0.001,
|
||||||
gamma=0.95,
|
|
||||||
epsilon=0.3, # Lower epsilon for more exploitation
|
epsilon=0.3, # Lower epsilon for more exploitation
|
||||||
epsilon_min=0.05,
|
epsilon_min=0.05,
|
||||||
epsilon_decay=0.995,
|
epsilon_decay=0.995,
|
||||||
|
239
test_training_status.py
Normal file
239
test_training_status.py
Normal file
@ -0,0 +1,239 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Training Status Audit - Check if models are actively training
|
||||||
|
"""
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
from pathlib import Path
|
||||||
|
sys.path.append(str(Path('.').absolute()))
|
||||||
|
|
||||||
|
from core.enhanced_orchestrator import EnhancedTradingOrchestrator
|
||||||
|
from core.data_provider import DataProvider
|
||||||
|
|
||||||
|
async def check_training_status():
|
||||||
|
print("=" * 70)
|
||||||
|
print("TRAINING STATUS AUDIT")
|
||||||
|
print("=" * 70)
|
||||||
|
|
||||||
|
try:
|
||||||
|
data_provider = DataProvider()
|
||||||
|
orchestrator = EnhancedTradingOrchestrator(
|
||||||
|
data_provider=data_provider,
|
||||||
|
symbols=['ETH/USDT', 'BTC/USDT'],
|
||||||
|
enhanced_rl_training=True
|
||||||
|
)
|
||||||
|
|
||||||
|
print(f"✓ Enhanced Orchestrator created")
|
||||||
|
|
||||||
|
# 1. Check DQN Agent Status
|
||||||
|
print("\n--- DQN AGENT STATUS ---")
|
||||||
|
if hasattr(orchestrator, 'sensitivity_dqn_agent'):
|
||||||
|
dqn_agent = orchestrator.sensitivity_dqn_agent
|
||||||
|
print(f"DQN Agent: {dqn_agent}")
|
||||||
|
|
||||||
|
if dqn_agent is not None:
|
||||||
|
print(f"DQN Agent Type: {type(dqn_agent)}")
|
||||||
|
|
||||||
|
# Check if it has training stats
|
||||||
|
if hasattr(dqn_agent, 'get_enhanced_training_stats'):
|
||||||
|
try:
|
||||||
|
stats = dqn_agent.get_enhanced_training_stats()
|
||||||
|
print(f"DQN Training Stats: {stats}")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error getting DQN stats: {e}")
|
||||||
|
|
||||||
|
# Check memory and training status
|
||||||
|
if hasattr(dqn_agent, 'memory'):
|
||||||
|
print(f"DQN Memory Size: {len(dqn_agent.memory)}")
|
||||||
|
if hasattr(dqn_agent, 'batch_size'):
|
||||||
|
print(f"DQN Batch Size: {dqn_agent.batch_size}")
|
||||||
|
if hasattr(dqn_agent, 'epsilon'):
|
||||||
|
print(f"DQN Epsilon: {dqn_agent.epsilon}")
|
||||||
|
|
||||||
|
# Check if training is possible
|
||||||
|
can_train = hasattr(dqn_agent, 'replay') and hasattr(dqn_agent, 'memory')
|
||||||
|
print(f"DQN Can Train: {can_train}")
|
||||||
|
|
||||||
|
else:
|
||||||
|
print("❌ DQN Agent is None - needs initialization")
|
||||||
|
try:
|
||||||
|
orchestrator._initialize_sensitivity_dqn()
|
||||||
|
print("✓ DQN Agent initialized")
|
||||||
|
dqn_agent = orchestrator.sensitivity_dqn_agent
|
||||||
|
print(f"New DQN Agent: {type(dqn_agent)}")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error initializing DQN: {e}")
|
||||||
|
else:
|
||||||
|
print("❌ No DQN agent attribute found")
|
||||||
|
|
||||||
|
# 2. Check CNN Status
|
||||||
|
print("\n--- CNN MODEL STATUS ---")
|
||||||
|
if hasattr(orchestrator, 'williams_structure'):
|
||||||
|
williams = orchestrator.williams_structure
|
||||||
|
print(f"Williams CNN: {williams}")
|
||||||
|
|
||||||
|
if williams is not None:
|
||||||
|
print(f"Williams Type: {type(williams)}")
|
||||||
|
|
||||||
|
# Check if it has training stats
|
||||||
|
if hasattr(williams, 'get_training_stats'):
|
||||||
|
try:
|
||||||
|
stats = williams.get_training_stats()
|
||||||
|
print(f"CNN Training Stats: {stats}")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error getting CNN stats: {e}")
|
||||||
|
|
||||||
|
# Check if it's enabled
|
||||||
|
print(f"Williams Enabled: {getattr(orchestrator, 'williams_enabled', False)}")
|
||||||
|
else:
|
||||||
|
print("❌ Williams CNN is None")
|
||||||
|
else:
|
||||||
|
print("❌ No Williams CNN attribute found")
|
||||||
|
|
||||||
|
# 3. Check COB Integration Training
|
||||||
|
print("\n--- COB INTEGRATION STATUS ---")
|
||||||
|
if hasattr(orchestrator, 'cob_integration'):
|
||||||
|
cob = orchestrator.cob_integration
|
||||||
|
print(f"COB Integration: {cob}")
|
||||||
|
|
||||||
|
if cob is not None:
|
||||||
|
print(f"COB Type: {type(cob)}")
|
||||||
|
|
||||||
|
# Check if COB is started
|
||||||
|
cob_active = getattr(orchestrator, 'cob_integration_active', False)
|
||||||
|
print(f"COB Active: {cob_active}")
|
||||||
|
|
||||||
|
# Try to start COB if not active
|
||||||
|
if not cob_active:
|
||||||
|
print("Starting COB integration...")
|
||||||
|
try:
|
||||||
|
await orchestrator.start_cob_integration()
|
||||||
|
print("✓ COB integration started")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error starting COB: {e}")
|
||||||
|
|
||||||
|
# Get COB stats
|
||||||
|
try:
|
||||||
|
stats = cob.get_statistics()
|
||||||
|
print(f"COB Statistics: {stats}")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error getting COB stats: {e}")
|
||||||
|
|
||||||
|
# Check COB feature generation
|
||||||
|
cob_features = getattr(orchestrator, 'latest_cob_features', {})
|
||||||
|
print(f"COB Features Available: {list(cob_features.keys())}")
|
||||||
|
else:
|
||||||
|
print("❌ COB Integration is None")
|
||||||
|
else:
|
||||||
|
print("❌ No COB integration attribute found")
|
||||||
|
|
||||||
|
# 4. Check Training Queues and Learning
|
||||||
|
print("\n--- TRAINING ACTIVITY STATUS ---")
|
||||||
|
|
||||||
|
# Check extrema trainer
|
||||||
|
if hasattr(orchestrator, 'extrema_trainer'):
|
||||||
|
extrema = orchestrator.extrema_trainer
|
||||||
|
print(f"Extrema Trainer: {extrema}")
|
||||||
|
if extrema and hasattr(extrema, 'get_training_stats'):
|
||||||
|
try:
|
||||||
|
stats = extrema.get_training_stats()
|
||||||
|
print(f"Extrema Training Stats: {stats}")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error getting extrema stats: {e}")
|
||||||
|
|
||||||
|
# Check negative case trainer
|
||||||
|
if hasattr(orchestrator, 'negative_case_trainer'):
|
||||||
|
negative = orchestrator.negative_case_trainer
|
||||||
|
print(f"Negative Case Trainer: {negative}")
|
||||||
|
|
||||||
|
# Check recent decisions and training queues
|
||||||
|
if hasattr(orchestrator, 'recent_decisions'):
|
||||||
|
recent_decisions = orchestrator.recent_decisions
|
||||||
|
print(f"Recent Decisions: {len(recent_decisions) if recent_decisions else 0}")
|
||||||
|
|
||||||
|
if hasattr(orchestrator, 'sensitivity_learning_queue'):
|
||||||
|
queue = orchestrator.sensitivity_learning_queue
|
||||||
|
print(f"Sensitivity Learning Queue: {len(queue) if queue else 0}")
|
||||||
|
|
||||||
|
if hasattr(orchestrator, 'rl_evaluation_queue'):
|
||||||
|
queue = orchestrator.rl_evaluation_queue
|
||||||
|
print(f"RL Evaluation Queue: {len(queue) if queue else 0}")
|
||||||
|
|
||||||
|
# 5. Test Signal Generation and Training
|
||||||
|
print("\n--- TESTING SIGNAL GENERATION ---")
|
||||||
|
|
||||||
|
# Generate a test decision to see if training is triggered
|
||||||
|
try:
|
||||||
|
print("Making coordinated decisions...")
|
||||||
|
decisions = await orchestrator.make_coordinated_decisions()
|
||||||
|
print(f"Decisions Generated: {len(decisions) if decisions else 0}")
|
||||||
|
|
||||||
|
for symbol, decision in decisions.items():
|
||||||
|
if decision:
|
||||||
|
print(f"{symbol}: {decision.action} (confidence: {decision.confidence:.3f})")
|
||||||
|
else:
|
||||||
|
print(f"{symbol}: No decision")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error making decisions: {e}")
|
||||||
|
|
||||||
|
# 6. Wait and check for training activity
|
||||||
|
print("\n--- MONITORING TRAINING ACTIVITY (10 seconds) ---")
|
||||||
|
|
||||||
|
initial_stats = {}
|
||||||
|
|
||||||
|
# Capture initial state
|
||||||
|
if hasattr(orchestrator, 'sensitivity_dqn_agent') and orchestrator.sensitivity_dqn_agent:
|
||||||
|
if hasattr(orchestrator.sensitivity_dqn_agent, 'memory'):
|
||||||
|
initial_stats['dqn_memory'] = len(orchestrator.sensitivity_dqn_agent.memory)
|
||||||
|
|
||||||
|
# Wait and monitor
|
||||||
|
for i in range(10):
|
||||||
|
await asyncio.sleep(1)
|
||||||
|
print(f"Monitoring... {i+1}/10")
|
||||||
|
|
||||||
|
# Check if any training happened
|
||||||
|
if hasattr(orchestrator, 'sensitivity_dqn_agent') and orchestrator.sensitivity_dqn_agent:
|
||||||
|
if hasattr(orchestrator.sensitivity_dqn_agent, 'memory'):
|
||||||
|
current_memory = len(orchestrator.sensitivity_dqn_agent.memory)
|
||||||
|
if current_memory != initial_stats.get('dqn_memory', 0):
|
||||||
|
print(f"🔥 DQN training detected! Memory: {initial_stats.get('dqn_memory', 0)} -> {current_memory}")
|
||||||
|
|
||||||
|
# Final status
|
||||||
|
print("\n--- FINAL TRAINING STATUS ---")
|
||||||
|
|
||||||
|
# Check if models are actively learning
|
||||||
|
dqn_learning = False
|
||||||
|
cnn_learning = False
|
||||||
|
cob_learning = False
|
||||||
|
|
||||||
|
if hasattr(orchestrator, 'sensitivity_dqn_agent') and orchestrator.sensitivity_dqn_agent:
|
||||||
|
memory_size = getattr(orchestrator.sensitivity_dqn_agent, 'memory', [])
|
||||||
|
batch_size = getattr(orchestrator.sensitivity_dqn_agent, 'batch_size', 32)
|
||||||
|
dqn_learning = len(memory_size) >= batch_size if hasattr(memory_size, '__len__') else False
|
||||||
|
|
||||||
|
print(f"DQN Learning Ready: {dqn_learning}")
|
||||||
|
print(f"CNN Learning Ready: {cnn_learning}")
|
||||||
|
print(f"COB Learning Ready: {cob_learning}")
|
||||||
|
|
||||||
|
# GPU Utilization Check
|
||||||
|
try:
|
||||||
|
import GPUtil
|
||||||
|
gpus = GPUtil.getGPUs()
|
||||||
|
if gpus:
|
||||||
|
for gpu in gpus:
|
||||||
|
print(f"GPU {gpu.id}: {gpu.load*100:.1f}% utilization, {gpu.memoryUtil*100:.1f}% memory")
|
||||||
|
else:
|
||||||
|
print("No GPUs detected")
|
||||||
|
except ImportError:
|
||||||
|
print("GPUtil not available - cannot check GPU status")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error in training status check: {e}")
|
||||||
|
import traceback
|
||||||
|
traceback.print_exc()
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
asyncio.run(check_training_status())
|
13624
training_data/trade_ETHUSDT_20250625_142057.json
Normal file
13624
training_data/trade_ETHUSDT_20250625_142057.json
Normal file
File diff suppressed because it is too large
Load Diff
@ -1540,6 +1540,9 @@ class CleanTradingDashboard:
|
|||||||
logger.warning("No current price available for manual trade")
|
logger.warning("No current price available for manual trade")
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# CAPTURE ALL MODEL INPUTS FOR COLD START TRAINING
|
||||||
|
model_inputs = self._capture_comprehensive_model_inputs(symbol, action, current_price)
|
||||||
|
|
||||||
# Create manual trading decision
|
# Create manual trading decision
|
||||||
decision = {
|
decision = {
|
||||||
'timestamp': datetime.now().strftime('%H:%M:%S'),
|
'timestamp': datetime.now().strftime('%H:%M:%S'),
|
||||||
@ -1551,7 +1554,8 @@ class CleanTradingDashboard:
|
|||||||
'executed': False,
|
'executed': False,
|
||||||
'blocked': False,
|
'blocked': False,
|
||||||
'manual': True,
|
'manual': True,
|
||||||
'reason': f'Manual {action} button'
|
'reason': f'Manual {action} button',
|
||||||
|
'model_inputs': model_inputs # Store for training
|
||||||
}
|
}
|
||||||
|
|
||||||
# Execute through trading executor
|
# Execute through trading executor
|
||||||
@ -1561,7 +1565,7 @@ class CleanTradingDashboard:
|
|||||||
decision['executed'] = True
|
decision['executed'] = True
|
||||||
logger.info(f"Manual {action} executed at ${current_price:.2f}")
|
logger.info(f"Manual {action} executed at ${current_price:.2f}")
|
||||||
|
|
||||||
# Create a trade record for tracking
|
# Create a trade record for tracking WITH model inputs
|
||||||
trade_record = {
|
trade_record = {
|
||||||
'symbol': symbol,
|
'symbol': symbol,
|
||||||
'side': action,
|
'side': action,
|
||||||
@ -1572,12 +1576,21 @@ class CleanTradingDashboard:
|
|||||||
'exit_time': datetime.now(),
|
'exit_time': datetime.now(),
|
||||||
'pnl': 0.0, # Manual test trades have 0 P&L initially
|
'pnl': 0.0, # Manual test trades have 0 P&L initially
|
||||||
'fees': 0.0,
|
'fees': 0.0,
|
||||||
'confidence': 1.0
|
'confidence': 1.0,
|
||||||
|
'trade_type': 'manual',
|
||||||
|
'model_inputs_at_entry': model_inputs, # CRITICAL: Store model inputs for training
|
||||||
|
'entry_market_state': model_inputs.get('market_state', {}),
|
||||||
|
'entry_features': model_inputs.get('features', {}),
|
||||||
|
'entry_predictions': model_inputs.get('predictions', {}),
|
||||||
|
'training_ready': True # Mark as ready for cold start training
|
||||||
}
|
}
|
||||||
|
|
||||||
# Add to closed trades for display
|
# Add to closed trades for display
|
||||||
self.closed_trades.append(trade_record)
|
self.closed_trades.append(trade_record)
|
||||||
|
|
||||||
|
# Store for cold start training when trade closes
|
||||||
|
self._store_trade_for_training(trade_record)
|
||||||
|
|
||||||
# Update session metrics
|
# Update session metrics
|
||||||
if action == 'BUY':
|
if action == 'BUY':
|
||||||
self.session_pnl += 0.0 # No immediate P&L for entry
|
self.session_pnl += 0.0 # No immediate P&L for entry
|
||||||
@ -1587,6 +1600,9 @@ class CleanTradingDashboard:
|
|||||||
self.session_pnl += demo_pnl
|
self.session_pnl += demo_pnl
|
||||||
trade_record['pnl'] = demo_pnl
|
trade_record['pnl'] = demo_pnl
|
||||||
|
|
||||||
|
# TRIGGER COLD START TRAINING on profitable demo trade
|
||||||
|
self._trigger_cold_start_training(trade_record, demo_pnl)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
decision['executed'] = False
|
decision['executed'] = False
|
||||||
decision['blocked'] = True
|
decision['blocked'] = True
|
||||||
@ -1609,6 +1625,411 @@ class CleanTradingDashboard:
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Error executing manual {action}: {e}")
|
logger.error(f"Error executing manual {action}: {e}")
|
||||||
|
|
||||||
|
def _capture_comprehensive_model_inputs(self, symbol: str, action: str, current_price: float) -> Dict[str, Any]:
|
||||||
|
"""Capture comprehensive model inputs for cold start training"""
|
||||||
|
try:
|
||||||
|
logger.info(f"Capturing model inputs for {action} trade on {symbol} at ${current_price:.2f}")
|
||||||
|
|
||||||
|
model_inputs = {
|
||||||
|
'timestamp': datetime.now().isoformat(),
|
||||||
|
'symbol': symbol,
|
||||||
|
'action': action,
|
||||||
|
'price': current_price,
|
||||||
|
'capture_type': 'trade_execution'
|
||||||
|
}
|
||||||
|
|
||||||
|
# 1. Market State Features
|
||||||
|
try:
|
||||||
|
market_state = self._get_comprehensive_market_state(symbol, current_price)
|
||||||
|
model_inputs['market_state'] = market_state
|
||||||
|
logger.debug(f"Captured market state: {len(market_state)} features")
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning(f"Error capturing market state: {e}")
|
||||||
|
model_inputs['market_state'] = {}
|
||||||
|
|
||||||
|
# 2. CNN Features and Predictions
|
||||||
|
try:
|
||||||
|
cnn_data = self._get_cnn_features_and_predictions(symbol)
|
||||||
|
model_inputs['cnn_features'] = cnn_data.get('features', {})
|
||||||
|
model_inputs['cnn_predictions'] = cnn_data.get('predictions', {})
|
||||||
|
logger.debug(f"Captured CNN data: {len(cnn_data)} items")
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning(f"Error capturing CNN data: {e}")
|
||||||
|
model_inputs['cnn_features'] = {}
|
||||||
|
model_inputs['cnn_predictions'] = {}
|
||||||
|
|
||||||
|
# 3. DQN/RL State Features
|
||||||
|
try:
|
||||||
|
dqn_state = self._get_dqn_state_features(symbol, current_price)
|
||||||
|
model_inputs['dqn_state'] = dqn_state
|
||||||
|
logger.debug(f"Captured DQN state: {len(dqn_state) if dqn_state else 0} features")
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning(f"Error capturing DQN state: {e}")
|
||||||
|
model_inputs['dqn_state'] = {}
|
||||||
|
|
||||||
|
# 4. COB (Order Book) Features
|
||||||
|
try:
|
||||||
|
cob_data = self._get_cob_features_for_training(symbol)
|
||||||
|
model_inputs['cob_features'] = cob_data
|
||||||
|
logger.debug(f"Captured COB features: {len(cob_data) if cob_data else 0} features")
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning(f"Error capturing COB features: {e}")
|
||||||
|
model_inputs['cob_features'] = {}
|
||||||
|
|
||||||
|
# 5. Technical Indicators
|
||||||
|
try:
|
||||||
|
technical_indicators = self._get_technical_indicators(symbol)
|
||||||
|
model_inputs['technical_indicators'] = technical_indicators
|
||||||
|
logger.debug(f"Captured technical indicators: {len(technical_indicators)} indicators")
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning(f"Error capturing technical indicators: {e}")
|
||||||
|
model_inputs['technical_indicators'] = {}
|
||||||
|
|
||||||
|
# 6. Recent Price History (for context)
|
||||||
|
try:
|
||||||
|
price_history = self._get_recent_price_history(symbol, periods=50)
|
||||||
|
model_inputs['price_history'] = price_history
|
||||||
|
logger.debug(f"Captured price history: {len(price_history)} periods")
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning(f"Error capturing price history: {e}")
|
||||||
|
model_inputs['price_history'] = []
|
||||||
|
|
||||||
|
total_features = sum(len(v) if isinstance(v, (dict, list)) else 1 for v in model_inputs.values())
|
||||||
|
logger.info(f"✅ Captured {total_features} total features for cold start training")
|
||||||
|
|
||||||
|
return model_inputs
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error capturing model inputs: {e}")
|
||||||
|
return {
|
||||||
|
'timestamp': datetime.now().isoformat(),
|
||||||
|
'symbol': symbol,
|
||||||
|
'action': action,
|
||||||
|
'price': current_price,
|
||||||
|
'error': str(e)
|
||||||
|
}
|
||||||
|
|
||||||
|
def _get_comprehensive_market_state(self, symbol: str, current_price: float) -> Dict[str, float]:
|
||||||
|
"""Get comprehensive market state features"""
|
||||||
|
try:
|
||||||
|
market_state = {}
|
||||||
|
|
||||||
|
# Price-based features
|
||||||
|
market_state['current_price'] = current_price
|
||||||
|
|
||||||
|
# Get historical data for features
|
||||||
|
df = self.data_provider.get_historical_data(symbol, '1m', limit=100)
|
||||||
|
if df is not None and not df.empty:
|
||||||
|
prices = df['close'].values
|
||||||
|
volumes = df['volume'].values
|
||||||
|
|
||||||
|
# Price features
|
||||||
|
market_state['price_sma_5'] = float(prices[-5:].mean())
|
||||||
|
market_state['price_sma_20'] = float(prices[-20:].mean())
|
||||||
|
market_state['price_std_20'] = float(prices[-20:].std())
|
||||||
|
market_state['price_rsi'] = self._calculate_rsi(prices, 14)
|
||||||
|
|
||||||
|
# Volume features
|
||||||
|
market_state['volume_current'] = float(volumes[-1])
|
||||||
|
market_state['volume_sma_20'] = float(volumes[-20:].mean())
|
||||||
|
market_state['volume_ratio'] = float(volumes[-1] / volumes[-20:].mean())
|
||||||
|
|
||||||
|
# Trend features
|
||||||
|
market_state['price_momentum_5'] = float((prices[-1] - prices[-5]) / prices[-5])
|
||||||
|
market_state['price_momentum_20'] = float((prices[-1] - prices[-20]) / prices[-20])
|
||||||
|
|
||||||
|
# Add timestamp features
|
||||||
|
now = datetime.now()
|
||||||
|
market_state['hour_of_day'] = now.hour
|
||||||
|
market_state['minute_of_hour'] = now.minute
|
||||||
|
market_state['day_of_week'] = now.weekday()
|
||||||
|
|
||||||
|
return market_state
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning(f"Error getting market state: {e}")
|
||||||
|
return {'current_price': current_price}
|
||||||
|
|
||||||
|
def _calculate_rsi(self, prices, period=14):
|
||||||
|
"""Calculate RSI indicator"""
|
||||||
|
try:
|
||||||
|
deltas = np.diff(prices)
|
||||||
|
gains = np.where(deltas > 0, deltas, 0)
|
||||||
|
losses = np.where(deltas < 0, -deltas, 0)
|
||||||
|
|
||||||
|
avg_gain = np.mean(gains[-period:])
|
||||||
|
avg_loss = np.mean(losses[-period:])
|
||||||
|
|
||||||
|
if avg_loss == 0:
|
||||||
|
return 100.0
|
||||||
|
|
||||||
|
rs = avg_gain / avg_loss
|
||||||
|
rsi = 100 - (100 / (1 + rs))
|
||||||
|
return float(rsi)
|
||||||
|
except:
|
||||||
|
return 50.0 # Neutral RSI
|
||||||
|
|
||||||
|
def _get_cnn_features_and_predictions(self, symbol: str) -> Dict[str, Any]:
|
||||||
|
"""Get CNN features and predictions from orchestrator"""
|
||||||
|
try:
|
||||||
|
cnn_data = {}
|
||||||
|
|
||||||
|
# Get CNN features if available
|
||||||
|
if hasattr(self.orchestrator, 'latest_cnn_features'):
|
||||||
|
cnn_features = getattr(self.orchestrator, 'latest_cnn_features', {}).get(symbol)
|
||||||
|
if cnn_features is not None:
|
||||||
|
cnn_data['features'] = cnn_features.tolist() if hasattr(cnn_features, 'tolist') else cnn_features
|
||||||
|
|
||||||
|
# Get CNN predictions if available
|
||||||
|
if hasattr(self.orchestrator, 'latest_cnn_predictions'):
|
||||||
|
cnn_predictions = getattr(self.orchestrator, 'latest_cnn_predictions', {}).get(symbol)
|
||||||
|
if cnn_predictions is not None:
|
||||||
|
cnn_data['predictions'] = cnn_predictions.tolist() if hasattr(cnn_predictions, 'tolist') else cnn_predictions
|
||||||
|
|
||||||
|
return cnn_data
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.debug(f"Error getting CNN data: {e}")
|
||||||
|
return {}
|
||||||
|
|
||||||
|
def _get_dqn_state_features(self, symbol: str, current_price: float) -> Dict[str, Any]:
|
||||||
|
"""Get DQN state features from orchestrator"""
|
||||||
|
try:
|
||||||
|
# Get DQN state from orchestrator if available
|
||||||
|
if hasattr(self.orchestrator, 'build_comprehensive_rl_state'):
|
||||||
|
rl_state = self.orchestrator.build_comprehensive_rl_state(symbol)
|
||||||
|
if rl_state is not None:
|
||||||
|
return {
|
||||||
|
'state_vector': rl_state.tolist() if hasattr(rl_state, 'tolist') else rl_state,
|
||||||
|
'state_size': len(rl_state) if hasattr(rl_state, '__len__') else 0
|
||||||
|
}
|
||||||
|
|
||||||
|
return {}
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.debug(f"Error getting DQN state: {e}")
|
||||||
|
return {}
|
||||||
|
|
||||||
|
def _get_cob_features_for_training(self, symbol: str) -> Dict[str, Any]:
|
||||||
|
"""Get COB features for training"""
|
||||||
|
try:
|
||||||
|
cob_data = {}
|
||||||
|
|
||||||
|
# Get COB features from orchestrator
|
||||||
|
if hasattr(self.orchestrator, 'latest_cob_features'):
|
||||||
|
cob_features = getattr(self.orchestrator, 'latest_cob_features', {}).get(symbol)
|
||||||
|
if cob_features is not None:
|
||||||
|
cob_data['features'] = cob_features.tolist() if hasattr(cob_features, 'tolist') else cob_features
|
||||||
|
|
||||||
|
# Get COB snapshot
|
||||||
|
cob_snapshot = self._get_cob_snapshot(symbol)
|
||||||
|
if cob_snapshot:
|
||||||
|
cob_data['snapshot_available'] = True
|
||||||
|
cob_data['bid_levels'] = len(getattr(cob_snapshot, 'consolidated_bids', []))
|
||||||
|
cob_data['ask_levels'] = len(getattr(cob_snapshot, 'consolidated_asks', []))
|
||||||
|
else:
|
||||||
|
cob_data['snapshot_available'] = False
|
||||||
|
|
||||||
|
return cob_data
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.debug(f"Error getting COB features: {e}")
|
||||||
|
return {}
|
||||||
|
|
||||||
|
def _get_technical_indicators(self, symbol: str) -> Dict[str, float]:
|
||||||
|
"""Get technical indicators"""
|
||||||
|
try:
|
||||||
|
indicators = {}
|
||||||
|
|
||||||
|
# Get recent price data
|
||||||
|
df = self.data_provider.get_historical_data(symbol, '1m', limit=50)
|
||||||
|
if df is not None and not df.empty:
|
||||||
|
closes = df['close'].values
|
||||||
|
highs = df['high'].values
|
||||||
|
lows = df['low'].values
|
||||||
|
volumes = df['volume'].values
|
||||||
|
|
||||||
|
# Moving averages
|
||||||
|
indicators['sma_10'] = float(closes[-10:].mean())
|
||||||
|
indicators['sma_20'] = float(closes[-20:].mean())
|
||||||
|
|
||||||
|
# Bollinger Bands
|
||||||
|
sma_20 = closes[-20:].mean()
|
||||||
|
std_20 = closes[-20:].std()
|
||||||
|
indicators['bb_upper'] = float(sma_20 + 2 * std_20)
|
||||||
|
indicators['bb_lower'] = float(sma_20 - 2 * std_20)
|
||||||
|
indicators['bb_position'] = float((closes[-1] - indicators['bb_lower']) / (indicators['bb_upper'] - indicators['bb_lower']))
|
||||||
|
|
||||||
|
# MACD
|
||||||
|
ema_12 = closes[-12:].mean() # Simplified
|
||||||
|
ema_26 = closes[-26:].mean() # Simplified
|
||||||
|
indicators['macd'] = float(ema_12 - ema_26)
|
||||||
|
|
||||||
|
# Volatility
|
||||||
|
indicators['volatility'] = float(std_20 / sma_20)
|
||||||
|
|
||||||
|
return indicators
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.debug(f"Error calculating technical indicators: {e}")
|
||||||
|
return {}
|
||||||
|
|
||||||
|
def _get_recent_price_history(self, symbol: str, periods: int = 50) -> List[float]:
|
||||||
|
"""Get recent price history"""
|
||||||
|
try:
|
||||||
|
df = self.data_provider.get_historical_data(symbol, '1m', limit=periods)
|
||||||
|
if df is not None and not df.empty:
|
||||||
|
return df['close'].tolist()
|
||||||
|
return []
|
||||||
|
except Exception as e:
|
||||||
|
logger.debug(f"Error getting price history: {e}")
|
||||||
|
return []
|
||||||
|
|
||||||
|
def _store_trade_for_training(self, trade_record: Dict[str, Any]):
|
||||||
|
"""Store trade for future cold start training"""
|
||||||
|
try:
|
||||||
|
# Create training data storage directory
|
||||||
|
import os
|
||||||
|
training_dir = "training_data"
|
||||||
|
os.makedirs(training_dir, exist_ok=True)
|
||||||
|
|
||||||
|
# Store trade data with timestamp
|
||||||
|
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
||||||
|
filename = f"trade_{trade_record['symbol'].replace('/', '')}_{timestamp}.json"
|
||||||
|
filepath = os.path.join(training_dir, filename)
|
||||||
|
|
||||||
|
import json
|
||||||
|
with open(filepath, 'w') as f:
|
||||||
|
json.dump(trade_record, f, indent=2, default=str)
|
||||||
|
|
||||||
|
logger.info(f"✅ Stored trade data for training: {filepath}")
|
||||||
|
|
||||||
|
# Also store in memory for immediate access
|
||||||
|
if not hasattr(self, 'stored_trades'):
|
||||||
|
self.stored_trades = []
|
||||||
|
|
||||||
|
self.stored_trades.append(trade_record)
|
||||||
|
|
||||||
|
# Keep only last 100 trades in memory
|
||||||
|
if len(self.stored_trades) > 100:
|
||||||
|
self.stored_trades = self.stored_trades[-100:]
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error storing trade for training: {e}")
|
||||||
|
|
||||||
|
def _trigger_cold_start_training(self, trade_record: Dict[str, Any], pnl: float):
|
||||||
|
"""Trigger cold start training when we have trade outcome"""
|
||||||
|
try:
|
||||||
|
logger.info(f"🔥 TRIGGERING COLD START TRAINING")
|
||||||
|
logger.info(f"Trade: {trade_record['side']} {trade_record['symbol']} @ ${trade_record['entry_price']:.2f}")
|
||||||
|
logger.info(f"P&L: ${pnl:.4f} ({'PROFIT' if pnl > 0 else 'LOSS'})")
|
||||||
|
|
||||||
|
# Calculate reward based on P&L
|
||||||
|
reward = self._calculate_training_reward(pnl, trade_record)
|
||||||
|
|
||||||
|
# Send to DQN agent if available
|
||||||
|
if hasattr(self.orchestrator, 'sensitivity_dqn_agent') and self.orchestrator.sensitivity_dqn_agent:
|
||||||
|
self._train_dqn_on_trade_outcome(trade_record, reward)
|
||||||
|
|
||||||
|
# Send to CNN if available
|
||||||
|
if hasattr(self.orchestrator, 'williams_structure') and self.orchestrator.williams_structure:
|
||||||
|
self._train_cnn_on_trade_outcome(trade_record, reward)
|
||||||
|
|
||||||
|
# Send to COB RL if available
|
||||||
|
if hasattr(self.orchestrator, 'cob_integration') and self.orchestrator.cob_integration:
|
||||||
|
self._train_cob_rl_on_trade_outcome(trade_record, reward)
|
||||||
|
|
||||||
|
logger.info(f"✅ Cold start training triggered with reward: {reward:.4f}")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error triggering cold start training: {e}")
|
||||||
|
|
||||||
|
def _calculate_training_reward(self, pnl: float, trade_record: Dict[str, Any]) -> float:
|
||||||
|
"""Calculate training reward based on trade outcome"""
|
||||||
|
try:
|
||||||
|
# Base reward from P&L
|
||||||
|
base_reward = pnl * 100 # Scale up for training
|
||||||
|
|
||||||
|
# Confidence adjustment (higher confidence wrong predictions get bigger penalties)
|
||||||
|
confidence = trade_record.get('confidence', 0.5)
|
||||||
|
if pnl < 0: # Loss
|
||||||
|
confidence_penalty = confidence * 2 # Higher confidence losses hurt more
|
||||||
|
base_reward *= (1 + confidence_penalty)
|
||||||
|
else: # Profit
|
||||||
|
confidence_bonus = confidence * 0.5 # Higher confidence wins get small bonus
|
||||||
|
base_reward *= (1 + confidence_bonus)
|
||||||
|
|
||||||
|
# Time-based adjustment (faster profits are better)
|
||||||
|
# For demo trades, just use a small bonus
|
||||||
|
time_bonus = 0.1 if pnl > 0 else 0
|
||||||
|
|
||||||
|
final_reward = base_reward + time_bonus
|
||||||
|
|
||||||
|
logger.debug(f"Reward calculation: P&L={pnl:.4f}, Confidence={confidence:.2f}, Final={final_reward:.4f}")
|
||||||
|
|
||||||
|
return final_reward
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning(f"Error calculating reward: {e}")
|
||||||
|
return pnl # Fallback to simple P&L
|
||||||
|
|
||||||
|
def _train_dqn_on_trade_outcome(self, trade_record: Dict[str, Any], reward: float):
|
||||||
|
"""Train DQN agent on trade outcome"""
|
||||||
|
try:
|
||||||
|
dqn_agent = self.orchestrator.sensitivity_dqn_agent
|
||||||
|
|
||||||
|
# Get the state that was used for the decision
|
||||||
|
model_inputs = trade_record.get('model_inputs_at_entry', {})
|
||||||
|
dqn_state = model_inputs.get('dqn_state', {}).get('state_vector', [])
|
||||||
|
|
||||||
|
if not dqn_state:
|
||||||
|
logger.debug("No DQN state available for training")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Convert to numpy array
|
||||||
|
state = np.array(dqn_state, dtype=np.float32)
|
||||||
|
|
||||||
|
# Map action to DQN action space
|
||||||
|
action = 1 if trade_record['side'] == 'BUY' else 0
|
||||||
|
|
||||||
|
# Create next state (current market state after trade)
|
||||||
|
current_state = self._get_dqn_state_features(trade_record['symbol'], trade_record['entry_price'])
|
||||||
|
next_state = np.array(current_state.get('state_vector', state), dtype=np.float32)
|
||||||
|
|
||||||
|
# Add experience to DQN memory
|
||||||
|
dqn_agent.remember(state, action, reward, next_state, True) # done=True for completed trade
|
||||||
|
|
||||||
|
# Trigger training if enough experiences
|
||||||
|
if len(dqn_agent.memory) >= dqn_agent.batch_size:
|
||||||
|
loss = dqn_agent.replay()
|
||||||
|
if loss:
|
||||||
|
logger.info(f"🧠 DQN trained on trade outcome - Loss: {loss:.6f}, Reward: {reward:.4f}")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.debug(f"Error training DQN on trade outcome: {e}")
|
||||||
|
|
||||||
|
def _train_cnn_on_trade_outcome(self, trade_record: Dict[str, Any], reward: float):
|
||||||
|
"""Train CNN on trade outcome (simplified for now)"""
|
||||||
|
try:
|
||||||
|
# CNN training requires more complex setup - log for now
|
||||||
|
logger.info(f"📊 CNN training opportunity: {trade_record['side']} with reward {reward:.4f}")
|
||||||
|
|
||||||
|
# In future: extract CNN features from model_inputs and create training sample
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.debug(f"Error training CNN on trade outcome: {e}")
|
||||||
|
|
||||||
|
def _train_cob_rl_on_trade_outcome(self, trade_record: Dict[str, Any], reward: float):
|
||||||
|
"""Train COB RL on trade outcome (simplified for now)"""
|
||||||
|
try:
|
||||||
|
# COB RL training requires accessing the 400M parameter model - log for now
|
||||||
|
logger.info(f"📈 COB RL training opportunity: {trade_record['side']} with reward {reward:.4f}")
|
||||||
|
|
||||||
|
# In future: access COB RL model and create training sample
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.debug(f"Error training COB RL on trade outcome: {e}")
|
||||||
|
|
||||||
def _clear_session(self):
|
def _clear_session(self):
|
||||||
"""Clear session data"""
|
"""Clear session data"""
|
||||||
try:
|
try:
|
||||||
|
Reference in New Issue
Block a user