Skip to content

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

ORB Trading Backtester

A rigorous, honesty-first backtester for the Opening Range Breakout (ORB) day-trading strategy.

This project does two things:

  1. Implements ORB variants — from a naive fixed-target version to the strategy documented in academic research.
  2. Tests them with out-of-sample discipline so the results mean something, instead of curve-fitting until a number turns green.

The headline finding is deliberately unglamorous: a naive ORB loses money, the research-grade version has a real but thin and currently-decaying edge, and aggressive parameter-filtering makes things worse, not better. The point of this repo is to show that honestly.


TL;DR results (QQQ, 5-min bars, 2 years)

Strategy avg R / trade Profit Factor Verdict
Naive ORB — 15-min range, fixed 2R target −0.083 0.11–0.48 Loses even before costs
Research ORB — 5-min candle direction, 1R stop, 10R + EOD exit +0.224 1.31 Real edge (full sample)
Research ORB — out-of-sample (recent 12 months) +0.065 1.09 Marginally profitable
Research ORB — last 3 months −0.316 0.60 Currently in drawdown

All results are reported in R-multiples (profit measured in units of the trade's own risk), which is independent of position sizing and commission scaling — the number that actually tells you whether an edge exists.

Equity curve

The equity curve climbs steadily in-sample, then flattens and rolls over in the most recent months — the strategy is currently in the deepest drawdown of the entire 2-year sample.


The story

1. The naive version loses

A textbook ORB (mark the first 15 minutes, enter on a breakout close, stop at the opposite side, target a fixed 2R) was tested on 372 trades of SPY over 18 months. It lost, and the trade log showed why: the 2R target was hit only 14% of the time — you need >33% to break even at 2R. ORB has an asymmetric, fat-tailed payoff, and a fixed 2R target amputates exactly the right tail that pays for everything.

2. The research version fixes the structure

Following Zarattini, Barbon & Aziz ("Can Day Trading Really Be Profitable?", 2023):

  • Opening range = the first 5-minute candle.
  • Direction = the sign of that candle (closed up → long, down → short).
  • Entry = open of the 2nd 5-minute bar.
  • Stop = the candle's opposite extreme (= 1R).
  • Target = 10R, i.e. effectively "let it run"; exit at the market close if untouched.

This single structural change flipped QQQ from −0.083R to +0.224R per trade. Win rate is only 27%, but the average winner (+3.49R) dwarfs the average loser (−0.99R) — exactly the mechanism the paper describes.

3. Filters don't help — they overfit

The paper's supporting filters (relative-volume "stock-in-play", VWAP bias, minimum range) were tested with strict in-sample / out-of-sample separation. Every filter that looked best in-sample lost money out-of-sample:

Variant In-sample avg R Out-of-sample avg R
base (no filters) +0.383 +0.065
+ RVOL ≥ 1.25 +0.774 −0.140
+ RVOL ≥ 1.0 +0.564 −0.074
+ min-range ≥ 1.0 +0.140 −0.137

The more the strategy was filtered, the worse it did on unseen data. The robust choice is the plain, unfiltered base strategy. This table is the whole lesson: optimizing a backtest until it looks great is how you build something that bleeds live.


Files

File Purpose
orb_backtest.py Naive ORB backtester (configurable range, R:R, longs/shorts, costs)
orb_zarattini.py Research-grade ORB (5-min direction, 1R stop, 10R+EOD) with in/out-of-sample split
compare_filters.py Honest filter comparison — reports IS vs OOS side by side
fetch_data.py Pulls extended intraday history from Polygon.io into a CSV
trades_zarattini.csv Trade log from the research strategy
equity_zarattini.png Cumulative-R equity curve with IS/OOS boundary
requirements.txt Python dependencies

Setup & usage

# 1. Environment
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt

# 2. Get data (free Polygon.io API key: https://polygon.io/dashboard/signup)
export POLYGON_API_KEY=your_key_here
python fetch_data.py --symbol QQQ --interval 5 --months 24 --out qqq_5min.csv

# 3. Backtest the research strategy with an out-of-sample split
python orb_zarattini.py --csv qqq_5min.csv --oos-split

# 4. See why filters overfit
python compare_filters.py

# (optional) the naive baseline
python orb_backtest.py --csv qqq_5min.csv --or-min 15 --rr 2.0 --point-value 1

Raw price CSVs are git-ignored (large and reproducible); regenerate them with fetch_data.py.


Honest caveats

  • The out-of-sample edge is marginal (PF ~1.1) and, in the most recent months, negative. This is not a money printer.
  • Results assume ~1 cent/side slippage and no commissions (typical for a modern equity broker). Real fills, gaps, and missed entries will erode a thin edge further.
  • A positive backtest is necessary but nowhere near sufficient. The only real test of whether this edge is alive is forward paper-trading.

Data & references

  • Data: Polygon.io aggregates (free tier).
  • Zarattini, Barbon & Aziz, A Profitable Day Trading Strategy for the U.S. Equity Market / Can Day Trading Really Be Profitable? (2023), SSRN.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages