← Back to Home
Adaptive PSAR Volume Strategy Backtest BTC-USD 46.39% Return With 111 Closed Trades

Adaptive PSAR Volume Strategy Backtest BTC-USD 46.39% Return With 111 Closed Trades

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.

Parabolic SAR is designed to follow trends, but a fixed acceleration factor can be too slow in fast markets and too sensitive in quiet ones. PSARVolumeAdaptiveAFStrategy combines a volatility-responsive PSAR setting with trend and volume filters, then uses trailing orders to manage positions.

In this BTC-USD backtest, the implementation turned a $10,000 account into $14,638.55. That equals a 46.39% strategy return, while BTC buy-and-hold lost 4.34% over the same daily data window.

The test used BTC-USD daily candles from July 27, 2024 to July 27, 2026.

Headline result Value
Strategy return 46.39%
BTC buy-and-hold return -4.34%
Excess return 50.73%
Final portfolio value $14,638.55
Sharpe ratio 0.81
Max drawdown 22.27%
Closed trades 111
Open trades at the end 1
Win rate on closed trades 43.24%

Why This Strategy Is Interesting

PSARVolumeAdaptiveAFStrategy is a trend-following system built from four ideas:

  1. Use a 30-day simple moving average to define the broad trend.
  2. Adjust the PSAR acceleration setting in response to ATR relative to its recent average.
  3. Require current volume to exceed its seven-day average by 20%.
  4. Attach a 2% trailing stop after an order fills.

These filters ask different questions. The moving average asks whether price is in a bullish or bearish regime. PSAR looks for a directional flip. Relative volume checks whether participation supports the signal. ATR influences how quickly the PSAR should react.

The result is not a low-turnover strategy. It recorded 111 completed trades, won 48, lost 63, and still finished profitably because win rate alone does not determine performance. The size of winners and losers—and the path taken to reach them—matters just as much.

How the Code Works

The strategy starts with a trend filter, short-term ATR, smoothed ATR, and a volume average:

self.sma = bt.indicators.SimpleMovingAverage(
    self.datas[0], period=self.p.ma_period
)

self.atr = bt.indicators.ATR(
    self.datas[0], period=self.p.atr_period
)
self.avg_atr = bt.indicators.SMA(
    self.atr, period=self.p.atr_smoothing_period
)

self.volume_ma = bt.indicators.SMA(
    self.datavolume, period=self.p.volume_ma_period
)

The default parameters use a 30-day trend average, seven-day ATR, 30-day ATR smoothing, and a seven-day volume average.

Each bar, the strategy maps the current ATR-to-average-ATR relationship into a value between the configured minimum and maximum acceleration factors:

current_af = self.p.psar_af_min + (
    self.p.psar_af_max - self.p.psar_af_min
) * min(
    1.0,
    max(
        0.0,
        (
            self.atr[0] / self.avg_atr[0]
            if self.avg_atr[0]
            else 1.0
        ) - 0.5,
    ),
)

self.psar.af = current_af
self.psar.afmax = current_af * 10

The intended effect is intuitive: when ATR rises relative to its smoothed baseline, PSAR should react faster; when volatility cools, it should become less aggressive. Dynamic indicator parameters deserve careful implementation testing in Backtrader, so this behavior should be verified bar by bar before the strategy is modified or deployed.

Volume must also clear its confirmation threshold:

volume_confirmed = (
    self.datavolume[0]
    > self.volume_ma[0] * self.p.volume_multiplier
)

With the default volume_multiplier of 1.2, current volume must be more than 120% of its seven-day average.

The initial entry logic then combines regime, PSAR direction, and volume:

if not self.position:
    if self.dataclose[0] > self.sma[0]:
        if self.psar_cross[0] > 0.0 and volume_confirmed:
            self.order = self.buy()

    elif self.dataclose[0] < self.sma[0]:
        if self.psar_cross[0] < 0.0 and volume_confirmed:
            self.order = self.sell()

Above the SMA, only bullish PSAR flips qualify. Below the SMA, only bearish flips qualify. That makes the moving average a directional gate instead of a separate entry signal.

