← Back to Home
HP Trend Following Strategy Backtest BTC-USD 38.81% Return With 42.50% Excess Return

HP Trend Following Strategy Backtest BTC-USD 38.81% Return With 42.50% Excess Return

Want the full code behind this test? The Mega Backtrader Strategy Pack includes 500+ Backtrader-ready Python strategies, batch runners, dashboards, CSV metrics, chart exports, and documentation. You can get the full package here: Mega Backtrader Strategy Pack.

Trend following usually starts with moving averages, but the Hodrick-Prescott filter takes a different route. It decomposes price into a smoother trend component and a cyclical component, then lets the strategy trade only when trend direction, trend strength, and cycle position line up.

In this BTC-USD daily backtest, HPTrendFollowingStrategy returned 38.81% while BTC buy-and-hold lost 3.69% over the same period. The strategy finished with a 42.50% excess return, a 1.04 Sharpe ratio, and a 12.51% maximum drawdown.

The test used BTC-USD daily candles from July 27, 2024 to July 27, 2026. The benchmark was BTC buy-and-hold.

Result Value
Strategy return 38.81%
BTC buy-and-hold return -3.69%
Excess return 42.50%
Final portfolio value $13,881.12
Sharpe ratio 1.04
Max drawdown 12.51%
Closed trades 11
Open trades 1
Win rate 54.55%

Why This Strategy Matters

HPTrendFollowingStrategy is a trend-following system built around the Hodrick-Prescott filter. Instead of reacting to every short-term price move, it separates price into a smoothed trend and a cycle around that trend.

That matters because many trend strategies fail by buying every small breakout and exiting on every pullback. This strategy asks for more confirmation. It wants the fast trend to point in the right direction, the slow trend to support the move, trend strength to clear a threshold, and the cycle component to avoid buying into a weak part of the move.

The strategy logic is:

  1. Calculate a fast HP trend with a lower smoothing value.
  2. Calculate a slower HP trend with a higher smoothing value.
  3. Measure fast trend direction and slow trend direction.
  4. Compare the fast trend against the slow trend to estimate trend strength.
  5. Require trend direction to persist for several bars.
  6. Use the HP cycle component to avoid poor entries.
  7. Manage open positions with a trailing stop, trend reversal exit, cycle exit, and fixed stop loss.

The package run used the default long-only execution mode. The strategy file includes short-side logic too, but the reported result should be read as the long-only batch-run result unless shorting is explicitly enabled.

How The Code Works

The foundation is a custom Backtrader indicator that calculates the Hodrick-Prescott trend and cycle:

class HodrickPrescottFilter(bt.Indicator):
    lines = ('hp_trend', 'hp_cycle')
    params = (
        ('lambda_param', 129600),
        ('lookback', 100),
        ('min_periods', 50),
    )

Inside the indicator, the HP filter solves for a smooth trend component. The cycle is simply the difference between price and that trend:

A = I + lambda_param * D2.T @ D2

try:
    trend = spsolve(A, data)
    cycle = data - trend
    return trend, cycle
except:
    trend = np.convolve(data, np.ones(min(20, n)) / min(20, n), mode='same')
    cycle = data - trend
    return trend, cycle

The strategy creates two versions of the HP filter. The fast version responds more quickly, while the slow version acts as the broader trend anchor:

self.fast_hp = HodrickPrescottFilter(
    lambda_param=self.params.fast_lambda,
    lookback=self.params.lookback,
    min_periods=self.params.lookback // 2,
)

self.slow_hp = HodrickPrescottFilter(
    lambda_param=self.params.slow_lambda,
    lookback=self.params.lookback,
    min_periods=self.params.lookback // 2,
)

Then it derives trend direction, trend strength, and price position versus the slow trend:

self.fast_trend_direction = self.fast_hp.hp_trend - self.fast_hp.hp_trend(-1)
self.slow_trend_direction = self.slow_hp.hp_trend - self.slow_hp.hp_trend(-1)

self.trend_strength = self.fast_hp.hp_trend / self.slow_hp.hp_trend - 1
self.price_vs_trend = (
    self.data.close - self.slow_hp.hp_trend
) / self.slow_hp.hp_trend

The entry rule is selective. A long signal needs fast-trend strength, slow-trend agreement, positive trend strength, and cycle confirmation:

long_trend = (
    fast_trend_dir > abs(fast_trend) * self.params.trend_threshold
    and slow_trend_dir > 0
    and trend_strength > self.params.trend_threshold
)

