,

XLE PBands Backtest: Profitable, But Risk-Adjusted Evidence Is Weak

A concise quant research note testing PBands Lower Band Mean Reversion Long Only on XLE, with rules, benchmark comparison, friction, and stress testing.

Desk: ,
Equity curve and drawdown for PBands Lower Band Mean Reversion Long Only

Executive Summary

Energy ETFs trend and gap more aggressively, which makes them a useful stress test for <span class="lf0-tooltip" tabindex="0" style="border-bottom: 1px dotted currentColor; cursor: help;" title="A tendency for prices that moved unusually far in one direction to snap back toward a more normal level." data-tooltip="A tendency for prices that moved unusually far in one direction to snap back toward a more normal level." aria-label="mean reversion: A tendency for prices that moved unusually far in one direction to snap back toward a more normal level.">mean reversion</span>. This run covers 2016-01-01 to 2025-01-01 using quantstrat in R, with initial equity of $100,000. I compare it with buy-and-hold, apply base friction, and run a first sequence stress test.

Research Card

FieldDetail
InstrumentXLE
Strategy typeMean reversion / band break
Publication archetypeempirical myth-busting research note
Test period2016-01-01 to 2025-01-01
Enginequantstrat in R
Starting equity$100,000
Strategy net P&L$1,470
Strategy <span class="lf0-tooltip" tabindex="0" style="border-bottom: 1px dotted currentColor; cursor: help;" title="Compound annual growth rate. It converts the full-period return into an annualized growth pace." data-tooltip="Compound annual growth rate. It converts the full-period return into an annualized growth pace." aria-label="CAGR: Compound annual growth rate. It converts the full-period return into an annualized growth pace.">CAGR</span>0.16%
Strategy max <span class="lf0-tooltip" tabindex="0" style="border-bottom: 1px dotted currentColor; cursor: help;" title="The fall from a prior equity high to a later low. It measures the pain a trader had to sit through." data-tooltip="The fall from a prior equity high to a later low. It measures the pain a trader had to sit through." aria-label="drawdown: The fall from a prior equity high to a later low. It measures the pain a trader had to sit through.">drawdown</span>-0.42%
Trades50
<span class="lf0-tooltip" tabindex="0" style="border-bottom: 1px dotted currentColor; cursor: help;" title="The comparison hurdle. For a single ETF strategy, buy-and-hold of the same ETF is the first test to beat." data-tooltip="The comparison hurdle. For a single ETF strategy, buy-and-hold of the same ETF is the first test to beat." aria-label="Benchmark: The comparison hurdle. For a single ETF strategy, buy-and-hold of the same ETF is the first test to beat.">Benchmark</span>Buy and hold XLE
Benchmark CAGR13.03%
CAGR spread-12.87%
Costs/stressBase friction and <span class="lf0-tooltip" tabindex="0" style="border-bottom: 1px dotted currentColor; cursor: help;" title="A simulation method that repeatedly reshuffles the same historical trades to see how much the sequence alone changes the path." data-tooltip="A simulation method that repeatedly reshuffles the same historical trades to see how much the sequence alone changes the path." aria-label="Monte Carlo: A simulation method that repeatedly reshuffles the same historical trades to see how much the sequence alone changes the path.">Monte Carlo</span> sequence stress included
VerdictTrailed buy-and-hold on CAGR before costs

The Setup

I’m testing a simple but non-obvious version of mean reversion in XLE: when energy names get pushed below a short-term lower bound, do they tend to snap back rather than keep trending lower? The idea is that sector ETF flows, commodity-linked overreaction, and periodic macro shocks can create temporary dislocations that price eventually digests.

Results

