GarmanKlassVolatility — Garman-Klass Volatility
An OHLC volatility estimator: the log range and the log open-to-close move combined, which is more efficient than either the close-to-close or the pure range estimator.
Signature
GarmanKlassVolatility(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 open, high, low, close. |
Formula
$$ \sigma_{GK} = \sqrt{A \cdot \frac{1}{n}\sum_i \left[\tfrac{1}{2}\ln^2!\frac{H_i}{L_i} - (2\ln 2 - 1)\ln^2!\frac{C_i}{O_i}\right]} \times 100 $$
The per-bar term can go slightly negative on a doji; the average is floored at zero before the square root.
Warmup
period bars.
Reading the value
gk.valueExample
class GkRegime(Strategy): """Trade only in the calm half of the volatility distribution.""" trade = Symbol() sizing = FixedCapital()
def execute(self): gk = GarmanKlassVolatility(20, 252, on=self.trade) sma = SMA(50, on=self.trade) if gk.value < 18 and self.trade.close > sma.value and self.trade.is_flat: self.buy(self.trade, reason=f"GK vol {gk.value:.1f}") if gk.value > 30 and self.trade.is_long: self.sell(self.trade, self.trade.position, reason="Vol regime shift")Notes
- Mark Garman and Michael Klass, Journal of Business (1980).
- Like Parkinson’s, it assumes no drift and no overnight gap.