public void testCachedValue() { // Testing Black yoy inflation cap/floor price against cached values... CommonVars vars = new CommonVars(); int whichPricer = 0; // black double K = 0.0295; // one centi-point is fair rate error i.e. < 1 cp int j = 2; List<CashFlow> leg = vars.makeYoYLeg(vars.evaluationDate,j); Instrument cap = vars.makeYoYCapFloor(CapFloorType.Cap,leg, K, 0.01, whichPricer); Instrument floor = vars.makeYoYCapFloor(CapFloorType.Floor,leg, K, 0.01, whichPricer); // close to atm prices double cachedCapNPVblack = 219.452; double cachedFloorNPVblack = 314.641; // N.B. notionals are 10e6. Assert.IsTrue(Math.Abs(cap.NPV()-cachedCapNPVblack)<0.02,"yoy cap cached NPV wrong " +cap.NPV()+" should be "+cachedCapNPVblack+" Black pricer" +" diff was "+(Math.Abs(cap.NPV()-cachedCapNPVblack))); Assert.IsTrue(Math.Abs(floor.NPV()-cachedFloorNPVblack)<0.02,"yoy floor cached NPV wrong " +floor.NPV()+" should be "+cachedFloorNPVblack+" Black pricer" +" diff was "+(Math.Abs(floor.NPV()-cachedFloorNPVblack))); whichPricer = 1; // dd cap = vars.makeYoYCapFloor(CapFloorType.Cap,leg, K, 0.01, whichPricer); floor = vars.makeYoYCapFloor(CapFloorType.Floor,leg, K, 0.01, whichPricer); // close to atm prices double cachedCapNPVdd = 9114.61; double cachedFloorNPVdd = 9209.8; // N.B. notionals are 10e6. Assert.IsTrue(Math.Abs(cap.NPV()-cachedCapNPVdd)<0.22,"yoy cap cached NPV wrong " +cap.NPV()+" should be "+cachedCapNPVdd+" dd Black pricer" +" diff was "+(Math.Abs(cap.NPV()-cachedCapNPVdd))); Assert.IsTrue(Math.Abs(floor.NPV()-cachedFloorNPVdd)<0.22,"yoy floor cached NPV wrong " +floor.NPV()+" should be "+cachedFloorNPVdd+" dd Black pricer" +" diff was "+(Math.Abs(floor.NPV()-cachedFloorNPVdd))); whichPricer = 2; // bachelier cap = vars.makeYoYCapFloor(CapFloorType.Cap,leg, K, 0.01, whichPricer); floor = vars.makeYoYCapFloor(CapFloorType.Floor,leg, K, 0.01, whichPricer); // close to atm prices double cachedCapNPVbac = 8852.4; double cachedFloorNPVbac = 8947.59; // N.B. notionals are 10e6. Assert.IsTrue(Math.Abs(cap.NPV()-cachedCapNPVbac)<0.22,"yoy cap cached NPV wrong " +cap.NPV()+" should be "+cachedCapNPVbac+" bac Black pricer" +" diff was "+(Math.Abs(cap.NPV()-cachedCapNPVbac))); Assert.IsTrue(Math.Abs(floor.NPV()-cachedFloorNPVbac)<0.22,"yoy floor cached NPV wrong " +floor.NPV()+" should be "+cachedFloorNPVbac+" bac Black pricer" +" diff was "+(Math.Abs(floor.NPV()-cachedFloorNPVbac))); // remove circular refernce vars.hy.linkTo(new YoYInflationTermStructure()); }
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 testParity() { // Testing yoy inflation cap/floor parity... CommonVars vars = new CommonVars(); int[] lengths = { 1, 2, 3, 5, 7, 10, 15, 20 }; // vol is low ... double[] strikes = { 0.0, 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 }; // cap-floor-swap parity is model-independent 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)) .withConvention(BusinessDayConvention.Unadjusted) .withCalendar(new UnitedKingdom()).backwards().value(); YearOnYearInflationSwap swap = new YearOnYearInflationSwap (YearOnYearInflationSwap.Type.Payer, 1000000.0, yoySchedule,//fixed schedule, but same as yoy 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); // N.B. nominals are 10e6 if (Math.Abs((cap.NPV()-floor.NPV()) - swap.NPV()) > 1.0e-6) { Assert.Fail( "put/call parity violated:\n" + " length: " + lengths[i] + " years\n" + " volatility: " + vols[k] + "\n" + " strike: " + strikes[j] + "\n" + " cap value: " + cap.NPV() + "\n" + " floor value: " + floor.NPV() + "\n" + " swap value: " + swap.NPV()); } } } } } // remove circular refernce vars.hy.linkTo(new YoYInflationTermStructure()); }
public void testConsistency() { // Testing consistency between yoy inflation cap,floor and collar... CommonVars vars = new CommonVars(); int[] lengths = { 1, 2, 3, 5, 7, 10, 15, 20 }; double[] cap_rates = { 0.01, 0.025, 0.029, 0.03, 0.031, 0.035, 0.07 }; double[] floor_rates = { 0.01, 0.025, 0.029, 0.03, 0.031, 0.035, 0.07 }; double[] vols = { 0.001, 0.005, 0.010, 0.015, 0.020 }; for (int whichPricer = 0; whichPricer < 3; whichPricer++) { for (int i=0; i<lengths.Length; i++) { for (int j=0; j<cap_rates.Length; j++) { for (int k=0; k<floor_rates.Length; k++) { for (int l=0; l<vols.Length; l++) { List<CashFlow> leg = vars.makeYoYLeg(vars.evaluationDate,lengths[i]); YoYInflationCapFloor cap = vars.makeYoYCapFloor(CapFloorType.Cap, leg, cap_rates[j], vols[l], whichPricer); YoYInflationCapFloor floor = vars.makeYoYCapFloor(CapFloorType.Floor, leg, floor_rates[k], vols[l], whichPricer); YoYInflationCollar collar = new YoYInflationCollar(leg,new List<double>(){cap_rates[j]}, new List<double>(){floor_rates[k]}); collar.setPricingEngine(vars.makeEngine(vols[l], whichPricer)); if (Math.Abs((cap.NPV()-floor.NPV())-collar.NPV()) > 1e-6) { Assert.Fail( "inconsistency between cap, floor and collar:\n" + " length: " + lengths[i] + " years\n" + " volatility: " + "\n" + " cap value: " + cap.NPV() + " at strike: " + "\n" + " floor value: " + floor.NPV() + " at strike: " + "\n" + " collar value: " + collar.NPV()); } // test re-composition by optionlets, N.B. ONE per year double capletsNPV = 0.0; List<YoYInflationCapFloor> caplets = new List<YoYInflationCapFloor>(); for (int m=0; m<lengths[i]*1; m++) { caplets.Add(cap.optionlet(m)); caplets[m].setPricingEngine(vars.makeEngine(vols[l], whichPricer)); capletsNPV += caplets[m].NPV(); } if (Math.Abs(cap.NPV() - capletsNPV) > 1e-6) { Assert.Fail( "sum of caplet NPVs does not equal cap NPV:\n" + " length: " + lengths[i] + " years\n" + " volatility: " + "\n" + " cap value: " + cap.NPV() + " at strike: " + "\n" + " sum of caplets value: " + capletsNPV + " at strike (first): " + caplets[0].capRates()[0] + "\n" ); } double floorletsNPV = 0.0; List<YoYInflationCapFloor> floorlets = new List<YoYInflationCapFloor>(); for (int m=0; m<lengths[i]*1; m++) { floorlets.Add(floor.optionlet(m)); floorlets[m].setPricingEngine(vars.makeEngine(vols[l], whichPricer)); floorletsNPV += floorlets[m].NPV(); } if (Math.Abs(floor.NPV() - floorletsNPV) > 1e-6) { Assert.Fail( "sum of floorlet NPVs does not equal floor NPV:\n" + " length: " + lengths[i] + " years\n" + " volatility: " + "\n" + " cap value: " + floor.NPV() + " at strike: " + floor_rates[j] + "\n" + " sum of floorlets value: " + floorletsNPV + " at strike (first): " + floorlets[0].floorRates()[0] + "\n" ); } double collarletsNPV = 0.0; List<YoYInflationCapFloor> collarlets = new List<YoYInflationCapFloor>(); for (int m=0; m<lengths[i]*1; m++) { collarlets.Add(collar.optionlet(m)); collarlets[m].setPricingEngine(vars.makeEngine(vols[l], whichPricer)); collarletsNPV += collarlets[m].NPV(); } if (Math.Abs(collar.NPV() - collarletsNPV) > 1e-6) { Assert.Fail( "sum of collarlet NPVs does not equal floor NPV:\n" + " length: " + lengths[i] + " years\n" + " volatility: " + vols[l] + "\n" + " cap value: " + collar.NPV() + " at strike floor: " + floor_rates[j] + " at strike cap: " + cap_rates[j] + "\n" + " sum of collarlets value: " + collarletsNPV + " at strike floor (first): " + collarlets[0].floorRates()[0] + " at strike cap (first): " + collarlets[0].capRates()[0] + "\n" ); } } } } } } // pricer loop // remove circular refernce vars.hy.linkTo(new YoYInflationTermStructure()); }
public void testCachedValue() { // Testing Black yoy inflation cap/floor price against cached values... CommonVars vars = new CommonVars(); int whichPricer = 0; // black double K = 0.0295; // one centi-point is fair rate error i.e. < 1 cp int j = 2; List <CashFlow> leg = vars.makeYoYLeg(vars.evaluationDate, j); Instrument cap = vars.makeYoYCapFloor(CapFloorType.Cap, leg, K, 0.01, whichPricer); Instrument floor = vars.makeYoYCapFloor(CapFloorType.Floor, leg, K, 0.01, whichPricer); // close to atm prices double cachedCapNPVblack = 219.452; double cachedFloorNPVblack = 314.641; // N.B. notionals are 10e6. Assert.IsTrue(Math.Abs(cap.NPV() - cachedCapNPVblack) < 0.02, "yoy cap cached NPV wrong " + cap.NPV() + " should be " + cachedCapNPVblack + " Black pricer" + " diff was " + (Math.Abs(cap.NPV() - cachedCapNPVblack))); Assert.IsTrue(Math.Abs(floor.NPV() - cachedFloorNPVblack) < 0.02, "yoy floor cached NPV wrong " + floor.NPV() + " should be " + cachedFloorNPVblack + " Black pricer" + " diff was " + (Math.Abs(floor.NPV() - cachedFloorNPVblack))); whichPricer = 1; // dd cap = vars.makeYoYCapFloor(CapFloorType.Cap, leg, K, 0.01, whichPricer); floor = vars.makeYoYCapFloor(CapFloorType.Floor, leg, K, 0.01, whichPricer); // close to atm prices double cachedCapNPVdd = 9114.61; double cachedFloorNPVdd = 9209.8; // N.B. notionals are 10e6. Assert.IsTrue(Math.Abs(cap.NPV() - cachedCapNPVdd) < 0.22, "yoy cap cached NPV wrong " + cap.NPV() + " should be " + cachedCapNPVdd + " dd Black pricer" + " diff was " + (Math.Abs(cap.NPV() - cachedCapNPVdd))); Assert.IsTrue(Math.Abs(floor.NPV() - cachedFloorNPVdd) < 0.22, "yoy floor cached NPV wrong " + floor.NPV() + " should be " + cachedFloorNPVdd + " dd Black pricer" + " diff was " + (Math.Abs(floor.NPV() - cachedFloorNPVdd))); whichPricer = 2; // bachelier cap = vars.makeYoYCapFloor(CapFloorType.Cap, leg, K, 0.01, whichPricer); floor = vars.makeYoYCapFloor(CapFloorType.Floor, leg, K, 0.01, whichPricer); // close to atm prices double cachedCapNPVbac = 8852.4; double cachedFloorNPVbac = 8947.59; // N.B. notionals are 10e6. Assert.IsTrue(Math.Abs(cap.NPV() - cachedCapNPVbac) < 0.22, "yoy cap cached NPV wrong " + cap.NPV() + " should be " + cachedCapNPVbac + " bac Black pricer" + " diff was " + (Math.Abs(cap.NPV() - cachedCapNPVbac))); Assert.IsTrue(Math.Abs(floor.NPV() - cachedFloorNPVbac) < 0.22, "yoy floor cached NPV wrong " + floor.NPV() + " should be " + cachedFloorNPVbac + " bac Black pricer" + " diff was " + (Math.Abs(floor.NPV() - cachedFloorNPVbac))); // remove circular refernce vars.hy.linkTo(new YoYInflationTermStructure()); }
public void testParity() { // Testing yoy inflation cap/floor parity... CommonVars vars = new CommonVars(); int[] lengths = { 1, 2, 3, 5, 7, 10, 15, 20 }; // vol is low ... double[] strikes = { 0.0, 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 }; // cap-floor-swap parity is model-independent 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)) .withConvention(BusinessDayConvention.Unadjusted) .withCalendar(new UnitedKingdom()).backwards().value(); YearOnYearInflationSwap swap = new YearOnYearInflationSwap (YearOnYearInflationSwap.Type.Payer, 1000000.0, yoySchedule, //fixed schedule, but same as yoy 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); // N.B. nominals are 10e6 if (Math.Abs((cap.NPV() - floor.NPV()) - swap.NPV()) > 1.0e-6) { Assert.Fail( "put/call parity violated:\n" + " length: " + lengths[i] + " years\n" + " volatility: " + vols[k] + "\n" + " strike: " + strikes[j] + "\n" + " cap value: " + cap.NPV() + "\n" + " floor value: " + floor.NPV() + "\n" + " swap value: " + swap.NPV()); } } } } } // remove circular refernce vars.hy.linkTo(new YoYInflationTermStructure()); }
public void testConsistency() { // Testing consistency between yoy inflation cap,floor and collar... CommonVars vars = new CommonVars(); int[] lengths = { 1, 2, 3, 5, 7, 10, 15, 20 }; double[] cap_rates = { 0.01, 0.025, 0.029, 0.03, 0.031, 0.035, 0.07 }; double[] floor_rates = { 0.01, 0.025, 0.029, 0.03, 0.031, 0.035, 0.07 }; double[] vols = { 0.001, 0.005, 0.010, 0.015, 0.020 }; for (int whichPricer = 0; whichPricer < 3; whichPricer++) { for (int i = 0; i < lengths.Length; i++) { for (int j = 0; j < cap_rates.Length; j++) { for (int k = 0; k < floor_rates.Length; k++) { for (int l = 0; l < vols.Length; l++) { List <CashFlow> leg = vars.makeYoYLeg(vars.evaluationDate, lengths[i]); YoYInflationCapFloor cap = vars.makeYoYCapFloor(CapFloorType.Cap, leg, cap_rates[j], vols[l], whichPricer); YoYInflationCapFloor floor = vars.makeYoYCapFloor(CapFloorType.Floor, leg, floor_rates[k], vols[l], whichPricer); YoYInflationCollar collar = new YoYInflationCollar(leg, new List <double>() { cap_rates[j] }, new List <double>() { floor_rates[k] }); collar.setPricingEngine(vars.makeEngine(vols[l], whichPricer)); if (Math.Abs((cap.NPV() - floor.NPV()) - collar.NPV()) > 1e-6) { Assert.Fail( "inconsistency between cap, floor and collar:\n" + " length: " + lengths[i] + " years\n" + " volatility: " + "\n" + " cap value: " + cap.NPV() + " at strike: " + "\n" + " floor value: " + floor.NPV() + " at strike: " + "\n" + " collar value: " + collar.NPV()); } // test re-composition by optionlets, N.B. ONE per year double capletsNPV = 0.0; List <YoYInflationCapFloor> caplets = new List <YoYInflationCapFloor>(); for (int m = 0; m < lengths[i] * 1; m++) { caplets.Add(cap.optionlet(m)); caplets[m].setPricingEngine(vars.makeEngine(vols[l], whichPricer)); capletsNPV += caplets[m].NPV(); } if (Math.Abs(cap.NPV() - capletsNPV) > 1e-6) { Assert.Fail( "sum of caplet NPVs does not equal cap NPV:\n" + " length: " + lengths[i] + " years\n" + " volatility: " + "\n" + " cap value: " + cap.NPV() + " at strike: " + "\n" + " sum of caplets value: " + capletsNPV + " at strike (first): " + caplets[0].capRates()[0] + "\n" ); } double floorletsNPV = 0.0; List <YoYInflationCapFloor> floorlets = new List <YoYInflationCapFloor>(); for (int m = 0; m < lengths[i] * 1; m++) { floorlets.Add(floor.optionlet(m)); floorlets[m].setPricingEngine(vars.makeEngine(vols[l], whichPricer)); floorletsNPV += floorlets[m].NPV(); } if (Math.Abs(floor.NPV() - floorletsNPV) > 1e-6) { Assert.Fail( "sum of floorlet NPVs does not equal floor NPV:\n" + " length: " + lengths[i] + " years\n" + " volatility: " + "\n" + " cap value: " + floor.NPV() + " at strike: " + floor_rates[j] + "\n" + " sum of floorlets value: " + floorletsNPV + " at strike (first): " + floorlets[0].floorRates()[0] + "\n" ); } double collarletsNPV = 0.0; List <YoYInflationCapFloor> collarlets = new List <YoYInflationCapFloor>(); for (int m = 0; m < lengths[i] * 1; m++) { collarlets.Add(collar.optionlet(m)); collarlets[m].setPricingEngine(vars.makeEngine(vols[l], whichPricer)); collarletsNPV += collarlets[m].NPV(); } if (Math.Abs(collar.NPV() - collarletsNPV) > 1e-6) { Assert.Fail( "sum of collarlet NPVs does not equal floor NPV:\n" + " length: " + lengths[i] + " years\n" + " volatility: " + vols[l] + "\n" + " cap value: " + collar.NPV() + " at strike floor: " + floor_rates[j] + " at strike cap: " + cap_rates[j] + "\n" + " sum of collarlets value: " + collarletsNPV + " at strike floor (first): " + collarlets[0].floorRates()[0] + " at strike cap (first): " + collarlets[0].capRates()[0] + "\n" ); } } } } } } // pricer loop // remove circular refernce vars.hy.linkTo(new YoYInflationTermStructure()); }