* 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 ;