better decision details

This commit is contained in:
Dobromir Popov
2025-07-29 09:49:09 +03:00
parent e2ededcdf0
commit f34b2a46a2
3 changed files with 95 additions and 7 deletions

View File

@ -256,6 +256,7 @@ class TradingDecision:
timestamp: datetime timestamp: datetime
reasoning: Dict[str, Any] # Why this decision was made reasoning: Dict[str, Any] # Why this decision was made
memory_usage: Dict[str, int] # Memory usage of models memory_usage: Dict[str, int] # Memory usage of models
source: str = "orchestrator" # Source of the decision (model name or system)
# NEW: Aggressiveness parameters # NEW: Aggressiveness parameters
entry_aggressiveness: float = 0.5 # 0.0 = conservative, 1.0 = very aggressive entry_aggressiveness: float = 0.5 # 0.0 = conservative, 1.0 = very aggressive
exit_aggressiveness: float = 0.5 # 0.0 = conservative, 1.0 = very aggressive exit_aggressiveness: float = 0.5 # 0.0 = conservative, 1.0 = very aggressive
@ -4637,6 +4638,56 @@ class TradingOrchestrator:
except Exception as e: except Exception as e:
logger.error(f"Error creating RL state for {symbol}: {e}") logger.error(f"Error creating RL state for {symbol}: {e}")
return None return None
def _determine_decision_source(self, models_used: List[str], confidence: float) -> str:
"""Determine the source of a trading decision based on contributing models"""
try:
if not models_used:
return "no_models"
# If only one model contributed, use that as source
if len(models_used) == 1:
model_name = models_used[0]
# Map internal model names to user-friendly names
model_mapping = {
"dqn_agent": "DQN",
"cnn_model": "CNN",
"cob_rl": "COB-RL",
"decision_fusion": "Fusion",
"extrema_trainer": "Extrema",
"transformer": "Transformer"
}
return model_mapping.get(model_name, model_name)
# Multiple models - determine primary contributor
# Priority order: COB-RL > DQN > CNN > Others
priority_order = ["cob_rl", "dqn_agent", "cnn_model", "decision_fusion", "transformer", "extrema_trainer"]
for priority_model in priority_order:
if priority_model in models_used:
model_mapping = {
"cob_rl": "COB-RL",
"dqn_agent": "DQN",
"cnn_model": "CNN",
"decision_fusion": "Fusion",
"transformer": "Transformer",
"extrema_trainer": "Extrema"
}
primary_model = model_mapping.get(priority_model, priority_model)
# If high confidence, show primary model
if confidence > 0.7:
return primary_model
else:
# Lower confidence, show it's a combination
return f"{primary_model}+{len(models_used)-1}"
# Fallback: show number of models
return f"Ensemble({len(models_used)})"
except Exception as e:
logger.error(f"Error determining decision source: {e}")
return "orchestrator"
def _combine_predictions( def _combine_predictions(
self, self,
@ -4798,6 +4849,9 @@ class TradingOrchestrator:
symbol, current_position_pnl symbol, current_position_pnl
) )
# Determine decision source based on contributing models
source = self._determine_decision_source(reasoning.get("models_used", []), best_confidence)
# Create final decision # Create final decision
decision = TradingDecision( decision = TradingDecision(
action=best_action, action=best_action,
@ -4807,6 +4861,7 @@ class TradingOrchestrator:
timestamp=timestamp, timestamp=timestamp,
reasoning=reasoning, reasoning=reasoning,
memory_usage=memory_usage.get("models", {}) if memory_usage else {}, memory_usage=memory_usage.get("models", {}) if memory_usage else {},
source=source,
entry_aggressiveness=entry_aggressiveness, entry_aggressiveness=entry_aggressiveness,
exit_aggressiveness=exit_aggressiveness, exit_aggressiveness=exit_aggressiveness,
current_position_pnl=current_position_pnl, current_position_pnl=current_position_pnl,
@ -4828,6 +4883,7 @@ class TradingOrchestrator:
action="HOLD", action="HOLD",
confidence=0.0, confidence=0.0,
symbol=symbol, symbol=symbol,
source="error_fallback",
price=price, price=price,
timestamp=timestamp, timestamp=timestamp,
reasoning={"error": str(e)}, reasoning={"error": str(e)},
@ -5465,6 +5521,9 @@ class TradingOrchestrator:
except Exception: except Exception:
pass pass
# Determine decision source
source = self._determine_decision_source(reasoning.get("models_used", []), best_confidence)
# Create final decision # Create final decision
decision = TradingDecision( decision = TradingDecision(
action=best_action, action=best_action,
@ -5474,6 +5533,7 @@ class TradingOrchestrator:
timestamp=timestamp, timestamp=timestamp,
reasoning=reasoning, reasoning=reasoning,
memory_usage=memory_usage.get("models", {}) if memory_usage else {}, memory_usage=memory_usage.get("models", {}) if memory_usage else {},
source=source,
entry_aggressiveness=self.entry_aggressiveness, entry_aggressiveness=self.entry_aggressiveness,
exit_aggressiveness=self.exit_aggressiveness, exit_aggressiveness=self.exit_aggressiveness,
current_position_pnl=current_position_pnl, current_position_pnl=current_position_pnl,
@ -6643,10 +6703,25 @@ class TradingOrchestrator:
} }
target = target_mapping.get(action, [0, 0, 1]) target = target_mapping.get(action, [0, 0, 1])
# Add training sample # Decision fusion network doesn't have add_training_sample method
self.decision_fusion_network.add_training_sample( # Instead, we'll store the training data for later batch training
fusion_input, target, weight=confidence if not hasattr(self, 'decision_fusion_training_data'):
) self.decision_fusion_training_data = []
# Convert target list to action string for compatibility
target_action = "BUY" if target[0] == 1 else "SELL" if target[1] == 1 else "HOLD"
self.decision_fusion_training_data.append({
'input_features': fusion_input,
'target_action': target_action,
'weight': confidence,
'timestamp': datetime.now()
})
# Train the network if we have enough samples
if len(self.decision_fusion_training_data) >= 5: # Train every 5 samples
self._train_decision_fusion_network()
self.decision_fusion_training_data = [] # Clear after training
models_trained.append("decision_fusion") models_trained.append("decision_fusion")
logger.debug(f"🤝 Added decision fusion training sample: {action} {symbol}") logger.debug(f"🤝 Added decision fusion training sample: {action} {symbol}")

View File

@ -21,5 +21,5 @@
"training_enabled": true "training_enabled": true
} }
}, },
"timestamp": "2025-07-29T09:07:36.747677" "timestamp": "2025-07-29T09:18:36.627596"
} }

