A simple intraday volatility measure​
​by Robert Rimmer
This notebook explores the utility of a volatility measure which is simply the natural logarithm of a stock or index’s high/low price each day. This appears to be a coherent measure of volatility for trading within the day. It excludes price changes that occur overnight, but shocks in foreign markets usually travel in a wave around the world so that intraday changes are picked up in each country on the day following the shock if it occurs when markets are closed. The rationale that this should be a coherent measure comes from a paper by Thomas Mikosch, http://web.math.ku.dk/~mikosch/Preprint/Increment/BEJ255.pdf, which shows that the limiting distribution of the difference between a maximum and a minimum point in a sample block from of a heavy tailed random walk is a Fréchet distribution. For market prices which arise from increments of log returns, this would represent Log[high price] minus Log[low price] during a trading time of a regular market day. Despite the fact that market returns have significant sequential dependence, this measure of volatility, Log[high/low], from daily prices is well fit by a MaxStableDistribution[] in Mathematica, also known as the generalized extreme value distribution.

Data for the Rest of the Notebook

In[]:=
spx0=FinancialData["SP500","OHLCV",{1970},Method->"Legacy"];​​spx={DateObject[#1,"Day"],#2}&@@@spx0;
Selected periods.
covid=Select[spx,#[[1]]>DateObject[{2020,1,1},"Day"]&];​​crash08=Select[spx,DateObject[{2007,9,1},"Day"]<#[[1]]<DateObject[{2014,1,1},"Day"]&];​​crash00=Select[spx,DateObject[{2000,1,1},"Day"]<#[[1]]<DateObject[{2008,1,1},"Day"]&];​​crash87=Select[spx,DateObject[{1987,1,1},"Day"]<#[[1]]<DateObject[{1990,1,1},"Day"]&];​​crash74=Select[spx,DateObject[{1970,1,1},"Day"]<#[[1]]<DateObject[{1980,1,1},"Day"]&];​​

COVID Period

The current period shows a crash caused by lock downs to curtail the pandemic and the economic consequences. The graphs show that the point of maximum volatility occurs with the market bottom. There is concern that we are currently entering a bear market. So far there is no sign that the current decline has reached a bottom coinciding with a very sharp spike in volatility followed by declining volatility. The red line on the volatility graph represents the median volatility for the graph.
In[]:=
period=covid;​​median=Median[Log[#2[[2]]/#2[[3]]]&@@@period];​​max=Max[Log[#2[[2]]/#2[[3]]]&@@@period];​​GraphicsColumn[{DateListLogPlot[{#1,#2[[4]]}&@@@period,Joined->False,GridLines->Automatic,ImageSize->Large,PlotLabel->"S&P 500 Index"],​​DateListPlot[{{#1,Log[#2[[2]]/#2[[3]]]}&@@@period},Joined->False,Filling->Axis,FillingStyleDirective[Opacity[0.4],Thick],GridLines{Automatic,{Sequence@@Table[i,{i,0,Ceiling[max,0.01],0.01}],{median,Directive[Darker[Red],Thick]}}},PlotRange->All,ImageSize->Large,PlotLabel->"Volatility"]}]
Out[]=
Here is some analysis of the volatility measure for the above period. There is strong serial dependence in the data as shown by the autocorrelation function.
In[]:=
vol=Log[#2[[2]]/#2[[3]]]&@@@covid;​​ListPlot[CorrelationFunction[vol,{50}],Filling->0,PlotRangeAll,PlotLabel->"Autocorrelation Function Volatility"]
Out[]=
Despite the serial dependence the data are well fit by a Fréchet type of extreme value distribution.
In[]:=
edf=EmpiricalDistribution[vol];​​gev=EstimatedDistribution[vol,MaxStableDistribution[μ,σ,ξ]]
Out[]=
MaxStableDistribution[0.00891461,0.00529365,0.337855]
In[]:=
LogLogPlot[{1-CDF[edf,x],1-CDF[gev,x]},{x,0.001,Max[vol]},PlotRangeAll,GridLines->Automatic,PerformanceGoal"Speed",PlotLabel"GEV Tail Fit"]
Out[]=
In[]:=
HTgev=DistributionFitTest[vol,gev,"HypothesisTestData"];​​HTgev["TestDataTable",All]
Out[]=
Statistic
P-Value
Anderson-Darling
0.443232
0.804961
Cramér-von Mises
0.0457885
0.901311
Kolmogorov-Smirnov
0.0225483
0.912595
Kuiper
0.0399769
0.777387
Pearson
2
χ
19.0631
0.794084
Watson
2
U
0.043167
0.788322
The power tail exponent is close to 3.0 which is typical for the S&P 500 log return tail behavior.
In[]:=
1/gev[[3]]
Out[]=
2.95985
In[]:=
Median[vol]​​Median[gev]
Out[]=
0.0111896
Out[]=
0.01098
This compares the estimated and empirical density curves.
In[]:=
skd=SmoothKernelDistribution[vol];​​Plot[{PDF[skd,x],PDF[gev,x]},{x,Min[vol],Max[vol]},PlotLegends->{"Empirical Density","GEV Fit Density"}]
Out[]=
0.02
0.04
0.06
0.08
0
20
40
60
Empirical Density
GEV Fit Density

2008 Market Crash

For this market crash the peak volatility occurred at a local minimum that preceded the slightly later final market bottom.
Out[]=

2000 Market Crash

This market crash had three local minima and the peak volatility was nearest the second. The market recovery gained momentum as volatility decreased.

1987 Market Crash

Here there was one very extreme volatility spike on October 19. The bottom was tested again a few days later.

1974 Market Crash

Here again, the market bottom coincided with a peak volatility spike. The graph also shows an earlier market decline in 1970 with the bottom occurring near the peak volatility.