try to fix input dimentions

This commit is contained in:
Dobromir Popov
2025-07-13 23:41:47 +03:00
parent bcc13a5db3
commit ebf65494a8
7 changed files with 358 additions and 145 deletions

View File

@ -250,6 +250,12 @@ class COBRLModelInterface(ModelInterface):
logger.info(f"COB RL Model Interface initialized on {self.device}")
def to(self, device):
"""PyTorch-style device movement method"""
self.device = device
self.model = self.model.to(device)
return self
def predict(self, cob_features: np.ndarray) -> Dict[str, Any]:
"""Make prediction using the model"""
self.model.eval()

View File

@ -454,6 +454,13 @@ class DQNAgent:
logger.error(f"Failed to move models to {self.device}: {str(e)}")
return False
def to(self, device):
"""PyTorch-style device movement method"""
self.device = device
self.policy_net = self.policy_net.to(device)
self.target_net = self.target_net.to(device)
return self
def remember(self, state: np.ndarray, action: int, reward: float,
next_state: np.ndarray, done: bool, is_extrema: bool = False):
"""

View File

@ -498,10 +498,20 @@ class EnhancedCNN(nn.Module):
"""Enhanced action selection with ultra massive model predictions"""
if explore and np.random.random() < 0.1: # 10% random exploration
return np.random.choice(self.n_actions)
self.eval()
state_tensor = torch.FloatTensor(state).unsqueeze(0).to(self.device)
# Accept both NumPy arrays and already-built torch tensors
if isinstance(state, torch.Tensor):
state_tensor = state.detach().to(self.device)
if state_tensor.dim() == 1:
state_tensor = state_tensor.unsqueeze(0)
else:
# Convert to tensor **directly on the target device** to avoid intermediate CPU copies
state_tensor = torch.as_tensor(state, dtype=torch.float32, device=self.device)
if state_tensor.dim() == 1:
state_tensor = state_tensor.unsqueeze(0)
with torch.no_grad():
q_values, extrema_pred, price_predictions, features, advanced_predictions = self(state_tensor)

View File

@ -99,6 +99,10 @@ class TradingOrchestrator:
self.model_registry = model_registry or get_model_registry()
self.enhanced_rl_training = enhanced_rl_training
# Determine the device to use (GPU if available, else CPU)
self.device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
logger.info(f"Using device: {self.device}")
# Configuration - AGGRESSIVE for more training data
self.confidence_threshold = self.config.orchestrator.get('confidence_threshold', 0.15) # Lowered from 0.20
self.confidence_threshold_close = self.config.orchestrator.get('confidence_threshold_close', 0.08) # Lowered from 0.10
@ -226,6 +230,7 @@ class TradingOrchestrator:
state_size = self.config.rl.get('state_size', 13800) # Enhanced with COB features
action_size = self.config.rl.get('action_space', 3)
self.rl_agent = DQNAgent(state_shape=state_size, n_actions=action_size)
self.rl_agent.to(self.device) # Move DQN agent to the determined device
# Load best checkpoint and capture initial state
checkpoint_loaded = False
@ -268,6 +273,7 @@ class TradingOrchestrator:
cnn_input_shape = self.config.cnn.get('input_shape', 100)
cnn_n_actions = self.config.cnn.get('n_actions', 3)
self.cnn_model = EnhancedCNN(input_shape=cnn_input_shape, n_actions=cnn_n_actions)
self.cnn_model.to(self.device) # Move CNN model to the determined device
self.cnn_optimizer = optim.Adam(self.cnn_model.parameters(), lr=0.001) # Initialize optimizer for CNN
# Load best checkpoint and capture initial state
@ -300,6 +306,7 @@ class TradingOrchestrator:
try:
from NN.models.cnn_model import CNNModel
self.cnn_model = CNNModel()
self.cnn_model.to(self.device) # Move basic CNN model to the determined device
self.cnn_optimizer = optim.Adam(self.cnn_model.parameters(), lr=0.001) # Initialize optimizer for basic CNN
# Load checkpoint for basic CNN as well
@ -355,6 +362,9 @@ class TradingOrchestrator:
try:
from NN.models.cob_rl_model import COBRLModelInterface
self.cob_rl_agent = COBRLModelInterface()
# Move COB RL agent to the determined device if it supports it
if hasattr(self.cob_rl_agent, 'to'):
self.cob_rl_agent.to(self.device)
# Load best checkpoint and capture initial state
checkpoint_loaded = False
@ -458,7 +468,19 @@ class TradingOrchestrator:
def predict(self, data):
try:
if hasattr(self.model, 'predict'):
return self.model.predict(data)
# Ensure data has correct dimensions for COB RL model (2000 features)
if isinstance(data, np.ndarray):
features = data.flatten()
# COB RL expects 2000 features
if len(features) < 2000:
padded_features = np.zeros(2000)
padded_features[:len(features)] = features
features = padded_features
elif len(features) > 2000:
features = features[:2000]
return self.model.predict(features)
else:
return self.model.predict(data)
return None
except Exception as e:
logger.error(f"Error in COB RL prediction: {e}")
@ -929,7 +951,7 @@ class TradingOrchestrator:
logger.error(f"Error in decision callback: {e}")
# Clean up memory periodically
if len(self.recent_decisions[symbol]) % 50 == 0:
if len(self.recent_decisions[symbol]) % 200 == 0: # Reduced from 50 to 200
self.model_registry.cleanup_all_models()
return decision
@ -970,119 +992,93 @@ class TradingOrchestrator:
async def _get_cnn_predictions(self, model: CNNModelInterface, symbol: str) -> List[Prediction]:
"""Get predictions from CNN model for all timeframes with enhanced COB features"""
predictions = []
try:
# Safely get timeframes from config
timeframes = getattr(self.config, 'timeframes', None)
if timeframes is None:
timeframes = ['1m', '5m', '15m', '1h'] # Default timeframes
timeframes = getattr(self.config, 'timeframes', ['1m','5m','15m','1h'])
for timeframe in timeframes:
# Get standard feature matrix for this timeframe
# 1) build or fetch your feature matrix (and optionally augment with COB)…
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
if enhanced_features is not None:
# Get CNN prediction - use the actual underlying model
try:
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
if feature_matrix is None:
continue
# …apply COBaugmentation here (omitted for brevity)—
enhanced_features = self._augment_with_cob(feature_matrix, symbol)
# 2) Initialize these before we call the model
action_probs, confidence = None, None
# 3) Try the actual model inference
try:
# if your model has an .act() that returns (probs, conf)
if hasattr(model.model, 'act'):
# Flatten / reshape enhanced_features as needed…
x = self._prepare_cnn_input(enhanced_features)
action_probs, confidence = model.model.act(x, explore=False)
else:
# fallback to generic predict
result = model.predict(enhanced_features)
if isinstance(result, tuple) and len(result)==2:
action_probs, confidence = result
else:
# Fallback to generic predict method
prediction_result = model.predict(enhanced_features)
if prediction_result is not None:
if isinstance(prediction_result, tuple) and len(prediction_result) == 2:
action_probs, confidence = prediction_result
else:
action_probs = prediction_result
confidence = 0.7
else:
action_probs, confidence = None, None
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)
action_probs = result
confidence = 0.7
except Exception as e:
logger.warning(f"CNN inference failed for {symbol}@{timeframe}: {e}")
continue # skip this timeframe entirely
# 4) If we still dont have valid probs, skip
if action_probs is None:
continue
# 5) Build your Prediction
action_names = ['SELL','HOLD','BUY']
best_idx = int(np.argmax(action_probs))
best_action = action_names[best_idx]
pred = Prediction(
action=best_action,
confidence=float(confidence),
probabilities={n: float(p) for n,p in zip(action_names, action_probs)},
timeframe=timeframe,
timestamp=datetime.now(),
model_name=model.name,
metadata={
'feature_shape': str(enhanced_features.shape),
'cob_enhanced': enhanced_features is not feature_matrix
}
)
predictions.append(pred)
# …and capture for the dashboard if you like…
current_price = self._get_current_price(symbol)
if current_price is not None:
predicted_price = current_price * (1 + (0.01 * (confidence if best_action=='BUY' else -confidence if best_action=='SELL' else 0)))
self.capture_cnn_prediction(
symbol,
direction=best_idx,
confidence=confidence,
current_price=current_price,
predicted_price=predicted_price
)
except Exception as e:
logger.error(f"Error getting CNN predictions: {e}")
logger.error(f"Orch: Error getting CNN predictions: {e}")
return predictions
# helper stubs for clarity
def _augment_with_cob(self, feature_matrix, symbol):
# your existing cobaugmentation logic…
return feature_matrix
def _prepare_cnn_input(self, features):
arr = features.flatten()
# pad/truncate to 300, reshape to (1,300)
if len(arr) < 300:
arr = np.pad(arr, (0,300-len(arr)), 'constant')
else:
arr = arr[:300]
return arr.reshape(1,-1)
async def _get_rl_prediction(self, model: RLAgentInterface, symbol: str) -> Optional[Prediction]:
"""Get prediction from RL agent"""
try:
@ -1230,7 +1226,20 @@ class TradingOrchestrator:
# This would come from a portfolio manager in a real implementation
additional_state = np.array([0.0, 1.0, 0.0]) # [position, balance, unrealized_pnl]
return np.concatenate([state, additional_state])
combined_state = np.concatenate([state, additional_state])
# Ensure DQN gets exactly 403 features (expected by the model)
target_size = 403
if len(combined_state) < target_size:
# Pad with zeros
padded_state = np.zeros(target_size)
padded_state[:len(combined_state)] = combined_state
combined_state = padded_state
elif len(combined_state) > target_size:
# Truncate to target size
combined_state = combined_state[:target_size]
return combined_state
return None
@ -1547,7 +1556,9 @@ class TradingOrchestrator:
return torch.softmax(self.fc3(x), dim=1)
self.decision_fusion_network = DecisionFusionNet()
logger.info("Decision fusion network initialized")
# Move decision fusion network to the device
self.decision_fusion_network.to(self.device)
logger.info(f"Decision fusion network initialized on device: {self.device}")
except Exception as e:
logger.warning(f"Decision fusion initialization failed: {e}")

View File

@ -56,6 +56,7 @@ class EnhancedRealtimeTrainingSystem:
self.performance_history = {
'dqn_losses': deque(maxlen=1000),
'cnn_losses': deque(maxlen=1000),
'cob_rl_losses': deque(maxlen=1000), # Added COB RL loss tracking
'prediction_accuracy': deque(maxlen=500),
'trading_performance': deque(maxlen=200),
'validation_scores': deque(maxlen=100)
@ -553,18 +554,33 @@ class EnhancedRealtimeTrainingSystem:
# Statistical features across time for each aggregated dimension
for feature_idx in range(agg_matrix.shape[1]):
feature_series = agg_matrix[:, feature_idx]
combined_features.extend([
np.mean(feature_series),
np.std(feature_series),
np.min(feature_series),
np.max(feature_series),
feature_series[-1] - feature_series[0] if len(feature_series) > 1 else 0, # Total change
np.mean(np.diff(feature_series)) if len(feature_series) > 1 else 0, # Average momentum
np.std(np.diff(feature_series)) if len(feature_series) > 2 else 0, # Momentum volatility
np.percentile(feature_series, 25), # 25th percentile
np.percentile(feature_series, 75), # 75th percentile
len([x for x in np.diff(feature_series) if x > 0]) / max(len(feature_series) - 1, 1) if len(feature_series) > 1 else 0.5 # Positive change ratio
])
# Clean feature series to prevent division warnings
feature_series_clean = feature_series[np.isfinite(feature_series)]
if len(feature_series_clean) > 0:
# Safe percentile calculation
try:
percentile_25 = np.percentile(feature_series_clean, 25)
percentile_75 = np.percentile(feature_series_clean, 75)
except (ValueError, RuntimeWarning):
percentile_25 = np.median(feature_series_clean) if len(feature_series_clean) > 0 else 0
percentile_75 = np.median(feature_series_clean) if len(feature_series_clean) > 0 else 0
combined_features.extend([
np.mean(feature_series_clean),
np.std(feature_series_clean),
np.min(feature_series_clean),
np.max(feature_series_clean),
feature_series_clean[-1] - feature_series_clean[0] if len(feature_series_clean) > 1 else 0, # Total change
np.mean(np.diff(feature_series_clean)) if len(feature_series_clean) > 1 else 0, # Average momentum
np.std(np.diff(feature_series_clean)) if len(feature_series_clean) > 2 else 0, # Momentum volatility
percentile_25, # 25th percentile
percentile_75, # 75th percentile
len([x for x in np.diff(feature_series_clean) if x > 0]) / max(len(feature_series_clean) - 1, 1) if len(feature_series_clean) > 1 else 0.5 # Positive change ratio
])
else:
# All values are NaN or inf, use zeros
combined_features.extend([0.0] * 10)
else:
combined_features.extend([0.0] * (15 * 10)) # 15 features * 10 statistics
@ -702,13 +718,14 @@ class EnhancedRealtimeTrainingSystem:
lows = np.array([bar['low'] for bar in self.real_time_data['ohlcv_1m']])
# Update indicators
price_mean = np.mean(prices[-20:])
self.technical_indicators = {
'sma_10': np.mean(prices[-10:]),
'sma_20': np.mean(prices[-20:]),
'rsi': self._calculate_rsi(prices, 14),
'volatility': np.std(prices[-20:]) / np.mean(prices[-20:]),
'volatility': np.std(prices[-20:]) / price_mean if price_mean > 0 else 0,
'volume_sma': np.mean(volumes[-10:]),
'price_momentum': (prices[-1] - prices[-5]) / prices[-5] if len(prices) >= 5 else 0,
'price_momentum': (prices[-1] - prices[-5]) / prices[-5] if len(prices) >= 5 and prices[-5] > 0 else 0,
'atr': np.mean(highs[-14:] - lows[-14:]) if len(prices) >= 14 else 0
}
@ -724,8 +741,8 @@ class EnhancedRealtimeTrainingSystem:
current_time = time.time()
current_bar = self.real_time_data['ohlcv_1m'][-1]
# Create comprehensive state features
state_features = self._build_comprehensive_state()
# Create comprehensive state features with default dimensions
state_features = self._build_comprehensive_state(100) # Use default 100 for general experiences
# Create experience with proper reward calculation
experience = {
@ -748,8 +765,8 @@ class EnhancedRealtimeTrainingSystem:
except Exception as e:
logger.debug(f"Error creating training experiences: {e}")
def _build_comprehensive_state(self) -> np.ndarray:
"""Build comprehensive state vector for RL training"""
def _build_comprehensive_state(self, target_dimensions: int = 100) -> np.ndarray:
"""Build comprehensive state vector for RL training with adaptive dimensions"""
try:
state_features = []
@ -792,15 +809,138 @@ class EnhancedRealtimeTrainingSystem:
state_features.append(np.cos(2 * np.pi * now.hour / 24))
state_features.append(now.weekday() / 6.0) # Day of week
# Pad to fixed size (100 features)
while len(state_features) < 100:
# Current count: 10 (prices) + 7 (indicators) + 1 (volume) + 5 (COB) + 3 (time) = 26 base features
# 6. Enhanced features for larger dimensions
if target_dimensions > 50:
# Add more price history
if len(self.real_time_data['ohlcv_1m']) >= 20:
extended_prices = [bar['close'] for bar in list(self.real_time_data['ohlcv_1m'])[-20:]]
base_price = extended_prices[0]
extended_normalized = [(p - base_price) / base_price for p in extended_prices[10:]] # Additional 10
state_features.extend(extended_normalized)
else:
state_features.extend([0.0] * 10)
# Add volume history
if len(self.real_time_data['ohlcv_1m']) >= 10:
volume_history = [bar['volume'] for bar in list(self.real_time_data['ohlcv_1m'])[-10:]]
avg_vol = np.mean(volume_history) if volume_history else 1.0
# Prevent division by zero
if avg_vol == 0:
avg_vol = 1.0
normalized_volumes = [v / avg_vol for v in volume_history]
state_features.extend(normalized_volumes)
else:
state_features.extend([0.0] * 10)
# Add extended COB features
extended_cob = self._extract_cob_features()
state_features.extend(extended_cob[5:]) # Remaining COB features
# Add 5m timeframe data if available
if len(self.real_time_data['ohlcv_5m']) >= 5:
tf_5m_prices = [bar['close'] for bar in list(self.real_time_data['ohlcv_5m'])[-5:]]
if tf_5m_prices:
base_5m = tf_5m_prices[0]
# Prevent division by zero
if base_5m == 0:
base_5m = 1.0
normalized_5m = [(p - base_5m) / base_5m for p in tf_5m_prices]
state_features.extend(normalized_5m)
else:
state_features.extend([0.0] * 5)
else:
state_features.extend([0.0] * 5)
# 7. Adaptive padding/truncation based on target dimensions
current_length = len(state_features)
if target_dimensions > current_length:
# Pad with additional engineered features
remaining = target_dimensions - current_length
# Add statistical features if we have data
if len(self.real_time_data['ohlcv_1m']) >= 20:
all_prices = [bar['close'] for bar in list(self.real_time_data['ohlcv_1m'])[-20:]]
all_volumes = [bar['volume'] for bar in list(self.real_time_data['ohlcv_1m'])[-20:]]
# Statistical features
additional_features = [
np.std(all_prices) / np.mean(all_prices) if np.mean(all_prices) > 0 else 0, # Price CV
np.std(all_volumes) / np.mean(all_volumes) if np.mean(all_volumes) > 0 else 0, # Volume CV
(max(all_prices) - min(all_prices)) / np.mean(all_prices) if np.mean(all_prices) > 0 else 0, # Price range
# Safe correlation calculation
np.corrcoef(all_prices, all_volumes)[0, 1] if (len(all_prices) == len(all_volumes) and len(all_prices) > 1 and
np.std(all_prices) > 0 and np.std(all_volumes) > 0) else 0, # Price-volume correlation
]
# Add momentum features
for window in [3, 5, 10]:
if len(all_prices) >= window:
momentum = (all_prices[-1] - all_prices[-window]) / all_prices[-window] if all_prices[-window] > 0 else 0
additional_features.append(momentum)
else:
additional_features.append(0.0)
# Extend to fill remaining space
while len(additional_features) < remaining and len(additional_features) < 50:
additional_features.extend([
np.sin(len(additional_features) * 0.1), # Sine waves for variety
np.cos(len(additional_features) * 0.1),
np.tanh(len(additional_features) * 0.01)
])
state_features.extend(additional_features[:remaining])
else:
# Fill with structured zeros/patterns if no data
pattern_features = []
for i in range(remaining):
pattern_features.append(np.sin(i * 0.01)) # Small oscillating pattern
state_features.extend(pattern_features)
# Ensure exact target dimension
state_features = state_features[:target_dimensions]
while len(state_features) < target_dimensions:
state_features.append(0.0)
return np.array(state_features[:100])
return np.array(state_features)
except Exception as e:
logger.error(f"Error building state: {e}")
return np.zeros(100)
return np.zeros(target_dimensions)
def _get_model_expected_dimensions(self, model_type: str) -> int:
"""Get expected input dimensions for different model types"""
try:
if model_type == 'dqn':
# Try to get DQN expected dimensions from model
if (self.orchestrator and hasattr(self.orchestrator, 'rl_agent')
and self.orchestrator.rl_agent and hasattr(self.orchestrator.rl_agent, 'policy_net')):
# Get first layer input size
first_layer = list(self.orchestrator.rl_agent.policy_net.children())[0]
if hasattr(first_layer, 'in_features'):
return first_layer.in_features
return 403 # Default for DQN based on error logs
elif model_type == 'cnn':
# CNN might have different input expectations
if (self.orchestrator and hasattr(self.orchestrator, 'cnn_model')
and self.orchestrator.cnn_model):
# Try to get CNN input size
if hasattr(self.orchestrator.cnn_model, 'input_shape'):
return self.orchestrator.cnn_model.input_shape
return 300 # Default for CNN based on error logs
elif model_type == 'cob_rl':
return 2000 # COB RL expects 2000 features
else:
return 100 # Default
except Exception as e:
logger.debug(f"Error getting model dimensions for {model_type}: {e}")
return 100 # Fallback
def _extract_cob_features(self) -> List[float]:
"""Extract features from COB data"""
@ -964,6 +1104,18 @@ class EnhancedRealtimeTrainingSystem:
aggregated_matrix = self.get_cob_training_matrix(symbol, '1s_aggregated')
if combined_features is not None:
# Ensure features are exactly 2000 dimensions
if len(combined_features) != 2000:
logger.warning(f"COB features wrong size: {len(combined_features)}, padding/truncating to 2000")
if len(combined_features) < 2000:
# Pad with zeros
padded_features = np.zeros(2000, dtype=np.float32)
padded_features[:len(combined_features)] = combined_features
combined_features = padded_features
else:
# Truncate to 2000
combined_features = combined_features[:2000]
# Create enhanced COB training experience
current_price = self._get_current_price_from_data(symbol)
if current_price:
@ -973,7 +1125,7 @@ class EnhancedRealtimeTrainingSystem:
# Calculate reward based on COB prediction accuracy
reward = self._calculate_cob_reward(symbol, action, combined_features)
# Create comprehensive state vector for COB RL
# Create comprehensive state vector for COB RL (exactly 2000 dimensions)
state = combined_features # 2000-dimensional state
# Store experience in COB RL agent
@ -1268,16 +1420,29 @@ class EnhancedRealtimeTrainingSystem:
# Moving averages
if len(prev_prices) >= 5:
ma5 = sum(prev_prices[-5:]) / 5
tech_features.append((current_price - ma5) / ma5)
# Prevent division by zero
if ma5 != 0:
tech_features.append((current_price - ma5) / ma5)
else:
tech_features.append(0.0)
if len(prev_prices) >= 10:
ma10 = sum(prev_prices[-10:]) / 10
tech_features.append((current_price - ma10) / ma10)
# Prevent division by zero
if ma10 != 0:
tech_features.append((current_price - ma10) / ma10)
else:
tech_features.append(0.0)
# Volatility measure
if len(prev_prices) >= 5:
volatility = np.std(prev_prices[-5:]) / np.mean(prev_prices[-5:])
tech_features.append(volatility)
price_mean = np.mean(prev_prices[-5:])
# Prevent division by zero
if price_mean != 0:
volatility = np.std(prev_prices[-5:]) / price_mean
tech_features.append(volatility)
else:
tech_features.append(0.0)
# Pad technical features to 200
while len(tech_features) < 200:
@ -1978,8 +2143,9 @@ class EnhancedRealtimeTrainingSystem:
def _generate_forward_dqn_prediction(self, symbol: str, current_time: float):
"""Generate a DQN prediction for future price movement"""
try:
# Get current market state (only historical data)
current_state = self._build_comprehensive_state()
# Get current market state with DQN-specific dimensions
target_dims = self._get_model_expected_dimensions('dqn')
current_state = self._build_comprehensive_state(target_dims)
current_price = self._get_current_price_from_data(symbol)
# SKIP prediction if price is invalid
@ -2051,7 +2217,7 @@ class EnhancedRealtimeTrainingSystem:
self.last_prediction_time[symbol] = int(current_time)
logger.info(f"Forward DQN prediction: {symbol} action={['BUY','SELL','HOLD'][action]} confidence={confidence:.2f} price=${current_price:.2f} target={target_time.strftime('%H:%M:%S')}")
logger.info(f"Forward DQN prediction: {symbol} action={['BUY','SELL','HOLD'][action]} confidence={confidence:.2f} price=${current_price:.2f} target={target_time.strftime('%H:%M:%S')} dims={len(current_state)}")
except Exception as e:
logger.error(f"Error generating forward DQN prediction: {e}")

View File

@ -984,6 +984,10 @@ class CleanTradingDashboard:
timestamp = pred.get('timestamp', datetime.now())
price = pred.get('price', 0)
# FILTER OUT INVALID PRICES - Skip predictions with price 0 or None
if price is None or price <= 0:
continue
if confidence > 0.3: # Only show predictions with reasonable confidence
pred_data = {
'x': timestamp,
@ -1096,7 +1100,12 @@ class CleanTradingDashboard:
current_price = pred.get('current_price', 0)
predicted_price = pred.get('predicted_price', current_price)
if confidence > 0.4 and current_price > 0: # Only show confident predictions
# FILTER OUT INVALID PRICES - Skip predictions with price 0 or None
if (current_price is None or current_price <= 0 or
predicted_price is None or predicted_price <= 0):
continue
if confidence > 0.4: # Only show confident predictions
# Calculate prediction end point (5 minutes ahead)
end_time = timestamp + timedelta(minutes=5)
@ -1171,10 +1180,10 @@ class CleanTradingDashboard:
if not cob_predictions:
return # No real predictions to display
# Separate predictions by direction
up_predictions = [p for p in cob_predictions if p['direction'] == 2]
down_predictions = [p for p in cob_predictions if p['direction'] == 0]
sideways_predictions = [p for p in cob_predictions if p['direction'] == 1]
# Separate predictions by direction and filter out invalid prices
up_predictions = [p for p in cob_predictions if p['direction'] == 2 and p.get('price', 0) > 0]
down_predictions = [p for p in cob_predictions if p['direction'] == 0 and p.get('price', 0) > 0]
sideways_predictions = [p for p in cob_predictions if p['direction'] == 1 and p.get('price', 0) > 0]
# Add COB_RL UP predictions (blue diamonds)
if up_predictions:

View File

@ -45,6 +45,10 @@ class DashboardComponentManager:
blocked = decision.get('blocked', False)
manual = decision.get('manual', False)
# FILTER OUT INVALID PRICES - Skip signals with price 0 or None
if price is None or price <= 0:
continue
# Determine signal style
if executed:
badge_class = "bg-success"