From ff41f0a27802a3bcdb5556f53fa4a53550c3b2a0 Mon Sep 17 00:00:00 2001 From: Dobromir Popov Date: Tue, 29 Jul 2025 15:25:36 +0300 Subject: [PATCH] training wip --- core/orchestrator.py | 56 ++++++++++++++++++++++++++++++++++-------- data/ui_state.json | 6 ++--- web/clean_dashboard.py | 53 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 102 insertions(+), 13 deletions(-) diff --git a/core/orchestrator.py b/core/orchestrator.py index 7467378..2a8c81a 100644 --- a/core/orchestrator.py +++ b/core/orchestrator.py @@ -2014,26 +2014,59 @@ class TradingOrchestrator: logger.debug(f"No fallback prediction available for {symbol}") return None - # Choose decision method based on configuration and toggle state + # NEW BEHAVIOR: Check inference and training toggle states separately decision_fusion_inference_enabled = self.is_model_inference_enabled("decision_fusion") + decision_fusion_training_enabled = self.is_model_training_enabled("decision_fusion") - if ( + # If training is enabled, we should also inference the model for training purposes + # but we may not use the predictions for actions/signals depending on inference toggle + should_inference_for_training = decision_fusion_training_enabled and ( self.decision_fusion_enabled and self.decision_fusion_mode == "neural" and self.decision_fusion_network is not None + ) + + # If inference is enabled, use neural decision fusion for actions + if ( + should_inference_for_training and decision_fusion_inference_enabled ): - # Use neural decision fusion + # Use neural decision fusion for both training and actions + logger.debug(f"Using neural decision fusion for {symbol} (inference enabled)") decision = self._make_decision_fusion_decision( symbol=symbol, predictions=predictions, current_price=current_price, timestamp=current_time, ) + elif should_inference_for_training and not decision_fusion_inference_enabled: + # Inference for training only, but use programmatic for actions + logger.info(f"Decision fusion inference disabled, using programmatic mode for {symbol} (training enabled)") + + # Make neural inference for training purposes only + training_decision = self._make_decision_fusion_decision( + symbol=symbol, + predictions=predictions, + current_price=current_price, + timestamp=current_time, + ) + + # Store inference for decision fusion training + self._store_decision_fusion_inference( + training_decision, predictions, current_price + ) + + # Use programmatic decision for actual actions + decision = self._combine_predictions( + symbol=symbol, + price=current_price, + predictions=predictions, + timestamp=current_time, + ) else: - # Use programmatic decision combination - if not decision_fusion_inference_enabled: - logger.info(f"Decision fusion model disabled, using programmatic mode for {symbol}") + # Use programmatic decision combination (no neural inference) + if not decision_fusion_inference_enabled and not decision_fusion_training_enabled: + logger.info(f"Decision fusion model disabled (inference and training off), using programmatic mode for {symbol}") else: logger.debug(f"Using programmatic decision combination for {symbol}") @@ -2044,8 +2077,11 @@ class TradingOrchestrator: timestamp=current_time, ) - # Train decision fusion model even in programmatic mode - if self.decision_fusion_enabled and self.decision_fusion_network is not None: + # Train decision fusion model even in programmatic mode if training is enabled + if (decision_fusion_training_enabled and + self.decision_fusion_enabled and + self.decision_fusion_network is not None): + # Store inference for decision fusion (like other models) self._store_decision_fusion_inference( decision, predictions, current_price @@ -5562,8 +5598,8 @@ class TradingOrchestrator: # DEBUG: Log decision fusion input features logger.info(f"=== DECISION FUSION INPUT FEATURES ===") logger.info(f" Input shape: {input_features.shape}") - logger.info(f" Input features (first 20): {input_features[0, :20].cpu().numpy()}") - logger.info(f" Input features (last 20): {input_features[0, -20:].cpu().numpy()}") + # logger.info(f" Input features (first 20): {input_features[0, :20].cpu().numpy()}") + # logger.info(f" Input features (last 20): {input_features[0, -20:].cpu().numpy()}") logger.info(f" Input features mean: {input_features.mean().item():.4f}") logger.info(f" Input features std: {input_features.std().item():.4f}") diff --git a/data/ui_state.json b/data/ui_state.json index b61cf10..f548137 100644 --- a/data/ui_state.json +++ b/data/ui_state.json @@ -1,7 +1,7 @@ { "model_toggle_states": { "dqn": { - "inference_enabled": false, + "inference_enabled": true, "training_enabled": true }, "cnn": { @@ -14,12 +14,12 @@ }, "decision_fusion": { "inference_enabled": false, - "training_enabled": true + "training_enabled": false }, "transformer": { "inference_enabled": true, "training_enabled": true } }, - "timestamp": "2025-07-29T09:18:36.627596" + "timestamp": "2025-07-29T15:16:02.752760" } \ No newline at end of file diff --git a/web/clean_dashboard.py b/web/clean_dashboard.py index 605f07e..867c487 100644 --- a/web/clean_dashboard.py +++ b/web/clean_dashboard.py @@ -1456,6 +1456,59 @@ class CleanTradingDashboard: self.decision_fusion_training_enabled = enabled logger.info(f"Decision Fusion training toggle: {enabled}") return value + + # NEW: Callback to sync toggle states from orchestrator on page load + @self.app.callback( + [Output('dqn-inference-toggle', 'value'), + Output('dqn-training-toggle', 'value'), + Output('cnn-inference-toggle', 'value'), + Output('cnn-training-toggle', 'value'), + Output('cob-rl-inference-toggle', 'value'), + Output('cob-rl-training-toggle', 'value'), + Output('decision-fusion-inference-toggle', 'value'), + Output('decision-fusion-training-toggle', 'value')], + [Input('interval-component', 'n_intervals')], + prevent_initial_call=False + ) + def sync_toggle_states_from_orchestrator(n): + """Sync toggle states from orchestrator to ensure UI consistency""" + if not self.orchestrator: + return [], [], [], [], [], [], [], [] + + try: + # Get toggle states from orchestrator + dqn_state = self.orchestrator.get_model_toggle_state("dqn") + cnn_state = self.orchestrator.get_model_toggle_state("cnn") + cob_rl_state = self.orchestrator.get_model_toggle_state("cob_rl") + decision_fusion_state = self.orchestrator.get_model_toggle_state("decision_fusion") + + # Convert to checklist values (list with 'enabled' if True, empty list if False) + dqn_inf = ['enabled'] if dqn_state.get('inference_enabled', True) else [] + dqn_trn = ['enabled'] if dqn_state.get('training_enabled', True) else [] + cnn_inf = ['enabled'] if cnn_state.get('inference_enabled', True) else [] + cnn_trn = ['enabled'] if cnn_state.get('training_enabled', True) else [] + cob_rl_inf = ['enabled'] if cob_rl_state.get('inference_enabled', True) else [] + cob_rl_trn = ['enabled'] if cob_rl_state.get('training_enabled', True) else [] + decision_inf = ['enabled'] if decision_fusion_state.get('inference_enabled', True) else [] + decision_trn = ['enabled'] if decision_fusion_state.get('training_enabled', True) else [] + + # Update dashboard state variables + self.dqn_inference_enabled = bool(dqn_inf) + self.dqn_training_enabled = bool(dqn_trn) + self.cnn_inference_enabled = bool(cnn_inf) + self.cnn_training_enabled = bool(cnn_trn) + self.cob_rl_inference_enabled = bool(cob_rl_inf) + self.cob_rl_training_enabled = bool(cob_rl_trn) + self.decision_fusion_inference_enabled = bool(decision_inf) + self.decision_fusion_training_enabled = bool(decision_trn) + + logger.debug(f"Synced toggle states from orchestrator: DQN(inf:{self.dqn_inference_enabled}, trn:{self.dqn_training_enabled}), CNN(inf:{self.cnn_inference_enabled}, trn:{self.cnn_training_enabled}), COB_RL(inf:{self.cob_rl_inference_enabled}, trn:{self.cob_rl_training_enabled}), Decision_Fusion(inf:{self.decision_fusion_inference_enabled}, trn:{self.decision_fusion_training_enabled})") + + return dqn_inf, dqn_trn, cnn_inf, cnn_trn, cob_rl_inf, cob_rl_trn, decision_inf, decision_trn + + except Exception as e: + logger.error(f"Error syncing toggle states from orchestrator: {e}") + return [], [], [], [], [], [], [], [] """Update cold start training mode""" logger.debug(f"Cold start callback triggered with value: {switch_value}") try: