ods html close;
%let stocks =mmm aa axp t bac ba cat cvx csco ko dd xom ge hpq hd intc ibm jnj jpm mcd mrk msft pfe pg trv utx vz wmt dis;
libname dow30 "C:\temp\9.3\dow30";
proc datasets lib=work nolist kill;
quit;
/*Download stocks and prices*/
%get_stocks(&stocks,01JAN1998,30JUL2012,keepPrice=1);
/*output prices and returns to permanent location*/
data dow30.returns;
set returns;
run;
/*Put Week, Quarter, and Year on returns for aggregation*/
data returns;
format week qtr year 4.;
set returns;
week = week(date);
year = year(date);
qtr = qtr(date);
run;
data dow30.prices;
format week qtr year 4.;
set prices;
week = week(date);
year = year(date);
qtr = qtr(date);
run;
data dow30.prices_wk;
set dow30.prices;
by year week;
if last.week;
run;
/*Sum returns over each week to create weekly returns*/
proc summary data=returns;
var &stocks;
by year week;
output out=weekly(drop=_type_ _freq_) sum=;
run;
/*Copy weekly returns to perm library*/
proc datasets lib=work nolist;
copy out=dow30;
select weekly ;
run;
quit;
/*Add a record index*/
data weekly(index=(indx));
set weekly;
indx = _N_;
run;
/*Select the index values for each quarter end,
starting with year end 1999, and ending with
year end 2011 */
proc sql noprint;
select indx, year, week
into :starts separated by ' '
from weekly
where (2012 > year > 1999
and week in (13,26,39,52)
)
or (year = 1999 and week = 52)
order by year, week;
quit;
%put &starts;
/*Macro will loop over the starting index values
starts = period starting index values
obs = number of observations for copula fitting
fwd = number of periods forward to simulate
draws = number of draws for simulation
max = number of times to loop, m<1 means loop over all
values in starts */
%macro loop(starts,obs=100,fwd=1,draws=100,max=0);
/*Total draws needed in sumulation*/
%let nDraws = %eval(&fwd*&draws);
/*Number of items in starts*/
%let nSims = %sysfunc(countw(&starts));
/*update max with nSims if max < 1*/
%if %sysevalf(&max < 1) %then
%let max=&nSims;
;
/*Delete optES if it exists*/
proc datasets lib=work nolist;
delete optES;
run;
quit;
/*Delete cov if it exists*/
proc datasets lib=dow30 nolist;
delete cov;
run;
quit;
/*Start main loop*/
%do i=1 %to &max;
/*start= current starting index*/
%let start = %scan(&starts,&i);
/*e= ending index*/
%let e = %eval(&start - &obs);
/*create subset of weekly returns
get the as-of week and year*/
data test;
set weekly(where=(&e <= indx <=&start)) end=last;
if _n_ = 1 then do;
call symput("foy",put(year,4.));
call symput("fow",put(week,2.));
end;
if last then do;
call symput("aoy", put(year,4.));
call symput("aow", put(week,2.));
end;
run;
/*de-mean the weekly returns over the subset*/
proc standard mean=0 data=test out=test;
var &stocks;
run;
/*Create the covariance matrix for the subset,
store in perm location */
proc corr data=test
out=cov(where=(_type_="COV")) cov noprint;
var &stocks;
run;
data cov;
format year week 4.;
set cov;
year=&aoy;
week=&aow;
run;
proc append base=dow30.cov data=cov force;
run;
%put AS OF = &start;
%put From &foy, Week &fow: To &aoy, Week &aow;
ods select NONE ;
/*Fit a T copula and simulate from it*/
proc copula data=test;
var &stocks;
fit t /
marginals=empirical
method=MLE;
simulate /
ndraws=&nDraws
seed=54321
out=sim;
run;
/*Check the sim data. If no observations then the
fitting failed. Fail over to a Normal/Gaussian
Copula */
proc sql noprint;
select count(*) format=5. into :nsim from sim;
quit;
%if &nsim = 0 %then %do;
%put NSIM=&nsim, switching to NORMAL Model;
proc copula data=test ;
var &stocks;
fit normal /
marginals=empirical;
simulate /
ndraws=&nDraws
seed=54321
out=sim;
run;
%end;
ods select default;
/*Create an iteration number in the simulations*/
data sim_&aoy._%left(&aow);
format iter 8.;
set sim;
iter = mod(_N_,&draws);
run;
proc sort data=sim_&aoy._%left(&aow);
by iter;
run;
/*Aggregate the iterations into a final number for
the forward period*/
proc summary data=sim_&aoy._%left(&aow);
var &stocks;
by iter;
output out=sim_&aoy._%left(&aow)(drop=_type_ _freq_ iter) sum=;
run;
/*Use IML for the NL Optimization */
proc iml noprint;
/*Read the simulations into a matrix*/
use sim_&aoy._%left(&aow);
read all var _num_ into sim[colname=cnames];
close sim_&aoy._%left(&aow);
s = ncol(sim);
w0 = repeat(1/s,s);
/*Function calculating expected shortfall*/
start F_ES(x) global(sim);
v = sim*x`;
call sort(v);
cutoff = floor(nrow(sim)*.05);
es = v[1:cutoff][:];
return (-es);
finish F_ES;
/*Setup constraints*/
lb = repeat(0,1,s);
ub = repeat(.1,1,s);
ones = repeat(1,1,s);
addc = ones || {0 1};
con = (lb || {. .}) //
(ub || {. .}) //
addc;
optn = {0 0};
x = w0`;
/*Call the nl quasi-Newton optimizer*/
call nlpqn(rc,w,"F_ES",x,optn,con);
/*Put the returns into a data set*/
create results_&aoy._%left(&aow) from w[colname=cnames];
append from w;
close results_&aoy._%left(&aow);
quit;
/*Add the week and year to the results*/
data results_&aoy._%left(&aow);
year = &aoy;
week = &aow;
set results_&aoy._%left(&aow);
run;
/*Append the results into the final results*/
proc append data=results_&aoy._%left(&aow) base=optES force;
run;
%end;
/*Delete the simulation and result files*/
proc datasets lib=work nolist;
delete sim: results:;
run;
quit;
%mend;
/*Call the simulations and optimizations
Use 104 weeks (2 years) in each subset
simulate 13 weeks (1 qtr) forward
draw 5000 iterations */
%let st = %sysfunc(datetime());
options nonotes nomprint;
*loop(starts,obs=100,fwd=1,draws=100,max=0);
%loop(&starts,obs=104,fwd=13,draws=5000,max=0);
options notes nomprint;
%let el = %sysevalf(%sysfunc(datetime()) - &st);
%put Took: ⪙
/*Copy the final results and covariance matrices to
output locationthe */
proc datasets lib=work nolist;
copy out=dow30;
select optES ;
run;
quit;
/*Download DIA and SPY returns*/
%get_stocks(dia spy,03JAN2000,30JUL2012,keepPrice=0);
/*Finally, export the optimal portfolio weights
into R and save the DataFrame*/
proc iml;
call ExportDataSetToR("dow30.optES", "optES" );
call ExportDataSetToR("dow30.cov","cov");
call ExportDataSetToR("dow30.prices","prices");
call ExportDataSetToR("dow30.prices_wk","prices_wk");
call ExportDataSetToR("returns","dia_spy");
submit / R;
save(optES, file="C:\\temp\\9.3\\dow30\\optES");
save(cov, file="C:\\temp\\9.3\\dow30\\cov");
save(prices, file="C:\\temp\\9.3\\dow30\\prices");
save(prices_wk, file="C:\\temp\\9.3\\dow30\\prices_wk");
save(dia_spy, file="C:\\temp\\9.3\\dow30\\dia");
endsubmit;
quit;