* annvol.sas 070704 Daniel Brockman Calc annualized volatility of vars in set.;
* illustrates use of symgetn and symput;
* illustrates use of series like var1-var15 ;
* retested 070805;
* tested 070729 (not completely but sufficient for this project, I think);
%macro annvol( iset=, oset=, Dv=, voth=, vlist=, cal=C, ndy=7, anndy=365.25 ) ;
/*
* iset = input data set
* oset = output data set
* Dv = date variable (a SAS datevalue). This is the
* independent time variable. Under most circumstances,
* sensible results depend on your sorting iset in
* ascending order prior to invoking annvol.
* voth = list of other variables to maintain with the dataset.
* vlist = list of vars for which to calc annualized volatilities.
* iset contains the day to day changes in value of these vars.
* cal = "C" (default) implies calendar calculation, every day considered,
* including weekends.
* "T" implies trading calendar, skipping Saturdays and Sundays,
* so that Monday is the day after Friday.
* Other values of cal are errors (yours).
* ndy = integer number of days on which to calc volatility.
* Default = 7. Minimum = 2. If cal="T", then ndy=5 recommended.
* Results if you use non-integer or less than 2: Undefined.
* anndy = assumed number of days per year.
* Volatility is calculated as the standard deviation of
* ndy consecutive daily changes in value.
* The value stored as the volatility of the variable is
* an annualized number calculated as
* annv = v * sqrt(anndy)
* where annv is the annualized volatility, and v is the
* volatility calculated over the period of ndy days.
* Default anndy = 365.25 . If cal="T", then anndy=250 recommended.
*
*
* Resulting volatility V for a date is calculated as
* V = vdy*sqrt(anndy)
* where vdy = volatility calculated on ndy days.
*
* Dv is the name of the time variable, a SAS datevalue. We assume
* all inputs are daily data.
*
* vlist contains the names of relevant variables, separated by spaces,
* for example: "Height Weight Length Capacity"
*
* Volatility is defined as the standard deviation of the
* change in value of the variable. (Cox & Rubenstein, "Options Markets",
* pp. 255-6)
*
* You may choose anndy other than 365.25 when appropriate. With market
* prices as input data, you may wish to use the number of trading days
* per year, rather than the number of calendar days.
*
* Remarks on Methods:
*
* annvol assigns global var greturn.
*
* We use methods that emphasize use of SAS capabilities. These may well
* turn out data-intensive, so that quicker execution or execution with
* larger data sets might be possible with explicit calculation of values
* such as standard deviations. Provided the machine can complete such
* implicit calculations, more explicit calculations would require more
* labor. Thus we consider reasonable the tradeoff between labor and
* automated methods.
*
* 070729 Daniel Brockman -- overhauled logic.
* 070801 db. added voth to parms.
*/
%global greturn ;
%global greturn1 ;
%let cal=%upcase(&cal); * disambiguate ;
%if ((&cal ne C) and (&cal ne T)) %then %do ;
%put "ERROR annvol.sas cal:&cal Invalid value.";
%return ;
%end;
%if ((&ndy<2) or (&anndy<1)) %then %do ;
%put "ERROR annvol.sas ndy:&ndy or anndy:&anndy is too small.";
%return ;
%end;
* calculate annualizing factor ;
data _null_;
call symput('annfac',sqrt(&anndy)) ;
run;
* temp dsn ;
%getdsname(temp01);
%let t1=&greturn;
%if (&cal ne C) %then %do ; * knock out weekends if necc ;
data &t1 (keep=&Dv &voth &vlist);
set &iset ;
%if (&cal eq T) %then %do ;
if (weekday(&Dv) ne 7) ; * subset to days not Saturday;
if (weekday(&Dv) ne 1) ; * subset to days not Sunday;
%end;
run;
%end ;
%else %let t1=&iset ; * otherwise, we like our input set;
* count the variables of interest. NoV=Number of Variables ;
%let NoV=0 ; * init count ;
%do %until( %scan(&vlist,%eval(&NoV+1)) eq ) ;
%let NoV=%eval(&NoV+1) ; * increment count ;
%end;
data &oset (keep=&Dv &voth &vlist) ;
*data &oset ; * test ;
set &t1 ;
* generate retain statements ;
%do ii=1 %to &NoV ; /* loop the vars */
%let Vn=%scan(&vlist,&ii) ; /* name of the var */
/* we use names unlikely to collide */
retain Lg_&Vn._Lg_1-Lg_&Vn._Lg_&ndy. ; /* make sure we still have it */
%end ; /* do ii */
/* assign the lagged values (we don't trust the lag functions ); */
%do ii=1 %to &NoV ; * loop the vars ;
%let Vn=%scan(&vlist,&ii); * name of the var ;
%do Di=&ndy %to 2 %by -1 ; * loop the calc period ;
%let Dj=%eval(&Di-1); * later day ;
Lg_&Vn._Lg_&Di.=Lg_&Vn._Lg_&Dj. ; * slip from later to earlier ;
%end ; * do Di ;
Lg_&Vn._Lg_1=&Vn. ; * the current value is element 1;
/* this is where we actually calculate annualized volatility */
/* replace value of var with calculated annualized volatility */
&Vn=std(of Lg_&Vn._Lg_1-Lg_&Vn._Lg_&ndy.) * symgetn('annfac' ) ;
%end ; * do ii ;
run;
/* discard the tempo dataset */
%delds(&t1);
/* we are thru */
%mend annvol ;