""" Indicator calculation utilities for backtesting. These functions calculate indicators directly from price data, without requiring MT5 indicator handles. """ import numpy as np import pandas as pd def calculate_rsi(prices: pd.Series, period: int = 14) -> pd.Series: """Calculate RSI indicator.""" delta = prices.diff() gain = (delta.where(delta > 0, 0)).rolling(window=period).mean() loss = (-delta.where(delta < 0, 0)).rolling(window=period).mean() rs = gain / loss rsi = 100 - (100 / (1 + rs)) return rsi def calculate_ema(prices: pd.Series, period: int = 50) -> pd.Series: """Calculate EMA indicator.""" return prices.ewm(span=period, adjust=False).mean() def calculate_sma(prices: pd.Series, period: int = 50) -> pd.Series: """Calculate SMA indicator.""" return prices.rolling(window=period).mean() def calculate_atr(df: pd.DataFrame, period: int = 14) -> pd.Series: """Calculate ATR indicator.""" high_low = df['high'] - df['low'] high_close = np.abs(df['high'] - df['close'].shift()) low_close = np.abs(df['low'] - df['close'].shift()) tr = pd.concat([high_low, high_close, low_close], axis=1).max(axis=1) atr = tr.rolling(window=period).mean() return atr def calculate_macd(prices: pd.Series, fast: int = 12, slow: int = 26, signal: int = 9) -> pd.DataFrame: """Calculate MACD indicator.""" ema_fast = prices.ewm(span=fast, adjust=False).mean() ema_slow = prices.ewm(span=slow, adjust=False).mean() macd = ema_fast - ema_slow signal_line = macd.ewm(span=signal, adjust=False).mean() histogram = macd - signal_line return pd.DataFrame({ 'macd': macd, 'signal': signal_line, 'histogram': histogram })