Important Implementation Detail

The order callback submits an opposite trailing-stop order after every completed buy or sell:

if order.status in [order.Completed]:
    if order.isbuy():
        self.sell(
            exectype=bt.Order.StopTrail,
            trailpercent=self.p.trail_percent,
        )
    elif order.issell():
        self.buy(
            exectype=bt.Order.StopTrail,
            trailpercent=self.p.trail_percent,
        )

This is important when interpreting the test. A trailing order that closes a position is itself a completed buy or sell, so the callback can submit another opposite trailing order. The measured result therefore reflects the code exactly as written, including possible chained reversals after the first filtered entry. It should not be read as proof that all 112 recorded positions independently passed the SMA, PSAR, and volume conditions.

A production revision would normally distinguish an entry fill from an exit fill, cancel stale orders, and verify whether the strategy is flat before creating the next protective order. That change would produce a different system and would need a separate backtest.

Backtest Setup

Setting Value
Asset BTC-USD
Benchmark BTC-USD buy-and-hold
Period 2 years
Data window July 27, 2024 to July 27, 2026
Interval 1 day
Starting cash $10,000.00
Commission 0.10%
Default stake allocation 95%
Strategy file PSARVolumeAdaptiveAFStrategy.py
Strategy class PSARVolumeAdaptiveAFStrategy

The backtest was rerun specifically for this article with the repository's standard runner and refreshed BTC-USD data.

Performance Results

Metric Value
Starting portfolio value $10,000.00
Final portfolio value $14,638.55
Strategy return 46.39%
BTC buy-and-hold return -4.34%
Excess return vs BTC buy-and-hold 50.73%
Sharpe ratio 0.81
Max drawdown 22.27%
Total recorded trades 112
Closed trades 111
Open trades 1
Winning trades 48
Losing trades 63
Win rate 43.24%
Strategy execution time 2.50 seconds

The final equity includes the mark-to-market value of one open position at the last bar. Win rate is calculated only from the 111 closed trades.

Equity Curve vs Benchmark

PSARVolumeAdaptiveAFStrategy BTC-USD equity curve versus benchmark

The equity curve provides the clearest view of the strategy's advantage during this sample. BTC buy-and-hold ended below its starting value, while the strategy finished substantially higher. The path was not smooth, however, so the ending return should always be considered alongside drawdown.

Drawdown vs Benchmark

PSARVolumeAdaptiveAFStrategy BTC-USD drawdown versus benchmark

Maximum drawdown reached 22.27%. That is large enough to matter in live portfolio construction and helps explain why the 46.39% headline return came with a moderate 0.81 Sharpe ratio.

Rolling Return vs Benchmark

PSARVolumeAdaptiveAFStrategy BTC-USD rolling return versus benchmark

Rolling returns show whether the strategy's edge persisted across the full test or arrived in a narrow period. They also reveal when holding BTC directly would have been the stronger choice.

Daily Return Distribution

PSARVolumeAdaptiveAFStrategy BTC-USD daily returns histogram

The strategy equity changed on 477 of the 730 return observations and was flat on 253. The histogram helps expose tail behavior that a single average or Sharpe ratio can hide.

What Traders Can Learn From This Test

Three lessons stand out.

First, a strategy can be profitable with a sub-50% win rate. Payoff distribution and loss control matter more than pursuing a cosmetically high percentage of winning trades.

Second, excess return does not remove risk. The strategy beat BTC buy-and-hold by 50.73 percentage points, but it still experienced a 22.27% maximum drawdown.

Third, backtests measure implementations, not strategy descriptions. Small order-management details can materially change the sequence of trades. Inspecting callbacks, position state, and pending orders is just as important as reviewing entry indicators.

The Mega Backtrader Strategy Pack is designed to make that research loop repeatable: inspect a strategy, run it in isolation, compare it with a benchmark, review the exported charts, and revise the implementation when the evidence calls for it.

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. The test does not establish out-of-sample robustness and does not model every source of live-trading friction. Validate strategy logic, indicator behavior, position sizing, order state, data quality, costs, slippage, and risk before using any trading system.