public void testCachedValue() { //"Testing swaption value against cached value..."); CommonVars vars = new CommonVars(); vars.today = new Date(13, 3, 2002); vars.settlement = new Date(15, 3, 2002); Settings.setEvaluationDate( vars.today); vars.termStructure.linkTo(Utilities.flatRate(vars.settlement, 0.05, new Actual365Fixed())); Date exerciseDate = vars.calendar.advance(vars.settlement, new Period(5,TimeUnit.Years)); Date startDate = vars.calendar.advance(exerciseDate, vars.settlementDays,TimeUnit.Days); VanillaSwap swap = new MakeVanillaSwap(new Period(10,TimeUnit.Years), vars.index, 0.06) .withEffectiveDate(startDate); Swaption swaption = vars.makeSwaption(swap, exerciseDate, 0.20); //#if QL_USE_INDEXED_COUPON double cachedNPV = 0.036418158579; //#else // double cachedNPV = 0.036421429684; //#endif // FLOATING_POINT_EXCEPTION if (Math.Abs(swaption.NPV()-cachedNPV) > 1.0e-12) Assert.Fail ("failed to reproduce cached swaption value:\n" + //QL_FIXED + std::setprecision(12) + "\ncalculated: " + swaption.NPV() + "\nexpected: " + cachedNPV); }
public RendistatoCalculator(RendistatoBasket basket, Euribor euriborIndex, Handle <YieldTermStructure> discountCurve) { basket_ = basket; euriborIndex_ = euriborIndex; discountCurve_ = discountCurve; yields_ = new InitializedList <double>(basket_.size(), 0.05); durations_ = new List <double>(basket_.size()); nSwaps_ = 15; // TODO: generalize number of swaps and their lenghts swaps_ = new List <VanillaSwap>(nSwaps_); swapLenghts_ = new List <double>(nSwaps_); swapBondDurations_ = new InitializedList <double?>(nSwaps_, null); swapBondYields_ = new InitializedList <double?>(nSwaps_, 0.05); swapRates_ = new InitializedList <double?>(nSwaps_, null); basket_.registerWith(update); euriborIndex_.registerWith(update); discountCurve_.registerWith(update); double dummyRate = 0.05; for (int i = 0; i < nSwaps_; ++i) { swapLenghts_[i] = (i + 1); swaps_[i] = new MakeVanillaSwap(new Period((int)swapLenghts_[i], TimeUnit.Years), euriborIndex_, dummyRate, new Period(1, TimeUnit.Days)) .withDiscountingTermStructure(discountCurve_); } }
public MakeCapFloor(CapFloorType capFloorType, Period tenor, IborIndex iborIndex, double?strike = null, Period forwardStart = null) { capFloorType_ = capFloorType; strike_ = strike; firstCapletExcluded_ = (forwardStart == new Period(0, TimeUnit.Days)); asOptionlet_ = false; makeVanillaSwap_ = new MakeVanillaSwap(tenor, iborIndex, 0.0, forwardStart); }
public Swaption value() { Date evaluationDate = Settings.evaluationDate(); Calendar fixingCalendar = swapIndex_.fixingCalendar(); fixingDate_ = fixingCalendar.advance(evaluationDate, optionTenor_, optionConvention_); if (exerciseDate_ == null) { exercise_ = new EuropeanExercise(fixingDate_); } else { Utils.QL_REQUIRE(exerciseDate_ <= fixingDate_, () => "exercise date (" + exerciseDate_ + ") must be less " + "than or equal to fixing date (" + fixingDate_ + ")"); exercise_ = new EuropeanExercise(exerciseDate_); } double usedStrike; if (strike_ == null) { // ATM on the forecasting curve Utils.QL_REQUIRE(!swapIndex_.forwardingTermStructure().empty(), () => "no forecasting term structure set to " + swapIndex_.name()); VanillaSwap temp = swapIndex_.underlyingSwap(fixingDate_); temp.setPricingEngine(new DiscountingSwapEngine(swapIndex_.forwardingTermStructure())); usedStrike = temp.fairRate(); } else { usedStrike = strike_.Value; } BusinessDayConvention bdc = swapIndex_.fixedLegConvention(); underlyingSwap_ = new MakeVanillaSwap(swapIndex_.tenor(), swapIndex_.iborIndex(), usedStrike) .withEffectiveDate(swapIndex_.valueDate(fixingDate_)) .withFixedLegCalendar(swapIndex_.fixingCalendar()) .withFixedLegDayCount(swapIndex_.dayCounter()) .withFixedLegConvention(bdc) .withFixedLegTerminationDateConvention(bdc); Swaption swaption = new Swaption(underlyingSwap_, exercise_, delivery_); swaption.setPricingEngine(engine_); return(swaption); }
public void testImpliedVolatility() { //"Testing implied volatility for swaptions..."; CommonVars vars=new CommonVars(); int maxEvaluations = 100; double tolerance = 1.0e-08; Settlement.Type[] types = { Settlement.Type.Physical, Settlement.Type.Cash }; // test data double[] strikes = { 0.02, 0.03, 0.04, 0.05, 0.06, 0.07 }; double[] vols = { 0.01, 0.05, 0.10, 0.20, 0.30, 0.70, 0.90 }; for (int i = 0; i < exercises.Length; i++) { for (int j = 0; j < lengths.Length; j++) { Date exerciseDate = vars.calendar.advance(vars.today, exercises[i]); Date startDate = vars.calendar.advance(exerciseDate, vars.settlementDays, TimeUnit.Days); Date maturity = vars.calendar.advance(startDate, lengths[j], vars.floatingConvention); for (int t = 0; t < strikes.Length; t++) { for (int k = 0; k < type.Length; k++) { VanillaSwap swap = new MakeVanillaSwap(lengths[j], vars.index, strikes[t]) .withEffectiveDate(startDate) .withFloatingLegSpread(0.0) .withType(type[k]); for (int h = 0; h < types.Length; h++) { for (int u = 0; u < vols.Length; u++) { Swaption swaption = vars.makeSwaption(swap, exerciseDate, vols[u], types[h]); // Black price double value = swaption.NPV(); double implVol = 0.0; try { implVol = swaption.impliedVolatility(value, vars.termStructure, 0.10, tolerance, maxEvaluations); } catch (System.Exception e) { // couldn't bracket? swaption.setPricingEngine(vars.makeEngine(0.0)); double value2 = swaption.NPV(); if (Math.Abs(value - value2) < tolerance) { // ok, just skip: continue; } // otherwise, report error Assert.Fail("implied vol failure: " + exercises[i] + "x" + lengths[j] + " " + type[k] + "\nsettlement: " + types[h] + "\nstrike " + strikes[t] + "\natm level: " + swap.fairRate() + "\nvol: " + vols[u] + "\nprice: " + value + "\n" + e.Message.ToString()); } if (Math.Abs(implVol - vols[u]) > tolerance) { // the difference might not matter swaption.setPricingEngine(vars.makeEngine(implVol)); double value2 = swaption.NPV(); if (Math.Abs(value - value2) > tolerance) { Assert.Fail("implied vol failure: " + exercises[i] + "x" + lengths[j] + " " + type[k] + "\nsettlement: " + types[h] + "\nstrike " + strikes[t] + "\natm level: " + swap.fairRate() + "\nvol: " + vols[u] + "\nprice: " + value + "\nimplied vol: " + implVol + "\nimplied price: " + value2); } } } } } } } } }
public void testVega() { //"Testing swaption vega..."; CommonVars vars = new CommonVars(); Settlement.Type[] types = { Settlement.Type.Physical, Settlement.Type.Cash }; double[] strikes = { 0.03, 0.04, 0.05, 0.06, 0.07 }; double[] vols = { 0.01, 0.20, 0.30, 0.70, 0.90 }; double shift = 1e-8; for (int i=0; i<exercises.Length ; i++) { Date exerciseDate = vars.calendar.advance(vars.today, exercises[i]); // A VERIFIER§§§§ Date startDate = vars.calendar.advance(exerciseDate, vars.settlementDays, TimeUnit.Days); for (int j=0; j<lengths.Length ; j++) { for (int t=0; t<strikes.Length ; t++) { for (int h=0; h<type.Length ; h++) { VanillaSwap swap = new MakeVanillaSwap(lengths[j], vars.index, strikes[t]) .withEffectiveDate(startDate) .withFloatingLegSpread(0.0) .withType(type[h]); for (int u=0; u<vols.Length ; u++) { Swaption swaption = vars.makeSwaption(swap, exerciseDate, vols[u], types[h]); // FLOATING_POINT_EXCEPTION Swaption swaption1 = vars.makeSwaption(swap, exerciseDate, vols[u]-shift, types[h]); Swaption swaption2 = vars.makeSwaption(swap, exerciseDate, vols[u]+shift, types[h]); double swaptionNPV = swaption.NPV(); double numericalVegaPerPoint = (swaption2.NPV()-swaption1.NPV())/(200.0*shift); // check only relevant vega if (numericalVegaPerPoint/swaptionNPV>1.0e-7) { double analyticalVegaPerPoint = (double)swaption.result("vega")/100.0; double discrepancy = Math.Abs(analyticalVegaPerPoint - numericalVegaPerPoint); discrepancy /= numericalVegaPerPoint; double tolerance = 0.015; if (discrepancy > tolerance) Assert.Fail ("failed to compute swaption vega:" + "\n option tenor: " + exercises[i] + "\n volatility: " + vols[u] + "\n option type: " + swaption.type() + "\n swap tenor: " + lengths[j] + "\n strike: " + strikes[t] + "\n settlement: " + types[h] + "\n nominal: " + swaption.underlyingSwap().nominal + "\n npv: " + swaptionNPV + "\n calculated vega: " + analyticalVegaPerPoint + "\n expected vega: " + numericalVegaPerPoint + "\n discrepancy: " + discrepancy + "\n tolerance: " + tolerance); } } } } } } }
public void testStrikeDependency() { //("Testing swaption dependency on strike......"); CommonVars vars = new CommonVars(); double[] strikes = new double[] { 0.03, 0.04, 0.05, 0.06, 0.07 }; for (int i = 0; i < exercises.Length; i++) { for (int j = 0; j < lengths.Length; j++) { for (int k=0; k < type.Length ; k++) { Date exerciseDate = vars.calendar.advance(vars.today, exercises[i]); Date startDate = vars.calendar.advance(exerciseDate, vars.settlementDays, TimeUnit.Days); // store the results for different rates... List<double> values = new InitializedList<double>(strikes.Length); List<double> values_cash = new InitializedList<double>(strikes.Length); double vol = 0.20; for (int l=0; l< strikes.Length ; l++) { VanillaSwap swap = new MakeVanillaSwap(lengths[j], vars.index, strikes[l]) .withEffectiveDate(startDate) .withFloatingLegSpread(0.0) .withType(type[k]); Swaption swaption = vars.makeSwaption(swap,exerciseDate,vol); // FLOATING_POINT_EXCEPTION values[l]=swaption.NPV(); Swaption swaption_cash = vars.makeSwaption( swap,exerciseDate,vol, Settlement.Type.Cash); values_cash[l]=swaption_cash.NPV(); } // and check that they go the right way if (type[k]==VanillaSwap.Type.Payer) { for (int z = 0; z < values.Count - 1; z++) { if( values[z]<values[z+1]){ Assert.Fail("NPV of Payer swaption with delivery settlement"+ "is increasing with the strike:" + "\noption tenor: " + exercises[i] + "\noption date: " + exerciseDate + "\nvolatility: " + vol + "\nswap tenor: " + lengths[j] + "\nvalue: " + values[z ] +" at strike: " + strikes[z ] + "\nvalue: " + values[z+1] + " at strike: " + strikes[z+1]); } } for (int z = 0; z < values_cash.Count - 1; z++) { if (values_cash[z] < values_cash[z + 1]) { Assert.Fail("NPV of Payer swaption with cash settlement" + "is increasing with the strike:" + "\noption tenor: " + exercises[i] + "\noption date: " + exerciseDate + "\nvolatility: " + vol + "\nswap tenor: " + lengths[j] + "\nvalue: " + values_cash[z] + " at strike: " + strikes[z] + "\nvalue: " + values_cash[z + 1] + " at strike: " + strikes[z + 1]); } } } else { for (int z = 0; z < values.Count - 1; z++){ if (values[z] > values[z+1]){ Assert.Fail("NPV of Receiver swaption with delivery settlement" + "is increasing with the strike:" + "\noption tenor: " + exercises[i] + "\noption date: " + exerciseDate + "\nvolatility: " + vol + "\nswap tenor: " + lengths[j] + "\nvalue: " + values[z] + " at strike: " + strikes[z] + "\nvalue: " + values[z + 1] + " at strike: " + strikes[z + 1]); } } for (int z = 0; z < values_cash.Count - 1; z++) { if (values[z] > values[z+1]) { Assert.Fail("NPV of Receiver swaption with cash settlement" + "is increasing with the strike:" + "\noption tenor: " + exercises[i] + "\noption date: " + exerciseDate + "\nvolatility: " + vol + "\nswap tenor: " + lengths[j] + "\nvalue: " + values_cash[z] + " at strike: " + strikes[z] + "\nvalue: " + values_cash[z + 1] + " at strike: " + strikes[z + 1]); } } } } } } }
public void testSpreadTreatment() { //"Testing swaption treatment of spread..."; CommonVars vars = new CommonVars(); double[] spreads = { -0.002, -0.001, 0.0, 0.001, 0.002 }; for (int i=0; i<exercises.Length; i++) { for (int j=0; j<lengths.Length ; j++) { for (int k=0; k<type.Length ; k++) { Date exerciseDate = vars.calendar.advance(vars.today, exercises[i]); Date startDate = vars.calendar.advance(exerciseDate, vars.settlementDays,TimeUnit.Days); for (int l=0; l<spreads.Length ; l++) { VanillaSwap swap = new MakeVanillaSwap(lengths[j], vars.index, 0.06) .withEffectiveDate(startDate) .withFloatingLegSpread(spreads[l]) .withType(type[k]); // FLOATING_POINT_EXCEPTION double correction = spreads[l] * swap.floatingLegBPS() / swap.fixedLegBPS(); VanillaSwap equivalentSwap = new MakeVanillaSwap(lengths[j], vars.index, 0.06+correction) .withEffectiveDate(startDate) .withFloatingLegSpread(0.0) .withType(type[k]); Swaption swaption1 = vars.makeSwaption(swap,exerciseDate,0.20); Swaption swaption2 = vars.makeSwaption(equivalentSwap,exerciseDate,0.20); Swaption swaption1_cash = vars.makeSwaption(swap,exerciseDate,0.20, Settlement.Type.Cash); Swaption swaption2_cash = vars.makeSwaption(equivalentSwap,exerciseDate,0.20, Settlement.Type.Cash); if (Math.Abs(swaption1.NPV()-swaption2.NPV()) > 1.0e-6) Assert.Fail("wrong spread treatment:" + "\nexercise: " + exerciseDate + "\nlength: " + lengths[j] + "\ntype " + type[k] + "\nspread: " + spreads[l] + "\noriginal swaption value: " + swaption1.NPV() + "\nequivalent swaption value: " + swaption2.NPV()); if (Math.Abs(swaption1_cash.NPV()-swaption2_cash.NPV()) > 1.0e-6) Assert.Fail("wrong spread treatment:" + "\nexercise date: " + exerciseDate + "\nlength: " + lengths[j] + //"\npay " + (type[k] ? "fixed" : "floating") + "\nspread: " + spreads[l] + "\nvalue of original swaption: " + swaption1_cash.NPV() + "\nvalue of equivalent swaption: " + swaption2_cash.NPV()); } } } } }
public void testSpreadDependency() { //"Testing swaption dependency on spread..."; CommonVars vars = new CommonVars(); double[] spreads = { -0.002, -0.001, 0.0, 0.001, 0.002 }; for (int i=0; i<exercises.Length ; i++) { for (int j=0; j<lengths.Length ; j++) { for (int k=0; k<type.Length ; k++) { Date exerciseDate = vars.calendar.advance(vars.today, exercises[i]); Date startDate = vars.calendar.advance(exerciseDate, vars.settlementDays,TimeUnit.Days); // store the results for different rates... List<double> values=new InitializedList<double>(spreads.Length); List<double> values_cash = new InitializedList<double>(spreads.Length); for (int l=0; l<spreads.Length; l++) { VanillaSwap swap = new MakeVanillaSwap(lengths[j], vars.index, 0.06) .withEffectiveDate(startDate) .withFloatingLegSpread(spreads[l]) .withType(type[k]); Swaption swaption = vars.makeSwaption(swap,exerciseDate,0.20); // FLOATING_POINT_EXCEPTION values[l]=swaption.NPV(); Swaption swaption_cash = vars.makeSwaption(swap,exerciseDate,0.20, Settlement.Type.Cash); values_cash[l]=swaption_cash.NPV(); } // and check that they go the right way if (type[k]==VanillaSwap.Type.Payer) { for (int n = 0; n < spreads.Length - 1; n++) { if (values[n] > values[n + 1]) Assert.Fail("NPV is decreasing with the spread " + "in a payer swaption (physical delivered):" + "\nexercise date: " + exerciseDate + "\nlength: " + lengths[j] + "\nvalue: " + values[n] + " for spread: " + spreads[n] + "\nvalue: " + values[n + 1] + " for spread: " + spreads[n + 1]); if (values_cash[n] > values_cash[n + 1]) Assert.Fail("NPV is decreasing with the spread " + "in a payer swaption (cash delivered):" + "\nexercise date: " + exerciseDate + "\nlength: " + lengths[j] + "\nvalue: " + values_cash[n] + " for spread: " + spreads[n] + "\nvalue: " + values_cash[n + 1] + " for spread: " + spreads[n + 1]); } } else { for (int n = 0; n < spreads.Length - 1; n++) { if (values[n] < values[n + 1]) Assert.Fail("NPV is increasing with the spread " + "in a receiver swaption (physical delivered):" + "\nexercise date: " + exerciseDate + "\nlength: " + lengths[j] + "\nvalue: " + values[n] + " for spread: " + spreads[n] + "\nvalue: " + values[n + 1] + " for spread: " + spreads[n + 1]); if (values_cash[n] < values_cash[n+1]) Assert.Fail("NPV is increasing with the spread " + "in a receiver swaption (cash delivered):" + "\nexercise date: " + exerciseDate + "\nlength: " + lengths[j] + "\nvalue: " + values_cash[n ] + " for spread: " + spreads[n] + "\nvalue: " + values_cash[n+1] + " for spread: " + spreads[n+1]); } } } } } }
public RendistatoCalculator(RendistatoBasket basket, Euribor euriborIndex, Handle<YieldTermStructure> discountCurve) { basket_ = basket; euriborIndex_ = euriborIndex; discountCurve_ = discountCurve; yields_ = new InitializedList<double>(basket_.size(), 0.05); durations_ = new List<double>(basket_.size()); nSwaps_ = 15; // TODO: generalize number of swaps and their lenghts swaps_ = new List<VanillaSwap>(nSwaps_); swapLenghts_ = new List<double>(nSwaps_); swapBondDurations_ = new InitializedList<double?>(nSwaps_, null); swapBondYields_ = new InitializedList<double?>(nSwaps_, 0.05); swapRates_ = new InitializedList<double?>(nSwaps_, null); basket_.registerWith(update); euriborIndex_.registerWith(update); discountCurve_.registerWith(update); double dummyRate = 0.05; for (int i=0; i<nSwaps_; ++i) { swapLenghts_[i] = (i+1); swaps_[i] = new MakeVanillaSwap( new Period((int)swapLenghts_[i],TimeUnit.Years), euriborIndex_, dummyRate, new Period(1,TimeUnit.Days)) .withDiscountingTermStructure(discountCurve_); } }
public override void calculate() { /* both DTS, YTS ref dates and pricing date consistency * checks? settlement... */ Utils.QL_REQUIRE(!discountCurve_.empty(), () => "no discount term structure set"); Utils.QL_REQUIRE(!defaultTS_.empty(), () => "no ctpty default term structure set"); Utils.QL_REQUIRE(!swaptionletEngine_.empty(), () => "no swap option engine set"); Date priceDate = defaultTS_.link.referenceDate(); double cumOptVal = 0.0, cumPutVal = 0.0; // Vanilla swap so 0 leg is floater int index = 0; Date nextFD = arguments_.fixedPayDates[index]; Date swapletStart = priceDate; while (nextFD < priceDate) { index++; nextFD = arguments_.fixedPayDates[index]; } // Compute fair spread for strike value: // copy args into the non risky engine Swap.Arguments noCVAArgs = baseSwapEngine_.link.getArguments() as Swap.Arguments; noCVAArgs.legs = this.arguments_.legs; noCVAArgs.payer = this.arguments_.payer; baseSwapEngine_.link.calculate(); double baseSwapRate = ((FixedRateCoupon)arguments_.legs[0][0]).rate(); Swap.Results vSResults = baseSwapEngine_.link.getResults() as Swap.Results; double?baseSwapFairRate = -baseSwapRate * vSResults.legNPV[1] / vSResults.legNPV[0]; double?baseSwapNPV = vSResults.value; VanillaSwap.Type reversedType = arguments_.type == VanillaSwap.Type.Payer ? VanillaSwap.Type.Receiver : VanillaSwap.Type.Payer; // Swaplet options summatory: while (nextFD != arguments_.fixedPayDates.Last()) { // iFD coupon not fixed, create swaptionlet: IborIndex swapIndex = ((FloatingRateCoupon)arguments_.legs[1][0]).index() as IborIndex; // Alternatively one could cap this period to, say, 1M Period baseSwapsTenor = new Period(arguments_.fixedPayDates.Last().serialNumber() - swapletStart.serialNumber(), TimeUnit.Days); VanillaSwap swaplet = new MakeVanillaSwap(baseSwapsTenor, swapIndex, baseSwapFairRate) .withType(arguments_.type) .withNominal(arguments_.nominal) .withEffectiveDate(swapletStart) .withTerminationDate(arguments_.fixedPayDates.Last()).value(); VanillaSwap revSwaplet = new MakeVanillaSwap(baseSwapsTenor, swapIndex, baseSwapFairRate) .withType(reversedType) .withNominal(arguments_.nominal) .withEffectiveDate(swapletStart) .withTerminationDate(arguments_.fixedPayDates.Last()).value(); Swaption swaptionlet = new Swaption(swaplet, new EuropeanExercise(swapletStart)); Swaption putSwaplet = new Swaption(revSwaplet, new EuropeanExercise(swapletStart)); swaptionlet.setPricingEngine(swaptionletEngine_.currentLink()); putSwaplet.setPricingEngine(swaptionletEngine_.currentLink()); // atm underlying swap means that the value of put = value // call so this double pricing is not needed cumOptVal += swaptionlet.NPV() * defaultTS_.link.defaultProbability( swapletStart, nextFD); cumPutVal += putSwaplet.NPV() * invstDTS_.link.defaultProbability(swapletStart, nextFD); swapletStart = nextFD; index++; nextFD = arguments_.fixedPayDates[index]; } results_.value = baseSwapNPV - (1.0 - ctptyRecoveryRate_) * cumOptVal + (1.0 - invstRecoveryRate_) * cumPutVal; results_.fairRate = -baseSwapRate * (vSResults.legNPV[1] - (1.0 - ctptyRecoveryRate_) * cumOptVal + (1.0 - invstRecoveryRate_) * cumPutVal) / vSResults.legNPV[0]; }