SASPy Sample Program (2) A Simple Application

Eunji Oh (WRDS), June 2020

Requirements:

  • Internet connection
  • Python 3.4 or higher, Jupyter Lab, SASPy(3.3.5 or higher), BeautifulSoup4, numpy
  • Subscriptions for CRSP Monthly via WRDS

Other Notes:




0. Select custom python 3 kernel

  • Required pakcages:
    • saspy 3.3.5 or higher
    • BeautifulSoup 4
    • numpy
  • Optional packages:
    • Paramiko (or replace this with any ssh client software)



1. Import packages

In [1]:
import saspy
from IPython.display import HTML

import pandas as pd

import requests
from bs4 import BeautifulSoup as bs
import re

import numpy as np

import time



2. Python: simple web scraping

2.1 Scrape FOMC meeting dates (2020s) from St.Louis Fed

In [2]:
# Download the HTML source
period = str(2020) # If you have subscription for CRSP Annual, replace 2020 with 2010
url = '''https://fraser.stlouisfed.org/title/federal-open-market-committee-meeting-minutes-transcripts-documents-677?browse=''' + period + 's'
r = requests.get(url)
In [3]:
# Find all tags containing meeting date string
soup = bs(r.text)
li_tags = soup.find_all('li')
meeting_titles = [t.find('span').string.replace('Meeting, ', '').strip() for t in li_tags if t.find('span') and 'Meeting, ' in t.find('span').string]  
In [4]:
# Parse meeting dates from the downloaded page using regex and change its format to SAS DATE9. style

def mdate(x):
    year = re.search('\s(\d{4})', x)[1]

    first_day = re.search('^([a-zA-Z]+)\s(\d+)', x)
    if first_day:
        month1 = first_day[1]
        day1 = first_day[2]
        
    else:
        month=''
        day1=''
        date1=''
    
    second_day = re.search('-(\d{1,2})', x)
    if second_day:
        month2 = month1
        day2 = second_day[1]
    else:
        second_day = re.search('-([a-zA-Z]+)\s(\d+)', x)
        if second_day:
            month2 = second_day[1]
            day2 = second_day[2]
            
        else:
            month2=''
            day2=''
    
    date1 = day1 + month1[0:3].upper() + year
    date2 = day2 + month2[0:3].upper() + year
    
    return {'year': year, 'month1':month1, 'day1': day1, 'sasdate1':np.where(day1!='', date1, ''),'month2':month2, 'day2':day2, 'sasdate2': np.where(day2 != '',date2,'')}
In [5]:
# Convert parsed meeting date list to a Pandas DataFrame
meeting_dates = pd.DataFrame([mdate(x) for x in meeting_titles])
meeting_dates.head()
Out[5]:
year month1 day1 sasdate1 month2 day2 sasdate2
0 2020 January 28 28JAN2020 January 29 29JAN2020
1 2020 March 3 3MAR2020
2 2020 March 15 15MAR2020
3 2020 March 17 17MAR2020 March 18 18MAR2020
4 2020 March 19 19MAR2020



3. SAS: Work with SASPy

3.1 Start a SAS Session

In [ ]:
# Start a SAS session and check configuration information
sas = saspy.SASsession() 
#sas

3.2 Connect to WRDS Server (SKIP if you work on WRDS cloud)

In [ ]:
PC_SAS = '''%let wrds = wrds.wharton.upenn.edu 4016;
options comamid=TCP remote=wrds;
signon username="&username" password="&pw";
'''
prompt = {'username':True, 'pw': True}

sas.submitLOG(code=PC_SAS, prompt=prompt)

3.3 Set a Library Reference

In [ ]:
# Set a library references
sas.saslib(libref='home', path='~', options='server=wrds') # Remove options if you work on WRDS cloud

3.4 Convert the dataframe to a sas dataset

