Files
jerem 633b033f4d MidasBot: bot trading crypto IA + stratégies Ichimoku validées
- Infra: Freqtrade (futures dry-run) + Redis + dashboard + Docker Compose
- Couche IA: ai_analyzer (Claude via abonnement, MCP TradingView, backfill biais)
- Stratégies: SampleStrategy, AiBiasStrategy, IchimokuLS (long/short, validée
  train/test + données vierges + walk-forward), MTFIchimoku, variantes hyperopt
- Arbitrage CEX (dry-run), backtesting, walk-forward, volatility targeting
- IchimokuLS en dry-run live (config_live.json)

Claude-Session: https://claude.ai/code/session_01VHETcFacdnDhQzthLpdYFR
2026-06-23 19:25:49 +02:00

136 lines
5.6 KiB
Python

# pragma pylint: disable=missing-docstring, invalid-name, too-few-public-methods
"""
MTFIchimoku — Ichimoku MULTI-TIMEFRAME (technique S/R inter-unités).
Idée (méthode de l'utilisateur) : trader sur une unité basse (15m) en utilisant
les Tenkan/Kijun de l'unité SUPÉRIEURE (1h) comme supports/résistances.
Règles :
- Tendance 1h donnée par tenkan_1h vs kijun_1h.
- LONG : en tendance 1h haussière, le prix 15m RECLAIME le support (croise au-dessus
de la Kijun 1h) → rebond sur support.
- SHORT : en tendance 1h baissière, le prix 15m CASSE le support (croise sous la
Kijun 1h) → rejet sur résistance.
- Sortie : perte du niveau (close repasse de l'autre côté de la Kijun 1h) + ROI/stop.
La Kijun 1h sert de S/R principal (niveau lent/fort), la Tenkan 1h de filtre de tendance.
"""
from __future__ import annotations
import talib.abstract as ta
from pandas import DataFrame
from freqtrade.strategy import (
IStrategy,
informative,
IntParameter,
DecimalParameter,
)
class MTFIchimoku(IStrategy):
INTERFACE_VERSION = 3
timeframe = "15m" # unité de trading
can_short = True
# Paramètres optimisables
buy_adx_min = IntParameter(15, 40, default=25, space="buy", optimize=True)
buy_pullback_pct = DecimalParameter(0.004, 0.03, default=0.012, decimals=3, space="buy", optimize=True)
buy_rsi_max = IntParameter(50, 72, default=60, space="buy", optimize=True)
sell_rsi_min = IntParameter(28, 50, default=40, space="sell", optimize=True)
minimal_roi = {"0": 0.02, "60": 0.012, "180": 0.006, "360": 0}
stoploss = -0.025
trailing_stop = True
trailing_stop_positive = 0.008
trailing_stop_positive_offset = 0.014
trailing_only_offset_is_reached = True
startup_candle_count: int = 240
process_only_new_candles = True
use_exit_signal = True
def leverage(self, pair, current_time, current_rate, proposed_leverage,
max_leverage, entry_tag, side, **kwargs) -> float:
return 1.0
@informative("1h")
def populate_indicators_1h(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
# Tenkan / Kijun sur l'unité supérieure (1h) → deviendront tenkan_1h / kijun_1h.
high, low = dataframe["high"], dataframe["low"]
dataframe["tenkan"] = (high.rolling(9).max() + low.rolling(9).min()) / 2
dataframe["kijun"] = (high.rolling(26).max() + low.rolling(26).min()) / 2
return dataframe
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
# tenkan_1h / kijun_1h sont injectés automatiquement (forward-fill sur le 15m).
dataframe["rsi"] = ta.RSI(dataframe, timeperiod=14)
dataframe["adx"] = ta.ADX(dataframe, timeperiod=14)
# Plus haut/bas récents (pour exiger un VRAI pullback vers le niveau)
dataframe["hh8"] = dataframe["high"].rolling(8).max()
dataframe["ll8"] = dataframe["low"].rolling(8).min()
return dataframe
def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
kijun = dataframe["kijun_1h"]
tenkan = dataframe["tenkan_1h"]
close, op, low, high = (
dataframe["close"], dataframe["open"], dataframe["low"], dataframe["high"]
)
rsi = dataframe["rsi"]
adx = dataframe["adx"]
adx_min = self.buy_adx_min.value
pb = self.buy_pullback_pct.value
uptrend_1h = (tenkan > kijun) & (close > kijun) # biais haussier 1h
downtrend_1h = (tenkan < kijun) & (close < kijun) # biais baissier 1h
# LONG : en tendance forte, VRAI pullback vers le support Kijun 1h puis rebond + momentum.
dataframe.loc[
(
uptrend_1h
& (adx > adx_min) # tendance forte
& (dataframe["hh8"] > kijun * (1 + pb)) # le prix venait nettement au-dessus
& (low <= kijun * 1.001) # mèche teste le support
& (close > kijun) # clôture au-dessus (support tient)
& (close > op) # bougie de rebond
& (rsi > rsi.shift(1)) # momentum qui se retourne à la hausse
& (rsi < self.buy_rsi_max.value) # pas déjà suracheté
& (dataframe["volume"] > 0)
),
"enter_long",
] = 1
# SHORT : miroir exact (rejet sur résistance en tendance baissière forte).
dataframe.loc[
(
downtrend_1h
& (adx > adx_min)
& (dataframe["ll8"] < kijun * (1 - pb))
& (high >= kijun * 0.999)
& (close < kijun)
& (close < op)
& (rsi < rsi.shift(1))
& (rsi > self.sell_rsi_min.value)
& (dataframe["volume"] > 0)
),
"enter_short",
] = 1
return dataframe
def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
kijun = dataframe["kijun_1h"]
tenkan = dataframe["tenkan_1h"]
close = dataframe["close"]
# Sortie LONG : cassure NETTE du support (clôture sous la Kijun ET sous la Tenkan 1h)
dataframe.loc[
((close < kijun) & (close < tenkan) & (dataframe["volume"] > 0)),
"exit_long",
] = 1
# Sortie SHORT : reprise NETTE au-dessus de la résistance
dataframe.loc[
((close > kijun) & (close > tenkan) & (dataframe["volume"] > 0)),
"exit_short",
] = 1
return dataframe