// Finds a minimum of a multidimensional function f in direction dir. // Minimum is stored in min, its location in p : static void min1dir(int dim, PnlVect * p, PnlVect * dir, double *min, double f(PnlVect *)) { int j; const double TOL=1.0e-10; double xx,xmin,bx,ax; // Initialise les variables globales _n=dim; _p = p; _dir = dir; func=f; // [0,1] is the initial bracketing guess ax=0.0; xx=1.0; minenc(&ax,&xx,&bx,f1dim); // Computes an acutal bracketing triplet *min=min1dim(ax,xx,bx,f1dim,TOL,&xmin); // Computes the minimum of function f1dim // (which is the minimum of function f in direction dir) for(j=0;j<dim;j++){ double d = pnl_vect_get (dir , j); pnl_vect_set (dir, j, d*xmin); pnl_vect_set (p, j, pnl_vect_get (p, j) + pnl_vect_get (dir, j)); // Sets actual position of the minimum } }
// 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 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; }
//------------------------Sampling the transition probability (v(0)=X_t, v(1)=int_0^t X_s ds) //-------------------------dX_t = kappa(theta-X_t)dt + sigma sqrt(X_t)dW_t //-------------------------------------In the case of the troncation serie static void Sample_C( PnlVect* v,double t, double kappa, double sigma, double theta ,int generator) { //----------Declaration of variable double gamma, lambda; double tmp; double tmp2; int j,pss; int order_tr; // Default value is equal to 20 //----------Initialization of parammter tmp=0.; j=0; gamma = 4.*kappa/(sigma*sigma*(1.-exp(-kappa*t))); lambda = pnl_vect_get(v,0)*gamma*exp(-kappa*t); order_tr = 20; //----------Begin operations //----generate vt --> tmp pss = pnl_rand_poisson(lambda*0.5,generator); for(j=1;j<= pss;j++) tmp = tmp + pnl_rand_gamma(1.,2., generator); tmp = tmp +pnl_rand_gamma(2.*kappa*theta/(sigma*sigma),2.,generator); tmp = tmp/gamma; //----generate the variable Z tmp2 =0.; j=0; pss = pnl_rand_bessel(2.*theta*kappa/(sigma*sigma)-1.,2.*kappa*sqrt(pnl_vect_get(v,0)*tmp)/(sigma*sigma*sinh(kappa*t*0.5)),generator); for(j=1;j<=pss;j++) { tmp2=tmp2+X_3_sample( order_tr, t, kappa, sigma, generator); } //----generate int_0^t vs = X1 +X2 +X3 --> lambda lambda=tmp2+X_2_sample( order_tr, t, kappa, sigma, theta , generator)+X_1_sample( order_tr, t, kappa, sigma, pnl_vect_get(v,0), tmp, generator); //----set the new value pnl_vect_set(v,0,tmp); pnl_vect_set(v,1,lambda); }
/** * Solve a tridiagonal system defined by matrix whose three diagonals are * defined by three values. * @param low the double value of M(i,i-1) * @param diag the double value of M(i,i) * @param up the double value of M(i,i+1) * @param rhs the right and side member of the system * @param lhs contains the solution on exit */ void pnl_progonka(const double low, const double diag, const double up, const PnlVect * rhs, PnlVect * lhs) { int i; double *D,tmp; D = malloc((rhs->size)*sizeof(double)); /* Do Down-Solve L y = rhs */ if((D[0]=diag)==0) { PNL_ERROR("division by zero","pnl_progonka"); } pnl_vect_set(lhs,0,pnl_vect_get(rhs,0)); for(i=1; i<rhs->size; i++) { tmp=low/D[i-1]; if((D[i]=diag-tmp*up)==0) { PNL_ERROR("division by zero","pnl_progonka"); } pnl_vect_set(lhs,i,pnl_vect_get(rhs,i)-tmp*pnl_vect_get(lhs,i-1)); } /* Do Up-Solve L y = rhs */ pnl_vect_set(lhs,rhs->size-1,pnl_vect_get(lhs,rhs->size-1)/D[rhs->size-1]); for(i=rhs->size-2;i>=0;i--) { pnl_vect_set(lhs,i,(pnl_vect_get(lhs,i)-up*pnl_vect_get(lhs,i+1))/D[i]); } free(D); }
// 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); }
double call_by_density(double k, params *p) { int N ; double m_dVarianceCurve; double m_dGamma ; double m_dOmega1 ; double m_dOmega2 ; double m_dCorrel; int path,i ; double sup ; PnlVect *axis; double strikeMin, res; N = p->n; m_dVarianceCurve= p->VarianceCurve; m_dGamma = p->Gamma; m_dOmega1 = p->Omega1; m_dOmega2 = p->Omega2; m_dCorrel = p->Correl; path = 2000; sup = 12; axis = pnl_vect_create(path); strikeMin = z(k * k,p); res = 0; for (i = 0; i < path; i++) pnl_vect_set(axis,i,strikeMin + sup * i / (double)path); for (i = 0; i < path - 1; i++) res += (pnl_vect_get(axis,i+1) - pnl_vect_get(axis,i)) * MAX(sqrt(g(pnl_vect_get(axis,i),p)) - k, 0.0) * exp(-pnl_vect_get(axis,i) * pnl_vect_get(axis,i) / 2.0) / sqrt(2.0 * M_PI); return res; }
double put_by_density(double k, params *p) { int N ; double m_dVarianceCurve; double m_dGamma ; double m_dOmega1 ; double m_dOmega2 ; double m_dCorrel; int path,i ; double inf ; PnlVect *axis; double strikeMax, res; N = p->n; m_dVarianceCurve= p->VarianceCurve; m_dGamma = p->Gamma; m_dOmega1 = p->Omega1; m_dOmega2 = p->Omega2; m_dCorrel = p->Correl; path = 2000; inf = -12; axis = pnl_vect_create(path); strikeMax = z(k * k,p); res = 0; for (i = 0; i < path; i++) pnl_vect_set(axis,i,inf + (i + 1) * (strikeMax - inf) / (double)path); for (i = 0; i < path - 1; i++) res += (pnl_vect_get(axis,i+1) - pnl_vect_get(axis,i)) * MAX(k - sqrt(g(pnl_vect_get(axis,i),p)), 0.0) * exp(-pnl_vect_get(axis,i) * pnl_vect_get(axis,i) / 2.0) / sqrt(2.0 * M_PI); return res; }
double Barrier_l :: payoff (const PnlMat *path) { double sum ; PnlVect* final = pnl_vect_create(size_); //On met dans final la dernière colonne de Path correspond à la valeur à maturité des sous-jacents. pnl_mat_get_col(final, path, TimeSteps_); sum = pnl_vect_scalar_prod(final, Coeff_) - Strike_; //On vérifie que toutes les valeurs des sous-jacents soient au dessus de la barrière //Si on en trouve une alors le prix de l'option est de 0 for (int i=0; i<TimeSteps_+1; i++){ for (int d=0; d<size_; d++){ if (pnl_mat_get(path,d,i) < pnl_vect_get(Bl_,d)){ pnl_vect_free(&final); return 0; } } }
double Barrier_u :: payoff ( double t, const PnlMat* path) const { double sum ; //Vecteur utilisé pour effectuer la somme de chaque actif à maturité PnlVect* final = pnl_vect_create(size_); //On met dans final la dernière colonne de Path correspond à la valeur à maturité des sous-jacents pnl_mat_get_col(final, path, timeStep_); sum = pnl_vect_scalar_prod(final, Coeff_) - strike_; //On vérifie que toutes les valeurs des sous-jacents soient en dessous de la barrière //Si on en trouve une alors le prix de l'option est de 0 for (int i=0; i<timeStep_+1; i++){ for (int d=0; d<size_; d++){ if (MGET(path,d,i) > pnl_vect_get(Bu_,d)){ pnl_vect_free(&final); return 0; } } }
double f_by_density(params *p) { int N ; double m_dVarianceCurve; double m_dGamma ; double m_dOmega1 ; double m_dOmega2 ; double m_dCorrel; int path,i ; double sup ; PnlVect *axis; double res ; N = p->n; m_dVarianceCurve= p->VarianceCurve; m_dGamma = p->Gamma; m_dOmega1 = p->Omega1; m_dOmega2 = p->Omega2; m_dCorrel = p->Correl; path = 2000; sup = 12; axis = pnl_vect_create(path); res = 0; for ( i = 0; i < path; i++) pnl_vect_set(axis,i, -sup + 2 * sup * i / (double)path); for ( i = 0; i < path - 1; i++) res += (pnl_vect_get(axis,i + 1) - pnl_vect_get(axis,i)) * sqrt(m_dVarianceCurve * (1 - m_dGamma) * exp(m_dOmega1 * pnl_vect_get(axis,i) - m_dOmega1 * m_dOmega1 / 2.0) + m_dVarianceCurve * m_dGamma * exp(m_dOmega2 * pnl_vect_get(axis,i) - m_dOmega2 * m_dOmega2 / 2.0)) * exp(-pnl_vect_get(axis,i) * pnl_vect_get(axis,i) / 2.0) / sqrt(2.0 *M_PI); return res; }
// Auxiliary cost function to minimize used in lowlinearprice : static double Cost(PnlVect *ksi) { int i, j; double p=0,arg=0; double normv=0; for (i=0; i<Dim+1; i++) { double ksi_i = pnl_vect_get (ksi, i); normv += ksi_i * ksi_i; } normv = sqrt (normv); for(i=0; i<Dim+1;i++){ double tmp=0; for(j=0;j<Dim+1;j++){ tmp+=pnl_mat_get (Rac_C, i, j) * pnl_vect_get (ksi, j); } arg=pnl_vect_get (ksi, Dim+1) + pnl_vect_get (Sigma, i) * tmp*sqrt(Echeance)/normv; p+=pnl_vect_get (Eps, i) * pnl_vect_get (X, i) * cdf_nor(arg); } return (-1.0*p); // The function is to be maximized }
// 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); }
static int SingularPoints_Up(int am,double s,NumFunc_1 *p,double t,double r,double sigma,PnlVect *divid_dates,PnlVect *divid_amounts,int N,double h_up,double *ptprice,double *ptdelta) { int n; double u,d,h,pu,pd,a1; double K=p->Par[0].Val.V_DOUBLE; double *v_min,*v_max,*new_vm,*new_vm1,*new_vm2,*new_vpm,*new_vpm1,*new_vpm2; double *vect_t; int * nb_critical; int *divid_steps; double value1,value2,value_price1,value_price2; double dist1,dist2; double TOL1=0.00000000001; double TOL2=0.00000000001; int i,j,k,l,jj,kk,Nb_div,new_nb_critical,n_k; int max_critical=0; int i1,index,nb_critical_put; double m1,error,errp; int old_nb_critical; double x1,x2,y2,y11,a,b; int n_max; /*Number of Dividends Dates*/ Nb_div=divid_dates->size; //Number maximum of singular points n_max=50000; /*Compute steps of the tree*/ n=N*Nb_div; /*Memory allocations*/ divid_steps= malloc((n+1)*sizeof(int)); nb_critical=(int*)malloc(sizeof(int)*(n+1)); v_min=(double*)malloc(sizeof(double)*(n+1)); v_max=(double*)malloc(sizeof(double)*(n+1)); vm=(double*)malloc(sizeof(double)*(n_max)); vpm=(double*)malloc(sizeof(double)*(n_max)); new_vm=(double*)malloc(sizeof(double)*(n_max)); new_vm1=(double*)malloc(sizeof(double)*(n_max)); new_vm2=(double*)malloc(sizeof(double)*(n_max)); new_vpm=(double*)malloc(sizeof(double)*(n_max)); new_vpm1=(double*)malloc(sizeof(double)*(n_max)); new_vpm2=(double*)malloc(sizeof(double)*(n_max)); vect_t= malloc((n+1)*sizeof(double)); /*Up and Down factors*/ h=t/(double)n; a1= exp(h*r); u = exp(sigma*sqrt(h)); d= 1./u; /*Risk-Neutral Probability*/ pu=(a1-d)/(u-d); pd=1.-pu; if ((pd>=1.) || (pd<=0.)) return NEGATIVE_PROBABILITY; pu*=exp(-r*h); pd*=exp(-r*h); for(i=0;i<=n;i++) vect_t[i]=h*(double)i; //Compute steps related to the dividend dates for(k=0;k<Nb_div;k++) { i=0; while(vect_t[i]<pnl_vect_get(divid_dates,k)) i++; if(fabs(pnl_vect_get(divid_dates,k)-vect_t[i])<1.e-10) divid_steps[k]=i; else { dist1=vect_t[i]-pnl_vect_get(divid_dates,k); dist2=pnl_vect_get(divid_dates,k)-vect_t[i-1]; if (dist1<dist2) divid_steps[k]=i; else divid_steps[k]=i-1; } } /*Compute Minimum and Maximum of the stock at each step taking in to account of the dividend payements*/ v_min[0]=s; v_max[0]=s; j=0; for(i=1;i<=n;i++) { v_min[i]=v_min[i-1]*d; v_max[i]=v_max[i-1]*u; for(k=0;k<Nb_div;k++) if(i==divid_steps[k]) { v_min[i]=v_min[i]-pnl_vect_get(divid_amounts,Nb_div-k-1); v_max[i]=v_max[i]-pnl_vect_get(divid_amounts,Nb_div-k-1); } } /***Singular points at Maturity****/ if((v_min[n]<K)&&(v_max[n]>K)) { nb_critical[n]=2; //Abscissa vm[0]=v_min[n]; vm[1]=K; vm[2]=v_max[n]; //Ordinate vpm[0]=(p->Compute)(p->Par,vm[0]); vpm[1]=(p->Compute)(p->Par,vm[1]); vpm[2]=(p->Compute)(p->Par,vm[2]); } else { nb_critical[n]=1; //Abscissa vm[0]=v_min[n]; vm[1]=v_max[n]; //Ordinate vpm[0]=(p->Compute)(p->Par,vm[0]); vpm[1]=(p->Compute)(p->Par,vm[1]); } /***Backward algorithm****/ for(i=1;i<=n;i++) { /*Min point*/ new_vm[0]=v_min[n-i];//Abscissa value1=new_vm[0]*u; value_price1=compute_pricesp(value1,nb_critical[n-i+1]); value2=new_vm[0]*d; value_price2=compute_pricesp(value2,nb_critical[n-i+1]); new_vpm[0]=pu*value_price1+pd*value_price2;//Ordinate /*Middle points*/ n_k=1; for(j=1;j<nb_critical[n-i+1];j++) { for(jj=-1;jj<=1;jj=jj+2) { new_vm[n_k]=vm[j]*pow(u,(double)jj);//Abscissa if((new_vm[n_k]>v_min[n-i])&&(new_vm[n_k]<v_max[n-i])) { value1=new_vm[n_k]*u; value_price1=compute_pricesp(value1,nb_critical[n-i+1]); value2=new_vm[n_k]*d; value_price2=compute_pricesp(value2,nb_critical[n-i+1]); new_vpm[n_k]=pu*value_price1+pd*value_price2;//Ordinate n_k++; } } } /*Max point*/ new_vm[n_k]=v_max[n-i];//Abscissa value1=new_vm[n_k]*u; value_price1=compute_pricesp(value1,nb_critical[n-i+1]); value2=new_vm[n_k]*d; value_price2=compute_pricesp(value2,nb_critical[n-i+1]); new_vpm[n_k]=pu*value_price1+pd*value_price2;//Ordinate //Shift at the dividends dates for(k=0;k<Nb_div;k++) if(i==divid_steps[k]) { for(j=0;j<=n_k;j++) new_vm[j]+=pnl_vect_get(divid_amounts,Nb_div-k-1); } /*Sorting*/ nb_critical[n-i]=n_k; Sort2Vect(nb_critical[n-i],new_vm,new_vpm); //Remove singular points very close TOL1=e-10,TOL2=e-10 new_vm1[0]=new_vm[0]; new_vpm1[0]=new_vpm[0]; kk=0; l=0; do { do { l++; }while((new_vm[l]<=new_vm1[kk]+TOL1)&&(l<nb_critical[n-i])); kk++; new_vm1[kk]=new_vm[l]; new_vpm1[kk]=new_vpm[l]; }while((l<nb_critical[n-i])); new_nb_critical=kk; nb_critical[n-i]=kk; if(fabs(new_vm1[nb_critical[n-i]]-new_vm1[nb_critical[n-i]-1])<TOL2) nb_critical[n-i]=new_nb_critical-1; //Upper bound i1=0; index=0; new_vm2[0]=new_vm1[0]; new_vpm2[0]=new_vpm1[0]; while(i1<nb_critical[n-i]-1) { l=1; do { l++; m1=(new_vpm1[i1+l]-new_vpm1[i1])/(new_vm1[i1+l]-new_vm1[i1]); error=0.; for(jj=1;jj<=l-1;jj++) { errp=m1*(new_vm1[i1+jj]-new_vm1[i1])+new_vpm1[i1]-new_vpm1[i1+jj]; if (errp<0) errp=-errp; if (errp>error) error=errp; } } while(!((error>h_up)||((i1+l)==nb_critical[n-i]))); index++; new_vm2[index]=new_vm1[i1+l-1]; new_vpm2[index]=new_vpm1[i1+l-1]; i1=i1+l-1; } while(i1<nb_critical[n-i]) { index++; new_vm2[index]=new_vm1[i1+1]; new_vpm2[index]=new_vpm1[i1+1]; i1 =i1+1; } nb_critical[n-i]=index; //American Call Case if((am==1)&&((p->Compute)==&Call)) { old_nb_critical=nb_critical[n-i]; if(MAX(0.,new_vm2[0]-K)<=new_vpm2[0]) { l=1; while((new_vpm2[l]>=MAX(0.,new_vm2[l]-K))&&(l<=nb_critical[n-i])) { l++; if(l>nb_critical[n-i]) break; } if(l<=nb_critical[n-i]) { nb_critical[n-i]=l+1; x1=new_vm2[l-1]; x2=new_vm2[l]; y11=new_vpm2[l-1]; y2=new_vpm2[l]; a=(y2-y11)/(x2-x1); b=(y11*x2-x1*y2)/(x2-x1); new_vm2[l]=(K+b)/(1.-a); new_vpm2[l]=MAX(0.,new_vm2[l]-K); new_vm2[l+1]=new_vm2[old_nb_critical]; new_vpm2[l+1]=MAX(0.,new_vm2[l+1]-K); } } } /* //Dynamic Programming:American Put Case if((am==1)&&((p->Compute)==&Put)) for(j=0;j<=nb_critical[n-i];j++) { new_vpm2[j]=MAX(new_vpm2[j],K-new_vm2[j]); }*/ //American Put Case else if((am==1)&&((p->Compute)==&Put)) { if(MAX(0.,K-new_vm2[0])>=new_vpm2[0]) { new_vm1[0]=new_vm2[0]; new_vpm1[0]=MAX(0.,K-new_vm2[0]); l=1; while((new_vpm2[l]<MAX(0.,K-new_vm2[l]))&&(l<=nb_critical[n-i])) { l++; if(l>nb_critical[n-i]) break; } if(l>nb_critical[n-i]) { new_vm1[1]=new_vm2[nb_critical[n-i]]; new_vpm1[1]=MAX(0.,K-new_vm1[1]); nb_critical[n-i]=1; } else if(l<=nb_critical[n-i]) { x1=new_vm2[l-1]; x2=new_vm2[l]; y11=new_vpm2[l-1]; y2=new_vpm2[l]; a=(y2-y11)/(x2-x1); b=(y11*x2-x1*y2)/(x2-x1); new_vm1[1]=(K-b)/(1.+a); new_vpm1[1]=MAX(0.,K-new_vm1[1]); j=l; nb_critical_put=1; while((j<=nb_critical[n-i])) { nb_critical_put++; new_vm1[nb_critical_put]=new_vm2[j]; new_vpm1[nb_critical_put]=new_vpm2[j]; j++; }; nb_critical[n-i]=nb_critical_put; } for(j=0;j<=nb_critical[n-i];j++) { new_vm2[j]=new_vm1[j]; new_vpm2[j]=new_vpm1[j]; } } } max_critical=MAX(nb_critical[n-i],max_critical); //Copy for(j=0;j<=nb_critical[n-i];j++) { vm[j]=new_vm2[j]; vpm[j]=new_vpm2[j]; } /*Delta*/ if(i==(n-1)) *ptdelta=(vpm[nb_critical[n-i]]-vpm[0])/(vm[nb_critical[n-i]]-vm[0]); } /*Price*/ *ptprice=vpm[0]; //Memory desallocation free(nb_critical); free(divid_steps); free(v_min); free(v_max); free(vpm); free(vm); free(new_vm); free(new_vm1); free(new_vm2); free(new_vpm); free(new_vpm1); free(new_vpm2); free(vect_t); return OK; }
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); }
int MCGlassermanKim(double S0, NumFunc_1 *p, double T, double r, double q, double v0,double kappa,double theta,double sigma,double rho,int Nmc,int generator,double *ptprice, double *ptdelta,double *error_price) { //------------------Declaration of variable int j,call_put; PnlVect* vv; double tmp1, tmp, tmp2, tmp3; double tmpvar; int init_mc; double mt,sigmat; double d1,d2; double epsilon; double K; if ((p->Compute)==&Call) call_put=0; else call_put=1; K=p->Par[0].Val.V_PDOUBLE; //-----------------Initialization of variable vv = pnl_vect_create_from_double(2,0.); pnl_vect_set(vv,0,v0); epsilon = 0.01; init_mc= pnl_rand_init(generator,1,(long)Nmc); //-----------------Operation begins tmp=0.; tmp2=0.; tmpvar=0.; for(j=1;j<= Nmc;j++) { pnl_vect_set(vv,0,v0); pnl_vect_set(vv,1,0.); Sample_C( vv, T, kappa, sigma, theta , generator); mt= (r-q -kappa*theta*rho/sigma) *T + rho*(pnl_vect_get(vv,0)-v0)/sigma+(kappa*rho/sigma-0.5)*pnl_vect_get(vv,1); sigmat = sqrt((1-rho*rho)*pnl_vect_get(vv,1)); if(call_put==0)//call pricing { d1 = (log(S0/K)+mt)/sigmat+ sigmat; d2 = d1 - sigmat; tmp1 = S0*exp(mt-r*T+0.5*sigmat*sigmat)*cdf_nor(d1)-K*exp(-r*T)*cdf_nor(d2); d1 = (log((S0+epsilon)/K)+mt)/sigmat+ sigmat; d2 = d1 - sigmat; tmp3 = (S0+epsilon)*exp(mt-r*T+0.5*sigmat*sigmat)*cdf_nor(d1)-K*exp(-r*T)*cdf_nor(d2); } else { d1 = (log(S0/K)+mt)/sigmat+ sigmat; d2 = d1 - sigmat; tmp1 = K*exp(-r*T)*(1.-cdf_nor(d2))-S0*(1.-exp(mt-r*T+0.5*sigmat*sigmat)*cdf_nor(d1)); d1 = (log((S0+epsilon)/K)+mt)/sigmat+ sigmat; d2 = d1 - sigmat; tmp3 = K*exp(-r*T)*(1.-cdf_nor(d2))-(S0+epsilon)*(1.-exp(mt-r*T+0.5*sigmat*sigmat)*cdf_nor(d1)); } tmp = tmp1 +tmp; tmp2 = tmp3+ tmp2; //--------------confidence interval tmpvar = tmp1*tmp1+tmpvar; } tmp = tmp /((double)Nmc); tmp2 = tmp2/ ((double)Nmc); tmpvar = tmpvar/((double) Nmc) - tmp*tmp; *ptprice = tmp; *ptdelta = (tmp2-tmp) /epsilon; *error_price=sqrt(tmpvar/((double)Nmc)); //printf("the interval of confidence is +/- %f\n", 2.* sqrt(tmpvar/((double) Nmc))); //-----------Free Memory pnl_vect_free(&vv); return init_mc; }
/** * 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; }
// Auxiliary gradient of function Cost, used in routine lowlinearprice : static void Gradcost(PnlVect *ksi, PnlVect *g) { int i,j,k; double normv=0, s; for (i=0; i<Dim+1; i++) { double ksi_i = pnl_vect_get (ksi, i); normv += ksi_i * ksi_i; } normv=sqrt(normv); pnl_vect_set (g, Dim+1, 0); for(j=0; j<Dim+1;j++){ pnl_vect_set (g, j, 0.); for(i=0;i<Dim+1;i++){ double tmp=0; for(k=0; k<Dim+1;k++){ tmp+=pnl_mat_get (Rac_C, i, k) * pnl_vect_get (ksi, k); } s=pnl_normal_density(pnl_vect_get (ksi, Dim+1) + pnl_vect_get (Sigma, i) * tmp*sqrt(Echeance)/normv); s*=pnl_vect_get (Eps, i) * pnl_vect_get (X, i); if(j==Dim) pnl_vect_set (g, Dim+1, pnl_vect_get (g, Dim+1) + s); s*=pnl_vect_get (Sigma, i) * sqrt(Echeance)/normv; s*=pnl_mat_get (Rac_C, i, j) - pnl_vect_get (ksi, j) *tmp/(normv*normv); pnl_vect_set (g, j, pnl_vect_get (g, j) + s); } pnl_vect_set (g , j , -pnl_vect_get (g, j)); } pnl_vect_set (g , Dim+1 , -pnl_vect_get (g, Dim+1)); }
void calibToVIXSmiles(double k1, double k2, double Theta , double RhoXY, params *p, FILE* MarketData, FILE* OUTOMEGA) { char chaine[TAILLE_MAX] = ""; int NumberMat,i,j; PnlMat *Data; PnlVect *aux; PnlMat *OMEGA; double varStateProces,T, Delta; if(MarketData != NULL) { if(fgets(chaine, TAILLE_MAX, MarketData) != NULL) i=0; //LiborNumber = (int)atof ( chaine ); if(fgets(chaine, TAILLE_MAX, MarketData) != NULL) NumberMat = (int) atof ( chaine ); Data = pnl_mat_create (NumberMat,7); OMEGA = pnl_mat_create (2*NumberMat,3); aux = pnl_vect_create (7); for(j=0;j<NumberMat;j++) { if(fgets(chaine, TAILLE_MAX, MarketData) != NULL) { RowFromFile(chaine, NumberMat, aux); for(i=0;i<7;i++) { pnl_mat_set(Data,j,i,pnl_vect_get(aux,i)/100.0); } } } fclose(MarketData); } for(i=0;i<NumberMat;i++) { p->VarianceCurve=pnl_mat_get(Data,i,1); p->VIXFuture =pnl_mat_get(Data,i,2); p->Strike =pnl_mat_get(Data,i,3); p->PutVIX =pnl_mat_get(Data,i,4); calibSkew(pnl_mat_get(Data,i,5), pnl_mat_get(Data,i,6), p); if(i<NumberMat-1) { T = pnl_mat_get(Data,i+1,0); Delta = pnl_mat_get(Data,i+1,0) - pnl_mat_get(Data,i,0); } else { Delta = pnl_mat_get(Data,i,0) - pnl_mat_get(Data,i-1,0); T = pnl_mat_get(Data,i,0)+ Delta; } varStateProces = calcul_var(T, Delta, k1, k2, Theta , RhoXY); pnl_mat_set(OMEGA,2*i,0, T-Delta); pnl_mat_set(OMEGA,2*i,1, p->Omega1); pnl_mat_set(OMEGA,2*i,2, p->VarianceCurve); pnl_mat_set(OMEGA,2*i+1,0, T-p->Gamma*Delta); pnl_mat_set(OMEGA,2*i+1,1, p->Omega2); pnl_mat_set(OMEGA,2*i+1,2, p->VarianceCurve); } if (OUTOMEGA != NULL) { fprintf( OUTOMEGA, "%d \n", 2*NumberMat ); // Ecriture du caractère A for(i=0;i<2*NumberMat;i++) fprintf( OUTOMEGA, "%f \t %f \t %f \n", pnl_mat_get(OMEGA,i,0), pnl_mat_get(OMEGA,i,1), pnl_mat_get(OMEGA,i,2)); // Ecriture du caractère A fclose(OUTOMEGA); } //pnl_mat_print(OMEGA); }
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; }