VolatilityCloseToClose — Close-to-Close Volatility
The plain close-to-close estimator with a zero-mean assumption: the root mean square of log returns, annualised. This is the baseline every other estimator in the family is judged against, and it is the only one that sees overnight gaps.
Signature
VolatilityCloseToClose(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, OHLCV field, or indicator | No | Source. Defaults to the trade symbol’s close. |
Formula
$$ \sigma = \sqrt{A \cdot \frac{1}{n}\sum_i \ln^2!\left(\frac{C_i}{C_{i-1}}\right)} \times 100 $$
Warmup
period + 1 bars.
Reading the value
ctc.valueExample
class VolCompare(Strategy): """Gap risk shows up as close-to-close volatility above the range estimator.""" trade = Symbol() sizing = FixedCapital()
def execute(self): ctc = VolatilityCloseToClose(20, 252, on=self.trade) pv = ParkinsonVolatility(20, 252, on=self.trade) if ctc.value < pv.value * 1.2 and self.trade.is_flat: self.buy(self.trade, reason="No unusual gap risk") if ctc.value > pv.value * 2 and self.trade.is_long: self.sell(self.trade, self.trade.position, reason="Gap risk")Notes
- Zero-mean, not de-meaned. It squares raw log returns rather than deviations from their
average, which is the estimator most volatility literature means by “close-to-close”.
HistoricalVolatilityuses the sample standard deviation instead; on a strongly trending window the two differ visibly. - Proven by an assert-via-trade run on SPY daily (matched a strategy-side log-return reference to 0.01 on every bar; zero alarm trades).