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 a classic trend-following tool, but raw PSAR flips can be noisy. This version adds two important filters: volume confirmation and an adaptive acceleration factor based on volatility. In this BTC-USD backtest, the strategy returned 46.39% while BTC buy-and-hold fell 4.34% over the same period.
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 | 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 | 1 |
| Win rate | 43.24% |
PSARVolumeAdaptiveAFStrategy is a volatility-adaptive
Parabolic SAR strategy with a volume filter and trailing-stop exits.
The strategy is interesting because it does not treat every PSAR flip equally. A signal must occur in the right trend regime, and volume must be above average before the trade is allowed. The PSAR acceleration factor also changes with ATR, which makes the stop-and-reverse logic more responsive when volatility expands.
The strategy logic is:
The package run used the default long-only execution mode. The strategy file contains both long and short-side logic, but the reported result should be read as the long-only batch-run result unless shorting is explicitly enabled.
The strategy starts with the trend, volatility, volume, and PSAR indicators:
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,
)
self.psar = bt.indicators.ParabolicSAR(
self.datas[0],
af=self.p.psar_af_min,
afmax=self.p.psar_af_max,
)The adaptive part is the PSAR acceleration factor. When current ATR rises relative to average ATR, the strategy increases the acceleration factor, making PSAR more responsive:
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 * 10Volume confirmation is simple and practical:
volume_confirmed = self.datavolume[0] > (
self.volume_ma[0] * self.p.volume_multiplier
)That prevents the strategy from taking every technical flip. The signal needs participation behind it.
The long entry requires price above the SMA, a bullish price-PSAR crossover, and confirmed 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()Once a buy order completes, the strategy attaches a trailing stop:
if order.isbuy():
self.sell(
exectype=bt.Order.StopTrail,
trailpercent=self.p.trail_percent,
)That stop is important. PSAR handles the signal, but the trailing stop handles the trade after entry.
| 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 | $14,638.55 |
| Strategy file | PSARVolumeAdaptiveAFStrategy.py |
| Strategy class | PSARVolumeAdaptiveAFStrategy |
| 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-hold | 50.73% |
| Sharpe ratio | 0.81 |
| Max drawdown | 22.27% |
| Total trades | 112 |
| Closed trades | 111 |
| Open trades | 1 |
| Winning trades | 48 |
| Losing trades | 63 |
| Win rate | 43.24% |
| Runtime | 2.50 seconds |
The run ended with one open trade. Final equity includes the mark-to-market value of that position at the last bar, while win rate is calculated from the 111 closed trades.
The win rate is below 50%, which is useful context. The strategy did not win by being right most of the time. It won by catching enough large directional moves to offset many smaller losing trades.
The equity curve shows the strategy growing from $10,000.00 to $14,638.55 while BTC buy-and-hold finished negative.
The drawdown chart shows the cost of the approach. Maximum drawdown reached 22.27%, so this is a more active and more volatile strategy than the cleaner low-drawdown examples.
The rolling return chart shows when the strategy gained its edge. This matters because the headline return alone does not explain whether performance came from a single lucky stretch or from repeated trend captures.
The daily return distribution excludes zero-return strategy days. In this run, 253 flat strategy-equity days were removed, leaving 477 non-zero strategy return days plotted.
This strategy is a good example of making a familiar indicator more selective. Parabolic SAR is easy to understand, but it can overtrade. Adding a trend filter, volume confirmation, adaptive acceleration, and a trailing stop creates a more complete trading system.
That is the point of the Mega Backtrader Strategy Pack: it gives you a large library of complete strategy implementations, not just isolated indicator snippets. You can run them across assets, compare the results, inspect the code, and publish the strongest research examples.
Get the full package here: Mega Backtrader Strategy Pack.
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.