📄 calibrator.java
字号:
* * @param p swap starts at <code>T_p</code> * @param q swap stops at <code>T_q</code> * @param kappa strike rate. */ public double swaptionPrice(int p, int q, double kappa) { double S_pq0=S_pq[p][q-p], // swap rate S_pq(0) swpnSigma,Nplus,Nminus; swpnSigma=Sigma(p,q); // aggregate volatility to expiry Nplus=FinMath.N(FinMath.d_plus(S_pq0,kappa,swpnSigma)); Nminus=FinMath.N(FinMath.d_minus(S_pq0,kappa,swpnSigma)); return B_pq[p][q-p]*(S_pq0*Nplus-kappa*Nminus); } // end swaptionPrice /******************************************************************************* * * INTEGRAL OF VOLATILITY FUNCTION g * ******************************************************************************/ //EXPONENTIAL INTEGRALS: // integral exp(s/D)ds double F(double D, double s){ return D*Math.exp(s/D); } // integral s*exp(s/D)ds double G(double D, double s){ return D*Math.exp(s/D)*(s-D); } // integral s^2*exp(s/D)ds double H(double D, double s){ return D*Math.exp(s/D)*((s-D)*(s-D)+D*D); } /** <code>integral_0^T g(u)^2du</code>, where <code>g(u)</code> is the * function defining the volatilities * <code>sigma_j(t)=c_jg(1-t/T_j)</code> in the {@link CS_FactorLoading}. * Makes use of the current values of the fields * <code>A,D,rho00,alpha,beta</code>. */ public double integral_g_squared(double T) { double R=T; R+=2*A*(G(-D,T)+D*D); R+=A*A*(H(-D/2,T)+D*D*D/4); return R; } //end Integral_g_squared /******************************************************************************* * * CALIBRATION * ******************************************************************************/ //<!--Greek characters tau="C4", epsilon="ε" --> /** <p><a name="calibration"><b>Calibration</b></a> * of a {@link CS_FactorLoading} to caplet and swaption * prices. All caplets are used and missing caplets interpolated. * Caplet prices are matched precisely. * Only available swaptions are used, missing swaptions are ignored.</p> * * <p>The calibration routine is an "exhaustive" search of the parameter * rectangle along a low discrepancy sequence. The routine repeatedly * narrows the search space to a smaller rectangle around the current * optimum.</p> * * <p>The calibration routine tries to minimize the mean percent deviation * of model computed analytic swaption prices from quoted prices and * returns an <code>LMM_Parameters</code> object which can be handed to a * constructor to instantiate a <code>LiborProcess.</p> * * <p>Intial search region for the <code>CS_FactorLoading</code> * parameters:<br> * <code>A ε[0,30], D ε[0.1,0.9], rho00 ε[0.01,0.8], * alpha ε[0,-6log(rho00)], beta ε[0,alpha/n]. * </code><br> * It is a good idea to modify these settings (in the source code) * to see how this alters the performance. Experiments show some * <a href=#main>unexpected phenomena</a>. * </p> * */ public LMM_Parameters calibrate(int nPoints) { readCaplets(); readSwaptions(); // the basic generator for the search points, 5 parameters LowDiscrepancySequence sbl=new Sobol(5); System.out.println("ZOOMING IN ON OPTIMUM, 10 ZOOM LEVELS."); //initial search range double A_min=0, A_max=30, D_min=0.1, D_max=0.9, rho_min=0.01, rho_max=0.8, alpha_min=0, alpha_max=10, beta_min=0, beta_max=alpha_max/(3*n); // zoom depth int zoom=0; // current optima, minimal error double A_opt=0, D_opt=0, rho00_opt=0, alpha_opt=0, beta_opt=0, // swaption price errors error_min=1000000, // minimal mean percent error percent_error, // percent deviation, current swaption sum_percent_error, // sum of percent error mean_percent_error; // mean of percent errors // loop over zoom levels while(zoom<10) { System.out.println("\nZOOM DEPTH: "+zoom); if(zoom>0){ // search range zooms in on current optimum, reduce number of // search points double down=(2.0*zoom)/(2.0*zoom+1), up=1.0/down; A_min=down*A_opt; A_max=up*A_opt; D_min=down*D_opt; D_max=up*D_opt; rho_min=down*rho00_opt; rho_max=up*rho00_opt; alpha_min=down*alpha_opt; alpha_max=up*alpha_opt; beta_min=down*beta_opt; beta_max=up*beta_opt; nPoints=3*nPoints/5; } //end if System.out.println("Mean swaption price error (%): "); //random search over x=(A,D,rho00,alpha,beta) along points // of a Sobol sequence LoopStatus loopStatus=new LoopStatus(); long before=System.currentTimeMillis(); // loop progress reported 100 times int m=nPoints/100; sbl.restart(); for(int pt=1;pt<nPoints;pt++) { double[] x=sbl.nextPoint(); A=A_min+x[0]*(A_max-A_min); D=D_min+x[1]*(D_max-D_min); rho00=rho_min+x[2]*(rho_max-rho_min); rho00=Math.min(rho00,0.8); alpha=alpha_min+x[3]*(alpha_max-alpha_min); // parameter condition for alpha alpha=Math.min(alpha,-6*Math.log(rho00)); beta=beta_min+x[4]*(beta_max-beta_min); // parameter condition for beta beta=Math.min(beta,alpha/(3*n)); beta=Math.min(beta,3*(-Math.log(rho00)-alpha/6)); //search vector complete setParameters(A,D,alpha,beta,rho00); // compute the c[j]=c_j to match the caplet implied vols for(int i=1;i<n;i++) c[i]=capletSigma[i]/Math.sqrt(Tc[i]*integral_g_squared(1.0)); // with this set the factor loading setFactorLoading (new CS_FactorLoading(n,A,D,alpha,beta,rho00,c,Tc)); setCholeskyRoots(); // error with the new parameters sum_percent_error=0; int nSwpn=0; // number of swaptions // loop through the swaptions, Iterator swapnIterator=swaptions.iterator(); while(swapnIterator.hasNext()) { double price, modelprice, kappa; int p,q; // get the next swaption and extract the parameters Swpn swpn=(Swpn)swapnIterator.next(); p=swpn.p; q=swpn.q; kappa=swpn.kappa; price=swpn.price; // compute the analytic LMM-model price for this swaption modelprice=swaptionPrice(p,q,kappa); // percent error, current swaption percent_error=Math.abs(price-modelprice)/price; // cumulative squared error and percent_error sum_percent_error+=percent_error; nSwpn++; } // end swaption loop // check if we have a new optimum mean_percent_error=sum_percent_error/nSwpn; if(mean_percent_error<error_min){ A_opt=A; D_opt=D; rho00_opt=rho00; alpha_opt=alpha; beta_opt=beta; error_min=mean_percent_error; // mean swaption price error in percent mean_percent_error*=100; // cut this down to 4 digits String report=new Double(mean_percent_error).toString(); report=report.substring(0,4); System.out.println(report); } // progress report on pt-loop if((m>1)&&(pt%m==m-1)) loopStatus.progressReport(pt,nPoints,m,before); } // end for(pt) zoom++; } // end while(zoom) // parameters are set to optimum, return LMM_parameters object System.out.println("\nOPTIMAL PARAMETERS:\n"); printParameters(); return new LMM_Parameters(l,factorLoading); } // end calibrate /******************************************************************************* * * TEST PROGRAM * ******************************************************************************/ /** <p><a name="main"><b>Calibration test</b>,</a> * calibrates a {@link CS_FactorLoading} to a set of data in dimension * <code>n=15</code>.</p> * * <p>The data are synthetic prices generated from a Libor process based * on a {@link EP_FactorLoading}. These data are then used to calibrate * a {@link CS_FactorLoading}.</p> * * <p>Recall that the calibration routine does not build an initial term * structure of forward Libors (from quoted Libors and swap rates) but * instead receives the precise initial term strucutre as a parameter. * Likewise an <code>EP_FactorLoading</code> is close in spirit to a * <code>CS_FactorLoading</code>. Both have humped forward Libor * volatilities and a correlation structure of the form * <code>rho_ij=b_i/b_j, i<=j</code> where <code>b_i</code> is an * increasing sequence. Needless to say this makes calibration easier. * </p> * * <p>Obviously it is extremely important to test this routine and the * concept of a <code>CS_FactorLoading</code> on market data. Thus this * class and its methods should mainly be viewed as an infrastructure to * base your own calibration experiments on and as an example of how * one might go about doing this.</p> * * <p>Even so some interesting phenomena are already evident in this * rudimentary example. In particular it is observed that the optimal * parameter values are often highly nonintuitive. For example very * large volatility bumps (large parameter <code>A</code>) combined with * very low correlations (much lower than in the data) often match the data * very closely. Moreover widely different parameter tuples yield very good * approximations. Of course this could be interpreted as saying that we * are not close to an optimum yet. On the other hand the model * swaption prices show a mean percentage error of less than * <code>0.5%</code>, a very good approximation indeed.</p> */ public static void main(String[] args) throws IOException { int n=15, nPoints=5000; double delta=0.25; double[] l=new double[n], c=new double[n], Tc=new double[n+1]; for(int i=0;i<n;i++){ l[i]=0.04; c[i]=0; Tc[i]=i*delta; } Tc[n]=n*delta; System.out.println ("Writing synthetic swaption and caplet price files.\n"+ "Using EP_FactorLoading."); new SyntheticData("Caplets","Swaptions").writeData(n); System.out.println ("\nCalibrating CS_FactorLoading to synthetic prices.\n"); new Calibrator(n,l,c,Tc,"Caplets","Swaptions").calibrate(nPoints); } // end main } // end Calibrator
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -