/// Price at time "s" of a ZC bond maturing at "T" using a trinomial tree. static double tr_hw1d_zcbond(TreeShortRate* Meth, ModelParameters* ModelParam, ZCMarketData* ZCMarket, double T) { int index_last, index_first; double OptionPrice; PnlVect* OptionPriceVect1; // Matrix of prices of the option at i PnlVect* OptionPriceVect2; // Matrix of prices of the option at i+1 OptionPriceVect1 = pnl_vect_create(1); OptionPriceVect2 = pnl_vect_create(1); ///****************** Computation of the vector of payoff at the maturity of the option *******************/// ZCBond_InitialPayoffHW1D(Meth, OptionPriceVect2); ///****************** Backward computation of the option price until time 0 *******************/// index_last = Meth->Ngrid; index_first = 0; BackwardIteration(Meth, ModelParam, OptionPriceVect1, OptionPriceVect2, index_last, index_first, &func_model_hw1d); OptionPrice = GET(OptionPriceVect1, 0); pnl_vect_free(& OptionPriceVect1); pnl_vect_free(& OptionPriceVect2); return OptionPrice; }
static void triadiag_scalar_prod_test () { PnlVect *y, *x; PnlTridiagMat *M; PnlMat *full; int n = 5; int gen = PNL_RNG_MERSENNE_RANDOM_SEED; pnl_rand_init (gen, 1, 1); x = pnl_vect_create (n); y = pnl_vect_create (n); pnl_vect_rand_normal (x, n, gen); pnl_vect_rand_normal (y, n, gen); M = create_random_tridiag (n, gen); full = pnl_tridiag_mat_to_mat (M); pnl_test_eq_abs ( pnl_tridiag_mat_scalar_prod (M, x, y), pnl_mat_scalar_prod (full, x, y), 1E-12, "tridiag_mat_scalar_prod", ""); pnl_vect_free (&x); pnl_vect_free (&y); pnl_tridiag_mat_free (&M); pnl_mat_free (&full); }
int CALC(AP_CarmonaDurrleman)(void *Opt, void *Mod, PricingMethod *Met) { TYPEOPT* ptOpt=(TYPEOPT*)Opt; TYPEMOD* ptMod=(TYPEMOD*)Mod; double r; int i, res; PnlVect *divid = pnl_vect_create(ptMod->Size.Val.V_PINT); PnlVect *spot, *sig; spot = pnl_vect_compact_to_pnl_vect (ptMod->S0.Val.V_PNLVECTCOMPACT); sig = pnl_vect_compact_to_pnl_vect (ptMod->Sigma.Val.V_PNLVECTCOMPACT); for(i=0; i<ptMod->Size.Val.V_PINT; i++) pnl_vect_set (divid, i, log(1.+ pnl_vect_compact_get (ptMod->Divid.Val.V_PNLVECTCOMPACT, i)/100.)); r= log(1.+ptMod->R.Val.V_DOUBLE/100.); res=ap_carmonadurrleman(spot, ptOpt->PayOff.Val.V_NUMFUNC_ND, ptOpt->Maturity.Val.V_DATE-ptMod->T.Val.V_DATE, r, divid, sig, ptMod->Rho.Val.V_DOUBLE, &(Met->Res[0].Val.V_DOUBLE),Met->Res[1].Val.V_PNLVECT); pnl_vect_free(&divid); pnl_vect_free (&spot); pnl_vect_free (&sig); return res; }
static void tridiag_lu_syslin_test () { PnlVect *b, *x, *Mx; PnlTridiagMat *M; PnlTridiagMatLU *LU; int n = 5; int gen = PNL_RNG_MERSENNE_RANDOM_SEED; pnl_rand_init (gen, 1, 1); x = pnl_vect_create (n); b = pnl_vect_create (n); pnl_vect_rand_normal (b, n, gen); M = create_random_tridiag (n, gen); LU = pnl_tridiag_mat_lu_new (); pnl_tridiag_mat_lu_compute (LU, M); pnl_tridiag_mat_lu_syslin (x, LU, b); Mx = pnl_tridiag_mat_mult_vect (M, x); pnl_test_vect_eq_abs (Mx, b, 1E-12, "tridiag_mat_syslin", ""); pnl_vect_free (&x); pnl_vect_free (&Mx); pnl_vect_free (&b); pnl_tridiag_mat_free (&M); pnl_tridiag_mat_lu_free (&LU); }
static void tridiag_mv_test () { PnlVect *y, *x, *Fy; PnlMat *FM; PnlTridiagMat *M; int n = 5; int gen = PNL_RNG_MERSENNE_RANDOM_SEED; pnl_rand_init (gen, 1, 1); x = pnl_vect_create (n); y = pnl_vect_create (n); pnl_vect_rand_normal (x, n, gen); M = create_random_tridiag (n, gen); FM = pnl_tridiag_mat_to_mat (M); pnl_tridiag_mat_mult_vect_inplace (y, M, x); Fy = pnl_mat_mult_vect (FM, x); pnl_test_vect_eq_abs (y, Fy, 1E-18, "tridiag_mat_mutl_vect", ""); pnl_vect_free (&x); pnl_vect_free (&y); pnl_vect_free (&Fy); pnl_mat_free (&FM); pnl_tridiag_mat_free (&M); }
static void tridiag_lAxpby_test () { PnlVect *y, *x, *Fy; PnlTridiagMat *M; PnlMat *FM; int n = 5; int gen = PNL_RNG_MERSENNE_RANDOM_SEED; pnl_rand_init (gen, 1, 1); x = pnl_vect_create (n); y = pnl_vect_create (n); pnl_vect_rand_normal (x, n, gen); pnl_vect_rand_normal (y, n, gen); Fy = pnl_vect_copy (y); M = create_random_tridiag (n, gen); FM = pnl_tridiag_mat_to_mat (M); pnl_tridiag_mat_lAxpby (1.5, M, x, 3., y); pnl_mat_lAxpby (1.5, FM, x, 3., Fy); pnl_test_vect_eq_abs (y, Fy, 1E-12, "tridiag_mat_lAxpby", ""); pnl_vect_free (&x); pnl_vect_free (&y); pnl_vect_free (&Fy); pnl_mat_free (&FM); pnl_tridiag_mat_free (&M); }
/* * example of how to use pnl_basis_fit_ls to regress on a basis. * regression of the exponential function on the grid [0:0.05:5] */ static void exp_regression2() { int n, basis_name, basis_dim, space_dim; int i; double a, b, h, err; PnlMat *t; PnlVect *y; PnlVect *alpha; PnlBasis *basis; alpha = pnl_vect_create (0); /* creating the grid */ a=0.0; b=5.0; n = 100; h = (b-a)/n; t = pnl_mat_create_from_double (n+1, 1, h); pnl_mat_set (t, 0, 0, 0.0); pnl_mat_cumsum (t, 'r'); /* creating the values of exp on the grid */ y = pnl_vect_create (n+1); for ( i=0 ; i<n+1 ; i++ ) { pnl_vect_set (y, i, function(pnl_mat_get(t, i, 0))); } basis_name = PNL_BASIS_HERMITIAN; /* PNL_BASIS_TCHEBYCHEV; */ space_dim = 1; /* real valued basis */ basis_dim = 5; /* number of elements in the basis */ basis = pnl_basis_create (basis_name, basis_dim, space_dim); pnl_basis_fit_ls (basis, alpha, t, y); if ( verbose ) { printf("coefficients of the decomposition : "); pnl_vect_print (alpha); } /* computing the infinity norm of the error */ err = 0.; for (i=0; i<t->m; i++) { double tmp = function(pnl_mat_get(t, i, 0)) - pnl_basis_eval (basis,alpha, pnl_mat_lget(t, i, 0)); if (fabs(tmp) > err) err = fabs(tmp); } pnl_test_eq_abs (err, 1.812972, 1E-5, "pnl_basis_eval", "exponential function on [0:0.05:5]"); pnl_basis_free (&basis); pnl_mat_free (&t); pnl_vect_free (&y); pnl_vect_free (&alpha); }
static void test_hybrX () { int j, n, maxfev, info, nfev; double xtol, fnorm; PnlVect *x, *fvec, *diag; PnlRnFuncRnDFunc f; n = 9; x = pnl_vect_create (n); fvec = pnl_vect_create (n); diag = pnl_vect_create (n); /* the following starting values provide a rough solution. */ pnl_vect_set_double (x, -1); /* default value for xtol */ xtol = 0; maxfev = 2000; pnl_vect_set_double (diag, 1); /* * Test without Jacobian */ printf ("Test of pnl_root_fsolve without user supplied Jacobian.\n\n"); f.function = fcn_fsolve; f.Dfunction = NULL; f.params = NULL; info = pnl_root_fsolve (&f, x, fvec, xtol, maxfev, &nfev, diag, FALSE); fnorm = pnl_vect_norm_two(fvec); printf(" final l2 norm of the residuals %15.7g\n\n", fnorm); printf(" number of function evaluations %10i\n\n", nfev); printf(" exit parameter %10i\n\n", info); printf(" final approximate solution\n"); for (j=1; j<=n; j++) printf("%s%15.7g", j%3==1?"\n ":"", GET(x,j-1)); printf("\n\n"); /* * Test with Jacobian */ printf ("Test of pnl_root_fsolve without user supplied Jacobian.\n\n"); f.function = fcn_fsolve; f.Dfunction = Dfcn_fsolve; f.params = NULL; info = pnl_root_fsolve (&f, x, fvec, xtol, maxfev, &nfev, diag, FALSE); fnorm = pnl_vect_norm_two(fvec); printf(" final l2 norm of the residuals %15.7g\n\n", fnorm); printf(" number of function evaluations %10i\n\n", nfev); printf(" exit parameter %10i\n\n", info); printf(" final approximate solution\n"); for (j=1; j<=n; j++) printf("%s%15.7g", j%3==1?"\n ":"", GET(x,j-1)); printf("\n\n"); pnl_vect_free (&x); pnl_vect_free (&fvec); pnl_vect_free (&diag); }
static void test_lmdif () { int m, n, info, nfev, maxfev; double tol, fnorm; PnlVect *x, *fvec; PnlRnFuncRmDFunc f; m = 15; n = 3; x = pnl_vect_create (n); fvec = pnl_vect_create (m); /* the following starting values provide a rough fit. */ pnl_vect_set_double (x, 1.); /* default vlaues */ tol = 0; maxfev = 0; /* * Test without user supplied Jacobian */ printf ("Test of pnl_root_fsolve_lsq without user supplied Jacobian.\n\n"); f.function = fcn_lsq; f.Dfunction = NULL; f.params = NULL; info = pnl_root_fsolve_lsq(&f, x, m, fvec, tol, tol, 0., maxfev, &nfev, NULL, TRUE); fnorm = pnl_vect_norm_two(fvec); printf(" final l2 norm of the residuals%15.7f\n\n",fnorm); printf(" exit parameter %10i\n\n", info); printf(" final approximate solution\n\n %15.7f%15.7f%15.7f\n\n", GET(x,0), GET(x,1), GET(x,2)); /* * Test with user supplied Jacobian */ printf ("Test of pnl_root_fsolve_lsq with user supplied Jacobian.\n\n"); f.function = fcn_lsq; f.Dfunction = Dfcn_lsq; f.params = NULL; info = pnl_root_fsolve_lsq(&f, x, m, fvec, tol, tol, 0., maxfev, &nfev, NULL, TRUE); fnorm = pnl_vect_norm_two(fvec); printf(" final l2 norm of the residuals%15.7f\n\n",fnorm); printf(" exit parameter %10i\n\n", info); printf(" final approximate solution\n\n %15.7f%15.7f%15.7f\n\n", GET(x,0), GET(x,1), GET(x,2)); pnl_vect_free (&x); pnl_vect_free (&fvec); }
int DeleteZCMarketData(ZCMarketData* ZCMarket) { if(ZCMarket->FlatOrMarket!=0) { pnl_vect_free(&(ZCMarket->tm)); pnl_vect_free(&(ZCMarket->Pm)); } return 1; }
static PnlTridiagMat* create_random_tridiag (n, gen) { PnlVect *dl, *du, *d; PnlTridiagMat *M; d = pnl_vect_create (n); du = pnl_vect_create (n); dl = pnl_vect_create (n); pnl_vect_rand_uni (d, n, 0., 1., gen); pnl_vect_rand_uni (du, n-1, 0., 1., gen); pnl_vect_rand_uni (dl, n-1, 0., 1., gen); M = pnl_tridiag_mat_create_from_ptr (n, dl->array, d->array, du->array); pnl_vect_free (&d); pnl_vect_free (&dl); pnl_vect_free (&du); return M; }
static int ap_carmonadurrleman(PnlVect *BS_Spot, NumFunc_nd *p, double OP_Maturity, double BS_Interest_Rate, PnlVect *BS_Dividend_Rate, PnlVect *BS_Volatility, double rho, double *LowerPrice, PnlVect *LowerDelta) { int BS_Dimension = BS_Spot->size; int put_or_call; PnlVect *Weights = pnl_vect_create_from_double (BS_Dimension, 1./BS_Dimension); double Strike=p->Par[0].Val.V_DOUBLE; *LowerPrice=0.; if ((p->Compute)==&CallBasket_nd) put_or_call=0; else put_or_call=1; lower_basket(put_or_call,BS_Dimension,BS_Volatility,Weights,BS_Spot,BS_Dividend_Rate,rho,BS_Interest_Rate,Strike,OP_Maturity,LowerPrice,LowerDelta); /*upper_basket(put_or_call,BS_Dimension,BS_Volatility->array,Weights,BS_Spot->array,BS_Dividend_Rate->array,rho,BS_Interest_Rate,Strike,OP_Maturity,Prixsup,Deltassup);*/ pnl_vect_free (&Weights); return OK; }
static void derive_approx_fonction(PnlBasis *B, PnlVect *D, PnlVect *alpha, double t, double x) { double sum0, sum1, sum2, sum3; double arg[2]; PnlMat *Hes = pnl_mat_new(); PnlVect *grad = pnl_vect_new(); arg[0] = t; arg[1] = x; sum0=0.0;//calcule la valeur de la fonction sum1=0.0;//calcule la valeur de sa derivee en x sum2=0.0;//calcule la valeur de sa derivee seconde en x sum3=0.0;//calcule la valeur de sa derivee en t /* sum0 = pnl_basis_eval (B, alpha, arg); * sum1 = pnl_basis_eval_D (B, alpha, arg, 1); * sum2 = pnl_basis_eval_D2 (B, alpha, arg, 1, 1); * sum3 = pnl_basis_eval_D (B, alpha, arg, 0); * * LET(D,0)=sum0; * LET(D,1)=sum1; * LET(D,2)=sum2; * LET(D,3)=sum3; */ pnl_basis_eval_derivs (B, alpha, arg, &sum0, grad, Hes); LET(D,3) = GET(grad,0); LET(D,1) = GET(grad,1); LET(D,0) = sum0; LET(D,2) = PNL_MGET(Hes, 1, 1); LET(D,4) = PNL_MGET(Hes, 0, 1); pnl_mat_free (&Hes); pnl_vect_free (&grad); }
static void prix(PnlMat *res, PnlMat *res_no_call, int M, int N, PnlMat *asset, PnlVectInt *res_theta, double spot, double T, param *P, PnlBasis *basis) { int i,j; double Sij,mu_ij,v0; PnlVect *Si,*V_iplus1,*alpha, *c_iplus1;//(ligne i de la matrice) PnlMat MSi; double h=T/N; Si=pnl_vect_new(); c_iplus1=pnl_vect_create(M); alpha=pnl_vect_new(); V_iplus1=pnl_vect_new(); pnl_mat_resize(res,N+1,M); prix_no_call(res_no_call,M,N,asset,spot,T,P,basis); for(j=0;j<M;j++) pnl_mat_set(res,N,j,(pnl_mat_get(res_no_call,N,j))); for(i=N-1;i>=1;i--) { for(j=0;j<M;j++) pnl_vect_set(c_iplus1,j,c(pnl_mat_get(asset,i+1,j),spot,P)*h); pnl_mat_get_row(Si,asset,i); pnl_vect_mult_double(Si,1.0/spot); pnl_mat_get_row(V_iplus1,res,i+1); pnl_vect_plus_vect(V_iplus1,c_iplus1); MSi = pnl_mat_wrap_vect(Si); pnl_basis_fit_ls(basis,alpha,&MSi,V_iplus1); for(j=0;j<M;j++) { Sij=pnl_mat_get(asset,i,j)/spot; mu_ij=mu(spot,spot*Sij,P); if(i>=pnl_vect_int_get(res_theta,j)) { pnl_mat_set(res,i,j,pnl_mat_get(res_no_call,i,j));} else pnl_mat_set(res,i,j,MAX(low(spot*Sij,P),exp(-mu_ij*h)*pnl_basis_eval(basis,alpha,&Sij))); } } pnl_mat_get_row(V_iplus1,res,1); for(j=0;j<M;j++) pnl_vect_set(c_iplus1,j,c(pnl_mat_get(asset,1,j),spot,P)*h); pnl_vect_plus_vect(V_iplus1,c_iplus1); v0=pnl_vect_sum(V_iplus1)/M; v0=MAX(low(spot,P),exp(-mu(spot,spot,P)*h)*v0); for(j=0;j<M;j++) { if(pnl_vect_int_get(res_theta,j)==0) pnl_mat_set(res,0,j,pnl_mat_get(res_no_call,i,j)); else pnl_mat_set(res,0,j,v0); } pnl_vect_free(&Si); pnl_vect_free(&c_iplus1); pnl_vect_free(&V_iplus1); pnl_vect_free(&alpha); }
static int Free_AndersenStruct(AndersenStruct *andersen_struct) { pnl_mat_free(&(andersen_struct->DiscountedPayoff)); pnl_mat_free(&(andersen_struct->NumeraireValue)); pnl_vect_free(&(andersen_struct->AndersenParams)); pnl_vect_int_free(&(andersen_struct->AndersenIndices)); return OK; }
/** * compute the sum of all element in the row of matrix * * @param[in] mat matrix * @param[in] nb_row the number of row * @return sum of all element in the row of matrix * */ static double sum_row_matrix(const PnlMat* mat,int nb_row) { double result; PnlVect* V=pnl_vect_create(mat->m); pnl_mat_get_row(V,mat,nb_row); result= pnl_vect_sum(V); pnl_vect_free(&V); return result; }
static double f1dim( double x) { int j; double val; PnlVect * xt = pnl_vect_create (_n); for(j=0; j<_n; j++){ pnl_vect_set (xt, j, pnl_vect_get (_p, j) + x * pnl_vect_get (_dir, j)); } val=func(xt); pnl_vect_free (&xt); return val; }
/// Prix at time s of an option, maturing at T, on a ZC, with maturity S, using a trinomial tree. double tr_bk1d_zcoption(TreeShortRate* Meth, ModelParameters* ModelParam, ZCMarketData* ZCMarket, double T, double S, NumFunc_1 *p, double r, int Eur_Or_Am) { int i_T; double OptionPrice; PnlVect* OptionPriceVect1; // Vector of prices of the option at time i PnlVect* OptionPriceVect2; // Vector of prices of the option at time i+1 PnlVect* ZCbondPriceVect1; // Vector of prices of the option at time i PnlVect* ZCbondPriceVect2; // Vector of prices of the option at time i+1 OptionPriceVect1 = pnl_vect_create(1); OptionPriceVect2 = pnl_vect_create(1); ZCbondPriceVect1 = pnl_vect_create(1); ZCbondPriceVect2 = pnl_vect_create(1); ///****************** Computation of the vector of payoff at the maturity of the option *******************/// i_T = IndexTime(Meth, T); // Localisation of s on the tree ZCBond_InitialPayoffBK1D(Meth, ZCbondPriceVect2); ZCOption_BackwardIterationBK1D(Meth, ModelParam, ZCbondPriceVect1, ZCbondPriceVect2, ZCbondPriceVect1, ZCbondPriceVect2, Meth->Ngrid, i_T, p, 0); ZCOption_InitialPayoffBK1D(ZCbondPriceVect2, OptionPriceVect2, p); ///****************** Backward computation of the option price until initial time s *******************/// ZCOption_BackwardIterationBK1D(Meth, ModelParam, ZCbondPriceVect1, ZCbondPriceVect2, OptionPriceVect1, OptionPriceVect2, i_T, 0, p, Eur_Or_Am); OptionPrice = GET(OptionPriceVect1, 0); pnl_vect_free(& OptionPriceVect1); pnl_vect_free(& OptionPriceVect2); pnl_vect_free(& ZCbondPriceVect1); pnl_vect_free(& ZCbondPriceVect2); return OptionPrice; }// FIN de la fonction ZCOption
// Conjugate gradient optimization of function f, given its gradient gradf. // Minimum is stored in min, its location in p. Tolerance is asked : static void optigc(int dim, PnlVect *p, double tol, double *min, double f(PnlVect *), void gradf(PnlVect *, PnlVect *)) { int i, j; /* Scalars used to define directions */ double gg,gam,fp,dgg; PnlVect *g = pnl_vect_create (dim); /* Auxiliary direction : gradient at the minimum */ PnlVect *h = pnl_vect_create (dim); /* Conjugate direction along which to minimize */ PnlVect *grad = pnl_vect_create (dim); /* Gradient */ const int ITMAX = 20000; const double EPS = 1.0e-18; fp=f(p); gradf(p,grad); pnl_vect_clone (h, grad); pnl_vect_clone (g, grad); pnl_vect_mult_double (h ,-1.0); pnl_vect_mult_double (g ,-1.0); pnl_vect_mult_double (grad ,-1.0); for(i=0; i<ITMAX; i++) { min1dir(dim,p,h,min,f); // Minimizing along direction h if(2.0*fabs((*min)-fp) <= tol*(fabs((*min))+fabs(fp)+EPS)) // Done : tolerance reached { pnl_vect_free (&g); pnl_vect_free (&h); pnl_vect_free (&grad); return; } fp=(*min); gradf(p,grad); // Computes gradient at point p, location of minimum dgg=gg=0.0; /* Computes coefficients applied to new direction for h */ gg = pnl_vect_scalar_prod (g, g); /* Denominator */ dgg = pnl_vect_scalar_prod (grad, grad) + pnl_vect_scalar_prod (g, grad); /* Numerator : Polak-Ribiere */ if(gg==0.0) // Gradient equals zero : done { pnl_vect_free (&g); pnl_vect_free (&h); pnl_vect_free (&grad); return; } gam=dgg/gg; for(j=0; j<dim; j++){ // Defining directions for next iteration pnl_vect_set (g, j, - pnl_vect_get (grad, j)); pnl_vect_set (h, j, pnl_vect_get (g, j)+gam * pnl_vect_get (h, j)); } } perror ("Too many iterations in optigc\n"); }
static void tridiag_syslin_test () { PnlVect *b, *x, *Mx; PnlTridiagMat *M, *Mcopy; int n = 5; int gen = PNL_RNG_MERSENNE_RANDOM_SEED; pnl_rand_init (gen, 1, 1); x = pnl_vect_create (n); b = pnl_vect_create (n); pnl_vect_rand_normal (b, n, gen); M = create_random_tridiag (n, gen); Mcopy = pnl_tridiag_mat_copy (M); pnl_tridiag_mat_syslin (x, M, b); Mx = pnl_tridiag_mat_mult_vect (Mcopy, x); pnl_test_vect_eq_abs (Mx, b, 1E-12, "tridiag_mat_syslin", ""); pnl_vect_free (&x); pnl_vect_free (&Mx); pnl_vect_free (&b); pnl_tridiag_mat_free (&M); pnl_tridiag_mat_free (&Mcopy); }
/// Backward computation of the price of a Zero Coupon Bond static void ZCBond_BackwardIterationCIRpp1D(TreeCIRpp1D* Meth, ModelCIRpp1D* ModelParam, ZCMarketData* ZCMarket, PnlVect* OptionPriceVect1, PnlVect* OptionPriceVect2, int index_last, int index_first) { double a, b, sigma; double delta_t, sqrt_delta_t; double current_rate, current_x, x_middle; int i, h; int NumberNode, index; PnlVect* Probas; Probas = pnl_vect_create(3); ///********* Model parameters *********/// a = (ModelParam->MeanReversion); b = (ModelParam->LongTermMean); sigma = (ModelParam->Volatility); delta_t = GET(Meth->t, 1) - GET(Meth->t,0); // = t[i] - t[i-1] sqrt_delta_t = sqrt(delta_t); for(i = index_last-1; i>=index_first; i--) { NumberNode = (int) ((GET(Meth->Xmax, i) - GET(Meth->Xmin, i)) / (Meth->delta_x) + 0.1); pnl_vect_resize(OptionPriceVect1, NumberNode +1); // OptionPriceVect1 := Price of the bond in the tree at time t(i) // Loop over the node at the time i for(h = 0 ; h<= NumberNode ; h++) { current_x = x_value(i, h, Meth); current_rate = R(current_x, sigma) + GET(Meth->alpha,i); x_middle = MiddleNode(Meth, i, a, b, sigma, current_x, sqrt_delta_t, Probas); index = (int) ((x_middle-GET(Meth->Xmin,i+1))/(Meth->delta_x) + 0.1); LET(OptionPriceVect1,h) = exp(-current_rate*delta_t) * ( GET(Probas,2) * GET(OptionPriceVect2, index+1) + GET(Probas,1) * GET(OptionPriceVect2, index) + GET(Probas,0) * GET(OptionPriceVect2, index-1)); // Backward computation of the bond price } pnl_vect_clone(OptionPriceVect2, OptionPriceVect1); // Copy OptionPriceVect1 in OptionPriceVect2 } // END of the loop on i (time) pnl_vect_free(&Probas); }
double Barrier::payoff(const PnlMat *path) { PnlVect * lastrow = pnl_vect_new(); pnl_mat_get_row(lastrow, path, TimeSteps_-1); double prod = pnl_vect_scalar_prod(lastrow, payOffCoeff_) - S_; pnl_vect_free(&lastrow); if (std::max(prod,0.0) == 0.0) { return 0.0; } for (int i = 0; i < size_; i++) { for (int j = 0; j < TimeSteps_; j++) { if (MGET(path, j, i) < GET(lowerBarrier_, i) || MGET(path, j, i) > GET(upperBarrier_, i)) { return 0.0; } } } return prod; }
/* Approximation of the call/put function by a polynomial*/ static int pol_approx(NumFunc_1 *p,PnlVect *coeff, double S0, double K, int Nb_Degree_Pol) { /* Input: NumFunc_1 *p specifies the payoff function (Call or Put), PnlVect *coeff is of dimension Nb_Degree_Pol+1, S0 initial value to determine the interval where the approximation is done, K strike, Nb_Degree_Pol corresponds to the degree of the approximating polynomial. The coefficients of the polynomial approximating the Call/Put payoff function are calculated and stored in coeff in increasing order starting with the coefficient corresponding to degree 0. */ PnlMat *x; PnlVect *y; PnlBasis *f; int dim; int j; dim=(int)((log(S0*10)-log(S0/10))/0.01+0.5); /* [log(S0/10), log(S0*10)] is the interval of approximation*/ x=pnl_mat_create_from_double(dim,1,0.); y=pnl_vect_create_from_double(dim,0.); MLET(x,0,0)=log(S0/10); LET(y,0)=(p->Compute)(p->Par,S0/10.); for(j=1;j<dim;j++) { MLET(x,j,0)=MGET(x,j-1,0)+0.01; /* grid of equally spaced points with distance 0.01 in interval [log(S0/10), log(S0*10)] */ LET(y,j)=(p->Compute)(p->Par,exp(MGET(x,j,0))); /* evaluation of the payoff function at x */ } f=pnl_basis_create(PNL_BASIS_CANONICAL,Nb_Degree_Pol+1,1); pnl_basis_fit_ls(f,coeff,x,y); pnl_basis_free (&f); pnl_mat_free(&x); pnl_vect_free(&y); return 1.; }
/*Matrix correponding to infinitesimal generator of the Bates model */ static int matrix_computation(PnlMat *A, int m, double r, double divid, double kappa, double theta, double lambda, double mu, double gamma2, double sigmav, double rho) { /* Input: PnlMat *A is of dimension (m+1)(m+2)/2 x (m+1)(m+2)/2, m corresponds to the degree of the polynomial, other parameters are the inputs of the Bates model. The procedure calculates the matrix corresponding to the infinitesimal generator of a Bates model applied to the polynomials x^iv^j, (i+j)<=m, where x corresponds to the logprice and v to the variance. It is stored in A. */ int i,j,k,row,column; PnlVect *c; c=pnl_vect_create_from_double(m,0.); moments_normal(c,m,mu,gamma2); for(i=0;i<m+1;i++) { for(j=0;j<m-i+1;j++) { row=(i+j)*(i+j+1)/2+j; for(k=2;k<i+1;k++) { column=(i-k+j)*(i-k+j+1)/2+j; MLET(A,row,column)=(double) pnl_sf_choose (i, k)*GET(c,k-1)*lambda; } if (i >0) { MLET(A,row,((i-1+j)*(i+j)/2+j))=i*(r-divid+lambda*(mu-exp(mu+gamma2/2)+1)+j*sigmav*rho); MLET(A,row,((i+j)*(i+j+1)/2+j+1))=-(double)i/2; } MLET(A,row,((i+j)*(i+j+1)/2+j))=-j*kappa; if (j >0) { MLET(A,row,((i+j-1)*(i+j)/2+j-1))=j*(kappa*theta+(j-1)*sigmav*sigmav/2); } if (i >1) { MLET(A,row,((i+j-1)*(i+j)/2+j+1))=(double)i*((double)i-1)/2; } } } pnl_vect_free(&c); return 1.; }
// Computes the price and the deltas of a claim using the lower bound of the // price for an option // that is paying a linear combination of assets : static void lowlinearprice(int _dim, PnlVect *_eps, PnlVect *_x, PnlMat *_rac_C, PnlVect *_sigma, double _echeance, double *prix, PnlVect *deltas) { int i, j; double arg; double normv=0; double tol=1e-15; PnlVect *xopt = pnl_vect_create_from_double ( _dim+2, 1./sqrt(_dim+1.)); // Starting point for optimization : normalized vector pnl_vect_set (xopt, _dim+1, 0.0); // Initializing global variables to parameters of the problem Dim=_dim; Echeance=_echeance; Sigma = _sigma; Rac_C = _rac_C; Eps = _eps; X = _x; optigc(Dim+2,xopt,tol,prix,Cost,Gradcost); *prix = -1.0* (*prix); // Price is the maximum of function for (i=0; i<Dim+1; i++) { double xopt_i = pnl_vect_get (xopt, i); normv += xopt_i * xopt_i; } normv = sqrt (normv); for(i=0; i<Dim; i++){ double tmp=0; for(j=0; j<Dim+1; j++){ tmp+=pnl_mat_get (_rac_C, i+1, j) * pnl_vect_get (xopt, j); } arg=pnl_vect_get (xopt, Dim+1) + pnl_vect_get (Sigma, i+1) * tmp*sqrt(Echeance)/normv; pnl_vect_set (deltas, i, pnl_vect_get (Eps, i+1) * cdf_nor(arg)); // Computing the deltas } pnl_vect_free (&xopt); }
Barrier_u :: ~Barrier_u(){ pnl_vect_free(&Bu_); }
static void pnl_basis_eval_test () { PnlMat *X; PnlVect *V, *x, *t, *D, *alpha, *lower, *upper; PnlRng *rng; PnlBasis *basis; int j, deg, n; double t0, x0, tol; tol = 1E-8; deg=5; //total degree n=50; D=pnl_vect_create(5); x=pnl_vect_create(n); t=pnl_vect_create(n); t0=0.5; x0=2.5; rng = pnl_rng_create (PNL_RNG_MERSENNE); pnl_rng_sseed (rng, 0); /* * Random points where the function will be evaluted */ pnl_vect_rng_uni(x,n,-5,4,rng); pnl_vect_rng_uni(t,n,0,1,rng); basis = pnl_basis_create_from_degree (PNL_BASIS_HERMITIAN, deg, 2); alpha = pnl_vect_create (basis->nb_func); X = pnl_mat_create (n, 2); for(j=0;j<n;j++) { MLET (X, j, 0) = GET(t,j); MLET (X, j, 1) = GET(x,j); } V=pnl_vect_create(n); /* * Vector of values for the function to recover */ for(j=0;j<n;j++) { LET(V,j)=fonction_a_retrouver(GET(t,j),GET(x,j)); } pnl_basis_fit_ls (basis, alpha, X, V); /* * compute approximations of the derivatives (first order in time and * second order in space ) */ derive_approx_fonction(basis, D, alpha,t0,x0); pnl_test_eq_abs (pnl_vect_get(D,0), fonction_a_retrouver(t0,x0), tol, "deriv_approx_fonction", "derivative 0"); pnl_test_eq_abs (derive_x_approx_fonction(basis, alpha, t0, x0), derive_x_fonction_a_retrouver(t0,x0), tol, "deriv_approx_fonction", "derivative %% x"); pnl_test_eq_abs (pnl_vect_get(D,2), derive_xx_fonction_a_retrouver(t0,x0), tol, "deriv_approx_fonction", "derivative %% xx"); pnl_test_eq_abs (pnl_vect_get(D,3), derive_t_fonction_a_retrouver(t0,x0), tol, "deriv_approx_fonction", "derivative %% t"); pnl_test_eq_abs (pnl_vect_get(D,4), derive_xt_fonction_a_retrouver(t0,x0), tol, "deriv_approx_fonction", "derivative %% tx"); pnl_basis_free (&basis); /* reduced basis */ basis = pnl_basis_create_from_degree (PNL_BASIS_HERMITIAN, deg, 2); lower = pnl_vect_create_from_list (2, 0., -5.); upper = pnl_vect_create_from_list (2, 1., 4.); pnl_basis_set_domain (basis, lower, upper); pnl_basis_fit_ls (basis, alpha, X, V); derive_approx_fonction(basis, D, alpha,t0,x0); pnl_test_eq_abs (pnl_vect_get(D,0), fonction_a_retrouver(t0,x0), tol, "deriv_approx_fonction (reduced)", "derivative 0"); pnl_test_eq_abs (derive_x_approx_fonction(basis, alpha, t0, x0), derive_x_fonction_a_retrouver(t0,x0), tol, "deriv_approx_fonction (reduced)", "derivative %% x"); pnl_test_eq_abs (pnl_vect_get(D,2), derive_xx_fonction_a_retrouver(t0,x0), tol, "deriv_approx_fonction (reduced)", "derivative %% xx"); pnl_test_eq_abs (pnl_vect_get(D,3), derive_t_fonction_a_retrouver(t0,x0), tol, "deriv_approx_fonction (reduced)", "derivative %% t"); pnl_test_eq_abs (pnl_vect_get(D,4), derive_xt_fonction_a_retrouver(t0,x0), tol, "deriv_approx_fonction (reduced)", "derivative %% tx"); pnl_basis_free (&basis); pnl_rng_free (&rng); pnl_vect_free(&alpha); pnl_vect_free(&x); pnl_vect_free(&t); pnl_vect_free(&V); pnl_vect_free(&D); pnl_vect_free(&lower); pnl_vect_free(&upper); pnl_mat_free(&X); }
static void regression_multid() { int n, basis_name, nb_func, nb_variates, degree; int i, j; double a, b, h, err; PnlMat *t; PnlVect *y; PnlVect *alpha; PnlBasis *basis; alpha = pnl_vect_create (0); /* creating the grid */ a=-2.0; b=2.0; n = 100; h = (b-a)/n; t = pnl_mat_create ((n+1)*(n+1), 2); /* creating the values of exp on the grid */ y = pnl_vect_create ((n+1)*(n+1)); for (i=0; i<n+1; i++) { for (j=0; j<n+1; j++) { pnl_mat_set (t, i*(n+1)+j, 0, a + i * h); pnl_mat_set (t, i*(n+1)+j, 1, a + j * h); pnl_vect_set (y, i*(n+1)+j, function2d(pnl_mat_lget(t, i*(n+1)+j, 0))); } } basis_name = PNL_BASIS_HERMITIAN; nb_variates = 2; /* functions with values in R^2 */ nb_func = 15; /* number of elements in the basis */ basis = pnl_basis_create (basis_name, nb_func, nb_variates); pnl_basis_fit_ls (basis, alpha, t, y); if ( verbose ) { printf("coefficients of the decomposition : "); pnl_vect_print (alpha); } /* computing the infinity norm of the error */ err = 0.; for (i=0; i<t->m; i++) { double tmp = function2d(pnl_mat_lget(t, i, 0)) - pnl_basis_eval (basis,alpha, pnl_mat_lget(t, i, 0)); if (fabs(tmp) > err) err = fabs(tmp); } pnl_test_eq_abs (err, 0.263175, 1E-5, "pnl_basis_eval", "log (1+x[0]*x[0] + x[1]*x[1]) on [-2,2]^2"); pnl_basis_free (&basis); degree = 4; /* total sum degree */ basis = pnl_basis_create_from_degree (basis_name, degree, nb_variates); pnl_basis_fit_ls (basis, alpha, t, y); if ( verbose ) { printf("coefficients of the decomposition : "); pnl_vect_print (alpha); } /* computing the infinity norm of the error */ err = 0.; for (i=0; i<t->m; i++) { double tmp = function2d(pnl_mat_lget(t, i, 0)) - pnl_basis_eval (basis,alpha, pnl_mat_lget(t, i, 0)); if (fabs(tmp) > err) err = fabs(tmp); } pnl_test_eq_abs (err, 0.263175, 1E-5, "pnl_basis_eval (sum degree)", "log (1+x[0]*x[0] + x[1]*x[1]) on [-2,2]^2"); pnl_basis_free (&basis); degree = 4; /* total product degree */ basis = pnl_basis_create_from_prod_degree (basis_name, degree, nb_variates); pnl_basis_fit_ls (basis, alpha, t, y); if ( verbose ) { printf("coefficients of the decomposition : "); pnl_vect_print (alpha); } /* computing the infinity norm of the error */ err = 0.; for (i=0; i<t->m; i++) { double tmp = function2d(pnl_mat_lget(t, i, 0)) - pnl_basis_eval (basis,alpha, pnl_mat_lget(t, i, 0)); if (fabs(tmp) > err) err = fabs(tmp); } pnl_test_eq_abs (err, 0.263175, 1E-5, "pnl_basis_eval (prod degree)", "log (1+x[0]*x[0] + x[1]*x[1]) on [-2,2]^2"); pnl_basis_free (&basis); pnl_mat_free (&t); pnl_vect_free (&y); pnl_vect_free (&alpha); }
/// 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; }