SAS Documentation
SASĀ® Solution for Stress Testing
Reference manual - version 08.2021
Loading...
Searching...
No Matches
irmst_model_postcode_creditRiskPlus.sas
1/* ************************************************** *
2 * Model Post-Code Template *
3 * ************************************************** *
4
5Purpose:
6 Injection point for executing custom code after the MIP model execution
7
8Details:
9 The following SAS macro variables are available to the model at run time:
10 - ticket: SAS authentication service ticket (useful for performing operations that require authentication, i.e. interacting with REST services).
11 - rgf_protocol: Communication protocol (http/https) of the SAS Risk and Governance Framework web application
12 - rgf_host: Hostname of the SAS Risk and Governance Framework web application
13 - rgf_port: Port where the SAS Risk and Governance Framework web application is listening
14 - ds_in_model_result: Name of the input table containing the result of the MIP model execution
15 - ds_out_model_result: Name of the output table to be created by this code
16*/
17
18
19/* Analysis Run Key */
20/* Get the root location of the SAS Risk Workgroup Application */
21%let sas_risk_workgroup_dir = ${globals.sas_risk_workgroup_dir};
22
23/* Cycle Key */
24%let cycle_key = ${context.cycle.key};
25
26/* Analysis Run Key */
27%let analysis_run_key = ${context.analysisRun.key};
28
29%let ValueAtRisk_Level = ${params.VARLEVEL};
30
31%let current_dt_ymd = %sysfunc(date(), yymmddd10.);
32%let current_tm_tod = %sysfunc(time(), tod10.);
33
34/* Initialize the environment */
35%include "&sas_risk_workgroup_dir./groups/Public/SASRiskManagementCore/cycles/&cycle_key./init.sas" / lrecl = 32000 source2;
36
37/* Get information from the cycle */
38%let ticket =;
39%let httpSuccess = 0;
40%let responseStatus =;
41%irm_rest_get_rgf_cycle(key = &cycle_key.
42 , host = &rgf_protocol://&rgf_host.
43 , port = &rgf_port.
44 , tgt_ticket = &tgt_ticket.
45 , outds = cycle_info
46 , outVarTicket = ticket
47 , outSuccess = httpSuccess
48 , outResponseStatus = responseStatus
49 );
50data _null_;
51 set cycle_info;
52 call symputx("cycle_baseDt", baseDt, "L");
53 call symputx("cycle_entityId", entityId, "L");
54run;
55
56%let sectors_cnt =4; /*Number of active sectors in CrediRisk+ - including specific sector */
57%let exposureHistogram_max =${params.EXPOSUREMAX}; /*Maximum value of the exposure domain to be investigated*/
58%let exposureHistogram_cellCnt =${params.EXPOSURECELLCOUNT}; /*SUGGESTION: exposureHistogram_cellCnt=2^k.
59 It is the number of cells used to approximate the histogram of the losses.
60 For computational reasons it is best to set it to 2^k where k is positive integer.
61 The approximation and the computational complexity grows with k.
62 In particular, this code requires the evaluation of Discrete Fourier transform.
63 If exposureHistogram_cellCnt=2^k then the evaluation of the Discrete Fourier transform
64 can per performed significantly faster.*/
65%let exposureHistogram_width =%eval(&exposureHistogram_max./&exposureHistogram_cellCnt.); /* Discretization interval for creditrisk+:
66 Base units of exposures *//**/
67%let debug_flg =${params.DEBUGFLG}; /*It allows to store temporary data sets.*/
68
69%let custom_AnalysisName =${params.ANALYSISDATANAME};
70/*Post-Execution program to evaluate the risk exposure based on the Credit Risk+ methodology.
71 The main idea is to obtain the the compound distribution of losses through convolution.
72 The convolution is obtain by using the the Fast Fourier Transform and the Characteristic function associated with the probability distribution.
73 The Post-Execution program has been created based on the material presented in
74 "CreditRisk+ by Fast Fourier Transform", July 2004. YieldCurve, August 2004.
75 Available at SSRN: https://ssrn.com/abstract=1122844 or https://dx.doi.org/10.2139/ssrn.1122844
76 It presumes a pre-execution program called: ST_CreditPlus_Pre_Exec
77 It is executed after the User Defined Logic (UDL): ST_CreditRisk_Plus_Exposure*/
78
79/*Collect the information about the scenarios,
80Notice that a scenario associated with k horizons/forecast_times is equivalent to k scenarios.
81For example, if there are main scenarios and the interest is to project the portfolio for 3 periods ahead in time:
82Scenario_1: 1 year forecast_time, 2 year forecast_time and 3 year forecast_time.
83Scenario_2: 1 year forecast_time, 2 year forecast_time and 3 year forecast_time.
84Then there are 6 actual scenarios:
85Scenario_1_1yr
86Scenario_1_2yr
87Scenario_1_3yr
88Scenario_2_1yr
89Scenario_2_2yr
90Scenario_2_3yr
91*/
92
93%macro debug_folder;
94 /*By default, temporary results are stored under the WORK llibname*/
95 libname libdebug %sysfunc(quote(%sysfunc(pathname(work)))) ;
96 /*If the debug option is set to TRUE, then you have the option to store the temporary results under a different LILBNAME*/
97 %if %upcase(&debug_flg.) = TRUE %then %do;
98 /*debugging path*/
99 %let dubug_libname_path=/opt/sas/config/Lev1/AppData/SASRiskWorkGroup/groups/StressTesting/testing_debug;
100 /*If the debugging folder does not exist, create one.*/
101 %if %rsk_dir_exists(DIR=&dubug_libname_path.)=0 %then %do;
102 %rsk_mkdirs(DIR=&dubug_libname_path.);
103 %end;
104 libname libdebug "&dubug_libname_path.";
105 data libdebug.&ds_in_model_result.;
106 set &ds_in_model_result.;
107 run;
108 %end;
109%mend debug_folder;
110%debug_folder;
111
112/*Get the scenario list*/
113proc sql noprint;
114 select distinct SCENARIO_ID into :_actualscenario_list_ separated by " "
115 from &ds_in_model_result.(where=(DISCRETIZED_EXPOSURE NE . and SCENARIO_ID NE "BASECASE"));
116 select distinct reporting_dt into :_reporting_dt_
117 from &ds_in_model_result.(where=(DISCRETIZED_EXPOSURE NE . and SCENARIO_ID NE "BASECASE"));
118quit;
119
120/*Count the number of scenarios*/
121%let _actualscenario_cnt_ = %sysfunc(countw(&_actualscenario_list_,%str( )));
122
123/**/
124/*This macro loops around the actual scenarios.
125 1) It prepares the data sets.
126 2) It triggers the FFT based algorithm to evaluate the compound distribution.
127 3) It fetched the output from the analysis of the different scenarios.*/
128%macro scenario_loop( libname =
129 , ds_in =
130 , ds_out =
131 , scenario_cnt =
132 , scenarioname_list =
133 );
134
135 %do i_scenario=1 %to &scenario_cnt.;
136
137 /*It filters the data for the given scenario.*/
138 data &libname..scenario_data_&i_scenario.;
139 set &ds_in.(where=(DISCRETIZED_EXPOSURE NE . and SCENARIO_ID="%scan(&scenarioname_list., &i_scenario., %str( ))"));
140 run;
141
142 /*It evaluates the compound distribution.*/
143 %irmst_fft_convolution( libname=&libname.
144 , ValueAtRisk_Level=&ValueAtRisk_Level.
145 , ds_in=scenario_data_&i_scenario.
146 , ds_out=compoundDistribution_&i_scenario.
147 );
148
149 /*It queries the output dataset to retrieve the relevant information.*//**/
150 proc sql noprint;
151 select VAR,
152 ExpectedCompoundLoss,
153 EconomicCapital
154 %do i_sector=1 %to &sectors_cnt.;
155 , VAR_&i_sector.
156 , ExpectedCompoundLoss_&i_sector.
157 , EconomicCapital_&i_sector.
158 %end;
159 into :_VAR_&i_scenario.,
160 :_ExpectedCompoundLoss_&i_scenario. ,
161 :_EconomicCapital_&i_scenario.
162 %do i_sector=1 %to &sectors_cnt.;
163 , :_VAR_&i_scenario._&i_sector.
164 , :_ExpectedCompoundLoss_&i_scenario._&i_sector.
165 , :_EconomicCapital_&i_scenario._&i_sector.
166 %end;
167 from &libname..compoundDistribution_&i_scenario.(obs=1);
168
169 /*It queries the original data conditional on the scenarios in order to obtain some information
170 to evaluate the weights needed for the calculation of the CVAR (Component VAR).
171 Specifically, the weight are proportional to the expected loss. As an alternative you could consider the exposure.*/
172 proc sql noprint;
173 select sum((normalized_expected_loss*PD_SD)**2)
174 %do i_sector=1 %to &sectors_cnt.;
175 , sum((normlzd_expctd_loss_sector_&i_sector.*PD_Volatility_Sector_&i_sector.)**2)
176 %end;
177 into :CVAR_denom_scenario_&i_scenario.
178 %do i_sector=1 %to &sectors_cnt.;
179 ,:CVAR_denom_scenario_&i_scenario._sector_&i_sector.
180 %end;
181 from &libname..scenario_data_&i_scenario.;
182 quit;
183
184 %end;/*End of the scenario loop*/
185
186 /*it creates the output dataset.
187 It is important to notice that the portfolio VAR is disaggregated across instruments through the CVAR (Component VAR).
188 The sum of the CVAR across instruments results in the portfolio VAR.
189 The CVAR is evaluated as
190 CVAR_i= beta_i * weight_i * VAR
191 where the portfolio weights are defined from
192 R_p=w_1*R_1+...+w_n*R_n
193 and
194 beta_i=cov(R_i, R_p)/var(R_p)=\frac{w_i*var_i+sum_{j \neq i}w_j*cov(R_i,R_j)}{var(R_p)}
195 For simplicity we are assuming cov(R_i,R_j)=0 \forall j \neq i, therefore
196 beta_i=cov(R_i, R_p)/var(R_p)=\frac{w_i*var_i} {\sum_j weight_j^2*var(R_j)}
197 This assumption implies that
198 CVAR_i= VAR * w_i *beta_i = VAR * \frac{weight_i^2*var(R_i)}{\sum_j weight_j^2*var(R_j)}
199 If this assumption is satisfactory , you should provide the value for each beta_i conditionally on the scenario.
200 IMPORTANT: irregardless of the assumption on beta_i, the value of VAR at the aggregate level does not change.
201 The assumption on beta_i only affects how the VAR is attributed to the individual instruments.*/
202 data &ds_out.;
203 set &ds_in.;
204 %do i_scenario=1 %to &scenario_cnt.;
205 if SCENARIO_ID="%scan(&scenarioname_list., &i_scenario., %str( ))" then do;
206 /*The following assumes beta_i=1*/
207 VAR = &&_VAR_&i_scenario.. * ((normalized_expected_loss*PD_SD)**2) / &&CVAR_denom_scenario_&i_scenario.;
208 ExpectedLoss = &&_ExpectedCompoundLoss_&i_scenario.. * ((normalized_expected_loss*PD_SD)**2) / &&CVAR_denom_scenario_&i_scenario.;
209 EconomicCapital = &&_EconomicCapital_&i_scenario.. * ((normalized_expected_loss*PD_SD)**2) / &&CVAR_denom_scenario_&i_scenario.;
210 ValueAtRisk_Alpha = &ValueAtRisk_Level.;
211 %do i_sector=1 %to &sectors_cnt.;
212 /*The following assumes beta_i=1*/
213 VAR_SECTOR&i_sector. = &&_VAR_&i_scenario._&i_sector.. * ((normlzd_expctd_loss_sector_&i_sector.*PD_Volatility_Sector_&i_sector.)**2) / &&CVAR_denom_scenario_&i_scenario._sector_&i_sector.;
214 ExpectedCompoundLoss_SECTOR&i_sector. = &&_ExpectedCompoundLoss_&i_scenario._&i_sector.. * ((normlzd_expctd_loss_sector_&i_sector.*PD_Volatility_Sector_&i_sector.)**2) / &&CVAR_denom_scenario_&i_scenario._sector_&i_sector.;
215 EconomicCapital_SECTOR&i_sector. = &&_EconomicCapital_&i_scenario._&i_sector.. * ((normlzd_expctd_loss_sector_&i_sector.*PD_Volatility_Sector_&i_sector.)**2) / &&CVAR_denom_scenario_&i_scenario._sector_&i_sector.;
216 %end;
217 end;
218 %end;
219 SIMULATIONPART = 'Exposure';
220 run;
221
222 /*If in DEBUG modem the save the output table in the predefined debuging libname.*/
223 %if %upcase(&debug_flg.) = TRUE %then %do;
224 data libdebug.ECON_CAP;
225 set &ds_out.;
226 run;
227 %end;
228
229%mend scenario_loop;/*end of the definition of the macro function.*/
230
231/*It triggers the main analysis.*/
232
233%scenario_loop( libname =libdebug
234 , ds_in =&ds_in_model_result.
235 , ds_out =&ds_out_model_result.
236 , scenario_cnt =&_actualscenario_cnt_.
237 , scenarioname_list =&_actualscenario_list_.
238 );
239
240/*template code to provide a graph of the aggregate loss distribution*/
241/*
242proc sql noprint;
243select VAR into :_VAR_
244from miprslt.compoundDistribution(obs=1);
245quit;
246
247%put &=_VAR_;
248
249proc sgplot data=miprslt.compoundDistribution;
250 title "Compounded Distribution";
251 series x=CompoundLoss y=compoundDistribution;
252 band x=CompoundLoss lower=0 upper=compoundDistribution/fillattrs=(color=blue);
253 band x=CompoundLoss lower=0 upper=compoundDistribution_tail/fillattrs=(color=red);
254 lineparm x=&_VAR_. y=0 slope=./curvelabel="&ValueAtRisk_Level. Value-at-Risk";
255run;
256
257proc means sum data=compoundDistribution print;
258run;
259*/
260
261