MetricStrategyBenchmarkWhy it matters
Final Equity$101,470$301,093Ending account value before full friction modeling.
CAGR0.16%13.03%Annualized growth; the first hurdle is buy-and-hold.
Max Drawdown-0.42%-64.17%Worst peak-to-trough decline.
<span class="lf0-tooltip" tabindex="0" style="border-bottom: 1px dotted currentColor; cursor: help;" title="Return per unit of volatility. It asks whether the strategy was paid enough for the ride it took." data-tooltip="Return per unit of volatility. It asks whether the strategy was paid enough for the ride it took." aria-label="Sharpe Ratio: Return per unit of volatility. It asks whether the strategy was paid enough for the ride it took.">Sharpe Ratio</span>3.610.56Return earned per unit of volatility.
<span class="lf0-tooltip" tabindex="0" style="border-bottom: 1px dotted currentColor; cursor: help;" title="Like Sharpe, but it only penalizes downside volatility, which is often what traders actually care about." data-tooltip="Like Sharpe, but it only penalizes downside volatility, which is often what traders actually care about." aria-label="Sortino Ratio: Like Sharpe, but it only penalizes downside volatility, which is often what traders actually care about.">Sortino Ratio</span>0.400.73Like Sharpe, but focused on downside volatility.
<span class="lf0-tooltip" tabindex="0" style="border-bottom: 1px dotted currentColor; cursor: help;" title="Annualized return divided by maximum drawdown. It asks how much growth the strategy earned for the pain it caused." data-tooltip="Annualized return divided by maximum drawdown. It asks how much growth the strategy earned for the pain it caused." aria-label="Calmar Ratio: Annualized return divided by maximum drawdown. It asks how much growth the strategy earned for the pain it caused.">Calmar Ratio</span>0.39N/ACAGR divided by max drawdown.
<span class="lf0-tooltip" tabindex="0" style="border-bottom: 1px dotted currentColor; cursor: help;" title="Gross profits divided by gross losses. Above 1 means winners outweighed losers before considering other constraints." data-tooltip="Gross profits divided by gross losses. Above 1 means winners outweighed losers before considering other constraints." aria-label="Profit Factor: Gross profits divided by gross losses. Above 1 means winners outweighed losers before considering other constraints.">Profit Factor</span>1.92N/AGross profits divided by gross losses.
<span class="lf0-tooltip" tabindex="0" style="border-bottom: 1px dotted currentColor; cursor: help;" title="Average winning trade divided by average losing trade. It shows whether wins are large enough to pay for losses." data-tooltip="Average winning trade divided by average losing trade. It shows whether wins are large enough to pay for losses." aria-label="Payoff Ratio: Average winning trade divided by average losing trade. It shows whether wins are large enough to pay for losses.">Payoff Ratio</span>1.28N/AAverage winner divided by average loser.
Median Trade$14N/AA reality check against a few outsized trades.
<span class="lf0-tooltip" tabindex="0" style="border-bottom: 1px dotted currentColor; cursor: help;" title="The share of the test period where capital was actually in the market. Lower exposure can change how returns should be judged." data-tooltip="The share of the test period where capital was actually in the market. Lower exposure can change how returns should be judged." aria-label="Exposure: The share of the test period where capital was actually in the market. Lower exposure can change how returns should be judged.">Exposure</span>13.87%100.00%Percentage of days with capital at risk.
Equity Curve And Drawdown
Monthly Return Heatmap

I do not think the backtest supports the original mean-reversion hypothesis in a strong way. Final equity was 101,469.67 from 100,000, for net P&L of 1,469.67 and CAGR of 0.162%. That is economically small, and the statistical limit matters here: the closed-trade bootstrap puts the 95% CI for mean P&L at -1.03 to 61.08, the Wilcoxon p-value is 0.2548, and the win-rate binomial test is 60.8% with p…

Statistical Limits And Regime Dependence

The key question is whether the evidence survives sampling uncertainty, clustered trades, and regime shifts. P-values are diagnostics, not trading signals.

Statistical CheckEvidenceWhy it matters
Bootstrap mean trade P&L$-1.03 to $61.08 95% intervalTests whether the <span class="lf0-tooltip" tabindex="0" style="border-bottom: 1px dotted currentColor; cursor: help;" title="The typical profit or loss per closed trade. Small values are fragile because costs can erase them quickly." data-tooltip="The typical profit or loss per closed trade. Small values are fragile because costs can erase them quickly." aria-label="average trade: The typical profit or loss per closed trade. Small values are fragile because costs can erase them quickly.">average trade</span> edge survives resampling.
Bootstrap mean positive rate97.0%Useful for direction, but not a substitute for <span class="lf0-tooltip" tabindex="0" style="border-bottom: 1px dotted currentColor; cursor: help;" title="The later portion of the historical test, used here to check whether the result held up after the initial sample." data-tooltip="The later portion of the historical test, used here to check whether the result held up after the initial sample." aria-label="out-of-sample: The later portion of the historical test, used here to check whether the result held up after the initial sample.">out-of-sample</span> proof.
Binomial win-rate diagnosticp=0.1608Checks whether the hit rate is unusual versus a neutral 50% baseline.
Wilcoxon trade-P&L diagnosticp=0.2548Non-parametric check of whether trade P&L is centered above zero.
Equity-return serial dependencep=0.0000Flags whether daily strategy returns are path-dependent.
Closed-trade serial dependencep=0.0007Checks whether trade outcomes cluster.
Analysis AreaStatusArtifact
trade_edgereadystatistical_diagnostics.rds/per_trade_stats.rds
win_ratereadystatistical_diagnostics.rds/per_trade_stats.rds
path_riskreadystress_summary.rds
cost_sensitivityreadyfriction_summary.rds
parameter_robustnessreadyparameter_sensitivity.rds
sample_splitreadystress_summary.rds
walk_forwardreadywalk_forward_summary.rds
serial_dependencereadystatistical_diagnostics.rds

