Skip to content
All library documents

Annualizing Historical Volatility Across Trading-Day Horizons

Article Quant Q&A · Author: flo

Summary

The document addresses why a trader’s 30-day volatility estimate from daily stock returns differs from a website’s published figure. The accepted answer says that a one-month estimate should use about 20 trading sessions, rather than 30, when annualizing with a trading year of roughly 250 or 252 sessions. It describes calculating the standard deviation of daily percentage returns over that window and scaling it by the square root of the annual trading-day count.

A second response cautions that matching a vendor’s result also depends on the underlying data and implementation. Differences can arise from end-of-day prices, corporate-action adjustments, or calculation errors, and the available excerpt does not identify the website or its exact conventions. The discussion gives a practical annualization convention, but it does not establish that every vendor uses the same window, return definition, or estimator. The supplied code and return series are part of the question rather than independently validated evidence for the quoted vendor figure.

Key ideas

  • A one-month historical volatility window is commonly represented by about 20 trading sessions.
  • Annualize daily return volatility by scaling it with the square root of the annual trading-session count.
  • Use daily percentage changes as the input series, while checking how prices were adjusted.
  • Vendor figures may differ because of data sources, corporate actions, window definitions, or implementation choices.

Tags

Full text
# Historic Volatility calculation does not fit to given figures


# Historic Volatility calculation does not fit to given figures












First, I have to say sorry - my question is very basic. I do not have a good understanding of math and statistics. I did a lot of research before posting here, but I could not come to a 100% satisfying answer to my problem. Here is my situation:

So there is this pretty neat financial website which shows me the 250 and 30 day Volatility in % of a certian stock on a certain stock exchange.

And I have this pretty neat C# code which calculates the Standard Variation for a given return array.

I also have all CLOSE prices of the last 250 trading days for this asset on that stock exchange. When I run my C# logic over all calculated returns the result matches exactly the figure I can see on that website - 40.8 % for the 250d Volatiliy.

So far so good.

But when I run the same Code handing over the returns of only the last 30 trading days, it comes up with 6.6% - instead of the figure for 30d on that website which is around 20.07%.

So I guess I am doing something wrong. I searched many websites to find the correct approach to calculate the figure correctly, but I did not manage to get a result which is close to 20.07%.

The closest approach I have is this: I am guessing the 30d figure on that website is the annualized volatility. So I thought I have to multiply my result of 6.6% with the the respective multiplier which I learned should be the Square Root of 250 / 30. The result in this case is 19.05% - which is not 20.07% obviously.

Could someone please tell me if my approach is correct or not? It could of course be that the website does not take the CLOSE prices to calculate the volatilites, that would be an explanation. I just want to know if my approach is correct.

EDIT: Code for calculation of Volatility (not written by me):

```
    public static class Volatility
{
    public static double stdDeviation;
    public static double semiDeviation;

    public static void CalcVolatility(List<float> returns, Predicate<int> filter)
    {
        double tempStandard = 0;
        double tempSemi = 0;
        int count = 0;

        double averageLogReturn = logAverage(returns, filter);

        for (int ii = 0; ii < returns.Count; ii++)
        {
            if (!filter.Invoke(ii))
                continue;

            double logReturn = Math.Log(1 + returns[ii]);
            double add = Math.Pow(logReturn - averageLogReturn, 2);

            tempStandard = tempStandard + add;
            count++;

            if (logReturn < averageLogReturn)
                tempSemi = tempSemi + add;
        }

        stdDeviation = Math.Sqrt(tempStandard/(count - 1)*count);
        semiDeviation = Math.Sqrt(tempSemi/(count - 1)*count);
    }

    private static double logAverage(List<float> returns, Predicate<int> filter)
    {
        double sum = 0;
        int count = 0;

        for (int ii = 0; ii < returns.Count; ii++)
        {
            if (!filter.Invoke(ii))
                continue;

            sum += Math.Log(1 + returns[ii]);
            count++;
        }

        return sum/count;
    }
}
```

Here is the list of returns, starting with the oldest:

