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; }
/*Moments of normal distribution*/ static int moments_normal(PnlVect *c, int m, double mu, double gamma2) { /* Input: PnlVect *c is of dimension m, mu=mean of normal distribution, gamma2=variance of normal distribution. The moments of the normal distribution with mean mu and variance gamma2 up to degree m are calculated and stored in c. */ int i,j,n,index1; PnlMat *a; index1=(int)(m/2+1.); LET(c,0)=mu; a=pnl_mat_create_from_double(m,index1,0.); for(j=0;j<m;j++) { MLET(a,j,0)=1; } for(i=2;i<m+1;i++) { index1=(int)(i/2+1.); for (n=2;n<=index1;n++) { MLET(a,i-1,n-1)=MGET(a,i-2,n-2)*(i-1-2*(n-1)+2)+MGET(a,i-2,n-1); LET(c,i-1)=GET(c,i-1)+MGET(a,i-1,n-1)*pow(mu, (double) i-2.*(double) n+2.)*pow(sqrt(gamma2), 2*(double)n-2.); } LET(c,i-1)=GET(c,i-1)+ pow (mu,(double)i); } pnl_mat_free (&a); return 1.; }
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 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); }
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); }
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); }
/* * 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 double prix_highly_path_dependent_protection(int M, int N, int N_trading, double spot, double T, int gen, int bindex, int m, param *P) { PnlMat *asset; PnlBasis *basis; double sol; basis=pnl_basis_create(bindex, m, 1); asset=pnl_mat_new(); simul_asset(asset,M,N,spot,T,P,gen); prix_en_0_ls(&sol,asset,M,N,N_trading,spot,T,P,basis); pnl_basis_free(&basis); pnl_mat_free(&asset); return sol; }
TEST (OptionAsian2, Payoff) { double strike=3.0; double T=10.0; int TimeSteps=5; int size=10; PnlMat *mat= pnl_mat_create_from_list(6,1,1.0,1.0,1.0,1.0,1.0,1.0); OptionAsian O=OptionAsian(T,TimeSteps,size,strike); double payoff = O.payoff(mat); pnl_mat_free(&mat); ASSERT_EQ(payoff,0.0); }
/* 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.; }
static void load_rng_array (PnlMat *orig) { int i, j; PnlRng **rngtab; PnlMat *res; rngtab = pnl_rng_create_from_file (binfile, NB_GEN); res = pnl_mat_create (NB_GEN, NB_INT); for ( i=0 ; i<NB_GEN ; i++ ) { for ( j=0 ; j<NB_INT ; j++ ) MLET(res, i, j) = pnl_rng_uni (rngtab[i]); pnl_rng_free (&(rngtab[i])); } pnl_test_mat_eq_abs (res, orig, 1E-10, "Save / Load (rng array)", ""); pnl_mat_free (&res); free(rngtab); unlink(binfile); }
static int load_rng (PnlMat *orig) { PnlRng *rng1, *rng2; PnlList *L; PnlMat *res; FILE *stream; int i; res = pnl_mat_create (2, NB_INT); stream = fopen (binfile, "rb"); rng1 = PNL_RNG_OBJECT(pnl_object_load (stream)); rng2 = PNL_RNG_OBJECT(pnl_object_load (stream)); fclose (stream); for ( i=0 ; i<NB_INT ; i++ ) MLET(res, 0, i) = pnl_rng_uni (rng1); pnl_rng_free (&rng1); for ( i=0 ; i<NB_INT ; i++ ) MLET(res, 1, i) = pnl_rng_uni (rng2); pnl_rng_free (&rng2); pnl_test_mat_eq_abs (res, orig, 1E-10, "Save / Load (object)", ""); stream = fopen (binfile, "rb"); L = pnl_object_load_into_list (stream); fclose (stream); rng1 = PNL_RNG_OBJECT(pnl_list_get (L, 0)); rng2 = PNL_RNG_OBJECT(pnl_list_get (L, 1)); for ( i=0 ; i<NB_INT ; i++ ) MLET(res, 0, i) = pnl_rng_uni (rng1); for ( i=0 ; i<NB_INT ; i++ ) MLET(res, 1, i) = pnl_rng_uni (rng2); pnl_test_mat_eq_abs (res, orig, 1E-10, "Save / Load (into list)", ""); pnl_mat_free (&res); pnl_list_free (&L); unlink(binfile); return MPI_SUCCESS; }
int main (int argc, char **argv) { PnlRngType t; PnlMat *orig; pnl_test_init (argc, argv); orig = pnl_mat_new(); MPI_Init (&argc, &argv); t = PNL_RNG_MERSENNE; save_rng(t, orig); load_rng(orig); save_rng_array(orig); load_rng_array(orig); MPI_Finalize(); pnl_mat_free (&orig); exit (pnl_test_finalize("Save/Load interface")); }
/** * Inverse Laplace transform * Optimal linear combination for the Gaver Stehfest's method. * Unlike the Euler method, the inversion is here performed on the real line * * @param fhat the real valued Laplace transform of f * @param t the point at which f is to be recovered * @param n the number of iterations of the method * @return f(t) */ double pnl_ilap_gs (PnlFunc *fhat, double t, int n) { int k; double f, Cnk; PnlMat *work; PnlMatInt *iwork; f = 0.; Cnk = 1. / pnl_fact (n-1); work = pnl_mat_create (2 * n, n+1); iwork = pnl_mat_int_create_from_int (2 * n, n+1, 0); for ( k=1 ; k<n+1 ; k++ ) { f += ALTERNATE(n-k) * pow(k, n) * Cnk * f_tilde (fhat, work, iwork, k, t, k); Cnk = (Cnk * (n - k)) / (k + 1); } pnl_mat_free (&work); pnl_mat_int_free (&iwork); return f; }
//simulation par schéma d'euler de la matrice des //trajectoires. On obtient une matrice de taille (N+1)*M //(la fonction marche) static void simul_asset(PnlMat *asset, int M, int N, double spot, double T, param *P, int type_generator) { double h=T/N; int i,j; PnlMat *G; double Si_1; G=pnl_mat_create(0,0); pnl_mat_resize(asset,N+1,M); pnl_mat_rand_normal(G,N,M,type_generator); for(j=0;j<M;j++) {pnl_mat_set(asset,0,j,spot);} for(i=1;i<N+1;i++) { for(j=0;j<M;j++) { Si_1=pnl_mat_get(asset,i-1,j); pnl_mat_set(asset,i,j,Si_1*(1+b((i-1)*h,Si_1,spot,P)*h+vol((i-1)*h,Si_1,P)*sqrt(h)*pnl_mat_get(G,i-1,j))); } } pnl_mat_free(&G); }
// Exercice dates are : T(0), T(1), ..., T(NbrExerciseDates-1). // with T(0)=0 and T(NbrExerciseDates-1)=Maturity. static int MC_Am_Alfonsi_LoSc_Bates(NumFunc_1 *p, double S0, double Maturity, double r, double divid, double V0, double k, double theta, double sigma, double rho, double mu_jump,double gamma2,double lambda, long NbrMCsimulation, int NbrExerciseDates, int NbrStepPerPeriod, int generator, int basis_name, int DimApprox, double confidence, int flag_cir, double *ptPriceAm, double *ptPriceAmError, double *ptInfPriceAm, double *ptSupPriceAm) { int j, m, nbr_var_explicatives, init_mc; int flag_SpotPaths, flag_VarPaths, flag_AveragePaths; double continuation_value, discounted_payoff, european_price, european_delta, S_t, V_t, discount_step, discount, step, exercise_date, z_alpha, mean_price, var_price; double *VariablesExplicatives; PnlMat *SpotPaths, *VarPaths, *AveragePaths, *ExplicativeVariables; PnlVect *DiscountedOptimalPayoff, *RegressionCoeffVect; PnlBasis *basis; /* Value to construct the confidence interval */ z_alpha= pnl_inv_cdfnor((1.+ confidence)/2.); step = Maturity / (double)(NbrExerciseDates-1); discount_step = exp(-r*step); discount = exp(-r*Maturity); /* We store Spot and Variance*/ flag_SpotPaths = 1; flag_VarPaths = 1; flag_AveragePaths = 0; european_price = 0.; european_delta = 0.; nbr_var_explicatives = 2; basis = pnl_basis_create(basis_name, DimApprox, nbr_var_explicatives); VariablesExplicatives = malloc(nbr_var_explicatives*sizeof(double)); ExplicativeVariables = pnl_mat_create(NbrMCsimulation, nbr_var_explicatives); DiscountedOptimalPayoff = pnl_vect_create(NbrMCsimulation); // Continuation Value RegressionCoeffVect = pnl_vect_create(0); SpotPaths = pnl_mat_create(0, 0); // Matrix of the whole trajectories of the spot VarPaths = pnl_mat_create(0, 0); // Matrix of the whole trajectories of the variance AveragePaths = pnl_mat_create(0, 0); init_mc=pnl_rand_init(generator, NbrExerciseDates*NbrStepPerPeriod, NbrMCsimulation); if (init_mc != OK) return init_mc; // Simulation of the whole paths BatesSimulation_Alfonsi (flag_SpotPaths, SpotPaths, flag_VarPaths, VarPaths, flag_AveragePaths, AveragePaths, S0, Maturity, r, divid, V0, k, theta, sigma, rho, mu_jump, gamma2, lambda, NbrMCsimulation, NbrExerciseDates, NbrStepPerPeriod, generator, flag_cir); // At maturity, the price of the option = discounted_payoff exercise_date = Maturity; for (m=0; m<NbrMCsimulation; m++) { S_t = MGET(SpotPaths, NbrExerciseDates-1, m); // Simulated Value of the spot at the maturity T LET(DiscountedOptimalPayoff, m) = discount * (p->Compute)(p->Par, S_t); // Discounted payoff } for (j=NbrExerciseDates-2; j>=1; j--) { /** Least square fitting **/ exercise_date -= step; discount /= discount_step; for (m=0; m<NbrMCsimulation; m++) { V_t = MGET(VarPaths, j, m); // Simulated value of the variance S_t = MGET(SpotPaths, j, m); // Simulated value of the spot ApAlosHeston(S_t, p, Maturity-exercise_date, r, divid, V_t, k, theta, sigma,rho, &european_price, &european_delta); MLET(ExplicativeVariables, m, 0) = discount*european_price/S0; MLET(ExplicativeVariables, m, 1) = discount*european_delta*S_t*sqrt(V_t)/S0; } pnl_basis_fit_ls(basis,RegressionCoeffVect, ExplicativeVariables, DiscountedOptimalPayoff); /** Dynamical programming equation **/ for (m=0; m<NbrMCsimulation; m++) { V_t = MGET(VarPaths, j, m); // Simulated value of the variance S_t = MGET(SpotPaths, j, m); // Simulated value of the spot discounted_payoff = discount * (p->Compute)(p->Par, S_t); // Discounted payoff if (discounted_payoff>0.) // If the payoff is null, the OptimalPayoff doesnt change. { ApAlosHeston(S_t, p, Maturity-exercise_date, r, divid, V_t, k, theta, sigma,rho, &european_price, &european_delta); VariablesExplicatives[0] = discount*european_price/S0; VariablesExplicatives[1] = discount*european_delta*S_t*sqrt(V_t)/S0; continuation_value = pnl_basis_eval(basis,RegressionCoeffVect, VariablesExplicatives); if (discounted_payoff > continuation_value) { LET(DiscountedOptimalPayoff, m) = discounted_payoff; } } } } discount /= discount_step; // At initial date, no need for regression, continuation value is just a plain expectation estimated with empirical mean. continuation_value = pnl_vect_sum(DiscountedOptimalPayoff)/(double)NbrMCsimulation; discounted_payoff = discount*(p->Compute)(p->Par, S0); /* Price */ mean_price = MAX(discounted_payoff, continuation_value); /* Sum of squares */ var_price = SQR(pnl_vect_norm_two(DiscountedOptimalPayoff))/(double)NbrMCsimulation; var_price = MAX(var_price, SQR(discounted_payoff)) - SQR(mean_price); /* Price estimator */ *ptPriceAm = mean_price; *ptPriceAmError = sqrt(var_price/((double)NbrMCsimulation-1)); /* Price Confidence Interval */ *ptInfPriceAm= *ptPriceAm - z_alpha*(*ptPriceAmError); *ptSupPriceAm= *ptPriceAm + z_alpha*(*ptPriceAmError); free(VariablesExplicatives); pnl_basis_free (&basis); pnl_mat_free(&SpotPaths); pnl_mat_free(&VarPaths); pnl_mat_free(&AveragePaths); pnl_mat_free(&ExplicativeVariables); pnl_vect_free(&DiscountedOptimalPayoff); pnl_vect_free(&RegressionCoeffVect); return OK; }
/// Price of an option on a ZC using a trinomial tree. static double tr_hw2d_zcoption(TreeHW2D* Meth, ModelHW2D* ModelParam, ZCMarketData* ZCMarket, double T, double S, int NumberOfTimeStep, NumFunc_1 *p, double r, double u, int Eur_Or_Am) { double a ,sigma1, b, sigma2, rho, sigma3; double delta_t1, current_rate, current_u, OptionPrice, delta_y1, delta_u1, A_tT, B_tT, C_tT, ZCPrice; int i, h, l, jmin, jmax, kmin, kmax; PnlMat* OptionPriceMat1; // Matrix of prices of the option at i PnlMat* OptionPriceMat2; // Matrix of prices of the option at i+1 OptionPriceMat1 = pnl_mat_create(1,1); OptionPriceMat2 = pnl_mat_create(1,1); A_tT=0; B_tT=0; C_tT=0; ///*******************Parameters of the processes r, u and y *********************//// a = (ModelParam->rMeanReversion); sigma1 = (ModelParam->rVolatility); b = (ModelParam->uMeanReversion); sigma2 = (ModelParam->uVolatility); rho = (ModelParam->correlation); sigma3 = sqrt(sigma1*sigma1 + sigma2*sigma2/((b-a)*(b-a)) + 2*rho*sigma1*sigma2 / (b-a) ); ///****************** Computation of the vector of payoff at the maturity of the option *******************/// ZCOption_InitialPayoff(Meth, ModelParam, ZCMarket,OptionPriceMat2, p, S); ///****************** Backward computation of the option price until time 0 *******************/// for (i = Meth->Ngrid-1; i>=0; i--) { BackwardIterationHW2D(Meth, ModelParam, ZCMarket, OptionPriceMat1, OptionPriceMat2, i+1, i); if (Eur_Or_Am != 0) { jmin = pnl_vect_int_get(Meth->yIndexMin, i); // jmin(i) jmax = pnl_vect_int_get(Meth->yIndexMax, i); // jmax(i) kmin = pnl_vect_int_get(Meth->uIndexMin, i); // kmin(i) kmax = pnl_vect_int_get(Meth->uIndexMax, i); // kmax(i) delta_t1 = GET(Meth->t, i) - GET(Meth->t,MAX(i-1,0)); // time step. if i=0, then delta=0 in order to have delta_x=0. delta_y1 = delta_xHW2D(delta_t1, a, sigma3); // space step 1 delta_u1 = delta_xHW2D(delta_t1, b, sigma2); // space step 2 ZCPrice_Coefficient(ZCMarket, a, sigma1, b, sigma2, rho, GET(Meth->t, i), S, &A_tT , &B_tT, &C_tT); for (h= jmin ; h <=jmax ; h++) { for (l= kmin ; l <=kmax ; l++) { current_u = l*delta_u1; current_rate = GET(Meth->alpha, i) + h*delta_y1 - current_u/(b-a); ZCPrice = ZCPrice_Using_Coefficient(current_rate, current_u, A_tT, B_tT, C_tT); // Decide whether to exercise the option or not if ( MGET(OptionPriceMat2, h-jmin, l-kmin) < (p->Compute)(p->Par, ZCPrice)) { MLET(OptionPriceMat2, h-jmin, l-kmin) = (p->Compute)(p->Par, ZCPrice); } } } } } OptionPrice = MGET(OptionPriceMat2, 0, 0); pnl_mat_free(& OptionPriceMat1); pnl_mat_free(& OptionPriceMat2); return OptionPrice; }// FIN de la fonction ZCOption
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 prix_en_0_ls(double *res_prix, PnlMat *asset, int M, int N, int N_trading, double spot, double T, param *P, PnlBasis *basis) { PnlMat *V, *res_beta, *res_no_call; PnlMatInt *H, *mod_H; PnlVectInt *res_zeta, *res_tau,*res_theta; PnlVect *tmp_prix; int j, i, zeta_j, tau_j, theta_j; double sprix,s; double h=T/N; //initialisation V=pnl_mat_new(); res_no_call=pnl_mat_new(); res_beta=pnl_mat_new(); res_zeta=pnl_vect_int_new(); res_theta=pnl_vect_int_new(); res_tau=pnl_vect_int_new(); tmp_prix=pnl_vect_create(M); H=pnl_mat_int_new(); mod_H=pnl_mat_int_new(); //calcul du vecteur H calcul_H(H,asset,M,N,N_trading,spot,P); calcul_mod_H(mod_H,H,M,N,N_trading,P); //calcul du vecteur theta theta(res_theta,mod_H,M,N,N_trading,P); //calcul du prix_no_call protection prix_no_call(res_no_call,M,N,asset,spot,T,P,basis); //calcul du prix standard protection prix(V,res_no_call,M,N,asset,res_theta,spot,T,P,basis); //calcul de tau, zeta et beta tau(res_tau,M,N,V,asset,res_theta,P); zeta(res_zeta,res_tau,res_theta); beta(res_beta,spot,asset,T,N,P); //calcul de la somme Monte Carlo for(j=0;j<M;j++) { s=0; tau_j=pnl_vect_int_get(res_tau,j); theta_j=pnl_vect_int_get(res_theta,j); zeta_j=pnl_vect_int_get(res_zeta,j); if(tau_j<theta_j) { pnl_vect_set(tmp_prix,j,pnl_mat_get(res_beta,zeta_j,j)*low(pnl_mat_get(asset,tau_j,j),P)); } else { pnl_vect_set(tmp_prix,j,pnl_mat_get(res_beta,zeta_j,j)*pnl_mat_get(res_no_call,theta_j,j)); } for(i=1;i<=zeta_j;i++) s=s+h*pnl_mat_get(res_beta,i,j)*c(pnl_mat_get(asset,i,j),spot,P); pnl_vect_set(tmp_prix,j,pnl_vect_get(tmp_prix,j)+s); } sprix=pnl_vect_sum(tmp_prix); pnl_mat_free(&V); pnl_mat_free(&res_beta); pnl_mat_int_free(&H); pnl_mat_int_free(&mod_H); pnl_vect_int_free(&res_zeta); pnl_vect_int_free(&res_tau); pnl_vect_int_free(&res_theta); pnl_vect_free(&tmp_prix); *res_prix=sprix/M; }
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); }
/*/////////////////////////////////////////////////////*/ static int wh_rstemperedstable_amerput(int ifCall, double Spot, double T, double h, double Strike1, double er, long int step, int n_state, double *ptprice, double *ptdelta) { PnlVect *divi, *rr, *num, *nup, *lambdap, *lambdam, *cm, *cp, *strike, *mu, *qu; PnlVect *prices, *deltas; double eps; PnlMat *lam; int res, i, nstates; double tomega, omegas, lpnu, lmnu; eps= 1.0e-7; // accuracy of iterations res=readparamstsl_rs(&nstates, &rr, &divi, &num, &nup, &lambdam, &lambdap, &cm, &cp, &lam, infilename); if(!res) { printf("An error occured while reading file!\n"); *ptprice=0.; *ptdelta=0.; return OK; } mu= pnl_vect_create(nstates+1); qu= pnl_vect_create(nstates+1); strike= pnl_vect_create(nstates+1); prices= pnl_vect_create(nstates+1); deltas= pnl_vect_create(nstates+1); for(i=0;i<nstates; i++) LET(strike,i)=Strike1; if(ifCall==0) {omegas=2.0; } else {omegas=-1.0; } for(i=0;i<nstates;i++) { LET(rr,i)=log(1.+GET(rr,i)/100.); LET(divi,i)=log(1.+GET(divi,i)/100.); if(ifCall==0) { tomega = GET(lambdam,i)<-2. ? 2. : (-GET(lambdam,i)+1.)/2.; omegas = omegas>tomega ? tomega :omegas; } else { tomega=GET(lambdap,i)>1. ? -1. : -GET(lambdap,i)/2.; omegas = omegas<tomega ? tomega :omegas; } LET(cp,i) = GET(cp,i) * pnl_tgamma(-GET(nup,i)); LET(cm,i) = GET(cm,i) * pnl_tgamma(-GET(num,i)); lpnu=exp(GET(nup,i)*log(GET(lambdap,i))); lmnu=exp(GET(num,i)*log(-GET(lambdam,i))); LET(mu,i)= GET(rr,i) - GET(divi,i) + GET(cp,i)*(lpnu-exp(GET(nup,i)*log(GET(lambdap,i)+1.0))) + GET(cm,i)*(lmnu-exp(GET(num,i)*log(-GET(lambdam,i)-1.0))); LET(qu,i) = GET(rr,i) + (pow(GET(lambdap,i),GET(nup,i)) - pow(GET(lambdap,i)+omegas,GET(nup,i)))*GET(cp,i) + (pow(-GET(lambdam,i),GET(num,i))-pow(-GET(lambdam,i)-omegas,GET(num,i)))*GET(cm,i); } res = fastwienerhopfamerican_rs(1, nstates, mu, qu, omegas, ifCall, Spot, lambdam, lambdap, num, nup, cm, cp, rr, divi, lam, T, h, strike, er, step, eps, prices, deltas); //Price *ptprice =GET(prices,n_state-1); //Delta *ptdelta =GET(deltas,n_state-1); // Memory desallocation pnl_vect_free(&mu); pnl_vect_free(&qu); pnl_vect_free(&prices); pnl_vect_free(&deltas); pnl_vect_free(&rr); pnl_vect_free(&divi); pnl_vect_free(&lambdap); pnl_vect_free(&lambdam); pnl_vect_free(&cp); pnl_vect_free(&cm); pnl_vect_free(&num); pnl_vect_free(&nup); pnl_vect_free(&strike); pnl_mat_free(&lam); return OK; }
/* European Call/Put price with Bates model */ int MCCuchieroKellerResselTeichmann(double S0, NumFunc_1 *p, double t, double r, double divid, double V0,double kappa,double theta,double sigmav,double rho,double mu,double gamma2,double lambda, long N, int M,int Nb_Degree_Pol,int generator, double confidence,double *ptprice, double *ptdelta, double *pterror_price, double *pterror_delta , double *inf_price, double *sup_price, double *inf_delta, double *sup_delta) { /* Inputs: NumFunc_1 *p specifies the payoff function (Call or Put), S_0, K, t: option inputs other inputs: model parameters N: number of iterations in the Monte Carlo simulation M: number of discretization steps Nb_Degree_Pol: degree of approximating polynomial for variance reduction, between 0 and 8. Calculates the price of a European Call/Put option using Monte Carlo with variance reduction. Variance reduction is achieved by approximating the payoff function with a polynomial whose expectation can be calculated analytically and which therefore serves as control variate. */ double mean_price,var_price,mean_delta,mean_delta_novar,var_delta,polyprice, polydelta,mean_price_novar; double poly_sample,price_sample_novar,delta_sample,delta_poly_sample,delta_sample_novar; int init_mc,i,j,k,n,m1,m2; int simulation_dim= 1; double alpha, z_alpha; double g,g2,h,Xt,Vt; double dt,sqrt_dt; int nj; double poisson_jump=0,mm=0,Eu; int matrix_dim, line; double K; double rhoc; PnlMat *A, *eA; PnlVect *coeff; PnlVect *deltacoeff; PnlVect *matcoeff; PnlVect *deltamatcoeff; PnlVect *b; PnlVect *deltab; PnlVect *veczero; PnlVect *vecX; rhoc=sqrt(1.-SQR(rho)); Eu= exp(mu+0.5*gamma2)-1.; dt=t/(double)M; sqrt_dt=sqrt(dt); K=p->Par[0].Val.V_DOUBLE; /* Initialisation of vectors and matrices */ coeff=pnl_vect_create_from_double(Nb_Degree_Pol+1,0.); deltacoeff=pnl_vect_create_from_double(Nb_Degree_Pol+1,0.); vecX=pnl_vect_create_from_double(Nb_Degree_Pol+1,0.); matrix_dim = (Nb_Degree_Pol+1)*(Nb_Degree_Pol+2)/2; matcoeff=pnl_vect_create_from_double(matrix_dim,0.); deltamatcoeff=pnl_vect_create_from_double(matrix_dim,0.); veczero=pnl_vect_create_from_double(matrix_dim,0.); A=pnl_mat_create_from_double(matrix_dim,matrix_dim,0.); eA= pnl_mat_create_from_double(matrix_dim,matrix_dim,0.); /* Approximation of payoff function */ pol_approx(p,coeff,S0,K,Nb_Degree_Pol); /* Calculation of the coefficients of the derivative of the approximating polynomial */ for (n=0;n<Nb_Degree_Pol;n++) LET(deltacoeff,n)=GET(coeff,n+1)*(double)n; /* Reordering of coefficients, to fit the size of the generator matrix */ for(n=0;n<Nb_Degree_Pol+1;n++) { LET(matcoeff,n*(n+1)/2)=GET(coeff,n); LET(deltamatcoeff,n*(n+1)/2)=GET(deltacoeff,n); } /* Calculation of the matrix corresponding to the generator of the Bates model */ matrix_computation(A,Nb_Degree_Pol, r, divid, kappa, theta, lambda, mu, gamma2, sigmav, rho); pnl_mat_mult_double(A,t); /* Matrix exponentiation */ pnl_mat_exp (eA,A); pnl_mat_sq_transpose (eA); b=pnl_mat_mult_vect(eA, matcoeff); deltab=pnl_mat_mult_vect(eA, deltamatcoeff); /* Calculation log(S0)^m1 V0^m2, m1+m2 <=Nb_Degree_Pol */ for(m1=0;m1<Nb_Degree_Pol+1;m1++) for(m2=0;m2<Nb_Degree_Pol+1-m1;m2++) { line=(m1+m2)*(m1+m2+1)/2+m2; LET(veczero,line)=pow(log(S0),(double) m1)*pow(V0, (double) m2); } /* Expectation of approximating polynomial */ polyprice=pnl_vect_scalar_prod(b,veczero); /* Expectation of derivative of approximating polynomial */ polydelta=pnl_vect_scalar_prod(deltab,veczero); /* Value to construct the confidence interval */ alpha= (1.- confidence)/2.; z_alpha= pnl_inv_cdfnor(1.- alpha); /*Initialisation*/ mean_price= 0.0; var_price= 0.0; mean_delta= 0.0; mean_delta_novar= 0.0; var_delta= 0.0; mean_price_novar=0.; /*MC sampling*/ init_mc= pnl_rand_init(generator,simulation_dim,N); /* Test after initialization for the generator */ if(init_mc ==OK) { /* Begin N iterations */ for(i=0;i<N;i++) { Xt=log(S0); Vt=V0; for(j=0;j<M;j++) { mm = r-divid-0.5*Vt-lambda*Eu; /* Generation of standard normal random variables */ g= pnl_rand_normal(generator); g2= pnl_rand_normal(generator); /* Generation of Poisson random variable */ if(pnl_rand_uni(generator)<lambda*dt) nj=1; else nj=0; /* Normally distributed jump size */ h = pnl_rand_normal(generator); poisson_jump=mu*nj+sqrt(gamma2*nj)*h; /* Euler scheme for log price and variance */ Xt+=mm*dt+sqrt(MAX(0.,Vt))*sqrt_dt*g+poisson_jump; Vt+=kappa*(theta-Vt)*dt+sigmav*sqrt(MAX(0.,Vt))*sqrt_dt* (rho*g+rhoc*g2); } price_sample_novar=(p->Compute)(p->Par,exp(Xt)); /* Creation of vector containing Xt^k, k<=Nb_Degree_Pol */ for(k=0;k<Nb_Degree_Pol+1;k++) { LET(vecX,k)=pow(Xt, (double) k); } /* Approximating polynomial evaluated at Xt */ poly_sample=pnl_vect_scalar_prod(coeff,vecX); /* Derivative of approximating polynomial evaluated at Xt */ delta_poly_sample=pnl_vect_scalar_prod(deltacoeff,vecX); /*Sum for prices*/ mean_price_novar+=price_sample_novar; /* without control variate */ mean_price+=price_sample_novar-(poly_sample-polyprice); /* with control variate*/ /* Delta sampling */ if (price_sample_novar>0.) { delta_sample_novar=exp(Xt)/S0;//Call Case delta_sample= (exp(Xt)-(delta_poly_sample-polydelta))/S0; /* Delta sampling with control variate*/ if((p->Compute) == &Put) delta_sample=(-exp(Xt)-(delta_poly_sample-polydelta))/S0; /* Delta sampling with control variate */ } else{ delta_sample_novar=0; delta_sample=0.-(delta_poly_sample-polydelta)/S0; /* Delta sampling with control variate */ } /*Sum for delta*/ mean_delta_novar+=delta_sample_novar; /* without control variate */ mean_delta+=delta_sample; /* with control variate*/ /*Sum of squares*/ var_price+=SQR(price_sample_novar-(poly_sample-polyprice)); var_delta+=SQR(delta_sample); } /*Price */ *ptprice=exp(-r*t)*(mean_price/(double) N); /*Error*/ *pterror_price= sqrt(exp(-2.0*r*t)*var_price/(double)N - SQR(*ptprice))/sqrt(N-1); /* Price Confidence Interval */ *inf_price= *ptprice - z_alpha*(*pterror_price); *sup_price= *ptprice + z_alpha*(*pterror_price); /*Delta*/ *ptdelta=exp(-r*t)*mean_delta/(double) N; *pterror_delta= sqrt(exp(-2.0*r*t)*(var_delta/(double)N-SQR(*ptdelta)))/sqrt((double)N-1); /* Delta Confidence Interval */ *inf_delta= *ptdelta - z_alpha*(*pterror_delta); *sup_delta= *ptdelta + z_alpha*(*pterror_delta); } //Memory desallocation pnl_mat_free (&eA); pnl_mat_free (&A); pnl_vect_free(&coeff); pnl_vect_free(&b); pnl_vect_free(&matcoeff); pnl_vect_free(&veczero); pnl_vect_free(&vecX); pnl_vect_free(&deltacoeff); pnl_vect_free(&deltamatcoeff); pnl_vect_free(&deltab); return init_mc; }
/** * Computes garch price for GARCH model * @param[in] today_price taday price * @param[in] alpha_zero garch parameter * @param[in] alpha_one garch parameter * @param[in] lambda the constant unit risk premium * @param[in] beta_one garch parameter * @param[in] interest the annulized interest * @param[in] K exercise price * @param[in] frequency frequency * @param[in] T time to mutrity * @param[in] choice emscorrection(ems_on or ems_off) * @param[in] type_generator the type of generator for random number * @param[out] garch option price * garch->call obtains call option price * garch->put obtains put option price * @return OK if ok otherwise return FAIL */ static int garch_price(NumFunc_1 *p,double today_price,double alpha_zero,double alpha_one,double beta_one,double lambda,double interest,int frequency,double K,int T,int N,int choice,int type_generator,double *price,double *delta) { double sum_callorput; double sum_delta; double s_T; double garch_delta; int i; PnlMat *path_ems, *path, *path1D; PnlVect *h; path=pnl_mat_create(T,N); h=pnl_vect_create (1); sum_callorput=0; sum_delta=0; pnl_vect_set(h,0,today_price); if (calculate_path(h,path,interest,frequency,N,T,alpha_zero,alpha_one,lambda,beta_one,type_generator)==FAIL) { pnl_vect_free(&h); pnl_mat_free(&path); return FAIL; } //if we choose ems option switch (choice) { case 1: pnl_vect_free(&h); pnl_rand_init(type_generator,N,T); path_ems=pnl_mat_create(T,N); if(ems(path,interest,frequency,path_ems)==FAIL) { pnl_mat_free(&path); pnl_mat_free(&path_ems); return FAIL; } pnl_mat_clone(path, path_ems); for(i=0;i<N;i++) { s_T=pnl_mat_get(path,T-1,i); sum_callorput=sum_callorput+(p->Compute)(p->Par,pnl_mat_get(path,T-1,i)); if(s_T>K) garch_delta=1.; sum_delta=sum_delta+(s_T/today_price)*garch_delta; } pnl_mat_free(&path_ems); break; case 2: path1D=pnl_mat_create(T,1); pnl_rand_init(type_generator,1,T); for(i=0;i<N;i++) { calculate_path(h,path1D,interest,frequency,1,T,alpha_zero,alpha_one,lambda,beta_one,type_generator); s_T=pnl_mat_get(path1D,T-1,0); sum_callorput=sum_callorput+(p->Compute)(p->Par,pnl_mat_get(path,T-1,i)); if(s_T>K) garch_delta=1.; sum_delta=sum_delta+(s_T/today_price)*garch_delta; } pnl_vect_free(&h); pnl_mat_free(&path1D); break; default: printf ("Wrong value for parameter EMS\n"); return FAIL; } interest=(interest*frequency)/252.; //Price *price=sum_callorput/(N*pow(M_E,(interest*T))); *delta=sum_delta/(N*pow(M_E,(T*interest))); if ((p->Compute)==&Put) *delta=*delta-1; pnl_mat_free(&path); return OK ; }
static int wh_rskou_bar(int am, int upordown, int ifCall, double Spot, double T, double h, double Strike1, double bar,double rebate, double er, long int step,int n_state, double *ptprice, double *ptdelta) { PnlVect *divi, *rr, *lambda, *pp, *lambdap, *lambdam, *cm, *cp, *strike, *sigmas, *rebates, *mu, *qu; PnlVect *prices, *deltas; double eps; PnlMat *lam; int res, i, nstates; double tomega, omegas, sig2; eps= 1.0e-7; // accuracy of iterations res=readparamskou_rs(&nstates, &rr, &divi, &sigmas, &lambdam, &lambdap, &lambda, &pp, &lam, infilename); if(!res) { printf("An error occured while reading file!\n"); *ptprice=0.; *ptdelta=0.; return OK; } mu= pnl_vect_create(nstates+1); qu= pnl_vect_create(nstates+1); cp= pnl_vect_create(nstates+1); cm= pnl_vect_create(nstates+1); strike= pnl_vect_create(nstates+1); rebates= pnl_vect_create(nstates+1); prices= pnl_vect_create(nstates+1); deltas= pnl_vect_create(nstates+1); for(i=0;i<nstates; i++) LET(strike,i)=Strike1; if(upordown==0) {omegas=2.0; } else {omegas=-1.0;} for(i=0;i<nstates;i++) { LET(rr,i)=log(1.+GET(rr,i)/100.); LET(divi,i)=log(1.+GET(divi,i)/100.); LET(rebates,i)= rebate; if(upordown==0) { tomega = GET(lambdam,i)<-2. ? 2. : (-GET(lambdam,i)+1.)/2.; omegas = omegas>tomega ? tomega :omegas; } else { tomega=GET(lambdap,i)>1. ? -1. : -GET(lambdap,i)/2.; omegas = omegas<tomega ? tomega :omegas; } LET(cp,i)=(1-GET(pp,i))*GET(lambda,i); LET(cm,i)=GET(pp,i)*GET(lambda,i); sig2=GET(sigmas,i)*GET(sigmas,i); LET(mu,i)= GET(rr,i)- GET(divi,i)+GET(cp,i)/(GET(lambdap,i)+1.0)+GET(cm,i)/(GET(lambdam,i)+1.0)-sig2/2.0; LET(qu,i)=GET(rr,i)-GET(mu,i)*omegas-sig2*omegas*omegas/2.0+GET(cp,i)+GET(cm,i)-GET(cp,i)*GET(lambdap,i)/(GET(lambdap,i)+omegas)-GET(cm,i)*GET(lambdam,i)/(GET(lambdam,i)+omegas); } res= fastwienerhopf_rs(4, nstates, mu, qu, omegas, 1, upordown, ifCall, Spot, lambdam, lambdap,sigmas, sigmas, cm, cp, rr, divi, lam, T, h, strike, bar, rebates, er, step, eps, prices, deltas); //Price *ptprice =GET(prices,n_state-1); //Delta *ptdelta =GET(deltas,n_state-1); // Memory desallocation pnl_vect_free(&mu); pnl_vect_free(&qu); pnl_vect_free(&prices); pnl_vect_free(&deltas); pnl_vect_free(&rr); pnl_vect_free(&divi); pnl_vect_free(&sigmas); pnl_vect_free(&lambdap); pnl_vect_free(&lambdam); pnl_vect_free(&cp); pnl_vect_free(&cm); pnl_vect_free(&lambda); pnl_vect_free(&pp); pnl_vect_free(&strike); pnl_vect_free(&rebates); pnl_mat_free(&lam); return OK; }
/** * compute the paths from vector which contains historical price and stock the result in a matrix with dimensions (T+1)*N for GARCH model * @param[in] h vector which contain all values history of price * @param[out] path matrix stock all path after compute * @param[in] T Exercise time * @param[in] alpha_zero garch parameter * @param[in] alpha_one garch parameter * @param[in] interest interest rate * @param[in] lambda the constant unit risk premium * @param[in] beta_one parameter garch * @param[in] type_generator the type of generator for random number * @return OK if ok otherwise return FAIL */ static int calculate_path(const PnlVect* h,PnlMat* path,double interest,int frequency,int N,int T,double alpha_zero,double alpha_one,double lambda,double beta_one,int type_generator) { double sigma,s,sigma_t; int size;//size of vector double s_t;//price at time t double s_0;//price init double presigma=alpha_zero/(1-beta_one-alpha_one*(1+pow(lambda,2))); double preepsilon=0; PnlMat* eps;//matrix contains all variables epsilon with value random PnlMat* array_sigma; int dimension=N;//colum of matrix int samples;//row of matrix int i,j; interest=(frequency*interest)/252.; size=h->size; s_0=pnl_vect_get(h,0); eps=pnl_mat_create(T-size+1,N);//matrix contains all variables epsilon with value random array_sigma=pnl_mat_create(T-size+1,N); samples=T-size+1; pnl_rand_init(type_generator,dimension,samples); pnl_mat_rand_normal(eps,samples,dimension,type_generator); if(size==1) { s_t=s_0; } else { s_t=pnl_vect_get(h,size-1); } if(size>1) { for(i=0;i<size-1;i++) { presigma=sqrt(alpha_zero+alpha_one*pow((presigma*preepsilon-lambda*presigma),2)+beta_one*pow(presigma,2)); preepsilon=(1/presigma)*(log(pnl_vect_get(h,i+1)/pnl_vect_get(h,i))-interest+0.5*pow(presigma,2)); } } for(i=0;i<dimension;i++) { for(j=0;j<samples;j++) { if(j==0) { sigma=presigma; pnl_mat_set(array_sigma,0,i,sigma); if(size>1) { s=s_t*pow(M_E,(interest-0.5*pow(pnl_mat_get(array_sigma,0,i),2)+pnl_mat_get(array_sigma,0,i)*preepsilon)); } else { s=s_0*pow(M_E,(interest-0.5*pow(pnl_mat_get(array_sigma,0,i),2)+pnl_mat_get(array_sigma,0,i)*pnl_mat_get(eps,0,i))); } pnl_mat_set(path,0,i,s); } else { sigma_t=pnl_mat_get(array_sigma,j-1,i); sigma=sqrt(alpha_zero+alpha_one*pow((sigma_t*pnl_mat_get(eps,j-1,i)-lambda*sigma_t),2)+beta_one*pow(sigma_t,2)); pnl_mat_set(array_sigma,j,i,sigma); s=pnl_mat_get(path,j-1,i)*pow(M_E,(interest-0.5*pow(sigma,2)+sigma*pnl_mat_get(eps,j,i))); pnl_mat_set(path,j,i,s); } } } pnl_mat_free(&eps); pnl_mat_free(&array_sigma); return OK; }
// Initialization of AndersenStruct. We fill the matrices DiscountedPayoff and NumeraireValue using simulated paths. // We also fill AndersenIndices with "q" kink-points. static int Init_AndersenStruct(AndersenStruct *andersen_struct, Libor *ptLib, Swaption *ptBermSwpt, Volatility *ptVol, NumFunc_1 *p, int NbrMCsimulation, int NbrStepPerTenor, int generator, int flag_numeraire, double Nominal, int q) { int alpha, beta, start_index, end_index, save_brownian, save_all_paths; int i, m, j, NbrExerciseDates, step; double tenor, param_max, discounted_payoff_j, numeraire_j; Libor *ptL_current; Swaption *ptSwpt; PnlMat *LiborPathsMatrix; LiborPathsMatrix = pnl_mat_create(0, 0); tenor = ptBermSwpt->tenor; alpha = pnl_iround(ptBermSwpt->swaptionMaturity/tenor); // T(alpha) is the swaption maturity beta = pnl_iround(ptBermSwpt->swapMaturity/tenor); // T(beta) is the swap maturity NbrExerciseDates = beta-alpha; start_index = 0; end_index = beta-1; param_max = 0; save_brownian = 0; save_all_paths = 1; // SImulation of "NbrMCsimulation" Libor paths under "flag_numeraire" measure. Sim_Libor_Glasserman(start_index, end_index, ptLib, ptVol, generator, NbrMCsimulation, NbrStepPerTenor, save_all_paths, LiborPathsMatrix, save_brownian, LiborPathsMatrix, flag_numeraire); step = (NbrExerciseDates-1)/q; mallocLibor(&ptL_current, LiborPathsMatrix->n, tenor, 0.); mallocSwaption(&ptSwpt, ptBermSwpt->swaptionMaturity, ptBermSwpt->swapMaturity, 0.0, ptBermSwpt->strike, tenor); andersen_struct->NbrExerciseDates = NbrExerciseDates; andersen_struct->NbrMCsimulation = NbrMCsimulation; andersen_struct->j_start = 0; andersen_struct->q = q; pnl_mat_resize(andersen_struct->DiscountedPayoff, NbrExerciseDates, NbrMCsimulation); pnl_mat_resize(andersen_struct->NumeraireValue, NbrExerciseDates, NbrMCsimulation); pnl_vect_resize(andersen_struct->AndersenParams, NbrExerciseDates); pnl_vect_int_resize(andersen_struct->AndersenIndices, q+1); // Set the indices of kink-points, where parmeters will be estimated pnl_vect_int_set(andersen_struct->AndersenIndices, q, NbrExerciseDates-1); pnl_vect_int_set(andersen_struct->AndersenIndices, 0, 0); for (i=1; i<q; i++) { pnl_vect_int_set(andersen_struct->AndersenIndices, q-i, (NbrExerciseDates-1)-i*step); } // Fill the structure andersen_struct with discounted payoff and numeraire values. for (j=alpha; j<beta; j++) { for (m=0; m<NbrMCsimulation; m++) { pnl_mat_get_row(ptL_current->libor, LiborPathsMatrix, j + m*end_index); discounted_payoff_j = Nominal*Swaption_Payoff_Discounted(ptL_current, ptSwpt, p, flag_numeraire); numeraire_j = Numeraire(j, ptL_current, flag_numeraire); MLET(andersen_struct->DiscountedPayoff, j-alpha, m) = discounted_payoff_j; MLET(andersen_struct->NumeraireValue, j-alpha, m) = numeraire_j; param_max = MAX(param_max, numeraire_j*discounted_payoff_j); } ptSwpt->swaptionMaturity += tenor; } andersen_struct->H_max = param_max; pnl_mat_free(&LiborPathsMatrix); freeSwaption(&ptSwpt); freeLibor(&ptL_current); return OK; }
// Returning the price and the deltas of a basket option using its lower bound approximation : static void lower_basket(int put_or_call,int dim, PnlVect *vol, PnlVect *poids, PnlVect *val_init, PnlVect *div, double cor, double tx_int, double strike, double echeance, double *prix, PnlVect* deltas) { int i,j; // Initializing parameters PnlVect *sigma = pnl_vect_create (dim+1); PnlVect *x = pnl_vect_create (dim+1); PnlVect *eps = pnl_vect_create (dim+1); PnlMat *rac_C = pnl_mat_create (dim+1, dim+1); pnl_vect_set (sigma, 0, 0); for(i=1; i<dim+1;i++){ pnl_vect_set (sigma, i, pnl_vect_get (vol, i-1)); } pnl_vect_set (x, 0, strike*exp(-tx_int*echeance)); for (i=1; i<dim+1; i++){ pnl_vect_set (x, i, fabs(pnl_vect_get (poids, i-1)) * pnl_vect_get (val_init, i-1)* exp(-pnl_vect_get (div, i-1)*echeance)); } pnl_vect_set (eps, 0, -1); for (i=1; i<dim+1; i++){ if(pnl_vect_get (poids, i-1)<0) pnl_vect_set (eps, i, -1); else pnl_vect_set (eps, i, 1); } if(put_or_call==1) { pnl_vect_mult_double (eps, -1.0); } if(cor != 1){ PnlMat *C = pnl_mat_create (dim, dim); // double *C=new double[dim*dim]; // Correlation matrix for(i=0; i<dim; i++){ for(j=0; j<dim; j++){ if(i==j) pnl_mat_set (C, i, j, 1); else pnl_mat_set (C, i, j, cor); } } pnl_mat_chol (C); for(i=0; i<dim+1; i++){ pnl_mat_set (rac_C, i, 0, 0); pnl_mat_set (rac_C, 0, i, 0); } for(i=1; i<dim+1; i++){ for(j=1; j<=i;j++){ pnl_mat_set (rac_C, i, j, pnl_mat_get (C, i-1, j-1)); } for(j=i+1;j<dim+1;j++){ pnl_mat_set (rac_C, i, j , 0); } } /* Correlation was useful only to compute a square root of it */ pnl_mat_free (&C); } else { for(i=0; i<dim+1;i++){ pnl_mat_set (rac_C, i, 0, 0); pnl_mat_set (rac_C, i, 1, 1); for(j=2; j<dim+1;j++){ pnl_mat_set (rac_C, i, j, 0); } } pnl_mat_set (rac_C, 0, 1, 0); } lowlinearprice(dim,eps,x,rac_C,sigma,echeance,prix,deltas); // Uses the general formula /* In deltas are stored the derivatives along x[i], which differ from those along val_init[i] */ for(i=0;i<dim;i++){ double d = pnl_vect_get (deltas, i); pnl_vect_set (deltas, i, d * pnl_vect_get (x, i+1) / pnl_vect_get (val_init, i)); } pnl_vect_free (&eps); pnl_vect_free (&x); pnl_vect_free (&sigma); pnl_mat_free (&rac_C); }