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());
        }
Beispiel #2
0
        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);
        }
Beispiel #3
0
        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);
        }
        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());
        }
Beispiel #6
0
        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());
        }
Beispiel #7
0
        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());
        }
Beispiel #8
0
        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 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;
             InitializedList<double> caps = new InitializedList<double>(vars.length,capstrike);
             List<double> caps0 = new List<double>();
             InitializedList<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)
             {
            Assert.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)
             {
            Assert.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)
             {
            Assert.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)
             {
            Assert.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)
             {
            Assert.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)
             {
            Assert.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)
             {
            Assert.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)
             {
            Assert.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)
             {
            Assert.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(new YoYInflationTermStructure());
        }