Announcement

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

  • 5*5*5 triple sorting (dependent sorting) based on 3 variables to generate 125 portfolios


    Basically, what I want to do is follow Daniel et al( 1997), to do a 5*5 * triple sort (dependent sorting) in CRSP common stock universe. I want to place stocks into a 3-dimensional characteristics space. I want to use a 5*5*5 sorting procedure to classify every potential stock position into quintiles according to three characteristics : market capitalization (ME), book-to-market ratio (BM) and past stock return momentum (Mom).

    yrm: date variable, e.g. 1998m1,1998m2...
    exchcd: exchange code, = 1 if the stock is listed on NYSE (New York Stock Exchange)

    Step 1: to achieve the first sorting, i.e. sort all stocks (NYSE listed and Non-NYSE listed) based on the NYSE market equity breakpoints;

    My codes are as follows:
    forvalues i = 20(20)80{
    qui bysort yrm: egen ME_Brkp`i' = pctile(ME) if exchcd == 1, p(`i')

    }
    // so obviously, for many non-NYSE listed stocks, has the missing values for all ME breakpoints
    //need to assgin these NYSE based breakpoints to those non-NYSE ones too
    forvalues i = 20(20)80{
    qui by yrm (permno), sort: replace ME_Brkp`i' = ME_Brkp`i'[_n-1] if ME_Brkp`i' >= .
    }
    if ME_Brkp20 !=. & ME_Brkp40 !=. & ME_Brkp60 !=. & ME_Brkp80 !=. {
    qui {
    g ME_rank = 1 if ME <= ME_Brkp20 // Smallest Stocks
    replace ME_rank = 2 if ME > ME_Brkp20 & ME <= ME_Brkp40
    replace ME_rank = 3 if ME > ME_Brkp40 & ME <= ME_Brkp60
    replace ME_rank = 4 if ME > ME_Brkp60 & ME <= ME_Brkp80
    replace ME_rank = 5 if ME > ME_Brkp80 & ME!=. //Big stocks
    }
    }

    Step 2: Each quintile portfolio is further subdivided into book-to-market quintiles

    forval r = 1(1)5{
    forvalues i = 20(20)80 {
    qui bysort yrm ME_rank: egen BM_p`i'_`r' = pctile(cond(ME_rank==`r',BM,.)), p(`i')

    }
    }
    g BM_rank = .

    forval r=1(1)5{
    qui{
    replace BM_rank = 1 if BM<=BM_p20_`r' & ME_rank== `r'
    replace BM_rank = 2 if BM>BM_p20_`r' & BM<=BM_p40_`r' & ME_rank== `r'
    replace BM_rank = 3 if BM>BM_p40_`r' & BM<=BM_p60_`r' & ME_rank== `r'
    replace BM_rank = 4 if BM>BM_p60_`r' & BM<=BM_p80_`r' & ME_rank== `r'
    replace BM_rank = 5 if BM>BM_p80_`r' & ME_rank== `r' & BM!=.
    }
    }

    Step 3: each of the resulting 25 fractile portfolios are further subdivided into quintiles based on the 12-month past returns of stocks
    forval mer = 1(1)5{
    forval bmr = 1(1)5{
    forvalues i = 20(20)80 {
    qui bysort yrm ME_rank BM_rank: egen Mom_p`i'_`mer'_`bmr' = pctile(cond(ME_rank==`mer',BM_rank==`bmr',Mom,.)), p(`i')

    }
    }
    }


    g Mom_rank =.
    forval mer=1(1)5{
    forval bmr=1(1)5{
    qui{
    replace Mom_rank = 1 if Mom<=Mom_p20_`mer'_`bmr' & ME_rank== `mer' & BM_rank== `bmr'
    replace Mom_rank = 2 if Mom>Mom_p20_`mer'_`bmr' & Mom<=Mom_p40_`mer'_`bmr' & ME_rank== `mer' & BM_rank== `bmr'
    replace Mom_rank = 3 if Mom>Mom_p40_`mer'_`bmr' & Mom<=Mom_p60_`mer'_`bmr' & ME_rank== `mer' & BM_rank== `bmr'
    replace Mom_rank = 4 if Mom>Mom_p60_`mer'_`bmr' & Mom<=Mom_p80_`mer'_`bmr' & ME_rank== `mer' & BM_rank== `bmr'
    replace Mom_rank = 5 if Mom>Mom_p80_`mer'_`bmr' & ME_rank== `mer' & BM_rank== `bmr' & Mom!=.
    }
    }
    }


    Can you identify if there is something wrong with the above codes?
    Since when I tab the resulting variables:
    tab ME_rank
    tab BM_rank
    tab Mom_rank

    I got very confusing and suspicious results for the rank based on Mom (Momentum, the past 12 month return):
    tab Mom_rank

    Mom_rank | Freq. Percent Cum.
    ------------+-----------------------------------
    1 | 1,912,688 93.12 93.12
    5 | 141,391 6.88 100.00
    ------------+-----------------------------------
    Total | 2,054,079 100.00

    some observations should have Mom_rank 2,3, or 4 values. Why does Mom_rank only take two values: 1 and 5? And over 90% of them hold value 1?




  • #2
    Cross-posted (and easier to follow) at http://stackoverflow.com/questions/2...enerate-125-po

    Comment


    • #3
      I changed my codes to the following, but those codes still don't work

      //1. ME, quintile portfolios are formed based on NYSE size quintile breakpoints

      forvalues i = 20(20)80{
      qui bysort yrm: egen ME_Brkp`i' = pctile(ME) if exchcd == 1, p(`i')

      }

      // so obviously, for many non-NYSE listed stocks, has the missing values for all ME breakpoints
      //need to assgin these NYSE based breakpoints to those non-NYSE ones too

      assert ME_Brkp20 ==. if exchcd != 1
      tabmiss ME_Brk*
      forvalues i = 20(20)80{
      qui by yrm (permno), sort: replace ME_Brkp`i' = ME_Brkp`i'[_n-1] if ME_Brkp`i' >= .
      }

      tabmiss ME_Brk*


      qui {
      g ME_rank = 1 if ME <= ME_Brkp20 // Smallest Stocks
      replace ME_rank = 2 if ME > ME_Brkp20 & ME <= ME_Brkp40
      replace ME_rank = 3 if ME > ME_Brkp40 & ME <= ME_Brkp60
      replace ME_rank = 4 if ME > ME_Brkp60 & ME <= ME_Brkp80
      replace ME_rank = 5 if ME > ME_Brkp80 & ME!=. //Big stocks
      }

      //2. Each quintile portfolio is further subdivided into book-to-market quintiles,
      // based on industry-adjusted book-to-market ratio

      bysort yrm ME_rank: egen BM_rank = xtile(BM), p(20(20)80)

      // 3. each of the resulting 25 fractile portfolios are further subdivided into quintiles based on the 12-month past returns of stocks

      bysort yrm ME_rank BM_rank: egen Mom_rank = xtile(Mom), p(20(20)80)

      Comment


      • #4
        I got the following error message from the last line of codes:

        too many values r(134);

        Comment


        • #5
          Though I am late to the party, but it seems that correction will do some good to others who are interested. There are several issues with your code. I shall highlight just one aspect as an example.
          // so obviously, for many non-NYSE listed stocks, has the missing values for all ME breakpoints
          //need to assgin these NYSE based breakpoints to those non-NYSE ones too
          forvalues i = 20(20)80{
          qui by yrm (permno), sort: replace ME_Brkp`i' = ME_Brkp`i'[_n-1] if ME_Brkp`i' >= .
          }
          Since you use NYSE breakpoints and apply those break points to other stocks, the above code incorrectly stretches ranks of NYSE stocks to non-NYSE stocks, as there seems no criteria of assigning ranks. The code just fills empty spaces with n-1 observation, which might be any value of any stock. Therefore, I would suggest the following approach.
          Code:
          gen PF=.
                  qui sum yrm
                  loc lower=r(min)
                  loc upper=r(max)
                  gen PF = .
                  forv i = `lower' / `upper' {
                      _pctile ME if exchcd == 1 , nq(11)
                      mat q = (r(r1), r(r2), r(r3), r(r4), r(r5), r(r6), r(r7), r(r8), r(r9), r(r10) )
                      replace PF= ///
                      cond(ME <= q[1, 1]  , .1 , ///
                      cond(ME <= q[1, 2]  , .2 , ///
                      cond(ME <= q[1, 3]  , .3 , ///
                      cond(ME <= q[1, 4]  , .4 , ///
                      cond(ME <= q[1, 5]  , .5 , ///
                      cond(ME <= q[1, 6]  , .6 , ///
                      cond(ME <= q[1, 7]  , .7 , ///
                      cond(ME <= q[1, 8]  , .8 , ///
                      cond(ME <= q[1, 9]  , .9 , 1 ))))))))) if yrm==`i' & ME!=.
                      
                      }
          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


          • #6
            I assume the triple sort can now be done with much less effort due to the astile command developed by Attaullah Shah (ssc install astile)

            astile sort1 =market_capitalization, nq(5) qc (exchcd == 1) by(month_id) //exchcd == 1 refers to stocks traded on NYSE
            bys month_id sort1: astile sort2 = book-to-market, nq(5)
            bys month_id sort1 sort2: astile sort3 = momentum, nq(5)

            Comment


            • #7
              Attaullah Shah Phil Maier can you please confirm if indeed the astile command computes Dependent or Independent) sorting? Thank you.
              A follow up question will be how to calculate the alternative sorting procedure. Thank you again

              Comment

              Working...
              X