View File

@ -2491,7 +2491,14 @@ class CleanTradingDashboard:
# Extract source information from signal # Extract source information from signal
signal_source = 'Unknown' signal_source = 'Unknown'
if hasattr(signal, 'reasoning') and signal.reasoning:
# First try to get source directly from the signal (new method)
if hasattr(signal, 'source') and signal.source:
signal_source = signal.source
elif isinstance(signal, dict) and 'source' in signal and signal['source']:
signal_source = signal['source']
# Fallback to old method using reasoning.models_used
elif hasattr(signal, 'reasoning') and signal.reasoning:
models_used = signal.reasoning.get('models_used', []) models_used = signal.reasoning.get('models_used', [])
if models_used: if models_used:
signal_source = ', '.join(models_used) signal_source = ', '.join(models_used)
@ -5107,6 +5114,7 @@ class CleanTradingDashboard:
'blocked': False, 'blocked': False,
'manual': True, # CRITICAL: Mark as manual for special handling 'manual': True, # CRITICAL: Mark as manual for special handling
'reason': f'Manual {action} button', 'reason': f'Manual {action} button',
'source': 'Manual', # Clear source for manual trades
'model_inputs': model_inputs, # Store for training 'model_inputs': model_inputs, # Store for training
'persistent': True, # MARK for persistent display 'persistent': True, # MARK for persistent display
'chart_priority': 'HIGH' # High priority for chart display 'chart_priority': 'HIGH' # High priority for chart display
@ -8169,7 +8177,9 @@ class CleanTradingDashboard:
'symbol': symbol, 'symbol': symbol,
'confidence': confidence, 'confidence': confidence,
'timestamp': datetime.now(), 'timestamp': datetime.now(),
'executed': False 'executed': False,
'source': getattr(decision, 'source', 'Unknown'),
'reasoning': getattr(decision, 'reasoning', {})
} }
# Add any other attributes from the decision object # Add any other attributes from the decision object
for attr in ['price', 'quantity', 'reasoning', 'model_source']: for attr in ['price', 'quantity', 'reasoning', 'model_source']:
@ -8179,6 +8189,9 @@ class CleanTradingDashboard:
dashboard_decision = decision.copy() dashboard_decision = decision.copy()
dashboard_decision['timestamp'] = datetime.now() dashboard_decision['timestamp'] = datetime.now()
dashboard_decision['executed'] = False dashboard_decision['executed'] = False
# Ensure source is preserved
if 'source' not in dashboard_decision:
dashboard_decision['source'] = 'Unknown'
logger.info(f"[ORCHESTRATOR SIGNAL] Received: {action} for {symbol} (confidence: {confidence:.3f})") logger.info(f"[ORCHESTRATOR SIGNAL] Received: {action} for {symbol} (confidence: {confidence:.3f})")