public void testCapletPricing()
        {
            //"Testing caplet pricing...";

            //SavedSettings backup;

            const int size = 10;

            #if QL_USE_INDEXED_COUPON
            const double tolerance = 1e-5;
            #else
            const double tolerance = 1e-12;
            #endif

            IborIndex index = makeIndex();
            LiborForwardModelProcess process = new LiborForwardModelProcess(size, index);

            // set-up pricing engine
            OptionletVolatilityStructure capVolCurve = makeCapVolCurve(Settings.evaluationDate());

            Vector variances = new LfmHullWhiteParameterization(process, capVolCurve).covariance(0.0, null).diagonal();

            LmVolatilityModel volaModel = new LmFixedVolatilityModel(Vector.Sqrt(variances), process.fixingTimes());

            LmCorrelationModel corrModel = new LmExponentialCorrelationModel(size, 0.3);

            IAffineModel model = (IAffineModel)(new LiborForwardModel(process, volaModel, corrModel));

            Handle <YieldTermStructure> termStructure = process.index().forwardingTermStructure();

            AnalyticCapFloorEngine engine1 = new AnalyticCapFloorEngine(model, termStructure);

            Cap cap1 = new Cap(process.cashFlows(),
                               new InitializedList <double>(size, 0.04));
            cap1.setPricingEngine(engine1);

            const double expected   = 0.015853935178;
            double       calculated = cap1.NPV();

            if (Math.Abs(expected - calculated) > tolerance)
            {
                Assert.Fail("Failed to reproduce npv"
                            + "\n    calculated: " + calculated
                            + "\n    expected:   " + expected);
            }
        }
