Ejemplo n.º 1
0
        public void testConsistency()
        {
            CommonVars vars = new CommonVars();

            int[]    lengths     = { 1, 2, 3, 5, 7, 10, 15, 20 };
            double[] cap_rates   = { 0.03, 0.04, 0.05, 0.06, 0.07 };
            double[] floor_rates = { 0.03, 0.04, 0.05, 0.06, 0.07 };
            double[] vols        = { 0.01, 0.05, 0.10, 0.15, 0.20 };

            Date startDate = vars.termStructure.link.referenceDate();

            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.makeLeg(startDate, lengths[i]);
                            Instrument      cap = vars.makeCapFloor(CapFloorType.Cap, leg,
                                                                    cap_rates[j], vols[l]);
                            Instrument floor = vars.makeCapFloor(CapFloorType.Floor, leg,
                                                                 floor_rates[k], vols[l]);
                            Collar collar = new Collar(leg, new InitializedList <double>(1, cap_rates[j]),
                                                       new InitializedList <double>(1, floor_rates[k]));
                            collar.setPricingEngine(vars.makeEngine(vols[l]));

                            if (Math.Abs((cap.NPV() - floor.NPV()) - collar.NPV()) > 1e-10)
                            {
                                QAssert.Fail(
                                    "inconsistency between cap, floor and collar:\n"
                                    + "    length:       " + lengths[i] + " years\n"
                                    + "    volatility:   " + vols[l] + "\n"
                                    + "    cap value:    " + cap.NPV()
                                    + " at strike: " + cap_rates[j] + "\n"
                                    + "    floor value:  " + floor.NPV()
                                    + " at strike: " + floor_rates[k] + "\n"
                                    + "    collar value: " + collar.NPV());
                            }
                        }
                    }
                }
            }
        }
Ejemplo n.º 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);
            }
        }
Ejemplo n.º 3
0
        public void testConsistency()
        {
            CommonVars vars = new CommonVars();

            int[] lengths = { 1, 2, 3, 5, 7, 10, 15, 20 };
            double[] cap_rates = { 0.03, 0.04, 0.05, 0.06, 0.07 };
            double[] floor_rates = { 0.03, 0.04, 0.05, 0.06, 0.07 };
            double[] vols = { 0.01, 0.05, 0.10, 0.15, 0.20 };

            Date startDate = vars.termStructure.link.referenceDate();

            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.makeLeg(startDate, lengths[i]);
                            Instrument cap = vars.makeCapFloor(CapFloorType.Cap, leg,
                                                  cap_rates[j], vols[l]);
                            Instrument floor = vars.makeCapFloor(CapFloorType.Floor, leg,
                                                  floor_rates[k], vols[l]);
                            Collar collar = new Collar(leg, new InitializedList<double>(1, cap_rates[j]),
                                          new InitializedList<double>(1, floor_rates[k]));
                            collar.setPricingEngine(vars.makeEngine(vols[l]));

                            if (Math.Abs((cap.NPV() - floor.NPV()) - collar.NPV()) > 1e-10) {
                                Assert.Fail(
                                  "inconsistency between cap, floor and collar:\n"
                                  + "    length:       " + lengths[i] + " years\n"
                                  + "    volatility:   " + vols[l] + "\n"
                                  + "    cap value:    " + cap.NPV()
                                  + " at strike: " + cap_rates[j] + "\n"
                                  + "    floor value:  " + floor.NPV()
                                  + " at strike: " + floor_rates[k] + "\n"
                                  + "    collar value: " + collar.NPV());
                            }
                        }
                    }
                }
            }
        }