SAS Documentation
SASĀ® Solution for Stress Testing
Reference manual - version 08.2021
Loading...
Searching...
No Matches
irmst_riskagg_linear.sas
Go to the documentation of this file.
1/*
2 Copyright (C) 2020 SAS Institute Inc. Cary, NC, USA
3 */
4
5/**
6 \file
7 \anchor irmst_riskagg_linear
8 \anchor irmst_riskagg_linear_key
9
10 \brief Linear aggregation of risk.
11
12 \param[in] ds_in_configuration_table Input configuration table. It provides information about risk sources to be aggregated and information about the corresponding scenarios.
13 \param[in] ds_in_correlation_table Input correlation table. It contains information about the correlation matrix to be used for the linear aggregation
14 \param[in] working_libname Working LIBNAME. By default, it is set to work. This option is typically used to facilitate debugging.
15 \param[out] ds_out_risk_analysis_table Output table. It contains results about the linear aggregation..
16
17
18 \details
19
20 Given an input configuration table (<i>DS_IN_CONFIGURATION_TABLE</i>) and an input correlation matrix (<i>DS_IN_CORRELATION_TABLE</i>),
21 this macro will linearly aggregate the risk sources defined in the configuration table (<i>DS_IN_CONFIGURATION_TABLE</i>).
22 Notice that the aggregation can be performed with respect to different scenarios: the configuration table (<i>DS_IN_CONFIGURATION_TABLE</i>) and the (<i>DS_IN_CORRELATION_TABLE</i>) need to contain a properly specified scenario variable (<i>&lt;SCENARIO_ID&gt;</i>).
23
24
25 The structure of the <b><i>DS_IN_CONFIGURATION_TABLE</i></b> table is as follows:
26
27 | Variable | Type | Description |
28 |-----------------------------|-------------------|----------------------------------------|
29 | <i>&lt;REPORTING_DT&gt;</i> | NUMERIC | SAS Date value. |
30 | <i>&lt;SCENARIO_ID&gt;</i> | CHARACTER/NUMERIC | Scenario identifier variable. |
31 | <i>&lt;NAME&gt;</i> | CHARACTER | Name of the risk source. |
32 | <i>&lt;EXPECTEDLOSS&gt;</i> | NUMERIC | Expected Loss |
33 | <i>&lt;VALUEATRISK&gt;</i> | NUMERIC | Value-at-Risk |
34 | <i>&lt;ECONOMIC_CAPITAL&gt;</i> | NUMERIC | Economic Capital |
35
36
37
38 The structure of the <b><i>DS_IN_CORRELATION_TABLE</i></b> table is as follows:
39
40 | Variable | Type | Description |
41 |-----------------------------|-------------------|---------------------------------------------------------------------------------------------------------------|
42 | <i>&lt;SCENARIO_ID&gt;</i> | CHARACTER/NUMERIC | Scenario identifier variable. |
43 | <i>&lt;_NAME_&gt;</i> | CHARACTER | Name of the risk source. |
44 | <i>&lt;RISK_MEASURE&gt;</i> | CHARACTER | Type of risk measure: VaR, EC, etc.... |
45 | <i>&lt;_TYPE_&gt;</i> | CHARACTER | Type of dependence matrix. Currently it only supports "corr" |
46 | <i>_NAME_ variables</i> | NUMERIC | The list of variables specified in <i>&lt;_NAME_&gt;</i>. These specify the values of the dependence matrix. |
47
48
49
50
51 \ingroup RiskAggregation
52
53 \author SAS Institute INC.
54 \date 2020
55
56*/
57
58
59/* Sample call:
60%irmst_riskagg_linear( ds_in_configuration_table = riskagg_linear_config
61 , ds_in_correlation_table = riskagg_linear_corr
62 , ds_out_risk_analysis_table = risk_analysis_table
63 );
64*/
65
66
67%macro irmst_riskagg_linear( ds_in_configuration_table =
68 , ds_in_correlation_table =
69 , working_libname = work
70 , ds_out_risk_analysis_table =
71 );
72
73 %local
74 bygroup_cnt
75 bygroup_list
76 bygroup_i
77 valid_bygroup_cnt
78 valid_bygroup_list
79 valid_bygroup_i
80 valid_bygroup_index
81 config_dim
82 corr_dim
83 ;
84
85 /*Create a look up table containing the distinct combinations of scenario and reporting_dt.
86 Notice that in theory the linear aggregation can be performed on multiple scenarios at the same time.*/
87 proc sql noprint;
88 create table &working_libname..bygroup_lookup as
89 select distinct scenario_id, reporting_dt
90 from &ds_in_configuration_table.;
91 quit;
92
93 /*Adding a numeric index to the bygroup lookup table. This index makes the bygroup analysis much simpler when using PROC IML*/
94 data &working_libname..bygroup_lookup;
95 set &working_libname..bygroup_lookup;
96 index=_N_;
97 run;
98
99 /*Create some macro var*/
100 proc sql noprint;
101 select count(index), index into :bygroup_cnt, :bygroup_list separated by " "
102 from &working_libname..bygroup_lookup;
103 quit;
104
105 /*Enhance the configuration table with a numeric index identifying the bygroups*/
106 data &working_libname..enhanced_configuration_unordered;
107 set &ds_in_configuration_table.;
108 if _N_=1 then do;
109 declare hash h(dataset: "&working_libname..bygroup_lookup");
110 h.definekey("scenario_id");
111 h.definedata("index");
112 h.defineDone();
113 call missing(index);
114 end;
115 rc=h.find();
116 if rc=0 then output;
117 drop rc;
118 run;
119
120 /*Enhance the correlation table with a numeric index identifying the bygroups*/
121 data &working_libname..enhanced_correlation_table;
122 set &ds_in_correlation_table.;
123 if _N_=1 then do;
124 declare hash h(dataset: "&working_libname..bygroup_lookup");
125 h.definekey("scenario_id");
126 h.definedata("index");
127 h.defineDone();
128 call missing(index);
129 end;
130 rc=h.find();
131 if rc=0 then output;
132 drop rc;
133 run;
134
135 /*Check the validity of the bygroups*/
136 %let valid_bygroup_list=;
137 %let valid_bygroup_cnt=0;
138 %do bygroup_i=1 %to &bygroup_cnt.;
139 /*Check if the configuration table has the same length as the correlation table for each subgroup ("scenario_id")*/
140 data _NULL_;
141 set &working_libname..enhanced_configuration_unordered(where=(index=&bygroup_i.)) end=last;
142 if last then do;
143 call symputx("config_dim",_N_,"L");
144 end;
145 run;
146 data _NULL_;
147 set &working_libname..enhanced_correlation_table(where=(index=&bygroup_i.)) end=last;
148 if last then do;
149 call symputx("corr_dim",_N_,"L");
150 end;
151 run;
152 %*let config_dim=%rsk_attrn(&working_libname..enhanced_configuration_i_by, nobs);
153 %*let corr_dim=%rsk_attrn(&working_libname..enhanced_correlation_i_by, nobs);
154 %if &config_dim.=&corr_dim. %then %do;
155 %let valid_bygroup_list=&valid_bygroup_list. &bygroup_i.;
156 %let valid_bygroup_cnt=%eval(&valid_bygroup_cnt.+1);
157 %end;
158 %else %do;
159 %put WARNING: The subgroup "scenario_id" identified by index=&bygroup_i. is not valid because the dimnsions of the configuration table are (&config_dim. x 1) while the dimension of the correlation table are (&corr_dim. x &corr_dim.).;
160 %end;
161 %end;
162
163
164 /*it makes sure that the VaR entries and the correlation matrix entries are alligned.*/
165 data &working_libname..enhanced_configuration_table;
166 set &working_libname..enhanced_correlation_table(keep=_NAME_ index) &working_libname..enhanced_configuration_unordered(obs=0);
167 if _N_=1 then do;
168 declare hash h(dataset:"&working_libname..enhanced_configuration_unordered(rename=(name=_NAME_))");
169 h.definedata("EXPECTEDLOSS", "VALUEATRISK", "ECONOMIC_CAPITAL", "VALUEATRISK_ALPHA");
170 h.definekey("_NAME_","index");
171 h.defineDone();
172 end;
173 rc=h.find();
174 if rc=0 then do;
175 output;
176 end;
177 run;
178
179 /*
180 Proc iml is used to perform the linear aggregation of the risk.
181 In essence if you define the following two elements:
182 risk_vec = [num_1,num_2,...,num_k]`
183 risk_corr = |num_11,num_12,......,num_1k|
184 |num_21,num_22,......,num_2k|
185 |......,......,......,......|
186 |num_k1,num_k2,......,num_kk|
187 then
188 aggregated_risk = risk_vec`*risk_corr*risk_vec
189 */
190 proc iml;
191
192 /*Define empty placeholders to store the aggregation results across the different by group*/
193 EXPECTEDLOSS=j(&valid_bygroup_cnt.,1,.);
194 VALUEATRISK=j(&valid_bygroup_cnt.,1,.);
195 ECONOMIC_CAPITAL=j(&valid_bygroup_cnt.,1,.);
196 VALUEATRISK_ALPHA=j(&valid_bygroup_cnt.,1,.);
197 index=j(&valid_bygroup_cnt.,1,.);
198
199 /*Process the valid bygroups*/
200 %do valid_bygroup_i=1 %to &valid_bygroup_cnt.;
201 %let valid_bygroup_index=%scan(&valid_bygroup_list., &valid_bygroup_i., %str( ));
202
203 /*Read the configuration table*/
204 use &working_libname..enhanced_configuration_table(where=(index=&valid_bygroup_index.)); /* open the data set */
205 read all var {"EXPECTEDLOSS"} into expected_loss; /* read variable of interest */
206 read all var {"VALUEATRISK"} into var; /* read variable of interest */
207 read all var {"VALUEATRISK_ALPHA"} into ALPHA; /* read variable of interest */
208 close &working_libname..enhanced_configuration_table; /* close the data set */
209
210 /*Read the column names of the correlation table*/
211 use &working_libname..enhanced_correlation_table(where=(index=&valid_bygroup_index.)); /* open the data set */
212 read all var {"_name_"} into columns; /* read variable of interest */
213 close &working_libname..enhanced_correlation_table; /* close the data set */
214
215 /*Read the correlation table*/
216 use &working_libname..enhanced_correlation_table(where=(index=&valid_bygroup_index.)); /* open the data set */
217 read all var columns into risk_corr; /* read variable of interest */
218 close &working_libname..enhanced_correlation_table; /* close the data set */
219
220 /*Evaluate the aggregated risk*/
221 EXPECTEDLOSS[&valid_bygroup_i.,1]=sum(expected_loss);
222 VALUEATRISK[&valid_bygroup_i.,1]=sqrt(var`*risk_corr*var);
223 if EXPECTEDLOSS[&valid_bygroup_i.,1]<0 then ECONOMIC_CAPITAL[&valid_bygroup_i.,1]=VALUEATRISK[&valid_bygroup_i.,1];
224 else ECONOMIC_CAPITAL[&valid_bygroup_i.,1]=VALUEATRISK[&valid_bygroup_i.,1]-EXPECTEDLOSS[&valid_bygroup_i.,1];
225 if ECONOMIC_CAPITAL[&valid_bygroup_i.,1]<0 then ECONOMIC_CAPITAL[&valid_bygroup_i.,1]=0;
226 index[&valid_bygroup_i.,1]=&valid_bygroup_index.;
227 /*The data must match when it comes to the alpha. This allows us to pick only the first entry and apply its level uniformly.*/
228 VALUEATRISK_ALPHA[&valid_bygroup_i.,1]=ALPHA[1,1];
229 %end;
230
231 /*Store the aggregated risk results*/
232 create &ds_out_risk_analysis_table. var {"EXPECTEDLOSS" "VALUEATRISK" "ECONOMIC_CAPITAL" "VALUEATRISK_ALPHA" "index"}; /* create data set */
233 append; /* write data in vectors */
234 close &ds_out_risk_analysis_table.; /* close the data set */
235
236 quit;
237
238 /*Use the bygroup lookup table to populate the aggregated risk result table with corresponding values of
239 the scenarios.*/
240 data &ds_out_risk_analysis_table.;
241 set &ds_out_risk_analysis_table. &working_libname..enhanced_configuration_table(obs=0);
242 if _N_=1 then do;
243 declare hash h(dataset: "&working_libname..bygroup_lookup");
244 h.definekey("index");
245 h.definedata("scenario_id","reporting_dt");
246 h.defineDone();
247 end;
248 rc=h.find();
249 entity_id="+";
250 RISK_TYPE="+";
251 if rc=0 then output;
252 drop rc name NValue table_id project_id load_id processed_dttm;
253 run;
254
255
256 proc append base=&ds_out_risk_analysis_table.( keep= ENTITY_ID
257 RISK_TYPE
258 REPORTING_DT
259 SCENARIO_ID
260 EXPECTEDLOSS
261 VALUEATRISK
262 VALUEATRISK_ALPHA
263 ECONOMIC_CAPITAL )
264 data=&DS_IN_CONFIGURATION_TABLE.( keep= ENTITY_ID
265 RISK_TYPE
266 REPORTING_DT
267 SCENARIO_ID
268 EXPECTEDLOSS
269 VALUEATRISK
270 VALUEATRISK_ALPHA
271 ECONOMIC_CAPITAL )
272 ;
273 run;
274
275
276
277%mend;
278
279