Freqtrade Strategy

AverageStrategy

4h candlesMoving-average crossoverSpot, long only

Tested 1 Jun 2023 – 30 May 2025
Rank 2 of 27 by return

AverageStrategy turned $1,000 into $2,233 (+123.3%) over 729 days, while holding Bitcoin returned +288.1% and an equal mix of the ten coins +194.8%. Its worst drawdown was a relatively contained 13.1%. It lost more trades than it won (31% win rate) but its winners were large enough for a profit factor of 1.52.

AverageStrategy account balance compared with holding Bitcoin$0$1,000$2,000$3,000$4,000JulOctJan 2024AprJulOctJan 2025AprAverageStrategy $2,233BTC hold $3,880
Account balance from $1,000 (closed trades, daily). Dashed line: $1,000 held in BTC over the same days.
Total return+123.3%$2,233 final balance
Max drawdown13.1%9 Dec 2024 to 15 Apr 2025
Win rate31.1%184 wins / 408 losses
Profit factor1.52Gross wins ÷ gross losses
Trades5920.8 per day
Average trade+1.04%after fees
Average hold3d 12hwinners 7d 11h, losers 1d 17h
Annualised (CAGR)+49.5%Sharpe 1.65 · Sortino 7.22

How AverageStrategy trades

A classic two-line crossover on the 4-hour chart. AverageStrategy buys when the 8-period EMA crosses above the 21-period EMA and sells on the opposite cross. A 50% take-profit and a 20% stoploss act as outer limits.

Crossover systems lose often but let winners run, which is why the win rate is low while the total return can still be positive. Expect long flat or losing stretches in sideways markets.

Rules at a glance

Indicators
EMA 8, EMA 21
Take-profit (minimal ROI)
50% from entry
Stoploss
−20%
Trailing stop
Off
Exit signal
Used

Results by month

Profit or loss in USDT for trades closed in each month.

JFMAMJJASOND2023-14+74-77-28+110+163+1852024-99+223+259-22+32-80+21-39+43+21+405+1052025-1-119+33-33+71

Results by coin

PairTradesWin rateProfit (USDT)Avg. hold
SOL/USDT7536.0%+298.163d 17h
BNB/USDT7636.8%+199.064d 3h
AVAX/USDT3339.4%+181.463d 18h
BTC/USDT7733.8%+145.504d 8h
ETH/USDT7429.7%+127.703d 14h
DOGE/USDT5129.4%+126.662d 20h
DOT/USDT4332.6%+119.673d 14h
XRP/USDT5425.9%+109.863d 0h
ADA/USDT5125.5%+33.482d 17h
LINK/USDT5820.7%−108.142d 16h

Why trades closed

Exit reasonTradesWin rateProfit (USDT)
Take-profit (ROI)15100.0%+1,501.55
Still open at end of test250.0%+6.12
Stoploss20.0%−80.71
Exit signal57329.3%−193.54

The code

AverageStrategy comes from the community freqtrade-strategies repository (GPL-3.0). These are the parts that decide when it trades; the full file is 79 lines.

Entry rules
def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
    dataframe.loc[
        (
            qtpylib.crossed_above(
                dataframe[f'ema{self.buy_range_short.value}'],
                dataframe[f'ema{self.buy_range_long.value}']
            ) &
            (dataframe['volume'] > 0)
        ),
        'enter_long'] = 1

    return dataframe
Exit rules
def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
    dataframe.loc[
        (
            qtpylib.crossed_above(
                dataframe[f'ema{self.buy_range_long.value}'],
                dataframe[f'ema{self.buy_range_short.value}']
                ) &
            (dataframe['volume'] > 0)
        ),
        'exit_long'] = 1
    return dataframe
Indicators
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:

    # Combine all ranges ... to avoid duplicate calculation
    for val in list(set(list(self.buy_range_short.range) + list(self.buy_range_long.range))):
        dataframe[f'ema{val}'] = ta.EMA(dataframe, timeperiod=val)

    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 4h --timerange 20230501-20250530
freqtrade backtesting --strategy AverageStrategy --timeframe 4h \
  --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.