27 lines
1.3 KiB
Python
27 lines
1.3 KiB
Python
from core.models import Signal
|
|
from strategies.base import Strategy
|
|
from utils.indicators import ema, rsi, atr, adx
|
|
|
|
class RegimeRsi(Strategy):
|
|
"""Stratégie par régime (ADX) : pullback RSI en range, reprise de momentum en tendance.
|
|
SL et TP fixes basés sur l'ATR. Pas de martingale, pas de grille."""
|
|
name = "regime_rsi"
|
|
|
|
def on_bar(self, symbol, df):
|
|
p = self.p
|
|
f, s = ema(df.close, p["fast"]), ema(df.close, p["slow"])
|
|
r = rsi(df.close, p["rsi_period"])
|
|
ad, a = adx(df, 14).iloc[-1], atr(df, 14).iloc[-1]
|
|
if ad > p["adx_max"]: # mouvement trop étendu: on ne poursuit pas
|
|
return None
|
|
up = f.iloc[-1] > s.iloc[-1]
|
|
r1, r0 = r.iloc[-1], r.iloc[-2]
|
|
if ad < p["adx_threshold"]: # marché calme / range: RSI "assoupli"
|
|
buy = up and r1 < p["rsi_buy_range"] and r1 > r0
|
|
sell = (not up) and r1 > p["rsi_sell_range"] and r1 < r0
|
|
else: # tendance: reprise de momentum autour de 50
|
|
buy = up and r0 < 50 <= r1 < p["rsi_ob"]
|
|
sell = (not up) and r0 > 50 >= r1 > p["rsi_os"]
|
|
if buy or sell:
|
|
return Signal(symbol, "buy" if buy else "sell", p["sl_atr"] * a, p["tp_atr"] * a,
|
|
self.name, "range" if ad < p["adx_threshold"] else "trend")
|