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()); } } } } } }
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); } }
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()); } } } } } }