diff --git a/core/data_provider.py b/core/data_provider.py index fddc3c8..fc2fc5a 100644 --- a/core/data_provider.py +++ b/core/data_provider.py @@ -1334,10 +1334,10 @@ class DataProvider: df['psar'] = psar.psar() # === MOMENTUM INDICATORS === - # RSI (multiple periods) - df['rsi_14'] = ta.momentum.rsi(df['close'], window=14) - df['rsi_7'] = ta.momentum.rsi(df['close'], window=7) - df['rsi_21'] = ta.momentum.rsi(df['close'], window=21) + # RSI (multiple periods) - using our own implementation to avoid ta library deprecation warnings + df['rsi_14'] = self._calculate_rsi(df['close'], period=14) + df['rsi_7'] = self._calculate_rsi(df['close'], period=7) + df['rsi_21'] = self._calculate_rsi(df['close'], period=21) # Stochastic Oscillator stoch = ta.momentum.StochasticOscillator(df['high'], df['low'], df['close']) @@ -2191,9 +2191,9 @@ class DataProvider: df['sma_20'] = ta.trend.sma_indicator(df['close'], window=20) df['ema_12'] = ta.trend.ema_indicator(df['close'], window=12) - # Basic RSI + # Basic RSI - using our own implementation to avoid ta library deprecation warnings if len(df) >= 14: - df['rsi_14'] = ta.momentum.rsi(df['close'], window=14) + df['rsi_14'] = self._calculate_rsi(df['close'], period=14) # Basic volume indicators if len(df) >= 10: @@ -2212,6 +2212,31 @@ class DataProvider: logger.error(f"Error adding basic indicators: {e}") return df + def _calculate_rsi(self, prices: pd.Series, period: int = 14) -> float: + """Calculate RSI (Relative Strength Index) - custom implementation to avoid ta library deprecation warnings""" + try: + if len(prices) < period + 1: + return 50.0 # Default neutral value + + # Calculate price changes + delta = prices.diff() + + # Separate gains and losses + gain = (delta.where(delta > 0, 0)).rolling(window=period).mean() + loss = (-delta.where(delta < 0, 0)).rolling(window=period).mean() + + # Calculate RS and RSI + rs = gain / loss + rsi = 100 - (100 / (1 + rs)) + + # Return the last value, or 50 if NaN + last_rsi = rsi.iloc[-1] + return float(last_rsi) if not pd.isna(last_rsi) else 50.0 + + except Exception as e: + logger.debug(f"Error calculating RSI: {e}") + return 50.0 # Default neutral value + def _load_from_cache(self, symbol: str, timeframe: str) -> Optional[pd.DataFrame]: """Load data from cache""" try: diff --git a/core/orchestrator.py b/core/orchestrator.py index 10250c8..cdbadb1 100644 --- a/core/orchestrator.py +++ b/core/orchestrator.py @@ -81,9 +81,15 @@ class ModelStatistics: """Statistics for tracking model performance and inference metrics""" model_name: str last_inference_time: Optional[datetime] = None + last_training_time: Optional[datetime] = None total_inferences: int = 0 + total_trainings: int = 0 inference_rate_per_minute: float = 0.0 inference_rate_per_second: float = 0.0 + training_rate_per_minute: float = 0.0 + training_rate_per_second: float = 0.0 + average_inference_time_ms: float = 0.0 + average_training_time_ms: float = 0.0 current_loss: Optional[float] = None average_loss: Optional[float] = None best_loss: Optional[float] = None @@ -92,10 +98,14 @@ class ModelStatistics: last_prediction: Optional[str] = None last_confidence: Optional[float] = None inference_times: deque = field(default_factory=lambda: deque(maxlen=100)) # Last 100 inference times + training_times: deque = field(default_factory=lambda: deque(maxlen=100)) # Last 100 training times + inference_durations_ms: deque = field(default_factory=lambda: deque(maxlen=100)) # Last 100 inference durations + training_durations_ms: deque = field(default_factory=lambda: deque(maxlen=100)) # Last 100 training durations losses: deque = field(default_factory=lambda: deque(maxlen=100)) # Last 100 losses predictions_history: deque = field(default_factory=lambda: deque(maxlen=50)) # Last 50 predictions - def update_inference_stats(self, prediction: Optional[Prediction] = None, loss: Optional[float] = None): + def update_inference_stats(self, prediction: Optional[Prediction] = None, loss: Optional[float] = None, + inference_duration_ms: Optional[float] = None): """Update inference statistics""" current_time = datetime.now() @@ -104,6 +114,12 @@ class ModelStatistics: self.total_inferences += 1 self.inference_times.append(current_time) + # Update inference duration + if inference_duration_ms is not None: + self.inference_durations_ms.append(inference_duration_ms) + if self.inference_durations_ms: + self.average_inference_time_ms = sum(self.inference_durations_ms) / len(self.inference_durations_ms) + # Calculate inference rates if len(self.inference_times) > 1: time_window = (self.inference_times[-1] - self.inference_times[0]).total_seconds() @@ -4483,8 +4499,9 @@ class TradingOrchestrator: # Calculate basic technical indicators indicators = {} try: - import ta - indicators['rsi'] = ta.momentum.RSIIndicator(df['close']).rsi().iloc[-1] + # Use our own RSI implementation to avoid ta library deprecation warnings + if len(df) >= 14: + indicators['rsi'] = self._calculate_rsi(df['close'], period=14) indicators['sma_20'] = df['close'].rolling(20).mean().iloc[-1] indicators['ema_12'] = df['close'].ewm(span=12).mean().iloc[-1] indicators['ema_26'] = df['close'].ewm(span=26).mean().iloc[-1] @@ -4594,9 +4611,9 @@ class TradingOrchestrator: # Calculate indicators indicators = {} try: - import ta + # Use our own RSI implementation to avoid ta library deprecation warnings if len(df) >= 14: - indicators['rsi'] = ta.momentum.RSIIndicator(df['close']).rsi().iloc[-1] + indicators['rsi'] = self._calculate_rsi(df['close'], period=14) if len(df) >= 20: indicators['sma_20'] = df['close'].rolling(20).mean().iloc[-1] if len(df) >= 12: diff --git a/data/trading_system.db b/data/trading_system.db index 0aa8b65..7622418 100644 Binary files a/data/trading_system.db and b/data/trading_system.db differ