public void testCapletPricing() { //"Testing caplet pricing..."; //SavedSettings backup; const int size = 10; #if QL_USE_INDEXED_COUPON const double tolerance = 1e-5; #else const double tolerance = 1e-12; #endif IborIndex index = makeIndex(); LiborForwardModelProcess process = new LiborForwardModelProcess(size, index); // set-up pricing engine OptionletVolatilityStructure capVolCurve = makeCapVolCurve(Settings.evaluationDate()); Vector variances = new LfmHullWhiteParameterization(process, capVolCurve).covariance(0.0, null).diagonal(); LmVolatilityModel volaModel = new LmFixedVolatilityModel(Vector.Sqrt(variances), process.fixingTimes()); LmCorrelationModel corrModel = new LmExponentialCorrelationModel(size, 0.3); IAffineModel model = (IAffineModel)(new LiborForwardModel(process, volaModel, corrModel)); Handle <YieldTermStructure> termStructure = process.index().forwardingTermStructure(); AnalyticCapFloorEngine engine1 = new AnalyticCapFloorEngine(model, termStructure); Cap cap1 = new Cap(process.cashFlows(), new InitializedList <double>(size, 0.04)); cap1.setPricingEngine(engine1); const double expected = 0.015853935178; double calculated = cap1.NPV(); if (Math.Abs(expected - calculated) > tolerance) { Assert.Fail("Failed to reproduce npv" + "\n calculated: " + calculated + "\n expected: " + expected); } }
public void testSwaptionPricing() { // Testing forward swap and swaption pricing const int size = 10; const int steps = 8 * size; #if QL_USE_INDEXED_COUPON const double tolerance = 1e-6; #else const double tolerance = 1e-12; #endif List <Date> dates = new List <Date>(); List <double> rates = new List <double>(); dates.Add(new Date(4, 9, 2005)); dates.Add(new Date(4, 9, 2011)); rates.Add(0.04); rates.Add(0.08); IborIndex index = makeIndex(dates, rates); LiborForwardModelProcess process = new LiborForwardModelProcess(size, index); LmCorrelationModel corrModel = new LmExponentialCorrelationModel(size, 0.5); LmVolatilityModel volaModel = new LmLinearExponentialVolatilityModel(process.fixingTimes(), 0.291, 1.483, 0.116, 0.00001); // set-up pricing engine process.setCovarParam((LfmCovarianceParameterization) new LfmCovarianceProxy(volaModel, corrModel)); // set-up a small Monte-Carlo simulation to price swations List <double> tmp = process.fixingTimes(); TimeGrid grid = new TimeGrid(tmp, tmp.Count, steps); List <int> location = new List <int>(); for (int i = 0; i < tmp.Count; ++i) { location.Add(grid.index(tmp[i])); } ulong seed = 42; const int nrTrails = 5000; LowDiscrepancy.icInstance = new InverseCumulativeNormal(); IRNG rsg = (InverseCumulativeRsg <RandomSequenceGenerator <MersenneTwisterUniformRng> , InverseCumulativeNormal>) new PseudoRandom().make_sequence_generator(process.factors() * (grid.size() - 1), seed); MultiPathGenerator <IRNG> generator = new MultiPathGenerator <IRNG>(process, grid, rsg, false); LiborForwardModel liborModel = new LiborForwardModel(process, volaModel, corrModel); Calendar calendar = index.fixingCalendar(); DayCounter dayCounter = index.forwardingTermStructure().link.dayCounter(); BusinessDayConvention convention = index.businessDayConvention(); Date settlement = index.forwardingTermStructure().link.referenceDate(); SwaptionVolatilityMatrix m = liborModel.getSwaptionVolatilityMatrix(); for (int i = 1; i < size; ++i) { for (int j = 1; j <= size - i; ++j) { Date fwdStart = settlement + new Period(6 * i, TimeUnit.Months); Date fwdMaturity = fwdStart + new Period(6 * j, TimeUnit.Months); Schedule schedule = new Schedule(fwdStart, fwdMaturity, index.tenor(), calendar, convention, convention, DateGeneration.Rule.Forward, false); double swapRate = 0.0404; VanillaSwap forwardSwap = new VanillaSwap(VanillaSwap.Type.Receiver, 1.0, schedule, swapRate, dayCounter, schedule, index, 0.0, index.dayCounter()); forwardSwap.setPricingEngine(new DiscountingSwapEngine(index.forwardingTermStructure())); // check forward pricing first double expected = forwardSwap.fairRate(); double calculated = liborModel.S_0(i - 1, i + j - 1); if (Math.Abs(expected - calculated) > tolerance) { QAssert.Fail("Failed to reproduce fair forward swap rate" + "\n calculated: " + calculated + "\n expected: " + expected); } swapRate = forwardSwap.fairRate(); forwardSwap = new VanillaSwap(VanillaSwap.Type.Receiver, 1.0, schedule, swapRate, dayCounter, schedule, index, 0.0, index.dayCounter()); forwardSwap.setPricingEngine(new DiscountingSwapEngine(index.forwardingTermStructure())); if (i == j && i <= size / 2) { IPricingEngine engine = new LfmSwaptionEngine(liborModel, index.forwardingTermStructure()); Exercise exercise = new EuropeanExercise(process.fixingDates()[i]); Swaption swaption = new Swaption(forwardSwap, exercise); swaption.setPricingEngine(engine); GeneralStatistics stat = new GeneralStatistics(); for (int n = 0; n < nrTrails; ++n) { Sample <IPath> path = (n % 2 != 0) ? generator.antithetic() : generator.next(); MultiPath value = path.value as MultiPath; Utils.QL_REQUIRE(value != null, () => "Invalid Path"); //Sample<MultiPath> path = generator.next(); List <double> rates_ = new InitializedList <double>(size); for (int k = 0; k < process.size(); ++k) { rates_[k] = value[k][location[i]]; } List <double> dis = process.discountBond(rates_); double npv = 0.0; for (int k = i; k < i + j; ++k) { npv += (swapRate - rates_[k]) * (process.accrualEndTimes()[k] - process.accrualStartTimes()[k]) * dis[k]; } stat.add(Math.Max(npv, 0.0)); } if (Math.Abs(swaption.NPV() - stat.mean()) > stat.errorEstimate() * 2.35) { QAssert.Fail("Failed to reproduce swaption npv" + "\n calculated: " + stat.mean() + "\n expected: " + swaption.NPV()); } } } } }
public void testSimpleCovarianceModels() { // Testing simple covariance models const int size = 10; const double tolerance = 1e-14; int i; LmCorrelationModel corrModel = new LmExponentialCorrelationModel(size, 0.1); Matrix recon = corrModel.correlation(0.0, null) - corrModel.pseudoSqrt(0.0, null) * Matrix.transpose(corrModel.pseudoSqrt(0.0, null)); for (i = 0; i < size; ++i) { for (int j = 0; j < size; ++j) { if (Math.Abs(recon[i, j]) > tolerance) { QAssert.Fail("Failed to reproduce correlation matrix" + "\n calculated: " + recon[i, j] + "\n expected: " + 0); } } } List <double> fixingTimes = new InitializedList <double>(size); for (i = 0; i < size; ++i) { fixingTimes[i] = 0.5 * i; } const double a = 0.2; const double b = 0.1; const double c = 2.1; const double d = 0.3; LmVolatilityModel volaModel = new LmLinearExponentialVolatilityModel(fixingTimes, a, b, c, d); LfmCovarianceProxy covarProxy = new LfmCovarianceProxy(volaModel, corrModel); LiborForwardModelProcess process = new LiborForwardModelProcess(size, makeIndex()); LiborForwardModel liborModel = new LiborForwardModel(process, volaModel, corrModel); for (double t = 0; t < 4.6; t += 0.31) { recon = covarProxy.covariance(t, null) - covarProxy.diffusion(t, null) * Matrix.transpose(covarProxy.diffusion(t, null)); for (int k = 0; k < size; ++k) { for (int j = 0; j < size; ++j) { if (Math.Abs(recon[k, j]) > tolerance) { QAssert.Fail("Failed to reproduce correlation matrix" + "\n calculated: " + recon[k, j] + "\n expected: " + 0); } } } Vector volatility = volaModel.volatility(t, null); for (int k = 0; k < size; ++k) { double expected = 0; if (k > 2 * t) { double T = fixingTimes[k]; expected = (a * (T - t) + d) * Math.Exp(-b * (T - t)) + c; } if (Math.Abs(expected - volatility[k]) > tolerance) { QAssert.Fail("Failed to reproduce volatities" + "\n calculated: " + volatility[k] + "\n expected: " + expected); } } } }