*copyright Yufeng Han UNCC, Dashan Huang SMU, Dayong Huang UNCG, Guofu Zhou, Wash U. 02/17/2021.;
*Use this code at your risk. If you do, please cite our JFE volume paper. Thank you!;
*This code implement double sorts of two variables, report portfolio return, FF5 alpha and Q alphas; 

%macro Port55HMLNOTNYSE2020dLite(dsin, dsout, rkvar, rkvar2,dsout4);

data sicsorte1;
	set &dsin;
run;

data sicsorte2;
	set sicsorte1;
	if  &rkvar = . then delete;
	if  &rkvar2 = . then delete;
run;

proc sort data=sicsorte2;
	by yyyymm permno;
run;

*Ind TWO-way sorting;
%let grp=5;
%let grp2=5;

data nysesample;
	set sicsorte2;
run;

*Method 1, Sort into 30, 70 percentile groups;
proc univariate data=nysesample noprint;
  var &rkvar &rkvar2;
  by yyyymm;
  output out=NYSE1 pctlpts = 20 to 80 by 20  pctlpre=&rkvar &rkvar2 ;
run;

* Assign &rkvar breakpoints to Entire Sample ;
proc sql;
  create table tem2
  as select a.*, b.&rkvar.20, b.&rkvar2.20, b.&rkvar.40, b.&rkvar2.40, b.&rkvar.60, b.&rkvar2.60, b.&rkvar.80, b.&rkvar2.80 
  from sicsorte2 as a
  left join
  NYSE1 as b
  on a.yyyymm= b.yyyymm;
quit;

*Create Portfolios according to 30, 70 breakpoint.;
data rankoutB;
  set tem2;
    if &rkvar<&rkvar.20 then rk_&rkvar = 1;
    	else if &rkvar >= &rkvar.20 and &rkvar < &rkvar.40 then rk_&rkvar =2;
    	else if &rkvar >= &rkvar.40 and &rkvar < &rkvar.60 then rk_&rkvar =3;
    	else if &rkvar >= &rkvar.60 and &rkvar < &rkvar.80 then rk_&rkvar =4;
    	else if &rkvar >=  &rkvar.80 then rk_&rkvar =5;
    if &rkvar2<&rkvar2.20 then rk_&rkvar2 = 1;
    	else if &rkvar2 >= &rkvar2.20 and &rkvar2 < &rkvar2.40 then rk_&rkvar2 =2;
    	else if &rkvar2 >= &rkvar2.40 and &rkvar2 < &rkvar2.60 then rk_&rkvar2 =3;
    	else if &rkvar2 >= &rkvar2.60 and &rkvar2 < &rkvar2.80 then rk_&rkvar2 =4;
    	else if &rkvar2 >  &rkvar2.80 then rk_&rkvar2 =5;
run;

proc sort data = rankoutB out = rankoutC;
	by yyyymm rk_&rkvar rk_&rkvar2;
run;

proc means data = rankoutC noprint n ;
    by yyyymm rk_&rkvar rk_&rkvar2;
    var ret / weight=lagme ;
    output out = retdat1(drop=_type_ _freq_ ) mean= ret n = nobs1 ;	
run;

data data3;
	set retdat1;
	if rk_&rkvar=. | rk_&rkvar2=.  | yyyymm=. then delete;
run;

proc sql; 
    create table data4
    as select distinct a.yyyymm, a.rk_&rkvar, b.rk_&rkvar2 + 1 as rk_&rkvar2, a.ret- b.ret as ret
	from data3 as a, data3 as b
    where a.yyyymm=b.yyyymm and a.rk_&rkvar = b.rk_&rkvar and a.rk_&rkvar2 = b.rk_&rkvar2-&grp2+1 
    group by a.yyyymm, a.rk_&rkvar, a.rk_&rkvar2;
quit;

proc sql; 
    create table data5
    as select distinct a.yyyymm, a.rk_&rkvar+1 as rk_&rkvar, a.rk_&rkvar2, a.ret- b.ret as ret
	from data3 as a, data3 as b
    where a.yyyymm=b.yyyymm and a.rk_&rkvar-&grp+1 = b.rk_&rkvar and a.rk_&rkvar2 = b.rk_&rkvar2 
    group by a.yyyymm, a.rk_&rkvar, a.rk_&rkvar2;
quit;

proc sql; 
    create table data4b
    as select distinct a.yyyymm, a.rk_&rkvar + 1 as rk_&rkvar, b.rk_&rkvar2 as rk_&rkvar2, a.ret- b.ret as ret

	from data4 as a, data4 as b
    where a.yyyymm=b.yyyymm and b.rk_&rkvar = a.rk_&rkvar-&grp2+1 and a.rk_&rkvar2 = b.rk_&rkvar2 
    group by a.yyyymm, a.rk_&rkvar, a.rk_&rkvar2;
quit;

data data6;
	set data3 data4 data5 data4b;
run;

