Overnight Risk Premium: Trading the Open-to-Close Gap
Overnight risk premium refers to the empirical fact that a large share of equity index returns accrues from close to open, not during regular trading hours. Holding the market overnight has historically paid; holding only during the day has often been flat or negative after costs. This is not a free lunch — it is compensation for overnight gap risk, news flow, and funding — but it is one of the most robust calendar effects in equity quant research. This article shows how to measure it, trade it, and when it fails.
The split
Decompose daily returns:
R_close_to_close = R_close_to_open + R_open_to_close
| Component | Window | Typical pattern (US equities, multi-decade) |
|---|---|---|
| Close-to-open | Prior close → open | Positive average, large share of equity premium |
| Open-to-close | Open → close | Near zero or negative after costs |
| Close-to-close | Full day | Positive (classic equity premium) |
import pandas as pd
def overnight_intraday(open_: pd.Series, close: pd.Series) -> pd.DataFrame:
overnight = open_ / close.shift(1) - 1
intraday = close / open_ - 1
return pd.DataFrame({"overnight": overnight, "intraday": intraday})
Always verify on your universe and sample — international markets and small caps differ, and post-2020 microstructure changed overnight ETF flows.
Economic explanations
Competing (not mutually exclusive) stories:
- News risk — earnings, geopolitics, macro prints often hit outside RTH
- Dealer inventory — market makers want to flatten into close; risk transfers overnight
- Buyback / flow timing — some institutional flow concentrates near the close
- Funding / leverage — overnight margin and borrow have different pricing
- Behavioral — retail activity more intraday; institutions mark and hold overnight
You do not need the true cause to trade a premium — but you need a story that predicts when it breaks (e.g. weekend gaps, FOMC nights, crash regimes).
Simple systematic expressions
Buy close, sell open (harvest overnight):
enter: buy at close (or MOC)
exit: sell at open (or near open)
Avoid overnight (intraday only): buy open, sell close — historically weak for indices.
Implementation details dominate:
- Auction fills vs continuous
- Bid-ask at open (wide) and close (auction)
- ETF vs futures (ES overnight is nearly 24h — different premium structure)
- Shorting overnight requires borrow (short selling)
def overnight_strategy_rets(open_, close, cost_bps=2.0):
"""Long close→open, flat daytime. cost_bps = one-way."""
r = open_ / close.shift(1) - 1
cost = cost_bps / 10_000 * 2 # round trip per day
return r - cost
At 2 bps one-way, daily round-trip is 4 bps. Annualized cost ≈ 4 bps × 252 ≈ 10% — enough to erase a thin premium. Edge must clear costs with room for slippage.
Futures vs cash
Equity index futures trade nearly around the clock. "Overnight" for ES is not the same as cash SPY close-to-open. Futures embed:
- Continuous price discovery offshore
- Roll and basis
- Different open auction dynamics on the cash session
Do not mix cash overnight stats with futures execution without aligning sessions.
Conditioning the premium
The unconditional overnight mean is not the whole trade. Condition on:
| Filter | Rationale |
|---|---|
| Realized vol | Premium may rise with risk; gaps also larger |
| Day of week | Monday open includes weekend news |
| Event calendar | CPI/FOMC nights change gap distribution |
| Prior day return | Continuation vs reversal overnight |
| VIX term structure | Contango vs backwardation (VIX curve) |
def conditional_overnight(on_rets: pd.Series, vix: pd.Series, thresh=20):
high = on_rets[vix.shift(1) > thresh].mean()
low = on_rets[vix.shift(1) <= thresh].mean()
return {"high_vix": high, "low_vix": low}
Risk: the left tail is the product
Overnight strategies sell gap insurance. Average day: small positive. Crash night: large negative. Metrics that matter:
- Max drawdown and gap-day contribution
- CVaR of overnight returns
- Weekend exposure (Fri close → Mon open)
Size with vol targeting on overnight volatility, not close-to-close — daytime vol can understate gap risk.
Crowding and decay
Close-to-open has been widely published. Expect:
- Compression of the mean after popularization
- Higher competition for MOC liquidity (crowding)
- Capacity limits for large AUM at the close auction
Treat it as a risk premium sleeve, not a high-Sharpe unique alpha. Combine with intraday signals that have different decay.
Key takeaways
- Equity premia often accrue overnight; open-to-close is weaker after costs
- Round-trip costs can kill a naive buy-close/sell-open strategy
- Futures and cash overnight are different products
- Condition on vol, events, and day-of-week; size for gap tails
- Treat as a premium sleeve — crowded, capacity-limited, left-tailed
