I use Yhang Zhang measure for intraday volatility for timeseries with a rolling 5 or 10 day window. I wrote a C++ and vba implementation which I'm happy to share if you wish. Takes olhc data and gives an 'estimate' of the volatility.
For intraday trading (gamma hedging), I found it is a fairly good estimator of the days range.
But I would caution on whether it's a predictor of vol. Day to day intraday vol correlation tends to be small in my opinion.
I've added the code on request. It's probably not 100% robust, and there's probably some conditions on which it produces odd numbers or plain crashes. No implied guarantees
/**
Calculate the yzvol from the intraday data using a given window size
Note that this window will make the final array (size - window) in length
so the first 'window' dates in the dt_ array are to be skipped
@open - open prices
@high - high prices
@low - low prices
@close - close prices
@window - window size to do a rolling apply over
*/
std::vector<float> calculate_yzvol(
const std::vector<float>& open,
const std::vector<float>& high,
const std::vector<float>& low,
const std::vector<float>& close,
const size_t window) {
std::vector<float> yzvol;
const size_t element_num = open.size();
if (element_num - 1 < window) {
BOOST_LOG_TRIVIAL(warning) << "Number of daily prices " << element_num << " from DB is smaller than window size" << window;
return yzvol;
}
std::vector<float> log_ho(element_num);
std::vector<float> log_lo(element_num);
std::vector<float> log_co(element_num);
std::vector<float> log_oc_sq(element_num);
std::vector<float> log_cc_sq(element_num - 1);
std::vector<float> rs(element_num);
std::transform(open.begin(), open.end(), high.begin(),std::back_inserter<std::vector<float>>(log_ho),[](auto open, auto high) {
return ::log(high / dailyopen);
});
for (size_t i = 0; i < element_num; i++) {
const float dailyopen = static_cast<float>(1.0 / open[i]);
log_ho[i] = log(high[i] * dailyopen);
log_lo[i] = log(low[i] * dailyopen);
log_co[i] = log(close[i] * dailyopen);
float oc = log(open[i] / close[i]);
log_oc_sq[i] = boost::math::pow<2>(oc);
rs[i] = log_ho[i] * (log_ho[i] - log_co[i]) + log_lo[i] * (log_lo[i] - log_co[i]);
}
for (size_t i = 1; i < element_num; i++) {
const float cc = log(close[i] / close[i - 1]);
log_cc_sq[i - 1] = boost::math::pow<2>(cc);
}
// Vol sum function
auto vol_sum = [](auto begin, auto end, auto window) {
const float window_factor = static_cast<float>(1.0 / (window - 1.0));
float sum = 0.0f;
for (auto i = begin; i != end; i++) {
sum += *i;
}
return sum * window_factor;
};
typedef std::vector<float> vf;
const vf close_vol = rolling_window<vf, vf>(log_cc_sq, window, vol_sum);
const vf open_vol = rolling_window<vf, vf>(log_oc_sq, window, vol_sum);
const vf window_rs_vol = rolling_window<vf, vf>(rs, window, vol_sum);
// Note that this window will make the final array (size - window) in length
boost::range::for_each(close_vol | boost::adaptors::indexed(0),[&](auto i) {
const float result = ::sqrt(open_vol[i.index() + 1] + 0.16433 * close_vol[i.index()] + 0.835667 * window_rs_vol[i.index() + 1]);
yzvol.emplace_back(result);
});
return yzvol;
}