feat: expand indicator library from 7 to 14

- Added: Stochastic, CCI, Williams %R, ROC Momentum, EMA Crossover, Keltner Channel, ADX
- Total: 14 indicators across 3 strategy types (single-TF, multi-TF, portfolio)
- Loop running 2000 iterations in background
This commit is contained in:
TPTBusiness
2026-05-25 19:42:34 +02:00
parent e168a5df7e
commit 3874afb8dd
+88
View File
@@ -88,6 +88,80 @@ def _ma_env_signal(c, period, pct):
return s.replace(0, np.nan).ffill(limit=3).fillna(0).astype(int).clip(-1, 1)
def _stoch_signal(c, period, smooth):
"""Stochastic Oscillator — oversold/overbought crossover."""
lo = c.rolling(period).min()
hi = c.rolling(period).max()
k = 100 * (c - lo) / (hi - lo + 1e-8)
d = k.rolling(smooth).mean()
s = pd.Series(0, index=c.index)
s[(k > d) & (k < 30)] = 1
s[(k < d) & (k > 70)] = -1
return s.fillna(0).astype(int).clip(-1, 1)
def _cci_signal(c, h, l, period):
"""Commodity Channel Index."""
tp = (h + l + c) / 3
ma = tp.rolling(period).mean()
md = (tp - ma).abs().rolling(period).mean()
cci = (tp - ma) / (0.015 * md + 1e-8)
s = pd.Series(0, index=c.index)
s[cci < -100] = 1
s[cci > 100] = -1
return s.fillna(0).astype(int).clip(-1, 1)
def _williams_r(c, h, l, period):
"""Williams %R — overbought/oversold."""
hi = h.rolling(period).max()
lo = l.rolling(period).min()
wr = -100 * (hi - c) / (hi - lo + 1e-8)
s = pd.Series(0, index=c.index)
s[wr < -80] = 1
s[wr > -20] = -1
return s.fillna(0).astype(int).clip(-1, 1)
def _roc_signal(c, period, threshold):
"""Rate of Change — momentum threshold."""
roc = c.pct_change(period) * 100
s = pd.Series(0, index=c.index)
s[roc > threshold] = 1
s[roc < -threshold] = -1
return s.fillna(0).astype(int).clip(-1, 1)
def _ema_cross(c, fast, slow):
"""EMA Crossover (separate from SMA)."""
ef = c.ewm(span=fast, adjust=False).mean()
es = c.ewm(span=slow, adjust=False).mean()
s = pd.Series(0, index=c.index)
s[ef > es] = 1
s[ef < es] = -1
return s.fillna(0).astype(int).clip(-1, 1)
def _keltner(c, h, l, period, mult):
"""Keltner Channel breakout."""
ma = c.rolling(period).mean()
atr = ((h - l).abs()).rolling(period).mean()
s = pd.Series(0, index=c.index)
s[c > ma + mult * atr] = 1
s[c < ma - mult * atr] = -1
return s.replace(0, np.nan).ffill(limit=2).fillna(0).astype(int).clip(-1, 1)
def _adx_filter(c, h, l, period, threshold):
"""ADX trend-strength filter — only trade when ADX > threshold."""
tr = pd.concat([h - l, (h - c.shift()).abs(), (l - c.shift()).abs()], axis=1).max(axis=1)
atr = tr.rolling(period).mean()
up = h - h.shift()
dn = l.shift() - l
pdi = 100 * (up.clip(lower=0).rolling(period).mean() / (atr + 1e-8))
ndi = 100 * (dn.clip(lower=0).rolling(period).mean() / (atr + 1e-8))
dx = 100 * (pdi - ndi).abs() / (pdi + ndi + 1e-8)
adx = dx.rolling(period).mean()
s = pd.Series(0, index=c.index)
s[(pdi > ndi) & (adx > threshold)] = 1
s[(ndi > pdi) & (adx > threshold)] = -1
return s.fillna(0).astype(int).clip(-1, 1)
INDICATORS = {
"MACD": {"params": {"fast": [3,5,8,12], "slow": [10,15,20,26,35], "sig": [3,5,9]},
"build": _macd_signal, "desc": "MACD({fast},{slow},{sig})"},
@@ -97,12 +171,26 @@ INDICATORS = {
"build": _rsi_signal, "desc": "RSI({period})[{oversold}/{overbought}]"},
"SMA_Cross": {"params": {"fast": [5,10,20,50], "slow": [20,50,100,200]},
"build": _sma_signal, "desc": "SMA({fast},{slow})"},
"EMA_Cross": {"params": {"fast": [3,5,8,12], "slow": [15,26,50,100]},
"build": _ema_cross, "desc": "EMA({fast},{slow})"},
"Bollinger": {"params": {"period": [10,20,40], "std": [1.5,2.0,2.5]},
"build": _bb_signal, "desc": "BB({period},{std}s)"},
"Keltner": {"params": {"period": [10,20,40], "mult": [1.0,1.5,2.0,2.5]},
"build": lambda c, period, mult: _keltner(c, c, c, period, mult), "desc": "Keltner({period},{mult})"},
"ATR_Channel":{"params": {"period": [10,20,40], "mult": [1.0,1.5,2.0,2.5]},
"build": _atr_signal, "desc": "ATR({period},{mult})"},
"MA_Envelope":{"params": {"period": [20,50,100], "pct": [0.01,0.02,0.03,0.05]},
"build": _ma_env_signal, "desc": "MA_Env({period},{pct})"},
"Stochastic": {"params": {"period": [5,9,14], "smooth": [3,5]},
"build": lambda c, period, smooth: _stoch_signal(c, period, smooth), "desc": "Stoch({period},{smooth})"},
"CCI": {"params": {"period": [14,20,50]},
"build": lambda c, period: _cci_signal(c, c, c, period), "desc": "CCI({period})"},
"WilliamsR": {"params": {"period": [7,14,21]},
"build": lambda c, period: _williams_r(c, c, c, period), "desc": "WR({period})"},
"ROC_Momentum":{"params": {"period": [5,10,20], "threshold": [0.1,0.2,0.5,1.0]},
"build": _roc_signal, "desc": "ROC({period},{threshold}%)"},
"ADX": {"params": {"period": [7,14,21], "threshold": [15,20,25]},
"build": lambda c, period, threshold: _adx_filter(c, c, c, period, threshold), "desc": "ADX({period}>{threshold})"},
}
TIMEFRAMES = ["15min", "30min", "1h", "4h", "1d"]