Skip to content
Open RaamTrade

ParkinsonVolatility — Parkinson Volatility

A volatility estimator built from the high-low range rather than closes. Because the range uses more of each bar’s information, it is roughly five times more efficient than the close-to-close estimator — the same accuracy from a fifth of the data.

Signature

ParkinsonVolatility(period, annualization, on=<source>)
Argument Type Required Notes
period int Param or literal Yes Window. Default 20, bounds 1–400.
annualization int Param or literal Yes Bars per year. 252 daily. Bounds 1–100000.
on= symbol No Source symbol. Defaults to the trade symbol. Reads high and low.

Formula

$$ \sigma_P = \sqrt{\frac{A}{4\ln 2}\cdot\frac{1}{n}\sum_i \ln^2!\left(\frac{H_i}{L_i}\right)} \times 100 $$

Warmup

period bars; partial average during the lead-in.

Reading the value

pv.value
pv.value > hv.value

Example

class RangeVsCloseVol(Strategy):
"""Compare range volatility against close-to-close: a gap between them is trend."""
trade = Symbol()
sizing = FixedCapital()
def execute(self):
pv = ParkinsonVolatility(20, 252, on=self.trade)
hv = HistoricalVolatility(20, 252, on=self.trade)
sma = SMA(50, on=self.trade)
if pv.value < hv.value and self.trade.close > sma.value and self.trade.is_flat:
self.buy(self.trade, reason="Trending, not just noisy")
if pv.value > hv.value * 1.5 and self.trade.is_long:
self.sell(self.trade, self.trade.position, reason="Range churn")

Notes

  • Michael Parkinson, Journal of Business (1980).
  • Assumes no drift and no gaps. It cannot see overnight moves at all, so it understates volatility on gappy instruments — which is exactly why comparing it to the close-to-close estimator is informative.
  • Proven by an assert-via-trade run on SPY daily (matched a strategy-side log-range reference to 0.01 on every bar; zero alarm trades).