In [9]:
sd = sas.df2sd(df = meeting_dates, table = 'fomc_meetings', libref='home')
print(sas.lastlog())
15                                                         The SAS System                               15:11 Tuesday, June 30, 2020

101        
102        data _null_; e = exist("home.'fomc_meetings'n");
103        v = exist("home.'fomc_meetings'n", 'VIEW');
104         if e or v then e = 1;
105        te='TABLE_EXISTS='; put te e;run;

TABLE_EXISTS= 1
NOTE: DATA statement used (Total process time):
      real time           0.00 seconds
      cpu time            0.00 seconds
      

106        
107        
108        
109        
16                                                         The SAS System                               15:11 Tuesday, June 30, 2020

110        
In [10]:
sd.columnInfo()
Out[10]:
Member Num Variable Type Len Pos
0 HOME.FOMC_MEETINGS 3 day1 Char 2 11
1 HOME.FOMC_MEETINGS 6 day2 Char 2 29
2 HOME.FOMC_MEETINGS 2 month1 Char 7 4
3 HOME.FOMC_MEETINGS 5 month2 Char 7 22
4 HOME.FOMC_MEETINGS 4 sasdate1 Char 9 13
5 HOME.FOMC_MEETINGS 7 sasdate2 Char 9 31
6 HOME.FOMC_MEETINGS 1 year Char 4 0



4. Submit a SAS job

  • You can use 'submit' method to run the code below if you work on non-Jupyter environment
In [11]:
# Read a SAS macro from local directory and rsubmit it to declare the macro on the server session
with open('EVTSTUDY.sas','r') as f:
    evtstudy = f.read()

evtstudy_macro_code = 'rsubmit;' + evtstudy + 'endrsubmit;'
sas.submitLOG(evtstudy_macro_code)

# Instead, you can upload the sas file via scp or sftp and use %include method in the SAS program
30                                                         The SAS System                               15:11 Tuesday, June 30, 2020

189        ods listing close;ods html5 (id=saspy_internal) file=_tomods1 options(bitmap_mode='inline') device=svg style=HTMLBlue;
189      ! ods graphics on / outputfmt=png;
NOTE: Writing HTML5(SASPY_INTERNAL) Body file: _TOMODS1
190        
191        rsubmit;
31                                                         The SAS System                               15:11 Tuesday, June 30, 2020

