This commit is contained in:
Dobromir Popov
2025-09-08 11:44:15 +03:00
parent fe6763c4ba
commit 4fe952dbee
6 changed files with 743 additions and 141 deletions

View File

@@ -385,7 +385,7 @@ class TradingOrchestrator:
logger.info(f"Transformer checkpoint loaded: {metadata.checkpoint_id}")
except Exception as e:
logger.debug(f"No transformer checkpoint found: {e}")
if not checkpoint_loaded:
self.model_states['transformer']['checkpoint_loaded'] = False
self.model_states['transformer']['checkpoint_filename'] = 'none (fresh start)'
@@ -1182,137 +1182,156 @@ class TradingOrchestrator:
logger.debug(f"Error getting current price for {symbol}: {e}")
return 0.0
# Get standard feature matrix for this timeframe
feature_matrix = self.data_provider.get_feature_matrix(
symbol=symbol,
timeframes=[timeframe],
window_size=getattr(model, 'window_size', 20)
)
# Enhance with COB feature matrix if available
enhanced_features = feature_matrix
if feature_matrix is not None and self.cob_integration:
try:
# Get COB feature matrix (5-minute history)
cob_feature_matrix = self.get_cob_feature_matrix(symbol, sequence_length=60)
if cob_feature_matrix is not None:
# Take the latest COB features to augment the standard features
latest_cob_features = cob_feature_matrix[-1:, :] # Shape: (1, 400)
# Resize to match the feature matrix timeframe dimension
timeframe_count = feature_matrix.shape[0]
cob_features_expanded = np.repeat(latest_cob_features, timeframe_count, axis=0)
# Concatenate COB features with standard features
# Standard features shape: (timeframes, window_size, features)
# COB features shape: (timeframes, 400)
# We'll add COB as additional features to each timeframe
window_size = feature_matrix.shape[1]
cob_features_reshaped = cob_features_expanded.reshape(timeframe_count, 1, 400)
cob_features_tiled = np.tile(cob_features_reshaped, (1, window_size, 1))
# Concatenate along feature dimension
enhanced_features = np.concatenate([feature_matrix, cob_features_tiled], axis=2)
logger.debug(f"Enhanced CNN features with COB data for {symbol}: "
f"{feature_matrix.shape} + COB -> {enhanced_features.shape}")
except Exception as cob_error:
logger.debug(f"Could not enhance CNN features with COB data: {cob_error}")
enhanced_features = feature_matrix
# Add extrema features if available
if self.extrema_trainer:
try:
extrema_features = self.extrema_trainer.get_context_features_for_model(symbol)
if extrema_features is not None:
# Reshape and tile to match the enhanced_features shape
extrema_features = extrema_features.flatten()
tiled_extrema = np.tile(extrema_features, (enhanced_features.shape[0], enhanced_features.shape[1], 1))
enhanced_features = np.concatenate([enhanced_features, tiled_extrema], axis=2)
logger.debug(f"Enhanced CNN features with Extrema data for {symbol}")
except Exception as extrema_error:
logger.debug(f"Could not enhance CNN features with Extrema data: {extrema_error}")
if enhanced_features is not None:
# Get CNN prediction - use the actual underlying model
try:
# Ensure features are properly shaped and limited
if isinstance(enhanced_features, np.ndarray):
# Flatten and limit features to prevent shape mismatches
enhanced_features = enhanced_features.flatten()
if len(enhanced_features) > 100: # Limit to 100 features
enhanced_features = enhanced_features[:100]
elif len(enhanced_features) < 100: # Pad with zeros
padded = np.zeros(100)
padded[:len(enhanced_features)] = enhanced_features
enhanced_features = padded
if hasattr(model.model, 'act'):
# Use the CNN's act method
action_result = model.model.act(enhanced_features, explore=False)
if isinstance(action_result, tuple):
action_idx, confidence = action_result
else:
action_idx = action_result
confidence = 0.7 # Default confidence
# Convert to action probabilities
action_probs = [0.1, 0.1, 0.8] # Default distribution
action_probs[action_idx] = confidence
else:
# Fallback to generic predict method
action_probs, confidence = model.predict(enhanced_features)
except Exception as e:
logger.warning(f"CNN prediction failed: {e}")
action_probs, confidence = None, None
if action_probs is not None:
# Convert to prediction object
action_names = ['SELL', 'HOLD', 'BUY']
best_action_idx = np.argmax(action_probs)
best_action = action_names[best_action_idx]
prediction = Prediction(
action=best_action,
confidence=float(confidence) if confidence is not None else float(action_probs[best_action_idx]),
probabilities={name: float(prob) for name, prob in zip(action_names, action_probs)},
timeframe=timeframe,
timestamp=datetime.now(),
model_name=model.name,
metadata={
'timeframe_specific': True,
'cob_enhanced': enhanced_features is not feature_matrix,
'feature_shape': str(enhanced_features.shape)
}
)
predictions.append(prediction)
# Capture CNN prediction for dashboard visualization
current_price = self._get_current_price(symbol)
if current_price:
direction = best_action_idx # 0=SELL, 1=HOLD, 2=BUY
pred_confidence = float(confidence) if confidence is not None else float(action_probs[best_action_idx])
predicted_price = current_price * (1 + (pred_confidence * 0.01 if best_action == 'BUY' else -pred_confidence * 0.01 if best_action == 'SELL' else 0))
self.capture_cnn_prediction(symbol, int(direction), pred_confidence, current_price, predicted_price)
except Exception as e:
logger.error(f"Error getting CNN predictions: {e}")
return predictions
async def _get_rl_prediction(self, model: RLAgentInterface, symbol: str) -> Optional[Prediction]:
"""Get prediction from RL agent"""
async def _get_cob_rl_prediction(self, model: COBRLModelInterface, symbol: str) -> Optional[Prediction]:
"""Get prediction from COB RL model"""
try:
# Get current state for RL agent
state = self._get_rl_state(symbol)
if state is None:
# Get COB state from current market data
cob_state = self._get_cob_state(symbol)
if cob_state is None:
return None
# Get RL agent's action, confidence, and q_values from the underlying model
# Get prediction from COB RL model
if hasattr(model.model, 'act_with_confidence'):
result = model.model.act_with_confidence(cob_state)
if len(result) == 2:
action_idx, confidence = result
else:
action_idx = result[0] if isinstance(result, (list, tuple)) else result
confidence = 0.6
else:
action_idx = model.model.act(cob_state)
confidence = 0.6
# Convert to action name
action_names = ['BUY', 'SELL', 'HOLD']
if 0 <= action_idx < len(action_names):
action = action_names[action_idx]
else:
return None
# Store prediction in database for tracking
if (hasattr(self, 'enhanced_training_system') and
self.enhanced_training_system and
hasattr(self.enhanced_training_system, 'store_model_prediction')):
current_price = self._get_current_price_safe(symbol)
if current_price > 0:
prediction_id = self.enhanced_training_system.store_model_prediction(
model_name=f"COB_RL_{model.model_name}" if hasattr(model, 'model_name') else "COB_RL",
symbol=symbol,
prediction_type=action,
confidence=confidence,
current_price=current_price
)
logger.debug(f"Stored COB RL prediction {prediction_id} for {symbol}")
# Create prediction object
prediction = Prediction(
model_name=f"COB_RL_{model.model_name}" if hasattr(model, 'model_name') else "COB_RL",
symbol=symbol,
signal=action,
confidence=confidence,
reasoning=f"COB RL model prediction based on order book imbalance",
features=cob_state.tolist() if isinstance(cob_state, np.ndarray) else [],
metadata={
'action_idx': action_idx,
'cob_state_size': len(cob_state) if cob_state is not None else 0
}
)
return prediction
except Exception as e:
logger.error(f"Error getting COB RL prediction for {symbol}: {e}")
return None
async def _get_generic_prediction(self, model, symbol: str) -> Optional[Prediction]:
"""Get prediction from generic model interface"""
try:
# Placeholder for generic model prediction
logger.debug(f"Getting generic prediction from {model} for {symbol}")
return None
except Exception as e:
logger.error(f"Error getting generic prediction for {symbol}: {e}")
return None
def _get_rl_state(self, symbol: str) -> Optional[np.ndarray]:
"""Build RL state vector for DQN agent"""
try:
# Use data provider to get comprehensive RL state
if hasattr(self.data_provider, 'get_dqn_state_for_inference'):
symbols_timeframes = [(symbol, '1m'), (symbol, '5m'), (symbol, '1h')]
state = self.data_provider.get_dqn_state_for_inference(symbols_timeframes, target_size=100)
if state is not None:
return state
# Fallback: build basic state from market data
market_features = []
# Get latest price data
latest_data = self.data_provider.get_latest_data(symbol)
if latest_data and 'close' in latest_data:
current_price = float(latest_data['close'])
market_features.extend([
current_price,
latest_data.get('volume', 0.0),
latest_data.get('high', current_price) - latest_data.get('low', current_price), # Range
latest_data.get('open', current_price)
])
else:
market_features.extend([4300.0, 100.0, 10.0, 4295.0]) # Default values
# Pad to standard size
while len(market_features) < 100:
market_features.append(0.0)
return np.array(market_features[:100], dtype=np.float32)
except Exception as e:
logger.debug(f"Error building RL state for {symbol}: {e}")
return None
def _get_cob_state(self, symbol: str) -> Optional[np.ndarray]:
"""Build COB state vector for COB RL agent"""
try:
# Get COB data from integration
if hasattr(self, 'cob_integration') and self.cob_integration:
cob_snapshot = self.cob_integration.get_cob_snapshot(symbol)
if cob_snapshot:
# Extract features from COB snapshot
features = []
# Add bid/ask imbalance
bid_volume = sum([level['volume'] for level in cob_snapshot.get('bids', [])])
ask_volume = sum([level['volume'] for level in cob_snapshot.get('asks', [])])
if bid_volume + ask_volume > 0:
imbalance = (bid_volume - ask_volume) / (bid_volume + ask_volume)
else:
imbalance = 0.0
features.append(imbalance)
# Add spread
if cob_snapshot.get('bids') and cob_snapshot.get('asks'):
spread = cob_snapshot['asks'][0]['price'] - cob_snapshot['bids'][0]['price']
features.append(spread)
else:
features.append(0.0)
# Pad to standard size
while len(features) < 50:
features.append(0.0)
return np.array(features[:50], dtype=np.float32)
# Fallback state
return np.zeros(50, dtype=np.float32)
except Exception as e:
logger.debug(f"Error building COB state for {symbol}: {e}")
return None
def _combine_predictions(self, symbol: str, price: float, predictions: List[Prediction],
timestamp: datetime) -> TradingDecision:
# Call act_with_confidence and handle different return formats
result = model.model.act_with_confidence(state)
@@ -1728,7 +1747,7 @@ class TradingOrchestrator:
)
if needs_refresh:
result = load_best_checkpoint(model_name)
result = load_best_checkpoint(model_name)
self._checkpoint_cache[model_name] = result
self._checkpoint_cache_time[model_name] = current_time
@@ -1869,14 +1888,14 @@ class TradingOrchestrator:
logger.warning("EnhancedRealtimeTrainingSystem not available - training disabled")
self.training_enabled = False
return
# Initialize enhanced training system directly (no external training_integration module needed)
try:
from NN.training.enhanced_realtime_training import EnhancedRealtimeTrainingSystem
self.enhanced_training_system = EnhancedRealtimeTrainingSystem(
orchestrator=self,
data_provider=self.data_provider,
self.enhanced_training_system = EnhancedRealtimeTrainingSystem(
orchestrator=self,
data_provider=self.data_provider,
dashboard=None
)

View File

@@ -13,7 +13,7 @@ import logging
from datetime import datetime
from typing import Dict, List, Any, Optional
import numpy as np
from utils.reward_calculator import RewardCalculator
from core.reward_calculator import RewardCalculator
import threading
import time