Regime dependency: this setup can degrade when volatility expands, gaps dominate, or the sector enters a persistent trend. The forward-degradation rows test stability, not parameter-optimization skill.

Costs And Stress Test

I now run a simple friction pass before drafting the article. For this strategy test, the base case assumes 2.00 bps of <span class="lf0-tooltip" tabindex="0" style="border-bottom: 1px dotted currentColor; cursor: help;" title="The difference between the expected execution price and the actual fill. It usually gets worse in fast or illiquid markets." data-tooltip="The difference between the expected execution price and the actual fill. It usually gets worse in fast or illiquid markets." aria-label="slippage: The difference between the expected execution price and the actual fill. It usually gets worse in fast or illiquid markets.">slippage</span> per side and 1.00 bps of spread cost per side, or 6.00 bps per round trip. That is still a model, but it is a better starting point than pretending fills are free.

Friction CheckValue
Gross net P&L$1,470
Base <span class="lf0-tooltip" tabindex="0" style="border-bottom: 1px dotted currentColor; cursor: help;" title="The full entry-plus-exit trading cost for one completed trade, expressed here in basis points." data-tooltip="The full entry-plus-exit trading cost for one completed trade, expressed here in basis points." aria-label="round-trip cost: The full entry-plus-exit trading cost for one completed trade, expressed here in basis points.">round-trip cost</span>$70
<span class="lf0-tooltip" tabindex="0" style="border-bottom: 1px dotted currentColor; cursor: help;" title="Strategy profit after the friction model subtracts estimated spread, slippage, and commission costs." data-tooltip="Strategy profit after the friction model subtracts estimated spread, slippage, and commission costs." aria-label="Cost-adjusted net P&amp;L: Strategy profit after the friction model subtracts estimated spread, slippage, and commission costs.">Cost-adjusted net P&L</span>$1,400
Gross profit factor1.92
Cost-adjusted profit factor1.98
<span class="lf0-tooltip" tabindex="0" style="border-bottom: 1px dotted currentColor; cursor: help;" title="The estimated round-trip cost level where the historical net profit would be fully consumed by trading costs." data-tooltip="The estimated round-trip cost level where the historical net profit would be fully consumed by trading costs." aria-label="Break-even round-trip cost: The estimated round-trip cost level where the historical net profit would be fully consumed by trading costs.">Break-even round-trip cost</span>125.71 bps
Stress CheckValue
Monte Carlo simulations2000
Observed trade-order max drawdown-0.42%
<span class="lf0-tooltip" tabindex="0" style="border-bottom: 1px dotted currentColor; cursor: help;" title="A conservative drawdown estimate: only about 5% of reshuffled paths were worse than this level." data-tooltip="A conservative drawdown estimate: only about 5% of reshuffled paths were worse than this level." aria-label="95th percentile drawdown: A conservative drawdown estimate: only about 5% of reshuffled paths were worse than this level.">95th percentile drawdown</span>-0.43%
Median simulated ending P&L$1,469
<span class="lf0-tooltip" tabindex="0" style="border-bottom: 1px dotted currentColor; cursor: help;" title="The low-end bootstrapped outcome. It asks what the strategy looked like when the sampled trades were less favorable than history." data-tooltip="The low-end bootstrapped outcome. It asks what the strategy looked like when the sampled trades were less favorable than history." aria-label="Weak-path ending P&amp;L: The low-end bootstrapped outcome. It asks what the strategy looked like when the sampled trades were less favorable than history.">Weak-path ending P&L</span>$147
High-cost net P&L$1,329
<span class="lf0-tooltip" tabindex="0" style="border-bottom: 1px dotted currentColor; cursor: help;" title="The earlier portion of the historical test, used here as a rough development-period diagnostic." data-tooltip="The earlier portion of the historical test, used here as a rough development-period diagnostic." aria-label="In-sample: The earlier portion of the historical test, used here as a rough development-period diagnostic.">In-sample</span> net P&L$-148 over 35 trades
Out-of-sample net P&L$1,617 over 16 trades
Out-of-sample profit factor4.62
Forward average-trade degradation2493.96%
Forward profit-factor degradation446.94%
Walk-forward windows3 anchored test windows
Walk-forward positive test windows100.00%
Worst walk-forward test P&L$3
Median walk-forward avg-trade degradation557.35%
Parameter sensitivity27 <span class="lf0-tooltip" tabindex="0" style="border-bottom: 1px dotted currentColor; cursor: help;" title="Percentage Bands, a band-style indicator that marks stretched prices relative to recent behavior." data-tooltip="Percentage Bands, a band-style indicator that marks stretched prices relative to recent behavior." aria-label="PBands: Percentage Bands, a band-style indicator that marks stretched prices relative to recent behavior.">PBands</span> variants tested; best net P&L $2,084 at n=25, sd=1.5, stop=7.00%
Baseline grid result$1,744 net P&L; profit factor 2.51
Parameter Sensitivity Heatmap