NOTE: Remote submit to WRDS commencing.
191      !         /* ***************************************************************************** */
1            /*
1  ! ***************************************************************************
1  ! ** */
2    /* ********* W R D S   R E S E A R C H   A P P L I C A T I O N S
2  ! *************** */
3    /*
3  ! ***************************************************************************
3  ! ** */
4    /* Program : EVTSTUDY.SAS
4  !       */
5    /* Summary : Provides a sample methodology for calculating Cumulative
5  !       */
6    /*           Abnormal Returns(CARs)& Buy-Hold Abnormal Returns(BHARs)
6  !       */
7    /*           with various t-statistics (CS test, Standardized CS
7  ! test&Patell Z)  */
8    /*           in an event study setting. Displays the dynamics of mean CARs
8  ! and   */
9    /*           BHARs in the event window specified by the user
9  !       */
10   /*
10 !       */
11   /* Date    : Sep 2011
11 !       */
12   /* Author  : Denys Glushkov, WRDS
12 !       */
13   /* Modified by Eunji Oh, June 2020
14   /*
14 ! ***************************************************************************
14 ! *  */
15   
16   %macro EVTSTUDY(input_data
16 ! ,crsp_type='crsp',estper_num=150,start_win=-10,end_win=10,gap_num=15,minest
16 ! _num=120);
17   
18   /* STEP 1A: Speficify the parameters necessary to run the event study such
18 ! as    */
19   /* the length of estimation period and event window, gap b/w estimation &
19 ! event  */
20   /* window, etc
20 !       */
21   %let crsp=&crsp_type; /*CRSP libary to be used (CRSPQ - quarterly,
21 ! CRSP-annual update  */
22   %let estper=&estper_num; /*Length of the estimation period in trading days
22 ! over which    */
23                    /*the risk model is estimated
23 !       */
24   
25   %let start=&start_win; /*Beginning of the event window (wtr to the event
25 ! date,e.g. -2)   */
26   %let end=&end_win;    /*End of the event window (relative to the event
26 ! date, e.g., +1)  */
27   %let gap=&gap_num;    /*Length of pre-event window,i.e., number of trading
27 ! days b/w    */
28                   /*the end of estimation period and the start of the event
28 ! window */
29   
30   %let minest=&minest_num; /*Minimum of non-missing returns required for
30 ! estimation        */
31   %let evtwin=%eval(&end-&start+1);       /*length of event window in trading
31 !  days */
32   
33   /* STEP 1B: As an example, create the input table containing Permno-event
33 ! dates  */
34   /* corresponding to the stock additions to and deletions from S&P 500 index
34 !       */
35   
36   /* input_data should have permno and edate (event date) in sas date format
36 ! only */
37   proc sql;
38    create table input
39    as select distinct permno, edate format date9.
40    from &input_data where not missing(edate);
41   quit;
42   
43   
44   /* STEP 2. Creating Trading Calendar that accounts for the presence of  */
45   /* weekends, holidays and other non-trading days in the estimation      */
46   /* and event windows                                                    */
47   data caldates;
48    merge &crsp..dsi(keep=date rename=(date=estper_beg))
49    &crsp..dsi(keep=date firstobs=&estper rename=(date=estper_end))
50    &crsp..dsi(keep=date firstobs=%eval(&estper+&gap+1)
50 ! rename=(date=evtwin_beg))
51    &crsp..dsi(keep=date firstobs=%eval(&estper+&gap-&start+1)
51 ! rename=(date=evtdate))
52    &crsp..dsi(keep=date firstobs=%eval(&estper+&gap+&evtwin)
52 ! rename=(date=evtwin_end));
53     format estper_beg estper_end evtwin_beg evtdate evtwin_end date9.;
54     label estper_beg='Start of the Estimation Window'
55         estper_end='End of the Estimation Window'
56         evtwin_beg='Start of the Event Window'
57         evtwin_end='End of the Event Window'
58         evtdate='Event Date';
59     index+1;
60     if nmiss(estper_beg,estper_end,evtwin_beg,evtwin_end,evtdate)=0;
61   run;
62   
63   /*STEP 3: If event date is a non-trading day, select the closest trading
63 ! day that*/
64   /* follows the event day
64 !       */
65   proc sql; create table temp
66    as select a.permno, b.*
67     from input a left join caldates b
68     on b.evtdate-a.edate>=0
69     group by a.edate
70     having (b.evtdate-a.edate)=min(b.evtdate-a.edate);
71   
72    /*Returns for sample securities around the event dates */
73    create table evtrets_temp
74    as select a.permno, a.date format date9., a.ret as ret1,
75              b.evtdate, b.estper_beg, b.estper_end,
76              b.evtwin_beg, b.evtwin_end
77    from &crsp..dsf a, temp b
78    where a.permno=b.permno and b.estper_beg<=a.date<=b.evtwin_end;
79   
80    /* Merge in the risk factors                                           */
81    /* User can create her own risk factors and use it instead of FF+M ones*/
82    create view evtrets1
83      as select a.*, (b.mktrf+b.rf) as mkt, b.mktrf, b.rf,b.smb, b.hml, b.umd
84      from evtrets_temp a left join
85           ff.factors_daily (keep=date mktrf smb hml umd rf) b
86      on a.date=b.date;
87   
88    /*Bring in delisting returns*/
89    create table evtrets (drop=ret1 where=(not missing(mkt)))
90      as select a.*,
91      (1+a.ret1)*sum(1,b.dlret)-1-a.mkt as exret label='Market-adjusted total
91 ! ret',
92      (1+a.ret1)*sum(1,b.dlret)-1 as ret "Ret adjusted for delisting"
93      from evtrets1 a left join &crsp..dsedelist (where=(missing(dlret)=0)) b
94      on a.permno=b.permno and a.date=b.dlstdt
95    order by a.permno,a.evtdate,a.date;
96   quit;
97   
98   /* STEP 4. Estimating Factor Exposures over the estimation period*/
99   proc printto log=junk; run;
100  
101  proc reg data=evtrets edf outest=params  noprint;
102     where estper_beg<=date<=estper_end;
103     by permno evtdate;
104     eq0: model exret=;
105     eq1: model ret=mktrf;
106     eq2: model ret=mktrf smb hml;
107     eq3: model ret=mktrf smb hml umd;
108  run;
109  proc printto;run;
110  
111  
112  /* STEP 5. Calculating Abnormal Returns for all models */
113  /* for each trading day in the event window            */
114  data abrets1/view=abrets1; merge
115    evtrets(where=(evtwin_beg<=date<=evtwin_end) in=a)
116    params (where=(_model_='eq0')
117       keep=permno evtdate _model_ _rmse_ _p_ _edf_
118       rename=(_rmse_=std0 _p_=p0 _edf_=edf0))
119    params (where=(_model_='eq1')
120       keep=permno evtdate _model_ _rmse_ intercept mktrf
121       rename=(_rmse_=std1 intercept=alpha1 mktrf=beta1))
122    params (where=(_model_='eq2')
123       keep=permno evtdate _model_ _rmse_ intercept mktrf smb hml
124       rename=(_rmse_=std2 intercept=alpha2 mktrf=beta2 smb=sminb2
124! hml=hminl2))
125    params (where=(_model_='eq3')
126       keep=permno evtdate _model_ _rmse_ intercept mktrf smb hml umd
127       rename=(_rmse_=std3 intercept=alpha3 mktrf=beta3 smb=sminb3 hml=hminl3
127!  umd=umind3));
128    by permno evtdate;
129    retain missret;
130    if first.permno then missret=missing(ret);
131    if missing(ret) then missret+1; /*count number of missing returns*/
132    var0=std0**2; var1=std1**2;var2=std2**2;var3=std3**2;
133    abret0=exret;
134    expret1=alpha1+beta1*mktrf; abret1=ret-expret1;
135    expret2=alpha2+beta2*mktrf+sminb2*smb+hminl2*hml; abret2=ret-expret2;
136    expret3=alpha3+beta3*mktrf+sminb3*smb+hminl3*hml+umind3*umd;
136! abret3=ret-expret3;
137    nobs=p0+edf0;  /*number of observations used in estimation*/
138   drop p0 edf0 estper_beg estper_end std0 std1 std2 std3 _model_ exret;
139   if a and nobs>&minest;
140  run;
141  
142  /* Transform dates to event time using CRSP Trading Calendar       */
143  /* Using the latter takes into account non-consecutive date records*/
144  proc sql; create table abrets
145    as select a.*, (b.index-c.index) as evttime
146    from abrets1 a left join caldates b
147     on a.date=b.evtdate
148    left join caldates c
149     on a.evtdate=c.evtdate
150  order by permno, evtdate, date;
151  quit;
152  
153  /* Calculating Rolling Cumulative Abnormal Returns and various stats */
154  /* Transformout= calculates cumulative product of gross returns and  */
155  /* subtracts 1 to arrive at the total net cumulative return          */
156  proc expand data=abrets out=car method=none;
157    by permno evtdate; id date;
158    convert ret=cret/transformout=(+1 cuprod -1);
159    convert mkt=cmkt/transformout=(+1 cuprod -1);
160    convert expret1 =cexpret1 /transformout=(+1 cuprod -1);
161    convert expret2 =cexpret2 /transformout=(+1 cuprod -1);
162    convert expret3 =cexpret3 /transformout=(+1 cuprod -1);
163    convert abret0=car0/transformout=(sum);
164    convert abret1=car1/transformout=(sum);
165    convert abret2=car2/transformout=(sum);
166    convert abret3=car3/transformout=(sum);
167  run;
168  
169  /* Car_Evtdate Table the cross-sectional output that contains for each
169!  */
170  /* "firm-event date":
170!  */
171  /*   1) CAR, BHAR, and SCAR (standardized CAR)
171!  */
172  /*   2) Alpha and Beta from the estimation period
172!  */
173  /*   3) Estimation period variance
173!  */
174  
175  /* Car_Evtwin Table contains Raw, Abnormal, Std. and Buy-and-Hold Abnormal
175!  */
176  /* Daily Returns "firm-date" in event time
176!  */
177  proc printto log=junk;run;
178  
179  data car_evtdate
180          (drop=evttime ret mkt smb hml umd date calpha1 calpha2 calpha3
181                cmrkt csmb chml cumd evtwin_beg evtwin_end abret0 abret1
182                abret2 abret3 sar0 sar1 sar2 sar3 missret cexpret1 cexpret2
182! cexpret3)
183       car_evtwin
184           (keep=permno evtdate evttime date ret cret abret0 abret1 abret2
184! abret3
185            sar0 sar1 sar2 sar3 bhar0 bhar1 bhar2 bhar3 car0 car1 car2 car3);
186    set car;
187    by permno evtdate date;
188    /*Standardized CARs and ARs for various models*/
189    scar0=car0/(&evtwin*var0)**0.5; scar1=car1/(&evtwin*var1)**0.5;
190    scar2=car2/(&evtwin*var2)**0.5; scar3=car3/(&evtwin*var3)**0.5;
191    sar0=abret0/sqrt(var0);sar1=abret1/sqrt(var1);
192    sar2=abret2/sqrt(var2);sar3=abret3/sqrt(var3);
193    pat_scale=(nobs-2)/(nobs-4); /*Patell Z scaling factor*/
194    /*Buy-Hold Abnormal Returns*/
195    bhar0=cret-cmkt; bhar1=cret-cexpret1;
196    bhar2=cret-cexpret2; bhar3=cret-cexpret3;
197    if last.evtdate then do; nrets=&evtwin-missret; output car_evtdate; end;
198    output car_evtwin;
199  run;
200  proc printto;run;
201  
202  /*Put Cross-sectional and aggregate results together for further analysis*/
203  data allcars; merge
204    car_evtwin
205    (rename=(bhar0=bhar0win bhar1=bhar1win bhar2=bhar2win bhar3=bhar3win
206             car0=car0win car1=car1win car2=car2win car3=car3win
206! cret=cretwin))
207    car_evtdate;
208   by permno evtdate;
209  run;
210  
211  /* STEP 6: Compute Cumulative Average Abnormal Return (CAR_MEAN) */
212  /* and Average Buy-Hold Abnormal Return (BHAR_MEAN)              */
213  /* and other stats across all distinct events                    */
214  proc means data=allcars noprint;
215    class evttime; id nobs;
216    var ret cret car0 car1 car2 car3 bhar0 bhar1 bhar2 bhar3
217    bhar0win bhar1win bhar2win bhar3win cretwin
218    car0win car1win car2win car3win
219    scar0 scar1 scar2 scar3 abret0 abret1 abret2 abret3
220    sar0 sar1 sar2 sar3 pat_scale;
221    output out=allstats
222    mean= n= t= sum=/autoname;
223  run;
224  
225  /*calculate different stats for assessing    */
226  /*statistical signficance of abnormal returns*/
227  data MA_Evtdate (keep=evttime car0_n cret_mean car0_mean car0_t scar0_t
228                   bhar0_mean pat_car0 model)
229       MM_Evtdate (keep=evttime car1_n cret_mean car1_mean car1_t scar1_t
230                   bhar1_mean pat_car1 model )
231       FF_Evtdate (keep=evttime car2_n cret_mean car2_mean car2_t scar2_t
232                   bhar2_mean pat_car2 model )
233       FFM_Evtdate (keep=evttime car3_n cret_mean car3_mean car3_t scar3_t
234                   bhar3_mean pat_car3 model )
235       MA_Evtwin  (keep=evttime cretwin_mean abret0_n ret_mean abret0_mean
236                   car0win_mean bhar0win_mean abret0_t sar0_t pat_ar0 )
237       MM_Evtwin  (keep=evttime cretwin_mean abret1_n ret_mean abret1_mean
238                   car1win_mean bhar1win_mean abret1_t sar1_t pat_ar1 )
239       FF_Evtwin  (keep=evttime cretwin_mean abret2_n ret_mean abret2_mean
240                   car2win_mean bhar2win_mean abret2_t sar2_t pat_ar2 )
241       FFM_Evtwin (keep=evttime cretwin_mean abret3_n ret_mean abret3_mean
242                   car3win_mean bhar3win_mean abret3_t sar3_t pat_ar3 );
243   set allstats;
244   by evttime;
245     if _n_=1 and missing(evttime) then do;
246     abret0_mean=.; abret1_mean=.;
247     abret2_mean=.; abret3_mean=.;
248     cretwin_mean=0; ret_mean=.;
249     bhar1win_mean=0; bhar1win_mean=0;
250     bhar2win_mean=0;bhar3win_mean=0;
251     end;
252     /*Patell Z statistics*/
253     pat_car0=scar0_mean/(sqrt(pat_scale_sum)/scar0_n);
254     pat_car1=scar1_mean/(sqrt(pat_scale_sum)/scar1_n);
255     pat_car2=scar2_mean/(sqrt(pat_scale_sum)/scar2_n);
256     pat_car3=scar3_mean/(sqrt(pat_scale_sum)/scar3_n);
257     pat_ar0=sar0_mean/(sqrt(pat_scale_sum)/sar0_n);
258     pat_ar1=sar1_mean/(sqrt(pat_scale_sum)/sar1_n);
259     pat_ar2=sar2_mean/(sqrt(pat_scale_sum)/sar2_n);
260     pat_ar3=sar3_mean/(sqrt(pat_scale_sum)/sar3_n);
261   label
262     pat_ar0=       'Patell Z for AR_MA'  pat_ar1=        'Patell Z for
262! AR_MM'
263     pat_ar2=       'Patell Z for AR_FF'  pat_ar3=        'Patell Z for
263! AR_FFM'
264     abret0_t=      'CS t-stat, AR_MA'    abret1_t=       'CS t-stat, AR_MM'
265     abret2_t=      'CS t-stat, AR_FF'    abret3_t=       'CS t-stat, AR_FFM'
266     sar0_t=        'Std CS test, AR_MA'  sar1_t=         'Std CS test,
266! AR_MM'
267     sar2_t=        'Std CS test, AR_FF'  sar3_t=         'Std CS test,
267! AR_FFM'
268     abret0_mean=   'Mean AR_MA'          abret1_mean=    'Mean AR_MM'
269     abret2_mean=   'Mean AR_FF'          abret3_mean=    'Mean AR_FFM'
270     car0_n=        'Number of events in the portfolio'
271     abret0_n=      'Number of events in the portfolio'
272     evttime=       'Event Time t'
273     cret_mean=     "Mean CTR (&start, &end)"
274     cretwin_mean=  "Mean CTR (&start,t) "
275     car0win_mean=  "Average CAR_MA (&start, t)"
276     car1win_mean=  "Average CAR_MM (&start, t)"
277     car2win_mean=  "Average CAR_FF (&start, t)"
278     car3win_mean=  "Average CAR_FFM (&start, t)"
279     bhar0win_mean= "Mean BHAR_MA (&start, t)"
280     bhar1win_mean=  "Mean BHAR_MM (&start, t)"
281     bhar2win_mean= "Mean BHAR_FF (&start, t)"
282     bhar3win_mean=  "Mean BHAR_FFM (&start, t)"
283   ;
284     format ret_mean cret_mean abret0_mean abret1_mean abret2_mean
284! abret3_mean
285            car0_mean car1_mean car2_mean car3_mean bhar0_mean bhar1_mean
286            bhar2_mean bhar3_mean cretwin_mean
287            bhar0win_mean bhar1win_mean bhar2win_mean bhar3win_mean
288            car0win_mean car1win_mean car2win_mean car3win_mean percent7.4
289            abret0_t abret1_t abret2_t abret3_t sar0_t sar1_t sar2_t sar3_t
290            pat_car0 pat_car1 pat_car2 pat_car3 pat_ar0 pat_ar1 pat_ar2
290! pat_ar3
291            car0_t car1_t car2_t car3_t scar0_t scar1_t scar2_t scar3_t
291! comma10.2;
292    if evttime=0 then do; model='Market-Adjusted'; output MA_Evtdate;
293                          model='Market Model';    output MM_Evtdate;
294                          model='FF Model';        output FF_Evtdate;
295                          model='Carhart Model';   output FFM_Evtdate;
296                   end;
297    if missing(evttime) then evttime=&start-1;
298    output MA_Evtwin; output MM_Evtwin; output FF_Evtwin; output FFM_Evtwin;
299  run;
300  
301  /* STEP 7. Putting Event Date CARs and BHARS for various risk models
301! together*/
302  data allevtdate; set
303    MA_Evtdate  (rename=(car0_mean=car_mean bhar0_mean=bhar_mean
304                  car0_n=n car0_t=car_t scar0_t=scar_t pat_car0=pat_car))
305    MM_Evtdate  (rename=(car1_mean=car_mean bhar1_mean=bhar_mean
306                  car1_n=n car1_t=car_t scar1_t=scar_t pat_car1=pat_car))
307    FF_Evtdate  (rename=(car2_mean=car_mean bhar2_mean=bhar_mean
308                  car2_n=n car2_t=car_t scar2_t=scar_t pat_car2=pat_car))
309    FFM_evtdate (rename=(car3_mean=car_mean bhar3_mean=bhar_mean
310                  car3_n=n car3_t=car_t scar3_t=scar_t pat_car3=pat_car));
311   length=&evtwin;
312   label pat_car=   'Patell Z'
313         car_mean=  "Mean CAR (&start, &end)"
314         bhar_mean= "Mean BHAR (&start, &end)"
315         car_t=     'Cross-sectional t-stat for CAR'
316         scar_t=    'Standaridized cross-sectional t-stat for CAR'
317         length=    'Length of event window in trading days';
318  run;
319  
320  /*Cross-sectional output for CARs/BHARs at the firm-event level*/
321  data car_evtdate;
322    retain permno evtdate alpha1 beta1 cret car0 bhar0 var0 car1 bhar1 var1
323         car2 bhar2 var2 car3 bhar3 var3 nrets nobs;
324    set car_evtdate;
325    label alpha1=  'Alpha (Market Model)' beta1='Beta (Market Model'
326          car0=    'CAR_MA'               car1='CAR_MM'
327          car2=    'CAR_FF'               car3='CAR_FFM'
328          bhar0=   'BHAR_MA'              bhar1='BHAR_MM'
329          bhar2=   'BHAR_FF'              bhar3='BHAR_FFM'
330          var0=    'Estimation period variance (Market-adjusted returns)'
331          var1=    'Estimation period variance (Market Model)'
332          var2=    'Estimation period variance (FF Model)'
333          var3=    'Estimation period variance (Carhart Model)'
334          cret=    'Cumulative Total Return'
335          nrets=   'Number of non-missing returns in event window'
336          nobs=    'Length of the estimation period';
337    keep permno evtdate alpha1 beta1 cret car0 bhar0 var0 car1 bhar1 var1
338         car2 bhar2 var2 car3 bhar3 var3 nrets nobs;
339    format cret alpha1 car0 bhar0 car1 bhar1 car2 bhar2 car3 bhar3 percent7.4
340           beta1 comma10.3;
341  run;
342  
343  /* As an illustration, plot Carhart CAARs and average BHARs in the event
343! window*/
344  options nodate orientation=landscape; ods pdf file="Carhart_evtret.pdf";
345  goptions device=pdfc; /* Plot Saved in Home Directory */
346  *goptions hsize=4 vsize=3;
347  axis1 label=(angle=90 "Cumulative Returns");
348  axis2 label=("Event time");
349  symbol interpol=join w=3 l=1;
350  proc gplot data =FFM_Evtwin;
351   where evttime>=&start;
352   Title "Cumulative Total Returns vs. Carhart CAARs and BHARs around the
352! event date";
353   plot (cretwin_mean car3win_mean bhar3win_mean)*evttime
354         /overlay legend vaxis=axis1 haxis=axis2;
355  run;quit; ods pdf close;
356  
357  /*house cleaning*/
358   proc sql;
359    drop table abrets, allcars, allstats, caldates, car, car_evtwin, evtrets,
359!  temp,
360               evtrets_temp,ffm_evtdate, ff_evtdate, ma_evtdate, mm_evtdate,
360! params;
361    drop view  evtrets1, abrets1; quit;
362  
363  %mend;
364  /*
364! ***************************************************************************
364! ***** */
365  /* *************  Material Copyright Wharton Research Data Services
365! ************** */
366  /* ****************************** All Rights Reserved
366! ***************************** */
367  /*
367! ***************************************************************************
367! ***** */
NOTE: Remote submit to WRDS complete.
192        
193        
194        ods html5 (id=saspy_internal) close;ods listing;
195        
32                                                         The SAS System                               15:11 Tuesday, June 30, 2020

