model toggles
This commit is contained in:
@ -410,11 +410,11 @@ class TradingOrchestrator:
|
|||||||
|
|
||||||
# Model toggle states - control which models contribute to decisions
|
# Model toggle states - control which models contribute to decisions
|
||||||
self.model_toggle_states = {
|
self.model_toggle_states = {
|
||||||
"dqn": {"inference_enabled": True, "training_enabled": True},
|
"dqn": {"inference_enabled": True, "training_enabled": True, "routing_enabled": True},
|
||||||
"cnn": {"inference_enabled": True, "training_enabled": True},
|
"cnn": {"inference_enabled": True, "training_enabled": True, "routing_enabled": True},
|
||||||
"cob_rl": {"inference_enabled": True, "training_enabled": True},
|
"cob_rl": {"inference_enabled": True, "training_enabled": True, "routing_enabled": True},
|
||||||
"decision_fusion": {"inference_enabled": True, "training_enabled": True},
|
"decision_fusion": {"inference_enabled": True, "training_enabled": True, "routing_enabled": True},
|
||||||
"transformer": {"inference_enabled": True, "training_enabled": True},
|
"transformer": {"inference_enabled": True, "training_enabled": True, "routing_enabled": True},
|
||||||
}
|
}
|
||||||
|
|
||||||
# UI state persistence
|
# UI state persistence
|
||||||
@ -537,6 +537,23 @@ class TradingOrchestrator:
|
|||||||
self._initialize_transformer_model() # Initialize transformer model
|
self._initialize_transformer_model() # Initialize transformer model
|
||||||
self._initialize_enhanced_training_system() # Initialize real-time training
|
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):
|
def _initialize_ml_models(self):
|
||||||
"""Initialize ML models for enhanced trading"""
|
"""Initialize ML models for enhanced trading"""
|
||||||
try:
|
try:
|
||||||
@ -1411,7 +1428,22 @@ class TradingOrchestrator:
|
|||||||
with open(self.ui_state_file, "r") as f:
|
with open(self.ui_state_file, "r") as f:
|
||||||
ui_state = json.load(f)
|
ui_state = json.load(f)
|
||||||
if "model_toggle_states" in ui_state:
|
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}")
|
logger.info(f"UI state loaded from {self.ui_state_file}")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Error loading UI state: {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]:
|
def get_model_toggle_state(self, model_name: str) -> Dict[str, bool]:
|
||||||
"""Get toggle state for a model"""
|
"""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"""
|
"""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
|
# Initialize model toggle state if it doesn't exist
|
||||||
if model_name not in self.model_toggle_states:
|
if key not in self.model_toggle_states:
|
||||||
self.model_toggle_states[model_name] = {"inference_enabled": True, "training_enabled": True}
|
self.model_toggle_states[key] = {"inference_enabled": True, "training_enabled": True, "routing_enabled": True}
|
||||||
logger.info(f"Initialized toggle state for new model: {model_name}")
|
logger.info(f"Initialized toggle state for new model: {key}")
|
||||||
|
|
||||||
# Update the toggle states
|
# Update the toggle states
|
||||||
if inference_enabled is not None:
|
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:
|
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
|
# Save the updated state
|
||||||
self._save_ui_state()
|
self._save_ui_state()
|
||||||
|
|
||||||
# Log the change
|
# 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
|
# 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]):
|
def _notify_model_toggle_change(self, model_name: str, toggle_state: Dict[str, bool]):
|
||||||
"""Notify components about model toggle changes"""
|
"""Notify components about model toggle changes"""
|
||||||
@ -1513,11 +1549,23 @@ class TradingOrchestrator:
|
|||||||
|
|
||||||
def is_model_inference_enabled(self, model_name: str) -> bool:
|
def is_model_inference_enabled(self, model_name: str) -> bool:
|
||||||
"""Check if model inference is enabled"""
|
"""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:
|
def is_model_training_enabled(self, model_name: str) -> bool:
|
||||||
"""Check if model training is enabled"""
|
"""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"):
|
def disable_decision_fusion_temporarily(self, reason: str = "overconfidence detected"):
|
||||||
"""Temporarily disable decision fusion model due to issues"""
|
"""Temporarily disable decision fusion model due to issues"""
|
||||||
@ -2346,6 +2394,10 @@ class TradingOrchestrator:
|
|||||||
|
|
||||||
for model_name, model in self.model_registry.models.items():
|
for model_name, model in self.model_registry.models.items():
|
||||||
try:
|
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
|
prediction = None
|
||||||
model_input = base_data # Use the same base data for all models
|
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):
|
if not self.is_model_inference_enabled(pred.model_name):
|
||||||
logger.debug(f"Skipping disabled model {pred.model_name} in decision making")
|
logger.debug(f"Skipping disabled model {pred.model_name} in decision making")
|
||||||
continue
|
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
|
# DEBUG: Log individual model predictions
|
||||||
logger.debug(f"Model {pred.model_name}: {pred.action} (confidence: {pred.confidence:.3f})")
|
logger.debug(f"Model {pred.model_name}: {pred.action} (confidence: {pred.confidence:.3f})")
|
||||||
@ -6175,8 +6231,12 @@ class TradingOrchestrator:
|
|||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# Determine decision source
|
# Determine decision source, honoring routing toggles: only count models whose routing is enabled
|
||||||
source = self._determine_decision_source(reasoning.get("models_used", []), best_confidence)
|
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
|
# Create final decision
|
||||||
decision = TradingDecision(
|
decision = TradingDecision(
|
||||||
@ -6413,11 +6473,12 @@ class TradingOrchestrator:
|
|||||||
predicted_action = record.get("action", "HOLD")
|
predicted_action = record.get("action", "HOLD")
|
||||||
|
|
||||||
# Determine if the decision was correct based on price movement
|
# 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"
|
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"
|
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"
|
target_action = "HOLD"
|
||||||
else:
|
else:
|
||||||
# Decision was wrong - use opposite action as target
|
# 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"):
|
if self.decision_fusion_network and self.is_model_training_enabled("decision_fusion"):
|
||||||
try:
|
try:
|
||||||
# Create decision fusion input
|
# 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(
|
fusion_input = self._create_decision_fusion_training_input(
|
||||||
symbol, market_data
|
symbol, market_snapshot if market_snapshot else {}
|
||||||
)
|
)
|
||||||
|
|
||||||
# Create target based on action
|
# Create target based on action
|
||||||
|
@ -1662,20 +1662,42 @@ class CleanTradingDashboard:
|
|||||||
if self.orchestrator and hasattr(self.orchestrator, 'set_model_toggle_state'):
|
if self.orchestrator and hasattr(self.orchestrator, 'set_model_toggle_state'):
|
||||||
# Map dashboard names to orchestrator names
|
# Map dashboard names to orchestrator names
|
||||||
model_mapping = {
|
model_mapping = {
|
||||||
'dqn_agent': 'dqn_agent',
|
'dqn_agent': 'dqn',
|
||||||
'enhanced_cnn': 'enhanced_cnn',
|
'enhanced_cnn': 'cnn',
|
||||||
'cob_rl_model': 'cob_rl_model',
|
'cob_rl_model': 'cob_rl',
|
||||||
'extrema_trainer': 'extrema_trainer',
|
'extrema_trainer': 'extrema_trainer',
|
||||||
'transformer': 'transformer',
|
'transformer': 'transformer',
|
||||||
'decision_fusion': 'decision_fusion'
|
'decision_fusion': 'decision_fusion'
|
||||||
}
|
}
|
||||||
|
|
||||||
orchestrator_name = model_mapping.get(model_name, model_name)
|
orchestrator_name = model_mapping.get(model_name, model_name)
|
||||||
|
# Support three toggles: inference_enabled, training_enabled, routing_enabled
|
||||||
|
if toggle_type == 'inference':
|
||||||
self.orchestrator.set_model_toggle_state(
|
self.orchestrator.set_model_toggle_state(
|
||||||
orchestrator_name,
|
orchestrator_name,
|
||||||
toggle_type + '_enabled',
|
inference_enabled=is_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}")
|
logger.info(f"Updated {orchestrator_name} {toggle_type}_enabled = {is_enabled}")
|
||||||
|
|
||||||
# Return all current values (no change needed)
|
# Return all current values (no change needed)
|
||||||
|
@ -215,6 +215,7 @@ class ModelsTrainingPanel:
|
|||||||
if isinstance(toggle_state, dict):
|
if isinstance(toggle_state, dict):
|
||||||
model_data['training_enabled'] = toggle_state.get('training_enabled', True)
|
model_data['training_enabled'] = toggle_state.get('training_enabled', True)
|
||||||
model_data['inference_enabled'] = toggle_state.get('inference_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
|
# Get model statistics
|
||||||
if hasattr(self.orchestrator, 'get_model_statistics'):
|
if hasattr(self.orchestrator, 'get_model_statistics'):
|
||||||
@ -584,6 +585,16 @@ class ModelsTrainingPanel:
|
|||||||
className="form-check-input",
|
className="form-check-input",
|
||||||
style={"transform": "scale(0.7)"}
|
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 align-items-center")
|
||||||
], className="d-flex")
|
], className="d-flex")
|
||||||
], className="d-flex align-items-center mb-2"),
|
], className="d-flex align-items-center mb-2"),
|
||||||
|
Reference in New Issue
Block a user