feat: finalize portfolio system and quantitative validation- Finalized MA_Crossover(30,100) and TrendFiltered_MA(30,100,ADX=15)

- Implemented portfolio engine with risk-based allocation (50/50)
- Added equity-based metrics for system-level evaluation
- Validated portfolio against standalone strategies
- Reduced max drawdown and volatility at system level
- Quantitative decision closed before paper trading phase
This commit is contained in:
DaM
2026-02-02 14:38:05 +01:00
parent c569170fcc
commit f85c522f22
53 changed files with 2389 additions and 104 deletions

View File

@@ -0,0 +1,95 @@
# 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