196        
In [ ]:
%%SAS sas


rsubmit;

/* Generate Input Dataset for Event Study */

data home.fomc_meetings;
    set home.fomc_meetings; 
        beg_date = input(sasdate1, date9.);
        end_date = input(sasdate2, date9.); 
        edate = max(beg_date,end_date);
        format edate date9.;
run;
                
/* Get S&P 500, merge with FOMC meeting dates*/
proc sql;
    create table crspd500 as
    select a.permno, b.edate
      from crspm.dsp500list as a,
           home.fomc_meetings as b
    where b.beg_date >= a.start and b.end_date<= a.ending
    order by beg_date;
quit;


/* Event Study Macro is declared above */

/* Run Event Study - Output pdf (Carhart_evtret.pdf) file will be stored in your WRDS home directory*/
%EVTSTUDY(input_data=crspd500(where=(edate in ('23Mar2020'd))), crsp_type=crspm, estper_num=120, start_win=-5, end_win=5, gap_num=15, minest_num=60);

endrsubmit;

signoff;

5. Download output(non-SASdata) file via ssh

In [13]:
import paramiko
ssh_client =paramiko.SSHClient()
ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh_client.connect(hostname='wrds-cloud.wharton.upenn.edu',username='your-wrds-id',password='your-wrds-password')
In [14]:
# Download the output file from WRDS cloud server
ftp_client = ssh_client.open_sftp()

remotefile = 'Carhart_evtret.pdf' # remote file name to download from your WRDS home directory
localfile = 'Carhart_evtret_download.pdf' # local file name to store the downloaded file

ftp_client.get(remotefile, localfile)
ftp_client.close()



5. Finish the sas session

In [15]:
sas.endsas()
SAS Connection terminated. Subprocess id was 3504