long_cycle = (
    fast_cycle > -abs(slow_trend) * self.params.cycle_threshold
    and price_vs_trend > -self.params.cycle_threshold
)

if long_trend and long_cycle:
    self.order = self.buy()

After entry, the strategy manages risk with a trailing stop, a trend reversal exit, a cycle exit, and a fixed stop loss:

new_stop = current_price * (1 - self.params.trailing_stop_pct)
if new_stop > self.trailing_stop_price:
    self.trailing_stop_price = new_stop

trend_reversal = (
    fast_trend_dir < -abs(fast_trend) * self.params.trend_threshold
    or slow_trend_dir < 0
)
cycle_exit = fast_cycle < -abs(slow_trend) * self.params.cycle_threshold

if (
    current_price <= self.trailing_stop_price
    or trend_reversal
    or cycle_exit
    or current_price <= self.entry_price * (1 - self.params.stop_loss_pct)
):
    self.order = self.sell()

That combination makes the strategy more than a simple trend indicator. It has a signal layer, a confirmation layer, and a position-management layer.

Backtest Setup

Setting Value
Asset BTC-USD
Benchmark BTC-USD
Period 2y
Data window July 27, 2024 to July 27, 2026
Interval 1d
Starting cash $10,000.00
Final value $13,881.12
Strategy file HPTrendFollowingStrategy.py
Strategy class HPTrendFollowingStrategy

Performance Results

Metric Value
Starting portfolio value $10,000.00
Final portfolio value $13,881.12
Strategy return 38.81%
BTC buy-and-hold return -3.69%
Excess return vs BTC buy-hold 42.50%
Sharpe ratio 1.04
Max drawdown 12.51%
Total trades 12
Closed trades 11
Open trades 1
Winning trades 6
Losing trades 5
Win rate 54.55%
Runtime 3.53 seconds

The run ended with one open trade. Final portfolio value includes the mark-to-market value of that position at the final bar, while win rate is calculated from the 11 closed trades.

This is exactly why closed-trade count and return can look disconnected in a backtest report. A strategy can have an open position at the end of the test, and that open position still contributes to final equity even though it is not counted as a closed trade.

Equity Curve vs Benchmark

HP Trend Following BTC-USD equity curve versus benchmark

The equity curve shows the strategy growing from $10,000.00 to $13,881.12 while BTC buy-and-hold ended slightly negative over the same two-year window.

The important detail is not just the final number. The strategy avoided some of the weaker stretches in BTC and kept enough exposure to participate when the trend improved.

Drawdown vs Benchmark

HP Trend Following BTC-USD drawdown versus benchmark

Maximum drawdown was 12.51%, which is moderate for a BTC daily strategy over this window. That is one of the stronger parts of the result: the strategy did not need a 30%, 40%, or 50% drawdown to produce the return.

For research, this chart is as important as the equity curve. A strategy that beats buy-and-hold but does it with uncontrolled drawdowns is much harder to use in practice.

Rolling Return vs Benchmark

HP Trend Following BTC-USD rolling return versus benchmark

The rolling return chart shows when the edge appeared. This helps separate a usable trend model from a strategy that only looks good because of one final price move.

For this HP-filter version, the value comes from regime selectivity. The strategy is not trying to stay invested every day. It is trying to participate when the smoothed trend structure improves and step aside when the setup weakens.

Daily Return Distribution

HP Trend Following BTC-USD daily returns histogram

The daily return distribution excludes zero-return strategy days. In this run, 571 flat strategy-equity days were removed, leaving 159 non-zero strategy return days plotted.

Removing zero-return days makes the distribution easier to read for strategies that spend long periods in cash. Otherwise the histogram gets dominated by a large spike at zero and hides the shape of the actual trading days.

What Traders Can Learn From This Test

This backtest is a useful example of applying a signal-processing idea to trading. The HP filter is not a trading system by itself. It becomes more useful when it is wrapped in explicit rules for trend direction, trend strength, cycle position, entry confirmation, and exits.

The result also shows why a large strategy library is valuable. You do not need every strategy to work on every asset. You need a repeatable way to scan many complete strategies, find the ones that fit a market, inspect the code, and decide which ideas deserve deeper testing.

That is what the Mega Backtrader Strategy Pack is built for: strategy research, batch backtesting, chart review, and code-level learning across hundreds of Backtrader implementations.

Get the full package here: Mega Backtrader Strategy Pack.

Disclaimer

This article is for research and educational use only. Backtest results are not financial advice, investment advice, or a guarantee of future performance. Always validate strategy logic, data quality, execution assumptions, costs, slippage, and risk before using any trading system.