Announcement

Collapse
No announcement yet.
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • Calculate the standard deviation of the firm's daily stock return over the past three months

    Hello everyone,

    I have daily panel data and I want to calculate the standard deviation of the firm's daily stock return over the past three months. Could anyone help me to find an appropriate code to calculate annualized 3-month rolling sample standard deviation and assuming the standard deviation is centered on zero, instead of centered around mean value given a time period.

    Sample of my dataset is attached :



    Kind Regards
    Obada






    Attached Files

  • #2
    I want to calculate the standard deviation of the firm's daily stock return over the past three months.
    Code:
    rangestat (sd) ret, by(permno) interval(date -89 0)
    Note: to use this code you must install -rangestat-, written by Robert Picard, Roberto Ferrer, and Nick Cox, available from SSC.

    I have interpreted "past three months" to mean a 90 day period that includes the current date, hence -interval(date -89 0)-. If that is not what you meant by "past three months," modify the -interval- option accordingly.

    Could anyone help me to find an appropriate code to calculate annualized 3-month rolling sample standard deviation and assuming the standard deviation is centered on zero, instead of centered around mean value given a time period.
    I do not understand this.

    In the future, when showing data examples, please use the -dataex- command to do so. If you are running version 15.1 or a fully updated version 14.2, -dataex- is already part of your official Stata installation. If not, run -ssc install dataex- to get it. Either way, run -help dataex- to read the simple instructions for using it. -dataex- will save you time; it is easier and quicker than typing out tables. It includes complete information about aspects of the data that are often critical to answering your question but cannot be seen from tabular displays or screenshots. It also makes it possible for those who want to help you to create a faithful representation of your example to try out their code, which in turn makes it more likely that their answer will actually work in your data.



    When asking for help with code, always show example data. When showing example data, always use -dataex-.

    Comment


    • #3
      In the following example, I shall use asrol, which can be downloaded from SSC. You can read further resources related to asrol here on my website.

      In the following example, I assume that the rolling window is based on a fixed length of three months. Later on, I also show the code where the rolling window is based on the past 90 days.

      Use example dataset from my site. The data set has three variables, (1) symbols: a string variable to identify each firm (2) close - a numeric variable that records companies' share prices (3) date - a numeric variable that tracks daily dates

      Code:
      use http://fintechprofessor.com/stocks.dta
      
      * List the first 10 observations
           +-----------------------------+
           | symbol        date    close |
           |-----------------------------|
        1. |   AABS   07jan2013    103.5 |
        2. |   AABS   14jan2013      103 |
        3. |   AABS   16jan2013      103 |
        4. |   AABS   17jan2013   105.75 |
        5. |   AABS   25feb2013     96.7 |
           |-----------------------------|
        6. |   AABS   27feb2013      101 |
        7. |   AABS   05mar2013      106 |
        8. |   AABS   19mar2013      101 |
        9. |   AABS   28mar2013      101 |
       10. |   AABS   10apr2013      101 |
           +-----------------------------+
      
      * Create a month identifier
      gen mofd = mofd(date)
      format mofd %tm
      
      * generate returns
      bys symbol (date): gen returns = ln(close / close[_n-1])
      
      * Install asrol
      ssc install asrol
      
      * Find 3 months rolling window sd with asrol
      bys symbol: asrol returns, window(mofd 3) stat(sd)
      
      * Convert to annual volatility
      gen annual_sd = sd3_returns*sqrt(12)/sqrt(3)
      
      list  in 1/10
           +-------------------------------------------------------------------------+
           | symbol        date    close     mofd     returns   sd3_ret~s   annual~d |
           |-------------------------------------------------------------------------|
        1. |   AABS   07jan2013    103.5   2013m1           .     .016786    .033572 |
        2. |   AABS   14jan2013      103   2013m1   -.0048426     .016786    .033572 |
        3. |   AABS   16jan2013      103   2013m1           0     .016786    .033572 |
        4. |   AABS   17jan2013   105.75   2013m1    .0263488     .016786    .033572 |
        5. |   AABS   25feb2013     96.7   2013m2   -.0894644   .05122231   .1024446 |
           |-------------------------------------------------------------------------|
        6. |   AABS   27feb2013      101   2013m2    .0435071   .05122231   .1024446 |
        7. |   AABS   05mar2013      106   2013m3    .0483186   .04661255   .0932251 |
        8. |   AABS   19mar2013      101   2013m3   -.0483186   .04661255   .0932251 |
        9. |   AABS   28mar2013      101   2013m3           0   .04661255   .0932251 |
       10. |   AABS   10apr2013      101   2013m4           0   .05331813   .1066363 |
           +-------------------------------------------------------------------------+
      Method 2: Using trading days

      Code:
      bys symbol: asrol returns, window(date 90) stat(sd) gen(sd_90days)
      
      * Convert to annual volatility
      gen annual_sd2 = sd_90days *sqrt(252)/sqrt(90)
      
      
      list  in 1/10
      
           +------------------------------------------------------------------------------------------------+
           | symbol        date    close     mofd     returns   sd3_ret~s   annual~d   sd_90days   annual~2 |
           |------------------------------------------------------------------------------------------------|
        1. |   AABS   07jan2013    103.5   2013m1           .     .016786    .033572           .          . |
        2. |   AABS   14jan2013      103   2013m1   -.0048426     .016786    .033572           .          . |
        3. |   AABS   16jan2013      103   2013m1           0     .016786    .033572   .00342425   .0057299 |
        4. |   AABS   17jan2013   105.75   2013m1    .0263488     .016786    .033572     .016786   .0280883 |
        5. |   AABS   25feb2013     96.7   2013m2   -.0894644   .05122231   .1024446    .0502229    .084039 |
           |------------------------------------------------------------------------------------------------|
        6. |   AABS   27feb2013      101   2013m2    .0435071   .05122231   .1024446   .05122231   .0857113 |
        7. |   AABS   05mar2013      106   2013m3    .0483186   .04661255   .0932251   .05070348   .0848431 |
        8. |   AABS   19mar2013      101   2013m3   -.0483186   .04661255   .0932251   .05032963   .0842176 |
        9. |   AABS   28mar2013      101   2013m3           0   .04661255   .0932251   .04661255   .0779977 |
       10. |   AABS   10apr2013      101   2013m4           0   .05331813   .1066363   .04361395   .0729801 |
           +------------------------------------------------------------------------------------------------+
      The case of centering on zero

      Code:
      gen return2 = returns * returns
      bys symbol: asrol return2 , window(date 90) stat(mean) gen(sd0_90days)
      gen annual_sd0 = sqrt( sd0_90days ) *sqrt(252)/sqrt(90)
      
      . list symbol date returns annual_sd0 in 1/10
      
           +-------------------------------------------+
           | symbol        date     returns   annual~0 |
           |-------------------------------------------|
        1. |   AABS   07jan2013           .          . |
        2. |   AABS   14jan2013   -.0048426   .0081033 |
        3. |   AABS   16jan2013           0   .0057299 |
        4. |   AABS   17jan2013    .0263488   .0258817 |
        5. |   AABS   25feb2013   -.0894644   .0781353 |
           |-------------------------------------------|
        6. |   AABS   27feb2013    .0435071    .077098 |
        7. |   AABS   05mar2013    .0483186   .0777363 |
        8. |   AABS   19mar2013   -.0483186   .0781891 |
        9. |   AABS   28mar2013           0   .0731392 |
       10. |   AABS   10apr2013           0   .0689563 |
           +-------------------------------------------+
      Last edited by Attaullah Shah; 11 Feb 2019, 07:02.
      Regards
      --------------------------------------------------
      Attaullah Shah, PhD.
      Associate Professor of Finance, Institute of Management Sciences Peshawar, Pakistan
      www.FinTechProfessor.com
      If you use MS Word, do check my asdoc program that easily sends Stata output to MS Word

      Comment


      • #4
        I have a question concerning post #2 as I have a similar issue. I used it for 21 days (1 month of trading days). From that I want to annualize it. However, I don't know exactly what the rangestat command is giving you. Is this

        a) the daily standard deviation calculated over the interval, or

        b) the standard deviation over the interval?

        I mean, I could use Excel to check it but someone may know the solution and may want to share it. I have not really found the answer in the help rangestat.

        Comment


        • #5
          Michael Craig In turn I really don't follow what distinction you are making or alluding to. rangestat (SSC) does not pay attention to whether data are daily or anything else specifically; it just works on what it is instructed to work on.

          You don't give a data example or exact code you used (FAQ Advice #12 remains as valid as ever), so answers are restricted to explanations of principle or other examples invented for the purpose.

          Whether trading days do or do not complicate your problem I can't understand either.

          Here's an example you can run:

          Code:
          . clear
          
          . set obs 100
          number of observations (_N) was 0, now 100
          
          . gen y = _n
          
          . gen t = y  
          
          . rangestat (count) y (sd) y, int(t -20 0)
          
          .
          . list in 1/30
          
               +-------------------------------+
               |  y    t   y_count        y_sd |
               |-------------------------------|
            1. |  1    1         1           . |
            2. |  2    2         2   .70710678 |
            3. |  3    3         3           1 |
            4. |  4    4         4   1.2909944 |
            5. |  5    5         5   1.5811388 |
               |-------------------------------|
            6. |  6    6         6   1.8708287 |
            7. |  7    7         7   2.1602469 |
            8. |  8    8         8   2.4494897 |
            9. |  9    9         9   2.7386128 |
           10. | 10   10        10   3.0276504 |
               |-------------------------------|
           11. | 11   11        11   3.3166248 |
           12. | 12   12        12   3.6055513 |
           13. | 13   13        13   3.8944405 |
           14. | 14   14        14   4.1833001 |
           15. | 15   15        15    4.472136 |
               |-------------------------------|
           16. | 16   16        16   4.7609523 |
           17. | 17   17        17   5.0497525 |
           18. | 18   18        18   5.3385391 |
           19. | 19   19        19   5.6273143 |
           20. | 20   20        20   5.9160798 |
               |-------------------------------|
           21. | 21   21        21   6.2048368 |
           22. | 22   22        21   6.2048368 |
           23. | 23   23        21   6.2048368 |
           24. | 24   24        21   6.2048368 |
           25. | 25   25        21   6.2048368 |
               |-------------------------------|
           26. | 26   26        21   6.2048368 |
           27. | 27   27        21   6.2048368 |
           28. | 28   28        21   6.2048368 |
           29. | 29   29        21   6.2048368 |
           30. | 30   30        21   6.2048368 |
               +-------------------------------+
          
          .
          . su t in 1/21
          
              Variable |        Obs        Mean    Std. Dev.       Min        Max
          -------------+---------------------------------------------------------
                     t |         21          11    6.204837          1         21
          Key points that may illuminate your puzzlement:

          1. If given a window, rangestat uses whatever is available in that window. So in this example, windows potentially of length 21 only contain 21 observations from observation 21 on. Unlike some other commands, rangestat lets (indeed makes) users decide what they want to do with incomplete windows. Further, the interval() option could catch more observations than are implied by its length, as nothing in rangestat assumes that distinct values of the variable within that interval occur at most once. For example, rangestat neither assumes xtset or tsset beforehand nor makes use of either if either has been declared.

          2. The standard deviation recipe used is precisely that of summarize, which is documented. Sample size MINUS 1 is used, not sample size.

          3. You refer to annualized rates but I fear that rangestat may disappoint you there. In no sense is it geared to financial data; it's a general command and does not offer hooks for specialised financial calculations. I don't work in that area at all; Robert Picard who is first author and prime mover of rangestat, I think knows more about it than I do, but I think he would affirm that we don't explicitly offer hooks for particular kinds of data. However, what is important is that rangestat can be extended by writing your own Mata functions, as the help explains at length.

          I will refer you also to asrol (SSC), which in stark contrast is written with specific financial calculations in mind. I don't advise on its use, not least because its author Attaullah Shah watches the forum for mentions and is always willing to help.

          Comment


          • #6
            Thanks for the helpful explanation.

            I was just wondering if the code in #2
            rangestat (sd) ret, by(permno) interval(date -89 0) is calculating a daily standard deviation or a standard deviation over 90 days. For example, if it calculates daily and I need 90 days, I need to take sqrt(90) times daily std. I think it calculates 90day std but I am not totally sure, therefore my question. There is no actually code from my side required, as the interpretation of #2 gives me everything I need.

            Comment


            • #7
              Sorry, but you seem to be asking the same question, and I don't have a different answer. You make a verbal distinction

              daily standard deviation

              or

              a standard deviation over 90 days

              but I fail to understand what you're getting at.

              Also, I have explained, or at least implied, that multiplication by sqrt(90) is not an option that rangestat offers, but it is easy enough to apply outside rangestat, or (according to taste and expertise) write your own function for use with rangestat.

              I've already explained about incomplete windows in #5.

              My claiming ignorance of specialist calculations for finance is not false modesty, but genuine.

              There's a key principle behind #5. Don't wonder what code does: read the code itself (in the case of rangestat nothing is hidden) and/or experiment with simple examples where you can check independently what is happening, as I checked with summarize what the SD was.

              Comment

              Working...
              X