public void testDefaultProbability() { // Testing default-probability structure... double hazardRate = 0.0100; Handle<Quote> hazardRateQuote = new Handle<Quote>(new SimpleQuote(hazardRate)); DayCounter dayCounter = new Actual360(); Calendar calendar = new TARGET(); int n = 20; double tolerance = 1.0e-10; Date today = Settings.evaluationDate(); Date startDate = today; Date endDate = startDate; FlatHazardRate flatHazardRate = new FlatHazardRate(startDate, hazardRateQuote, dayCounter); for(int i=0; i<n; i++) { startDate = endDate; endDate = calendar.advance(endDate, 1, TimeUnit.Years); double pStart = flatHazardRate.defaultProbability(startDate); double pEnd = flatHazardRate.defaultProbability(endDate); double pBetweenComputed = flatHazardRate.defaultProbability(startDate, endDate); double pBetween = pEnd - pStart; if (Math.Abs(pBetween - pBetweenComputed) > tolerance) Assert.Fail( "Failed to reproduce probability(d1, d2) " + "for default probability structure\n" + " calculated probability: " + pBetweenComputed + "\n" + " expected probability: " + pBetween); double t2 = dayCounter.yearFraction(today, endDate); double timeProbability = flatHazardRate.defaultProbability(t2); double dateProbability = flatHazardRate.defaultProbability(endDate); if (Math.Abs(timeProbability - dateProbability) > tolerance) Assert.Fail( "single-time probability and single-date probability do not match\n" + " time probability: " + timeProbability + "\n" + " date probability: " + dateProbability); double t1 = dayCounter.yearFraction(today, startDate); timeProbability = flatHazardRate.defaultProbability(t1, t2); dateProbability = flatHazardRate.defaultProbability(startDate, endDate); if (Math.Abs(timeProbability - dateProbability) > tolerance) Assert.Fail( "double-time probability and double-date probability do not match\n" + " time probability: " + timeProbability + "\n" + " date probability: " + dateProbability); } }
public void testBSMOperatorConsistency() { //("Testing consistency of BSM operators..."); Vector grid = new Vector(10); double price = 20.0; double factor = 1.1; for (int i = 0; i < grid.size(); i++) { grid[i] = price; price *= factor; } double dx = Math.Log(factor); double r = 0.05; double q = 0.01; double sigma = 0.5; BSMOperator refer = new BSMOperator(grid.size(), dx, r, q, sigma); DayCounter dc = new Actual360(); Date today = Date.Today; Date exercise = today + new Period(2, TimeUnit.Years); double residualTime = dc.yearFraction(today, exercise); SimpleQuote spot = new SimpleQuote(0.0); YieldTermStructure qTS = Utilities.flatRate(today, q, dc); YieldTermStructure rTS = Utilities.flatRate(today, r, dc); BlackVolTermStructure volTS = Utilities.flatVol(today, sigma, dc); GeneralizedBlackScholesProcess stochProcess = new GeneralizedBlackScholesProcess( new Handle<Quote>(spot), new Handle<YieldTermStructure>(qTS), new Handle<YieldTermStructure>(rTS), new Handle<BlackVolTermStructure>(volTS)); BSMOperator op1 = new BSMOperator(grid, stochProcess, residualTime); PdeOperator<PdeBSM> op2 = new PdeOperator<PdeBSM>(grid, stochProcess, residualTime); double tolerance = 1.0e-6; Vector lderror = refer.lowerDiagonal() - op1.lowerDiagonal(); Vector derror = refer.diagonal() - op1.diagonal(); Vector uderror = refer.upperDiagonal() - op1.upperDiagonal(); for (int i = 2; i < grid.size() - 2; i++) { if (Math.Abs(lderror[i]) > tolerance || Math.Abs(derror[i]) > tolerance || Math.Abs(uderror[i]) > tolerance) { Assert.Fail("inconsistency between BSM operators:\n" + i + " row:\n" + "expected: " + refer.lowerDiagonal()[i] + ", " + refer.diagonal()[i] + ", " + refer.upperDiagonal()[i] + "\n" + "calculated: " + op1.lowerDiagonal()[i] + ", " + op1.diagonal()[i] + ", " + op1.upperDiagonal()[i]); } } lderror = refer.lowerDiagonal() - op2.lowerDiagonal(); derror = refer.diagonal() - op2.diagonal(); uderror = refer.upperDiagonal() - op2.upperDiagonal(); for (int i = 2; i < grid.size() - 2; i++) { if (Math.Abs(lderror[i]) > tolerance || Math.Abs(derror[i]) > tolerance || Math.Abs(uderror[i]) > tolerance) { Assert.Fail("inconsistency between BSM operators:\n" + i + " row:\n" + "expected: " + refer.lowerDiagonal()[i] + ", " + refer.diagonal()[i] + ", " + refer.upperDiagonal()[i] + "\n" + "calculated: " + op2.lowerDiagonal()[i] + ", " + op2.diagonal()[i] + ", " + op2.upperDiagonal()[i]); } } }
public void testFlatHazardRate() { // Testing flat hazard rate... double hazardRate = 0.0100; Handle<Quote> hazardRateQuote = new Handle<Quote>(new SimpleQuote(hazardRate)); DayCounter dayCounter = new Actual360(); Calendar calendar = new TARGET(); int n = 20; double tolerance = 1.0e-10; Date today = Settings.evaluationDate(); Date startDate = today; Date endDate = startDate; FlatHazardRate flatHazardRate = new FlatHazardRate(today, hazardRateQuote, dayCounter); for(int i=0; i<n; i++) { endDate = calendar.advance(endDate, 1, TimeUnit.Years); double t = dayCounter.yearFraction(startDate, endDate); double probability = 1.0 - Math.Exp(-hazardRate * t); double computedProbability = flatHazardRate.defaultProbability(t); if (Math.Abs(probability - computedProbability) > tolerance) Assert.Fail( "Failed to reproduce probability for flat hazard rate\n" + " calculated probability: " + computedProbability + "\n" + " expected probability: " + probability); } }
public void testAnalyticDiscreteGeometricAveragePriceGreeks() { //BOOST_MESSAGE("Testing discrete-averaging geometric Asian greeks..."); //SavedSettings backup; Dictionary<string,double> calculated, expected, tolerance; calculated = new Dictionary<string, double>(6); expected = new Dictionary<string, double>(6); tolerance = new Dictionary<string, double>(6); tolerance["delta"] = 1.0e-5; tolerance["gamma"] = 1.0e-5; tolerance["theta"] = 1.0e-5; tolerance["rho"] = 1.0e-5; tolerance["divRho"] = 1.0e-5; tolerance["vega"] = 1.0e-5; Option.Type[] types = { Option.Type.Call, Option.Type.Put }; double[] underlyings = { 100.0 }; double[] strikes = { 90.0, 100.0, 110.0 }; double[] qRates = { 0.04, 0.05, 0.06 }; double[] rRates = { 0.01, 0.05, 0.15 }; int[] lengths = { 1, 2 }; double[] vols = { 0.11, 0.50, 1.20 }; DayCounter dc = new Actual360(); Date today = Date.Today; Settings.setEvaluationDate(today); SimpleQuote spot = new SimpleQuote(0.0); SimpleQuote qRate = new SimpleQuote(0.0); Handle<YieldTermStructure> qTS = new Handle<YieldTermStructure> (Utilities.flatRate(qRate, dc)); SimpleQuote rRate = new SimpleQuote(0.0); Handle<YieldTermStructure> rTS = new Handle<YieldTermStructure> (Utilities.flatRate(rRate, dc)); SimpleQuote vol = new SimpleQuote(0.0); Handle<BlackVolTermStructure> volTS = new Handle<BlackVolTermStructure> (Utilities.flatVol(vol, dc)); BlackScholesMertonProcess process = new BlackScholesMertonProcess(new Handle<Quote>(spot), qTS, rTS, volTS); for (int i=0; i<types.Length ; i++) { for (int j=0; j<strikes.Length ; j++) { for (int k=0; k<lengths.Length ; k++) { EuropeanExercise maturity = new EuropeanExercise( today + new Period(lengths[k],TimeUnit.Years)); PlainVanillaPayoff payoff = new PlainVanillaPayoff(types[i], strikes[j]); double runningAverage = 120; int pastFixings = 1; List<Date> fixingDates = new List<Date>(); for (Date d = today + new Period(3, TimeUnit.Months); d <= maturity.lastDate(); d += new Period(3, TimeUnit.Months)) fixingDates.Add(d); IPricingEngine engine = new AnalyticDiscreteGeometricAveragePriceAsianEngine(process); DiscreteAveragingAsianOption option = new DiscreteAveragingAsianOption(Average.Type.Geometric, runningAverage, pastFixings, fixingDates, payoff, maturity); option.setPricingEngine(engine); for (int l=0; l<underlyings.Length ; l++) { for (int m=0; m<qRates.Length ; m++) { for (int n=0; n<rRates.Length ; n++) { for (int p=0; p<vols.Length ; p++) { double u = underlyings[l]; double q = qRates[m], r = rRates[n]; double v = vols[p]; spot.setValue(u); qRate.setValue(q); rRate.setValue(r); vol.setValue(v); double value = option.NPV(); calculated["delta"] = option.delta(); calculated["gamma"] = option.gamma(); calculated["theta"] = option.theta(); calculated["rho"] = option.rho(); calculated["divRho"] = option.dividendRho(); calculated["vega"] = option.vega(); if (value > spot.value()*1.0e-5) { // perturb spot and get delta and gamma double du = u*1.0e-4; spot.setValue(u+du); double value_p = option.NPV(), delta_p = option.delta(); spot.setValue(u-du); double value_m = option.NPV(), delta_m = option.delta(); spot.setValue(u); expected["delta"] = (value_p - value_m)/(2*du); expected["gamma"] = (delta_p - delta_m)/(2*du); // perturb rates and get rho and dividend rho double dr = r*1.0e-4; rRate.setValue(r+dr); value_p = option.NPV(); rRate.setValue(r-dr); value_m = option.NPV(); rRate.setValue(r); expected["rho"] = (value_p - value_m)/(2*dr); double dq = q*1.0e-4; qRate.setValue(q+dq); value_p = option.NPV(); qRate.setValue(q-dq); value_m = option.NPV(); qRate.setValue(q); expected["divRho"] = (value_p - value_m)/(2*dq); // perturb volatility and get vega double dv = v*1.0e-4; vol.setValue(v+dv); value_p = option.NPV(); vol.setValue(v-dv); value_m = option.NPV(); vol.setValue(v); expected["vega"] = (value_p - value_m)/(2*dv); // perturb date and get theta double dT = dc.yearFraction(today-1, today+1); Settings.setEvaluationDate(today-1); value_m = option.NPV(); Settings.setEvaluationDate(today+1); value_p = option.NPV(); Settings.setEvaluationDate(today); expected["theta"] = (value_p - value_m)/dT; // compare foreach (KeyValuePair<string, double> kvp in calculated){ string greek = kvp.Key; double expct = expected[greek], calcl = calculated[greek], tol = tolerance [greek]; double error =Utilities.relativeError(expct,calcl,u); if (error>tol) { REPORT_FAILURE(greek, Average.Type.Geometric, runningAverage, pastFixings, new List<Date>(), payoff, maturity, u, q, r, today, v, expct, calcl, tol); } } } } } } } } } } }