```
-0.02970294,-0.03061228,0.03157898,-0.0204082,-0.05208328,-0.02197807,-0.02247189,-0.02298848,0,0.03529408,0.01477274,-0.04703247,0.04347826,0.007882848,-0.002234608,-0.03919376,0.04895104,0.00777781,-0.0154355,0.003359486,-0.03236612,0.00922724,-0.03428568,0.02958577,-0.00114941,-0.02991947,-0.007117417,0.01194742,-0.005903182,0.01781471,0.002333762,0,-0.01979048,0.00356297,-0.004733737,0.009512433,-0.01295639,-0.002386604,-0.01315794,-0.001212106,-0.01820387,0.0321384,0.03113775,0.00464577,0.004624287,-0.01726127,-0.02341918,-0.002398051,0.01322113,-0.01542113,0.03734942,-0.01858301,-0.002366904,-0.03084226,-0.02692773,-0.04905665,-0.003968203,-0.01859229,0.04194852,0.02987013,-0.001261018,0.003787905,0.04402512,-0.1638554,-0.03458212,0.04626859,0.03708991,0.01100415,-0.0122449,0.0247934,-0.001344149,-0.1184388,-0.0396946,0.02543716,0.007751931,-0.01230763,0.01713392,0.02143951,0.001499231,0.002994063,0.03432836,-0.01731605,0.005873727,0.01605836,-0.02586208,0.07669624,0.04931501,-0.03263704,0.0202429,0.002645548,-0.02506595,-0.01082546,0.02188779,0.02275772,0.003926729,-0.01434164,0.001322813,0.03698811,-0.003821683,0.003836344,-0.02929937,0.02362198,0.03076929,-0.01368164,-0.01639346,0.001282111,0.03072982,-0.004968954,0.008739113,-0.001237682,0.01239156,0.002448022,-0.006105,0.001228485,-0.007361942,-0.00247223,-0.001239141,0.003722111,-0.01606924,-0.006281401,0,-0.05183313,-0.009333372,-0.0107671,-0.01360543,-0.001379375,0.02762437,0.03494618,-0.012987,-0.02894739,-0.009485054,0.02462381,0.005340465,-0.04913678,0.03212291,-0.01894452,-0.001379375,-0.006906071,0.02503478,-0.02713702,-0.01394699,-0.01414426,0.02439019,0.02380955,0.03146375,-0.007957536,0.01069513,0.02116407,0.01295335,0.0102302,0.01012653,-0.03007518,0.01162791,0.00638569,0.001269019,0.001267486,-0.02151901,-0.03104785,0.01068093,0,-0.02113611,-0.01349526,-0.02872781,-0.02535212,0.008670582,0.007163317,-0.004267455,-0.01714281,-0.03052329,0.04647679,0.002865293,0,0.01571434,-0.02531646,0.007215,0.01575928,-0.004231341,0.01558079,-0.009762942,-0.02957742,0.08708273,0.01735649,-0.001312397,-0.01314059,0.01597873,0.009174271,0.02337663,0.0177665,0.03241898,0.01086957,0.001194728,-0.0250597,0.04406366,0.01992968,-0.04022992,0.008383268,0,0.01068884,0.003525219,0.00234196,-0.003504697,-0.01289564,-0.02969125,0.01223996,0.02055618,-0.005924165,0.01549465,-0.01877931,-0.01196178,0.01089589,0.007185679,-0.007134413,-0.001197589,-0.01678657,0.001219496,-0.02436051,-0.02996253,0.01673103,0.005063301,0,0.0201511,0.02962962,-0.02637891,0.01354684,-0.01579588,0.007407385,-0.006127445,-0.01356347,-0.01125,0.002528413,-0.01513236,-0.007682512,-0.006451607,-0.012987,0.01710528,-0.02328591,0.01456951,-0.006527409,0.01445471,0.01683939,0.001273869,-0.007633641,0.002564146,-0.01406647,0.01426716,0.007672612,-0.002538038,-0.008905889,0.005134799,0.02043427,0.01376718,0.004938282,0.002456971,0.007352993
```

## Answer by amdopt (score 1, accepted)

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

> Could someone please tell me if my approach is correct or not? It could of course be that the website does not take the CLOSE prices to calculate the volatilites, that would be an explanation. I just want to know if my approach is correct.

The correct approach is as follows: For 1 month historical volatility using a 250 (I use 252) day trading year you would not use the past 30 trading days. 30 days would correspond with a 360 or 365 day trading year. You should use 20 trading days. This is an Excel formula that I just so happen to have open on my desktop right now. Hope it helps.

```
[Std Dev of Daily Returns of the last 20 trading days]*[Square Root of 252]
=(STDEV.P(I2807:I2826))*SQRT(252)
```

To calculate HV you need daily % changes. If your source isn't using the closing price to derive their daily % change then they do not have correct HV for the security you are referencing and you will not come up with the same number.

## Answer by Adam (score 0)

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

It's quite difficult to replicate without the data and the website you mentioned.

It is likely that the 20% is annualized (since that is a rather standard way of presenting it), so your 19% isn't too far off. Some possible reasons there's a difference may be:

- Your data is using EOD close price while the website isn't

- One dataset adjusts for stock splits, shares, repos, etc while the other doesn't

- Possible error in the C code

- Possible error in the website code

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.