BinHV27
Tested 1 Jun 2023 – 30 May 2025
Rank 21 of 27 by return
BinHV27 turned $1,000 into $406 (−59.4%) 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 60.3%, deep enough that most people would have switched it off. With a 56% win rate and a profit factor of 0.80, losses outweighed gains.
How BinHV27 trades
BinHV27 looks for sharp drops on the 5-minute chart: price below its 60 and 120 EMAs, a fast RSI that has fallen to 20 or less and stopped falling, and a strong directional move to the downside. Several alternative entry branches cover different trend states. Exits are driven by price recovering above those averages.
The 50% stoploss and 100% take-profit are effectively disabled, so the strategy depends entirely on its exit signal. In a falling market that can mean holding a losing coin for a long time.
Rules at a glance
- Indicators
- RSI 5, ADX, +DI / -DI, EMA 60 / 120 / 240
- Take-profit (minimal ROI)
- 100% (effectively off)
- Stoploss
- −50% (effectively off)
- 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 |
|---|---|---|---|---|
| SOL/USDT | 270 | 58.1% | +60.22 | 4h 50m |
| DOGE/USDT | 232 | 61.2% | +38.81 | 4h 36m |
| XRP/USDT | 246 | 55.7% | −31.27 | 4h 40m |
| DOT/USDT | 218 | 56.0% | −46.07 | 4h 58m |
| LINK/USDT | 228 | 56.1% | −55.33 | 4h 32m |
| BNB/USDT | 284 | 54.9% | −69.21 | 5h 8m |
| AVAX/USDT | 240 | 61.7% | −79.49 | 4h 33m |
| BTC/USDT | 237 | 49.8% | −81.84 | 5h 7m |
| ADA/USDT | 253 | 51.4% | −128.95 | 5h 7m |
| ETH/USDT | 269 | 52.8% | −201.15 | 5h 11m |
Why trades closed
| Exit reason | Trades | Win rate | Profit (USDT) |
|---|---|---|---|
| Still open at end of test | 1 | 0.0% | −1.09 |
| Exit signal | 2476 | 55.7% | −593.20 |
The code
BinHV27 comes from the community freqtrade-strategies repository (GPL-3.0). These are the parts that decide when it trades; the full file is 137 lines.
Entry rules
def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: dataframe.loc[ dataframe['slowsma'].gt(0) & dataframe['close'].lt(dataframe['highsma']) & dataframe['close'].lt(dataframe['lowsma']) & dataframe['minusdi'].gt(dataframe['minusdiema']) & dataframe['rsi'].ge(dataframe['rsi'].shift()) & ( ( ~dataframe['preparechangetrend'] & ~dataframe['continueup'] & dataframe['adx'].gt(25) & dataframe['bigdown'] & dataframe['emarsi'].le(20) ) | ( ~dataframe['preparechangetrend'] & dataframe['continueup'] & dataframe['adx'].gt(30) & dataframe['bigdown'] & dataframe['emarsi'].le(20) ) | ( ~dataframe['continueup'] & dataframe['adx'].gt(35) & dataframe['bigup'] & dataframe['emarsi'].le(20) ) | ( dataframe['continueup'] & dataframe['adx'].gt(30) & dataframe['bigup'] & dataframe['emarsi'].le(25) ) ), 'enter_long'] = 1 return dataframe
Exit rules
def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: dataframe.loc[ ( ( ~dataframe['preparechangetrendconfirm'] & ~dataframe['continueup'] & (dataframe['close'].gt(dataframe['lowsma']) | dataframe['close'].gt(dataframe['highsma'])) & dataframe['highsma'].gt(0) & dataframe['bigdown'] ) | ( ~dataframe['preparechangetrendconfirm'] & ~dataframe['continueup'] & dataframe['close'].gt(dataframe['highsma']) & dataframe['highsma'].gt(0) & (dataframe['emarsi'].ge(75) | dataframe['close'].gt(dataframe['slowsma'])) & dataframe['bigdown'] ) | ( ~dataframe['preparechangetrendconfirm'] & dataframe['close'].gt(dataframe['highsma']) & dataframe['highsma'].gt(0) & dataframe['adx'].gt(30) & dataframe['emarsi'].ge(80) & dataframe['bigup'] ) | ( dataframe['preparechangetrendconfirm'] & ~dataframe['continueup'] & dataframe['slowingdown'] & dataframe['emarsi'].ge(75) & dataframe['slowsma'].gt(0) ) | ( dataframe['preparechangetrendconfirm'] & dataframe['minusdi'].lt(dataframe['plusdi']) & dataframe['close'].gt(dataframe['lowsma']) & dataframe['slowsma'].gt(0) ) ), 'exit_long'] = 1 return dataframe
Indicators
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: dataframe['rsi'] = numpy.nan_to_num(ta.RSI(dataframe, timeperiod=5)) rsiframe = DataFrame(dataframe['rsi']).rename(columns={'rsi': 'close'}) dataframe['emarsi'] = numpy.nan_to_num(ta.EMA(rsiframe, timeperiod=5)) dataframe['adx'] = numpy.nan_to_num(ta.ADX(dataframe)) dataframe['minusdi'] = numpy.nan_to_num(ta.MINUS_DI(dataframe)) minusdiframe = DataFrame(dataframe['minusdi']).rename(columns={'minusdi': 'close'}) dataframe['minusdiema'] = numpy.nan_to_num(ta.EMA(minusdiframe, timeperiod=25)) dataframe['plusdi'] = numpy.nan_to_num(ta.PLUS_DI(dataframe)) plusdiframe = DataFrame(dataframe['plusdi']).rename(columns={'plusdi': 'close'}) dataframe['plusdiema'] = numpy.nan_to_num(ta.EMA(plusdiframe, timeperiod=5)) dataframe['lowsma'] = numpy.nan_to_num(ta.EMA(dataframe, timeperiod=60)) dataframe['highsma'] = numpy.nan_to_num(ta.EMA(dataframe, timeperiod=120)) dataframe['fastsma'] = numpy.nan_to_num(ta.SMA(dataframe, timeperiod=120)) dataframe['slowsma'] = numpy.nan_to_num(ta.SMA(dataframe, timeperiod=240)) dataframe['bigup'] = dataframe['fastsma'].gt(dataframe['slowsma']) & ((dataframe['fastsma'] - dataframe['slowsma']) > dataframe['close'] / 300) dataframe['bigdown'] = ~dataframe['bigup'] dataframe['trend'] = dataframe['fastsma'] - dataframe['slowsma'] dataframe['preparechangetrend'] = dataframe['trend'].gt(dataframe['trend'].shift()) dataframe['preparechangetrendconfirm'] = dataframe['preparechangetrend'] & dataframe['trend'].shift().gt(dataframe['trend'].shift(2)) dataframe['continueup'] = dataframe['slowsma'].gt(dataframe['slowsma'].shift()) & dataframe['slowsma'].shift().gt(dataframe['slowsma'].shift(2)) dataframe['delta'] = dataframe['fastsma'] - dataframe['fastsma'].shift() dataframe['slowingdown'] = dataframe['delta'].lt(dataframe['delta'].shift()) 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 BinHV27 --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.