model toggles
This commit is contained in:
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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"),
|
||||
|
Reference in New Issue
Block a user