feat: Backtesting engine completo + documentación (Semanas 3-4)

 Motor de backtesting:
- BacktestEngine con simulación de trades
- Sistema de Trade y Position
- Gestión de capital y comisiones
- Slippage simulado

 Estrategias implementadas:
- MovingAverageCrossover (SMA/EMA configurable)
- RSIStrategy (umbrales personalizables)
- BuyAndHold (baseline)

 Métricas de performance:
- Sharpe Ratio, Sortino Ratio, Calmar Ratio
- Max Drawdown, Win Rate, Profit Factor
- Expectancy, Risk/Reward Ratio

 Scripts:
- backtest.py: Ejecutar backtests individuales
- backtest.py compare: Comparar múltiples estrategias

 Documentación:
- README actualizado con sección de backtesting
- Ejemplos de uso programático
- Estructura de proyecto actualizada
This commit is contained in:
DaM
2026-01-27 21:37:39 +01:00
parent 0522ea17ca
commit 9b34de3127
14 changed files with 2020 additions and 20 deletions

View File

@@ -0,0 +1,65 @@
# src/strategies/rsi_strategy.py
"""
Estrategia basada en RSI
"""
import pandas as pd
from ..backtest.strategy import Strategy, Signal, calculate_rsi
class RSIStrategy(Strategy):
"""
Estrategia basada en RSI (Relative Strength Index)
Señales:
- BUY: Cuando RSI < oversold_threshold (mercado sobrevendido)
- SELL: Cuando RSI > overbought_threshold (mercado sobrecomprado)
- HOLD: RSI en zona neutral
Parámetros:
rsi_period: Periodo del RSI (default: 14)
oversold_threshold: Umbral de sobreventa (default: 30)
overbought_threshold: Umbral de sobrecompra (default: 70)
"""
def __init__(self, rsi_period: int = 14, oversold_threshold: float = 30, overbought_threshold: float = 70):
params = {
'rsi_period': rsi_period,
'oversold': oversold_threshold,
'overbought': overbought_threshold
}
super().__init__(name="RSI Strategy", params=params)
self.rsi_period = rsi_period
self.oversold = oversold_threshold
self.overbought = overbought_threshold
def init_indicators(self, data: pd.DataFrame) -> pd.DataFrame:
"""
Calcula el RSI
"""
data['rsi'] = calculate_rsi(data['close'], self.rsi_period)
return data
def generate_signal(self, idx: int) -> Signal:
"""
Genera señal basada en niveles de RSI
"""
if self.data is None:
raise ValueError("Data no establecida")
rsi = self.data.iloc[idx]['rsi']
# Verificar que RSI está calculado
if pd.isna(rsi):
return Signal.HOLD
# Sobreventa: señal de compra
if rsi < self.oversold and self.current_position <= 0:
return Signal.BUY
# Sobrecompra: señal de venta
elif rsi > self.overbought and self.current_position >= 0:
return Signal.SELL
return Signal.HOLD