/** * Euler acceleration to recover a CDF using the Laplace transform of its density * * @param f the Laplace transform with complex values of a real valued * density function * @param t the point at which the orignal is to be evaluated * @param h step size used to discretize the integral * @param N series truncation * @param M Euler averaging length. */ double pnl_ilap_cdf_euler(PnlCmplxFunc *f, double t, double h, int N, int M) { int i, Cnp; double sum, run_sum; sum = 0.; for(i=1;i<N+1;i++) { sum += sin(i*h*t) * Creal (PNL_EVAL_FUNC(f, Complex (0., h * i))) / (double)i; } run_sum = sum; /* partial sum of sn */ sum = 0.0; /* partial exponential sum */ Cnp = 1; /* binomial coefficients */ for(i=0;i<M+1;i++) { sum += run_sum * (double) Cnp ; run_sum += sin ((i + N + 1) * h * t) * Creal (PNL_EVAL_FUNC(f, Complex (0., h * (i + N + 1)))) / (double) (i + N + 1); Cnp = (Cnp * (M - i)) / (i + 1); } return(2.0 / M_PI * sum / pow(2.0,M) + h * t / M_PI); }
/** * Euler acceleration to invert a Laplace transform * * @param f the Laplace transform with complex values of a real valued * function * @param t the point at which the orignal is to be evaluated * @param N series truncation * @param M Euler averaging length. */ double pnl_ilap_euler(PnlCmplxFunc *f, double t, int N, int M) { int i, Cnp; double sum, a, pit, run_sum; double A; A = 13.; /* MIN (13., 13. / t); */ a = A/(2.0*t); pit = M_PI/t; sum = 0.5 * Creal (PNL_EVAL_FUNC(f, Complex (a, 0.))); for(i=1;i<N+1;i++) sum += ALTERNATE(i) * Creal (PNL_EVAL_FUNC(f, Complex (a, pit * i))); run_sum = sum; /* partial sum of sn */ sum = 0.0; /* partial exponential sum */ Cnp = 1; /* binomial coefficients */ for(i=0;i<M+1;i++) { sum += run_sum * (double) Cnp ; run_sum += ALTERNATE(i+N+1) * Creal (PNL_EVAL_FUNC(f, Complex (a, pit * (i + N + 1)))); Cnp = (Cnp * (M - i)) / (i + 1); } return exp (A / 2. - M * M_LN2) * sum / t ; }
/*We use the Cauchy Gourat theorem to compute the derivatives of the double(Mellin+Laplace) transform */ static dcomplex dermellin(dcomplex l, double sg, double r, int nummom) { dcomplex term, cv, mu; int i; double r0,sumr, sumi/*,x[NPOINTS_FUSAITAGL+1],w[NPOINTS_FUSAITAGL+1]*/; double v; double *x,*w; x=malloc((NPOINTS_FUSAITAGL+1)*sizeof(double)); w=malloc((NPOINTS_FUSAITAGL+1)*sizeof(double)); sumr=0.0; sumi=0.0; gauleg(0, 2*M_PI, x, w,NPOINTS_FUSAITAGL); v = 2*r/(sg*sg)-1.0; cv = Complex(v,0.0); mu = Csqrt(Cadd(Complex(v*v,0), RCmul(2.0,l))); r0 = Creal(RCmul(0.5,Csub(mu,cv))); if(r0>1.0) r0=0.25; for (i=1;i<=NPOINTS_FUSAITAGL;i++) { term = RCmul(pow(r0,nummom), Cexp(Complex(0.0, nummom*x[i]))); sumr += w[i]*Creal(Cdiv(mellintransform(l, RCmul(r0, Cexp(Complex(0.0, x[i]))), sg, r), term)); sumi += w[i]*Cimag(Cdiv(mellintransform(l, RCmul(r0, Cexp(Complex(0.0, x[i]))), sg, r), term)); } free(x); free(w); return Complex(exp(factln(nummom))*sumr/(2.0*M_PI),exp(factln(nummom))*sumi/(2.0*M_PI)); }
/** * FFT algorithm to invert a Laplace transform * @param res a real vector containing the result of the inversion. We know that * the imaginary part of the inversion vanishes. * @param f : the Laplace transform to be inverted * @param T : the time horizon up to which the function is to be recovered * @param eps : precision required on [0, T] */ void pnl_ilap_fft(PnlVect *res, PnlCmplxFunc *f, double T, double eps) { PnlVectComplex *fft; int i, N, size; double h, time_step, a; double f_a, omega; dcomplex mul, fac; h = M_PI / (2 * T); a = h * log (1 + 1. / eps) / (M_2PI); N = MAX (sqrt (exp (a * T) / eps), h / (M_2PI * eps)) ; N = pow (2., ceil (log (N) / M_LN2) ); time_step = M_2PI / (N * h); fft = pnl_vect_complex_create (N); size = floor (T / time_step) + 1; pnl_vect_resize (res, size); fac = CIexp (-M_2PI / N); mul = fac; f_a = Creal (PNL_EVAL_FUNC (f, Complex (a, 0))); omega = h; for (i=0 ; i<N ; i++) { pnl_vect_complex_set (fft, i, Cmul(mul,PNL_EVAL_FUNC (f, Complex (a, - omega)))); omega += h; mul = Cmul(mul,fac); } pnl_fft_inplace (fft); mul = CONE; for (i=0 ; i<size ; i++) { double res_i; res_i = Creal (Cmul (pnl_vect_complex_get (fft, i), mul)); mul = Cmul (mul, fac); res_i = (h / M_PI) * exp (a * (i + 1) * time_step) * (res_i + .5 * f_a); PNL_LET (res, i) = res_i; } pnl_vect_complex_free (&fft); }
double Var_Swap_price(double T, Levy_diffusion * Model, dcomplex (*psi)(dcomplex u,double t,Levy_diffusion * model)) { // phi is hermitian : // phi(epsilon,0)-phi(-epsilon,0)= 2 Im(phi)(epsilon) // phi'(0) == Im(phi)(epsilon)/epsilon // phi(epsilon,0)+phi(-epsilon,0)= 2 Re(phi)(epsilon) // phi''(0,0)== 2 Re(phi)(epsilon)/epsilon^2 dcomplex Phi = (psi(Complex(EPSILON_DIFF,0.),T,Model)); return 100.0*sqrt(-2.0*Creal(Phi)/(EPSILON_DIFF*EPSILON_DIFF*T)); }
static int pcons (void) { int ci; double d; ci = 0; switch (Ltok) { case L_NUMBER: d = atof (Lstrtok); ci = (d == (double) (long) d) ? Cinteger ((long) d) : Creal (d); break; case L_STRING: ci = Cstring (Lstrtok); break; default: err ("expected scalar constant, found: %s", Lnames[Ltok]); } Lgtok (); return ci; }
void newmomentsAM(int model, double rf, double dt, int maxmoment, int ndates, double parameters[], double **momtable) { int i,ii,k; double sum; for(i = 1; i < maxmoment + 1; i++) {momtable[1][i] = Creal(cfrn(model,rf, dt, Complex(0,-i), parameters)); } for(ii = 2;ii < ndates + 1; ii++) {for(i = 1; i < maxmoment + 1; i++) { sum=0; for(k=1;k<=i;k++) {sum=sum+momtable[ii - 1][ k]*bico(i, i-k); } momtable[ii][ i] = momtable[1][ i]*(1 + sum); } } }
/** * Complex Modified Bessel function of the first kind * divided by exp(|Creal(z)|) * * @param z a complex number * @param v a real number, the order of the Bessel function * */ dcomplex pnl_complex_bessel_i_scaled( double v, dcomplex z ) { int nz, ierr; dcomplex cy; int n = 1; int kode = 2; if (v >= 0) { pnl_zbesi(CADDR(z), &v, &kode, &n, CADDR(cy), &nz, &ierr); DO_MTHERR("ive:"); } else { dcomplex aux1, aux2; aux1 = pnl_complex_bessel_i_scaled (-v, z); aux2 = pnl_complex_bessel_k (-v, z); aux2 = CRmul (aux2, M_2_PI * sin(M_PI * -v) * exp ( -fabs ( Creal(z) ) )); cy = Cadd (aux1, aux2); } return cy; }
double Var_Swap_price_Levy(Levy_process * Model, dcomplex (*psi)(dcomplex u,Levy_process * model)) { /* dcomplex Phip = (psi(Complex(EPSILON_DIFF,0.),Model)); dcomplex Phi0 = (psi(Complex(0.,0.),Model)); dcomplex Phim = (psi(Complex(-EPSILON_DIFF,0.),Model)); dcomplex dPhi=Csub(Phip,Phim); Phi0=Csub(Cadd(Phip,Phim),RCmul(2.,Phi0)); return 100.0*sqrt((Creal(Phi0)+0.25*Creal(dPhi)*Creal(dPhi))/(EPSILON_DIFF*EPSILON_DIFF)); */ // psi is hermitian : // psi(epsilon,0)-psi(-epsilon,0)= 2 Im(psi)(epsilon) // psi'(0) == Im(psi)(epsilon)/epsilon // psi(epsilon,0)+psi(-epsilon,0)= 2 Re(psi)(epsilon) // psi''(0,0)== 2 Re(psi)(epsilon)/epsilon^2 dcomplex Phi = (psi(Complex(EPSILON_DIFF,0.),Model)); return 100.0*sqrt(2.0*Creal(Phi)/(EPSILON_DIFF*EPSILON_DIFF)); }
//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; }