Strategy005
Tested 1 Jun 2023 – 30 May 2025
Rank 22 of 27 by return
Strategy005 turned $1,000 into $380 (−62.0%) over 729 days, while holding Bitcoin returned +288.1% and an equal mix of the ten coins +194.8%. Its worst drawdown was a severe 68.3%, deep enough that most people would have switched it off. It won 83% of its trades yet still lost money, because its few losing trades were much larger than its many small wins.
How Strategy005 trades
Strategy005 waits for a volume spike of four times the 150-candle average while price is below its 40-period SMA and the Fisher RSI is deeply oversold. It exits when RSI crosses above 74 while MACD is negative.
Volume spikes on a falling price can mark capitulation or the start of a larger drop. The ROI table stretches to 24 hours, the longest of the sample strategies.
Rules at a glance
- Indicators
- Volume vs. 150-candle average, RSI, Fisher RSI, Fast Stochastic, MACD, -DI
- Take-profit (minimal ROI)
- 5% from entry; 4% after 20m; 3% after 40m; 2% after 1h 20m; 1% after 1d 0h
- Stoploss
- −10%
- Trailing stop
- Off
- 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 | 101 | 90.1% | +121.43 | 1d 3h |
| BTC/USDT | 84 | 91.7% | +78.45 | 1d 13h |
| ETH/USDT | 82 | 89.0% | +27.06 | 2d 18h |
| LINK/USDT | 94 | 86.2% | +8.48 | 1d 8h |
| BNB/USDT | 99 | 86.9% | −11.46 | 2d 23h |
| ADA/USDT | 95 | 80.0% | −126.57 | 1d 13h |
| XRP/USDT | 68 | 76.5% | −129.93 | 2d 7h |
| SOL/USDT | 92 | 77.2% | −166.30 | 1d 1h |
| DOT/USDT | 100 | 78.0% | −180.54 | 1d 11h |
| AVAX/USDT | 94 | 74.5% | −241.11 | 1d 5h |
Why trades closed
| Exit reason | Trades | Win rate | Profit (USDT) |
|---|---|---|---|
| Take-profit (ROI) | 755 | 100.0% | +2,500.03 |
| Still open at end of test | 1 | 0.0% | −5.09 |
| Stoploss | 153 | 0.0% | −3,115.42 |
The code
Strategy005 comes from the community freqtrade-strategies repository (GPL-3.0). These are the parts that decide when it trades; the full file is 185 lines.
Entry rules
def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: dataframe.loc[ # Prod ( (dataframe['close'] > 0.00000200) & (dataframe['volume'] > dataframe['volume'].rolling(self.buy_volumeAVG.value).mean() * 4) & (dataframe['close'] < dataframe['sma']) & (dataframe['fastd'] > dataframe['fastk']) & (dataframe['rsi'] > self.buy_rsi.value) & (dataframe['fastd'] > self.buy_fastd.value) & (dataframe['fisher_rsi_norma'] < self.buy_fishRsiNorma.value) ), 'enter_long'] = 1 return dataframe
Exit rules
def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: conditions = [] if self.sell_trigger.value == 'rsi-macd-minusdi': conditions.append(qtpylib.crossed_above(dataframe['rsi'], self.sell_rsi.value)) conditions.append(dataframe['macd'] < 0) conditions.append(dataframe['minus_di'] > self.sell_minusDI.value) if self.sell_trigger.value == 'sar-fisherRsi': conditions.append(dataframe['sar'] > dataframe['close']) conditions.append(dataframe['fisher_rsi'] > self.sell_fishRsiNorma.value) if conditions: dataframe.loc[reduce(lambda x, y: x & y, conditions), 'exit_long'] = 1 return dataframe
Indicators
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: # MACD macd = ta.MACD(dataframe) dataframe['macd'] = macd['macd'] dataframe['macdsignal'] = macd['macdsignal'] # Minus Directional Indicator / Movement dataframe['minus_di'] = ta.MINUS_DI(dataframe) # RSI dataframe['rsi'] = ta.RSI(dataframe) # Inverse Fisher transform on RSI, values [-1.0, 1.0] (https://goo.gl/2JGGoy) rsi = 0.1 * (dataframe['rsi'] - 50) dataframe['fisher_rsi'] = (numpy.exp(2 * rsi) - 1) / (numpy.exp(2 * rsi) + 1) # Inverse Fisher transform on RSI normalized, value [0.0, 100.0] (https://goo.gl/2JGGoy) dataframe['fisher_rsi_norma'] = 50 * (dataframe['fisher_rsi'] + 1) # Stoch fast stoch_fast = ta.STOCHF(dataframe) dataframe['fastd'] = stoch_fast['fastd'] dataframe['fastk'] = stoch_fast['fastk'] # Overlap Studies # ------------------------------------ # SAR Parabol dataframe['sar'] = ta.SAR(dataframe) # SMA - Simple Moving Average dataframe['sma'] = ta.SMA(dataframe, timeperiod=40) 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 5m --timerange 20230501-20250530
freqtrade backtesting --strategy Strategy005 --timeframe 5m \
--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.