Watch the break-even round-trip cost: above that level, the historical edge is gone. Monte Carlo separates edge from path luck; the in/out row is a closed-trade split, not walk-forward optimization.

What Breaks It

Per-Trade P&L Distribution

The trade P&L distribution is right-skewed: there are a lot of small-to-moderate gains, a meaningful cluster of losses below zero, and a few larger winners that pull the average up. That matters because the edge is not coming from a clean, symmetric payoff; it depends on occasional outsized snapbacks to offset many mediocre trades.

Verdict

I set out to test whether a simple lower-band PBands mean-reversion rule in XLE could capture temporary overshoots and turn them into a repeatable long-only edge.

What would change my mind: the same rule needs to survive costs while closing the gap versus buy-and-hold, or prove useful as a timing overlay rather than a standalone strategy.

R Notes

The reproducibility contract is the saved artifact set plus the R scripts that created it. The key JSON/RDS files are recorded in the frontmatter.

# Rebuild the evidence layer for one saved strategy output
source('backtesting_blog_posts/statistical_diagnostics.R')
source('backtesting_blog_posts/walk_forward_diagnostics.R')
source('backtesting_blog_posts/analysis_test_selector.R')

out_dir <- file.path('backtesting_blog_posts', 'outputs', 'strat_pbands_mean_reversion_long_only_xle')
per_trade <- readRDS(file.path(out_dir, 'per_trade_stats.rds'))
portfolio <- readRDS(file.path(out_dir, 'portfolio_summary.rds'))

diagnostics <- build_statistical_diagnostics(per_trade, portfolio)
walk_forward <- build_walk_forward_summary(per_trade)
test_plan <- build_analysis_test_plan(out_dir)

For the current PBands series, parameter_sensitivity uses a deterministic next-bar rerun helper because native quantstrat parameter clones can fail to propagate osMaxPos limits safely. Future strategy families should call register_parameter_sensitivity_builder() with their own sensitivity builder.

Important: Backtests are simulations. Past performance of a simulated strategy does not guarantee future results. Results do not yet fully account for real-world factors including <span class="lf0-tooltip" tabindex="0" style="border-bottom: 1px dotted currentColor; cursor: help;" title="The gap between the price buyers bid and sellers ask. Crossing that gap is a real trading cost." data-tooltip="The gap between the price buyers bid and sellers ask. Crossing that gap is a real trading cost." aria-label="bid-ask spread: The gap between the price buyers bid and sellers ask. Crossing that gap is a real trading cost.">bid-ask spread</span>, market impact, borrow costs, or taxes. This is for educational purposes only and is not investment advice.

Research disclaimer

This material is provided for research and educational purposes only. It is not investment advice, a recommendation, or an offer to buy or sell any security or strategy.

New stock analysis in your inbox.

Independent equity research on under-the-radar companies from lf0 — free, when new work publishes.




No spam. Unsubscribe anytime.

Prefer Substack? Follow lf0 Research on Substack

Leave a Comment

Your email address will not be published. Required fields are marked *