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 | """ 趋势跟踪策略 (TrendFollowingStrategy) 纯规则驱动,零 ML 依赖: - 入场: EMA(20) > EMA(50) > EMA(200) 多头排列 - 过滤: ADX > 20(只做趋势市) - 退出: EMA(20) < EMA(50) 或止损 - 止损: 2x ATR 跟踪止损 """ import logging from typing import Optional import pandas as pd import numpy as np from freqtrade.strategy import IStrategy, IntParameter, DecimalParameter logger = logging.getLogger(__name__) class TrendFollowingStrategy(IStrategy): timeframe = "4h" can_short = False process_only_new_candles = True # Risk stoploss = -0.05 trailing_stop = True trailing_stop_positive = 0.02 trailing_stop_positive_offset = 0.03 trailing_only_offset_is_reached = True # ROI minimal_roi = {"0": 0.10, "24": 0.05, "48": 0.02} # Hyperopt adx_threshold = IntParameter(15, 30, default=20, space="buy") ema_short = IntParameter(5, 20, default=10, space="buy") ema_mid = IntParameter(20, 50, default=30, space="buy") ema_long = IntParameter(80, 150, default=100, space="buy") def informative_pairs(self): return [] def populate_indicators(self, dataframe: pd.DataFrame, metadata: dict) -> pd.DataFrame: # EMAs dataframe["ema_short"] = dataframe["close"].ewm(span=self.ema_short.value).mean() dataframe["ema_mid"] = dataframe["close"].ewm(span=self.ema_mid.value).mean() dataframe["ema_long"] = dataframe["close"].ewm(span=self.ema_long.value).mean() # ADX high, low, close = dataframe["high"], dataframe["low"], dataframe["close"] tr = pd.DataFrame({ "hl": high - low, "hc": (high - close.shift()).abs(), "lc": (low - close.shift()).abs(), }).max(axis=1) atr = tr.ewm(span=14).mean() up = high.diff() down = -low.diff() plus_dm = up.where((up > 0) & (up > down), 0.0) minus_dm = down.where((down > 0) & (down > up), 0.0) plus_di = 100 * (plus_dm.ewm(span=14).mean() / atr) minus_di = 100 * (minus_dm.ewm(span=14).mean() / atr) dx = 100 * (plus_di - minus_di).abs() / (plus_di + minus_di) dataframe["adx"] = dx.ewm(span=14).mean() # ATR for stop dataframe["atr"] = atr return dataframe def populate_entry_trend(self, dataframe: pd.DataFrame, metadata: dict) -> pd.DataFrame: dataframe["enter_long"] = 0 # 多头排列: ema_short > ema_mid > ema_long trend_up = ( (dataframe["ema_short"] > dataframe["ema_mid"]) & (dataframe["ema_mid"] > dataframe["ema_long"]) ) # ADX 过滤 trending = dataframe["adx"] > self.adx_threshold.value # 价格在短均线上方 price_ok = dataframe["close"] > dataframe["ema_short"] dataframe.loc[trend_up & trending & price_ok, "enter_long"] = 1 return dataframe def populate_exit_trend(self, dataframe: pd.DataFrame, metadata: dict) -> pd.DataFrame: dataframe["exit_long"] = 0 # 趋势反转: ema_short < ema_mid trend_down = dataframe["ema_short"] < dataframe["ema_mid"] dataframe.loc[trend_down, "exit_long"] = 1 return dataframe def custom_stoploss( self, pair: str, trade, current_time, current_rate, current_profit, after_fill: bool, **kwargs ) -> Optional[float]: # 使用 ATR 动态止损 if after_fill: return None dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe) if dataframe is None or len(dataframe) == 0: return None last = dataframe.iloc[-1] atr = last.get("atr", 0) close = last.get("close", current_rate) if atr > 0 and close > 0: atr_pct = atr / close return -max(2.0 * atr_pct, 0.03) # 至少 3% 止损 return None |
Strategy League — fixed backtest that feeds the ranking
Export report Freqtrade logsRun finished · took 19.6s
ℹ️ This strategy uses a trailing stop / custom_stoploss() — freqtrade only
re-checks these once per 4h candle by default, not against the price movement within it.
For a more accurate read, re-run this backtest locally with --timeframe-detail 1m
(or 5m — freqtrade's own docs use 5m detail for an hourly strategy as a lighter
alternative). Freqle doesn't do this for every check here: multiplying every
League/sweep backtest by a finer detail timeframe is more compute than the sandbox can sustain
across every indexed strategy. why this matters →
- 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 (-90%)
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 |
|---|---|---|---|---|---|---|---|---|---|
| Feb 2021 | bullish trending high vol | 251 | -11.78 | -0.47 | 152 | 99 | 60.6 | -90.27 | 3h 27m |
| Jan 2021 | bullish trending high vol | 1009 | -78.28 | -0.78 | 584 | 425 | 57.9 | -78.96 | 1h 54m |
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 · 1 thing(s) worth reviewing before trusting the numbers
| Line | Pattern | Detail | |
|---|---|---|---|
| 99 | review | dead_callback | custom_stoploss() is defined but use_custom_stoploss isn't True, and freqtrade only calls it when that flag is set -- the method never runs and every trade uses the static stoploss |
ran by Ron · took s
Lookahead analysis
freqtrade lookahead-analysis: detects strategies peeking at future candles.