proc sort data = data6; by yyyymm rk_&rkvar rk_&rkvar2; run;

data data7d; 
	set data6; 
run;

*load Q factors;
data hxz;
	set eng.hxz_q_factors_monthly;
	yyyymm = year*100 + month;
	rename R_mkt = mkt2 r_me = me2 r_ia = ia2 r_roe = roe2;
run;

data hxz;
	set hxz;
	qmkt = mkt2/100;
	qme  = me2/100;
	qia = ia2/100;
	qroe = roe2/100;
run;

proc sort data = hxz; by yyyymm; run;

* load FF5 factors;
data regdata2;
	merge data7d (in = in1) eng.factors (in = in2) hxz;
	by yyyymm;
	if in1 = 1;
run;
 
proc sort data = regdata2; by rk_&rkvar rk_&rkvar2 yyyymm; run;

* compute alphas and output results;

%let xv1 = exmkt smb hml cma rmw;
%let y   = ret;
proc reg data=regdata2 outest=FB tableout noprint;
	by rk_&rkvar rk_&rkvar2 ;
	model &y = &xv1 ;
quit;
data fb2;
	set fb;
	if _type_ = 'PARMS' or _type_ = 'T';
	keep  rk_&rkvar rk_&rkvar2  _type_ intercept;
run;	

proc means data = regdata2 mean t noprint; var ret ; by rk_&rkvar rk_&rkvar2 ; output out = rep2 mean = ret t= tret; run;

data rep2; set rep2; drop  _type_ _freq_; run;

data fb2b; set fb2; if _type_ = "T"; rename intercept = t; run;
data fb2a; set fb2; if _type_ = "PARMS"; rename intercept = alpha; run;


data fb2ca;
	merge rep2 fb2a fb2b;
	by rk_&rkvar rk_&rkvar2;
	drop _type_;
	ret = ret*100;
	alpha = alpha*100;
run;


data s1;
	set fb2ca;
run;

proc sort data = s1 out = k2; by rk_&rkvar2 rk_&rkvar ; run;

proc transpose data=k2 out=wide1 prefix=a;
    by rk_&rkvar2;
    id rk_&rkvar;
    var ret ;
run;

proc transpose data=k2 out=wide2 prefix=b;
    by rk_&rkvar2;
    id rk_&rkvar;
    var tret ;
run;

proc transpose data=k2 out=wide3 prefix=c;
    by rk_&rkvar2;
    id rk_&rkvar;
    var alpha;
run;

proc transpose data=k2 out=wide4 prefix=d;
    by rk_&rkvar2;
    id rk_&rkvar;
    var t;
run;


data wide5;
    merge  wide1(drop=_name_) wide2(drop=_name_)  wide3(drop=_name_ _label_)  wide4(drop=_name_ _label_);
    by rk_&rkvar2;
run;


proc print data = wide5; format a1-a6 b1-b6 c1-c6 d1-d6 8.2; run;

*compute FF5 alphas; 
%let xv1 = qmkt qme qia qroe;
%let y   = ret;
proc reg data=regdata2 outest=FB tableout noprint;
	by rk_&rkvar rk_&rkvar2 ;
	model &y = &xv1 ;
quit;
data fb2;
	set fb;
	if _type_ = 'PARMS' or _type_ = 'T';
	keep  rk_&rkvar rk_&rkvar2  _type_ intercept;
run;	

proc means data = regdata2 mean t noprint; var ret ; by rk_&rkvar rk_&rkvar2 ; output out = rep2 mean = ret t= tret; run;

data rep2; set rep2; drop  _type_ _freq_; run;

data fb2b; set fb2; if _type_ = "T"; rename intercept = t; run;
data fb2a; set fb2; if _type_ = "PARMS"; rename intercept = alpha; run;


data fb2ca;
	merge rep2 fb2a fb2b;
	by rk_&rkvar rk_&rkvar2;
	drop _type_;
	ret = ret*100;
	alpha = alpha*100;
run;

data s1;
	set fb2ca;
run;

proc sort data = s1 out = k2; by rk_&rkvar2 rk_&rkvar ; run;

proc transpose data=k2 out=wide1 prefix=a;
    by rk_&rkvar2;
    id rk_&rkvar;
    var ret ;
run;

proc transpose data=k2 out=wide2 prefix=b;
    by rk_&rkvar2;
    id rk_&rkvar;
    var tret ;
run;

proc transpose data=k2 out=wide3 prefix=c;
    by rk_&rkvar2;
    id rk_&rkvar;
    var alpha;
run;

proc transpose data=k2 out=wide4 prefix=d;
    by rk_&rkvar2;
    id rk_&rkvar;
    var t;
run;


data wide5;
    merge  wide1(drop=_name_) wide2(drop=_name_)  wide3(drop=_name_ _label_)  wide4(drop=_name_ _label_);
    by rk_&rkvar2;
run;

 
proc print data = wide5; format a1-a6 b1-b6 c1-c6 d1-d6 8.2; run;

%mend;
