Announcement

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

  • calculating Buy Hold Returns using moving 12 months

    Hello everyone,
    I am posting regarding how to calculate Buy and Hold returns using monthly returns.
    My data consists of the monthly returns for various firms as downloaded from CRSP and looks like the following: (FYI columns ret1, prod & BHAR all calculated by me as explained below):
    firm_id date ret month ret1 prod BHAR
    10001 11/30/2015 -0.00907 1 0.99093 -0.00911 -1.00911
    10001 12/31/2015 -0.13215 2 0.867849 -0.14174 -1.14174
    10001 01/29/2016 0.116779 3 1.116778 0.110448 -0.88955
    10001 02/29/2016 -0.05529 4 0.944712 -0.05688 -1.05688
    10001 03/31/2016 -0.00636 5 0.993639 -0.00638 -1.00638
    10001 04/29/2016 -0.0557 6 0.944302 -0.05731 -1.05731
    10001 05/31/2016 -0.02192 7 0.978082 -0.02216 -1.02216
    10001 06/30/2016 -0.02101 8 0.978992 -0.02123 -1.02123
    10001 07/29/2016 0.026466 9 1.026466 0.026122 -0.97388
    10001 08/31/2016 0.03662 10 1.03662 0.035965 -0.96403
    10001 09/30/2016 0.04212 11 1.04212 0.041257 -0.95874
    10001 10/31/2016 0.619948 12 1.619948 0.482394 -0.51761
    10001 11/30/2016 0.012146 13 1.012146 0.012073 -0.98793
    10001 12/30/2016 0.01 14 1.01 0.00995 -0.99005
    10002 01/31/1986 .c 1 0 -1
    10002 02/28/1986 0.139785 2 1.139785 0.13084 -0.86916
    10002 03/31/1986 0.070755 3 1.070755 0.068364 -0.93164
    10002 04/30/1986 0.052863 4 1.052863 0.051514 -0.94849
    10002 05/30/1986 -0.02092 5 0.97908 -0.02114 -1.02114
    10002 06/30/1986 -0.13248 6 0.867521 -0.14212 -1.14212
    10002 07/31/1986 0.049261 7 1.049261 0.048086 -0.95191
    10002 08/29/1986 0 8 1 0 -1
    10002 09/30/1986 0.070423 9 1.070423 0.068054 -0.93195
    10002 10/31/1986 -0.0614 10 0.938597 -0.06337 -1.06337
    10002 11/28/1986 0 11 1 0 -1
    10002 12/31/1986 -0.07477 12 0.925234 -0.07771 -1.07771
    10002 01/30/1987 0.09596 13 1.09596 0.09163 -0.90837
    10002 02/27/1987 -0.01382 14 0.986175 -0.01392 -1.01392

    My first question is: How can I calculate the 12 month buy and hold returns (BHAR) for given month t?
    where BHAR=[ ((1+ return of month 1) * (1+ return of month 2)*….*(1+return of month12)) - 1]
    e.g.: Firm 1's BHAR for purchase in March 2015 =[((1+return of March 2015)*(1+return of April 2015)*(1+return of May 2015)* ...*(1+return of Feb 2016)) - 1]
    (FYI using Stata /SE v 14.1)

    In addition, in a previous post, I found the following code:
    Code:
    gen ret = 1+return
    bysort firmid year : gen prod = sum(ln(ret))
    by firmid year : replace prod = exp(prod[_N])
    gen buy_hold_ret= prod-1
    However, this calculates based on the calendar year taking the sum of Jan to Dec returns. I want to calculate 1 year returns using any month of the year.
    I tried amending the above code using forval to calculate the 12 months difference between the dates but the resulting BHAR is incorrect.
    my amended code is:

    Code:
    gen ret1=1+ret
    
    bysort permno month: gen prod=sum(ln(ret1)) 
    forvalues i = 1/`=_N' {
    count if dum==1 & 
    permno==permno[`i'] & ///
    inrange(month[`i']- month, 0, 12)
    by permno month: replace prod=exp(r(N)) in `i'
    }
    /
    gen BHAR=prod-1
    As a result, my second question is how can I amend this code so that prod=exp of the 12 months following each focal month t?
    As I am still relatively new to usingforval, I'd really appreciate any advice on what I am applying incorrectly and please let me know if you need any additional information!

    Thank you!

  • #2
    Note that the FAQ requests data examples generated by dataex.

    What you want is to calculate a measure for each observation based on a 12 month data window. This is something that can be done with rangestat (from SSC). To install it, type in Stata's Command window
    Code:
    ssc install rangestat
    The following example shows how to calculate the measure for a single observation using standard Stata commands. I chose observation 14 because the results will be based on a full 12 month window of data. The lret1_count variable will contain the number of non-missing values used to calculate lret1_sum. It's up to you to decide what to do when you do not have a full window.
    Code:
    * Example generated by -dataex-. To install: ssc install dataex
    clear
    input int firm_id str10 date float ret byte month float(ret1 prod bhar)
    10001 "11/30/2015" -.00907  1   .99093 -.00911 -1.00911
    10001 "12/31/2015" -.13215  2  .867849 -.14174 -1.14174
    10001 "01/29/2016" .116779  3 1.116778 .110448  -.88955
    10001 "02/29/2016" -.05529  4  .944712 -.05688 -1.05688
    10001 "03/31/2016" -.00636  5  .993639 -.00638 -1.00638
    10001 "04/29/2016"  -.0557  6  .944302 -.05731 -1.05731
    10001 "05/31/2016" -.02192  7  .978082 -.02216 -1.02216
    10001 "06/30/2016" -.02101  8  .978992 -.02123 -1.02123
    10001 "07/29/2016" .026466  9 1.026466 .026122  -.97388
    10001 "08/31/2016"  .03662 10  1.03662 .035965  -.96403
    10001 "09/30/2016"  .04212 11  1.04212 .041257  -.95874
    10001 "10/31/2016" .619948 12 1.619948 .482394  -.51761
    10001 "11/30/2016" .012146 13 1.012146 .012073  -.98793
    10001 "12/30/2016"     .01 14     1.01  .00995  -.99005
    10002 "01/31/1986"      .c  1        .       0       -1
    10002 "02/28/1986" .139785  2 1.139785  .13084  -.86916
    10002 "03/31/1986" .070755  3 1.070755 .068364  -.93164
    10002 "04/30/1986" .052863  4 1.052863 .051514  -.94849
    10002 "05/30/1986" -.02092  5   .97908 -.02114 -1.02114
    10002 "06/30/1986" -.13248  6  .867521 -.14212 -1.14212
    10002 "07/31/1986" .049261  7 1.049261 .048086  -.95191
    10002 "08/29/1986"       0  8        1       0       -1
    10002 "09/30/1986" .070423  9 1.070423 .068054  -.93195
    10002 "10/31/1986"  -.0614 10  .938597 -.06337 -1.06337
    10002 "11/28/1986"       0 11        1       0       -1
    10002 "12/31/1986" -.07477 12  .925234 -.07771 -1.07771
    10002 "01/30/1987"  .09596 13  1.09596  .09163  -.90837
    10002 "02/27/1987" -.01382 14  .986175 -.01392 -1.01392
    end
    
    * convert to monthly dates, see -help datetime- for more info
    gen mdate = mofd(daily(date,"MDY"))
    format %tm mdate
    
    * first, figure out how to calculate measure for one observation
    * see -help inrange()- and -help subscripting-
    * ...try for observation 14
    gen double lret1 = ln(1+ret)
    sum lret1 if firm_id == firm_id[14] ///
        & inrange(mdate, mdate[14]-11, mdate[14])
    dis exp(r(sum)) - 1
    
    * now redo for all observations using rangestat (from SSC)
    rangestat (sum) lret1 (count) lret1, interval(mdate -11 0) by(firm_id)
    gen buy_hold_ret= exp(lret1_sum) - 1
    
    * confirm that we get the same results as above
    list firm_id date mdate ret mdate-buy_hold_ret in 14
    and the results
    Code:
    . sum lret1 if firm_id == firm_id[14] ///
    >         & inrange(mdate, mdate[14]-11, mdate[14])
    
        Variable |        Obs        Mean    Std. Dev.       Min        Max
    -------------+---------------------------------------------------------
           lret1 |         12     .046187    .1448288  -.0573114   .4823941
    
    . dis exp(r(sum)) - 1
    .7406239
    
    . 
    . * now redo for all observations using rangestat (from SSC)
    . rangestat (sum) lret1 (count) lret1, interval(mdate -11 0) by(firm_id)
    
    . gen buy_hold_ret= exp(lret1_sum) - 1
    
    . 
    . * confirm that we get the same results as above
    . list firm_id date mdate ret mdate-buy_hold_ret in 14
    
         +----------------------------------------------------------------------------------------------+
         | firm_id         date     mdate   ret     mdate       lret1   lret1_sum   lret1_~t   buy_ho~t |
         |----------------------------------------------------------------------------------------------|
     14. |   10001   12/30/2016   2016m12   .01   2016m12   .00995033   .55424361         12   .7406239 |
         +----------------------------------------------------------------------------------------------+

    Comment


    • #3
      worked perfectly and will make sure to use dataex going forward! Thank you very very much for your answer as well as authoring rangestat !!!

      Comment


      • #4
        Originally posted by Robert Picard View Post
        Note that the FAQ requests data examples generated by dataex.

        What you want is to calculate a measure for each observation based on a 12 month data window. This is something that can be done with rangestat (from SSC). To install it, type in Stata's Command window
        Code:
        ssc install rangestat
        The following example shows how to calculate the measure for a single observation using standard Stata commands. I chose observation 14 because the results will be based on a full 12 month window of data. The lret1_count variable will contain the number of non-missing values used to calculate lret1_sum. It's up to you to decide what to do when you do not have a full window.
        Code:
        * Example generated by -dataex-. To install: ssc install dataex
        clear
        input int firm_id str10 date float ret byte month float(ret1 prod bhar)
        10001 "11/30/2015" -.00907 1 .99093 -.00911 -1.00911
        10001 "12/31/2015" -.13215 2 .867849 -.14174 -1.14174
        10001 "01/29/2016" .116779 3 1.116778 .110448 -.88955
        10001 "02/29/2016" -.05529 4 .944712 -.05688 -1.05688
        10001 "03/31/2016" -.00636 5 .993639 -.00638 -1.00638
        10001 "04/29/2016" -.0557 6 .944302 -.05731 -1.05731
        10001 "05/31/2016" -.02192 7 .978082 -.02216 -1.02216
        10001 "06/30/2016" -.02101 8 .978992 -.02123 -1.02123
        10001 "07/29/2016" .026466 9 1.026466 .026122 -.97388
        10001 "08/31/2016" .03662 10 1.03662 .035965 -.96403
        10001 "09/30/2016" .04212 11 1.04212 .041257 -.95874
        10001 "10/31/2016" .619948 12 1.619948 .482394 -.51761
        10001 "11/30/2016" .012146 13 1.012146 .012073 -.98793
        10001 "12/30/2016" .01 14 1.01 .00995 -.99005
        10002 "01/31/1986" .c 1 . 0 -1
        10002 "02/28/1986" .139785 2 1.139785 .13084 -.86916
        10002 "03/31/1986" .070755 3 1.070755 .068364 -.93164
        10002 "04/30/1986" .052863 4 1.052863 .051514 -.94849
        10002 "05/30/1986" -.02092 5 .97908 -.02114 -1.02114
        10002 "06/30/1986" -.13248 6 .867521 -.14212 -1.14212
        10002 "07/31/1986" .049261 7 1.049261 .048086 -.95191
        10002 "08/29/1986" 0 8 1 0 -1
        10002 "09/30/1986" .070423 9 1.070423 .068054 -.93195
        10002 "10/31/1986" -.0614 10 .938597 -.06337 -1.06337
        10002 "11/28/1986" 0 11 1 0 -1
        10002 "12/31/1986" -.07477 12 .925234 -.07771 -1.07771
        10002 "01/30/1987" .09596 13 1.09596 .09163 -.90837
        10002 "02/27/1987" -.01382 14 .986175 -.01392 -1.01392
        end
        
        * convert to monthly dates, see -help datetime- for more info
        gen mdate = mofd(daily(date,"MDY"))
        format %tm mdate
        
        * first, figure out how to calculate measure for one observation
        * see -help inrange()- and -help subscripting-
        * ...try for observation 14
        gen double lret1 = ln(1+ret)
        sum lret1 if firm_id == firm_id[14] ///
        & inrange(mdate, mdate[14]-11, mdate[14])
        dis exp(r(sum)) - 1
        
        * now redo for all observations using rangestat (from SSC)
        rangestat (sum) lret1 (count) lret1, interval(mdate -11 0) by(firm_id)
        gen buy_hold_ret= exp(lret1_sum) - 1
        
        * confirm that we get the same results as above
        list firm_id date mdate ret mdate-buy_hold_ret in 14
        and the results
        Code:
        . sum lret1 if firm_id == firm_id[14] ///
        > & inrange(mdate, mdate[14]-11, mdate[14])
        
        Variable | Obs Mean Std. Dev. Min Max
        -------------+---------------------------------------------------------
        lret1 | 12 .046187 .1448288 -.0573114 .4823941
        
        . dis exp(r(sum)) - 1
        .7406239
        
        .
        . * now redo for all observations using rangestat (from SSC)
        . rangestat (sum) lret1 (count) lret1, interval(mdate -11 0) by(firm_id)
        
        . gen buy_hold_ret= exp(lret1_sum) - 1
        
        .
        . * confirm that we get the same results as above
        . list firm_id date mdate ret mdate-buy_hold_ret in 14
        
        +----------------------------------------------------------------------------------------------+
        | firm_id date mdate ret mdate lret1 lret1_sum lret1_~t buy_ho~t |
        |----------------------------------------------------------------------------------------------|
        14. | 10001 12/30/2016 2016m12 .01 2016m12 .00995033 .55424361 12 .7406239 |
        +----------------------------------------------------------------------------------------------+

        Hi Robert, thanks for sharing the codes.

        Can I further ask if I wanna the buy_hold_ret on previous year, how could I modify the codes?

        Comment


        • #5
          Hello,

          How did you get the month data? the 1 2 3 4 5....14
          Did you use Stata to generate it or I can download from CRSP?
          Thank you.

          Comment


          • #6
            Hello,

            How did you get the month data? the 1 2 3 4 5....14
            Did you use Stata to generate it or I can download from CRSP?
            Thank you.

            Comment


            • #7
              Hyejin, Attaullah Shah has written a number of commands specifically for this. Take a look particularly at asrol, asgen, and ascol (all available on SSC.) (Try ssc install asrol, or findit asrol).

              Comment


              • #8
                David Benson Thanks for the reference.
                The month variable can be generated with mofd function
                Code:
                * Create a monthly date in Stata format
                gen mofd = mofd(date)
                
                * Format the data as monthly data
                format mofd %tm
                
                label var mofd "Monthly date"
                Further note: There are two widely used methods for calculating cumulative returns.

                1. If returns were calcualted using the simple percentage change ie.
                Code:
                simple_ri = (Price[i] - Price[i-1] ) /  Price[i-1]  --- (Eq. 1)
                Then the cumulatve returns would be obtained with
                Code:
                bys firm_id: asrol simple_ri, stat(product) window(mdate 12) add(1)
                option add(1) adds 1 to returns before finding the product and then subtracts it back at the end.


                2. If the returns were calculated using the log method, i.e
                Code:
                  
                 log_ri = ln( Price[i]  /  Price[i-1])  --- (Eq. 2)

                then the asrol command for cumulative returns would be:
                Code:
                bys firm_id: asrol log_ri , stat(sum) window(mdate 12)



                Regards
                --------------------------------------------------
                Attaullah Shah, PhD.
                Professor of Finance, Institute of Management Sciences Peshawar, Pakistan
                FinTechProfessor.com
                https://asdocx.com
                Check out my asdoc program, which sends outputs to MS Word.
                For more flexibility, consider using asdocx which can send Stata outputs to MS Word, Excel, LaTeX, or HTML.

                Comment


                • #9
                  Thanks Attaullah Shah for sharing the code! May I ask what if the time variable is with gaps? For example, the mdate is as follows:
                  Code:
                  mdate
                  2010m1
                  2010m2
                  2010m3
                  2010m5
                  2010m6
                  2010m8
                  2010m10
                  2010m11
                  2010m12
                  Question: If the focal month is 2010m8, would -window(mdate -3 -1) stat(mean)- calculate the mean value of [2010m7, 2010m6, and 2010m5] or the mean of [2010m6, 2010m5, and 2010m3]

                  Originally posted by Attaullah Shah View Post
                  David Benson Thanks for the reference.
                  The month variable can be generated with mofd function
                  Code:
                  * Create a monthly date in Stata format
                  gen mofd = mofd(date)
                  
                  * Format the data as monthly data
                  format mofd %tm
                  
                  label var mofd "Monthly date"
                  Further note: There are two widely used methods for calculating cumulative returns.

                  1. If returns were calcualted using the simple percentage change ie.
                  Code:
                  simple_ri = (Price[i] - Price[i-1] ) / Price[i-1] --- (Eq. 1)
                  Then the cumulatve returns would be obtained with
                  Code:
                  bys firm_id: asrol simple_ri, stat(product) window(mdate 12) add(1)
                  option add(1) adds 1 to returns before finding the product and then subtracts it back at the end.


                  2. If the returns were calculated using the log method, i.e
                  Code:
                  log_ri = ln( Price[i] / Price[i-1]) --- (Eq. 2)

                  then the asrol command for cumulative returns would be:
                  Code:
                  bys firm_id: asrol log_ri , stat(sum) window(mdate 12)


                  Comment


                  • #10
                    If time variable has gaps, the calculated statistics are based on the available observation within the range. For example, if you use window length of 2, just one observation is available for 2010m5 because 2010m4 is missing in your sample.
                    Regards
                    --------------------------------------------------
                    Attaullah Shah, PhD.
                    Professor of Finance, Institute of Management Sciences Peshawar, Pakistan
                    FinTechProfessor.com
                    https://asdocx.com
                    Check out my asdoc program, which sends outputs to MS Word.
                    For more flexibility, consider using asdocx which can send Stata outputs to MS Word, Excel, LaTeX, or HTML.

                    Comment

                    Working...
                    X