Пример #2
0
        public void testDecomposition()
        {
            // Testing collared coupon against its decomposition

            CommonVars vars = new CommonVars();

            double         tolerance = 1e-12;
            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.makeFloatingLeg(vars.startDate, vars.length);
            // floating leg with positive gearing (gearing_p) and spread<>0
            List <CashFlow> floatLeg_p = vars.makeFloatingLeg(vars.startDate, vars.length, gearing_p, spread_p);
            // floating leg with negative gearing (gearing_n) and spread<>0
            List <CashFlow> floatLeg_n = vars.makeFloatingLeg(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.termStructure);

            vanillaLeg.setPricingEngine(engine);
            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
             */

            // Case gearing = 1 and spread = 0
            List <CashFlow> cappedLeg = vars.makeCapFlooredLeg(vars.startDate, vars.length, caps, floors0, vars.volatility);
            Swap            capLeg    = new Swap(fixedLeg, cappedLeg);

            capLeg.setPricingEngine(engine);
            Cap cap = new Cap(floatLeg, new InitializedList <double>(1, capstrike));

            cap.setPricingEngine(vars.makeEngine(vars.volatility));
            npvVanilla   = vanillaLeg.NPV();
            npvCappedLeg = capLeg.NPV();
            npvCap       = cap.NPV();
            error        = Math.Abs(npvCappedLeg - (npvVanilla - npvCap));
            if (error > tolerance)
            {
                QAssert.Fail("\nCapped 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.makeCapFlooredLeg(vars.startDate, vars.length, caps0, floors, vars.volatility);
            Swap            floorLeg   = new Swap(fixedLeg, flooredLeg);

            floorLeg.setPricingEngine(engine);
            Floor floor = new Floor(floatLeg, new InitializedList <double>(1, floorstrike));

            floor.setPricingEngine(vars.makeEngine(vars.volatility));
            npvFlooredLeg = floorLeg.NPV();
            npvFloor      = floor.NPV();
            error         = Math.Abs(npvFlooredLeg - (npvVanilla + npvFloor));
            if (error > tolerance)
            {
                QAssert.Fail("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.makeCapFlooredLeg(vars.startDate, vars.length, caps, floors, vars.volatility);
            Swap            collarLeg   = new Swap(fixedLeg, collaredLeg);

            collarLeg.setPricingEngine(engine);
            Collar collar = new Collar(floatLeg, new InitializedList <double>(1, capstrike),
                                       new InitializedList <double>(1, floorstrike));

            collar.setPricingEngine(vars.makeEngine(vars.volatility));
            npvCollaredLeg = collarLeg.NPV();
            npvCollar      = collar.NPV();
            error          = Math.Abs(npvCollaredLeg - (npvVanilla - npvCollar));
            if (error > tolerance)
            {
                QAssert.Fail("\nCollared 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.makeCapFlooredLeg(vars.startDate, vars.length, caps, floors0,
                                                                 vars.volatility, gearing_p, spread_p);
            Swap capLeg_p = new Swap(fixedLeg, cappedLeg_p);

            capLeg_p.setPricingEngine(engine);
            Cap cap_p = new Cap(floatLeg_p, new InitializedList <double>(1, capstrike));

            cap_p.setPricingEngine(vars.makeEngine(vars.volatility));
            npvVanilla   = vanillaLeg_p.NPV();
            npvCappedLeg = capLeg_p.NPV();
            npvCap       = cap_p.NPV();
            error        = Math.Abs(npvCappedLeg - (npvVanilla - npvCap));
            if (error > tolerance)
            {
                QAssert.Fail("\nCapped 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.makeCapFlooredLeg(vars.startDate, vars.length, caps, floors0,
                                                                 vars.volatility, gearing_n, spread_n);
            Swap capLeg_n = new Swap(fixedLeg, cappedLeg_n);

            capLeg_n.setPricingEngine(engine);
            Floor floor_n = new Floor(floatLeg, new InitializedList <double>(1, (capstrike - spread_n) / gearing_n));

            floor_n.setPricingEngine(vars.makeEngine(vars.volatility));
            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("\nCapped 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.makeCapFlooredLeg(vars.startDate, vars.length, caps0, floors,
                                                                   vars.volatility, gearing_p, spread_p);
            Swap floorLeg_p1 = new Swap(fixedLeg, flooredLeg_p1);

            floorLeg_p1.setPricingEngine(engine);
            Floor floor_p1 = new Floor(floatLeg_p, new InitializedList <double>(1, floorstrike));

            floor_p1.setPricingEngine(vars.makeEngine(vars.volatility));
            npvVanilla    = vanillaLeg_p.NPV();
            npvFlooredLeg = floorLeg_p1.NPV();
            npvFloor      = floor_p1.NPV();
            error         = Math.Abs(npvFlooredLeg - (npvVanilla + npvFloor));
            if (error > tolerance)
            {
                QAssert.Fail("\nFloored 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.makeCapFlooredLeg(vars.startDate, vars.length, caps0, floors,
                                                                  vars.volatility, gearing_n, spread_n);
            Swap floorLeg_n = new Swap(fixedLeg, flooredLeg_n);

            floorLeg_n.setPricingEngine(engine);
            Cap cap_n = new Cap(floatLeg, new InitializedList <double>(1, (floorstrike - spread_n) / gearing_n));

            cap_n.setPricingEngine(vars.makeEngine(vars.volatility));
            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("\nCapped 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.makeCapFlooredLeg(vars.startDate, vars.length, caps, floors,
                                                                   vars.volatility, gearing_p, spread_p);
            Swap collarLeg_p1 = new Swap(fixedLeg, collaredLeg_p);

            collarLeg_p1.setPricingEngine(engine);
            Collar collar_p = new Collar(floatLeg_p, new InitializedList <double>(1, capstrike),
                                         new InitializedList <double>(1, floorstrike));

            collar_p.setPricingEngine(vars.makeEngine(vars.volatility));
            npvVanilla     = vanillaLeg_p.NPV();
            npvCollaredLeg = collarLeg_p1.NPV();
            npvCollar      = collar_p.NPV();
            error          = Math.Abs(npvCollaredLeg - (npvVanilla - npvCollar));
            if (error > tolerance)
            {
                QAssert.Fail("\nCollared 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.makeCapFlooredLeg(vars.startDate, vars.length, caps, floors,
                                                                   vars.volatility, gearing_n, spread_n);
            Swap collarLeg_n1 = new Swap(fixedLeg, collaredLeg_n);

            collarLeg_n1.setPricingEngine(engine);
            Collar collar_n = new Collar(floatLeg, new InitializedList <double>(1, (floorstrike - spread_n) / gearing_n),
                                         new InitializedList <double>(1, (capstrike - spread_n) / gearing_n));

            collar_n.setPricingEngine(vars.makeEngine(vars.volatility));
            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("\nCollared 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);
            }
        }
Пример #3
0
        public void testCapletPricing()
        {
            //"Testing caplet pricing...";

            //SavedSettings backup;

            const int size = 10;
            #if QL_USE_INDEXED_COUPON
            const double tolerance = 1e-5;
            #else
            const double tolerance = 1e-12;
            #endif

            IborIndex index = makeIndex();
            LiborForwardModelProcess process=new LiborForwardModelProcess(size, index);

            // set-up pricing engine
            OptionletVolatilityStructure capVolCurve = makeCapVolCurve(Settings.evaluationDate());

            Vector variances = new LfmHullWhiteParameterization(process, capVolCurve).covariance(0.0,null).diagonal();

            LmVolatilityModel volaModel = new LmFixedVolatilityModel(Vector.Sqrt(variances),process.fixingTimes());

            LmCorrelationModel corrModel = new LmExponentialCorrelationModel(size, 0.3);

            IAffineModel model = (IAffineModel)(new LiborForwardModel(process, volaModel, corrModel));

            Handle<YieldTermStructure> termStructure = process.index().forwardingTermStructure();

            AnalyticCapFloorEngine engine1 = new AnalyticCapFloorEngine(model, termStructure);

            Cap cap1 = new Cap( process.cashFlows(),
                                new InitializedList<double>(size, 0.04));
            cap1.setPricingEngine(engine1);

            const double expected = 0.015853935178;
            double calculated = cap1.NPV();

            if (Math.Abs(expected - calculated) > tolerance)
                Assert.Fail("Failed to reproduce npv"
                            + "\n    calculated: " + calculated
                            + "\n    expected:   " + expected);
        }