# src/strategies/mean_reversion.py import pandas as pd import numpy as np from src.strategies.base import Strategy from src.core.strategy import Signal class RSIMeanReversion(Strategy): """ Estrategia de reversión a la media basada en RSI. Idea: - Compra cuando el mercado está sobrevendido - Vende cuando el precio rebota hacia la media Señales: - BUY: RSI cruza por debajo de oversold - SELL: RSI cruza por encima de overbought - HOLD: en cualquier otro caso Parámetros: period: periodo del RSI oversold: nivel de sobreventa overbought: nivel de sobrecompra Valores típicos: period = 14 oversold = 30 overbought = 70 """ def __init__( self, period: int = 14, oversold: float = 30.0, overbought: float = 70.0, ): super().__init__( name="RSI_MeanReversion", params={ "period": period, "oversold": oversold, "overbought": overbought, }, ) self.period = period self.oversold = oversold self.overbought = overbought # -------------------------------------------------- def init_indicators(self, data: pd.DataFrame) -> pd.DataFrame: """ Calcula el RSI clásico (Wilder). Añade: - data["rsi"] """ delta = data["close"].diff() gain = delta.clip(lower=0) loss = -delta.clip(upper=0) avg_gain = gain.ewm(alpha=1 / self.period, adjust=False).mean() avg_loss = loss.ewm(alpha=1 / self.period, adjust=False).mean() rs = avg_gain / avg_loss rsi = 100 - (100 / (1 + rs)) data["rsi"] = rsi return data # -------------------------------------------------- def generate_signal(self, idx: int) -> Signal: """ Genera señales de trading basadas en cruces del RSI. """ if idx == 0: return Signal.HOLD rsi_prev = self.data["rsi"].iloc[idx - 1] rsi_curr = self.data["rsi"].iloc[idx] # BUY → cruce hacia abajo de oversold if rsi_prev > self.oversold and rsi_curr <= self.oversold: return Signal.BUY # SELL → cruce hacia arriba de overbought if rsi_prev < self.overbought and rsi_curr >= self.overbought: return Signal.SELL return Signal.HOLD