public void testMonteCarloCapletPricing() { //"Testing caplet LMM Monte-Carlo caplet pricing..." //SavedSettings backup; /* factor loadings are taken from Hull & White article plus extra normalisation to get orthogonal eigenvectors http://www.rotman.utoronto.ca/~amackay/fin/libormktmodel2.pdf */ double[] compValues = {0.85549771, 0.46707264, 0.22353259, 0.91915359, 0.37716089, 0.11360610, 0.96438280, 0.26413316,-0.01412414, 0.97939148, 0.13492952,-0.15028753, 0.95970595,-0.00000000,-0.28100621, 0.97939148,-0.13492952,-0.15028753, 0.96438280,-0.26413316,-0.01412414, 0.91915359,-0.37716089, 0.11360610, 0.85549771,-0.46707264, 0.22353259}; Matrix volaComp=new Matrix(9,3); List<double> lcompValues=new InitializedList<double>(27,0); List<double> ltemp = new InitializedList<double>(3, 0); lcompValues=compValues.ToList(); //std::copy(compValues, compValues+9*3, volaComp.begin()); for (int i = 0; i < 9; i++) { ltemp = lcompValues.GetRange(3*i, 3); for (int j = 0; j < 3; j++) volaComp[i, j] = ltemp[j]; } LiborForwardModelProcess process1 = makeProcess(); LiborForwardModelProcess process2 = makeProcess(volaComp); List<double> tmp = process1.fixingTimes(); TimeGrid grid=new TimeGrid(tmp ,12); List<int> location=new List<int>(); for (int i=0; i < tmp.Count; ++i) { location.Add(grid.index(tmp[i])) ; } // set-up a small Monte-Carlo simulation to price caplets // and ratchet caps using a one- and a three factor libor market model ulong seed = 42; LowDiscrepancy.icInstance = new InverseCumulativeNormal(); IRNG rsg1 = (IRNG)new LowDiscrepancy().make_sequence_generator( process1.factors()*(grid.size()-1), seed); IRNG rsg2 = (IRNG)new LowDiscrepancy().make_sequence_generator( process2.factors()*(grid.size()-1), seed); MultiPathGenerator<IRNG> generator1=new MultiPathGenerator<IRNG> (process1, grid, rsg1, false); MultiPathGenerator<IRNG> generator2=new MultiPathGenerator<IRNG> (process2, grid, rsg2, false); const int nrTrails = 250000; List<GeneralStatistics> stat1 = new InitializedList<GeneralStatistics>(process1.size()); List<GeneralStatistics> stat2 = new InitializedList<GeneralStatistics>(process2.size()); List<GeneralStatistics> stat3 = new InitializedList<GeneralStatistics>(process2.size() - 1); for (int i=0; i<nrTrails; ++i) { Sample<MultiPath> path1 = generator1.next(); Sample<MultiPath> path2 = generator2.next(); List<double> rates1=new InitializedList<double>(len); List<double> rates2 = new InitializedList<double>(len); for (int j=0; j<process1.size(); ++j) { rates1[j] = path1.value[j][location[j]]; rates2[j] = path2.value[j][location[j]]; } List<double> dis1 = process1.discountBond(rates1); List<double> dis2 = process2.discountBond(rates2); for (int k=0; k<process1.size(); ++k) { double accrualPeriod = process1.accrualEndTimes()[k] - process1.accrualStartTimes()[k]; // caplet payoff function, cap rate at 4% double payoff1 = Math.Max(rates1[k] - 0.04, 0.0) * accrualPeriod; double payoff2 = Math.Max(rates2[k] - 0.04, 0.0) * accrualPeriod; stat1[k].add(dis1[k] * payoff1); stat2[k].add(dis2[k] * payoff2); if (k != 0) { // ratchet cap payoff function double payoff3 = Math.Max(rates2[k] - (rates2[k-1]+0.0025), 0.0) * accrualPeriod; stat3[k-1].add(dis2[k] * payoff3); } } } double[] capletNpv = {0.000000000000, 0.000002841629, 0.002533279333, 0.009577143571, 0.017746502618, 0.025216116835, 0.031608230268, 0.036645683881, 0.039792254012, 0.041829864365}; double[] ratchetNpv = {0.0082644895, 0.0082754754, 0.0082159966, 0.0082982822, 0.0083803357, 0.0084366961, 0.0084173270, 0.0081803406, 0.0079533814}; for (int k=0; k < process1.size(); ++k) { double calculated1 = stat1[k].mean(); double tolerance1 = stat1[k].errorEstimate(); double expected = capletNpv[k]; if (Math.Abs(calculated1 - expected) > tolerance1) { Assert.Fail("Failed to reproduce expected caplet NPV" + "\n calculated: " + calculated1 + "\n error int: " + tolerance1 + "\n expected: " + expected); } double calculated2 = stat2[k].mean(); double tolerance2 = stat2[k].errorEstimate(); if (Math.Abs(calculated2 - expected) > tolerance2) { Assert.Fail("Failed to reproduce expected caplet NPV" + "\n calculated: " + calculated2 + "\n error int: " + tolerance2 + "\n expected: " + expected); } if (k != 0) { double calculated3 = stat3[k-1].mean(); double tolerance3 = stat3[k-1].errorEstimate(); expected = ratchetNpv[k-1]; double refError = 1e-5; // 1e-5. error bars of the reference values if (Math.Abs(calculated3 - expected) > tolerance3 + refError) { Assert.Fail("Failed to reproduce expected caplet NPV" + "\n calculated: " + calculated3 + "\n error int: " + tolerance3 + refError + "\n expected: " + expected); } } } }
/*! This method checks whether the asset was rolled at the given time. */ protected bool isOnTime(double t) { TimeGrid grid = method().timeGrid(); return(Utils.close(grid[grid.index(t)], time())); }
public void testSwaptionPricing() { //"Testing forward swap and swaption pricing..."); //SavedSettings backup; 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 ,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) Assert.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<MultiPath> path = (n%2!=0) ? generator.antithetic() : generator.next(); //Sample<MultiPath> path = generator.next(); List<double> rates_ = new InitializedList<double>(size); for (int k=0; k<process.size(); ++k) { rates_[k] = path.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) Assert.Fail("Failed to reproduce swaption npv" + "\n calculated: " + stat.mean() + "\n expected: " + swaption.NPV()); } } } }