public void testInstrumentEquality() { // Testing inflation capped/floored coupon against inflation capfloor instrument... CommonVars vars = new CommonVars(); int[] lengths = { 1, 2, 3, 5, 7, 10, 15, 20 }; // vol is low ... double[] strikes = { 0.01, 0.025, 0.029, 0.03, 0.031, 0.035, 0.07 }; // yoy inflation vol is generally very low double[] vols = { 0.001, 0.005, 0.010, 0.015, 0.020 }; // this is model independent // capped coupon = fwd - cap, and fwd = swap(0) // floored coupon = fwd + floor for (int whichPricer = 0; whichPricer < 3; whichPricer++) { for (int i = 0; i < lengths.Length; i++) { for (int j = 0; j < strikes.Length; j++) { for (int k = 0; k < vols.Length; k++) { List <CashFlow> leg = vars.makeYoYLeg(vars.evaluationDate, lengths[i]); Instrument cap = vars.makeYoYCapFloor(CapFloorType.Cap, leg, strikes[j], vols[k], whichPricer); Instrument floor = vars.makeYoYCapFloor(CapFloorType.Floor, leg, strikes[j], vols[k], whichPricer); Date from = vars.nominalTS.link.referenceDate(); Date to = from + new Period(lengths[i], TimeUnit.Years); Schedule yoySchedule = new MakeSchedule().from(from).to(to) .withTenor(new Period(1, TimeUnit.Years)) .withCalendar(new UnitedKingdom()) .withConvention(BusinessDayConvention.Unadjusted) .backwards().value(); YearOnYearInflationSwap swap = new YearOnYearInflationSwap(YearOnYearInflationSwap.Type.Payer, 1000000.0, yoySchedule, //fixed schedule, but same as yoy 0.0, //strikes[j], vars.dc, yoySchedule, vars.iir, vars.observationLag, 0.0, //spread on index vars.dc, new UnitedKingdom()); Handle <YieldTermStructure> hTS = new Handle <YieldTermStructure>(vars.nominalTS); IPricingEngine sppe = new DiscountingSwapEngine(hTS); swap.setPricingEngine(sppe); List <CashFlow> leg2 = vars.makeYoYCapFlooredLeg(whichPricer, from, lengths[i], new InitializedList <double?>(lengths[i], strikes[j]), //cap new List <double?>(), //floor vols[k], 1.0, // gearing 0.0); // spread List <CashFlow> leg3 = vars.makeYoYCapFlooredLeg(whichPricer, from, lengths[i], new List <double?>(), // cap new InitializedList <double?>(lengths[i], strikes[j]), //floor vols[k], 1.0, // gearing 0.0); // spread // N.B. nominals are 10e6 double capped = CashFlows.npv(leg2, vars.nominalTS, false); if (Math.Abs(capped - (swap.NPV() - cap.NPV())) > 1.0e-6) { QAssert.Fail( "capped coupon != swap(0) - cap:\n" + " length: " + lengths[i] + " years\n" + " volatility: " + vols[k] + "\n" + " strike: " + strikes[j] + "\n" + " cap value: " + cap.NPV() + "\n" + " swap value: " + swap.NPV() + "\n" + " capped coupon " + capped); } // N.B. nominals are 10e6 double floored = CashFlows.npv(leg3, vars.nominalTS, false); if (Math.Abs(floored - (swap.NPV() + floor.NPV())) > 1.0e-6) { QAssert.Fail( "floored coupon != swap(0) + floor :\n" + " length: " + lengths[i] + " years\n" + " volatility: " + vols[k] + "\n" + " strike: " + strikes[j] + "\n" + " floor value: " + floor.NPV() + "\n" + " swap value: " + swap.NPV() + "\n" + " floored coupon " + floored); } } } } } // remove circular refernce vars.hy.linkTo(null); }
public void testMonteCarloCapletPricing() { // Testing caplet LMM Monte-Carlo caplet pricing /* 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, tmp.Count, 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 <IPath> path1 = generator1.next(); Sample <IPath> path2 = generator2.next(); MultiPath value1 = path1.value as MultiPath; Utils.QL_REQUIRE(value1 != null, () => "Invalid Path"); MultiPath value2 = path2.value as MultiPath; Utils.QL_REQUIRE(value2 != null, () => "Invalid Path"); List <double> rates1 = new InitializedList <double>(len); List <double> rates2 = new InitializedList <double>(len); for (int j = 0; j < process1.size(); ++j) { rates1[j] = value1[j][location[j]]; rates2[j] = value2[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) { QAssert.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) { QAssert.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) { QAssert.Fail("Failed to reproduce expected caplet NPV" + "\n calculated: " + calculated3 + "\n error int: " + tolerance3 + refError + "\n expected: " + expected); } } } }
public void testHalton() { //("Testing Halton sequences..."); List <double> point; double tolerance = 1.0e-15; // testing "high" dimensionality int dimensionality = (int)SobolRsg.PPMT_MAX_DIM; HaltonRsg rsg = new HaltonRsg(dimensionality, 0, false, false); int points = 100, i, k; for (i = 0; i < points; i++) { point = rsg.nextSequence().value; if (point.Count != dimensionality) { QAssert.Fail("Halton sequence generator returns " + " a sequence of wrong dimensionality: " + point.Count + " instead of " + dimensionality) ; } } // testing first and second dimension (van der Corput sequence) double[] vanderCorputSequenceModuloTwo = { // first cycle (zero excluded) 0.50000, // second cycle 0.25000, 0.75000, // third cycle 0.12500, 0.62500, 0.37500, 0.87500, // fourth cycle 0.06250, 0.56250, 0.31250, 0.81250, 0.18750, 0.68750, 0.43750, 0.93750, // fifth cycle 0.03125, 0.53125, 0.28125, 0.78125, 0.15625, 0.65625, 0.40625, 0.90625, 0.09375, 0.59375, 0.34375, 0.84375, 0.21875, 0.71875, 0.46875, 0.96875, }; dimensionality = 1; rsg = new HaltonRsg(dimensionality, 0, false, false); points = (int)(Math.Pow(2.0, 5)) - 1; // five cycles for (i = 0; i < points; i++) { point = rsg.nextSequence().value; double error = Math.Abs(point[0] - vanderCorputSequenceModuloTwo[i]); if (error > tolerance) { QAssert.Fail(i + 1 + " draw (" + /*QL_FIXED*/ +point[0] + ") in 1-D Halton sequence is not in the " + "van der Corput sequence modulo two: " + "it should have been " + vanderCorputSequenceModuloTwo[i] //+ QL_SCIENTIFIC + " (error = " + error + ")"); } } double[] vanderCorputSequenceModuloThree = { // first cycle (zero excluded) 1.0 / 3, 2.0 / 3, // second cycle 1.0 / 9, 4.0 / 9, 7.0 / 9, 2.0 / 9, 5.0 / 9, 8.0 / 9, // third cycle 1.0 / 27, 10.0 / 27, 19.0 / 27, 4.0 / 27, 13.0 / 27, 22.0 / 27, 7.0 / 27, 16.0 / 27, 25.0 / 27, 2.0 / 27, 11.0 / 27, 20.0 / 27, 5.0 / 27, 14.0 / 27, 23.0 / 27, 8.0 / 27, 17.0 / 27, 26.0 / 27 }; dimensionality = 2; rsg = new HaltonRsg(dimensionality, 0, false, false); points = (int)(Math.Pow(3.0, 3)) - 1; // three cycles of the higher dimension for (i = 0; i < points; i++) { point = rsg.nextSequence().value; double error = Math.Abs(point[0] - vanderCorputSequenceModuloTwo[i]); if (error > tolerance) { QAssert.Fail("First component of " + i + 1 + " draw (" + /*QL_FIXED*/ +point[0] + ") in 2-D Halton sequence is not in the " + "van der Corput sequence modulo two: " + "it should have been " + vanderCorputSequenceModuloTwo[i] //+ QL_SCIENTIFIC + " (error = " + error + ")"); } error = Math.Abs(point[1] - vanderCorputSequenceModuloThree[i]); if (error > tolerance) { QAssert.Fail("Second component of " + i + 1 + " draw (" + /*QL_FIXED*/ +point[1] + ") in 2-D Halton sequence is not in the " + "van der Corput sequence modulo three: " + "it should have been " + vanderCorputSequenceModuloThree[i] //+ QL_SCIENTIFIC + " (error = " + error + ")"); } } // testing homogeneity properties dimensionality = 33; rsg = new HaltonRsg(dimensionality, 0, false, false); SequenceStatistics stat = new SequenceStatistics(dimensionality); List <double> mean; //, stdev, variance, skewness, kurtosis; k = 0; int j; for (j = 1; j < 5; j++) { // five cycle points = (int)(Math.Pow(2.0, j)) - 1; // base 2 for (; k < points; k++) { point = rsg.nextSequence().value; stat.add(point); } mean = stat.mean(); double error = Math.Abs(mean[0] - 0.5); if (error > tolerance) { QAssert.Fail("First dimension mean (" + /*QL_FIXED*/ +mean[0] + ") at the end of the " + j + 1 + " cycle in Halton sequence is not " + 0.5 //+ QL_SCIENTIFIC + " (error = " + error + ")"); } } // reset generator and gaussianstatistics rsg = new HaltonRsg(dimensionality, 0, false, false); stat.reset(dimensionality); k = 0; for (j = 1; j < 3; j++) { // three cycle points = (int)(Math.Pow(3.0, j)) - 1; // base 3 for (; k < points; k++) { point = rsg.nextSequence().value; stat.add(point); } mean = stat.mean(); double error = Math.Abs(mean[1] - 0.5); if (error > tolerance) { QAssert.Fail("Second dimension mean (" + /*QL_FIXED*/ +mean[1] + ") at the end of the " + j + 1 + " cycle in Halton sequence is not " + 0.5 //+ QL_SCIENTIFIC + " (error = " + error + ")"); } } }
public void testConventions() { // Testing business day conventions... SingleCase[] testCases = { // Following new SingleCase(new SouthAfrica(), BusinessDayConvention.Following, new Date(3, Month.February, 2015), new Period(1, TimeUnit.Months), false, new Date(3, Month.March, 2015)), new SingleCase(new SouthAfrica(), BusinessDayConvention.Following, new Date(3, Month.February, 2015), new Period(4, TimeUnit.Days), false, new Date(9, Month.February, 2015)), new SingleCase(new SouthAfrica(), BusinessDayConvention.Following, new Date(31, Month.January, 2015), new Period(1, TimeUnit.Months), true, new Date(27, Month.February, 2015)), new SingleCase(new SouthAfrica(), BusinessDayConvention.Following, new Date(31, Month.January, 2015), new Period(1, TimeUnit.Months), false, new Date(2, Month.March, 2015)), //ModifiedFollowing new SingleCase(new SouthAfrica(), BusinessDayConvention.ModifiedFollowing, new Date(3, Month.February, 2015), new Period(1, TimeUnit.Months), false, new Date(3, Month.March, 2015)), new SingleCase(new SouthAfrica(), BusinessDayConvention.ModifiedFollowing, new Date(3, Month.February, 2015), new Period(4, TimeUnit.Days), false, new Date(9, Month.February, 2015)), new SingleCase(new SouthAfrica(), BusinessDayConvention.ModifiedFollowing, new Date(31, Month.January, 2015), new Period(1, TimeUnit.Months), true, new Date(27, Month.February, 2015)), new SingleCase(new SouthAfrica(), BusinessDayConvention.ModifiedFollowing, new Date(31, Month.January, 2015), new Period(1, TimeUnit.Months), false, new Date(27, Month.February, 2015)), new SingleCase(new SouthAfrica(), BusinessDayConvention.ModifiedFollowing, new Date(25, Month.March, 2015), new Period(1, TimeUnit.Months), false, new Date(28, Month.April, 2015)), new SingleCase(new SouthAfrica(), BusinessDayConvention.ModifiedFollowing, new Date(7, Month.February, 2015), new Period(1, TimeUnit.Months), false, new Date(9, Month.March, 2015)), //Preceding new SingleCase(new SouthAfrica(), BusinessDayConvention.Preceding, new Date(3, Month.March, 2015), new Period(-1, TimeUnit.Months), false, new Date(3, Month.February, 2015)), new SingleCase(new SouthAfrica(), BusinessDayConvention.Preceding, new Date(3, Month.February, 2015), new Period(-2, TimeUnit.Days), false, new Date(30, Month.January, 2015)), new SingleCase(new SouthAfrica(), BusinessDayConvention.Preceding, new Date(1, Month.March, 2015), new Period(-1, TimeUnit.Months), true, new Date(30, Month.January, 2015)), new SingleCase(new SouthAfrica(), BusinessDayConvention.Preceding, new Date(1, Month.March, 2015), new Period(-1, TimeUnit.Months), false, new Date(30, Month.January, 2015)), //ModifiedPreceding new SingleCase(new SouthAfrica(), BusinessDayConvention.ModifiedPreceding, new Date(3, Month.March, 2015), new Period(-1, TimeUnit.Months), false, new Date(3, Month.February, 2015)), new SingleCase(new SouthAfrica(), BusinessDayConvention.ModifiedPreceding, new Date(3, Month.February, 2015), new Period(-2, TimeUnit.Days), false, new Date(30, Month.January, 2015)), new SingleCase(new SouthAfrica(), BusinessDayConvention.ModifiedPreceding, new Date(1, Month.March, 2015), new Period(-1, TimeUnit.Months), true, new Date(2, Month.February, 2015)), new SingleCase(new SouthAfrica(), BusinessDayConvention.ModifiedPreceding, new Date(1, Month.March, 2015), new Period(-1, TimeUnit.Months), false, new Date(2, Month.February, 2015)), //Unadjusted new SingleCase(new SouthAfrica(), BusinessDayConvention.Unadjusted, new Date(3, Month.February, 2015), new Period(1, TimeUnit.Months), false, new Date(3, Month.March, 2015)), new SingleCase(new SouthAfrica(), BusinessDayConvention.Unadjusted, new Date(3, Month.February, 2015), new Period(4, TimeUnit.Days), false, new Date(9, Month.February, 2015)), new SingleCase(new SouthAfrica(), BusinessDayConvention.Unadjusted, new Date(31, Month.January, 2015), new Period(1, TimeUnit.Months), true, new Date(27, Month.February, 2015)), new SingleCase(new SouthAfrica(), BusinessDayConvention.Unadjusted, new Date(31, Month.January, 2015), new Period(1, TimeUnit.Months), false, new Date(28, Month.February, 2015)), //HalfMonthModifiedFollowing new SingleCase(new SouthAfrica(), BusinessDayConvention.HalfMonthModifiedFollowing, new Date(3, Month.February, 2015), new Period(1, TimeUnit.Months), false, new Date(3, Month.March, 2015)), new SingleCase(new SouthAfrica(), BusinessDayConvention.HalfMonthModifiedFollowing, new Date(3, Month.February, 2015), new Period(4, TimeUnit.Days), false, new Date(9, Month.February, 2015)), new SingleCase(new SouthAfrica(), BusinessDayConvention.HalfMonthModifiedFollowing, new Date(31, Month.January, 2015), new Period(1, TimeUnit.Months), true, new Date(27, Month.February, 2015)), new SingleCase(new SouthAfrica(), BusinessDayConvention.HalfMonthModifiedFollowing, new Date(31, Month.January, 2015), new Period(1, TimeUnit.Months), false, new Date(27, Month.February, 2015)), new SingleCase(new SouthAfrica(), BusinessDayConvention.HalfMonthModifiedFollowing, new Date(3, Month.January, 2015), new Period(1, TimeUnit.Weeks), false, new Date(12, Month.January, 2015)), new SingleCase(new SouthAfrica(), BusinessDayConvention.HalfMonthModifiedFollowing, new Date(21, Month.March, 2015), new Period(1, TimeUnit.Weeks), false, new Date(30, Month.March, 2015)), new SingleCase(new SouthAfrica(), BusinessDayConvention.HalfMonthModifiedFollowing, new Date(7, Month.February, 2015), new Period(1, TimeUnit.Months), false, new Date(9, Month.March, 2015)), //Nearest new SingleCase(new SouthAfrica(), BusinessDayConvention.Nearest, new Date(3, Month.February, 2015), new Period(1, TimeUnit.Months), false, new Date(3, Month.March, 2015)), new SingleCase(new SouthAfrica(), BusinessDayConvention.Nearest, new Date(3, Month.February, 2015), new Period(4, TimeUnit.Days), false, new Date(9, Month.February, 2015)), new SingleCase(new SouthAfrica(), BusinessDayConvention.Nearest, new Date(16, Month.April, 2015), new Period(1, TimeUnit.Months), false, new Date(15, Month.May, 2015)), new SingleCase(new SouthAfrica(), BusinessDayConvention.Nearest, new Date(17, Month.April, 2015), new Period(1, TimeUnit.Months), false, new Date(18, Month.May, 2015)), new SingleCase(new SouthAfrica(), BusinessDayConvention.Nearest, new Date(4, Month.March, 2015), new Period(1, TimeUnit.Months), false, new Date(2, Month.April, 2015)), new SingleCase(new SouthAfrica(), BusinessDayConvention.Nearest, new Date(2, Month.April, 2015), new Period(1, TimeUnit.Months), false, new Date(4, Month.May, 2015)) }; int n = testCases.Length; for (int i = 0; i < n; i++) { Calendar calendar = new Calendar(testCases[i].calendar); Date result = calendar.advance(testCases[i].start, testCases[i].period, testCases[i].convention, testCases[i].endOfMonth); QAssert.IsTrue(result == testCases[i].result, "\ncase " + i + ":\n" //<< j << " ("<< desc << "): " + "start date: " + testCases[i].start + "\n" + "calendar: " + calendar + "\n" + "period: " + testCases[i].period + ", end of month: " + testCases[i].endOfMonth + "\n" + "convention: " + testCases[i].convention + "\n" + "expected: " + testCases[i].result + " vs. actual: " + result); } }
public void testSingle(StochasticProcess1D process, string tag, bool brownianBridge, double expected, double antithetic) { ulong seed = 42; double length = 10; int timeSteps = 12; var rsg = (InverseCumulativeRsg <RandomSequenceGenerator <MersenneTwisterUniformRng> , InverseCumulativeNormal>) new PseudoRandom().make_sequence_generator(timeSteps, seed); PathGenerator <IRNG> generator = new PathGenerator <IRNG>(process, length, timeSteps, rsg, brownianBridge); int i; for (i = 0; i < 100; i++) { generator.next(); } Sample <IPath> sample = generator.next(); Path value = sample.value as Path; Utils.QL_REQUIRE(value != null, () => "Invalid Path"); double calculated = value.back(); double error = Math.Abs(calculated - expected); double tolerance = 2.0e-8; if (error > tolerance) { QAssert.Fail("using " + tag + " process " + (brownianBridge ? "with " : "without ") + "brownian bridge:\n" //+ std::setprecision(13) + " calculated: " + calculated + "\n" + " expected: " + expected + "\n" + " error: " + error + "\n" + " tolerance: " + tolerance); } sample = generator.antithetic(); value = sample.value as Path; Utils.QL_REQUIRE(value != null, () => "Invalid Path"); calculated = value.back(); error = Math.Abs(calculated - antithetic); tolerance = 2.0e-7; if (error > tolerance) { QAssert.Fail("using " + tag + " process " + (brownianBridge ? "with " : "without ") + "brownian bridge:\n" + "antithetic sample:\n" //+ setprecision(13) + " calculated: " + calculated + "\n" + " expected: " + antithetic + "\n" + " error: " + error + "\n" + " tolerance: " + tolerance); } }
public void testSmartLookup() { Currency EUR = new EURCurrency(), USD = new USDCurrency(), GBP = new GBPCurrency(), CHF = new CHFCurrency(), SEK = new SEKCurrency(), JPY = new JPYCurrency(); ExchangeRateManager rateManager = ExchangeRateManager.Instance; rateManager.clear(); ExchangeRate eur_usd1 = new ExchangeRate(EUR, USD, 1.1983); ExchangeRate eur_usd2 = new ExchangeRate(USD, EUR, 1.0 / 1.2042); rateManager.add(eur_usd1, new Date(4, Month.August, 2004)); rateManager.add(eur_usd2, new Date(5, Month.August, 2004)); ExchangeRate eur_gbp1 = new ExchangeRate(GBP, EUR, 1.0 / 0.6596); ExchangeRate eur_gbp2 = new ExchangeRate(EUR, GBP, 0.6612); rateManager.add(eur_gbp1, new Date(4, Month.August, 2004)); rateManager.add(eur_gbp2, new Date(5, Month.August, 2004)); ExchangeRate usd_chf1 = new ExchangeRate(USD, CHF, 1.2847); ExchangeRate usd_chf2 = new ExchangeRate(CHF, USD, 1.0 / 1.2774); rateManager.add(usd_chf1, new Date(4, Month.August, 2004)); rateManager.add(usd_chf2, new Date(5, Month.August, 2004)); ExchangeRate chf_sek1 = new ExchangeRate(SEK, CHF, 0.1674); ExchangeRate chf_sek2 = new ExchangeRate(CHF, SEK, 1.0 / 0.1677); rateManager.add(chf_sek1, new Date(4, Month.August, 2004)); rateManager.add(chf_sek2, new Date(5, Month.August, 2004)); ExchangeRate jpy_sek1 = new ExchangeRate(SEK, JPY, 14.5450); ExchangeRate jpy_sek2 = new ExchangeRate(JPY, SEK, 1.0 / 14.6110); rateManager.add(jpy_sek1, new Date(4, Month.August, 2004)); rateManager.add(jpy_sek2, new Date(5, Month.August, 2004)); Money m1 = 100000.0 * USD; Money m2 = 100000.0 * EUR; Money m3 = 100000.0 * GBP; Money m4 = 100000.0 * CHF; Money m5 = 100000.0 * SEK; Money m6 = 100000.0 * JPY; Money.conversionType = Money.ConversionType.NoConversion; // two-rate chain ExchangeRate usd_sek = rateManager.lookup(USD, SEK, new Date(4, Month.August, 2004)); Money calculated = usd_sek.exchange(m1); Money expected = new Money(m1.value * usd_chf1.rate / chf_sek1.rate, SEK); if (!Utils.close(calculated, expected)) { QAssert.Fail("Wrong result: expected: " + expected + " calculated: " + calculated); } usd_sek = rateManager.lookup(SEK, USD, new Date(5, Month.August, 2004)); calculated = usd_sek.exchange(m5); expected = new Money(m5.value * usd_chf2.rate / chf_sek2.rate, USD); if (!Utils.close(calculated, expected)) { QAssert.Fail("Wrong result: expected: " + expected + " calculated: " + calculated); } // three-rate chain ExchangeRate eur_sek = rateManager.lookup(EUR, SEK, new Date(4, Month.August, 2004)); calculated = eur_sek.exchange(m2); expected = new Money(m2.value * eur_usd1.rate * usd_chf1.rate / chf_sek1.rate, SEK); if (!Utils.close(calculated, expected)) { QAssert.Fail("Wrong result: expected: " + expected + " calculated: " + calculated); } eur_sek = rateManager.lookup(SEK, EUR, new Date(5, Month.August, 2004)); calculated = eur_sek.exchange(m5); expected = new Money(m5.value * eur_usd2.rate * usd_chf2.rate / chf_sek2.rate, EUR); if (!Utils.close(calculated, expected)) { QAssert.Fail("Wrong result: expected: " + expected + " calculated: " + calculated); } // four-rate chain ExchangeRate eur_jpy = rateManager.lookup(EUR, JPY, new Date(4, Month.August, 2004)); calculated = eur_jpy.exchange(m2); expected = new Money(m2.value * eur_usd1.rate * usd_chf1.rate * jpy_sek1.rate / chf_sek1.rate, JPY); if (!Utils.close(calculated, expected)) { QAssert.Fail("Wrong result: expected: " + expected + " calculated: " + calculated); } eur_jpy = rateManager.lookup(JPY, EUR, new Date(5, Month.August, 2004)); calculated = eur_jpy.exchange(m6); expected = new Money(m6.value * jpy_sek2.rate * eur_usd2.rate * usd_chf2.rate / chf_sek2.rate, EUR); if (!Utils.close(calculated, expected)) { QAssert.Fail("Wrong result: expected: " + expected + " calculated: " + calculated); } // five-rate chain ExchangeRate gbp_jpy = rateManager.lookup(GBP, JPY, new Date(4, Month.August, 2004)); calculated = gbp_jpy.exchange(m3); expected = new Money(m3.value * eur_gbp1.rate * eur_usd1.rate * usd_chf1.rate * jpy_sek1.rate / chf_sek1.rate, JPY); if (!Utils.close(calculated, expected)) { QAssert.Fail("Wrong result: expected: " + expected + " calculated: " + calculated); } gbp_jpy = rateManager.lookup(JPY, GBP, new Date(5, Month.August, 2004)); calculated = gbp_jpy.exchange(m6); expected = new Money(m6.value * jpy_sek2.rate * eur_usd2.rate * usd_chf2.rate * eur_gbp2.rate / chf_sek2.rate, GBP); if (!Utils.close(calculated, expected)) { QAssert.Fail("Wrong result: expected: " + expected + " calculated: " + calculated); } }
public void testSwaps() { //BOOST_MESSAGE("Testing Hull-White swap pricing against known values..."); Date today; //=Settings::instance().evaluationDate();; Calendar calendar = new TARGET(); today = calendar.adjust(Date.Today); Settings.setEvaluationDate(today); Date settlement = calendar.advance(today, 2, TimeUnit.Days); Date[] dates = { settlement, calendar.advance(settlement, 1, TimeUnit.Weeks), calendar.advance(settlement, 1, TimeUnit.Months), calendar.advance(settlement, 3, TimeUnit.Months), calendar.advance(settlement, 6, TimeUnit.Months), calendar.advance(settlement, 9, TimeUnit.Months), calendar.advance(settlement, 1, TimeUnit.Years), calendar.advance(settlement, 2, TimeUnit.Years), calendar.advance(settlement, 3, TimeUnit.Years), calendar.advance(settlement, 5, TimeUnit.Years), calendar.advance(settlement, 10, TimeUnit.Years), calendar.advance(settlement, 15, TimeUnit.Years) }; double[] discounts = { 1.0, 0.999258, 0.996704, 0.990809, 0.981798, 0.972570, 0.963430, 0.929532, 0.889267, 0.803693, 0.596903, 0.433022 }; //for (int i = 0; i < dates.Length; i++) // dates[i] + dates.Length; LogLinear Interpolator = new LogLinear(); Handle <YieldTermStructure> termStructure = new Handle <YieldTermStructure>( new InterpolatedDiscountCurve <LogLinear>( dates.ToList <Date>(), discounts.ToList <double>(), new Actual365Fixed(), new Calendar(), null, null, Interpolator) ); HullWhite model = new HullWhite(termStructure); int[] start = { -3, 0, 3 }; int[] length = { 2, 5, 10 }; double[] rates = { 0.02, 0.04, 0.06 }; IborIndex euribor = new Euribor6M(termStructure); IPricingEngine engine = new TreeVanillaSwapEngine(model, 120, termStructure); #if QL_USE_INDEXED_COUPON double tolerance = 4.0e-3; #else double tolerance = 1.0e-8; #endif for (int i = 0; i < start.Length; i++) { Date startDate = calendar.advance(settlement, start[i], TimeUnit.Months); if (startDate < today) { Date fixingDate = calendar.advance(startDate, -2, TimeUnit.Days); TimeSeries <double?> pastFixings = new TimeSeries <double?>(); pastFixings[fixingDate] = 0.03; IndexManager.instance().setHistory(euribor.name(), pastFixings); } for (int j = 0; j < length.Length; j++) { Date maturity = calendar.advance(startDate, length[i], TimeUnit.Years); Schedule fixedSchedule = new Schedule(startDate, maturity, new Period(Frequency.Annual), calendar, BusinessDayConvention.Unadjusted, BusinessDayConvention.Unadjusted, DateGeneration.Rule.Forward, false); Schedule floatSchedule = new Schedule(startDate, maturity, new Period(Frequency.Semiannual), calendar, BusinessDayConvention.Following, BusinessDayConvention.Following, DateGeneration.Rule.Forward, false); for (int k = 0; k < rates.Length; k++) { VanillaSwap swap = new VanillaSwap(VanillaSwap.Type.Payer, 1000000.0, fixedSchedule, rates[k], new Thirty360(), floatSchedule, euribor, 0.0, new Actual360()); swap.setPricingEngine(new DiscountingSwapEngine(termStructure)); double expected = swap.NPV(); swap.setPricingEngine(engine); double calculated = swap.NPV(); double error = Math.Abs((expected - calculated) / expected); if (error > tolerance) { QAssert.Fail("Failed to reproduce swap NPV:" //+ QL_FIXED << std::setprecision(9) + "\n calculated: " + calculated + "\n expected: " + expected //+ QL_SCIENTIFIC + "\n rel. error: " + error); } } } } }
public void testActualActual() { SingleCase[] testCases = { // first example new SingleCase(ActualActual.Convention.ISDA, new Date(1, Month.November, 2003), new Date(1, Month.May, 2004), 0.497724380567), new SingleCase(ActualActual.Convention.ISMA, new Date(1, Month.November, 2003), new Date(1, Month.May, 2004), new Date(1, Month.November, 2003), new Date(1, Month.May, 2004), 0.500000000000), new SingleCase(ActualActual.Convention.AFB, new Date(1, Month.November, 2003), new Date(1, Month.May, 2004), 0.497267759563), // short first calculation period (first period) new SingleCase(ActualActual.Convention.ISDA, new Date(1, Month.February, 1999), new Date(1, Month.July, 1999), 0.410958904110), new SingleCase(ActualActual.Convention.ISMA, new Date(1, Month.February, 1999), new Date(1, Month.July, 1999), new Date(1, Month.July, 1998), new Date(1, Month.July, 1999), 0.410958904110), new SingleCase(ActualActual.Convention.AFB, new Date(1, Month.February, 1999), new Date(1, Month.July, 1999), 0.410958904110), // short first calculation period (second period) new SingleCase(ActualActual.Convention.ISDA, new Date(1, Month.July, 1999), new Date(1, Month.July, 2000), 1.001377348600), new SingleCase(ActualActual.Convention.ISMA, new Date(1, Month.July, 1999), new Date(1, Month.July, 2000), new Date(1, Month.July, 1999), new Date(1, Month.July, 2000), 1.000000000000), new SingleCase(ActualActual.Convention.AFB, new Date(1, Month.July, 1999), new Date(1, Month.July, 2000), 1.000000000000), // long first calculation period (first period) new SingleCase(ActualActual.Convention.ISDA, new Date(15, Month.August, 2002), new Date(15, Month.July, 2003), 0.915068493151), new SingleCase(ActualActual.Convention.ISMA, new Date(15, Month.August, 2002), new Date(15, Month.July, 2003), new Date(15, Month.January, 2003), new Date(15, Month.July, 2003), 0.915760869565), new SingleCase(ActualActual.Convention.AFB, new Date(15, Month.August, 2002), new Date(15, Month.July, 2003), 0.915068493151), // long first calculation period (second period) /* Warning: the ISDA case is in disagreement with mktc1198.pdf */ new SingleCase(ActualActual.Convention.ISDA, new Date(15, Month.July, 2003), new Date(15, Month.January, 2004), 0.504004790778), new SingleCase(ActualActual.Convention.ISMA, new Date(15, Month.July, 2003), new Date(15, Month.January, 2004), new Date(15, Month.July, 2003), new Date(15, Month.January, 2004), 0.500000000000), new SingleCase(ActualActual.Convention.AFB, new Date(15, Month.July, 2003), new Date(15, Month.January, 2004), 0.504109589041), // short final calculation period (penultimate period) new SingleCase(ActualActual.Convention.ISDA, new Date(30, Month.July, 1999), new Date(30, Month.January, 2000), 0.503892506924), new SingleCase(ActualActual.Convention.ISMA, new Date(30, Month.July, 1999), new Date(30, Month.January, 2000), new Date(30, Month.July, 1999), new Date(30, Month.January, 2000), 0.500000000000), new SingleCase(ActualActual.Convention.AFB, new Date(30, Month.July, 1999), new Date(30, Month.January, 2000), 0.504109589041), // short final calculation period (final period) new SingleCase(ActualActual.Convention.ISDA, new Date(30, Month.January, 2000), new Date(30, Month.June, 2000), 0.415300546448), new SingleCase(ActualActual.Convention.ISMA, new Date(30, Month.January, 2000), new Date(30, Month.June, 2000), new Date(30, Month.January, 2000), new Date(30, Month.July, 2000), 0.417582417582), new SingleCase(ActualActual.Convention.AFB, new Date(30, Month.January, 2000), new Date(30, Month.June, 2000), 0.41530054644) }; int n = testCases.Length; /// sizeof(SingleCase); for (int i = 0; i < n; i++) { ActualActual dayCounter = new ActualActual(testCases[i]._convention); Date d1 = testCases[i]._start; Date d2 = testCases[i]._end; Date rd1 = testCases[i]._refStart; Date rd2 = testCases[i]._refEnd; double calculated = dayCounter.yearFraction(d1, d2, rd1, rd2); if (Math.Abs(calculated - testCases[i]._result) > 1.0e-10) { QAssert.Fail(dayCounter.name() + "period: " + d1 + " to " + d2 + " calculated: " + calculated + " expected: " + testCases[i]._result); } } }
public void testChambersImpliedVol() { // Testing Chambers-Nawalkha implied vol approximation Option.Type[] types = { Option.Type.Call, Option.Type.Put }; double[] displacements = { 0.0000, 0.0010, 0.0050, 0.0100, 0.0200 }; double[] forwards = { -0.0010, 0.0000, 0.0050, 0.0100, 0.0200, 0.0500 }; double[] strikes = { -0.0100, -0.0050, -0.0010, 0.0000, 0.0010, 0.0050, 0.0100, 0.0200, 0.0500, 0.1000 }; double[] stdDevs = { 0.10, 0.15, 0.20, 0.30, 0.50, 0.60, 0.70, 0.80, 1.00, 1.50, 2.00 }; double[] discounts = { 1.00, 0.95, 0.80, 1.10 }; double tol = 5.0E-4; for (int i1 = 0; i1 < types.Length; ++i1) { for (int i2 = 0; i2 < displacements.Length; ++i2) { for (int i3 = 0; i3 < forwards.Length; ++i3) { for (int i4 = 0; i4 < strikes.Length; ++i4) { for (int i5 = 0; i5 < stdDevs.Length; ++i5) { for (int i6 = 0; i6 < discounts.Length; ++i6) { if (forwards[i3] + displacements[i2] > 0.0 && strikes[i4] + displacements[i2] > 0.0) { double premium = Utils.blackFormula( types[i1], strikes[i4], forwards[i3], stdDevs[i5], discounts[i6], displacements[i2]); double atmPremium = Utils.blackFormula( types[i1], forwards[i3], forwards[i3], stdDevs[i5], discounts[i6], displacements[i2]); double iStdDev = Utils.blackFormulaImpliedStdDevChambers( types[i1], strikes[i4], forwards[i3], premium, atmPremium, discounts[i6], displacements[i2]); double moneyness = (strikes[i4] + displacements[i2]) / (forwards[i3] + displacements[i2]); if (moneyness > 1.0) { moneyness = 1.0 / moneyness; } double error = (iStdDev - stdDevs[i5]) / stdDevs[i5] * moneyness; if (error > tol) { QAssert.Fail("Failed to verify Chambers-Nawalkha approximation for " + types[i1] + " displacement=" + displacements[i2] + " forward=" + forwards[i3] + " strike=" + strikes[i4] + " discount=" + discounts[i6] + " stddev=" + stdDevs[i5] + " result=" + iStdDev + " exceeds maximum error tolerance"); } } } } } } } } }
public void testThirty360_BondBasis() { // Testing thirty/360 day counter (Bond Basis) // http://www.isda.org/c_and_a/docs/30-360-2006ISDADefs.xls // Source: 2006 ISDA Definitions, Sec. 4.16 (f) // 30/360 (or Bond Basis) DayCounter dayCounter = new Thirty360(Thirty360.Thirty360Convention.BondBasis); List <Date> testStartDates = new List <Date>(); List <Date> testEndDates = new List <Date>(); int calculated; // ISDA - Example 1: End dates do not involve the last day of February testStartDates.Add(new Date(20, Month.August, 2006)); testEndDates.Add(new Date(20, Month.February, 2007)); testStartDates.Add(new Date(20, Month.February, 2007)); testEndDates.Add(new Date(20, Month.August, 2007)); testStartDates.Add(new Date(20, Month.August, 2007)); testEndDates.Add(new Date(20, Month.February, 2008)); testStartDates.Add(new Date(20, Month.February, 2008)); testEndDates.Add(new Date(20, Month.August, 2008)); testStartDates.Add(new Date(20, Month.August, 2008)); testEndDates.Add(new Date(20, Month.February, 2009)); testStartDates.Add(new Date(20, Month.February, 2009)); testEndDates.Add(new Date(20, Month.August, 2009)); // ISDA - Example 2: End dates include some end-February dates testStartDates.Add(new Date(31, Month.August, 2006)); testEndDates.Add(new Date(28, Month.February, 2007)); testStartDates.Add(new Date(28, Month.February, 2007)); testEndDates.Add(new Date(31, Month.August, 2007)); testStartDates.Add(new Date(31, Month.August, 2007)); testEndDates.Add(new Date(29, Month.February, 2008)); testStartDates.Add(new Date(29, Month.February, 2008)); testEndDates.Add(new Date(31, Month.August, 2008)); testStartDates.Add(new Date(31, Month.August, 2008)); testEndDates.Add(new Date(28, Month.February, 2009)); testStartDates.Add(new Date(28, Month.February, 2009)); testEndDates.Add(new Date(31, Month.August, 2009)); //// ISDA - Example 3: Miscellaneous calculations testStartDates.Add(new Date(31, Month.January, 2006)); testEndDates.Add(new Date(28, Month.February, 2006)); testStartDates.Add(new Date(30, Month.January, 2006)); testEndDates.Add(new Date(28, Month.February, 2006)); testStartDates.Add(new Date(28, Month.February, 2006)); testEndDates.Add(new Date(3, Month.March, 2006)); testStartDates.Add(new Date(14, Month.February, 2006)); testEndDates.Add(new Date(28, Month.February, 2006)); testStartDates.Add(new Date(30, Month.September, 2006)); testEndDates.Add(new Date(31, Month.October, 2006)); testStartDates.Add(new Date(31, Month.October, 2006)); testEndDates.Add(new Date(28, Month.November, 2006)); testStartDates.Add(new Date(31, Month.August, 2007)); testEndDates.Add(new Date(28, Month.February, 2008)); testStartDates.Add(new Date(28, Month.February, 2008)); testEndDates.Add(new Date(28, Month.August, 2008)); testStartDates.Add(new Date(28, Month.February, 2008)); testEndDates.Add(new Date(30, Month.August, 2008)); testStartDates.Add(new Date(28, Month.February, 2008)); testEndDates.Add(new Date(31, Month.August, 2008)); testStartDates.Add(new Date(26, Month.February, 2007)); testEndDates.Add(new Date(28, Month.February, 2008)); testStartDates.Add(new Date(26, Month.February, 2007)); testEndDates.Add(new Date(29, Month.February, 2008)); testStartDates.Add(new Date(29, Month.February, 2008)); testEndDates.Add(new Date(28, Month.February, 2009)); testStartDates.Add(new Date(28, Month.February, 2008)); testEndDates.Add(new Date(30, Month.March, 2008)); testStartDates.Add(new Date(28, Month.February, 2008)); testEndDates.Add(new Date(31, Month.March, 2008)); int[] expected = { 180, 180, 180, 180, 180, 180, 178, 183, 179, 182, 178, 183, 28, 28, 5, 14, 30, 28, 178, 180, 182, 183, 362, 363, 359, 32, 33 }; for (int i = 0; i < testStartDates.Count; i++) { calculated = dayCounter.dayCount(testStartDates[i], testEndDates[i]); if (calculated != expected[i]) { QAssert.Fail("from " + testStartDates[i] + " to " + testEndDates[i] + ":\n" + " calculated: " + calculated + "\n" + " expected: " + expected[i]); } } }
public void testThirty360_EurobondBasis() { // Testing thirty/360 day counter (Eurobond Basis) // Source: ISDA 2006 Definitions 4.16 (g) // 30E/360 (or Eurobond Basis) // Based on ICMA (Rule 251) and FBF; this is the version of 30E/360 used by Excel DayCounter dayCounter = new Thirty360(Thirty360.Thirty360Convention.EurobondBasis); List <Date> testStartDates = new List <Date>(); List <Date> testEndDates = new List <Date>(); int calculated; // ISDA - Example 1: End dates do not involve the last day of February testStartDates.Add(new Date(20, Month.August, 2006)); testEndDates.Add(new Date(20, Month.February, 2007)); testStartDates.Add(new Date(20, Month.February, 2007)); testEndDates.Add(new Date(20, Month.August, 2007)); testStartDates.Add(new Date(20, Month.August, 2007)); testEndDates.Add(new Date(20, Month.February, 2008)); testStartDates.Add(new Date(20, Month.February, 2008)); testEndDates.Add(new Date(20, Month.August, 2008)); testStartDates.Add(new Date(20, Month.August, 2008)); testEndDates.Add(new Date(20, Month.February, 2009)); testStartDates.Add(new Date(20, Month.February, 2009)); testEndDates.Add(new Date(20, Month.August, 2009)); //// ISDA - Example 2: End dates include some end-February dates testStartDates.Add(new Date(28, Month.February, 2006)); testEndDates.Add(new Date(31, Month.August, 2006)); testStartDates.Add(new Date(31, Month.August, 2006)); testEndDates.Add(new Date(28, Month.February, 2007)); testStartDates.Add(new Date(28, Month.February, 2007)); testEndDates.Add(new Date(31, Month.August, 2007)); testStartDates.Add(new Date(31, Month.August, 2007)); testEndDates.Add(new Date(29, Month.February, 2008)); testStartDates.Add(new Date(29, Month.February, 2008)); testEndDates.Add(new Date(31, Month.August, 2008)); testStartDates.Add(new Date(31, Month.August, 2008)); testEndDates.Add(new Date(28, Month.Feb, 2009)); testStartDates.Add(new Date(28, Month.February, 2009)); testEndDates.Add(new Date(31, Month.August, 2009)); testStartDates.Add(new Date(31, Month.August, 2009)); testEndDates.Add(new Date(28, Month.Feb, 2010)); testStartDates.Add(new Date(28, Month.February, 2010)); testEndDates.Add(new Date(31, Month.August, 2010)); testStartDates.Add(new Date(31, Month.August, 2010)); testEndDates.Add(new Date(28, Month.Feb, 2011)); testStartDates.Add(new Date(28, Month.February, 2011)); testEndDates.Add(new Date(31, Month.August, 2011)); testStartDates.Add(new Date(31, Month.August, 2011)); testEndDates.Add(new Date(29, Month.Feb, 2012)); //// ISDA - Example 3: Miscellaneous calculations testStartDates.Add(new Date(31, Month.January, 2006)); testEndDates.Add(new Date(28, Month.February, 2006)); testStartDates.Add(new Date(30, Month.January, 2006)); testEndDates.Add(new Date(28, Month.February, 2006)); testStartDates.Add(new Date(28, Month.February, 2006)); testEndDates.Add(new Date(3, Month.March, 2006)); testStartDates.Add(new Date(14, Month.February, 2006)); testEndDates.Add(new Date(28, Month.February, 2006)); testStartDates.Add(new Date(30, Month.September, 2006)); testEndDates.Add(new Date(31, Month.October, 2006)); testStartDates.Add(new Date(31, Month.October, 2006)); testEndDates.Add(new Date(28, Month.November, 2006)); testStartDates.Add(new Date(31, Month.August, 2007)); testEndDates.Add(new Date(28, Month.February, 2008)); testStartDates.Add(new Date(28, Month.February, 2008)); testEndDates.Add(new Date(28, Month.August, 2008)); testStartDates.Add(new Date(28, Month.February, 2008)); testEndDates.Add(new Date(30, Month.August, 2008)); testStartDates.Add(new Date(28, Month.February, 2008)); testEndDates.Add(new Date(31, Month.August, 2008)); testStartDates.Add(new Date(26, Month.February, 2007)); testEndDates.Add(new Date(28, Month.February, 2008)); testStartDates.Add(new Date(26, Month.February, 2007)); testEndDates.Add(new Date(29, Month.February, 2008)); testStartDates.Add(new Date(29, Month.February, 2008)); testEndDates.Add(new Date(28, Month.February, 2009)); testStartDates.Add(new Date(28, Month.February, 2008)); testEndDates.Add(new Date(30, Month.March, 2008)); testStartDates.Add(new Date(28, Month.February, 2008)); testEndDates.Add(new Date(31, Month.March, 2008)); int[] expected = { 180, 180, 180, 180, 180, 180, 182, 178, 182, 179, 181, 178, 182, 178, 182, 178, 182, 179, 28, 28, 5, 14, 30, 28, 178, 180, 182, 182, 362, 363, 359, 32, 32 }; for (int i = 0; i < testStartDates.Count; i++) { calculated = dayCounter.dayCount(testStartDates[i], testEndDates[i]); if (calculated != expected[i]) { QAssert.Fail("from " + testStartDates[i] + " to " + testEndDates[i] + ":\n" + " calculated: " + calculated + "\n" + " expected: " + expected[i]); } } }
public void testBusiness252() { // Testing business/252 day counter List <Date> testDates = new List <Date>(); testDates.Add(new Date(1, Month.February, 2002)); testDates.Add(new Date(4, Month.February, 2002)); testDates.Add(new Date(16, Month.May, 2003)); testDates.Add(new Date(17, Month.December, 2003)); testDates.Add(new Date(17, Month.December, 2004)); testDates.Add(new Date(19, Month.December, 2005)); testDates.Add(new Date(2, Month.January, 2006)); testDates.Add(new Date(13, Month.March, 2006)); testDates.Add(new Date(15, Month.May, 2006)); testDates.Add(new Date(17, Month.March, 2006)); testDates.Add(new Date(15, Month.May, 2006)); testDates.Add(new Date(26, Month.July, 2006)); testDates.Add(new Date(28, Month.June, 2007)); testDates.Add(new Date(16, Month.September, 2009)); testDates.Add(new Date(26, Month.July, 2016)); double[] expected = { 0.0039682539683, 1.2738095238095, 0.6031746031746, 0.9960317460317, 1.0000000000000, 0.0396825396825, 0.1904761904762, 0.1666666666667, -0.1507936507937, 0.1507936507937, 0.2023809523810, 0.912698412698, 2.214285714286, 6.84126984127 }; DayCounter dayCounter1 = new Business252(new Brazil()); double calculated; for (int i = 1; i < testDates.Count; i++) { calculated = dayCounter1.yearFraction(testDates[i - 1], testDates[i]); if (Math.Abs(calculated - expected[i - 1]) > 1.0e-12) { QAssert.Fail("from " + testDates[i - 1] + " to " + testDates[i] + ":\n" + " calculated: " + calculated + "\n" + " expected: " + expected[i - 1]); } } DayCounter dayCounter2 = new Business252(); for (int i = 1; i < testDates.Count; i++) { calculated = dayCounter2.yearFraction(testDates[i - 1], testDates[i]); if (Math.Abs(calculated - expected[i - 1]) > 1.0e-12) { QAssert.Fail("from " + testDates[i - 1] + " to " + testDates[i] + ":\n" + " calculated: " + calculated + "\n" + " expected: " + expected[i - 1]); } } }
public void testActualActualWithSchedule() { // Testing actual/actual day counter with schedule // long first coupon Date issueDateExpected = new Date(17, Month.January, 2017); Date firstCouponDateExpected = new Date(31, Month.August, 2017); Schedule schedule = new MakeSchedule() .from(issueDateExpected) .withFirstDate(firstCouponDateExpected) .to(new Date(28, Month.February, 2026)) .withFrequency(Frequency.Semiannual) .withCalendar(new Canada()) .withConvention(BusinessDayConvention.Unadjusted) .backwards() .endOfMonth().value(); Date issueDate = schedule.date(0); Utils.QL_REQUIRE(issueDate == issueDateExpected, () => "This is not the expected issue date " + issueDate + " expected " + issueDateExpected); Date firstCouponDate = schedule.date(1); Utils.QL_REQUIRE(firstCouponDate == firstCouponDateExpected, () => "This is not the expected first coupon date " + firstCouponDate + " expected: " + firstCouponDateExpected); //Make thw quasi coupon dates: Date quasiCouponDate2 = schedule.calendar().advance(firstCouponDate, -schedule.tenor(), schedule.businessDayConvention(), schedule.endOfMonth()); Date quasiCouponDate1 = schedule.calendar().advance(quasiCouponDate2, -schedule.tenor(), schedule.businessDayConvention(), schedule.endOfMonth()); Date quasiCouponDate1Expected = new Date(31, Month.August, 2016); Date quasiCouponDate2Expected = new Date(28, Month.February, 2017); Utils.QL_REQUIRE(quasiCouponDate2 == quasiCouponDate2Expected, () => "Expected " + quasiCouponDate2Expected + " as the later quasi coupon date but received " + quasiCouponDate2); Utils.QL_REQUIRE(quasiCouponDate1 == quasiCouponDate1Expected, () => "Expected " + quasiCouponDate1Expected + " as the earlier quasi coupon date but received " + quasiCouponDate1); DayCounter dayCounter = new ActualActual(ActualActual.Convention.ISMA, schedule); // full coupon double t_with_reference = dayCounter.yearFraction( issueDate, firstCouponDate, quasiCouponDate2, firstCouponDate ); double t_no_reference = dayCounter.yearFraction( issueDate, firstCouponDate ); double t_total = ISMAYearFractionWithReferenceDates(dayCounter, issueDate, quasiCouponDate2, quasiCouponDate1, quasiCouponDate2) + 0.5; double expected = 0.6160220994; if (Math.Abs(t_total - expected) > 1.0e-10) { QAssert.Fail("Failed to reproduce expected time:\n" + " calculated: " + t_total + "\n" + " expected: " + expected); } if (Math.Abs(t_with_reference - expected) > 1.0e-10) { QAssert.Fail("Failed to reproduce expected time:\n" + " calculated: " + t_with_reference + "\n" + " expected: " + expected); } if (Math.Abs(t_no_reference - t_with_reference) > 1.0e-10) { QAssert.Fail("Should produce the same time whether or not references are present"); } // settlement date in the first quasi-period Date settlementDate = new Date(29, Month.January, 2017); t_with_reference = ISMAYearFractionWithReferenceDates( dayCounter, issueDate, settlementDate, quasiCouponDate1, quasiCouponDate2 ); t_no_reference = dayCounter.yearFraction(issueDate, settlementDate); double t_expected_first_qp = 0.03314917127071823; //12.0/362 if (Math.Abs(t_with_reference - t_expected_first_qp) > 1.0e-10) { QAssert.Fail("Failed to reproduce expected time:\n" + " calculated: " + t_no_reference + "\n" + " expected: " + t_expected_first_qp); } if (Math.Abs(t_no_reference - t_with_reference) > 1.0e-10) { QAssert.Fail("Should produce the same time whether or not references are present"); } double t2 = dayCounter.yearFraction(settlementDate, firstCouponDate); if (Math.Abs(t_expected_first_qp + t2 - expected) > 1.0e-10) { QAssert.Fail("Sum of quasiperiod2 split is not consistent"); } // settlement date in the second quasi-period settlementDate = new Date(29, Month.July, 2017); t_no_reference = dayCounter.yearFraction(issueDate, settlementDate); t_with_reference = ISMAYearFractionWithReferenceDates( dayCounter, issueDate, quasiCouponDate2, quasiCouponDate1, quasiCouponDate2 ) + ISMAYearFractionWithReferenceDates( dayCounter, quasiCouponDate2, settlementDate, quasiCouponDate2, firstCouponDate ); if (Math.Abs(t_no_reference - t_with_reference) > 1.0e-10) { QAssert.Fail("These two cases should be identical"); } t2 = dayCounter.yearFraction(settlementDate, firstCouponDate); if (Math.Abs(t_total - (t_no_reference + t2)) > 1.0e-10) { QAssert.Fail("Failed to reproduce expected time:\n" + " calculated: " + t_total + "\n" + " expected: " + t_no_reference + t2); } }
public void testActualActualWithSemiannualSchedule() { // Testing actual/actual with schedule for undefined semiannual reference periods Calendar calendar = new UnitedStates(); Date fromDate = new Date(10, Month.January, 2017); Date firstCoupon = new Date(31, Month.August, 2017); Date quasiCoupon = new Date(28, Month.February, 2017); Date quasiCoupon2 = new Date(31, Month.August, 2016); Schedule schedule = new MakeSchedule() .from(fromDate) .withFirstDate(firstCoupon) .to(new Date(28, Month.February, 2026)) .withFrequency(Frequency.Semiannual) .withCalendar(calendar) .withConvention(BusinessDayConvention.Unadjusted) .backwards().endOfMonth(true).value(); Date testDate = schedule.date(1); DayCounter dayCounter = new ActualActual(ActualActual.Convention.ISMA, schedule); DayCounter dayCounterNoSchedule = new ActualActual(ActualActual.Convention.ISMA); Date referencePeriodStart = schedule.date(1); Date referencePeriodEnd = schedule.date(2); // Test QAssert.IsTrue(dayCounter.yearFraction(referencePeriodStart, referencePeriodStart).IsEqual(0.0), "This should be zero."); QAssert.IsTrue(dayCounterNoSchedule.yearFraction(referencePeriodStart, referencePeriodStart).IsEqual(0.0), "This should be zero"); QAssert.IsTrue(dayCounterNoSchedule.yearFraction(referencePeriodStart, referencePeriodStart, referencePeriodStart, referencePeriodStart).IsEqual(0.0), "This should be zero"); QAssert.IsTrue(dayCounter.yearFraction(referencePeriodStart, referencePeriodEnd).IsEqual(0.5), "This should be exact using schedule; " + referencePeriodStart + " to " + referencePeriodEnd + "Should be 0.5"); QAssert.IsTrue(dayCounterNoSchedule.yearFraction(referencePeriodStart, referencePeriodEnd, referencePeriodStart, referencePeriodEnd).IsEqual(0.5), "This should be exact for explicit reference periods with no schedule"); while (testDate < referencePeriodEnd) { double difference = dayCounter.yearFraction(testDate, referencePeriodEnd, referencePeriodStart, referencePeriodEnd) - dayCounter.yearFraction(testDate, referencePeriodEnd); if (Math.Abs(difference) > 1.0e-10) { QAssert.Fail("Failed to correctly use the schedule to find the reference period for Act/Act"); } testDate = calendar.advance(testDate, 1, TimeUnit.Days); } //Test long first coupon double calculatedYearFraction = dayCounter.yearFraction(fromDate, firstCoupon); double expectedYearFraction = 0.5 + ((double)dayCounter.dayCount(fromDate, quasiCoupon)) / (2 * dayCounter.dayCount(quasiCoupon2, quasiCoupon)); QAssert.IsTrue(Math.Abs(calculatedYearFraction - expectedYearFraction) < 1.0e-10, "Failed to compute the expected year fraction " + "\n expected: " + expectedYearFraction + "\n calculated: " + calculatedYearFraction); // test multiple periods schedule = new MakeSchedule() .from(new Date(10, Month.January, 2017)) .withFirstDate(new Date(31, Month.August, 2017)) .to(new Date(28, Month.February, 2026)) .withFrequency(Frequency.Semiannual) .withCalendar(calendar) .withConvention(BusinessDayConvention.Unadjusted) .backwards().endOfMonth(false).value(); Date periodStartDate = schedule.date(1); Date periodEndDate = schedule.date(2); dayCounter = new ActualActual(ActualActual.Convention.ISMA, schedule); while (periodEndDate < schedule.date(schedule.size() - 2)) { double expected = actualActualDaycountComputation(schedule, periodStartDate, periodEndDate); double calculated = dayCounter.yearFraction(periodStartDate, periodEndDate); if (Math.Abs(expected - calculated) > 1e-8) { QAssert.Fail("Failed to compute the correct year fraction " + "given a schedule: " + periodStartDate + " to " + periodEndDate + "\n expected: " + expected + " calculated: " + calculated); } periodEndDate = calendar.advance(periodEndDate, 1, TimeUnit.Days); } }
public void testCalibration() { // Testing calibration of a Libor forward model const int size = 14; const double tolerance = 8e-3; double[] capVols = { 0.145708, 0.158465, 0.166248, 0.168672, 0.169007, 0.167956, 0.166261, 0.164239, 0.162082, 0.159923, 0.157781, 0.155745, 0.153776, 0.151950, 0.150189, 0.148582, 0.147034, 0.145598, 0.144248 }; double[] swaptionVols = { 0.170595, 0.166844, 0.158306, 0.147444, 0.136930, 0.126833, 0.118135, 0.175963, 0.166359, 0.155203, 0.143712, 0.132769, 0.122947, 0.114310, 0.174455, 0.162265, 0.150539, 0.138734, 0.128215, 0.118470, 0.110540, 0.169780, 0.156860, 0.144821, 0.133537, 0.123167, 0.114363, 0.106500, 0.164521, 0.151223, 0.139670, 0.128632, 0.119123, 0.110330, 0.103114, 0.158956, 0.146036, 0.134555, 0.124393, 0.115038, 0.106996, 0.100064 }; IborIndex index = makeIndex(); LiborForwardModelProcess process = new LiborForwardModelProcess(size, index); Handle <YieldTermStructure> termStructure = index.forwardingTermStructure(); // set-up the model LmVolatilityModel volaModel = new LmExtLinearExponentialVolModel(process.fixingTimes(), 0.5, 0.6, 0.1, 0.1); LmCorrelationModel corrModel = new LmLinearExponentialCorrelationModel(size, 0.5, 0.8); LiborForwardModel model = new LiborForwardModel(process, volaModel, corrModel); int swapVolIndex = 0; DayCounter dayCounter = index.forwardingTermStructure().link.dayCounter(); // set-up calibration helper List <CalibrationHelper> calibrationHelper = new List <CalibrationHelper>(); int i; for (i = 2; i < size; ++i) { Period maturity = i * index.tenor(); Handle <Quote> capVol = new Handle <Quote>(new SimpleQuote(capVols[i - 2])); CalibrationHelper caphelper = new CapHelper(maturity, capVol, index, Frequency.Annual, index.dayCounter(), true, termStructure, CalibrationHelper.CalibrationErrorType.ImpliedVolError); caphelper.setPricingEngine(new AnalyticCapFloorEngine(model, termStructure)); calibrationHelper.Add(caphelper); if (i <= size / 2) { // add a few swaptions to test swaption calibration as well for (int j = 1; j <= size / 2; ++j) { Period len = j * index.tenor(); Handle <Quote> swaptionVol = new Handle <Quote>( new SimpleQuote(swaptionVols[swapVolIndex++])); CalibrationHelper swaptionHelper = new SwaptionHelper(maturity, len, swaptionVol, index, index.tenor(), dayCounter, index.dayCounter(), termStructure, CalibrationHelper.CalibrationErrorType.ImpliedVolError); swaptionHelper.setPricingEngine(new LfmSwaptionEngine(model, termStructure)); calibrationHelper.Add(swaptionHelper); } } } LevenbergMarquardt om = new LevenbergMarquardt(1e-6, 1e-6, 1e-6); //ConjugateGradient gc = new ConjugateGradient(); model.calibrate(calibrationHelper, om, new EndCriteria(2000, 100, 1e-6, 1e-6, 1e-6), new Constraint(), new List <double>()); // measure the calibration error double calculated = 0.0; for (i = 0; i < calibrationHelper.Count; ++i) { double diff = calibrationHelper[i].calibrationError(); calculated += diff * diff; } if (Math.Sqrt(calculated) > tolerance) { QAssert.Fail("Failed to calibrate libor forward model" + "\n calculated diff: " + Math.Sqrt(calculated) + "\n expected : smaller than " + tolerance); } }
public void testCachedMarketValue() { // Testing credit-default swap against cached market values... using (SavedSettings backup = new SavedSettings()) { Settings.setEvaluationDate(new Date(9, Month.June, 2006)); Date evalDate = Settings.evaluationDate(); Calendar calendar = new UnitedStates(); List <Date> discountDates = new List <Date>(); discountDates.Add(evalDate); discountDates.Add(calendar.advance(evalDate, 1, TimeUnit.Weeks, BusinessDayConvention.ModifiedFollowing)); discountDates.Add(calendar.advance(evalDate, 1, TimeUnit.Months, BusinessDayConvention.ModifiedFollowing)); discountDates.Add(calendar.advance(evalDate, 2, TimeUnit.Months, BusinessDayConvention.ModifiedFollowing)); discountDates.Add(calendar.advance(evalDate, 3, TimeUnit.Months, BusinessDayConvention.ModifiedFollowing)); discountDates.Add(calendar.advance(evalDate, 6, TimeUnit.Months, BusinessDayConvention.ModifiedFollowing)); discountDates.Add(calendar.advance(evalDate, 12, TimeUnit.Months, BusinessDayConvention.ModifiedFollowing)); discountDates.Add(calendar.advance(evalDate, 2, TimeUnit.Years, BusinessDayConvention.ModifiedFollowing)); discountDates.Add(calendar.advance(evalDate, 3, TimeUnit.Years, BusinessDayConvention.ModifiedFollowing)); discountDates.Add(calendar.advance(evalDate, 4, TimeUnit.Years, BusinessDayConvention.ModifiedFollowing)); discountDates.Add(calendar.advance(evalDate, 5, TimeUnit.Years, BusinessDayConvention.ModifiedFollowing)); discountDates.Add(calendar.advance(evalDate, 6, TimeUnit.Years, BusinessDayConvention.ModifiedFollowing)); discountDates.Add(calendar.advance(evalDate, 7, TimeUnit.Years, BusinessDayConvention.ModifiedFollowing)); discountDates.Add(calendar.advance(evalDate, 8, TimeUnit.Years, BusinessDayConvention.ModifiedFollowing)); discountDates.Add(calendar.advance(evalDate, 9, TimeUnit.Years, BusinessDayConvention.ModifiedFollowing)); discountDates.Add(calendar.advance(evalDate, 10, TimeUnit.Years, BusinessDayConvention.ModifiedFollowing)); discountDates.Add(calendar.advance(evalDate, 15, TimeUnit.Years, BusinessDayConvention.ModifiedFollowing)); List <double> dfs = new List <double>(); dfs.Add(1.0); dfs.Add(0.9990151375768731); dfs.Add(0.99570502636871183); dfs.Add(0.99118260474528685); dfs.Add(0.98661167950906203); dfs.Add(0.9732592953359388); dfs.Add(0.94724424481038083); dfs.Add(0.89844996737120875); dfs.Add(0.85216647839921411); dfs.Add(0.80775477692556874); dfs.Add(0.76517289234200347); dfs.Add(0.72401019553182933); dfs.Add(0.68503909569219212); dfs.Add(0.64797499814013748); dfs.Add(0.61263171936255534); dfs.Add(0.5791942350748791); dfs.Add(0.43518868769953606); DayCounter curveDayCounter = new Actual360(); RelinkableHandle <YieldTermStructure> discountCurve = new RelinkableHandle <YieldTermStructure>(); discountCurve.linkTo(new InterpolatedDiscountCurve <LogLinear>(discountDates, dfs, curveDayCounter, null, null, null, new LogLinear())); DayCounter dayCounter = new Thirty360(); List <Date> dates = new List <Date>(); dates.Add(evalDate); dates.Add(calendar.advance(evalDate, 6, TimeUnit.Months, BusinessDayConvention.ModifiedFollowing)); dates.Add(calendar.advance(evalDate, 1, TimeUnit.Years, BusinessDayConvention.ModifiedFollowing)); dates.Add(calendar.advance(evalDate, 2, TimeUnit.Years, BusinessDayConvention.ModifiedFollowing)); dates.Add(calendar.advance(evalDate, 3, TimeUnit.Years, BusinessDayConvention.ModifiedFollowing)); dates.Add(calendar.advance(evalDate, 4, TimeUnit.Years, BusinessDayConvention.ModifiedFollowing)); dates.Add(calendar.advance(evalDate, 5, TimeUnit.Years, BusinessDayConvention.ModifiedFollowing)); dates.Add(calendar.advance(evalDate, 7, TimeUnit.Years, BusinessDayConvention.ModifiedFollowing)); dates.Add(calendar.advance(evalDate, 10, TimeUnit.Years, BusinessDayConvention.ModifiedFollowing)); List <double> defaultProbabilities = new List <double>(); defaultProbabilities.Add(0.0000); defaultProbabilities.Add(0.0047); defaultProbabilities.Add(0.0093); defaultProbabilities.Add(0.0286); defaultProbabilities.Add(0.0619); defaultProbabilities.Add(0.0953); defaultProbabilities.Add(0.1508); defaultProbabilities.Add(0.2288); defaultProbabilities.Add(0.3666); List <double> hazardRates = new List <double>(); hazardRates.Add(0.0); for (int i = 1; i < dates.Count; ++i) { double t1 = dayCounter.yearFraction(dates[0], dates[i - 1]); double t2 = dayCounter.yearFraction(dates[0], dates[i]); double S1 = 1.0 - defaultProbabilities[i - 1]; double S2 = 1.0 - defaultProbabilities[i]; hazardRates.Add(Math.Log(S1 / S2) / (t2 - t1)); } RelinkableHandle <DefaultProbabilityTermStructure> piecewiseFlatHazardRate = new RelinkableHandle <DefaultProbabilityTermStructure>(); piecewiseFlatHazardRate.linkTo(new InterpolatedHazardRateCurve <BackwardFlat>(dates, hazardRates, new Thirty360())); // Testing credit default swap // Build the schedule Date issueDate = new Date(20, Month.March, 2006); Date maturity = new Date(20, Month.June, 2013); Frequency cdsFrequency = Frequency.Semiannual; BusinessDayConvention cdsConvention = BusinessDayConvention.ModifiedFollowing; Schedule schedule = new Schedule(issueDate, maturity, new Period(cdsFrequency), calendar, cdsConvention, cdsConvention, DateGeneration.Rule.Forward, false); // Build the CDS double recoveryRate = 0.25; double fixedRate = 0.0224; DayCounter dayCount = new Actual360(); double cdsNotional = 100.0; CreditDefaultSwap cds = new CreditDefaultSwap(Protection.Side.Seller, cdsNotional, fixedRate, schedule, cdsConvention, dayCount, true, true); cds.setPricingEngine(new MidPointCdsEngine(piecewiseFlatHazardRate, recoveryRate, discountCurve)); double calculatedNpv = cds.NPV(); double calculatedFairRate = cds.fairSpread(); double npv = -1.364048777; // from Bloomberg we have 98.15598868 - 100.00; double fairRate = 0.0248429452; // from Bloomberg we have 0.0258378; double tolerance = 1e-9; if (Math.Abs(npv - calculatedNpv) > tolerance) { QAssert.Fail( "Failed to reproduce the npv for the given credit-default swap\n" + " computed NPV: " + calculatedNpv + "\n" + " Given NPV: " + npv); } if (Math.Abs(fairRate - calculatedFairRate) > tolerance) { QAssert.Fail("Failed to reproduce the fair rate for the given credit-default swap\n" + " computed fair rate: " + calculatedFairRate + "\n" + " Given fair rate: " + fairRate); } } }
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 testImpliedHazardRate() { // Testing implied hazard-rate for credit-default swaps... using (SavedSettings backup = new SavedSettings()) { // Initialize curves Calendar calendar = new TARGET(); Date today = calendar.adjust(Date.Today); Settings.setEvaluationDate(today); double h1 = 0.30, h2 = 0.40; DayCounter dayCounter = new Actual365Fixed(); List <Date> dates = new List <Date>(3); List <double> hazardRates = new List <double>(3); dates.Add(today); hazardRates.Add(h1); dates.Add(today + new Period(5, TimeUnit.Years)); hazardRates.Add(h1); dates.Add(today + new Period(10, TimeUnit.Years)); hazardRates.Add(h2); RelinkableHandle <DefaultProbabilityTermStructure> probabilityCurve = new RelinkableHandle <DefaultProbabilityTermStructure>(); probabilityCurve.linkTo(new InterpolatedHazardRateCurve <BackwardFlat>(dates, hazardRates, dayCounter)); RelinkableHandle <YieldTermStructure> discountCurve = new RelinkableHandle <YieldTermStructure>(); discountCurve.linkTo(new FlatForward(today, 0.03, new Actual360())); Frequency frequency = Frequency.Semiannual; BusinessDayConvention convention = BusinessDayConvention.ModifiedFollowing; Date issueDate = calendar.advance(today, -6, TimeUnit.Months); double fixedRate = 0.0120; DayCounter cdsDayCount = new Actual360(); double notional = 10000.0; double recoveryRate = 0.4; double?latestRate = null; for (int n = 6; n <= 10; ++n) { Date maturity = calendar.advance(issueDate, n, TimeUnit.Years); Schedule schedule = new Schedule(issueDate, maturity, new Period(frequency), calendar, convention, convention, DateGeneration.Rule.Forward, false); CreditDefaultSwap cds = new CreditDefaultSwap(Protection.Side.Seller, notional, fixedRate, schedule, convention, cdsDayCount, true, true); cds.setPricingEngine(new MidPointCdsEngine(probabilityCurve, recoveryRate, discountCurve)); double NPV = cds.NPV(); double flatRate = cds.impliedHazardRate(NPV, discountCurve, dayCounter, recoveryRate); if (flatRate < h1 || flatRate > h2) { QAssert.Fail("implied hazard rate outside expected range\n" + " maturity: " + n + " years\n" + " expected minimum: " + h1 + "\n" + " expected maximum: " + h2 + "\n" + " implied rate: " + flatRate); } if (n > 6 && flatRate < latestRate) { QAssert.Fail("implied hazard rate decreasing with swap maturity\n" + " maturity: " + n + " years\n" + " previous rate: " + latestRate + "\n" + " implied rate: " + flatRate); } latestRate = flatRate; RelinkableHandle <DefaultProbabilityTermStructure> probability = new RelinkableHandle <DefaultProbabilityTermStructure>(); probability.linkTo(new FlatHazardRate(today, new Handle <Quote>(new SimpleQuote(flatRate)), dayCounter)); CreditDefaultSwap cds2 = new CreditDefaultSwap(Protection.Side.Seller, notional, fixedRate, schedule, convention, cdsDayCount, true, true); cds2.setPricingEngine(new MidPointCdsEngine(probability, recoveryRate, discountCurve)); double NPV2 = cds2.NPV(); double tolerance = 1.0; if (Math.Abs(NPV - NPV2) > tolerance) { QAssert.Fail("failed to reproduce NPV with implied rate\n" + " expected: " + NPV + "\n" + " calculated: " + NPV2); } } } }
public void testCalibration() { double forward = 0.03; double tau = 1.0; //Real a = 0.04; //Real b = 0.1; //Real rho = -0.5; //Real sigma = 0.1; //Real m = 0.0; double a = 0.1; double b = 0.06; double rho = -0.9; double m = 0.24; double sigma = 0.06; List <double> strikes = new List <double>(); strikes.Add(0.01); strikes.Add(0.015); strikes.Add(0.02); strikes.Add(0.025); strikes.Add(0.03); strikes.Add(0.035); strikes.Add(0.04); strikes.Add(0.045); strikes.Add(0.05); List <double> vols = new InitializedList <double>(strikes.Count, 0.20); //dummy vols (we do not calibrate here) SviInterpolation svi = new SviInterpolation(strikes, strikes.Count, vols, tau, forward, a, b, sigma, rho, m, true, true, true, true, true); svi.enableExtrapolation(); List <double> sviVols = new InitializedList <double>(strikes.Count, 0.0); for (int i = 0; i < strikes.Count; ++i) { sviVols[i] = svi.value(strikes[i]); } SviInterpolation svi2 = new SviInterpolation(strikes, strikes.Count, sviVols, tau, forward, null, null, null, null, null, false, false, false, false, false, false, null, null, 1E-8, false, 0); //don't allow for random start values svi2.enableExtrapolation(); svi2.update(); testOutputHelper.WriteLine("a=" + svi2.a()); if (!Utils.close_enough(a, svi2.a(), 100)) { QAssert.Fail("error in a coefficient estimation"); } testOutputHelper.WriteLine("b=" + svi2.b()); if (!Utils.close_enough(b, svi2.b(), 100)) { QAssert.Fail("error in b coefficient estimation"); } testOutputHelper.WriteLine("sigma=" + svi2.sigma()); if (!Utils.close_enough(sigma, svi2.sigma(), 100)) { QAssert.Fail("error in sigma coefficient estimation"); } testOutputHelper.WriteLine("rho=" + svi2.rho()); if (!Utils.close_enough(rho, svi2.rho(), 100)) { QAssert.Fail("error in rho coefficient estimation"); } testOutputHelper.WriteLine("m=" + svi2.m()); if (!Utils.close_enough(m, svi2.m(), 100)) { QAssert.Fail("error in m coefficient estimation"); } testOutputHelper.WriteLine("error=" + svi2.rmsError()); }
public void testCachedValue() { // Testing credit-default swap against cached values... using (SavedSettings backup = new SavedSettings()) { // Initialize curves Settings.setEvaluationDate(new Date(9, Month.June, 2006)); Date today = Settings.evaluationDate(); Calendar calendar = new TARGET(); Handle <Quote> hazardRate = new Handle <Quote>(new SimpleQuote(0.01234)); RelinkableHandle <DefaultProbabilityTermStructure> probabilityCurve = new RelinkableHandle <DefaultProbabilityTermStructure>(); probabilityCurve.linkTo(new FlatHazardRate(0, calendar, hazardRate, new Actual360())); RelinkableHandle <YieldTermStructure> discountCurve = new RelinkableHandle <YieldTermStructure>(); discountCurve.linkTo(new FlatForward(today, 0.06, new Actual360())); // Build the schedule Date issueDate = calendar.advance(today, -1, TimeUnit.Years); Date maturity = calendar.advance(issueDate, 10, TimeUnit.Years); Frequency frequency = Frequency.Semiannual; BusinessDayConvention convention = BusinessDayConvention.ModifiedFollowing; Schedule schedule = new Schedule(issueDate, maturity, new Period(frequency), calendar, convention, convention, DateGeneration.Rule.Forward, false); // Build the CDS double fixedRate = 0.0120; DayCounter dayCount = new Actual360(); double notional = 10000.0; double recoveryRate = 0.4; CreditDefaultSwap cds = new CreditDefaultSwap(Protection.Side.Seller, notional, fixedRate, schedule, convention, dayCount, true, true); cds.setPricingEngine(new MidPointCdsEngine(probabilityCurve, recoveryRate, discountCurve)); double npv = 295.0153398; double fairRate = 0.007517539081; double calculatedNpv = cds.NPV(); double calculatedFairRate = cds.fairSpread(); double tolerance = 1.0e-7; if (Math.Abs(calculatedNpv - npv) > tolerance) { QAssert.Fail( "Failed to reproduce NPV with mid-point engine\n" + " calculated NPV: " + calculatedNpv + "\n" + " expected NPV: " + npv); } if (Math.Abs(calculatedFairRate - fairRate) > tolerance) { QAssert.Fail( "Failed to reproduce fair rate with mid-point engine\n" + " calculated fair rate: " + calculatedFairRate + "\n" + " expected fair rate: " + fairRate); } cds.setPricingEngine(new IntegralCdsEngine(new Period(1, TimeUnit.Days), probabilityCurve, recoveryRate, discountCurve)); calculatedNpv = cds.NPV(); calculatedFairRate = cds.fairSpread(); tolerance = 1.0e-5; if (Math.Abs(calculatedNpv - npv) > notional * tolerance * 10) { QAssert.Fail( "Failed to reproduce NPV with integral engine " + "(step = 1 day)\n" + " calculated NPV: " + calculatedNpv + "\n" + " expected NPV: " + npv); } if (Math.Abs(calculatedFairRate - fairRate) > tolerance) { QAssert.Fail( "Failed to reproduce fair rate with integral engine " + "(step = 1 day)\n" + " calculated fair rate: " + calculatedFairRate + "\n" + " expected fair rate: " + fairRate); } cds.setPricingEngine(new IntegralCdsEngine(new Period(1, TimeUnit.Weeks), probabilityCurve, recoveryRate, discountCurve)); calculatedNpv = cds.NPV(); calculatedFairRate = cds.fairSpread(); tolerance = 1.0e-5; if (Math.Abs(calculatedNpv - npv) > notional * tolerance * 10) { QAssert.Fail( "Failed to reproduce NPV with integral engine " + "(step = 1 week)\n" + " calculated NPV: " + calculatedNpv + "\n" + " expected NPV: " + npv); } if (Math.Abs(calculatedFairRate - fairRate) > tolerance) { QAssert.Fail( "Failed to reproduce fair rate with integral engine " + "(step = 1 week)\n" + " calculated fair rate: " + calculatedFairRate + "\n" + " expected fair rate: " + fairRate); } } }
public void testCachedHullWhite() { //("Testing Hull-White calibration against cached values..."); Date today = new Date(15, Month.February, 2002); Date settlement = new Date(19, Month.February, 2002); Settings.setEvaluationDate(today); Handle <YieldTermStructure> termStructure = new Handle <YieldTermStructure>(Utilities.flatRate(settlement, 0.04875825, new Actual365Fixed())); //termStructure.link HullWhite model = new HullWhite(termStructure); CalibrationData[] data = { new CalibrationData(1, 5, 0.1148), new CalibrationData(2, 4, 0.1108), new CalibrationData(3, 3, 0.1070), new CalibrationData(4, 2, 0.1021), new CalibrationData(5, 1, 0.1000) }; IborIndex index = new Euribor6M(termStructure); IPricingEngine engine = new JamshidianSwaptionEngine(model); List <CalibrationHelper> swaptions = new List <CalibrationHelper>(); for (int i = 0; i < data.Length; i++) { Quote vol = new SimpleQuote(data[i].volatility); CalibrationHelper helper = new SwaptionHelper(new Period(data[i].start, TimeUnit.Years), new Period(data[i].length, TimeUnit.Years), new Handle <Quote>(vol), index, new Period(1, TimeUnit.Years), new Thirty360(), new Actual360(), termStructure); helper.setPricingEngine(engine); swaptions.Add(helper); } // Set up the optimization problem // Real simplexLambda = 0.1; // Simplex optimizationMethod(simplexLambda); LevenbergMarquardt optimizationMethod = new LevenbergMarquardt(1.0e-8, 1.0e-8, 1.0e-8); EndCriteria endCriteria = new EndCriteria(10000, 100, 1e-6, 1e-8, 1e-8); //Optimize model.calibrate(swaptions, optimizationMethod, endCriteria, new Constraint(), new List <double>()); EndCriteria.Type ecType = model.endCriteria(); // Check and print out results #if QL_USE_INDEXED_COUPON double cachedA = 0.0488199, cachedSigma = 0.00593579; #else double cachedA = 0.0488565, cachedSigma = 0.00593662; #endif double tolerance = 1.120e-5; //double tolerance = 1.0e-6; Vector xMinCalculated = model.parameters(); double yMinCalculated = model.value(xMinCalculated, swaptions); Vector xMinExpected = new Vector(2); xMinExpected[0] = cachedA; xMinExpected[1] = cachedSigma; double yMinExpected = model.value(xMinExpected, swaptions); if (Math.Abs(xMinCalculated[0] - cachedA) > tolerance || Math.Abs(xMinCalculated[1] - cachedSigma) > tolerance) { QAssert.Fail("Failed to reproduce cached calibration results:\n" + "calculated: a = " + xMinCalculated[0] + ", " + "sigma = " + xMinCalculated[1] + ", " + "f(a) = " + yMinCalculated + ",\n" + "expected: a = " + xMinExpected[0] + ", " + "sigma = " + xMinExpected[1] + ", " + "f(a) = " + yMinExpected + ",\n" + "difference: a = " + (xMinCalculated[0] - xMinExpected[0]) + ", " + "sigma = " + (xMinCalculated[1] - xMinExpected[1]) + ", " + "f(a) = " + (yMinCalculated - yMinExpected) + ",\n" + "end criteria = " + ecType); } }
public void testFairUpfront() { // Testing fair-upfront calculation for credit-default swaps... using (SavedSettings backup = new SavedSettings()) { // Initialize curves Calendar calendar = new TARGET(); Date today = calendar.adjust(Date.Today); Settings.setEvaluationDate(today); Handle <Quote> hazardRate = new Handle <Quote>(new SimpleQuote(0.01234)); RelinkableHandle <DefaultProbabilityTermStructure> probabilityCurve = new RelinkableHandle <DefaultProbabilityTermStructure>(); probabilityCurve.linkTo(new FlatHazardRate(0, calendar, hazardRate, new Actual360())); RelinkableHandle <YieldTermStructure> discountCurve = new RelinkableHandle <YieldTermStructure>(); discountCurve.linkTo(new FlatForward(today, 0.06, new Actual360())); // Build the schedule Date issueDate = today; Date maturity = calendar.advance(issueDate, 10, TimeUnit.Years); BusinessDayConvention convention = BusinessDayConvention.Following; Schedule schedule = new MakeSchedule().from(issueDate) .to(maturity) .withFrequency(Frequency.Quarterly) .withCalendar(calendar) .withTerminationDateConvention(convention) .withRule(DateGeneration.Rule.TwentiethIMM).value(); // Build the CDS double fixedRate = 0.05; double upfront = 0.001; DayCounter dayCount = new Actual360(); double notional = 10000.0; double recoveryRate = 0.4; IPricingEngine engine = new MidPointCdsEngine(probabilityCurve, recoveryRate, discountCurve, true); CreditDefaultSwap cds = new CreditDefaultSwap(Protection.Side.Seller, notional, upfront, fixedRate, schedule, convention, dayCount, true, true); cds.setPricingEngine(engine); double fairUpfront = cds.fairUpfront(); CreditDefaultSwap fairCds = new CreditDefaultSwap(Protection.Side.Seller, notional, fairUpfront, fixedRate, schedule, convention, dayCount, true, true); fairCds.setPricingEngine(engine); double fairNPV = fairCds.NPV(); double tolerance = 1e-10; if (Math.Abs(fairNPV) > tolerance) { QAssert.Fail( "Failed to reproduce null NPV with calculated fair upfront\n" + " calculated upfront: " + fairUpfront + "\n" + " calculated NPV: " + fairNPV); } // same with null upfront to begin with upfront = 0.0; CreditDefaultSwap cds2 = new CreditDefaultSwap(Protection.Side.Seller, notional, upfront, fixedRate, schedule, convention, dayCount, true, true); cds2.setPricingEngine(engine); fairUpfront = cds2.fairUpfront(); CreditDefaultSwap fairCds2 = new CreditDefaultSwap(Protection.Side.Seller, notional, fairUpfront, fixedRate, schedule, convention, dayCount, true, true); fairCds2.setPricingEngine(engine); fairNPV = fairCds2.NPV(); if (Math.Abs(fairNPV) > tolerance) { QAssert.Fail( "Failed to reproduce null NPV with calculated fair upfront\n" + " calculated upfront: " + fairUpfront + "\n" + " calculated NPV: " + fairNPV); } } }
public void testMultiple(StochasticProcess process, string tag, double[] expected, double[] antithetic) { ulong seed = 42; double length = 10; int timeSteps = 12; int assets = process.size(); var rsg = (InverseCumulativeRsg <RandomSequenceGenerator <MersenneTwisterUniformRng> , InverseCumulativeNormal>) new PseudoRandom().make_sequence_generator(timeSteps * assets, seed); MultiPathGenerator <IRNG> generator = new MultiPathGenerator <IRNG>(process, new TimeGrid(length, timeSteps), rsg, false); int i; for (i = 0; i < 100; i++) { generator.next(); } Sample <IPath> sample = generator.next(); MultiPath value = sample.value as MultiPath; Utils.QL_REQUIRE(value != null, () => "Invalid Path"); Vector calculated = new Vector(assets); double error, tolerance = 2.0e-7; for (int j = 0; j < assets; j++) { calculated[j] = value[j].back(); } for (int j = 0; j < assets; j++) { error = Math.Abs(calculated[j] - expected[j]); if (error > tolerance) { QAssert.Fail("using " + tag + " process " + "(" + j + 1 + " asset:)\n" //+ std::setprecision(13) + " calculated: " + calculated[j] + "\n" + " expected: " + expected[j] + "\n" + " error: " + error + "\n" + " tolerance: " + tolerance); } } sample = generator.antithetic(); value = sample.value as MultiPath; Utils.QL_REQUIRE(value != null, () => "Invalid Path"); for (int j = 0; j < assets; j++) { calculated[j] = value[j].back(); } for (int j = 0; j < assets; j++) { error = Math.Abs(calculated[j] - antithetic[j]); if (error > tolerance) { QAssert.Fail("using " + tag + " process " + "(" + j + 1 + " asset:)\n" + "antithetic sample:\n" //+ std::setprecision(13) + " calculated: " + calculated[j] + "\n" + " expected: " + antithetic[j] + "\n" + " error: " + error + "\n" + " tolerance: " + tolerance); } } }
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) { QAssert.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) { QAssert.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) { QAssert.Fail("double-time probability and double-date probability do not match\n" + " time probability: " + timeProbability + "\n" + " date probability: " + dateProbability); } } }
public void testCachedValues() { //("Testing Bermudan swaption against cached values..."); CommonVars vars = new CommonVars(); vars.today = new Date(15, Month.February, 2002); Settings.Instance.setEvaluationDate(vars.today); vars.settlement = new Date(19, Month.February, 2002); // flat yield term structure impling 1x5 swap at 5% vars.termStructure.linkTo(Utilities.flatRate(vars.settlement, 0.04875825, new Actual365Fixed())); double atmRate = vars.makeSwap(0.0).fairRate(); VanillaSwap itmSwap = vars.makeSwap(0.8 * atmRate); VanillaSwap atmSwap = vars.makeSwap(atmRate); VanillaSwap otmSwap = vars.makeSwap(1.2 * atmRate); double a = 0.048696, sigma = 0.0058904; ShortRateModel model = new HullWhite(vars.termStructure, a, sigma); List <Date> exerciseDates = new List <Date>(); List <CashFlow> leg = atmSwap.fixedLeg(); for (int i = 0; i < leg.Count; i++) { Coupon coupon = (Coupon)(leg[i]); exerciseDates.Add(coupon.accrualStartDate()); } Exercise exercise = new BermudanExercise(exerciseDates); IPricingEngine treeEngine = new TreeSwaptionEngine(model, 50); IPricingEngine fdmEngine = new FdHullWhiteSwaptionEngine(model as HullWhite); #if QL_USE_INDEXED_COUPON double itmValue = 42.2413, atmValue = 12.8789, otmValue = 2.4759; double itmValueFdm = 42.2111, atmValueFdm = 12.8879, otmValueFdm = 2.44443; #else double itmValue = 42.2470, atmValue = 12.8826, otmValue = 2.4769; double itmValueFdm = 42.2091, atmValueFdm = 12.8864, otmValueFdm = 2.4437; #endif double tolerance = 1.0e-4; Swaption swaption = new Swaption(itmSwap, exercise); swaption.setPricingEngine(treeEngine); if (Math.Abs(swaption.NPV() - itmValue) > tolerance) { QAssert.Fail("failed to reproduce cached in-the-money swaption value:\n" + "calculated: " + swaption.NPV() + "\n" + "expected: " + itmValue); } swaption.setPricingEngine(fdmEngine); if (Math.Abs(swaption.NPV() - itmValueFdm) > tolerance) { QAssert.Fail("failed to reproduce cached in-the-money swaption value:\n" + "calculated: " + swaption.NPV() + "\n" + "expected: " + itmValueFdm); } swaption = new Swaption(atmSwap, exercise); swaption.setPricingEngine(treeEngine); if (Math.Abs(swaption.NPV() - atmValue) > tolerance) { QAssert.Fail("failed to reproduce cached at-the-money swaption value:\n" + "calculated: " + swaption.NPV() + "\n" + "expected: " + atmValue); } swaption.setPricingEngine(fdmEngine); if (Math.Abs(swaption.NPV() - atmValueFdm) > tolerance) { QAssert.Fail("failed to reproduce cached at-the-money swaption value:\n" + "calculated: " + swaption.NPV() + "\n" + "expected: " + atmValueFdm); } swaption = new Swaption(otmSwap, exercise); swaption.setPricingEngine(treeEngine); if (Math.Abs(swaption.NPV() - otmValue) > tolerance) { QAssert.Fail("failed to reproduce cached out-of-the-money " + "swaption value:\n" + "calculated: " + swaption.NPV() + "\n" + "expected: " + otmValue); } swaption.setPricingEngine(fdmEngine); if (Math.Abs(swaption.NPV() - otmValueFdm) > tolerance) { QAssert.Fail("failed to reproduce cached out-of-the-money " + "swaption value:\n" + "calculated: " + swaption.NPV() + "\n" + "expected: " + otmValueFdm); } for (int j = 0; j < exerciseDates.Count; j++) { exerciseDates[j] = vars.calendar.adjust(exerciseDates[j] - 10); } exercise = new BermudanExercise(exerciseDates); #if QL_USE_INDEXED_COUPON itmValue = 42.1917; atmValue = 12.7788; otmValue = 2.4388; #else itmValue = 42.1974; atmValue = 12.7825; otmValue = 2.4399; #endif swaption = new Swaption(itmSwap, exercise); swaption.setPricingEngine(treeEngine); if (Math.Abs(swaption.NPV() - itmValue) > tolerance) { QAssert.Fail("failed to reproduce cached in-the-money swaption value:\n" + "calculated: " + swaption.NPV() + "\n" + "expected: " + itmValue); } swaption = new Swaption(atmSwap, exercise); swaption.setPricingEngine(treeEngine); if (Math.Abs(swaption.NPV() - atmValue) > tolerance) { QAssert.Fail("failed to reproduce cached at-the-money swaption value:\n" + "calculated: " + swaption.NPV() + "\n" + "expected: " + atmValue); } swaption = new Swaption(otmSwap, exercise); swaption.setPricingEngine(treeEngine); if (Math.Abs(swaption.NPV() - otmValue) > tolerance) { QAssert.Fail("failed to reproduce cached out-of-the-money " + "swaption value:\n" + "calculated: " + swaption.NPV() + "\n" + "expected: " + otmValue); } }
public void RiskStatisticsTest() { // ("Testing risk measures..."); IncrementalGaussianStatistics igs = new IncrementalGaussianStatistics(); RiskStatistics s = new RiskStatistics(); double[] averages = { -100.0, -1.0, 0.0, 1.0, 100.0 }; double[] sigmas = { 0.1, 1.0, 100.0 }; int i, j, k, N; N = (int)Math.Pow(2, 16) - 1; double dataMin, dataMax; List <double> data = new InitializedList <double>(N), weights = new InitializedList <double>(N); for (i = 0; i < averages.Length; i++) { for (j = 0; j < sigmas.Length; j++) { NormalDistribution normal = new NormalDistribution(averages[i], sigmas[j]); CumulativeNormalDistribution cumulative = new CumulativeNormalDistribution(averages[i], sigmas[j]); InverseCumulativeNormal inverseCum = new InverseCumulativeNormal(averages[i], sigmas[j]); SobolRsg rng = new SobolRsg(1); dataMin = double.MaxValue; dataMax = double.MinValue; for (k = 0; k < N; k++) { data[k] = inverseCum.value(rng.nextSequence().value[0]); dataMin = Math.Min(dataMin, data[k]); dataMax = Math.Max(dataMax, data[k]); weights[k] = 1.0; } igs.addSequence(data, weights); s.addSequence(data, weights); // checks double calculated, expected; double tolerance; if (igs.samples() != N) { QAssert.Fail("IncrementalGaussianStatistics: " + "wrong number of samples\n" + " calculated: " + igs.samples() + "\n" + " expected: " + N); } if (s.samples() != N) { QAssert.Fail("RiskStatistics: wrong number of samples\n" + " calculated: " + s.samples() + "\n" + " expected: " + N); } // weightSum() tolerance = 1e-10; expected = weights.Sum(); calculated = igs.weightSum(); if (Math.Abs(calculated - expected) > tolerance) { QAssert.Fail("IncrementalGaussianStatistics: " + "wrong sum of weights\n" + " calculated: " + calculated + "\n" + " expected: " + expected + "\n" + " tolerance: " + tolerance); } calculated = s.weightSum(); if (Math.Abs(calculated - expected) > tolerance) { QAssert.Fail("RiskStatistics: wrong sum of weights\n" + " calculated: " + calculated + "\n" + " expected: " + expected + "\n" + " tolerance: " + tolerance); } // min tolerance = 1e-12; expected = dataMin; calculated = igs.min(); if (Math.Abs(calculated - expected) > tolerance) { QAssert.Fail("IncrementalGaussianStatistics: " + "wrong minimum value\n" + " calculated: " + calculated + "\n" + " expected: " + expected + "\n" + " tolerance: " + tolerance); } calculated = s.min(); if (Math.Abs(calculated - expected) > tolerance) { QAssert.Fail("RiskStatistics: " + "wrong minimum value\n" + " calculated: " + calculated + "\n" + " expected: " + expected + "\n" + " tolerance: " + tolerance); } // max expected = dataMax; calculated = igs.max(); if (Math.Abs(calculated - expected) > tolerance) { QAssert.Fail("IncrementalGaussianStatistics: " + "wrong maximum value\n" + " calculated: " + calculated + "\n" + " expected: " + expected + "\n" + " tolerance: " + tolerance); } calculated = s.max(); if (Math.Abs(calculated - expected) > tolerance) { QAssert.Fail("RiskStatistics: " + "wrong maximum value\n" + " calculated: " + calculated + "\n" + " expected: " + expected + "\n" + " tolerance: " + tolerance); } // mean expected = averages[i]; tolerance = (expected == 0.0 ? 1.0e-13 : Math.Abs(expected) * 1.0e-13); calculated = igs.mean(); if (Math.Abs(calculated - expected) > tolerance) { QAssert.Fail("IncrementalGaussianStatistics: " + "wrong mean value" + " for N(" + averages[i] + ", " + sigmas[j] + ")\n" + " calculated: " + calculated + "\n" + " expected: " + expected + "\n" + " tolerance: " + tolerance); } calculated = s.mean(); if (Math.Abs(calculated - expected) > tolerance) { QAssert.Fail("RiskStatistics: wrong mean value" + " for N(" + averages[i] + ", " + sigmas[j] + ")\n" + " calculated: " + calculated + "\n" + " expected: " + expected + "\n" + " tolerance: " + tolerance); } // variance expected = sigmas[j] * sigmas[j]; tolerance = expected * 1.0e-1; calculated = igs.variance(); if (Math.Abs(calculated - expected) > tolerance) { QAssert.Fail("IncrementalGaussianStatistics: " + "wrong variance" + " for N(" + averages[i] + ", " + sigmas[j] + ")\n" + " calculated: " + calculated + "\n" + " expected: " + expected + "\n" + " tolerance: " + tolerance); } calculated = s.variance(); if (Math.Abs(calculated - expected) > tolerance) { QAssert.Fail("RiskStatistics: wrong variance" + " for N(" + averages[i] + ", " + sigmas[j] + ")\n" + " calculated: " + calculated + "\n" + " expected: " + expected + "\n" + " tolerance: " + tolerance); } // standardDeviation expected = sigmas[j]; tolerance = expected * 1.0e-1; calculated = igs.standardDeviation(); if (Math.Abs(calculated - expected) > tolerance) { QAssert.Fail("IncrementalGaussianStatistics: " + "wrong standard deviation" + " for N(" + averages[i] + ", " + sigmas[j] + ")\n" + " calculated: " + calculated + "\n" + " expected: " + expected + "\n" + " tolerance: " + tolerance); } calculated = s.standardDeviation(); if (Math.Abs(calculated - expected) > tolerance) { QAssert.Fail("RiskStatistics: wrong standard deviation" + " for N(" + averages[i] + ", " + sigmas[j] + ")\n" + " calculated: " + calculated + "\n" + " expected: " + expected + "\n" + " tolerance: " + tolerance); } // missing errorEstimate() test // skewness expected = 0.0; tolerance = 1.0e-4; calculated = igs.skewness(); if (Math.Abs(calculated - expected) > tolerance) { QAssert.Fail("IncrementalGaussianStatistics: " + "wrong skewness" + " for N(" + averages[i] + ", " + sigmas[j] + ")\n" + " calculated: " + calculated + "\n" + " expected: " + expected + "\n" + " tolerance: " + tolerance); } calculated = s.skewness(); if (Math.Abs(calculated - expected) > tolerance) { QAssert.Fail("RiskStatistics: wrong skewness" + " for N(" + averages[i] + ", " + sigmas[j] + ")\n" + " calculated: " + calculated + "\n" + " expected: " + expected + "\n" + " tolerance: " + tolerance); } // kurtosis expected = 0.0; tolerance = 1.0e-1; calculated = igs.kurtosis(); if (Math.Abs(calculated - expected) > tolerance) { QAssert.Fail("IncrementalGaussianStatistics: " + "wrong kurtosis" + " for N(" + averages[i] + ", " + sigmas[j] + ")\n" + " calculated: " + calculated + "\n" + " expected: " + expected + "\n" + " tolerance: " + tolerance); } calculated = s.kurtosis(); if (Math.Abs(calculated - expected) > tolerance) { QAssert.Fail("RiskStatistics: wrong kurtosis" + " for N(" + averages[i] + ", " + sigmas[j] + ")\n" + " calculated: " + calculated + "\n" + " expected: " + expected + "\n" + " tolerance: " + tolerance); } // percentile expected = averages[i]; tolerance = (expected == 0.0 ? 1.0e-3 : Math.Abs(expected * 1.0e-3)); calculated = igs.gaussianPercentile(0.5); if (Math.Abs(calculated - expected) > tolerance) { QAssert.Fail("IncrementalGaussianStatistics: " + "wrong Gaussian percentile" + " for N(" + averages[i] + ", " + sigmas[j] + ")\n" + " calculated: " + calculated + "\n" + " expected: " + expected + "\n" + " tolerance: " + tolerance); } calculated = s.gaussianPercentile(0.5); if (Math.Abs(calculated - expected) > tolerance) { QAssert.Fail("RiskStatistics: wrong Gaussian percentile" + " for N(" + averages[i] + ", " + sigmas[j] + ")\n" + " calculated: " + calculated + "\n" + " expected: " + expected + "\n" + " tolerance: " + tolerance); } calculated = s.percentile(0.5); if (Math.Abs(calculated - expected) > tolerance) { QAssert.Fail("RiskStatistics: wrong percentile" + " for N(" + averages[i] + ", " + sigmas[j] + ")\n" + " calculated: " + calculated + "\n" + " expected: " + expected + "\n" + " tolerance: " + tolerance); } // potential upside double upper_tail = averages[i] + 2.0 * sigmas[j], lower_tail = averages[i] - 2.0 * sigmas[j]; double twoSigma = cumulative.value(upper_tail); expected = Math.Max(upper_tail, 0.0); tolerance = (expected == 0.0 ? 1.0e-3 : Math.Abs(expected * 1.0e-3)); calculated = igs.gaussianPotentialUpside(twoSigma); if (Math.Abs(calculated - expected) > tolerance) { QAssert.Fail("IncrementalGaussianStatistics: " + "wrong Gaussian potential upside" + " for N(" + averages[i] + ", " + sigmas[j] + ")\n" + " calculated: " + calculated + "\n" + " expected: " + expected + "\n" + " tolerance: " + tolerance); } calculated = s.gaussianPotentialUpside(twoSigma); if (Math.Abs(calculated - expected) > tolerance) { QAssert.Fail("RiskStatistics: wrong Gaussian potential upside" + " for N(" + averages[i] + ", " + sigmas[j] + ")\n" + " calculated: " + calculated + "\n" + " expected: " + expected + "\n" + " tolerance: " + tolerance); } calculated = s.potentialUpside(twoSigma); if (Math.Abs(calculated - expected) > tolerance) { QAssert.Fail("RiskStatistics: wrong potential upside" + " for N(" + averages[i] + ", " + sigmas[j] + ")\n" + " calculated: " + calculated + "\n" + " expected: " + expected + "\n" + " tolerance: " + tolerance); } // just to check that GaussianStatistics<StatsHolder> does work StatsHolder h = new StatsHolder(s.mean(), s.standardDeviation()); GenericGaussianStatistics <StatsHolder> test = new GenericGaussianStatistics <StatsHolder>(h); expected = s.gaussianPotentialUpside(twoSigma); calculated = test.gaussianPotentialUpside(twoSigma); if (calculated != expected) { QAssert.Fail("GenericGaussianStatistics<StatsHolder> fails" + "\n calculated: " + calculated + "\n expected: " + expected); } // value-at-risk expected = -Math.Min(lower_tail, 0.0); tolerance = (expected == 0.0 ? 1.0e-3 : Math.Abs(expected * 1.0e-3)); calculated = igs.gaussianValueAtRisk(twoSigma); if (Math.Abs(calculated - expected) > tolerance) { QAssert.Fail("IncrementalGaussianStatistics: " + "wrong Gaussian value-at-risk" + " for N(" + averages[i] + ", " + sigmas[j] + ")\n" + " calculated: " + calculated + "\n" + " expected: " + expected + "\n" + " tolerance: " + tolerance); } calculated = s.gaussianValueAtRisk(twoSigma); if (Math.Abs(calculated - expected) > tolerance) { QAssert.Fail("RiskStatistics: wrong Gaussian value-at-risk" + " for N(" + averages[i] + ", " + sigmas[j] + ")\n" + " calculated: " + calculated + "\n" + " expected: " + expected + "\n" + " tolerance: " + tolerance); } calculated = s.valueAtRisk(twoSigma); if (Math.Abs(calculated - expected) > tolerance) { QAssert.Fail("RiskStatistics: wrong value-at-risk" + " for N(" + averages[i] + ", " + sigmas[j] + ")\n" + " calculated: " + calculated + "\n" + " expected: " + expected + "\n" + " tolerance: " + tolerance); } if (averages[i] > 0.0 && sigmas[j] < averages[i]) { // no data will miss the targets: // skip the rest of this iteration igs.reset(); s.reset(); continue; } // expected shortfall expected = -Math.Min(averages[i] - sigmas[j] * sigmas[j] * normal.value(lower_tail) / (1.0 - twoSigma), 0.0); tolerance = (expected == 0.0 ? 1.0e-4 : Math.Abs(expected) * 1.0e-2); calculated = igs.gaussianExpectedShortfall(twoSigma); if (Math.Abs(calculated - expected) > tolerance) { QAssert.Fail("IncrementalGaussianStatistics: " + "wrong Gaussian expected shortfall" + " for N(" + averages[i] + ", " + sigmas[j] + ")\n" + " calculated: " + calculated + "\n" + " expected: " + expected + "\n" + " tolerance: " + tolerance); } calculated = s.gaussianExpectedShortfall(twoSigma); if (Math.Abs(calculated - expected) > tolerance) { QAssert.Fail("RiskStatistics: wrong Gaussian expected shortfall" + " for N(" + averages[i] + ", " + sigmas[j] + ")\n" + " calculated: " + calculated + "\n" + " expected: " + expected + "\n" + " tolerance: " + tolerance); } calculated = s.expectedShortfall(twoSigma); if (Math.Abs(calculated - expected) > tolerance) { QAssert.Fail("RiskStatistics: wrong expected shortfall" + " for N(" + averages[i] + ", " + sigmas[j] + ")\n" + " calculated: " + calculated + "\n" + " expected: " + expected + "\n" + " tolerance: " + tolerance); } // shortfall expected = 0.5; tolerance = (expected == 0.0 ? 1.0e-3 : Math.Abs(expected * 1.0e-3)); calculated = igs.gaussianShortfall(averages[i]); if (Math.Abs(calculated - expected) > tolerance) { QAssert.Fail("IncrementalGaussianStatistics: " + "wrong Gaussian shortfall" + " for N(" + averages[i] + ", " + sigmas[j] + ")\n" + " calculated: " + calculated + "\n" + " expected: " + expected + "\n" + " tolerance: " + tolerance); } calculated = s.gaussianShortfall(averages[i]); if (Math.Abs(calculated - expected) > tolerance) { QAssert.Fail("RiskStatistics: wrong Gaussian shortfall" + " for N(" + averages[i] + ", " + sigmas[j] + ")\n" + " calculated: " + calculated + "\n" + " expected: " + expected + "\n" + " tolerance: " + tolerance); } calculated = s.shortfall(averages[i]); if (Math.Abs(calculated - expected) > tolerance) { QAssert.Fail("RiskStatistics: wrong shortfall" + " for N(" + averages[i] + ", " + sigmas[j] + ")\n" + " calculated: " + calculated + "\n" + " expected: " + expected + "\n" + " tolerance: " + tolerance); } // average shortfall expected = sigmas[j] / Math.Sqrt(2.0 * Const.M_PI) * 2.0; tolerance = expected * 1.0e-3; calculated = igs.gaussianAverageShortfall(averages[i]); if (Math.Abs(calculated - expected) > tolerance) { QAssert.Fail("IncrementalGaussianStatistics: " + "wrong Gaussian average shortfall" + " for N(" + averages[i] + ", " + sigmas[j] + ")\n" + " calculated: " + calculated + "\n" + " expected: " + expected + "\n" + " tolerance: " + tolerance); } calculated = s.gaussianAverageShortfall(averages[i]); if (Math.Abs(calculated - expected) > tolerance) { QAssert.Fail("RiskStatistics: wrong Gaussian average shortfall" + " for N(" + averages[i] + ", " + sigmas[j] + ")\n" + " calculated: " + calculated + "\n" + " expected: " + expected + "\n" + " tolerance: " + tolerance); } calculated = s.averageShortfall(averages[i]); if (Math.Abs(calculated - expected) > tolerance) { QAssert.Fail("RiskStatistics: wrong average shortfall" + " for N(" + averages[i] + ", " + sigmas[j] + ")\n" + " calculated: " + calculated + "\n" + " expected: " + expected + "\n" + " tolerance: " + tolerance); } // regret expected = sigmas[j] * sigmas[j]; tolerance = expected * 1.0e-1; calculated = igs.gaussianRegret(averages[i]); if (Math.Abs(calculated - expected) > tolerance) { QAssert.Fail("IncrementalGaussianStatistics: " + "wrong Gaussian regret(" + averages[i] + ") " + "for N(" + averages[i] + ", " + sigmas[j] + ")\n" + " calculated: " + calculated + "\n" + " expected: " + expected + "\n" + " tolerance: " + tolerance); } calculated = s.gaussianRegret(averages[i]); if (Math.Abs(calculated - expected) > tolerance) { QAssert.Fail("RiskStatistics: " + "wrong Gaussian regret(" + averages[i] + ") " + "for N(" + averages[i] + ", " + sigmas[j] + ")\n" + " calculated: " + calculated + "\n" + " expected: " + expected + "\n" + " tolerance: " + tolerance); } calculated = s.regret(averages[i]); if (Math.Abs(calculated - expected) > tolerance) { QAssert.Fail("RiskStatistics: " + "wrong regret(" + averages[i] + ") " + "for N(" + averages[i] + ", " + sigmas[j] + ")\n" + " calculated: " + calculated + "\n" + " expected: " + expected + "\n" + " tolerance: " + tolerance); } // downsideVariance expected = s.downsideVariance(); tolerance = (expected == 0.0 ? 1.0e-3 : Math.Abs(expected * 1.0e-3)); calculated = igs.downsideVariance(); if (Math.Abs(calculated - expected) > tolerance) { QAssert.Fail("IncrementalGaussianStatistics: " + "wrong downside variance" + "for N(" + averages[i] + ", " + sigmas[j] + ")\n" + " calculated: " + calculated + "\n" + " expected: " + expected + "\n" + " tolerance: " + tolerance); } calculated = igs.gaussianDownsideVariance(); if (Math.Abs(calculated - expected) > tolerance) { QAssert.Fail("IncrementalGaussianStatistics: " + "wrong Gaussian downside variance" + "for N(" + averages[i] + ", " + sigmas[j] + ")\n" + " calculated: " + calculated + "\n" + " expected: " + expected + "\n" + " tolerance: " + tolerance); } // downsideVariance if (averages[i] == 0.0) { expected = sigmas[j] * sigmas[j]; tolerance = expected * 1.0e-3; calculated = igs.downsideVariance(); if (Math.Abs(calculated - expected) > tolerance) { QAssert.Fail("IncrementalGaussianStatistics: " + "wrong downside variance" + "for N(" + averages[i] + ", " + sigmas[j] + ")\n" + " calculated: " + calculated + "\n" + " expected: " + expected + "\n" + " tolerance: " + tolerance); } calculated = igs.gaussianDownsideVariance(); if (Math.Abs(calculated - expected) > tolerance) { QAssert.Fail("IncrementalGaussianStatistics: " + "wrong Gaussian downside variance" + "for N(" + averages[i] + ", " + sigmas[j] + ")\n" + " calculated: " + calculated + "\n" + " expected: " + expected + "\n" + " tolerance: " + tolerance); } calculated = s.downsideVariance(); if (Math.Abs(calculated - expected) > tolerance) { QAssert.Fail("RiskStatistics: wrong downside variance" + "for N(" + averages[i] + ", " + sigmas[j] + ")\n" + " calculated: " + calculated + "\n" + " expected: " + expected + "\n" + " tolerance: " + tolerance); } calculated = s.gaussianDownsideVariance(); if (Math.Abs(calculated - expected) > tolerance) { QAssert.Fail("RiskStatistics: wrong Gaussian downside variance" + "for N(" + averages[i] + ", " + sigmas[j] + ")\n" + " calculated: " + calculated + "\n" + " expected: " + expected + "\n" + " tolerance: " + tolerance); } } igs.reset(); s.reset(); } } }
public void testSobol() { //("Testing Sobol sequences up to dimension " // + PPMT_MAX_DIM + "..."); List <double> point; double tolerance = 1.0e-15; // testing max dimensionality int dimensionality = (int)SobolRsg.PPMT_MAX_DIM; ulong seed = 123456; SobolRsg rsg = new SobolRsg(dimensionality, seed); int points = 100, i; for (i = 0; i < points; i++) { point = rsg.nextSequence().value; if (point.Count != dimensionality) { QAssert.Fail("Sobol sequence generator returns " + " a sequence of wrong dimensionality: " + point.Count + " instead of " + dimensionality); } } // testing homogeneity properties dimensionality = 33; seed = 123456; rsg = new SobolRsg(dimensionality, seed); SequenceStatistics stat = new SequenceStatistics(dimensionality); List <double> mean; int k = 0; for (int j = 1; j < 5; j++) { // five cycle points = (int)(Utils.Pow(2.0, j) - 1); // base 2 for (; k < points; k++) { point = rsg.nextSequence().value; stat.add(point); } mean = stat.mean(); for (i = 0; i < dimensionality; i++) { double error = Math.Abs(mean[i] - 0.5); if (error > tolerance) { QAssert.Fail(i + 1 + " dimension: " // + QL_FIXED + "mean (" + mean[i] + ") at the end of the " + j + 1 + " cycle in Sobol sequence is not " + 0.5 //+ QL_SCIENTIFIC + " (error = " + error + ")"); } } } // testing first dimension (van der Corput sequence) double[] vanderCorputSequenceModuloTwo = { // first cycle (zero excluded) 0.50000, // second cycle 0.75000, 0.25000, // third cycle 0.37500, 0.87500, 0.62500, 0.12500, // fourth cycle 0.18750, 0.68750, 0.93750, 0.43750, 0.31250, 0.81250, 0.56250, 0.06250, // fifth cycle 0.09375, 0.59375, 0.84375, 0.34375, 0.46875, 0.96875, 0.71875, 0.21875, 0.15625, 0.65625, 0.90625, 0.40625, 0.28125, 0.78125, 0.53125, 0.03125 }; dimensionality = 1; rsg = new SobolRsg(dimensionality); points = (int)(Utils.Pow(2.0, 5)) - 1; // five cycles for (i = 0; i < points; i++) { point = rsg.nextSequence().value; double error = Math.Abs(point[0] - vanderCorputSequenceModuloTwo[i]); if (error > tolerance) { QAssert.Fail(i + 1 + " draw (" //+ QL_FIXED + point[0] + ") in 1-D Sobol sequence is not in the " + "van der Corput sequence modulo two: " + "it should have been " + vanderCorputSequenceModuloTwo[i] //+ QL_SCIENTIFIC + " (error = " + error + ")"); } } }
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); } } } }
public void testModifiedBesselFunctions() { // Testing modified Bessel function of first and second kind /* reference values are computed with R and the additional package Bessel * http://cran.r-project.org/web/packages/Bessel */ double[][] r = { new double[4] { -1.3, 2.0, 1.2079888436539505, 0.1608243636110430 }, new double[4] { 1.3, 2.0, 1.2908192151358788, 0.1608243636110430 }, new double[4] { 0.001, 2.0, 2.2794705965773794, 0.1138938963603362 }, new double[4] { 1.2, 0.5, 0.1768918783499572, 2.1086579232338192 }, new double[4] { 2.3, 0.1, 0.00037954958988425198, 572.096866928290183 }, new double[4] { -2.3, 1.1, 1.07222017902746969, 1.88152553684107371 }, new double[4] { -10.0001, 1.1, 13857.7715614282552, 69288858.9474423379 } }; for (int i = 0; i < r.Length; ++i) { double nu = r[i][0]; double x = r[i][1]; double expected_i = r[i][2]; double expected_k = r[i][3]; double tol_i = 5e4 * Const.QL_EPSILON * Math.Abs(expected_i); double tol_k = 5e4 * Const.QL_EPSILON * Math.Abs(expected_k); double calculated_i = Utils.modifiedBesselFunction_i(nu, x); double calculated_k = Utils.modifiedBesselFunction_k(nu, x); if (Math.Abs(expected_i - calculated_i) > tol_i) { QAssert.Fail("failed to reproduce modified Bessel " + "function of first kind" + "\n order : " + nu + "\n argument : " + x + "\n calculated: " + calculated_i + "\n expected : " + expected_i); } if (Math.Abs(expected_k - calculated_k) > tol_k) { QAssert.Fail("failed to reproduce modified Bessel " + "function of second kind" + "\n order : " + nu + "\n argument : " + x + "\n calculated: " + calculated_k + "\n expected : " + expected_k); } } double[][] c = { new double[7] { -1.3, 2.0, 0.0, 1.2079888436539505, 0.0, 0.1608243636110430, 0.0 }, new double[7] { 1.2, 1.5, 0.3, 0.7891550871263575, 0.2721408731632123, 0.275126507673411, -0.1316314405663727 }, new double[7] { 1.2, -1.5, 0.0, -0.6650597524355781, -0.4831941938091643, -0.251112360556051, -2.400130904230102 }, new double[7] { -11.2, 1.5, 0.3, 12780719.20252659, 16401053.26770633, -34155172.65672453, -43830147.36759921 }, new double[7] { 1.2, -1.5, 2.0, -0.3869803778520574, 0.9756701796853728, -3.111629716783005, 0.6307859871879062 }, new double[7] { 1.2, 0.0, 9.9999, -0.03507838078252647, 0.1079601550451466, -0.05979939995451453, 0.3929814473878203 }, new double[7] { 1.2, 0.0, 10.1, -0.02782046891519293, 0.08562259917678558, -0.02035685034691133, 0.3949834389686676 }, new double[7] { 1.2, 0.0, 12.1, 0.07092110620741207, -0.2182727210128104, 0.3368505862966958, -0.1299038064313366 }, new double[7] { 1.2, 0.0, 14.1, -0.03014378676768797, 0.09277303628303372, -0.237531022649052, -0.2351923034581644 }, new double[7] { 1.2, 0.0, 16.1, -0.03823210284792657, 0.1176663135266562, -0.1091239402448228, 0.2930535651966139 }, new double[7] { 1.2, 0.0, 18.1, 0.05626742394733754, -0.173173324361983, 0.2941636588154642, -0.02023355577954348 }, new double[7] { 1.2, 0.0, 180.1, -0.001230682086826484, 0.003787649998122361, 0.02284509628723454, 0.09055419580980778 }, new double[7] { 1.2, 0.0, 21.0, -0.04746415965014021, 0.1460796627610969, -0.2693825171336859, -0.04830804448126782 }, new double[7] { 1.2, 10.0, 0.0, 2609.784936867044, 0, 1.904394919838336e-05, 0 }, new double[7] { 1.2, 14.0, 0.0, 122690.4873454286, 0, 2.902060692576643e-07, 0 }, new double[7] { 1.2, 20.0, 10.0, -37452017.91168936, -13917587.22151363, -3.821534367487143e-10, 4.083211255351664e-10 }, new double[7] { 1.2, 9.0, 9.0, -621.7335051293694, 618.1455736670332, -4.480795479964915e-05, -3.489034389148745e-08 } }; for (int i = 0; i < c.Length; ++i) { double nu = c[i][0]; Complex z = new Complex(c[i][1], c[i][2]); Complex expected_i = new Complex(c[i][3], c[i][4]); Complex expected_k = new Complex(c[i][5], c[i][6]); double tol_i = 5e4 * Const.QL_EPSILON * Complex.Abs(expected_i); double tol_k = 1e6 * Const.QL_EPSILON * Complex.Abs(expected_k); Complex calculated_i = Utils.modifiedBesselFunction_i(nu, z); Complex calculated_k = Utils.modifiedBesselFunction_k(nu, z); if (Complex.Abs(expected_i - calculated_i) > tol_i) { QAssert.Fail("failed to reproduce modified Bessel " + "function of first kind" + "\n order : " + nu + "\n argument : " + z + "\n calculated: " + calculated_i + "\n expected : " + expected_i); } if (Complex.Abs(expected_k) > 1e-4 && // do not check small values Complex.Abs(expected_k - calculated_k) > tol_k) { QAssert.Fail("failed to reproduce modified Bessel " + "function of second kind" + "\n order : " + nu + "\n argument : " + z + "\n diff : " + (calculated_k - expected_k) + "\n calculated: " + calculated_k + "\n expected : " + expected_k); } } }
public void testDecomposition() { // Testing collared coupon against its decomposition... CommonVars vars = new CommonVars(); double tolerance = 1e-10; double npvVanilla, npvCappedLeg, npvFlooredLeg, npvCollaredLeg, npvCap, npvFloor, npvCollar; double error; double floorstrike = 0.05; double capstrike = 0.10; List <double?> caps = new InitializedList <double?>(vars.length, capstrike); List <double?> caps0 = new List <double?>(); List <double?> floors = new InitializedList <double?>(vars.length, floorstrike); List <double?> floors0 = new List <double?>(); double gearing_p = 0.5; double spread_p = 0.002; double gearing_n = -1.5; double spread_n = 0.12; // fixed leg with zero rate List <CashFlow> fixedLeg = vars.makeFixedLeg(vars.startDate, vars.length); // floating leg with gearing=1 and spread=0 List <CashFlow> floatLeg = vars.makeYoYLeg(vars.startDate, vars.length); // floating leg with positive gearing (gearing_p) and spread<>0 List <CashFlow> floatLeg_p = vars.makeYoYLeg(vars.startDate, vars.length, gearing_p, spread_p); // floating leg with negative gearing (gearing_n) and spread<>0 List <CashFlow> floatLeg_n = vars.makeYoYLeg(vars.startDate, vars.length, gearing_n, spread_n); // Swap with null fixed leg and floating leg with gearing=1 and spread=0 Swap vanillaLeg = new Swap(fixedLeg, floatLeg); // Swap with null fixed leg and floating leg with positive gearing and spread<>0 Swap vanillaLeg_p = new Swap(fixedLeg, floatLeg_p); // Swap with null fixed leg and floating leg with negative gearing and spread<>0 Swap vanillaLeg_n = new Swap(fixedLeg, floatLeg_n); IPricingEngine engine = new DiscountingSwapEngine(vars.nominalTS); vanillaLeg.setPricingEngine(engine); // here use the autoset feature vanillaLeg_p.setPricingEngine(engine); vanillaLeg_n.setPricingEngine(engine); // CAPPED coupon - Decomposition of payoff // Payoff = Nom * Min(rate,strike) * accrualperiod = // = Nom * [rate + Min(0,strike-rate)] * accrualperiod = // = Nom * rate * accrualperiod - Nom * Max(rate-strike,0) * accrualperiod = // = VanillaFloatingLeg - Call // int whichPricer = 0; // Case gearing = 1 and spread = 0 List <CashFlow> cappedLeg = vars.makeYoYCapFlooredLeg(whichPricer, vars.startDate, vars.length, caps, floors0, vars.volatility); Swap capLeg = new Swap(fixedLeg, cappedLeg); capLeg.setPricingEngine(engine); YoYInflationCap cap = new YoYInflationCap(floatLeg, new List <double>() { capstrike }); cap.setPricingEngine(vars.makeEngine(vars.volatility, whichPricer)); npvVanilla = vanillaLeg.NPV(); npvCappedLeg = capLeg.NPV(); npvCap = cap.NPV(); error = Math.Abs(npvCappedLeg - (npvVanilla - npvCap)); if (error > tolerance) { QAssert.Fail("\nYoY Capped Leg: gearing=1, spread=0%, strike=" + capstrike * 100 + "%\n" + " Capped Floating Leg NPV: " + npvCappedLeg + "\n" + " Floating Leg NPV - Cap NPV: " + (npvVanilla - npvCap) + "\n" + " Diff: " + error); } // gearing = 1 and spread = 0 // FLOORED coupon - Decomposition of payoff // Payoff = Nom * Max(rate,strike) * accrualperiod = // = Nom * [rate + Max(0,strike-rate)] * accrualperiod = // = Nom * rate * accrualperiod + Nom * Max(strike-rate,0) * accrualperiod = // = VanillaFloatingLeg + Put // List <CashFlow> flooredLeg = vars.makeYoYCapFlooredLeg(whichPricer, vars.startDate, vars.length, caps0, floors, vars.volatility); Swap floorLeg = new Swap(fixedLeg, flooredLeg); floorLeg.setPricingEngine(engine); YoYInflationFloor floor = new YoYInflationFloor(floatLeg, new List <double>() { floorstrike }); floor.setPricingEngine(vars.makeEngine(vars.volatility, whichPricer)); npvFlooredLeg = floorLeg.NPV(); npvFloor = floor.NPV(); error = Math.Abs(npvFlooredLeg - (npvVanilla + npvFloor)); if (error > tolerance) { QAssert.Fail("YoY Floored Leg: gearing=1, spread=0%, strike=" + floorstrike * 100 + "%\n" + " Floored Floating Leg NPV: " + npvFlooredLeg + "\n" + " Floating Leg NPV + Floor NPV: " + (npvVanilla + npvFloor) + "\n" + " Diff: " + error); } // gearing = 1 and spread = 0 // COLLARED coupon - Decomposition of payoff // Payoff = Nom * Min(strikem,Max(rate,strikeM)) * accrualperiod = // = VanillaFloatingLeg - Collar // List <CashFlow> collaredLeg = vars.makeYoYCapFlooredLeg(whichPricer, vars.startDate, vars.length, caps, floors, vars.volatility); Swap collarLeg = new Swap(fixedLeg, collaredLeg); collarLeg.setPricingEngine(engine); YoYInflationCollar collar = new YoYInflationCollar(floatLeg, new List <double>() { capstrike }, new List <double>() { floorstrike }); collar.setPricingEngine(vars.makeEngine(vars.volatility, whichPricer)); npvCollaredLeg = collarLeg.NPV(); npvCollar = collar.NPV(); error = Math.Abs(npvCollaredLeg - (npvVanilla - npvCollar)); if (error > tolerance) { QAssert.Fail("\nYoY Collared Leg: gearing=1, spread=0%, strike=" + floorstrike * 100 + "% and " + capstrike * 100 + "%\n" + " Collared Floating Leg NPV: " + npvCollaredLeg + "\n" + " Floating Leg NPV - Collar NPV: " + (npvVanilla - npvCollar) + "\n" + " Diff: " + error); } // gearing = a and spread = b // CAPPED coupon - Decomposition of payoff // Payoff // = Nom * Min(a*rate+b,strike) * accrualperiod = // = Nom * [a*rate+b + Min(0,strike-a*rate-b)] * accrualperiod = // = Nom * a*rate+b * accrualperiod + Nom * Min(strike-b-a*rate,0) * accrualperiod // --> If a>0 (assuming positive effective strike): // Payoff = VanillaFloatingLeg - Call(a*rate+b,strike) // --> If a<0 (assuming positive effective strike): // Payoff = VanillaFloatingLeg + Nom * Min(strike-b+|a|*rate+,0) * accrualperiod = // = VanillaFloatingLeg + Put(|a|*rate+b,strike) // // Positive gearing List <CashFlow> cappedLeg_p = vars.makeYoYCapFlooredLeg(whichPricer, vars.startDate, vars.length, caps, floors0, vars.volatility, gearing_p, spread_p); Swap capLeg_p = new Swap(fixedLeg, cappedLeg_p); capLeg_p.setPricingEngine(engine); YoYInflationCap cap_p = new YoYInflationCap(floatLeg_p, new List <double>() { capstrike }); cap_p.setPricingEngine(vars.makeEngine(vars.volatility, whichPricer)); npvVanilla = vanillaLeg_p.NPV(); npvCappedLeg = capLeg_p.NPV(); npvCap = cap_p.NPV(); error = Math.Abs(npvCappedLeg - (npvVanilla - npvCap)); if (error > tolerance) { QAssert.Fail("\nYoY Capped Leg: gearing=" + gearing_p + ", " + "spread= " + spread_p * 100 + "%, strike=" + capstrike * 100 + "%, " + "effective strike= " + (capstrike - spread_p) / gearing_p * 100 + "%\n" + " Capped Floating Leg NPV: " + npvCappedLeg + "\n" + " Vanilla Leg NPV: " + npvVanilla + "\n" + " Cap NPV: " + npvCap + "\n" + " Floating Leg NPV - Cap NPV: " + (npvVanilla - npvCap) + "\n" + " Diff: " + error); } // Negative gearing List <CashFlow> cappedLeg_n = vars.makeYoYCapFlooredLeg(whichPricer, vars.startDate, vars.length, caps, floors0, vars.volatility, gearing_n, spread_n); Swap capLeg_n = new Swap(fixedLeg, cappedLeg_n); capLeg_n.setPricingEngine(engine); YoYInflationFloor floor_n = new YoYInflationFloor(floatLeg, new List <double>() { (capstrike - spread_n) / gearing_n }); floor_n.setPricingEngine(vars.makeEngine(vars.volatility, whichPricer)); npvVanilla = vanillaLeg_n.NPV(); npvCappedLeg = capLeg_n.NPV(); npvFloor = floor_n.NPV(); error = Math.Abs(npvCappedLeg - (npvVanilla + gearing_n * npvFloor)); if (error > tolerance) { QAssert.Fail("\nYoY Capped Leg: gearing=" + gearing_n + ", " + "spread= " + spread_n * 100 + "%, strike=" + capstrike * 100 + "%, " + "effective strike= " + ((capstrike - spread_n) / gearing_n * 100) + "%\n" + " Capped Floating Leg NPV: " + npvCappedLeg + "\n" + " npv Vanilla: " + npvVanilla + "\n" + " npvFloor: " + npvFloor + "\n" + " Floating Leg NPV - Cap NPV: " + (npvVanilla + gearing_n * npvFloor) + "\n" + " Diff: " + error); } // gearing = a and spread = b // FLOORED coupon - Decomposition of payoff // Payoff // = Nom * Max(a*rate+b,strike) * accrualperiod = // = Nom * [a*rate+b + Max(0,strike-a*rate-b)] * accrualperiod = // = Nom * a*rate+b * accrualperiod + Nom * Max(strike-b-a*rate,0) * accrualperiod // --> If a>0 (assuming positive effective strike): // Payoff = VanillaFloatingLeg + Put(a*rate+b,strike) // --> If a<0 (assuming positive effective strike): // Payoff = VanillaFloatingLeg + Nom * Max(strike-b+|a|*rate+,0) * accrualperiod = // = VanillaFloatingLeg - Call(|a|*rate+b,strike) // // Positive gearing List <CashFlow> flooredLeg_p1 = vars.makeYoYCapFlooredLeg(whichPricer, vars.startDate, vars.length, caps0, floors, vars.volatility, gearing_p, spread_p); Swap floorLeg_p1 = new Swap(fixedLeg, flooredLeg_p1); floorLeg_p1.setPricingEngine(engine); YoYInflationFloor floor_p1 = new YoYInflationFloor(floatLeg_p, new List <double>() { floorstrike }); floor_p1.setPricingEngine(vars.makeEngine(vars.volatility, whichPricer)); npvVanilla = vanillaLeg_p.NPV(); npvFlooredLeg = floorLeg_p1.NPV(); npvFloor = floor_p1.NPV(); error = Math.Abs(npvFlooredLeg - (npvVanilla + npvFloor)); if (error > tolerance) { QAssert.Fail("\nYoY Floored Leg: gearing=" + gearing_p + ", " + "spread= " + spread_p * 100 + "%, strike=" + floorstrike * 100 + "%, " + "effective strike= " + (floorstrike - spread_p) / gearing_p * 100 + "%\n" + " Floored Floating Leg NPV: " + npvFlooredLeg + "\n" + " Floating Leg NPV + Floor NPV: " + (npvVanilla + npvFloor) + "\n" + " Diff: " + error); } // Negative gearing List <CashFlow> flooredLeg_n = vars.makeYoYCapFlooredLeg(whichPricer, vars.startDate, vars.length, caps0, floors, vars.volatility, gearing_n, spread_n); Swap floorLeg_n = new Swap(fixedLeg, flooredLeg_n); floorLeg_n.setPricingEngine(engine); YoYInflationCap cap_n = new YoYInflationCap(floatLeg, new List <double>() { (floorstrike - spread_n) / gearing_n }); cap_n.setPricingEngine(vars.makeEngine(vars.volatility, whichPricer)); npvVanilla = vanillaLeg_n.NPV(); npvFlooredLeg = floorLeg_n.NPV(); npvCap = cap_n.NPV(); error = Math.Abs(npvFlooredLeg - (npvVanilla - gearing_n * npvCap)); if (error > tolerance) { QAssert.Fail("\nYoY Capped Leg: gearing=" + gearing_n + ", " + "spread= " + spread_n * 100 + "%, strike=" + floorstrike * 100 + "%, " + "effective strike= " + (floorstrike - spread_n) / gearing_n * 100 + "%\n" + " Capped Floating Leg NPV: " + npvFlooredLeg + "\n" + " Floating Leg NPV - Cap NPV: " + (npvVanilla - gearing_n * npvCap) + "\n" + " Diff: " + error); } // gearing = a and spread = b // COLLARED coupon - Decomposition of payoff // Payoff = Nom * Min(caprate,Max(a*rate+b,floorrate)) * accrualperiod // --> If a>0 (assuming positive effective strike): // Payoff = VanillaFloatingLeg - Collar(a*rate+b, floorrate, caprate) // --> If a<0 (assuming positive effective strike): // Payoff = VanillaFloatingLeg + Collar(|a|*rate+b, caprate, floorrate) // // Positive gearing List <CashFlow> collaredLeg_p = vars.makeYoYCapFlooredLeg(whichPricer, vars.startDate, vars.length, caps, floors, vars.volatility, gearing_p, spread_p); Swap collarLeg_p1 = new Swap(fixedLeg, collaredLeg_p); collarLeg_p1.setPricingEngine(engine); YoYInflationCollar collar_p = new YoYInflationCollar(floatLeg_p, new List <double>() { capstrike }, new List <double>() { floorstrike }); collar_p.setPricingEngine(vars.makeEngine(vars.volatility, whichPricer)); npvVanilla = vanillaLeg_p.NPV(); npvCollaredLeg = collarLeg_p1.NPV(); npvCollar = collar_p.NPV(); error = Math.Abs(npvCollaredLeg - (npvVanilla - npvCollar)); if (error > tolerance) { QAssert.Fail("\nYoY Collared Leg: gearing=" + gearing_p + ", " + "spread= " + spread_p * 100 + "%, strike=" + floorstrike * 100 + "% and " + capstrike * 100 + "%, " + "effective strike=" + (floorstrike - spread_p) / gearing_p * 100 + "% and " + (capstrike - spread_p) / gearing_p * 100 + "%\n" + " Collared Floating Leg NPV: " + npvCollaredLeg + "\n" + " Floating Leg NPV - Collar NPV: " + (npvVanilla - npvCollar) + "\n" + " Diff: " + error); } // Negative gearing List <CashFlow> collaredLeg_n = vars.makeYoYCapFlooredLeg(whichPricer, vars.startDate, vars.length, caps, floors, vars.volatility, gearing_n, spread_n); Swap collarLeg_n1 = new Swap(fixedLeg, collaredLeg_n); collarLeg_n1.setPricingEngine(engine); YoYInflationCollar collar_n = new YoYInflationCollar(floatLeg, new List <double>() { (floorstrike - spread_n) / gearing_n }, new List <double>() { (capstrike - spread_n) / gearing_n }); collar_n.setPricingEngine(vars.makeEngine(vars.volatility, whichPricer)); npvVanilla = vanillaLeg_n.NPV(); npvCollaredLeg = collarLeg_n1.NPV(); npvCollar = collar_n.NPV(); error = Math.Abs(npvCollaredLeg - (npvVanilla - gearing_n * npvCollar)); if (error > tolerance) { QAssert.Fail("\nYoY Collared Leg: gearing=" + gearing_n + ", " + "spread= " + spread_n * 100 + "%, strike=" + floorstrike * 100 + "% and " + capstrike * 100 + "%, " + "effective strike=" + (floorstrike - spread_n) / gearing_n * 100 + "% and " + (capstrike - spread_n) / gearing_n * 100 + "%\n" + " Collared Floating Leg NPV: " + npvCollaredLeg + "\n" + " Floating Leg NPV - Collar NPV: " + (npvVanilla - gearing_n * npvCollar) + "\n" + " Diff: " + error); } // remove circular refernce vars.hy.linkTo(null); }