model toggles

This commit is contained in:
Dobromir Popov
2025-08-09 23:03:54 +03:00
parent 31a41785d6
commit b17d53510a
3 changed files with 127 additions and 31 deletions

View File

@ -410,11 +410,11 @@ class TradingOrchestrator:
# Model toggle states - control which models contribute to decisions
self.model_toggle_states = {
"dqn": {"inference_enabled": True, "training_enabled": True},
"cnn": {"inference_enabled": True, "training_enabled": True},
"cob_rl": {"inference_enabled": True, "training_enabled": True},
"decision_fusion": {"inference_enabled": True, "training_enabled": True},
"transformer": {"inference_enabled": True, "training_enabled": True},
"dqn": {"inference_enabled": True, "training_enabled": True, "routing_enabled": True},
"cnn": {"inference_enabled": True, "training_enabled": True, "routing_enabled": True},
"cob_rl": {"inference_enabled": True, "training_enabled": True, "routing_enabled": True},
"decision_fusion": {"inference_enabled": True, "training_enabled": True, "routing_enabled": True},
"transformer": {"inference_enabled": True, "training_enabled": True, "routing_enabled": True},
}
# UI state persistence
@ -537,6 +537,23 @@ class TradingOrchestrator:
self._initialize_transformer_model() # Initialize transformer model
self._initialize_enhanced_training_system() # Initialize real-time training
def _normalize_model_name(self, name: str) -> str:
"""Map various registry/UI names to canonical toggle keys."""
try:
mapping = {
"dqn_agent": "dqn",
"enhanced_cnn": "cnn",
"cnn_model": "cnn",
"decision": "decision_fusion",
"decision_fusion": "decision_fusion",
"cob_rl_model": "cob_rl",
"cob_rl": "cob_rl",
"transformer_model": "transformer",
}
return mapping.get(name, name)
except Exception:
return name
def _initialize_ml_models(self):
"""Initialize ML models for enhanced trading"""
try:
@ -1411,7 +1428,22 @@ class TradingOrchestrator:
with open(self.ui_state_file, "r") as f:
ui_state = json.load(f)
if "model_toggle_states" in ui_state:
self.model_toggle_states.update(ui_state["model_toggle_states"])
# Normalize and sanitize loaded toggle states
loaded = {}
for raw_name, raw_state in ui_state["model_toggle_states"].items():
key = self._normalize_model_name(raw_name)
state = {
"inference_enabled": bool(raw_state.get("inference_enabled", True)) if isinstance(raw_state.get("inference_enabled", True), bool) else True,
"training_enabled": bool(raw_state.get("training_enabled", True)) if isinstance(raw_state.get("training_enabled", True), bool) else True,
"routing_enabled": bool(raw_state.get("routing_enabled", True)) if isinstance(raw_state.get("routing_enabled", True), bool) else True,
}
loaded[key] = state
# Merge into current defaults
for k, v in loaded.items():
if k not in self.model_toggle_states:
self.model_toggle_states[k] = v
else:
self.model_toggle_states[k].update(v)
logger.info(f"UI state loaded from {self.ui_state_file}")
except Exception as e:
logger.error(f"Error loading UI state: {e}")
@ -1432,29 +1464,33 @@ class TradingOrchestrator:
def get_model_toggle_state(self, model_name: str) -> Dict[str, bool]:
"""Get toggle state for a model"""
return self.model_toggle_states.get(model_name, {"inference_enabled": True, "training_enabled": True})
key = self._normalize_model_name(model_name)
return self.model_toggle_states.get(key, {"inference_enabled": True, "training_enabled": True, "routing_enabled": True})
def set_model_toggle_state(self, model_name: str, inference_enabled: bool = None, training_enabled: bool = None):
def set_model_toggle_state(self, model_name: str, inference_enabled: bool = None, training_enabled: bool = None, routing_enabled: bool = None):
"""Set toggle state for a model - Universal handler for any model"""
key = self._normalize_model_name(model_name)
# Initialize model toggle state if it doesn't exist
if model_name not in self.model_toggle_states:
self.model_toggle_states[model_name] = {"inference_enabled": True, "training_enabled": True}
logger.info(f"Initialized toggle state for new model: {model_name}")
if key not in self.model_toggle_states:
self.model_toggle_states[key] = {"inference_enabled": True, "training_enabled": True, "routing_enabled": True}
logger.info(f"Initialized toggle state for new model: {key}")
# Update the toggle states
if inference_enabled is not None:
self.model_toggle_states[model_name]["inference_enabled"] = inference_enabled
self.model_toggle_states[key]["inference_enabled"] = inference_enabled
if training_enabled is not None:
self.model_toggle_states[model_name]["training_enabled"] = training_enabled
self.model_toggle_states[key]["training_enabled"] = training_enabled
if routing_enabled is not None:
self.model_toggle_states[key]["routing_enabled"] = routing_enabled
# Save the updated state
self._save_ui_state()
# Log the change
logger.info(f"Model {model_name} toggle state updated: inference={self.model_toggle_states[model_name]['inference_enabled']}, training={self.model_toggle_states[model_name]['training_enabled']}")
logger.info(f"Model {key} toggle state updated: inference={self.model_toggle_states[key]['inference_enabled']}, training={self.model_toggle_states[key]['training_enabled']}, routing={self.model_toggle_states[key].get('routing_enabled', True)}")
# Notify any listeners about the toggle change
self._notify_model_toggle_change(model_name, self.model_toggle_states[model_name])
self._notify_model_toggle_change(key, self.model_toggle_states[key])
def _notify_model_toggle_change(self, model_name: str, toggle_state: Dict[str, bool]):
"""Notify components about model toggle changes"""
@ -1513,11 +1549,23 @@ class TradingOrchestrator:
def is_model_inference_enabled(self, model_name: str) -> bool:
"""Check if model inference is enabled"""
return self.model_toggle_states.get(model_name, {}).get("inference_enabled", True)
key = self._normalize_model_name(model_name)
return self.model_toggle_states.get(key, {}).get("inference_enabled", True)
def is_model_training_enabled(self, model_name: str) -> bool:
"""Check if model training is enabled"""
return self.model_toggle_states.get(model_name, {}).get("training_enabled", True)
key = self._normalize_model_name(model_name)
return self.model_toggle_states.get(key, {}).get("training_enabled", True)
def is_model_routing_enabled(self, model_name: str) -> bool:
"""Check if model output should be routed into decision making"""
key = self._normalize_model_name(model_name)
return self.model_toggle_states.get(key, {}).get("routing_enabled", True)
def set_model_routing_state(self, model_name: str, routing_enabled: bool):
"""Set routing state for a model"""
key = self._normalize_model_name(model_name)
self.set_model_toggle_state(key, routing_enabled=routing_enabled)
def disable_decision_fusion_temporarily(self, reason: str = "overconfidence detected"):
"""Temporarily disable decision fusion model due to issues"""
@ -2346,6 +2394,10 @@ class TradingOrchestrator:
for model_name, model in self.model_registry.models.items():
try:
# Respect inference toggle: skip inference entirely when disabled
if not self.is_model_inference_enabled(model_name):
logger.debug(f"Inference disabled for {model_name}; skipping model call")
continue
prediction = None
model_input = base_data # Use the same base data for all models
@ -5295,6 +5347,10 @@ class TradingOrchestrator:
if not self.is_model_inference_enabled(pred.model_name):
logger.debug(f"Skipping disabled model {pred.model_name} in decision making")
continue
# Check routing toggle: even if inference happened, we may ignore it in decision fusion/programmatic fusion
if not self.is_model_routing_enabled(pred.model_name):
logger.debug(f"Routing disabled for {pred.model_name}; excluding from decision aggregation")
continue
# DEBUG: Log individual model predictions
logger.debug(f"Model {pred.model_name}: {pred.action} (confidence: {pred.confidence:.3f})")
@ -6175,8 +6231,12 @@ class TradingOrchestrator:
except Exception:
pass
# Determine decision source
source = self._determine_decision_source(reasoning.get("models_used", []), best_confidence)
# Determine decision source, honoring routing toggles: only count models whose routing is enabled
try:
routed_models = [m for m in reasoning.get("models_used", []) if self.is_model_routing_enabled(m)]
except Exception:
routed_models = reasoning.get("models_used", [])
source = self._determine_decision_source(routed_models, best_confidence)
# Create final decision
decision = TradingDecision(
@ -6413,11 +6473,12 @@ class TradingOrchestrator:
predicted_action = record.get("action", "HOLD")
# Determine if the decision was correct based on price movement
if predicted_action == "BUY" and price_change_pct > 0.1:
# Use realistic microstructure thresholds (approx 0.1%)
if predicted_action == "BUY" and price_change_pct > 0.001:
target_action = "BUY"
elif predicted_action == "SELL" and price_change_pct < -0.1:
elif predicted_action == "SELL" and price_change_pct < -0.001:
target_action = "SELL"
elif predicted_action == "HOLD" and abs(price_change_pct) < 0.1:
elif predicted_action == "HOLD" and abs(price_change_pct) < 0.001:
target_action = "HOLD"
else:
# Decision was wrong - use opposite action as target
@ -7416,8 +7477,10 @@ class TradingOrchestrator:
if self.decision_fusion_network and self.is_model_training_enabled("decision_fusion"):
try:
# Create decision fusion input
# Build market_data on demand (avoid undefined reference)
market_snapshot = self._get_current_market_data(symbol)
fusion_input = self._create_decision_fusion_training_input(
symbol, market_data
symbol, market_snapshot if market_snapshot else {}
)
# Create target based on action

View File

@ -1662,20 +1662,42 @@ class CleanTradingDashboard:
if self.orchestrator and hasattr(self.orchestrator, 'set_model_toggle_state'):
# Map dashboard names to orchestrator names
model_mapping = {
'dqn_agent': 'dqn_agent',
'enhanced_cnn': 'enhanced_cnn',
'cob_rl_model': 'cob_rl_model',
'dqn_agent': 'dqn',
'enhanced_cnn': 'cnn',
'cob_rl_model': 'cob_rl',
'extrema_trainer': 'extrema_trainer',
'transformer': 'transformer',
'decision_fusion': 'decision_fusion'
}
orchestrator_name = model_mapping.get(model_name, model_name)
self.orchestrator.set_model_toggle_state(
orchestrator_name,
toggle_type + '_enabled',
is_enabled
)
# Support three toggles: inference_enabled, training_enabled, routing_enabled
if toggle_type == 'inference':
self.orchestrator.set_model_toggle_state(
orchestrator_name,
inference_enabled=is_enabled
)
elif toggle_type == 'training':
self.orchestrator.set_model_toggle_state(
orchestrator_name,
training_enabled=is_enabled
)
elif toggle_type == 'routing':
# New: whether the model output is routed into decision making
if hasattr(self.orchestrator, 'set_model_routing_state'):
self.orchestrator.set_model_routing_state(orchestrator_name, routing_enabled=is_enabled)
else:
# Fallback: store in orchestrator.model_toggle_states under 'routing_enabled'
if not hasattr(self.orchestrator, 'model_toggle_states'):
self.orchestrator.model_toggle_states = {}
if orchestrator_name not in self.orchestrator.model_toggle_states:
self.orchestrator.model_toggle_states[orchestrator_name] = {}
self.orchestrator.model_toggle_states[orchestrator_name]['routing_enabled'] = is_enabled
if hasattr(self.orchestrator, '_save_ui_state'):
try:
self.orchestrator._save_ui_state()
except Exception:
pass
logger.info(f"Updated {orchestrator_name} {toggle_type}_enabled = {is_enabled}")
# Return all current values (no change needed)

View File

@ -215,6 +215,7 @@ class ModelsTrainingPanel:
if isinstance(toggle_state, dict):
model_data['training_enabled'] = toggle_state.get('training_enabled', True)
model_data['inference_enabled'] = toggle_state.get('inference_enabled', True)
model_data['routing_enabled'] = toggle_state.get('routing_enabled', True)
# Get model statistics
if hasattr(self.orchestrator, 'get_model_statistics'):
@ -584,6 +585,16 @@ class ModelsTrainingPanel:
className="form-check-input",
style={"transform": "scale(0.7)"}
)
], className="d-flex align-items-center me-2"),
html.Div([
html.Label("Route", className="text-muted small me-1", style={"font-size": "10px"}),
dcc.Checklist(
id={'type': 'model-toggle', 'model': model_name, 'toggle_type': 'routing'},
options=[{"label": "", "value": True}],
value=[True] if model_data.get('routing_enabled', True) else [],
className="form-check-input",
style={"transform": "scale(0.7)"}
)
], className="d-flex align-items-center")
], className="d-flex")
], className="d-flex align-items-center mb-2"),