Basics
mode: spot
timeframe: 5m
Settings
stoploss: -0.13
has minimal roi
dca
process only new candles
startup candle count: 120
hyperopt
hyperopt params: 4
Indicators
RSI
SMA
Stochastic
pandas_ta
talib
Concepts
dca
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 | from datetime import datetime import talib.abstract as ta # TA-Lib 抽象接口(可直接对 DataFrame 使用) import pandas_ta as pta # pandas_ta 指标库,这里用到 cti from freqtrade.persistence import Trade from freqtrade.strategy.interface import IStrategy from pandas import DataFrame from freqtrade.strategy import DecimalParameter, IntParameter from functools import reduce # 组合多个条件用(逻辑或) class SampleStrategy1(IStrategy): # ROI 表:持仓 0 分钟起要求 2% 盈利即可触发 ROI 卖出;持仓满 120 分钟后只要 1% minimal_roi = { "0": 0.02, "120": 0.01 } timeframe = '5m' # 策略运行在 5 分钟线 process_only_new_candles = True # 只在新 K 线计算,省 CPU startup_candle_count = 120 # 至少准备 120 根 K,用于指标热身 position_adjustment_enable = True # 启用“仓位调整”(分批加减仓) # 订单类型设定 order_types = { 'entry': 'market', # 入场用市价 'exit': 'market', # 出场用市价 'emergency_exit': 'market', 'force_entry': 'market', 'force_exit': "market", 'stoploss': 'market', # 止损用市价 'stoploss_on_exchange': False, # 不在交易所挂实体止损单(本地管) # 下面两项仅在 stoploss_on_exchange=True 时生效,这里相当于预留 'stoploss_on_exchange_interval': 60, 'stoploss_on_exchange_market_ratio': 0.99 } stoploss = -0.13 # 全局硬止损:-13% # —— 超参定义(可被 Hyperopt 优化)—— is_optimize_32 = True buy_rsi_fast_32 = IntParameter(20, 70, default=46, space='buy', optimize=is_optimize_32) buy_rsi_32 = IntParameter(15, 50, default=19, space='buy', optimize=is_optimize_32) buy_sma15_32 = DecimalParameter(0.900, 1, default=0.942, decimals=3, space='buy', optimize=is_optimize_32) buy_cti_32 = DecimalParameter(-1, 0, default=-0.86, decimals=2, space='buy', optimize=is_optimize_32) # —— 初始下单金额控制:只用建议仓位的 70% 开仓 —— def custom_stake_amount(self, pair: str, current_time: datetime, current_rate: float, proposed_stake: float, min_stake: float, max_stake: float, leverage: float, entry_tag: str, side: str, **kwargs) -> float: return proposed_stake * 0.7 # 预留 30% 弹药以便后续加仓 # —— 仓位调整(分批/加减仓)—— def adjust_trade_position(self, trade: Trade, current_time: datetime, current_rate: float, current_profit: float, min_stake: float, max_stake: float, current_entry_rate: float, current_exit_rate: float, current_entry_profit: float, current_exit_profit: float, **kwargs) -> float: count_of_exits = trade.nr_of_successful_exits # 条件1:若当前浮盈 ≥ 2%,且从未分批减仓过 → 减仓 50% if current_profit >= 0.02 and count_of_exits == 0: return -0.5 * trade.stake_amount # 负值=减仓金额(按初始 stake 的一半) count_of_entries = trade.nr_of_successful_entries filled_entries = trade.select_filled_orders(trade.entry_side) # 历史入场订单 initial_stake = filled_entries[0].cost # 第一次入场的花费(70%) # 条件2:若浮亏 < -5% 且仅入场过一次 → 补仓到满仓(把剩余 30% 补上) if current_profit < -0.05 and count_of_entries == 1 : return initial_stake / 0.7 * 0.3 # 初始 70% 反推总额,再乘 30% 得到补仓额 return None # 其他情况不调整 # —— 计算技术指标 —— def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: dataframe['sma_15'] = ta.SMA(dataframe, timeperiod=15) # 15 期简单均线 dataframe['cti'] = pta.cti(dataframe["close"], length=20) # CTI(20):相关性趋势指标,负值偏超卖 dataframe['rsi'] = ta.RSI(dataframe, timeperiod=14) # 标准 RSI(14) dataframe['rsi_fast'] = ta.RSI(dataframe, timeperiod=4) # 快 RSI(4):更敏感 dataframe['rsi_slow'] = ta.RSI(dataframe, timeperiod=20) # 慢 RSI(20):趋势性 # STOCHF:快速随机指标,这里只用 fastk(0–100) stoch_fast = ta.STOCHF(dataframe, 5, 3, 0, 3, 0) # 建议改成关键词参数以免歧义 dataframe['fastk'] = stoch_fast['fastk'] return dataframe # —— 入场条件 —— def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: conditions = [] dataframe.loc[:, 'enter_tag'] = '' # 记录触发的买入标签 # buy_1 组合信号: buy_1 = ( (dataframe['rsi_slow'] < dataframe['rsi_slow'].shift(1)) & # 慢 RSI 走低(捕捉回撤) (dataframe['rsi_fast'] < self.buy_rsi_fast_32.value) & # 快 RSI 低于阈值(短期超卖) (dataframe['rsi'] > self.buy_rsi_32.value) & # 但整体 RSI 不能太弱 (dataframe['close'] < dataframe['sma_15'] * self.buy_sma15_32.value) & # 价格低于 SMA15 的某比例 (dataframe['cti'] < self.buy_cti_32.value) # CTI 足够负,倾向反弹 ) conditions.append(buy_1) dataframe.loc[buy_1, 'enter_tag'] += 'buy_1' # 打标签方便回测分析 # 任一买入条件满足 → 标记 enter_long = 1(Freqtrade 会据此下单) 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: # dataframe.loc[(), ['exit_long', 'exit_tag']] = (0, 'long_out') # 示例:可自定义出场信号 dataframe['exit_long'] = 0 dataframe['exit_tag'] = '' # 这里不主动给卖出信号 # 实际卖出由 ROI 表 / 全局止损 / adjust_trade_position 决定 return dataframe |
Strategy League — fixed backtest that feeds the ranking
Export report Freqtrade logsRun finished · took 399.3s
pairs 33 pairs
timerange 20210101-20260101
mode spot
timeframe 5m
stake 100 USDT
wallet 1000 USDT
max open trades 10
fee exchange lowest tier
total profit+60.75%
final wallet1608 USDT
win rate95.9%
max drawdown-3.52%
market change+451.55%
vs market-390.80%
timeframe5m
profit factor3.05
expectancy ratio0.084
break-even fee0.7697%
sharpe2.574
sortino6.955
CAGR+9.9%
calmar19.939
avg MFE+3.86%
avg MAE-2.90%
avg profit/trade1.42%
avg duration0h 20m
best trade+2.09%
worst trade-13.17%
win/loss streak150 / 3
DCA orders1 max / 0.12 avg
max stake exposure100.03 USDT (1.0x base)
positive months31/33
consistent (3-mo)87.1%
worst 3-mo-1.28%
trades660
revision1
likely annual return+10%
range (5th–95th)+8% … +12%
chance of profit100.0%
worst-5% outcome+8%
significance (p)0.0005
risk of ruin0.0%
- did not beat simply holding the market
- statistically significant edge (p=0.00)
- 100% of resampled runs stayed profitable
- profitable across 87% of rolling 3-month windows
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 |
|---|---|---|---|---|---|---|---|---|---|
| Nov 2025 | bearish trending high vol | 5 | +0.66 | 1.79 | 5 | 0 | 100.0 | 0.0 | 0h 49m |
| Oct 2025 | bearish trending low vol | 1 | +0.14 | 2.00 | 1 | 0 | 100.0 | 0.0 | 0h 00m |
| Feb 2025 | bearish trending low vol | 12 | +0.20 | 0.61 | 11 | 1 | 91.7 | -0.73 | 1h 19m |
| Dec 2024 | bullish trending low vol | 10 | +1.36 | 1.90 | 10 | 0 | 100.0 | 0.0 | 0h 14m |
| Nov 2024 | bullish trending low vol | 4 | +0.56 | 2.00 | 4 | 0 | 100.0 | 0.0 | 0h 15m |
| Aug 2024 | bearish choppy high vol | 4 | +0.48 | 1.49 | 4 | 0 | 100.0 | 0.0 | 3h 00m |
| Apr 2024 | bearish choppy high vol | 27 | +3.95 | 1.99 | 27 | 0 | 100.0 | 0.0 | 0h 14m |
| Mar 2024 | bullish trending high vol | 19 | +1.61 | 1.15 | 18 | 1 | 94.7 | -0.7 | 0h 38m |
| Jan 2024 | bearish choppy high vol | 1 | +0.14 | 2.00 | 1 | 0 | 100.0 | -0.25 | 0h 10m |
| Dec 2023 | bullish trending low vol | 1 | +0.14 | 2.00 | 1 | 0 | 100.0 | -0.34 | 0h 10m |
| Nov 2023 | bullish trending low vol | 7 | +0.98 | 1.99 | 7 | 0 | 100.0 | -0.99 | 0h 07m |
| Aug 2023 | bearish choppy low vol | 4 | +0.56 | 1.99 | 4 | 0 | 100.0 | -1.35 | 0h 14m |
| Jul 2023 | bullish trending low vol | 1 | +0.14 | 2.06 | 1 | 0 | 100.0 | -1.44 | 0h 30m |
| Jun 2023 | bullish trending low vol | 2 | +0.21 | 1.50 | 2 | 0 | 100.0 | -1.63 | 1h 18m |
| Apr 2023 | bullish trending low vol | 1 | +0.14 | 2.01 | 1 | 0 | 100.0 | -1.68 | 0h 05m |
| Mar 2023 | bullish trending high vol | 2 | +0.21 | 1.49 | 2 | 0 | 100.0 | -1.82 | 8h 00m |
| Nov 2022 | bearish trending high vol | 46 | -1.56 | 0.15 | 40 | 6 | 87.0 | -3.19 | 1h 00m |
| Oct 2022 | bullish choppy low vol | 1 | +0.14 | 2.00 | 1 | 0 | 100.0 | 0.0 | 0h 05m |
| Jun 2022 | bearish trending high vol | 1 | +0.14 | 2.01 | 1 | 0 | 100.0 | 0.0 | 0h 05m |
| May 2022 | bearish trending high vol | 32 | +3.24 | 1.57 | 31 | 1 | 96.9 | -0.78 | 0h 05m |
| Apr 2022 | bearish choppy high vol | 1 | +0.07 | 1.01 | 1 | 0 | 100.0 | 0.0 | 4h 00m |
| Jan 2022 | bearish trending high vol | 9 | +1.32 | 2.00 | 9 | 0 | 100.0 | -0.11 | 0h 11m |
| Dec 2021 | bearish trending high vol | 14 | +0.74 | 1.09 | 13 | 1 | 92.9 | -1.44 | 0h 02m |
| Nov 2021 | bullish trending high vol | 1 | +0.14 | 2.00 | 1 | 0 | 100.0 | -0.71 | 0h 05m |
| Oct 2021 | bullish trending high vol | 2 | -1.04 | -4.92 | 1 | 1 | 50.0 | -0.81 | 6h 40m |
| Sep 2021 | bearish trending high vol | 28 | +2.84 | 1.42 | 27 | 1 | 96.4 | -0.64 | 0h 12m |
| Aug 2021 | bullish trending high vol | 1 | +0.14 | 2.00 | 1 | 0 | 100.0 | 0.0 | 0h 05m |
| Jun 2021 | bearish trending high vol | 11 | +1.60 | 2.00 | 11 | 0 | 100.0 | 0.0 | 0h 06m |
| May 2021 | bearish trending high vol | 181 | +24.99 | 1.92 | 180 | 1 | 99.4 | -1.05 | 0h 13m |
| Apr 2021 | bearish choppy high vol | 60 | +3.64 | 1.11 | 56 | 4 | 93.3 | -3.14 | 0h 07m |
| Mar 2021 | bullish choppy high vol | 1 | +0.14 | 2.00 | 1 | 0 | 100.0 | -2.52 | 0h 00m |
| Feb 2021 | bullish trending high vol | 76 | +2.65 | 0.77 | 69 | 7 | 90.8 | -3.52 | 0h 08m |
| Jan 2021 | bullish trending high vol | 94 | +10.08 | 1.57 | 91 | 3 | 96.8 | -1.07 | 0h 07m |
Yearly breakdown
| Year | Trades | Profit % | Avg % | Win | Loss | Win % | DD % | Avg dur |
|---|---|---|---|---|---|---|---|---|
| 2025 | 18 | +1.00 | 1.01 | 17 | 1 | 94.4 | -0.73 | 1h 06m |
| 2024 | 65 | +8.10 | 1.70 | 64 | 1 | 98.5 | -0.7 | 0h 31m |
| 2023 | 18 | +2.38 | 1.89 | 18 | 0 | 100.0 | -1.82 | 1h 10m |
| 2022 | 90 | +3.35 | 0.89 | 83 | 7 | 92.2 | -3.19 | 0h 36m |
| 2021 | 469 | +45.92 | 1.48 | 451 | 18 | 96.2 | -3.52 | 0h 11m |
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
no lookahead patterns · 2 thing(s) worth reviewing before trusting the numbers
| Line | Pattern | Detail | |
|---|---|---|---|
| 19 | review | startup_candles_too_small | startup_candle_count is 120, but RSI(timeperiod=20) needing 8x warmup needs at least 160 candles -- so the first 40+ 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 |
| 20 | review | unbounded_dca | position_adjustment_enable is on but max_entry_position_adjustment is unset (default -1 = unlimited), so nothing caps how many times a losing position can be added to. backtesting.py only bounds entries when that value is > -1 |
ran by Ron · took s
Lookahead analysis
freqtrade lookahead-analysis: detects strategies peeking at future candles.