Basics
mode: futures
timeframe: 4h
interface version: 3
Settings
stoploss: -0.07
has minimal roi
process only new candles
startup candle count: 130
hyperopt
hyperopt params: 3
Concepts
breakout
Methods
leverage
15 related strategies (⧉ identical code, ≈ similar name)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 | from datetime import datetime from pandas import DataFrame from freqtrade.strategy import IntParameter, IStrategy class IchimokuCloudBreakoutStrategy(IStrategy): """ Ichimoku Kinko Hyo cloud breakout strategy. What this strategy does: - Computes the full Ichimoku system: - Tenkan-sen (Conversion Line): (9-period high + 9-period low) / 2 - Kijun-sen (Base Line): (26-period high + 26-period low) / 2 - Senkou Span A: (Tenkan + Kijun) / 2, plotted 26 bars forward - Senkou Span B: (52-period high + 52-period low) / 2, plotted 26 bars forward - Chikou Span: Close shifted 26 bars back - Enters long when: (a) Price is above both Senkou Span A and Span B (above the cloud). (b) Tenkan-sen is above Kijun-sen (short-term trend aligns with long-term). (c) Chikou Span is above price from 26 bars ago (past confirms current strength). - Enters short under mirrored conditions (below cloud, Tenkan < Kijun). - Exits when Tenkan crosses back through Kijun against the trade direction. Why it may work: Ichimoku is a comprehensive Japanese technical system that incorporates multiple timeframes of price information into a single chart. The cloud acts as a dynamic support/resistance zone. A price above a bullish cloud (Span A > Span B) signals that the medium-term trend is up, and requiring all three component confirmations reduces false entries significantly. It is widely used and the logic can be understood and defended. Expected failure modes: - Ichimoku requires significant bar history (52+ bars minimum); early data is noisy. - The system is slower to enter and exit than price-action-only approaches. - In choppy markets, price oscillates through the cloud, producing repeated signals. Retail-friendly because: - All components are based on simple price math (no complex transforms). - The visual cloud representation makes it easy to explain entries on a chart. - 4h timeframe keeps trade frequency manageable. """ INTERFACE_VERSION = 3 can_short = True timeframe = "4h" startup_candle_count: int = 130 process_only_new_candles = True use_exit_signal = True exit_profit_only = False ignore_roi_if_entry_signal = False minimal_roi = {"0": 0.20} stoploss = -0.07 trailing_stop = False tenkan_period = IntParameter(7, 15, default=9, space="buy", optimize=True, load=True) kijun_period = IntParameter(20, 35, default=26, space="buy", optimize=True, load=True) senkou_b_period = IntParameter(44, 60, default=52, space="buy", optimize=True, load=True) order_types = { "entry": "limit", "exit": "limit", "stoploss": "market", "stoploss_on_exchange": False, } order_time_in_force = {"entry": "GTC", "exit": "GTC"} plot_config = { "main_plot": { "tenkan": {"color": "blue"}, "kijun": {"color": "red"}, "span_a": {"color": "rgba(0,255,0,0.2)"}, "span_b": {"color": "rgba(255,0,0,0.2)"}, }, "subplots": {}, } def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: tenkan_p = int(self.tenkan_period.value) kijun_p = int(self.kijun_period.value) senkou_b_p = int(self.senkou_b_period.value) displacement = kijun_p # standard: displace forward by kijun_period bars # Tenkan-sen: (N-period high + N-period low) / 2 dataframe["tenkan"] = ( dataframe["high"].rolling(tenkan_p).max() + dataframe["low"].rolling(tenkan_p).min() ) / 2 # Kijun-sen: (M-period high + M-period low) / 2 dataframe["kijun"] = ( dataframe["high"].rolling(kijun_p).max() + dataframe["low"].rolling(kijun_p).min() ) / 2 # Senkou Span A: (Tenkan + Kijun) / 2, shifted forward by displacement span_a_raw = (dataframe["tenkan"] + dataframe["kijun"]) / 2 dataframe["span_a"] = span_a_raw.shift(displacement) # Senkou Span B: (senkou_b_p high + senkou_b_p low) / 2, shifted forward span_b_raw = ( dataframe["high"].rolling(senkou_b_p).max() + dataframe["low"].rolling(senkou_b_p).min() ) / 2 dataframe["span_b"] = span_b_raw.shift(displacement) # Causal Chikou reference: compare current close against close from # displacement bars ago (no future-candle access). dataframe["chikou"] = dataframe["close"].shift(displacement) # Cloud boundaries (using current cloud values = the span values computed # from displacement bars ago, which is what is "current" in the cloud) # For trading signals, we use the span values that correspond to NOW # (i.e., span computed from data displacement bars ago, now visible at t=0) dataframe["cloud_top"] = dataframe[["span_a", "span_b"]].max(axis=1) dataframe["cloud_bot"] = dataframe[["span_a", "span_b"]].min(axis=1) return dataframe def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: # Long: price above cloud, Tenkan above Kijun, current close above # displacement-bars-ago close. above_cloud = (dataframe["close"] > dataframe["cloud_top"]) & ( dataframe["cloud_top"].notna() ) tenkan_above_kijun = dataframe["tenkan"] > dataframe["kijun"] chikou_bullish = dataframe["close"] > dataframe["chikou"] long_setup = ( above_cloud & tenkan_above_kijun & chikou_bullish & (dataframe["volume"] > 0) ) # Short: price below cloud, Tenkan below Kijun, current close below # displacement-bars-ago close. below_cloud = (dataframe["close"] < dataframe["cloud_bot"]) & ( dataframe["cloud_bot"].notna() ) tenkan_below_kijun = dataframe["tenkan"] < dataframe["kijun"] chikou_bearish = dataframe["close"] < dataframe["chikou"] short_setup = ( below_cloud & tenkan_below_kijun & chikou_bearish & (dataframe["volume"] > 0) ) dataframe.loc[long_setup, ["enter_long", "enter_tag"]] = (1, "ichimoku_cloud_long") dataframe.loc[short_setup, ["enter_short", "enter_tag"]] = (1, "ichimoku_cloud_short") return dataframe def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: # Exit long when Tenkan crosses below Kijun (short-term trend reversal) exit_long = (dataframe["tenkan"] < dataframe["kijun"]) & ( dataframe["tenkan"].shift(1) >= dataframe["kijun"].shift(1) ) # Exit short when Tenkan crosses above Kijun exit_short = (dataframe["tenkan"] > dataframe["kijun"]) & ( dataframe["tenkan"].shift(1) <= dataframe["kijun"].shift(1) ) dataframe.loc[exit_long & (dataframe["volume"] > 0), ["exit_long", "exit_tag"]] = ( 1, "ichimoku_exit_long", ) dataframe.loc[exit_short & (dataframe["volume"] > 0), ["exit_short", "exit_tag"]] = ( 1, "ichimoku_exit_short", ) return dataframe def leverage( self, pair: str, current_time: datetime, current_rate: float, proposed_leverage: float, max_leverage: float, entry_tag: str | None, side: str, **kwargs, ) -> float: return min(2.0, max_leverage) |
Strategy League — fixed backtest that feeds the ranking
Export report Freqtrade logsRun finished · took 33.4s
pairs 33 pairs
timerange 20210101-20260101
mode futures
timeframe 4h
stake 100 USDT
wallet 1000 USDT
max open trades 10
fee exchange lowest tier
total profit-90.57%
final wallet94 USDT
win rate21.6%
max drawdown-92.15%
market change+427.60%
vs market-518.17%
timeframe4h
profit factor0.69
expectancy ratio-0.246
sharpe-0.892
sortino-11.599
CAGR-37.6%
calmar-1.028
avg leverage2.0x
avg MFE+5.70%
avg MAE-6.18%
avg profit/trade-1.77%
avg duration4h 53m
best trade+20.02%
worst trade-9.78%
win/loss streak6 / 69
positive months0/1
trades515
revision1
likely annual return-100%
range (5th–95th)-100% … -100%
chance of profit0.0%
worst-5% outcome-100%
significance (p)1.0
risk of ruin0.0%
- profit isn't statistically significant (p=1.00) — hard to tell apart from luck
- only 0% of resampled runs were profitable
- did not beat simply holding the market
- very deep drawdown (-92%)
Resampling the trade sequence 2,000× shows the spread of results this edge could plausibly produce — separating a dependable strategy from one that got lucky once.
Loading charts…
Monthly breakdown
| Month | Regime | Trades | Profit % | Avg % | Win | Loss | Win % | DD % | Avg dur |
|---|---|---|---|---|---|---|---|---|---|
| Jan 2021 | bullish trending high vol | 515 | -90.57 | -1.77 | 111 | 404 | 21.6 | -92.15 | 4h 53m |
Trade charts — best 2 and worst 2 performing pairs (full OHLC candles are expensive to render for every pair)
Backtests — over a market period
Backtest this strategy over a chosen crypto-cycle period. These don't affect the League ranking, and need that period's candle data downloaded.
Log in or sign up to run backtests.
| Period | Range | Total % | Win % | Max DD | Trades | |
|---|---|---|---|---|---|---|
| 2020 · DeFi Summer & Pre-Halving Rally | 20200101-20210101 | not run | ||||
| 2021 · Institutional Bull Market | 20210101-20220101 | not run | ||||
| 2022 · Post-Bull Crash & Macro Tightening | 20220101-20230101 | not run | ||||
| 2023–2024 · Recovery & ETF Anticipation | 20230101-20250101 | not run | ||||
| 2025–2026 · Current Cycle | 20250101-20260101 | not run | ||||
Walk forward
Out-of-sample backtest on recent data · 33 pairs · 20260101-20260701.
Backtest trust check
4 potential lookahead pattern(s) found · 2 to review
| Line | Pattern | Detail | |
|---|---|---|---|
| 112 | review | repaint_indicator | 'chikou' is Ichimoku's lagging span -- close shifted 26 bars into the past, so reading it at this bar reveals where price went 26 bars later |
| 118 | leak | whole_series_reduction | .max() over the whole column sees future rows (use .rolling(window).max() for a causal value) |
| 119 | leak | whole_series_reduction | .min() over the whole column sees future rows (use .rolling(window).min() for a causal value) |
| 130 | leak | repaint_indicator | 'chikou' is Ichimoku's lagging span -- close shifted 26 bars into the past, so reading it at this bar reveals where price went 26 bars later |
| 142 | |||
| 148 | review | enter_tag_overwrite | enter_tag/exit_tag is written by 4 separate assignments -- they share one column and run in source order, so a row matching more than one condition keeps only the LAST tag. Per-tag statistics won't mean what they appear to |
ran by Ron · took s
Lookahead analysis
freqtrade lookahead-analysis: detects strategies peeking at future candles.