Supertrend
Tested 1 Jun 2023 – 30 May 2025
Rank 6 of 27 by return
Supertrend turned $1,000 into $1,683 (+68.3%) over 729 days, while holding Bitcoin returned +288.1% and an equal mix of the ten coins +194.8%. Its worst drawdown was 27.0%, a substantial dip to sit through. It won 61% of trades for a profit factor of 1.13.
How Supertrend trades
Supertrend enters on the 1-hour chart only when three Supertrend indicators with different settings all point up, and exits only when three separate sell-side Supertrends all point down. A trailing stop locks in gains after a 14.4% move.
Requiring three indicators to agree reduces false signals but delays entries and exits. The author notes the Supertrend implementation has not been independently validated.
Rules at a glance
- Indicators
- 3 × Supertrend (buy), 3 × Supertrend (sell)
- Take-profit (minimal ROI)
- 8.7% from entry; 5.8% after 6h 12m; 2.9% after 14h 21m; 0% after 1d 13h
- Stoploss
- −26.5%
- Trailing stop
- Trails 5% behind the high once profit passes 14.4%
- Exit signal
- Used
Results by month
Profit or loss in USDT for trades closed in each month.
Results by coin
| Pair | Trades | Win rate | Profit (USDT) | Avg. hold |
|---|---|---|---|---|
| DOGE/USDT | 149 | 67.1% | +343.13 | 1d 4h |
| SOL/USDT | 217 | 68.2% | +194.83 | 1d 6h |
| AVAX/USDT | 136 | 64.7% | +116.98 | 1d 2h |
| BTC/USDT | 200 | 58.5% | +84.46 | 1d 12h |
| LINK/USDT | 134 | 61.9% | +63.77 | 1d 6h |
| ETH/USDT | 180 | 58.9% | +41.25 | 1d 9h |
| XRP/USDT | 144 | 56.2% | −4.89 | 1d 12h |
| ADA/USDT | 146 | 58.9% | −33.56 | 1d 7h |
| BNB/USDT | 169 | 53.8% | −51.68 | 1d 13h |
| DOT/USDT | 88 | 59.1% | −71.17 | 1d 7h |
Why trades closed
| Exit reason | Trades | Win rate | Profit (USDT) |
|---|---|---|---|
| Take-profit (ROI) | 1100 | 86.5% | +5,873.78 |
| Still open at end of test | 3 | 0.0% | −21.53 |
| Trailing stop | 1 | 0.0% | −50.05 |
| Exit signal | 459 | 0.0% | −5,119.08 |
The code
Supertrend comes from the community freqtrade-strategies repository (GPL-3.0). These are the parts that decide when it trades; the full file is 156 lines.
Entry rules
def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: dataframe.loc[ ( (dataframe[f'supertrend_1_buy_{self.buy_m1.value}_{self.buy_p1.value}'] == 'up') & (dataframe[f'supertrend_2_buy_{self.buy_m2.value}_{self.buy_p2.value}'] == 'up') & (dataframe[f'supertrend_3_buy_{self.buy_m3.value}_{self.buy_p3.value}'] == 'up') & # The three indicators are 'up' for the current candle (dataframe['volume'] > 0) # There is at least some trading volume ), 'enter_long'] = 1 return dataframe
Exit rules
def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: dataframe.loc[ ( (dataframe[f'supertrend_1_sell_{self.sell_m1.value}_{self.sell_p1.value}'] == 'down') & (dataframe[f'supertrend_2_sell_{self.sell_m2.value}_{self.sell_p2.value}'] == 'down') & (dataframe[f'supertrend_3_sell_{self.sell_m3.value}_{self.sell_p3.value}'] == 'down') & # The three indicators are 'down' for the current candle (dataframe['volume'] > 0) # There is at least some trading volume ), 'exit_long'] = 1 return dataframe
Indicators
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: new_cols = [] for multiplier in self.buy_m1.range: for period in self.buy_p1.range: new_cols.append(self.supertrend_direction( dataframe, multiplier, period, f'supertrend_1_buy_{multiplier}_{period}')) for multiplier in self.buy_m2.range: for period in self.buy_p2.range: new_cols.append(self.supertrend_direction( dataframe, multiplier, period, f'supertrend_2_buy_{multiplier}_{period}')) for multiplier in self.buy_m3.range: for period in self.buy_p3.range: new_cols.append(self.supertrend_direction( dataframe, multiplier, period, f'supertrend_3_buy_{multiplier}_{period}')) for multiplier in self.sell_m1.range: for period in self.sell_p1.range: new_cols.append(self.supertrend_direction( dataframe, multiplier, period, f'supertrend_1_sell_{multiplier}_{period}')) for multiplier in self.sell_m2.range: for period in self.sell_p2.range: new_cols.append(self.supertrend_direction( dataframe, multiplier, period, f'supertrend_2_sell_{multiplier}_{period}')) for multiplier in self.sell_m3.range: for period in self.sell_p3.range: new_cols.append(self.supertrend_direction( dataframe, multiplier, period, f'supertrend_3_sell_{multiplier}_{period}')) if new_cols: dataframe = pd.concat([dataframe] + new_cols, axis=1) return dataframe
Reproduce this test
With freqtrade installed (see our Docker guide), download the data and run the same backtest:
freqtrade download-data --exchange binance --pairs ADA/USDT AVAX/USDT BNB/USDT BTC/USDT DOGE/USDT DOT/USDT ETH/USDT LINK/USDT SOL/USDT XRP/USDT --timeframes 1h --timerange 20230501-20250530
freqtrade backtesting --strategy Supertrend --timeframe 1h \
--timerange 20230601-20250530 --dry-run-wallet 1000 --stake-amount 200 --max-open-trades 5 --fee 0.001
Results can differ slightly with a different data source or freqtrade version. See how we test.