Skip to content
All library documents

Implementing Parkinson Volatility from High-Low Prices

Article Quant Q&A · Author: Porsche Tan

Summary

The document reviews a Python implementation of the Parkinson volatility estimator, which uses high and low prices rather than close-to-close returns. Its central calculation squares the log ratio of each period’s high to low, sums those values over a rolling window, scales by four times the natural logarithm of two and the window length, then takes the square root. This gives a rolling volatility estimate from intraperiod price ranges.

The accepted answer points out that the submitted implementation’s aggregation and scaling do not match the stated formula. It replaces the rolling mean and additional trading-period multiplier with a rolling sum divided by the constant and the number of observations. The response says the revised code was written quickly and should be checked, so it is guidance rather than a validated implementation. Users also need to ensure the window length and annualization convention match their intended use; high-low based estimates have assumptions and may not capture every source of market risk.

Key ideas

  • The Parkinson estimator derives volatility from squared log high-to-low price ratios.
  • Its rolling calculation sums the squared ratios and scales by four times the log of two and the observation count.
  • The reviewed code is flagged for a mismatch between its averaging and scaling and the stated formula.
  • Confirm the window and annualization convention for the intended application.

Tags

Full text
# Clarifying Parkinson Python Code


# Clarifying Parkinson Python Code












I would appreciate opinions/reviews on whether my python code to calculate Parkinson Volatility index is correct. Thank you very much!

```
def parkinson(price_data, window=WINDOW, trading_periods=N, clean=True):
    rs =  (price_data['high']/price_data['low']).apply(np.log) ** 2.0
    def f(v):
        return (1.0 / (4.0 * math.log(2.0)) * trading_periods * v.mean()) ** 0.5
    result = rs.rolling(window=window, center=False).apply(func=f)
    
    if clean:
        return result.dropna()
    else:
        return result
```

Thank you very much!

## Answer by amdopt (score 3, accepted)

https://quant.stackexchange.com/a/76180

I don't know why you are multiplying by `v.mean()` and you are missing the sum of squared differences for the rolling window. I did this quickly, off the top of my head, so you may want to double-check.

I don't see why the nested function, the use of `pandas.apply()`, or `center=False` (default pandas behavior) is necessary, so I got rid of those. I made some other adjustments, too, that were more intuitive for me.

```
def parkinson(price_data, window=WINDOW, trading_periods=N, clean=True):

    const = 4.0 * np.log(2.0)

    # sum of squared differences
    rs = (np.log(price_data['high'] /
                 price_data['low']) ** 2.0).rolling(window=window).sum()

    result = (rs / (const * trading_periods)) ** 0.5
    
    if clean:
        return result.dropna()
    else:
        return result
```

Just to be sure we are on the same page, this is the formula I'm replicating in Python here:

$${Parkinson's Vol} = \sqrt{\frac{1}{4\ln(2)N}\sum_{i=1}^{N}\ln\left(\frac{H_i}{L_i}\right)^2}$$

I hope this helps.

Shown in full with attribution under the source's licence. Licence: CC BY-SA 4.0 (Stack Exchange)

This summary was written by Stratmill's research agent from the original; it is not a copy of the source.