ReinforcedQuickie
Tested 1 Jun 2023 – 30 May 2025
Rank 23 of 27 by return
ReinforcedQuickie turned $1,000 into $202 (−79.8%) 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 80.0%, deep enough that most people would have switched it off. With a 66% win rate and a profit factor of 0.73, losses outweighed gains.
How ReinforcedQuickie trades
ReinforcedQuickie combines two entries: a new short-term low below the EMAs and the lower Bollinger Band, or a five-candle decline that just turned up. Both are filtered by a longer resampled trend. It exits on an overbought setup or a run of green candles.
A 1% take-profit and 5% stoploss make every loss worth about five wins, so the win rate needs to stay very high.
Rules at a glance
- Indicators
- EMA 5 / 12 / 21, Bollinger Bands, MFI, Resampled SMA
- Take-profit (minimal ROI)
- 1% from entry
- Stoploss
- −5%
- 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 |
|---|---|---|---|---|
| BTC/USDT | 234 | 62.8% | −19.27 | 12h 28m |
| DOGE/USDT | 188 | 69.1% | −44.07 | 7h 7m |
| BNB/USDT | 245 | 64.5% | −51.48 | 10h 8m |
| AVAX/USDT | 178 | 74.2% | −56.42 | 5h 32m |
| XRP/USDT | 223 | 69.1% | −59.39 | 9h 15m |
| ETH/USDT | 198 | 59.1% | −80.65 | 9h 39m |
| DOT/USDT | 178 | 66.3% | −94.00 | 7h 25m |
| LINK/USDT | 195 | 65.1% | −118.35 | 6h 40m |
| ADA/USDT | 193 | 59.6% | −122.25 | 7h 14m |
| SOL/USDT | 268 | 69.4% | −152.38 | 5h 14m |
Why trades closed
| Exit reason | Trades | Win rate | Profit (USDT) |
|---|---|---|---|
| Take-profit (ROI) | 893 | 100.0% | +1,787.55 |
| Exit signal | 1015 | 48.4% | −594.09 |
| Stoploss | 192 | 0.0% | −1,991.73 |
The code
ReinforcedQuickie comes from the community freqtrade-strategies repository (GPL-3.0). These are the parts that decide when it trades; the full file is 195 lines.
Entry rules
def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: dataframe.loc[ ( ( ( (dataframe['close'] < dataframe['ema_{}'.format(self.EMA_SHORT_TERM)]) & (dataframe['close'] < dataframe['ema_{}'.format(self.EMA_MEDIUM_TERM)]) & (dataframe['close'] == dataframe['min']) & (dataframe['close'] <= dataframe['bb_lowerband']) ) | # simple v bottom shape (lopsided to the left to increase reactivity) # which has to be below a very slow average # this pattern only catches a few, but normally very good buy points ( (dataframe['average'].shift(5) > dataframe['average'].shift(4)) & (dataframe['average'].shift(4) > dataframe['average'].shift(3)) & (dataframe['average'].shift(3) > dataframe['average'].shift(2)) & (dataframe['average'].shift(2) > dataframe['average'].shift(1)) & (dataframe['average'].shift(1) < dataframe['average'].shift(0)) & (dataframe['low'].shift(1) < dataframe['bb_middleband']) & (dataframe['cci'].shift(1) < -100) & (dataframe['rsi'].shift(1) < 30) & (dataframe['mfi'].shift(1) < 30) ) ) # safeguard against down trending markets and a pump and dump & ( (dataframe['volume'] < (dataframe['volume'].rolling(window=30).mean().shift(1) * 20)) & (dataframe['resample_sma'] < dataframe['close']) & (dataframe['resample_sma'].shift(1) < dataframe['resample_sma']) ) ) , 'enter_long'] = 1 return dataframe
Exit rules
def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: dataframe.loc[ ( (dataframe['close'] > dataframe['ema_{}'.format(self.EMA_SHORT_TERM)]) & (dataframe['close'] > dataframe['ema_{}'.format(self.EMA_MEDIUM_TERM)]) & (dataframe['close'] >= dataframe['max']) & (dataframe['close'] >= dataframe['bb_upperband']) & (dataframe['mfi'] > 80) ) | # always sell on eight green candles # with a high rsi ( (dataframe['open'] < dataframe['close']) & (dataframe['open'].shift(1) < dataframe['close'].shift(1)) & (dataframe['open'].shift(2) < dataframe['close'].shift(2)) & (dataframe['open'].shift(3) < dataframe['close'].shift(3)) & (dataframe['open'].shift(4) < dataframe['close'].shift(4)) & (dataframe['open'].shift(5) < dataframe['close'].shift(5)) & (dataframe['open'].shift(6) < dataframe['close'].shift(6)) & (dataframe['open'].shift(7) < dataframe['close'].shift(7)) & (dataframe['rsi'] > 70) ) , 'exit_long' ] = 1 return dataframe
Indicators
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: dataframe = self.resample(dataframe, self.timeframe, self.resample_factor) ################################################################################## # buy and sell indicators dataframe['ema_{}'.format(self.EMA_SHORT_TERM)] = ta.EMA( dataframe, timeperiod=self.EMA_SHORT_TERM ) dataframe['ema_{}'.format(self.EMA_MEDIUM_TERM)] = ta.EMA( dataframe, timeperiod=self.EMA_MEDIUM_TERM ) dataframe['ema_{}'.format(self.EMA_LONG_TERM)] = ta.EMA( dataframe, timeperiod=self.EMA_LONG_TERM ) bollinger = qtpylib.bollinger_bands( qtpylib.typical_price(dataframe), window=20, stds=2 ) dataframe['bb_lowerband'] = bollinger['lower'] dataframe['bb_middleband'] = bollinger['mid'] dataframe['bb_upperband'] = bollinger['upper'] dataframe['min'] = ta.MIN(dataframe, timeperiod=self.EMA_MEDIUM_TERM) dataframe['max'] = ta.MAX(dataframe, timeperiod=self.EMA_MEDIUM_TERM) dataframe['cci'] = ta.CCI(dataframe) dataframe['mfi'] = ta.MFI(dataframe) dataframe['rsi'] = ta.RSI(dataframe, timeperiod=7) dataframe['average'] = (dataframe['close'] + dataframe['open'] + dataframe['high'] + dataframe['low']) / 4 ################################################################################## # required for graphing bollinger = qtpylib.bollinger_bands(dataframe['close'], window=20, stds=2) dataframe['bb_lowerband'] = bollinger['lower'] dataframe['bb_upperband'] = bollinger['upper'] dataframe['bb_middleband'] = bollinger['mid'] macd = ta.MACD(dataframe) dataframe['macd'] = macd['macd'] dataframe['macdsignal'] = macd['macdsignal'] dataframe['macdhist'] = macd['macdhist'] 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 ReinforcedQuickie --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.