From ec24d55e00a68af98001ee054e89f7381bd8006d Mon Sep 17 00:00:00 2001 From: Dobromir Popov Date: Wed, 30 Jul 2025 01:29:00 +0300 Subject: [PATCH] fix training on prev inferences, fix sim PnL calculations --- core/orchestrator.py | 35 +++++++++++++++++++++++++++++++++++ core/trading_executor.py | 22 ++++++++++++++-------- data/ui_state.json | 4 ++-- 3 files changed, 51 insertions(+), 10 deletions(-) diff --git a/core/orchestrator.py b/core/orchestrator.py index 1ab1962..493fd58 100644 --- a/core/orchestrator.py +++ b/core/orchestrator.py @@ -2808,8 +2808,16 @@ class TradingOrchestrator: "inference_price": current_price, # Store price at inference time } + # Store previous inference for training before overwriting + previous_inference = self.last_inference.get(model_name) + # Store only the last inference per model (for immediate training) self.last_inference[model_name] = inference_record + + # If we have a previous inference, trigger training on it immediately + if previous_inference and not previous_inference.get("outcome_evaluated", False): + logger.debug(f"Triggering immediate training on previous inference for {model_name}") + asyncio.create_task(self._trigger_immediate_training_for_previous_inference(model_name, previous_inference, current_price)) # Also save to database using database manager for future training and analysis asyncio.create_task( @@ -3167,6 +3175,18 @@ class TradingOrchestrator: logger.debug(f"Skipping {model_name} - already evaluated") return + # Check if enough time has passed since inference (minimum 30 seconds for meaningful price movement) + timestamp = inference_record.get("timestamp") + if isinstance(timestamp, str): + timestamp = datetime.fromisoformat(timestamp) + + time_since_inference = (datetime.now() - timestamp).total_seconds() + min_training_delay = 30 # Minimum 30 seconds before training + + if time_since_inference < min_training_delay: + logger.debug(f"Skipping {model_name} - only {time_since_inference:.1f}s since inference (minimum {min_training_delay}s required)") + return + # Get current price for outcome evaluation current_price = self._get_current_price(symbol) if current_price is None: @@ -3379,6 +3399,20 @@ class TradingOrchestrator: except Exception as e: logger.error(f"Error in immediate training for {model_name}: {e}") + async def _trigger_immediate_training_for_previous_inference(self, model_name: str, previous_inference: Dict, current_price: float): + """Trigger immediate training for a previous inference with current price""" + try: + logger.info(f"Training {model_name} on previous inference with current price: {current_price}") + + # Evaluate the previous prediction and train the model immediately + await self._evaluate_and_train_on_record(previous_inference, current_price) + + # Mark as evaluated + previous_inference["outcome_evaluated"] = True + + except Exception as e: + logger.error(f"Error in immediate training for previous inference {model_name}: {e}") + async def _evaluate_and_train_on_record(self, record: Dict, current_price: float): """Evaluate prediction outcome and train model""" try: @@ -4534,6 +4568,7 @@ class TradingOrchestrator: price_direction_pred, features_refined, advanced_pred, + multi_timeframe_pred, ) = self.cnn_model(features_tensor) # Calculate primary Q-value loss diff --git a/core/trading_executor.py b/core/trading_executor.py index dde4d04..f3e270f 100644 --- a/core/trading_executor.py +++ b/core/trading_executor.py @@ -1441,10 +1441,13 @@ class TradingExecutor: if self.simulation_mode: logger.info(f"SIMULATION MODE ({self.trading_mode.upper()}) - Short close logged but not executed") - # Calculate simulated fees in simulation mode + # Calculate simulated fees in simulation mode - FIXED to include both entry and exit fees trading_fees = self.exchange_config.get('trading_fees', {}) taker_fee_rate = trading_fees.get('taker_fee', trading_fees.get('default_fee', 0.0006)) - simulated_fees = position.quantity * current_price * taker_fee_rate + # Calculate both entry and exit fees + entry_fee = position.quantity * position.entry_price * taker_fee_rate + exit_fee = position.quantity * current_price * taker_fee_rate + simulated_fees = entry_fee + exit_fee # Get current leverage setting leverage = self.get_leverage() @@ -1452,8 +1455,8 @@ class TradingExecutor: # Calculate position size in USD position_size_usd = position.quantity * position.entry_price - # Calculate gross PnL (before fees) with leverage - gross_pnl = (current_price - position.entry_price) * position.quantity * leverage + # Calculate gross PnL (before fees) with leverage - FIXED for SHORT positions + gross_pnl = (position.entry_price - current_price) * position.quantity * leverage # Calculate net PnL (after fees) net_pnl = gross_pnl - simulated_fees @@ -1543,8 +1546,8 @@ class TradingExecutor: # Calculate position size in USD position_size_usd = position.quantity * position.entry_price - # Calculate gross PnL (before fees) with leverage - gross_pnl = (current_price - position.entry_price) * position.quantity * leverage + # Calculate gross PnL (before fees) with leverage - FIXED for SHORT positions + gross_pnl = (position.entry_price - current_price) * position.quantity * leverage # Calculate net PnL (after fees) net_pnl = gross_pnl - fees @@ -1619,10 +1622,13 @@ class TradingExecutor: if self.simulation_mode: logger.info(f"SIMULATION MODE ({self.trading_mode.upper()}) - Long close logged but not executed") - # Calculate simulated fees in simulation mode + # Calculate simulated fees in simulation mode - FIXED to include both entry and exit fees trading_fees = self.exchange_config.get('trading_fees', {}) taker_fee_rate = trading_fees.get('taker_fee', trading_fees.get('default_fee', 0.0006)) - simulated_fees = position.quantity * current_price * taker_fee_rate + # Calculate both entry and exit fees + entry_fee = position.quantity * position.entry_price * taker_fee_rate + exit_fee = position.quantity * current_price * taker_fee_rate + simulated_fees = entry_fee + exit_fee # Get current leverage setting leverage = self.get_leverage() diff --git a/data/ui_state.json b/data/ui_state.json index 8348fc1..a468778 100644 --- a/data/ui_state.json +++ b/data/ui_state.json @@ -21,9 +21,9 @@ "training_enabled": true }, "dqn_agent": { - "inference_enabled": false, + "inference_enabled": true, "training_enabled": true } }, - "timestamp": "2025-07-30T00:17:57.738273" + "timestamp": "2025-07-30T00:41:19.241862" } \ No newline at end of file