static double cf_lrs1d_zcb(ZCMarketData* ZCMarket, double t, double r0, double phi0, double kappa, double sigma, double rho, double lambda, double T) { if(t==0) { return BondPrice(T, ZCMarket); } else { double price; double P0_t, P0_T, P0_t_plus, P0_t_minus, f0_t, CapitalLambda; double dt; CapitalLambda = (1 - exp(-kappa*(T-t))) / kappa; dt = INC * t; P0_t = BondPrice(t, ZCMarket); P0_T = BondPrice(T, ZCMarket); P0_t_plus = BondPrice(t + dt, ZCMarket); P0_t_minus = BondPrice(t - dt, ZCMarket); f0_t = -(log(P0_t_plus) - log(P0_t_minus))/ (2 * dt); //Price of Zero Coupon Bond price = (P0_T/P0_t) * exp(-SQR(CapitalLambda)*phi0/2 + CapitalLambda*(f0_t-r0)); return price; } }
double ATMSwaptionStrike(double T_start, double T_end, double period, ZCMarketData* ZCMarket) { int i, n=pnl_iround((T_end-T_start)/period); double sum=0., T_i=T_start; for(i=0; i<n; i++) { T_i += period; sum += BondPrice(T_i, ZCMarket); } sum *= period; return (BondPrice(T_start, ZCMarket)-BondPrice(T_end, ZCMarket))/sum; }
// Compute the initial rate r_0 and corresponding value x_0 void initial_short_rate(ZCMarketData* ZCMarket, double *r0, double *x0) { if(ZCMarket->FlatOrMarket == 0) *r0 = ZCMarket->Rate; else *r0 = -log(BondPrice(INC, ZCMarket))/INC; *x0 = sqrt(2.* (*r0)); }
/// Computation of the payoff at the final time of the tree (ie the option maturity) static void CapFloor_InitialPayoffLRS1D(TreeLRS1D* Meth, ModelLRS1D* ModelParam, ZCMarketData* ZCMarket, PnlVect* OptionPriceVect2, NumFunc_1 *p, double T1, double T2, double CapFloorFixedRate) { double sigma, rho, kappa, lambda; int j, h; double delta_y, delta_t, sqrt_delta_t; double y_00, y_ih, r_ih, phi_ihj; double ZCPrice; int i_T1; double periodicity; /// Model Parameters kappa = (ModelParam->Kappa); sigma = (ModelParam->Sigma); rho = (ModelParam->Rho); lambda = (ModelParam->Lambda); /// Computation of the vector of payoff at the maturity of the option periodicity = T2 - T1; i_T1 = indiceTimeLRS1D(Meth, T1); pnl_vect_resize(OptionPriceVect2, 6*i_T1 - 3); delta_t = GET(Meth->t, i_T1+1) - GET(Meth->t,i_T1); sqrt_delta_t = sqrt(delta_t); delta_y = lambda * sqrt_delta_t; y_00 = r_to_y(ModelParam, -log(BondPrice(GET(Meth->t, 1), ZCMarket))/GET(Meth->t, 1)); p->Par[0].Val.V_DOUBLE = 1.0 ; for( h=0; h<=2*i_T1; h++) /// h : numero de la box { y_ih = y_00 + (i_T1-h) * delta_y; r_ih = y_to_r(ModelParam, y_ih); for(j=0;j<number_phi_in_box(i_T1, h);j++) /// Boucle sur les valeurs de phi à (i,h) { phi_ihj = phi_value(Meth, i_T1, h, j); ZCPrice = cf_lrs1d_zcb(ZCMarket, T1, r_ih, phi_ihj, kappa, sigma, rho, lambda, T2); LET(OptionPriceVect2, index_tree(i_T1, h, j)) = (p->Compute)(p->Par, (1+periodicity*CapFloorFixedRate)*ZCPrice); } } }
/*Call Option on Zero Coupon Bond*/ static double zbput(double a, double b,double sigma, double rcc,double t, double T, double S, double K, ZCMarketData* ZCMarket) { double PtS,PtT,ATS,BTS; double f0_t; double p1,p2,p3,k1,k2,k3,psi,phi,rb; double h; /*Computation of Forward rate*/ h=sqrt(SQR(a)+2.*SQR(sigma)); if(t-0.5*INC>0){f0_t = (log( BondPrice(t-0.5*INC, ZCMarket))-log( BondPrice(t+0.5*INC, ZCMarket)))/INC;} else {f0_t = -log( BondPrice(INC, ZCMarket))/INC; } PtT=zcbond(rcc,a,b,sigma,t,T, ZCMarket); PtS=zcbond(rcc,a,b,sigma,t,S, ZCMarket); BTS=B(S-T,a,b,sigma); ATS=A(S-T,a,b,sigma); /*X^2 parameters*/ rb=(log(ATS/K)+log(A(T,a,b,sigma)*BondPrice(S, ZCMarket))-log(A(S,a,b,sigma)*BondPrice(T, ZCMarket)))/BTS; phi=2.*h/(SQR(sigma)*(exp(h*(T-t))-1.)); psi=(a+h)/SQR(sigma); p1=2.*rb*(phi+psi+BTS); p2=4.*a*b/SQR(sigma); p3=2.*SQR(phi)*( rcc - shift(a,b,sigma,f0_t,t) )*exp(h*(T-t))/(phi+psi+BTS); k1=2.*rb*(phi+psi); k2=p2; k3=2.*SQR(phi)*( rcc - shift(a,b,sigma,f0_t,t) )*exp(h*(T-t))/(phi+psi); /*Price of Put by Parity*/ return PtS*pnl_cdfchi2n(p1,p2,p3)-K*PtT*pnl_cdfchi2n(k1,k2,k3) -PtS+K*PtT;; }
static double zcbond(double rcc,double a,double b,double sigma,double t,double T, ZCMarketData* ZCMarket) { if(t==0) { return BondPrice(T, ZCMarket); } else { double h, A, B, At, AT, shift, c; double f0_t, P0_t, P0_T, P0_t_plus, P0_t_minus; P0_t = BondPrice(t, ZCMarket); P0_T = BondPrice(T, ZCMarket); /*Computation of Forward rate*/ P0_t_plus = BondPrice(t*(1.+INC),ZCMarket); P0_t_minus = BondPrice(t*(1.-INC),ZCMarket); f0_t = -(log(P0_t_plus)-log(P0_t_minus))/(2.*t*INC); /*A,B coefficient*/ h=sqrt(SQR(a)+2.*SQR(sigma)); B=2.*(exp(h*(T-t))-1.)/(2.*h+(a+h)*(exp(h*(T-t))-1.)); A=pow(h*exp(0.5*(a+h)*(T-t))/(h+0.5*(a+h)*(exp(h*(T-t))-1.)), 2.*a*b/SQR(sigma)); At=pow(h*exp(0.5*(a+h)*(t))/(h+0.5*(a+h)*(exp(h*(t))-1.)), 2.*a*b/SQR(sigma)); AT=pow(h*exp(0.5*(a+h)*(T))/(h+0.5*(a+h)*(exp(h*(T))-1.)), 2.*a*b/SQR(sigma)); c=sqrt(a*a+2*sigma*sigma); shift = (f0_t - 2*a*b*(exp(t*c)-1)/(2*c+(a+c)*(exp(t*c)-1))); A=A*(P0_T*At)/(AT*P0_t)*exp(B*shift); /*Price*/ return A*exp(-B*rcc); } }
/*Call Option*/ static int zcb_quad1d(double flat_flag, double beta, double sigma, double r0, char *curve, double T, double *price) { double x0; Data data; ZCMarketData ZCMarket; /* Flag to decide to read or not ZC bond datas in "initialyields.dat" */ /* If P(0,T) not read then P(0,T)=exp(-r0*T) */ if(flat_flag==0) { ZCMarket.FlatOrMarket = 0; ZCMarket.Rate = r0; } else { ZCMarket.FlatOrMarket = 1; ZCMarket.filename = curve; ReadMarketData(&ZCMarket); r0 = -log(BondPrice(INC, &ZCMarket))/INC; if(T > GET(ZCMarket.tm,ZCMarket.Nvalue-1)) { printf("\nError : time bigger than the last time value entered in initialyield.dat\n"); exit(EXIT_FAILURE); } } x0 = sqrt(2.*r0); /* coefficients of P(0,T) */ bond_coeffs(&ZCMarket, &data, T, beta, sigma, x0); /*Price*/ *price = exp(-(r0 * data.B + data.b*x0 + data.c)); DeleteZCMarketData(&ZCMarket); return OK; }
// Compute f(0, T) the forward rate, known at 0, maturing at T. double ForwardRate(double T, ZCMarketData* ZCMarket) { return -(log(BondPrice(T + INC,ZCMarket))-log(BondPrice(T,ZCMarket)))/(INC); }
/// Backward computation of the price of a Zero Coupon Bond static void CapFloor_BackwardIterationLRS1D(TreeLRS1D* Meth, ModelLRS1D* ModelParam, ZCMarketData* ZCMarket, PnlVect* OptionPriceVect1, PnlVect* OptionPriceVect2, int index_last, int index_first) { double sigma, rho, kappa, lambda; int i, j, h; double delta_y, delta_t, sqrt_delta_t; double price_up, price_middle, price_down; double y_00, y_ih, r_ih, phi_ihj, phi_next; PnlVect* proba_from_ij; proba_from_ij = pnl_vect_create(3); ///********* Model parameters *********/// kappa = (ModelParam->Kappa); sigma = (ModelParam->Sigma); rho = (ModelParam->Rho); lambda = (ModelParam->Lambda); delta_t = GET(Meth->t, 1) - GET(Meth->t,0); y_00 = r_to_y(ModelParam, -log(BondPrice(GET(Meth->t, 1), ZCMarket))/delta_t); for(i = index_last-1; i>=index_first; i--) { pnl_vect_resize(OptionPriceVect1, 6*i-3); // OptionPriceVect1 := Price of the bond in the tree at time t(i) delta_t = GET(Meth->t, i+1) - GET(Meth->t,i); sqrt_delta_t = sqrt(delta_t); delta_y = lambda * sqrt_delta_t; for( h=0; h<=2*i; h++) /// h : numero de la box { y_ih = y_00 + (i-h) * delta_y; r_ih = y_to_r(ModelParam, y_ih); for(j=0;j<number_phi_in_box(i, h);j++) /// Boucle sur les valeurs de phi à (i,h) { phi_ihj = phi_value(Meth, i, h, j); phi_next = phi_ihj * (1-2*kappa*delta_t) + SQR(sigma) * pow(y_to_r(ModelParam, y_ih), (2*rho)) * delta_t; price_up = Interpolation(Meth, i+1, h , OptionPriceVect2, phi_next); price_middle = Interpolation(Meth, i+1, h+1, OptionPriceVect2, phi_next); price_down = Interpolation(Meth, i+1, h+2, OptionPriceVect2, phi_next); probabilities(GET(Meth->t,i), y_ih, phi_ihj, lambda, sqrt_delta_t, ModelParam, ZCMarket, proba_from_ij); LET(OptionPriceVect1, index_tree(i,h,j)) = exp(-r_ih*delta_t) * (GET(proba_from_ij,0) * price_up + GET(proba_from_ij,1) * price_middle + GET(proba_from_ij,2) * price_down ); } } pnl_vect_clone(OptionPriceVect2, OptionPriceVect1); // Copy OptionPriceVect1 in OptionPriceVect2 } // END of the loop on i (time) pnl_vect_free(&proba_from_ij); }
static double tr_lrs1d_capfloor(TreeLRS1D* Meth, ModelLRS1D* ModelParam, ZCMarketData* ZCMarket, int NumberOfTimeStep, NumFunc_1 *p, double s, double r, double periodicity,double first_reset_date,double contract_maturity, double CapFloorFixedRate) { double lambda; double delta_y; // delta_x1 = space step of the process x at time i ; delta_x2 same at time i+1. double delta_t, sqrt_delta_t; // time step double OptionPrice, OptionPrice1, OptionPrice2; int i, i_s, h_r; double theta; double y_r, y_ih, y_00, r_00; double Ti2, Ti1; int i_Ti2, i_Ti1, n; PnlVect* proba_from_ih; PnlVect* OptionPriceVect1; // Matrix of prices of the option at i PnlVect* OptionPriceVect2; // Matrix of prices of the option at i+1 proba_from_ih = pnl_vect_create(3); OptionPriceVect1 = pnl_vect_create(1); OptionPriceVect2 = pnl_vect_create(1); ///********* Model parameters *********/// lambda = (ModelParam->Lambda); ///**************** PAYOFF at the MATURITY of the OPTION : T(n-1)****************/// Ti2 = contract_maturity; Ti1 = Ti2 - periodicity; CapFloor_InitialPayoffLRS1D(Meth, ModelParam, ZCMarket, OptionPriceVect2, p, Ti1, Ti2, CapFloorFixedRate); ///**************** Backward computation of the option price ****************/// n = (int) ((contract_maturity-first_reset_date)/periodicity + 0.1); if(n>1) { for(i = n-2; i>=0; i--) { Ti1 = first_reset_date + i * periodicity; Ti2 = Ti1 + periodicity; i_Ti2 = indiceTimeLRS1D(Meth, Ti2); i_Ti1 = indiceTimeLRS1D(Meth, Ti1); CapFloor_BackwardIterationLRS1D(Meth, ModelParam, ZCMarket, OptionPriceVect1, OptionPriceVect2, i_Ti2, i_Ti1); CapFloor_InitialPayoffLRS1D(Meth, ModelParam, ZCMarket, OptionPriceVect1, p, Ti1, Ti2, CapFloorFixedRate); pnl_vect_plus_vect(OptionPriceVect2, OptionPriceVect1); } } ///****************** Price of the option at initial time s *******************/// i_s = indiceTimeLRS1D(Meth, s); // Localisation of s on the tree delta_t = GET(Meth->t, 1) - GET(Meth->t,0); sqrt_delta_t = sqrt(delta_t); r_00 = -log(BondPrice(GET(Meth->t, 1), ZCMarket))/delta_t; y_00 = r_to_y(ModelParam, r_00); Ti1 = first_reset_date; i_Ti1 = indiceTimeLRS1D(Meth, Ti1); if(i_s==0) // If s=0 { CapFloor_BackwardIterationLRS1D(Meth, ModelParam, ZCMarket, OptionPriceVect1, OptionPriceVect2, i_Ti1, 1); probabilities(GET(Meth->t,0), y_00, 0, lambda, sqrt_delta_t, ModelParam, ZCMarket, proba_from_ih); OptionPrice = exp(-r_00*delta_t) * ( GET(proba_from_ih,0) * GET(OptionPriceVect1, 0) + GET(proba_from_ih,1) * GET(OptionPriceVect1,1) + GET(proba_from_ih,2) * GET(OptionPriceVect1, 2)); } else { // We compute the price of the option as a linear interpolation of the prices at the nodes r(i_s,j_r) and r(i_s,j_r+1) delta_t = GET(Meth->t, i_s+1) - GET(Meth->t,i_s); sqrt_delta_t = sqrt(delta_t); delta_y = lambda * sqrt_delta_t; y_r = r_to_y(ModelParam, r); h_r = (int) floor(i_s - (y_r-y_00)/delta_y); // y_r between y(h_r) et y(h_r+1) : y(h_r+1) < y_r <= y(h_r) y_ih = y_00 + (i_s-h_r) * delta_y; if(h_r < 0 || h_r > 2*i_s) { printf("WARNING : Instantaneous futur spot rate is out of tree\n"); exit(EXIT_FAILURE); } CapFloor_BackwardIterationLRS1D(Meth, ModelParam, ZCMarket, OptionPriceVect1, OptionPriceVect2, i_Ti1, i_s); theta = (y_ih - y_r)/delta_y; OptionPrice1 = MeanPrice(Meth, i_s, h_r, OptionPriceVect2); //Interpolation(Meth, i_s, h_r , OptionPriceVect2, phi0); OptionPrice2 = MeanPrice(Meth, i_s, h_r+1, OptionPriceVect2); // Interpolation(Meth, i_s, h_r+1 , OptionPriceVect2, phi0); OptionPrice = (1-theta) * OptionPrice1 + theta * OptionPrice2 ; } pnl_vect_free(& OptionPriceVect1); pnl_vect_free(& OptionPriceVect2); pnl_vect_free(&proba_from_ih); return OptionPrice; }
//swaption_payer_receiver=0 : Payer //swaption_payer_receiver=1 : Receiver static double cf_swaption_direct(StructLiborAffine *LiborAffine, double swaption_start, double swaption_end, double swaption_period, double swaption_strike, double swaption_nominal, int swaption_payer_receiver) { double x0, lambda, theta, eta, Sqr_eta, Y; double P=0., Q=0., x, deg_freedom, n_centrality_param, bound, price, trm_k; double Tk, a_Ti, b_Ti, dzeta_k, sigma_k, sum=0.; int i, m, k, which=1, status; double psi_d; dcomplex uk, phi, psi; x0 = GET(LiborAffine->ModelParams, 0); lambda = GET(LiborAffine->ModelParams, 1); theta = GET(LiborAffine->ModelParams, 2); eta = GET(LiborAffine->ModelParams, 3); Sqr_eta = SQR(eta); // Static variables Ti = swaption_start; Tm = swaption_end; TN = LET(LiborAffine->TimeDates, (LiborAffine->TimeDates)->size-1); i = indiceTimeLiborAffine(LiborAffine, Ti); m = indiceTimeLiborAffine(LiborAffine, Tm); c_k = pnl_vect_create_from_double(m-i+1, swaption_period*swaption_strike); Phi_i_k = pnl_vect_create(m-i+1); Psi_i_k = pnl_vect_create(m-i+1); LET(c_k, 0) = -1.0; LET(c_k, m-i) += 1.; for (k=i; k<=m; k++) { uk = Complex(GET(LiborAffine->MartingaleParams, k), 0.); phi_psi_t_v(TN-Ti, uk, LiborAffine, &phi, &psi); LET(Phi_i_k, k-i) = Creal(phi); LET(Psi_i_k, k-i) = Creal(psi); } // Zero of the function f if (m==i+1) Y = find_Y_caplet(LiborAffine); else Y = find_Y_swaption(LiborAffine); a_Ti = exp(-lambda*Ti); if (lambda == 0.) b_Ti = Ti; else b_Ti = (1.-a_Ti)/lambda; deg_freedom = lambda*theta/Sqr_eta; sum=0.; Tk=Ti; for (k=i; k<=m; k++) { psi_d = GET(Psi_i_k, k-i); dzeta_k = 1 - 2*Sqr_eta*b_Ti*psi_d; sigma_k = Sqr_eta*b_Ti/dzeta_k; x = Y/sigma_k; n_centrality_param = x0*a_Ti/(Sqr_eta*b_Ti*dzeta_k); if (x<0) { P=0.; Q=1.; } else { pnl_cdf_chn (&which, &P, &Q, &x, °_freedom, &n_centrality_param, &status, &bound); } if (swaption_payer_receiver==0) trm_k = -GET(c_k, k-i)*BondPrice(Tk, LiborAffine->ZCMarket) * Q; else trm_k = GET(c_k, k-i)*BondPrice(Tk, LiborAffine->ZCMarket) * P; sum += trm_k; Tk += swaption_period; } price = swaption_nominal * sum; pnl_vect_free(&c_k); pnl_vect_free(&Phi_i_k); pnl_vect_free(&Psi_i_k); return price; }
///* Payer Swaption price as a combination of ZC Put option prices static int cf_ps1d(int flat_flag, double r_t, char *curve, double Nominal, double periodicity, double option_maturity, double contract_maturity, double SwaptionFixedRate, double a, double sigma,double *price) { int i, nb_payement; double ci, sum ,ti; double x0, critical_r, Strike_i, PutOptionPrice; Data data1, data2; Omega om; ZCMarketData ZCMarket; PutOptionPrice = 0.; /* to avoid warning */ /* Flag to decide to read or not ZC bond datas in "initialyields.dat" */ /* If P(0,T) not read then P(0,T)=exp(-r0*T) */ if(flat_flag==0) { ZCMarket.FlatOrMarket = 0; ZCMarket.Rate = r_t; } else { ZCMarket.FlatOrMarket = 1; ZCMarket.filename = curve; ReadMarketData(&ZCMarket); r_t = -log(BondPrice(INC, &ZCMarket))/INC; if(contract_maturity > GET(ZCMarket.tm,ZCMarket.Nvalue-1)) { printf("\nError : time bigger than the last time value entered in initialyield.dat\n"); exit(EXIT_FAILURE); } } x0 = sqrt(2* r_t); bond_coeffs(&ZCMarket, &data1, option_maturity, a, sigma, x0); ti = option_maturity; ci = periodicity * SwaptionFixedRate; nb_payement = (int)((contract_maturity-option_maturity)/periodicity); critical_r = Critical_Rate(&ZCMarket, r_t, periodicity, option_maturity, contract_maturity, SwaptionFixedRate, a, sigma); sum=0.; for(i=1; i<=nb_payement; i++) { ti += periodicity; /* coefficients of P(0,S) */ bond_coeffs(&ZCMarket, &data2, ti, a, sigma, x0); /* omega distribution of P(T,S) */ transport(&om, data1, data2, a, sigma, x0); Strike_i = exp(-(om.B*critical_r + om.b*sqrt(2*critical_r) + om.c)); PutOptionPrice = zb_call_quad1d(&ZCMarket, a, sigma, option_maturity, ti, Strike_i); sum += ci * PutOptionPrice; } sum += PutOptionPrice; *price = Nominal * sum; DeleteZCMarketData(&ZCMarket); return OK; }
double HeathJarrowMorton::Libor(double dt, double dStart, double dEnd, double dX, const CurveName & eCurveName) const { // Must change coverage to take into account real basis return 1.0 / (dEnd - dStart) * (BondPrice(dt, dStart, dX, eCurveName) / BondPrice(dt, dEnd, dX, eCurveName) - 1.0); }