* a) CAR1 (3-day window);
proc means data=sample noprint;
*define the even window and check that the start date is not far from report date;
where -1<=td_count<=1 and intck('day',rdq,date)<=5;
by permno rdq;
var ret;
output out=CAR1 (rename=(_freq_=daysCAR1)) sum=CAR1;
run;
* b) CAR2 (between consequent quarterly earnings announcement dates);
proc means data=sample noprint;
where 3<=td_count and date<=leadrdq1;
by permno rdq;
var ret;
output out=CAR2 (rename=(_freq_=daysCAR2)) sum=CAR2;
run;
I am trying to calculate returns around earnings announcement dates. The code above calculates summed returns. Does anybody know how to calculate compounded returns?
Thanks do you think my code is correct. I am trying to calculate compounded returns between earnings announcement dates. I am just curious how the code treats the 0 returns. These are not missing values.
proc univariate data=have2 noprint;
where 3<=td_count and date<=leadrdq1;
by permno rdq;
var _ret_plus1;
output out=need2 n=n geomean=gm_ret_plus1;
run;
data Ret2;
set need2;
compound_ret=gm_ret_plus1**n-1;
run;
It's late so my brain isn't working at the moment but I think there's a trick of some sort using either geometric means or log() of a value.
It's late so my brain isn't working at the moment but I think there's a trick of some sort using either geometric means or log() of a value.
So rdq is the announcement date right? And td_count represents the days until/since the announcement date?
So what does your desired output data set look like?
Yes rdq is the announcement date. For the first types of returns CAR1 I am trying to calculate compounded returns around the announcement date (1 day before and 1 day after). -1<=td_count<=1
For the second types of returns CAR2 I am trying to calculate returns around announcements dates 3 days after the announcement until the following announcement. (3<=td_count and date<=leadrdq1).
Check function FINANCE() ,maybe you could find answer in it.
Since proc univariate can produce a geometric mean, it can help generate a compound return:
data have2;
set have;
_ret_plus1=ret+1;
run;
proc univariate data=have2 noprint;
where -1<=td_count<=1 and intck('day',rdq,date)<=5;
by permno rdq;
var _ret_plus1;
output out=need n=n geomean=gm_ret_plus1;
run;
data want;
set need;
compound_ret=gm_ret_plus1**n-1;
run;
Thank you for the proposed solution. This is excellent. Do you know why there is a column called number of non-missing values. Why is it set to 3? Is it from the univarariate proc?
You need to know the number of non-missing values of _RET_PLUS1 because the geometric mean of _RET_PLUS1 is the constant value that would be required on each day to get to the compound return of the actual varying values of RET. So you need to know how many days were used to get the geometric mean, which you see used in may DATA WANT step.
Now perhaps you always know the number of days satisfying your WHERE filter, but my solution adapts to instances of missing records within the date ranges.
Thanks do you think my code is correct. I am trying to calculate compounded returns between earnings announcement dates. I am just curious how the code treats the 0 returns. These are not missing values.
proc univariate data=have2 noprint;
where 3<=td_count and date<=leadrdq1;
by permno rdq;
var _ret_plus1;
output out=need2 n=n geomean=gm_ret_plus1;
run;
data Ret2;
set need2;
compound_ret=gm_ret_plus1**n-1;
run;
You have asked a good question, which you can answer by looking at some data with zero returns. It's your turn now, to not just use the code I suggested, but to understand it through testing.
SAS Innovate 2025 is scheduled for May 6-9 in Orlando, FL. Sign up to be first to learn about the agenda and registration!
Learn how use the CAT functions in SAS to join values from multiple variables into a single value.
Find more tutorials on the SAS Users YouTube channel.
Ready to level-up your skills? Choose your own adventure.