1%macro irmst_market_risk_funs_def_3;
3 function RSK_BINARY_CASH_OPTION_PF(CallPutType $, Price, Payoff_Cash, Strike, RiskFreeRate, YieldParam, TimeToExpiration, Volatility)
4 label=
"European binary cash or nothing option pricing by Reiner and Rubinstein (1991)";
9 if TimeToExpiration < 0 then
return(0);
14 Fname =
'rsk_binary_cash_option_pf';
16 ReturnMissingFlg = rsk_check_num_missing_pf( Payoff_Cash, Fname,
'3',
'Payoff_Cash', ReturnMissingFlg );
17 ReturnMissingFlg = rsk_check_num_missing_pf( RiskFreeRate, Fname,
'5',
'RiskFreeRate', ReturnMissingFlg );
18 ReturnMissingFlg = rsk_check_num_missing_pf( YieldParam, Fname,
'6',
'YieldParam', ReturnMissingFlg );
22 ReturnMissingFlg = rsk_check_nonpositive_pf( Price, Fname,
'2',
'Price', ReturnMissingFlg );
23 ReturnMissingFlg = rsk_check_nonpositive_pf( Strike, Fname,
'4',
'Strike', ReturnMissingFlg );
24 ReturnMissingFlg = rsk_check_nonpositive_pf( Volatility, Fname,
'8',
'Volatility', ReturnMissingFlg );
26 if ReturnMissingFlg eq 1 then
return(.);
28 if abs(TimeToExpiration) le constant(
'SQRTMACEPS') then do;
29 if upcase(CallPutType) eq 'CALL' and Price > Strike then return(Payoff_Cash);
30 if upcase(CallPutType) ne'CALL' and Price < Strike then return(Payoff_Cash);
37 CostofCarry=RiskFreeRate - YieldParam;
38 g = Volatility*sqrt(TimeToExpiration);
39 d = (log(Price / Strike) + CostofCarry * TimeToExpiration )/g - 0.5 * g;
41 IF upcase(CallPutType) eq 'CALL' THEN DO;
42 OptionPrice = Payoff_Cash * exp(-RiskFreeRate * TimeToExpiration) * probnorm(d);
46 OptionPrice = Payoff_Cash * exp(-RiskFreeRate * TimeToExpiration) * probnorm(-d);
52 function RSK_EUROPEANPUTOPTION_PF(Price,Strike,RiskFreeRate,YieldParam,TimeToExpiration,Volatility)
53 label="European put option pricing by Black (1976)";
57 IF TimeToExpiration lt 0 THEN return(0);
58 IF TimeToExpiration eq 0 THEN return (max(Strike-Price,0));
63 Fname = 'rsk_europeanputoption_pf';
67 ReturnMissingFlg = rsk_check_num_missing_pf( RiskFreeRate, Fname, '3', 'RiskFreeRate', ReturnMissingFlg );
68 ReturnMissingFlg = rsk_check_num_missing_pf( YieldParam, Fname, '4', 'YieldParam', ReturnMissingFlg );
69 ReturnMissingFlg = rsk_check_num_missing_pf( TimeToExpiration, Fname, '5', 'TimeToExpiration', ReturnMissingFlg );
70 ReturnMissingFlg = rsk_check_num_missing_pf( Price, Fname, '1', 'Price', ReturnMissingFlg );
71 ReturnMissingFlg = rsk_check_nonpositive_pf( Strike, Fname, '2', 'Strike', ReturnMissingFlg );
72 ReturnMissingFlg = rsk_check_nonpositive_pf( Volatility, Fname, '6', 'Volatility', ReturnMissingFlg );
74 if ReturnMissingFlg eq 1 then return(.);
78 CostofCarry=RiskFreeRate - YieldParam;
79 g = Volatility * sqrt(TimeToExpiration);
80 d1 = (log(Price / Strike) + CostofCarry * TimeToExpiration )/g + 0.5 * g;
82 OptionPrice = -Price * exp(-YieldParam* TimeToExpiration) * probnorm(-d1) + Strike * exp(-RiskFreeRate * TimeToExpiration) * probnorm(-d2);
89 function RSK_BARRIEROPTION_PF(CallPutType $, BarrierType $, Price, Price_Chk_Barrier, Strike, Barrier, CashRebate, RiskFreeRate, YieldParam, TimeToExpiration, Volatility)
90 label="European barrier option pricing by Merton (1973) and Reiner and Rubinstein (1991)";
95 if TimeToexpiration < 0 then return(0);
100 Fname = 'rsk_barrieroption_pf';
102 ReturnMissingFlg = rsk_check_num_missing_pf( RiskFreeRate, Fname, '8', 'RiskFreeRate', ReturnMissingFlg );
103 ReturnMissingFlg = rsk_check_num_missing_pf( YieldParam, Fname, '9', 'YieldParam', ReturnMissingFlg );
104 ReturnMissingFlg = rsk_check_num_missing_pf( TimeToExpiration, Fname, '10', 'TimeToExpiration', ReturnMissingFlg );
108 ReturnMissingFlg = rsk_check_nonpositive_pf( Price, Fname, '3', 'Price', ReturnMissingFlg );
109 ReturnMissingFlg = rsk_check_nonpositive_pf( Strike, Fname, '5', 'Strike', ReturnMissingFlg );
110 ReturnMissingFlg = rsk_check_nonpositive_pf( Barrier, Fname, '6', 'Barrier', ReturnMissingFlg );
111 ReturnMissingFlg = rsk_check_nonpositive_pf( Volatility, Fname, '11', 'Volatility', ReturnMissingFlg );
113 if ReturnMissingFlg eq 1 then return(.);
115 BarrType = lowcase(BarrierType);
116 Cash_Rebate = coalesce(CashRebate,0);
118 if abs(TimeToExpiration) le constant('SQRTMACEPS') then do;
119 if upcase(CallPutType) eq 'CALL' then payoff = max( Price - Strike, 0 );
121 payoff = max( Strike - Price, 0 );
122 if max(Price_Chk_Barrier,Price) > Barrier then do;
123 if BarrType eq 'ui' then return(payoff);
124 if BarrType eq 'uo' then return(Cash_Rebate);
125 if BarrType eq 'di' then return(Cash_Rebate);
126 if BarrType eq 'do' then return(payoff);
129 if min(Price_Chk_Barrier,Price) < Barrier then do;
130 if BarrType eq 'ui' then return(Cash_Rebate);
131 if BarrType eq 'uo' then return(payoff);
132 if BarrType eq 'di' then return(payoff);
133 if BarrType eq 'do' then return(Cash_Rebate);
137 if BarrType eq 'ui' then return(payoff);
138 if BarrType eq 'uo' then return(Cash_Rebate);
139 if BarrType eq 'di' then return(payoff);
140 if BarrType eq 'do' then return(Cash_Rebate);
144 if ( BarrType in ( 'di', 'do' ) and Price_Chk_Barrier le Barrier and not missing(Price_Chk_Barrier) ) or ( BarrType in ( 'ui', 'uo' ) and Price_Chk_Barrier ge Barrier ) then
146 if BarrType in ( 'do', 'uo' ) then OptionPrice = Cash_Rebate;
149 if upcase(CallPutType) eq 'CALL' then do;
151 OptionPrice =rsk_europeancalloption_pf(Price,Strike,RiskFreeRate, YieldParam,TimeToExpiration,Volatility);
156 OptionPrice =rsk_europeanputoption_pf(Price,Strike,RiskFreeRate, YieldParam,TimeToExpiration,Volatility);
158 return( OptionPrice );
164 CostofCarry=RiskFreeRate - YieldParam;
165 _mu_=(CostofCarry - (volatility*volatility)/2)/(volatility*volatility);
166 _lambda_=sqrt(_mu_*_mu_ + (2*RiskFreeRate)/(volatility*volatility) );
167 x1= (log(Price/Strike))/( volatility*sqrt(TimeToExpiration) ) + (1+_mu_)* volatility*sqrt(TimeToExpiration);
168 x2= (log(Price/Barrier))/( volatility*sqrt(TimeToExpiration) ) + (1+_mu_)* volatility*sqrt(TimeToExpiration);
169 y1= (log((Barrier*Barrier)/(Price*Strike)))/( volatility*sqrt( TimeToExpiration) ) + (1+_mu_)*volatility*sqrt(TimeToExpiration);
170 y2= (log((Barrier)/(Price)))/( volatility*sqrt(TimeToExpiration) ) + (1+ _mu_)*volatility*sqrt(TimeToExpiration);
171 z= (log((Barrier)/(Price)))/( volatility*sqrt(TimeToExpiration) ) + ( _lambda_)*volatility*sqrt(TimeToExpiration);
172 _nn_=(Barrier/Price)**(2*(_mu_+1));
173 _nm_=(Barrier/Price)**(2*_mu_);
174 _mm_=(Barrier/Price)**(_mu_ + _lambda_);
175 _ms_=(Barrier/Price)**(_mu_ - _lambda_);
177 if BarrType in ( 'ui', 'uo' ) then _eta_ = -1;
183 if upcase(CallPutType) eq 'CALL' then _psi_ = 1;
189 A=_psi_ * Price * exp((CostofCarry - RiskFreeRate)*( TimeToExpiration)) * probnorm(_psi_*x1) - _psi_* Strike * exp(- RiskFreeRate*(TimeToExpiration)) * probnorm(_psi_*x1 - _psi_* volatility*sqrt(TimeToExpiration));
190 B=_psi_ * Price * exp((CostofCarry - RiskFreeRate)*( TimeToExpiration)) * probnorm(_psi_*x2) - _psi_* Strike * exp(- RiskFreeRate*(TimeToExpiration)) * probnorm(_psi_*x2 - _psi_* volatility*sqrt(TimeToExpiration));
191 C=_psi_ * Price * exp((CostofCarry - RiskFreeRate)*( TimeToExpiration)) * _nn_ * probnorm(_eta_*y1) - _psi_* Strike * exp(- RiskFreeRate*(TimeToExpiration)) * _nm_ * probnorm(_eta_*y1 - _eta_*volatility*sqrt(TimeToExpiration));
192 D=_psi_ * Price * exp((CostofCarry - RiskFreeRate)*( TimeToExpiration)) * _nn_ * probnorm(_eta_*y2) - _psi_* Strike * exp(- RiskFreeRate*(TimeToExpiration)) * _nm_ * probnorm(_eta_*y2 - _eta_*volatility*sqrt(TimeToExpiration));
193 E=Cash_Rebate * exp(- RiskFreeRate*(TimeToExpiration)) * ( probnorm(_eta_*x2 - _eta_*volatility*sqrt(TimeToExpiration)) - _nm_* probnorm(_eta_*y2 - _eta_*volatility*sqrt( TimeToExpiration)) ) ;
194 F=Cash_Rebate * ( probnorm(_eta_*z)*_mm_ + _ms_* probnorm(_eta_*z - 2*_eta_*_lambda_*volatility* sqrt(TimeToExpiration)) ) ;
197 IF upcase(CallPutType) eq 'CALL' THEN DO;
199 IF BarrType eq 'di' THEN DO;
201 IF Strike ge Barrier THEN DO;
206 OptionPrice = A - B + D + E;
209 IF BarrType eq 'ui' THEN DO;
211 IF Strike ge Barrier THEN DO;
216 OptionPrice = B - C +D + E;
219 IF BarrType eq 'do' THEN DO;
221 IF Strike ge Barrier THEN DO;
222 OptionPrice = A -C + F;
226 OptionPrice = B - D + F;
229 IF BarrType eq 'uo' THEN DO;
231 IF Strike ge Barrier THEN DO;
236 OptionPrice = A - B + C -D +F;
243 IF BarrType eq 'di' THEN DO;
245 IF Strike ge Barrier THEN DO;
246 OptionPrice = B - C + D + E;
253 IF BarrType eq 'ui' THEN DO;
255 IF Strike ge Barrier THEN DO;
256 OptionPrice = A - B + D + E;
263 IF BarrType eq 'do' THEN DO;
265 IF Strike ge Barrier THEN DO;
266 OptionPrice = A -B + C - D + F;
273 IF BarrType eq 'uo' THEN DO;
275 IF Strike ge Barrier THEN DO;
276 OptionPrice = B - D + F;
280 OptionPrice = A - C + F;
289 subroutine RSK_COMBINE_TWO_SCHEDULES(aggregation_method $, sched_one_dt[*], sched_one_amt[*], sched_one_num, sched_two_dt[*], sched_two_amt[*], sched_two_num, out_dt[*], out_amt[*], out_num)
290 label="Combines two schedules into one";
291 outargs out_dt, out_amt, out_num;
296 TEMP_DT = min( sched_one_dt[1], sched_two_dt[1] );
298 do while( ( i le sched_one_num or j le sched_two_num ) and not missing(TEMP_DT) );
300 if i le sched_one_num then temp_cap_dt = sched_one_dt[i];
303 if j le sched_two_num then temp_scen_dt = sched_two_dt[j];
306 TEMP_DT = min( temp_cap_dt, temp_scen_dt );
308 sched_one_dt_exists = 0;
310 if i le sched_one_num then do;
311 if TEMP_DT eq sched_one_dt[i] then do;
313 out_dt[n] = sched_one_dt[i];
314 out_amt[n] = sched_one_amt[i];
315 sched_one_dt_exists = 1;
320 if j le sched_two_num then do;
321 if TEMP_DT eq sched_two_dt[j] then do;
324 if sched_one_dt_exists eq 1 then do;
325 if upcase(aggregation_method) eq 'MIN' then out_amt[n] = min( out_amt[n], sched_two_amt[j] );
327 if upcase(aggregation_method) eq 'MAX' then out_amt[n] = max( out_amt[n], sched_two_amt[j] );
329 if upcase(aggregation_method) eq 'FIRST' then do;
333 if upcase(aggregation_method) eq 'SECOND' then out_amt[n] = sched_two_amt[j];
335 out_amt[n] = sum( out_amt[n], sched_two_amt[j] );
341 out_dt[n] = sched_two_dt[j];
342 out_amt[n] = sched_two_amt[j];
354 subroutine RSK_BOOTSTRAP_HAZARD_RATE(ValuationDate, PremiumFrequency $, CDS_SprdCurve[*], Mat_CDS_SprdCurve[*], LGD_PCT, DefaultFrequency $, DiscountFactorCurve[*], Mat_DiscountFactorCurve[*], DayCountConvention $, IntpMethod $, IF_ACC_PRE_FLAG, HazardRateCurve[*] )
355 label="Bootstraps the hazard rate from a credit spread curve";
356 outargs HazardRateCurve;
357 RecoveryRate=1-LGD_PCT/100;
358 Default_Time_Increment=rsk_get_frequency_in_year(1,DefaultFrequency);
360 DayofYear=rsk_get_day_of_year(DayCountConvention);
361 PrmFreq=rsk_get_frequency_in_year(1,PremiumFrequency);
363 array CDS_Sprd_DayCount[1]/nosym;
364 call DYNAMIC_ARRAY(CDS_Sprd_DayCount,DIM(CDS_SprdCurve));
365 if (ValuationDate ~= .) then do;
366 do i=1 to DIM(Mat_CDS_SprdCurve);
367 CDS_Sprd_DayCount[i]=rsk_daycount(DayCountConvention,ValuationDate,Mat_CDS_SprdCurve[i]);
372 do i=1 to DIM(Mat_CDS_SprdCurve);
373 CDS_Sprd_DayCount[i]=Mat_CDS_SprdCurve[i];
379 array solvopts[1] initial (0.20);
380 do i=1 to DIM(Mat_CDS_SprdCurve);
381 HazardRate=solve("PremiumLeg_Minus_ProtectionLeg", solvopts, 0, CDS_SprdCurve, Mat_CDS_SprdCurve, RecoveryRate, Default_Time_Increment, DiscountFactorCurve, Mat_DiscountFactorCurve, PremiumFrequency , DayCountConvention , IntpMethod , IF_ACC_PRE_FLAG, HazardRateCurve, i, . );
382 if (HazardRate<0) then do;
384 HazardRateCurve[i]=0;
388 HazardRateCurve[i]=HazardRate;
394 function PREMIUMLEG_MINUS_PROTECTIONLEG(CDS_SprdCurve[*], Mat_CDS_SprdCurve[*], RecoveryRate, DefaultFrequency, DiscountFactorCurve[*], Mat_DiscountFactorCurve[*], PremiumFrequency $, DayCountConvention $, IntpMethod $, IF_ACC_PRE_FLAG, bHazardRateCurve[*], EndIndexofHazardRateCurve, EstimatedHazardRate)
395 label="Computes the difference between premium leg and protection leg values in a credit default swap, given a hazard rate";
397 EndDate=Mat_CDS_SprdCurve[EndIndexofHazardRateCurve];
400 array HazardRateCurve[1]/nosym;
401 call DYNAMIC_ARRAY(HazardRateCurve,EndIndexofHazardRateCurve);
402 do i=1 to DIM(HazardRateCurve);
403 HazardRateCurve[i]=bHazardRateCurve[i];
405 HazardRateCurve[EndIndexofHazardRateCurve]=EstimatedHazardRate;
408 array Mat_HazardRateCurve[1]/nosym;
409 call DYNAMIC_ARRAY(Mat_HazardRateCurve,EndIndexofHazardRateCurve);
410 do i=1 to DIM(Mat_HazardRateCurve);
411 Mat_HazardRateCurve[i]=Mat_CDS_SprdCurve[i];
414 szSurvProb=round(EndDate/DefaultFrequency,1);
415 array ProtectionLeg_SurvProb[1]/nosym;
416 call DYNAMIC_ARRAY(ProtectionLeg_SurvProb,szSurvProb+1);
417 ProtectionLeg_SurvProb[1]=1;
419 do i=1 to DIM(ProtectionLeg_SurvProb)-1;
420 ProtectionLeg_SurvProb[i+1]=rsk_calc_survival_prob(HazardRateCurve, Mat_HazardRateCurve, i*DefaultFrequency);
423 ProtectionLeg= getProtectionLeg(RecoveryRate, DiscountFactorCurve, Mat_DiscountFactorCurve, ProtectionLeg_SurvProb, DefaultFrequency, IntpMethod);
425 Premium_Time_Increment=rsk_get_frequency_in_year(1,PremiumFrequency);
426 szSurvProb=round(EndDate/Premium_Time_Increment,1);
427 array PremiumLeg_SurvProb[1]/nosym;
428 call DYNAMIC_ARRAY(PremiumLeg_SurvProb,szSurvProb+1);
429 PremiumLeg_SurvProb[1]=1;
431 do i=1 to DIM(PremiumLeg_SurvProb)-1;
432 PremiumLeg_SurvProb[i+1]=rsk_calc_survival_prob(HazardRateCurve, Mat_HazardRateCurve, i*Premium_Time_Increment);
435 CDS_Sprd=CDS_SprdCurve[EndIndexofHazardRateCurve];
436 PremiumLeg=getPremiumLeg(CDS_Sprd, DiscountFactorCurve, Mat_DiscountFactorCurve, PremiumLeg_SurvProb, PremiumFrequency, IF_ACC_PRE_FLAG, IntpMethod);
437 diff=PremiumLeg-ProtectionLeg;
442 function RSK_GET_FREQUENCY_IN_YEAR(Frequency_Interval_NO,Frequency_Interval_Unit $)
443 label="Calculates the period length in years, given the period description";
444 freq_int_unit = upcase(Frequency_Interval_Unit);
445 select (freq_int_unit);
446 when ('SECOND', 'SECONDS')
450 when ('MINUTE', 'MINUTES')
454 when ('HOUR', 'HOURS')
466 when ('WEEK', 'WEEKS')
474 when ('MONTH', 'MONTHS')
478 when ('QUARTER', 'QUARTERS')
486 when ('ANNUAL','YEAR','YEARS')
491 freq=freq*Frequency_Interval_NO;
498 function RSK_GET_DAY_OF_YEAR(DayCountConvention $)
499 label="Returns the number of days in a year, given the day counting convention";
500 select (DayCountConvention);
526 function GETPREMIUMLEG(CDS_Spread, DiscountFactorCurve[*], Mat_DiscountFactorCurve[*], SurvProb[*], PremiumFrequency $, IF_ACC_PRE_FLAG, IntpMethod $)
527 label="Values premium leg of a credit default swap";
529 Premium_Time_Increment=rsk_get_frequency_in_year(1,PremiumFrequency);
530 do i=1 to DIM(SurvProb)-1;
533 if (IF_ACC_PRE_FLAG eq 1) then do;
534 TmpProb=0.5*(SurvProb[i]-SurvProb[i+1]);
536 TmpProb=TmpProb+SurvProb[i+1];
537 PremiumLeg=PremiumLeg+Premium_Time_Increment*TmpProb*rsk_intpolate2(i*Premium_Time_Increment,DiscountFactorCurve,Mat_DiscountFactorCurve,IntpMethod);
539 PremiumLeg=PremiumLeg*CDS_Spread;
545 function GETPROTECTIONLEG(RecoveryRate, DiscountFactorCurve[*], Mat_DiscountFactorCurve[*], SurvProb[*], DefaultFrequency, IntpMethod $)
546 label="Values protection leg of a credit default swap";
548 do i=1 to DIM(SurvProb)-1;
549 ProtectionLeg=ProtectionLeg+(SurvProb[i]-SurvProb[i+1])*rsk_intpolate2(i*DefaultFrequency,DiscountFactorCurve,Mat_DiscountFactorCurve,IntpMethod);
551 ProtectionLeg=ProtectionLeg*(1-RecoveryRate);
552 return (ProtectionLeg);
556 function RSK_CALC_SURVIVAL_PROB(HazardRateCurve[*], Mat_HazardRateCurve[*], TimePoint)
557 label="Calculates survival probability from a hazard rate curve";
558 if (TimePoint<=Mat_HazardRateCurve[1]) then do tHazardRate=HazardRateCurve[1]*TimePoint;
561 do tHazardRate=HazardRateCurve[1]*Mat_HazardRateCurve[1];
562 do i=2 to DIM(Mat_HazardRateCurve);
563 if(TimePoint>=Mat_HazardRateCurve[i]) then
565 tHazardRate=tHazardRate+HazardRateCurve[i]*(Mat_HazardRateCurve[i]-Mat_HazardRateCurve[i-1]);
569 tHazardRate=tHazardRate+HazardRateCurve[i]*(TimePoint-Mat_HazardRateCurve[i-1]);
573 OUTLOOP: if(TimePoint>Mat_HazardRateCurve[DIM(Mat_HazardRateCurve)]) then
575 tHazardRate=tHazardRate+HazardRateCurve[DIM(Mat_HazardRateCurve)]*(TimePoint-Mat_HazardRateCurve[DIM(Mat_HazardRateCurve)]);
578 SurvProb=exp(-1*tHazardRate);