ichiV1
♡
Basics
mode: spot
timeframe: 5m
interface version: 3
Settings
stoploss: -0.275
has minimal roi
process only new candles: false
startup candle count: 96
hyperopt
Indicators
ATR
EMA
Heikin_Ashi
Ichimoku
talib
technical
Concepts
trend_following
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 | # --- Do not remove these libs --- from freqtrade.strategy.interface import IStrategy from pandas import DataFrame import talib.abstract as ta import freqtrade.vendor.qtpylib.indicators as qtpylib import pandas as pd # noqa pd.options.mode.chained_assignment = None # default='warn' import technical.indicators as ftt from functools import reduce from datetime import datetime, timedelta from freqtrade.strategy import merge_informative_pair import numpy as np from freqtrade.strategy import stoploss_from_open class ichiV1(IStrategy): INTERFACE_VERSION = 3 # NOTE: settings as of the 25th july 21 # Buy hyperspace params: # NOTE: Good value (Win% ~70%), alot of trades #"buy_min_fan_magnitude_gain": 1.008 # NOTE: Very save value (Win% ~90%), only the biggest moves 1.008, buy_params = {'buy_trend_above_senkou_level': 1, 'buy_trend_bullish_level': 6, 'buy_fan_magnitude_shift_value': 3, 'buy_min_fan_magnitude_gain': 1.002} # Sell hyperspace params: # NOTE: was 15m but kept bailing out in dryrun sell_params = {'sell_trend_indicator': 'trend_close_2h'} # ROI table: minimal_roi = {'0': 0.059, '10': 0.037, '41': 0.012, '114': 0} # Stoploss: stoploss = -0.275 # Optimal timeframe for the strategy timeframe = '5m' startup_candle_count = 96 process_only_new_candles = False trailing_stop = False #trailing_stop_positive = 0.002 #trailing_stop_positive_offset = 0.025 #trailing_only_offset_is_reached = True use_exit_signal = True exit_profit_only = False ignore_roi_if_entry_signal = False # fill area between senkou_a and senkou_b #optional #optional #optional # plot senkou_b, too. Not only the area to it. plot_config = {'main_plot': {'senkou_a': {'color': 'green', 'fill_to': 'senkou_b', 'fill_label': 'Ichimoku Cloud', 'fill_color': 'rgba(255,76,46,0.2)'}, 'senkou_b': {}, 'trend_close_5m': {'color': '#FF5733'}, 'trend_close_15m': {'color': '#FF8333'}, 'trend_close_30m': {'color': '#FFB533'}, 'trend_close_1h': {'color': '#FFE633'}, 'trend_close_2h': {'color': '#E3FF33'}, 'trend_close_4h': {'color': '#C4FF33'}, 'trend_close_6h': {'color': '#61FF33'}, 'trend_close_8h': {'color': '#33FF7D'}}, 'subplots': {'fan_magnitude': {'fan_magnitude': {}}, 'fan_magnitude_gain': {'fan_magnitude_gain': {}}}} def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: heikinashi = qtpylib.heikinashi(dataframe) dataframe['open'] = heikinashi['open'] #dataframe['close'] = heikinashi['close'] dataframe['high'] = heikinashi['high'] dataframe['low'] = heikinashi['low'] dataframe['trend_close_5m'] = dataframe['close'] dataframe['trend_close_15m'] = ta.EMA(dataframe['close'], timeperiod=3) dataframe['trend_close_30m'] = ta.EMA(dataframe['close'], timeperiod=6) dataframe['trend_close_1h'] = ta.EMA(dataframe['close'], timeperiod=12) dataframe['trend_close_2h'] = ta.EMA(dataframe['close'], timeperiod=24) dataframe['trend_close_4h'] = ta.EMA(dataframe['close'], timeperiod=48) dataframe['trend_close_6h'] = ta.EMA(dataframe['close'], timeperiod=72) dataframe['trend_close_8h'] = ta.EMA(dataframe['close'], timeperiod=96) dataframe['trend_open_5m'] = dataframe['open'] dataframe['trend_open_15m'] = ta.EMA(dataframe['open'], timeperiod=3) dataframe['trend_open_30m'] = ta.EMA(dataframe['open'], timeperiod=6) dataframe['trend_open_1h'] = ta.EMA(dataframe['open'], timeperiod=12) dataframe['trend_open_2h'] = ta.EMA(dataframe['open'], timeperiod=24) dataframe['trend_open_4h'] = ta.EMA(dataframe['open'], timeperiod=48) dataframe['trend_open_6h'] = ta.EMA(dataframe['open'], timeperiod=72) dataframe['trend_open_8h'] = ta.EMA(dataframe['open'], timeperiod=96) dataframe['fan_magnitude'] = dataframe['trend_close_1h'] / dataframe['trend_close_8h'] dataframe['fan_magnitude_gain'] = dataframe['fan_magnitude'] / dataframe['fan_magnitude'].shift(1) ichimoku = ftt.ichimoku(dataframe, conversion_line_period=20, base_line_periods=60, laggin_span=120, displacement=30) dataframe['chikou_span'] = ichimoku['chikou_span'] dataframe['tenkan_sen'] = ichimoku['tenkan_sen'] dataframe['kijun_sen'] = ichimoku['kijun_sen'] dataframe['senkou_a'] = ichimoku['senkou_span_a'] dataframe['senkou_b'] = ichimoku['senkou_span_b'] dataframe['leading_senkou_span_a'] = ichimoku['leading_senkou_span_a'] dataframe['leading_senkou_span_b'] = ichimoku['leading_senkou_span_b'] dataframe['cloud_green'] = ichimoku['cloud_green'] dataframe['cloud_red'] = ichimoku['cloud_red'] dataframe['atr'] = ta.ATR(dataframe) return dataframe def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: conditions = [] # Trending market if self.buy_params['buy_trend_above_senkou_level'] >= 1: conditions.append(dataframe['trend_close_5m'] > dataframe['senkou_a']) conditions.append(dataframe['trend_close_5m'] > dataframe['senkou_b']) if self.buy_params['buy_trend_above_senkou_level'] >= 2: conditions.append(dataframe['trend_close_15m'] > dataframe['senkou_a']) conditions.append(dataframe['trend_close_15m'] > dataframe['senkou_b']) if self.buy_params['buy_trend_above_senkou_level'] >= 3: conditions.append(dataframe['trend_close_30m'] > dataframe['senkou_a']) conditions.append(dataframe['trend_close_30m'] > dataframe['senkou_b']) if self.buy_params['buy_trend_above_senkou_level'] >= 4: conditions.append(dataframe['trend_close_1h'] > dataframe['senkou_a']) conditions.append(dataframe['trend_close_1h'] > dataframe['senkou_b']) if self.buy_params['buy_trend_above_senkou_level'] >= 5: conditions.append(dataframe['trend_close_2h'] > dataframe['senkou_a']) conditions.append(dataframe['trend_close_2h'] > dataframe['senkou_b']) if self.buy_params['buy_trend_above_senkou_level'] >= 6: conditions.append(dataframe['trend_close_4h'] > dataframe['senkou_a']) conditions.append(dataframe['trend_close_4h'] > dataframe['senkou_b']) if self.buy_params['buy_trend_above_senkou_level'] >= 7: conditions.append(dataframe['trend_close_6h'] > dataframe['senkou_a']) conditions.append(dataframe['trend_close_6h'] > dataframe['senkou_b']) if self.buy_params['buy_trend_above_senkou_level'] >= 8: conditions.append(dataframe['trend_close_8h'] > dataframe['senkou_a']) conditions.append(dataframe['trend_close_8h'] > dataframe['senkou_b']) # Trends bullish if self.buy_params['buy_trend_bullish_level'] >= 1: conditions.append(dataframe['trend_close_5m'] > dataframe['trend_open_5m']) if self.buy_params['buy_trend_bullish_level'] >= 2: conditions.append(dataframe['trend_close_15m'] > dataframe['trend_open_15m']) if self.buy_params['buy_trend_bullish_level'] >= 3: conditions.append(dataframe['trend_close_30m'] > dataframe['trend_open_30m']) if self.buy_params['buy_trend_bullish_level'] >= 4: conditions.append(dataframe['trend_close_1h'] > dataframe['trend_open_1h']) if self.buy_params['buy_trend_bullish_level'] >= 5: conditions.append(dataframe['trend_close_2h'] > dataframe['trend_open_2h']) if self.buy_params['buy_trend_bullish_level'] >= 6: conditions.append(dataframe['trend_close_4h'] > dataframe['trend_open_4h']) if self.buy_params['buy_trend_bullish_level'] >= 7: conditions.append(dataframe['trend_close_6h'] > dataframe['trend_open_6h']) if self.buy_params['buy_trend_bullish_level'] >= 8: conditions.append(dataframe['trend_close_8h'] > dataframe['trend_open_8h']) # Trends magnitude conditions.append(dataframe['fan_magnitude_gain'] >= self.buy_params['buy_min_fan_magnitude_gain']) conditions.append(dataframe['fan_magnitude'] > 1) for x in range(self.buy_params['buy_fan_magnitude_shift_value']): conditions.append(dataframe['fan_magnitude'].shift(x + 1) < dataframe['fan_magnitude']) if conditions: dataframe.loc[reduce(lambda x, y: x & y, conditions), 'enter_long'] = 1 return dataframe def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: conditions = [] conditions.append(qtpylib.crossed_below(dataframe['trend_close_5m'], dataframe[self.sell_params['sell_trend_indicator']])) if conditions: dataframe.loc[reduce(lambda x, y: x & y, conditions), 'exit_long'] = 1 return dataframe |
Strategy League — fixed backtest that feeds the ranking
⏳ queued — the fixed-params League backtest is running. Updates automatically.
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
no lookahead patterns, but 3 backtest-realism warning(s) — results may not reflect real trading · 4 to review
| Line | Pattern | Detail | |
|---|---|---|---|
| 49 | realism | ohlc_overwrite | overwrites the 'open' candle column with Heikin-Ashi values -- freqtrade fills at open and checks stop/ROI against high/low, so the backtest uses prices that never traded |
| 51 | realism | ohlc_overwrite | overwrites the 'high' candle column with Heikin-Ashi values -- freqtrade fills at open and checks stop/ROI against high/low, so the backtest uses prices that never traded |
| 52 | realism | ohlc_overwrite | overwrites the 'low' candle column with Heikin-Ashi values -- freqtrade fills at open and checks stop/ROI against high/low, so the backtest uses prices that never traded |
| 72 | review | repaint_indicator | 'chikou_span' 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 |
| 72 | |||
| 31 | review | startup_candles_too_small | startup_candle_count is 96, but EMA(timeperiod=96) needing 3x warmup needs at least 288 candles -- so the first 192+ candles of every backtest use an indicator that hasn't warmed up. Recursive indicators (EMA/RSI/ADX/ATR) want several times their period, not exactly it |
| 32 | review | unthrottled_candle_processing | process_only_new_candles is False, so populate_indicators/populate_entry_trend/populate_exit_trend re-run every throttle_secs (default 5s) even though their inputs -- closed candles -- haven't changed since the last run. This wastes CPU without changing any value; if the goal is order-book-level checks, put that logic in confirm_trade_entry/custom_exit instead, which already run every loop |
ran by Ron · took s
Lookahead analysis
freqtrade lookahead-analysis: detects strategies peeking at future candles.