{adamcoding}
Part III
13
Chapter 13

Breakout and Volatility

Volatility is predictable; direction is not

This is the most useful asymmetry available to a systematic trader, and it is underused by retail.

Volatility clusters. Large moves follow large moves, quiet follows quiet. This is one of the most robust empirical facts in finance - it's the observation that motivated ARCH and GARCH models and won Engle a Nobel prize. Volatility is meaningfully forecastable at horizons from days to months.

Returns are not. The autocorrelation of returns is near zero at most horizons, and the effects described in the preceding two chapters are small enough to require hundreds of trades to detect.

So build strategies whose edge depends on the forecastable quantity. Volatility targeting, regime filtering, and options positions all exploit predictable volatility. A strategy that requires you to forecast direction is fighting for the small residual.

Measuring volatility properly

Close-to-close standard deviation discards the intraday range, which contains real information. Better estimators exist, and using one is free accuracy:

python
import numpy as np
import pandas as pd


def yang_zhang_volatility(df: pd.DataFrame, window: int = 20,
                          periods_per_year: int = 252) -> pd.Series:
    """
    Yang-Zhang (2000) volatility estimator.

    Handles both overnight gaps and intraday drift, and is substantially
    more efficient than close-to-close for the same window length --
    meaning you get a comparable-quality estimate from less data, which
    matters when volatility is changing.

    Expects columns: open, high, low, close.
    """
    o, h, l, c = df["open"], df["high"], df["low"], df["close"]

    log_ho = np.log(h / o)
    log_lo = np.log(l / o)
    log_co = np.log(c / o)
    log_oc = np.log(o / c.shift(1))       # overnight gap
    log_cc = np.log(c / c.shift(1))

    # Overnight variance
    sigma_o_sq = log_oc.rolling(window).var(ddof=1)
    # Open-to-close variance
    sigma_c_sq = log_co.rolling(window).var(ddof=1)
    # Rogers-Satchell: drift-independent intraday variance
    rs = log_ho * (log_ho - log_co) + log_lo * (log_lo - log_co)
    sigma_rs_sq = rs.rolling(window).mean()

    k = 0.34 / (1.34 + (window + 1) / (window - 1))
    variance = sigma_o_sq + k * sigma_c_sq + (1 - k) * sigma_rs_sq
    return np.sqrt(variance * periods_per_year)

Alternatives worth knowing: Parkinson (high-low only, ignores gaps), Garman-Klass (adds open and close, assumes no drift and no gaps), Rogers-Satchell (drift-independent). Yang-Zhang is the most general of the standard set. All of them assume continuous trading and will underestimate volatility on instruments with large gaps.

Breakouts

A breakout strategy enters when price exits a range - the Donchian channel construction, and the core of the original Turtle system.

Mechanically this is a trend-following expression, and everything in Chapter 11 applies. Two things distinguish it:

It targets volatility expansion specifically. Ranges compress, then expand. The entry is timed to the expansion.

False breakouts are the dominant cost. Price exits the range, triggers entries, and immediately reverses. This is not a flaw to be filtered out - it is the premium paid for the convexity, exactly as with whipsaw in Chapter 11.

The temptation is to add confirmation filters - require volume, require a close beyond the level, require a retest. Almost all of these are overfitting. They improve in-sample results because they remove trades and hindsight identifies which trades to remove. Chapter 8's rule applies with full force: a filter needs a stated mechanism before testing, not after.

The one filter with a defensible mechanism is volatility normalisation - defining the breakout threshold in ATR units rather than fixed price units, so the strategy behaves consistently across regimes. That's not a filter so much as correct scaling.

Trading volatility itself

The volatility risk premium is one of the better-documented effects in the literature: implied volatility exceeds subsequent realised volatility on average across most markets and most periods. Selling options is, in expectation, profitable.

The mechanism is straightforward and is a risk premium rather than an inefficiency: investors want crash insurance, insurance sellers demand compensation, and the compensation is the spread between implied and realised.

The payoff profile is the most extreme negative skew available to a retail trader. Small consistent gains, occasional catastrophic losses.

The canonical illustration is the termination of the XIV exchange-traded note on 5 February 2018. XIV was short VIX futures - a direct expression of the volatility risk premium - and had performed superbly for years. A single-day spike in VIX futures caused it to lose the overwhelming majority of its value in hours and triggered its acceleration clause. Holders who understood the strategy and its history were still wiped out, because the strategy's risk was never in the historical record. It was in the tail.

The lesson generalises beyond volatility: for a strategy with negative skew, the absence of a catastrophic loss in your backtest is not evidence that one cannot occur. It is usually evidence that your sample was too short.

How it kills you

  • Filter overfitting on breakout confirmation.
  • Regime dependence. Breakout systems have long unprofitable stretches in range-bound markets.
  • Underestimating tails in short-volatility positions. Your backtest almost certainly does not contain the worst possible day.
  • Gap risk. Volatility estimators assuming continuous trading understate risk in instruments that gap.
  • Leverage on short-vol positions, which converts a survivable loss into termination.