In Stata
permno
is the company identifierpermno month
, I want price end of last monthtsset permno date
gen m= mofd(date)
format m %tm
* price end of each month
bys permno m: gen prc_end= prc[_N]
* price end of the prior month
gen n=m-1
format n %tm
bys permno m: gen prc_endpm= prc_end if n==m[_n-1]
* no results
Current Data:
permno date prc m prc_end n
10026 24-Jan-19 145.8000031 2019m1 154.35 2018m12
10026 25-Jan-19 144.5500031 2019m1 154.35 2018m12
10026 28-Jan-19 140 2019m1 154.35 2018m12
10026 29-Jan-19 156.8200073 2019m1 154.35 2018m12
10026 30-Jan-19 150.5 2019m1 154.35 2018m12
10026 31-Jan-19 154.3500061 2019m1 154.35 2018m12
10026 01-Feb-19 154.8000031 2019m2 155.28 2019m1
10026 04-Feb-19 158.4400024 2019m2 155.28 2019m1
10026 05-Feb-19 158.2599945 2019m2 155.28 2019m1
10026 06-Feb-19 158.2400055 2019m2 155.28 2019m1
10026 07-Feb-19 156.4100037 2019m2 155.28 2019m1
To make things clearer, consider a silly example dataset.
clear
set obs 6
gen permno = 1
gen date = mdy(1 + (_n > 3), real(word("1 15 31 1 15 28", _n)), 2022)
format date %td
gen m = mofd(date)
format m %tm
gen n = m - 1
format n %tm
gen price = _n
list, sepby(permno m)
+-----------------------------------------------+
| permno date m n price |
|-----------------------------------------------|
1. | 1 01jan2022 2022m1 2021m12 1 |
2. | 1 15jan2022 2022m1 2021m12 2 |
3. | 1 31jan2022 2022m1 2021m12 3 |
|-----------------------------------------------|
4. | 1 01feb2022 2022m2 2022m1 4 |
5. | 1 15feb2022 2022m2 2022m1 5 |
6. | 1 28feb2022 2022m2 2022m1 6 |
+-----------------------------------------------+
Now
bys permno m: gen prc_end= price[_N]
will probably work, but this would be safer:
bys permno m (date): gen prc_end= price[_N]
Things go wrong when you go
bys permno m: gen prc_endpm= prc_end if n==m[_n-1]
The effect of the by:
is to confine calculations to blocks with the same permno
and monthly date. [_n-1]
here is legal but it refers to the previous observation in the same block of observations (usefully if there is one; if there isn't the code is still legal).
You want [_n-1]
to refer to the previous month (and the same permno
) but that is not what your syntax means. Also, the example shows that, although your syntax is legal, there are no observations that satisfy your if
condition, as m
and n
are never equal within the same block of observations.
What you want can be done with by:
but you need to look across months.
This should do it:
bysort permno (m date) : gen previous = price[_n-1] if m[_n-1] == m -1
bysort permno m (date) : replace previous = previous[1]
list, sepby(permno m)
+----------------------------------------------------------+
| permno date m n price previous |
|----------------------------------------------------------|
1. | 1 01jan2022 2022m1 2021m12 1 . |
2. | 1 15jan2022 2022m1 2021m12 2 . |
3. | 1 31jan2022 2022m1 2021m12 3 . |
|----------------------------------------------------------|
4. | 1 01feb2022 2022m2 2022m1 4 3 |
5. | 1 15feb2022 2022m2 2022m1 5 3 |
6. | 1 28feb2022 2022m2 2022m1 6 3 |
+----------------------------------------------------------+