public void zciisconsistency() { CommonVars common = new CommonVars(); ZeroCouponInflationSwap.Type ztype = ZeroCouponInflationSwap.Type.Payer; double nominal = 1000000.0; Date startDate = new Date(common.evaluationDate); Date endDate = new Date(25, Month.November, 2059); Calendar cal = new UnitedKingdom(); BusinessDayConvention paymentConvention = BusinessDayConvention.ModifiedFollowing; DayCounter dummyDC = null, dc = new ActualActual(); Period observationLag = new Period(2, TimeUnit.Months); double quote = 0.03714; ZeroCouponInflationSwap zciis = new ZeroCouponInflationSwap(ztype, nominal, startDate, endDate, cal, paymentConvention, dc, quote, common.ii, observationLag); // simple structure so simple pricing engine - most work done by index DiscountingSwapEngine dse = new DiscountingSwapEngine(common.nominalUK); zciis.setPricingEngine(dse); QAssert.IsTrue(Math.Abs(zciis.NPV()) < 1e-3, "zciis does not reprice to zero"); List <Date> oneDate = new List <Date>(); oneDate.Add(endDate); Schedule schOneDate = new Schedule(oneDate, cal, paymentConvention); CPISwap.Type stype = CPISwap.Type.Payer; double inflationNominal = nominal; double floatNominal = inflationNominal * Math.Pow(1.0 + quote, 50); bool subtractInflationNominal = true; double dummySpread = 0.0, dummyFixedRate = 0.0; int fixingDays = 0; Date baseDate = startDate - observationLag; double baseCPI = common.ii.fixing(baseDate); IborIndex dummyFloatIndex = new IborIndex(); CPISwap cS = new CPISwap(stype, floatNominal, subtractInflationNominal, dummySpread, dummyDC, schOneDate, paymentConvention, fixingDays, dummyFloatIndex, dummyFixedRate, baseCPI, dummyDC, schOneDate, paymentConvention, observationLag, common.ii, InterpolationType.AsIndex, inflationNominal); cS.setPricingEngine(dse); QAssert.IsTrue(Math.Abs(cS.NPV()) < 1e-3, "CPISwap as ZCIIS does not reprice to zero"); for (int i = 0; i < 2; i++) { double cs = cS.legNPV(i).GetValueOrDefault(); double z = zciis.legNPV(i).GetValueOrDefault(); QAssert.IsTrue(Math.Abs(cs - z) < 1e-3, "zciis leg does not equal CPISwap leg"); } // remove circular refernce common.hcpi.linkTo(null); }
//@} protected override void initializeDates() { Date settlementDate = settlementCalendar_.advance(evaluationDate_, settlementDays_, TimeUnit.Days); Date maturityDate = settlementDate + swapTenor_; Period shortLegTenor = shortIndex_.tenor(); Schedule shortLegSchedule = new MakeSchedule() .from(settlementDate) .to(maturityDate) .withTenor(shortLegTenor) .withCalendar(settlementCalendar_) .withConvention(rollConvention_) .endOfMonth(eom_) .value(); Period longLegTenor = longIndex_.tenor(); Schedule longLegSchedule = new MakeSchedule() .from(settlementDate) .to(maturityDate) .withTenor(longLegTenor) .withCalendar(settlementCalendar_) .withConvention(rollConvention_) .endOfMonth(eom_) .value(); double nominal = 1.0; double shortLegSpread = 0.0; double longLegSpread = 0.0; if (spreadOnShort_) { shortLegSpread = quote_.link.value(); } else { longLegSpread = quote_.link.value(); } /* Arbitrarily set the swap as paying the long index */ swap_ = new BasisSwap(BasisSwap.Type.Payer, nominal, shortLegSchedule, shortIndex_, shortLegSpread, shortIndex_.dayCounter(), longLegSchedule, longIndex_, longLegSpread, longIndex_.dayCounter(), BusinessDayConvention.Following); IPricingEngine engine; engine = new DiscountingSwapEngine(discountHandle_, false, settlementDate, settlementDate); engine.reset(); swap_.setPricingEngine(engine); earliestDate_ = swap_.startDate(); latestDate_ = swap_.maturityDate(); maturityDate_ = latestRelevantDate_ = swap_.maturityDate(); }
public void testFixing() { Date tradeDate = new Date(17, Month.April, 2015); Calendar calendar = new UnitedKingdom(); Date settlementDate = calendar.advance(tradeDate, 2, TimeUnit.Days, BusinessDayConvention.Following); Date maturityDate = calendar.advance(settlementDate, 5, TimeUnit.Years, BusinessDayConvention.Following); Date valueDate = new Date(20, Month.April, 2015); Settings.setEvaluationDate(valueDate); List <Date> dates = new List <Date>(); dates.Add(valueDate); dates.Add(valueDate + new Period(1, TimeUnit.Years)); dates.Add(valueDate + new Period(2, TimeUnit.Years)); dates.Add(valueDate + new Period(5, TimeUnit.Years)); dates.Add(valueDate + new Period(10, TimeUnit.Years)); dates.Add(valueDate + new Period(20, TimeUnit.Years)); List <double> rates = new List <double>(); rates.Add(0.01); rates.Add(0.01); rates.Add(0.01); rates.Add(0.01); rates.Add(0.01); rates.Add(0.01); var discountCurveHandle = new RelinkableHandle <YieldTermStructure>(); var forecastCurveHandle = new RelinkableHandle <YieldTermStructure>(); GBPLibor index = new GBPLibor(new Period(6, TimeUnit.Months), forecastCurveHandle); InterpolatedZeroCurve <Linear> zeroCurve = new InterpolatedZeroCurve <Linear>(dates, rates, new Actual360(), new Linear()); var fixedSchedule = new Schedule(settlementDate, maturityDate, new Period(1, TimeUnit.Years), calendar, BusinessDayConvention.Following, BusinessDayConvention.Following, DateGeneration.Rule.Forward, false); var floatSchedule = new Schedule(settlementDate, maturityDate, index.tenor(), calendar, BusinessDayConvention.Following, BusinessDayConvention.Following, DateGeneration.Rule.Forward, false); VanillaSwap swap = new VanillaSwap(VanillaSwap.Type.Payer, 1000000, fixedSchedule, 0.01, new Actual360(), floatSchedule, index, 0, new Actual360()); discountCurveHandle.linkTo(zeroCurve); forecastCurveHandle.linkTo(zeroCurve); var swapEngine = new DiscountingSwapEngine(discountCurveHandle, false, null); swap.setPricingEngine(swapEngine); try { double npv = swap.NPV(); } catch (Exception ex) { Assert.Fail(ex.Message); Console.WriteLine(ex); } }
public void testLargeRates() { // Testing degenerate collared coupon CommonVars vars = new CommonVars(); /* A vanilla floating leg and a capped floating leg with strike * equal to 100 and floor equal to 0 must have (about) the same NPV * (depending on variance: option expiry and volatility) */ List <double?> caps = new InitializedList <double?>(vars.length, 100.0); List <double?> floors = new InitializedList <double?>(vars.length, 0.0); double tolerance = 1e-10; // fixed leg with zero rate List <CashFlow> fixedLeg = vars.makeFixedLeg(vars.startDate, vars.length); List <CashFlow> floatLeg = vars.makeFloatingLeg(vars.startDate, vars.length); List <CashFlow> collaredLeg = vars.makeCapFlooredLeg(vars.startDate, vars.length, caps, floors, vars.volatility); IPricingEngine engine = new DiscountingSwapEngine(vars.termStructure); Swap vanillaLeg = new Swap(fixedLeg, floatLeg); Swap collarLeg = new Swap(fixedLeg, collaredLeg); vanillaLeg.setPricingEngine(engine); collarLeg.setPricingEngine(engine); double npvVanilla = vanillaLeg.NPV(); double npvCollar = collarLeg.NPV(); if (Math.Abs(npvVanilla - npvCollar) > tolerance) { QAssert.Fail("Lenght: " + vars.length + " y" + "\n" + "Volatility: " + vars.volatility * 100 + "%\n" + "Notional: " + vars.nominal + "\n" + "Vanilla floating leg NPV: " + vanillaLeg.NPV() + "\n" + "Collared floating leg NPV (strikes 0 and 100): " + collarLeg.NPV() + "\n" + "Diff: " + Math.Abs(vanillaLeg.NPV() - collarLeg.NPV())); } }
public VanillaSwap value() { Date startDate; if (effectiveDate_ != null) { startDate = effectiveDate_; } else { Date refDate = Settings.evaluationDate(); // if the evaluation date is not a business day // then move to the next business day refDate = floatCalendar_.adjust(refDate); Date spotDate = floatCalendar_.advance(refDate, new Period(settlementDays_, TimeUnit.Days)); startDate = spotDate + forwardStart_; if (forwardStart_.length() < 0) { startDate = floatCalendar_.adjust(startDate, BusinessDayConvention.Preceding); } else { startDate = floatCalendar_.adjust(startDate, BusinessDayConvention.Following); } } Date endDate = terminationDate_; if (endDate == null) { if (floatEndOfMonth_) { endDate = floatCalendar_.advance(startDate, swapTenor_, BusinessDayConvention.ModifiedFollowing, floatEndOfMonth_); } else { endDate = startDate + swapTenor_; } } Currency curr = iborIndex_.currency(); Period fixedTenor = null; if (fixedTenor_ != null) { fixedTenor = fixedTenor_; } else { if ((curr == new EURCurrency()) || (curr == new USDCurrency()) || (curr == new CHFCurrency()) || (curr == new SEKCurrency()) || (curr == new GBPCurrency() && swapTenor_ <= new Period(1, TimeUnit.Years))) { fixedTenor = new Period(1, TimeUnit.Years); } else if ((curr == new GBPCurrency() && swapTenor_ > new Period(1, TimeUnit.Years) || (curr == new JPYCurrency()) || (curr == new AUDCurrency() && swapTenor_ >= new Period(4, TimeUnit.Years)))) { fixedTenor = new Period(6, TimeUnit.Months); } else if ((curr == new HKDCurrency() || (curr == new AUDCurrency() && swapTenor_ < new Period(4, TimeUnit.Years)))) { fixedTenor = new Period(3, TimeUnit.Months); } else { Utils.QL_FAIL("unknown fixed leg default tenor for " + curr); } } Schedule fixedSchedule = new Schedule(startDate, endDate, fixedTenor, fixedCalendar_, fixedConvention_, fixedTerminationDateConvention_, fixedRule_, fixedEndOfMonth_, fixedFirstDate_, fixedNextToLastDate_); Schedule floatSchedule = new Schedule(startDate, endDate, floatTenor_, floatCalendar_, floatConvention_, floatTerminationDateConvention_, floatRule_, floatEndOfMonth_, floatFirstDate_, floatNextToLastDate_); DayCounter fixedDayCount = null; if (fixedDayCount_ != null) { fixedDayCount = fixedDayCount_; } else { if (curr == new USDCurrency()) { fixedDayCount = new Actual360(); } else if (curr == new EURCurrency() || curr == new CHFCurrency() || curr == new SEKCurrency()) { fixedDayCount = new Thirty360(Thirty360.Thirty360Convention.BondBasis); } else if (curr == new GBPCurrency() || curr == new JPYCurrency() || curr == new AUDCurrency() || curr == new HKDCurrency()) { fixedDayCount = new Actual365Fixed(); } else { Utils.QL_FAIL("unknown fixed leg day counter for " + curr); } } double?usedFixedRate = fixedRate_; if (fixedRate_ == null) { VanillaSwap temp = new VanillaSwap(type_, nominal_, fixedSchedule, 0.0, fixedDayCount, floatSchedule, iborIndex_, floatSpread_, floatDayCount_); if (engine_ == null) { Handle <YieldTermStructure> disc = iborIndex_.forwardingTermStructure(); Utils.QL_REQUIRE(!disc.empty(), () => "null term structure set to this instance of " + iborIndex_.name()); bool includeSettlementDateFlows = false; IPricingEngine engine = new DiscountingSwapEngine(disc, includeSettlementDateFlows); temp.setPricingEngine(engine); } else { temp.setPricingEngine(engine_); } usedFixedRate = temp.fairRate(); } VanillaSwap swap = new VanillaSwap(type_, nominal_, fixedSchedule, usedFixedRate.Value, fixedDayCount, floatSchedule, iborIndex_, floatSpread_, floatDayCount_); if (engine_ == null) { Handle <YieldTermStructure> disc = iborIndex_.forwardingTermStructure(); bool includeSettlementDateFlows = false; IPricingEngine engine = new DiscountingSwapEngine(disc, includeSettlementDateFlows); swap.setPricingEngine(engine); } else { swap.setPricingEngine(engine_); } return(swap); }
private static void Main() { DateTime startTime = DateTime.Now; var todaysDate = new DateTime(2002, 2, 15); Settings.instance().setEvaluationDate(todaysDate); Calendar calendar = new TARGET(); var settlementDate = new Date(19, Month.February, 2002); // flat yield term structure impling 1x5 swap at 5% Quote flatRate = new SimpleQuote(0.04875825); var myTermStructure = new FlatForward(settlementDate, new QuoteHandle(flatRate), new Actual365Fixed()); var rhTermStructure = new RelinkableYieldTermStructureHandle(); rhTermStructure.linkTo(myTermStructure); // Define the ATM/OTM/ITM swaps var fixedLegTenor = new Period(1, TimeUnit.Years); const BusinessDayConvention fixedLegConvention = BusinessDayConvention.Unadjusted; const BusinessDayConvention floatingLegConvention = BusinessDayConvention.ModifiedFollowing; DayCounter fixedLegDayCounter = new Thirty360(Thirty360.Convention.European); var floatingLegTenor = new Period(6, TimeUnit.Months); const double dummyFixedRate = 0.03; IborIndex indexSixMonths = new Euribor6M(rhTermStructure); Date startDate = calendar.advance(settlementDate, 1, TimeUnit.Years, floatingLegConvention); Date maturity = calendar.advance(startDate, 5, TimeUnit.Years, floatingLegConvention); var fixedSchedule = new Schedule(startDate, maturity, fixedLegTenor, calendar, fixedLegConvention, fixedLegConvention, DateGeneration.Rule.Forward, false); var floatSchedule = new Schedule(startDate, maturity, floatingLegTenor, calendar, floatingLegConvention, floatingLegConvention, DateGeneration.Rule.Forward, false); var swap = new VanillaSwap(VanillaSwap.Type.Payer, 1000.0, fixedSchedule, dummyFixedRate, fixedLegDayCounter, floatSchedule, indexSixMonths, 0.0, indexSixMonths.dayCounter()); var swapEngine = new DiscountingSwapEngine(rhTermStructure); swap.setPricingEngine(swapEngine); double fixedAtmRate = swap.fairRate(); double fixedOtmRate = fixedAtmRate * 1.2; double fixedItmRate = fixedAtmRate * 0.8; var atmSwap = new VanillaSwap(VanillaSwap.Type.Payer, 1000.0, fixedSchedule, fixedAtmRate, fixedLegDayCounter, floatSchedule, indexSixMonths, 0.0, indexSixMonths.dayCounter()); var otmSwap = new VanillaSwap(VanillaSwap.Type.Payer, 1000.0, fixedSchedule, fixedOtmRate, fixedLegDayCounter, floatSchedule, indexSixMonths, 0.0, indexSixMonths.dayCounter()); var itmSwap = new VanillaSwap(VanillaSwap.Type.Payer, 1000.0, fixedSchedule, fixedItmRate, fixedLegDayCounter, floatSchedule, indexSixMonths, 0.0, indexSixMonths.dayCounter()); atmSwap.setPricingEngine(swapEngine); otmSwap.setPricingEngine(swapEngine); itmSwap.setPricingEngine(swapEngine); // defining the swaptions to be used in model calibration var swaptionMaturities = new PeriodVector { new Period(1, TimeUnit.Years), new Period(2, TimeUnit.Years), new Period(3, TimeUnit.Years), new Period(4, TimeUnit.Years), new Period(5, TimeUnit.Years) }; var swaptions = new CalibrationHelperVector(); // List of times that have to be included in the timegrid var times = new DoubleVector(); for (int i = 0; i < NUM_ROWS; i++) { int j = NUM_COLS - i - 1; // 1x5, 2x4, 3x3, 4x2, 5x1 int k = i * NUM_COLS + j; Quote vol = new SimpleQuote(SWAPTION_VOLS[k]); var helper = new SwaptionHelper(swaptionMaturities[i], new Period(SWAP_LENGHTS[j], TimeUnit.Years), new QuoteHandle(vol), indexSixMonths, indexSixMonths.tenor(), indexSixMonths.dayCounter(), indexSixMonths.dayCounter(), rhTermStructure); swaptions.Add(helper); times.AddRange(helper.times()); } // Building time-grid var grid = new TimeGrid(times, 30); // defining the models // G2 modelG2 = new G2(rhTermStructure)); var modelHw = new HullWhite(rhTermStructure); var modelHw2 = new HullWhite(rhTermStructure); var modelBk = new BlackKarasinski(rhTermStructure); // model calibrations Console.WriteLine("Hull-White (analytic formulae) calibration"); foreach (CalibrationHelper calibrationHelper in swaptions) { NQuantLibc.as_black_helper(calibrationHelper).setPricingEngine(new JamshidianSwaptionEngine(modelHw)); } CalibrateModel(modelHw, swaptions, 0.05); Console.WriteLine("Hull-White (numerical) calibration"); foreach (CalibrationHelper calibrationHelper in swaptions) { NQuantLibc.as_black_helper(calibrationHelper).setPricingEngine(new TreeSwaptionEngine(modelHw2, grid)); } CalibrateModel(modelHw2, swaptions, 0.05); Console.WriteLine("Black-Karasinski (numerical) calibration"); foreach (CalibrationHelper calibrationHelper in swaptions) { NQuantLibc.as_black_helper(calibrationHelper).setPricingEngine(new TreeSwaptionEngine(modelBk, grid)); } CalibrateModel(modelBk, swaptions, 0.05); // ATM Bermudan swaption pricing Console.WriteLine("Payer bermudan swaption struck at {0} (ATM)", fixedAtmRate); var bermudanDates = new DateVector(); var schedule = new Schedule(startDate, maturity, new Period(3, TimeUnit.Months), calendar, BusinessDayConvention.Following, BusinessDayConvention.Following, DateGeneration.Rule.Forward, false); for (uint i = 0; i < schedule.size(); i++) { bermudanDates.Add(schedule.date(i)); } Exercise bermudaExercise = new BermudanExercise(bermudanDates); var bermudanSwaption = new Swaption(atmSwap, bermudaExercise); bermudanSwaption.setPricingEngine(new TreeSwaptionEngine(modelHw, 50)); Console.WriteLine("HW: " + bermudanSwaption.NPV()); bermudanSwaption.setPricingEngine(new TreeSwaptionEngine(modelHw2, 50)); Console.WriteLine("HW (num): " + bermudanSwaption.NPV()); bermudanSwaption.setPricingEngine(new TreeSwaptionEngine(modelBk, 50)); Console.WriteLine("BK (num): " + bermudanSwaption.NPV()); DateTime endTime = DateTime.Now; TimeSpan delta = endTime - startTime; Console.WriteLine(); Console.WriteLine("Run completed in {0} s", delta.TotalSeconds); Console.WriteLine(); }
internal static global::System.Runtime.InteropServices.HandleRef getCPtr(DiscountingSwapEngine obj) { return (obj == null) ? new global::System.Runtime.InteropServices.HandleRef(null, global::System.IntPtr.Zero) : obj.swigCPtr; }
public static object eqInstIROISSwap( [ExcelArgument(Description = "trade id ")] string tradeid, [ExcelArgument(Description = "payer/receiver (1/0) ")] bool ispayer, [ExcelArgument(Description = "notional ")] double notional, [ExcelArgument(Description = "fixed rate ")] double fixedRate, [ExcelArgument(Description = "start date ")] DateTime startdate, [ExcelArgument(Description = " (String) forward start month, e.g. 7D, 3M, 7Y ")] string Tenor, [ExcelArgument(Description = "id of overnight index ")] string indexid, [ExcelArgument(Description = "floating leg spread ")] double spread, [ExcelArgument(Description = "id of discount curve ")] string discountId, [ExcelArgument(Description = "trigger ")] object trigger) { if (ExcelUtil.CallFromWizard()) { return(""); } string callerAddress = ""; callerAddress = ExcelUtil.getActiveCellAddress(); try { Xl.Range rng = ExcelUtil.getActiveCellRange(); // by default // endOfMonth_(1*Months<=swapTenor && swapTenor<=2*Years ? true : false), bool end_of_month = true; EliteQuant.DayCounter fixeddc = new EliteQuant.Actual360(); if (!indexid.Contains('@')) { indexid = "IDX@" + indexid; } OvernightIndex idx = OHRepository.Instance.getObject <OvernightIndex>(indexid); if (!discountId.Contains('@')) { discountId = "CRV@" + discountId; } YieldTermStructure discountcurve = OHRepository.Instance.getObject <YieldTermStructure>(discountId); YieldTermStructureHandle dch = new YieldTermStructureHandle(discountcurve); EliteQuant.Period tenor_ = EliteQuant.EQConverter.ConvertObject <EliteQuant.Period>(Tenor); EliteQuant.Date sdate = EliteQuant.EQConverter.ConvertObject <EliteQuant.Date>(startdate); EliteQuant.Date fdate = idx.fixingDate(sdate); EliteQuant.Date tdate = idx.fixingCalendar().advance(sdate, tenor_); // fixed leg 1 yr. Forward? Schedule fixedsch = new Schedule(sdate, tdate, new Period(1, TimeUnit.Years), idx.fixingCalendar(), idx.businessDayConvention(), idx.businessDayConvention(), DateGeneration.Rule.Forward, end_of_month); OvernightIndexedSwap swap = new OvernightIndexedSwap(ispayer ? _OvernightIndexedSwap.Type.Payer : _OvernightIndexedSwap.Type.Receiver, notional, fixedsch, fixedRate, fixeddc, idx, spread); DiscountingSwapEngine engine = new DiscountingSwapEngine(dch); swap.setPricingEngine(engine); Date refDate = discountcurve.referenceDate(); // Store the futures and return its id string id = "SWP@" + tradeid; OHRepository.Instance.storeObject(id, swap, callerAddress); id += "#" + (String)DateTime.Now.ToString(@"HH:mm:ss"); return(id); } catch (Exception e) { ExcelUtil.logError(callerAddress, System.Reflection.MethodInfo.GetCurrentMethod().Name.ToString(), e.Message); return("#EQ_ERR!"); } }
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); }
static void Main(string[] args) { DateTime startTime = DateTime.Now; Date todaysDate = new Date(15, Month.February, 2002); Calendar calendar = new TARGET(); Date settlementDate = new Date(19, Month.February, 2002); Settings.instance().setEvaluationDate(todaysDate); // flat yield term structure impling 1x5 swap at 5% Quote flatRate = new SimpleQuote(0.04875825); FlatForward myTermStructure = new FlatForward( settlementDate, new QuoteHandle(flatRate), new Actual365Fixed()); RelinkableYieldTermStructureHandle rhTermStructure = new RelinkableYieldTermStructureHandle(); rhTermStructure.linkTo(myTermStructure); // Define the ATM/OTM/ITM swaps Period fixedLegTenor = new Period(1, TimeUnit.Years); BusinessDayConvention fixedLegConvention = BusinessDayConvention.Unadjusted; BusinessDayConvention floatingLegConvention = BusinessDayConvention.ModifiedFollowing; DayCounter fixedLegDayCounter = new Thirty360(Thirty360.Convention.European); Period floatingLegTenor = new Period(6, TimeUnit.Months); double dummyFixedRate = 0.03; IborIndex indexSixMonths = new Euribor6M(rhTermStructure); Date startDate = calendar.advance(settlementDate, 1, TimeUnit.Years, floatingLegConvention); Date maturity = calendar.advance(startDate, 5, TimeUnit.Years, floatingLegConvention); Schedule fixedSchedule = new Schedule(startDate, maturity, fixedLegTenor, calendar, fixedLegConvention, fixedLegConvention, DateGeneration.Rule.Forward, false); Schedule floatSchedule = new Schedule(startDate, maturity, floatingLegTenor, calendar, floatingLegConvention, floatingLegConvention, DateGeneration.Rule.Forward, false); VanillaSwap swap = new VanillaSwap( VanillaSwap.Type.Payer, 1000.0, fixedSchedule, dummyFixedRate, fixedLegDayCounter, floatSchedule, indexSixMonths, 0.0, indexSixMonths.dayCounter()); DiscountingSwapEngine swapEngine = new DiscountingSwapEngine(rhTermStructure); swap.setPricingEngine(swapEngine); double fixedATMRate = swap.fairRate(); double fixedOTMRate = fixedATMRate * 1.2; double fixedITMRate = fixedATMRate * 0.8; VanillaSwap atmSwap = new VanillaSwap( VanillaSwap.Type.Payer, 1000.0, fixedSchedule, fixedATMRate, fixedLegDayCounter, floatSchedule, indexSixMonths, 0.0, indexSixMonths.dayCounter()); VanillaSwap otmSwap = new VanillaSwap( VanillaSwap.Type.Payer, 1000.0, fixedSchedule, fixedOTMRate, fixedLegDayCounter, floatSchedule, indexSixMonths, 0.0, indexSixMonths.dayCounter()); VanillaSwap itmSwap = new VanillaSwap( VanillaSwap.Type.Payer, 1000.0, fixedSchedule, fixedITMRate, fixedLegDayCounter, floatSchedule, indexSixMonths, 0.0, indexSixMonths.dayCounter()); atmSwap.setPricingEngine(swapEngine); otmSwap.setPricingEngine(swapEngine); itmSwap.setPricingEngine(swapEngine); // defining the swaptions to be used in model calibration PeriodVector swaptionMaturities = new PeriodVector(); swaptionMaturities.Add(new Period(1, TimeUnit.Years)); swaptionMaturities.Add(new Period(2, TimeUnit.Years)); swaptionMaturities.Add(new Period(3, TimeUnit.Years)); swaptionMaturities.Add(new Period(4, TimeUnit.Years)); swaptionMaturities.Add(new Period(5, TimeUnit.Years)); CalibrationHelperVector swaptions = new CalibrationHelperVector(); // List of times that have to be included in the timegrid DoubleVector times = new DoubleVector(); for (int i = 0; i < numRows; i++) { int j = numCols - i - 1; // 1x5, 2x4, 3x3, 4x2, 5x1 int k = i * numCols + j; Quote vol = new SimpleQuote(swaptionVols[k]); SwaptionHelper helper = new SwaptionHelper( swaptionMaturities[i], new Period(swapLengths[j], TimeUnit.Years), new QuoteHandle(vol), indexSixMonths, indexSixMonths.tenor(), indexSixMonths.dayCounter(), indexSixMonths.dayCounter(), rhTermStructure); swaptions.Add(helper); times.AddRange(helper.times()); } // Building time-grid TimeGrid grid = new TimeGrid(times, 30); // defining the models // G2 modelG2 = new G2(rhTermStructure)); HullWhite modelHW = new HullWhite(rhTermStructure); HullWhite modelHW2 = new HullWhite(rhTermStructure); BlackKarasinski modelBK = new BlackKarasinski(rhTermStructure); // model calibrations // Console.WriteLine( "G2 (analytic formulae) calibration" ); // for (int i=0; i<swaptions.Count; i++) // NQuantLibc.as_black_helper(swaptions[i]).setPricingEngine( // new G2SwaptionEngine( modelG2, 6.0, 16 ) ); // // calibrateModel( modelG2, swaptions, 0.05); // Console.WriteLine( "calibrated to:" ); // Console.WriteLine( "a = " + modelG2.parameters()[0] ); // Console.WriteLine( "sigma = " + modelG2.parameters()[1] ); // Console.WriteLine( "b = " + modelG2.parameters()[2] ); // Console.WriteLine( "eta = " + modelG2.parameters()[3] ); // Console.WriteLine( "rho = " + modelG2.parameters()[4] ); Console.WriteLine("Hull-White (analytic formulae) calibration"); for (int i = 0; i < swaptions.Count; i++) { NQuantLibc.as_black_helper(swaptions[i]).setPricingEngine( new JamshidianSwaptionEngine(modelHW)); } calibrateModel(modelHW, swaptions, 0.05); // Console.WriteLine( "calibrated to:" ); // Console.WriteLine( "a = " + modelHW.parameters()[0] ); // Console.WriteLine( "sigma = " + modelHW.parameters()[1] ); Console.WriteLine("Hull-White (numerical) calibration"); for (int i = 0; i < swaptions.Count; i++) { NQuantLibc.as_black_helper(swaptions[i]).setPricingEngine( new TreeSwaptionEngine(modelHW2, grid)); } calibrateModel(modelHW2, swaptions, 0.05); // std::cout << "calibrated to:\n" // << "a = " << modelHW2->params()[0] << ", " // << "sigma = " << modelHW2->params()[1] // << std::endl << std::endl; Console.WriteLine("Black-Karasinski (numerical) calibration"); for (int i = 0; i < swaptions.Count; i++) { NQuantLibc.as_black_helper(swaptions[i]).setPricingEngine( new TreeSwaptionEngine(modelBK, grid)); } calibrateModel(modelBK, swaptions, 0.05); // std::cout << "calibrated to:\n" // << "a = " << modelBK->params()[0] << ", " // << "sigma = " << modelBK->params()[1] // << std::endl << std::endl; // ATM Bermudan swaption pricing Console.WriteLine("Payer bermudan swaption struck at {0} (ATM)", fixedATMRate); DateVector bermudanDates = new DateVector(); Schedule schedule = new Schedule(startDate, maturity, new Period(3, TimeUnit.Months), calendar, BusinessDayConvention.Following, BusinessDayConvention.Following, DateGeneration.Rule.Forward, false); for (uint i = 0; i < schedule.size(); i++) { bermudanDates.Add(schedule.date(i)); } Exercise bermudaExercise = new BermudanExercise(bermudanDates); Swaption bermudanSwaption = new Swaption(atmSwap, bermudaExercise); bermudanSwaption.setPricingEngine( new TreeSwaptionEngine(modelHW, 50)); Console.WriteLine("HW: " + bermudanSwaption.NPV()); bermudanSwaption.setPricingEngine( new TreeSwaptionEngine(modelHW2, 50)); Console.WriteLine("HW (num): " + bermudanSwaption.NPV()); bermudanSwaption.setPricingEngine( new TreeSwaptionEngine(modelBK, 50)); Console.WriteLine("BK (num): " + bermudanSwaption.NPV()); DateTime endTime = DateTime.Now; TimeSpan delta = endTime - startTime; Console.WriteLine(); Console.WriteLine("Run completed in {0} s", delta.TotalSeconds); Console.WriteLine(); }
public void consistency() { // check inflation leg vs calculation directly from inflation TS CommonVars common = new CommonVars(); // ZeroInflationSwap aka CPISwap CPISwap.Type type = CPISwap.Type.Payer; double nominal = 1000000.0; bool subtractInflationNominal = true; // float+spread leg double spread = 0.0; DayCounter floatDayCount = new Actual365Fixed(); BusinessDayConvention floatPaymentConvention = BusinessDayConvention.ModifiedFollowing; int fixingDays = 0; IborIndex floatIndex = new GBPLibor(new Period(6, TimeUnit.Months), common.nominalUK); // fixed x inflation leg double fixedRate = 0.1; //1% would be 0.01 double baseCPI = 206.1; // would be 206.13871 if we were interpolating DayCounter fixedDayCount = new Actual365Fixed(); BusinessDayConvention fixedPaymentConvention = BusinessDayConvention.ModifiedFollowing; Calendar fixedPaymentCalendar = new UnitedKingdom(); ZeroInflationIndex fixedIndex = common.ii; Period contractObservationLag = common.contractObservationLag; InterpolationType observationInterpolation = common.contractObservationInterpolation; // set the schedules Date startDate = new Date(2, Month.October, 2007); Date endDate = new Date(2, Month.October, 2052); Schedule floatSchedule = new MakeSchedule().from(startDate).to(endDate) .withTenor(new Period(6, TimeUnit.Months)) .withCalendar(new UnitedKingdom()) .withConvention(floatPaymentConvention) .backwards().value(); Schedule fixedSchedule = new MakeSchedule().from(startDate).to(endDate) .withTenor(new Period(6, TimeUnit.Months)) .withCalendar(new UnitedKingdom()) .withConvention(BusinessDayConvention.Unadjusted) .backwards().value(); CPISwap zisV = new CPISwap(type, nominal, subtractInflationNominal, spread, floatDayCount, floatSchedule, floatPaymentConvention, fixingDays, floatIndex, fixedRate, baseCPI, fixedDayCount, fixedSchedule, fixedPaymentConvention, contractObservationLag, fixedIndex, observationInterpolation); Date asofDate = Settings.evaluationDate(); double[] floatFix = { 0.06255, 0.05975, 0.0637, 0.018425, 0.0073438, -1, -1 }; double[] cpiFix = { 211.4, 217.2, 211.4, 213.4, -2, -2 }; for (int i = 0; i < floatSchedule.Count; i++) { if (floatSchedule[i] < common.evaluationDate) { floatIndex.addFixing(floatSchedule[i], floatFix[i], true);//true=overwrite } CPICoupon zic = zisV.cpiLeg()[i] as CPICoupon; if (zic != null) { if (zic.fixingDate() < (common.evaluationDate - new Period(1, TimeUnit.Months))) { fixedIndex.addFixing(zic.fixingDate(), cpiFix[i], true); } } } // simple structure so simple pricing engine - most work done by index DiscountingSwapEngine dse = new DiscountingSwapEngine(common.nominalUK); zisV.setPricingEngine(dse); // get float+spread & fixed*inflation leg prices separately double testInfLegNPV = 0.0; double diff; for (int i = 0; i < zisV.leg(0).Count; i++) { Date zicPayDate = (zisV.leg(0))[i].date(); if (zicPayDate > asofDate) { testInfLegNPV += (zisV.leg(0))[i].amount() * common.nominalUK.link.discount(zicPayDate); } CPICoupon zicV = zisV.cpiLeg()[i] as CPICoupon; if (zicV != null) { diff = Math.Abs(zicV.rate() - (fixedRate * (zicV.indexFixing() / baseCPI))); QAssert.IsTrue(diff < 1e-8, "failed " + i + "th coupon reconstruction as " + (fixedRate * (zicV.indexFixing() / baseCPI)) + " vs rate = " + zicV.rate() + ", with difference: " + diff); } } double error = Math.Abs(testInfLegNPV - zisV.legNPV(0).Value); QAssert.IsTrue(error < 1e-5, "failed manual inf leg NPV calc vs pricing engine: " + testInfLegNPV + " vs " + zisV.legNPV(0)); diff = Math.Abs(1 - zisV.NPV() / 4191660.0); #if QL_USE_INDEXED_COUPON double max_diff = 1e-5; #else double max_diff = 3e-5; #endif QAssert.IsTrue(diff < max_diff, "failed stored consistency value test, ratio = " + diff); // remove circular refernce common.hcpi.linkTo(null); }
internal static global::System.Runtime.InteropServices.HandleRef getCPtr(DiscountingSwapEngine obj) { return((obj == null) ? new global::System.Runtime.InteropServices.HandleRef(null, global::System.IntPtr.Zero) : obj.swigCPtr); }
static void Main(string[] args) { DateTime timer = DateTime.Now; /********************* *** MARKET DATA *** *********************/ Calendar calendar = new TARGET(); Date settlementDate = new Date(22, Month.September, 2004); // must be a business day settlementDate = calendar.adjust(settlementDate); int fixingDays = 2; Date todaysDate = calendar.advance(settlementDate, -fixingDays, TimeUnit.Days); // nothing to do with Date::todaysDate Settings.setEvaluationDate(todaysDate); todaysDate = Settings.evaluationDate(); Console.WriteLine("Today: {0}, {1}", todaysDate.DayOfWeek, todaysDate); Console.WriteLine("Settlement date: {0}, {1}", settlementDate.DayOfWeek, settlementDate); // deposits double d1wQuote = 0.0382; double d1mQuote = 0.0372; double d3mQuote = 0.0363; double d6mQuote = 0.0353; double d9mQuote = 0.0348; double d1yQuote = 0.0345; // FRAs double fra3x6Quote = 0.037125; double fra6x9Quote = 0.037125; double fra6x12Quote = 0.037125; // futures double fut1Quote = 96.2875; double fut2Quote = 96.7875; double fut3Quote = 96.9875; double fut4Quote = 96.6875; double fut5Quote = 96.4875; double fut6Quote = 96.3875; double fut7Quote = 96.2875; double fut8Quote = 96.0875; // swaps double s2yQuote = 0.037125; double s3yQuote = 0.0398; double s5yQuote = 0.0443; double s10yQuote = 0.05165; double s15yQuote = 0.055175; /******************** *** QUOTES *** ********************/ // SimpleQuote stores a value which can be manually changed; // other Quote subclasses could read the value from a database // or some kind of data feed. // deposits Quote d1wRate = new SimpleQuote(d1wQuote); Quote d1mRate = new SimpleQuote(d1mQuote); Quote d3mRate = new SimpleQuote(d3mQuote); Quote d6mRate = new SimpleQuote(d6mQuote); Quote d9mRate = new SimpleQuote(d9mQuote); Quote d1yRate = new SimpleQuote(d1yQuote); // FRAs Quote fra3x6Rate = new SimpleQuote(fra3x6Quote); Quote fra6x9Rate = new SimpleQuote(fra6x9Quote); Quote fra6x12Rate = new SimpleQuote(fra6x12Quote); // futures Quote fut1Price = new SimpleQuote(fut1Quote); Quote fut2Price = new SimpleQuote(fut2Quote); Quote fut3Price = new SimpleQuote(fut3Quote); Quote fut4Price = new SimpleQuote(fut4Quote); Quote fut5Price = new SimpleQuote(fut5Quote); Quote fut6Price = new SimpleQuote(fut6Quote); Quote fut7Price = new SimpleQuote(fut7Quote); Quote fut8Price = new SimpleQuote(fut8Quote); // swaps Quote s2yRate = new SimpleQuote(s2yQuote); Quote s3yRate = new SimpleQuote(s3yQuote); Quote s5yRate = new SimpleQuote(s5yQuote); Quote s10yRate = new SimpleQuote(s10yQuote); Quote s15yRate = new SimpleQuote(s15yQuote); /********************* *** RATE HELPERS *** *********************/ // RateHelpers are built from the above quotes together with // other instrument dependant infos. Quotes are passed in // relinkable handles which could be relinked to some other // data source later. // deposits DayCounter depositDayCounter = new Actual360(); RateHelper d1w = new DepositRateHelper(new Handle <Quote>(d1wRate), new Period(1, TimeUnit.Weeks), fixingDays, calendar, BusinessDayConvention.ModifiedFollowing, true, depositDayCounter); RateHelper d1m = new DepositRateHelper(new Handle <Quote>(d1mRate), new Period(1, TimeUnit.Months), fixingDays, calendar, BusinessDayConvention.ModifiedFollowing, true, depositDayCounter); RateHelper d3m = new DepositRateHelper(new Handle <Quote>(d3mRate), new Period(3, TimeUnit.Months), fixingDays, calendar, BusinessDayConvention.ModifiedFollowing, true, depositDayCounter); RateHelper d6m = new DepositRateHelper(new Handle <Quote>(d6mRate), new Period(6, TimeUnit.Months), fixingDays, calendar, BusinessDayConvention.ModifiedFollowing, true, depositDayCounter); RateHelper d9m = new DepositRateHelper(new Handle <Quote>(d9mRate), new Period(9, TimeUnit.Months), fixingDays, calendar, BusinessDayConvention.ModifiedFollowing, true, depositDayCounter); RateHelper d1y = new DepositRateHelper(new Handle <Quote>(d1yRate), new Period(1, TimeUnit.Years), fixingDays, calendar, BusinessDayConvention.ModifiedFollowing, true, depositDayCounter); // setup FRAs RateHelper fra3x6 = new FraRateHelper(new Handle <Quote>(fra3x6Rate), 3, 6, fixingDays, calendar, BusinessDayConvention.ModifiedFollowing, true, depositDayCounter); RateHelper fra6x9 = new FraRateHelper(new Handle <Quote>(fra6x9Rate), 6, 9, fixingDays, calendar, BusinessDayConvention.ModifiedFollowing, true, depositDayCounter); RateHelper fra6x12 = new FraRateHelper(new Handle <Quote>(fra6x12Rate), 6, 12, fixingDays, calendar, BusinessDayConvention.ModifiedFollowing, true, depositDayCounter); // setup futures // Handle<Quote> convexityAdjustment = new Handle<Quote>(new SimpleQuote(0.0)); int futMonths = 3; Date imm = IMM.nextDate(settlementDate); RateHelper fut1 = new FuturesRateHelper(new Handle <Quote>(fut1Price), imm, futMonths, calendar, BusinessDayConvention.ModifiedFollowing, true, depositDayCounter); imm = IMM.nextDate(imm + 1); RateHelper fut2 = new FuturesRateHelper(new Handle <Quote>(fut2Price), imm, futMonths, calendar, BusinessDayConvention.ModifiedFollowing, true, depositDayCounter); imm = IMM.nextDate(imm + 1); RateHelper fut3 = new FuturesRateHelper(new Handle <Quote>(fut3Price), imm, futMonths, calendar, BusinessDayConvention.ModifiedFollowing, true, depositDayCounter); imm = IMM.nextDate(imm + 1); RateHelper fut4 = new FuturesRateHelper(new Handle <Quote>(fut4Price), imm, futMonths, calendar, BusinessDayConvention.ModifiedFollowing, true, depositDayCounter); imm = IMM.nextDate(imm + 1); RateHelper fut5 = new FuturesRateHelper(new Handle <Quote>(fut5Price), imm, futMonths, calendar, BusinessDayConvention.ModifiedFollowing, true, depositDayCounter); imm = IMM.nextDate(imm + 1); RateHelper fut6 = new FuturesRateHelper(new Handle <Quote>(fut6Price), imm, futMonths, calendar, BusinessDayConvention.ModifiedFollowing, true, depositDayCounter); imm = IMM.nextDate(imm + 1); RateHelper fut7 = new FuturesRateHelper(new Handle <Quote>(fut7Price), imm, futMonths, calendar, BusinessDayConvention.ModifiedFollowing, true, depositDayCounter); imm = IMM.nextDate(imm + 1); RateHelper fut8 = new FuturesRateHelper(new Handle <Quote>(fut8Price), imm, futMonths, calendar, BusinessDayConvention.ModifiedFollowing, true, depositDayCounter); // setup swaps Frequency swFixedLegFrequency = Frequency.Annual; BusinessDayConvention swFixedLegConvention = BusinessDayConvention.Unadjusted; DayCounter swFixedLegDayCounter = new Thirty360(Thirty360.Thirty360Convention.European); IborIndex swFloatingLegIndex = new Euribor6M(); RateHelper s2y = new SwapRateHelper(new Handle <Quote>(s2yRate), new Period(2, TimeUnit.Years), calendar, swFixedLegFrequency, swFixedLegConvention, swFixedLegDayCounter, swFloatingLegIndex); RateHelper s3y = new SwapRateHelper(new Handle <Quote>(s3yRate), new Period(3, TimeUnit.Years), calendar, swFixedLegFrequency, swFixedLegConvention, swFixedLegDayCounter, swFloatingLegIndex); RateHelper s5y = new SwapRateHelper(new Handle <Quote>(s5yRate), new Period(5, TimeUnit.Years), calendar, swFixedLegFrequency, swFixedLegConvention, swFixedLegDayCounter, swFloatingLegIndex); RateHelper s10y = new SwapRateHelper(new Handle <Quote>(s10yRate), new Period(10, TimeUnit.Years), calendar, swFixedLegFrequency, swFixedLegConvention, swFixedLegDayCounter, swFloatingLegIndex); RateHelper s15y = new SwapRateHelper(new Handle <Quote>(s15yRate), new Period(15, TimeUnit.Years), calendar, swFixedLegFrequency, swFixedLegConvention, swFixedLegDayCounter, swFloatingLegIndex); /********************* ** CURVE BUILDING ** *********************/ // Any DayCounter would be fine. // ActualActual::ISDA ensures that 30 years is 30.0 DayCounter termStructureDayCounter = new ActualActual(ActualActual.Convention.ISDA); double tolerance = 1.0e-15; // A depo-swap curve List <RateHelper> depoSwapInstruments = new List <RateHelper>(); depoSwapInstruments.Add(d1w); depoSwapInstruments.Add(d1m); depoSwapInstruments.Add(d3m); depoSwapInstruments.Add(d6m); depoSwapInstruments.Add(d9m); depoSwapInstruments.Add(d1y); depoSwapInstruments.Add(s2y); depoSwapInstruments.Add(s3y); depoSwapInstruments.Add(s5y); depoSwapInstruments.Add(s10y); depoSwapInstruments.Add(s15y); YieldTermStructure depoSwapTermStructure = new PiecewiseYieldCurve <Discount, LogLinear>( settlementDate, depoSwapInstruments, termStructureDayCounter, new List <Handle <Quote> >(), new List <Date>(), tolerance); // A depo-futures-swap curve List <RateHelper> depoFutSwapInstruments = new List <RateHelper>(); depoFutSwapInstruments.Add(d1w); depoFutSwapInstruments.Add(d1m); depoFutSwapInstruments.Add(fut1); depoFutSwapInstruments.Add(fut2); depoFutSwapInstruments.Add(fut3); depoFutSwapInstruments.Add(fut4); depoFutSwapInstruments.Add(fut5); depoFutSwapInstruments.Add(fut6); depoFutSwapInstruments.Add(fut7); depoFutSwapInstruments.Add(fut8); depoFutSwapInstruments.Add(s3y); depoFutSwapInstruments.Add(s5y); depoFutSwapInstruments.Add(s10y); depoFutSwapInstruments.Add(s15y); YieldTermStructure depoFutSwapTermStructure = new PiecewiseYieldCurve <Discount, LogLinear>( settlementDate, depoFutSwapInstruments, termStructureDayCounter, new List <Handle <Quote> >(), new List <Date>(), tolerance); // A depo-FRA-swap curve List <RateHelper> depoFRASwapInstruments = new List <RateHelper>(); depoFRASwapInstruments.Add(d1w); depoFRASwapInstruments.Add(d1m); depoFRASwapInstruments.Add(d3m); depoFRASwapInstruments.Add(fra3x6); depoFRASwapInstruments.Add(fra6x9); depoFRASwapInstruments.Add(fra6x12); depoFRASwapInstruments.Add(s2y); depoFRASwapInstruments.Add(s3y); depoFRASwapInstruments.Add(s5y); depoFRASwapInstruments.Add(s10y); depoFRASwapInstruments.Add(s15y); YieldTermStructure depoFRASwapTermStructure = new PiecewiseYieldCurve <Discount, LogLinear>( settlementDate, depoFRASwapInstruments, termStructureDayCounter, new List <Handle <Quote> >(), new List <Date>(), tolerance); // Term structures that will be used for pricing: // the one used for discounting cash flows RelinkableHandle <YieldTermStructure> discountingTermStructure = new RelinkableHandle <YieldTermStructure>(); // the one used for forward rate forecasting RelinkableHandle <YieldTermStructure> forecastingTermStructure = new RelinkableHandle <YieldTermStructure>(); /********************* * SWAPS TO BE PRICED * **********************/ // constant nominal 1,000,000 Euro double nominal = 1000000.0; // fixed leg Frequency fixedLegFrequency = Frequency.Annual; BusinessDayConvention fixedLegConvention = BusinessDayConvention.Unadjusted; BusinessDayConvention floatingLegConvention = BusinessDayConvention.ModifiedFollowing; DayCounter fixedLegDayCounter = new Thirty360(Thirty360.Thirty360Convention.European); double fixedRate = 0.04; DayCounter floatingLegDayCounter = new Actual360(); // floating leg Frequency floatingLegFrequency = Frequency.Semiannual; IborIndex euriborIndex = new Euribor6M(forecastingTermStructure); double spread = 0.0; int lenghtInYears = 5; VanillaSwap.Type swapType = VanillaSwap.Type.Payer; Date maturity = settlementDate + new Period(lenghtInYears, TimeUnit.Years); Schedule fixedSchedule = new Schedule(settlementDate, maturity, new Period(fixedLegFrequency), calendar, fixedLegConvention, fixedLegConvention, DateGeneration.Rule.Forward, false); Schedule floatSchedule = new Schedule(settlementDate, maturity, new Period(floatingLegFrequency), calendar, floatingLegConvention, floatingLegConvention, DateGeneration.Rule.Forward, false); VanillaSwap spot5YearSwap = new VanillaSwap(swapType, nominal, fixedSchedule, fixedRate, fixedLegDayCounter, floatSchedule, euriborIndex, spread, floatingLegDayCounter); Date fwdStart = calendar.advance(settlementDate, 1, TimeUnit.Years); Date fwdMaturity = fwdStart + new Period(lenghtInYears, TimeUnit.Years); Schedule fwdFixedSchedule = new Schedule(fwdStart, fwdMaturity, new Period(fixedLegFrequency), calendar, fixedLegConvention, fixedLegConvention, DateGeneration.Rule.Forward, false); Schedule fwdFloatSchedule = new Schedule(fwdStart, fwdMaturity, new Period(floatingLegFrequency), calendar, floatingLegConvention, floatingLegConvention, DateGeneration.Rule.Forward, false); VanillaSwap oneYearForward5YearSwap = new VanillaSwap(swapType, nominal, fwdFixedSchedule, fixedRate, fixedLegDayCounter, fwdFloatSchedule, euriborIndex, spread, floatingLegDayCounter); /*************** * SWAP PRICING * ****************/ // utilities for reporting List <string> headers = new List <string>(); headers.Add("term structure"); headers.Add("net present value"); headers.Add("fair spread"); headers.Add("fair fixed rate"); string separator = " | "; int width = headers[0].Length + separator.Length + headers[1].Length + separator.Length + headers[2].Length + separator.Length + headers[3].Length + separator.Length - 1; string rule = string.Format("").PadLeft(width, '-'), dblrule = string.Format("").PadLeft(width, '='); string tab = string.Format("").PadLeft(8, ' '); // calculations Console.WriteLine(dblrule); Console.WriteLine("5-year market swap-rate = {0:0.00%}", s5yRate.value()); Console.WriteLine(dblrule); Console.WriteLine(tab + "5-years swap paying {0:0.00%}", fixedRate); Console.WriteLine(headers[0] + separator + headers[1] + separator + headers[2] + separator + headers[3] + separator); Console.WriteLine(rule); double NPV; double fairRate; double fairSpread; IPricingEngine swapEngine = new DiscountingSwapEngine(discountingTermStructure); spot5YearSwap.setPricingEngine(swapEngine); oneYearForward5YearSwap.setPricingEngine(swapEngine); // Of course, you're not forced to really use different curves forecastingTermStructure.linkTo(depoSwapTermStructure); discountingTermStructure.linkTo(depoSwapTermStructure); NPV = spot5YearSwap.NPV(); fairSpread = spot5YearSwap.fairSpread(); fairRate = spot5YearSwap.fairRate(); Console.Write("{0," + headers[0].Length + ":0.00}" + separator, "depo-swap"); Console.Write("{0," + headers[1].Length + ":0.00}" + separator, NPV); Console.Write("{0," + headers[2].Length + ":0.00%}" + separator, fairSpread); Console.WriteLine("{0," + headers[3].Length + ":0.00%}" + separator, fairRate); // let's check that the 5 years swap has been correctly re-priced if (!(Math.Abs(fairRate - s5yQuote) < 1e-8)) { throw new ApplicationException("5-years swap mispriced by " + Math.Abs(fairRate - s5yQuote)); } forecastingTermStructure.linkTo(depoFutSwapTermStructure); discountingTermStructure.linkTo(depoFutSwapTermStructure); NPV = spot5YearSwap.NPV(); fairSpread = spot5YearSwap.fairSpread(); fairRate = spot5YearSwap.fairRate(); Console.Write("{0," + headers[0].Length + ":0.00}" + separator, "depo-fut-swap"); Console.Write("{0," + headers[1].Length + ":0.00}" + separator, NPV); Console.Write("{0," + headers[2].Length + ":0.00%}" + separator, fairSpread); Console.WriteLine("{0," + headers[3].Length + ":0.00%}" + separator, fairRate); if (!(Math.Abs(fairRate - s5yQuote) < 1e-8)) { throw new ApplicationException("5-years swap mispriced by " + Math.Abs(fairRate - s5yQuote)); } forecastingTermStructure.linkTo(depoFRASwapTermStructure); discountingTermStructure.linkTo(depoFRASwapTermStructure); NPV = spot5YearSwap.NPV(); fairSpread = spot5YearSwap.fairSpread(); fairRate = spot5YearSwap.fairRate(); Console.Write("{0," + headers[0].Length + ":0.00}" + separator, "depo-FRA-swap"); Console.Write("{0," + headers[1].Length + ":0.00}" + separator, NPV); Console.Write("{0," + headers[2].Length + ":0.00%}" + separator, fairSpread); Console.WriteLine("{0," + headers[3].Length + ":0.00%}" + separator, fairRate); if (!(Math.Abs(fairRate - s5yQuote) < 1e-8)) { throw new ApplicationException("5-years swap mispriced by " + Math.Abs(fairRate - s5yQuote)); } Console.WriteLine(rule); // now let's price the 1Y forward 5Y swap Console.WriteLine(tab + "5-years, 1-year forward swap paying {0:0.00%}", fixedRate); Console.WriteLine(headers[0] + separator + headers[1] + separator + headers[2] + separator + headers[3] + separator); Console.WriteLine(rule); forecastingTermStructure.linkTo(depoSwapTermStructure); discountingTermStructure.linkTo(depoSwapTermStructure); NPV = oneYearForward5YearSwap.NPV(); fairSpread = oneYearForward5YearSwap.fairSpread(); fairRate = oneYearForward5YearSwap.fairRate(); Console.Write("{0," + headers[0].Length + ":0.00}" + separator, "depo-swap"); Console.Write("{0," + headers[1].Length + ":0.00}" + separator, NPV); Console.Write("{0," + headers[2].Length + ":0.00%}" + separator, fairSpread); Console.WriteLine("{0," + headers[3].Length + ":0.00%}" + separator, fairRate); forecastingTermStructure.linkTo(depoFutSwapTermStructure); discountingTermStructure.linkTo(depoFutSwapTermStructure); NPV = oneYearForward5YearSwap.NPV(); fairSpread = oneYearForward5YearSwap.fairSpread(); fairRate = oneYearForward5YearSwap.fairRate(); Console.Write("{0," + headers[0].Length + ":0.00}" + separator, "depo-fut-swap"); Console.Write("{0," + headers[1].Length + ":0.00}" + separator, NPV); Console.Write("{0," + headers[2].Length + ":0.00%}" + separator, fairSpread); Console.WriteLine("{0," + headers[3].Length + ":0.00%}" + separator, fairRate); forecastingTermStructure.linkTo(depoFRASwapTermStructure); discountingTermStructure.linkTo(depoFRASwapTermStructure); NPV = oneYearForward5YearSwap.NPV(); fairSpread = oneYearForward5YearSwap.fairSpread(); fairRate = oneYearForward5YearSwap.fairRate(); Console.Write("{0," + headers[0].Length + ":0.00}" + separator, "depo-FRA-swap"); Console.Write("{0," + headers[1].Length + ":0.00}" + separator, NPV); Console.Write("{0," + headers[2].Length + ":0.00%}" + separator, fairSpread); Console.WriteLine("{0," + headers[3].Length + ":0.00%}" + separator, fairRate); // now let's say that the 5-years swap rate goes up to 4.60%. // A smarter market element--say, connected to a data source-- would // notice the change itself. Since we're using SimpleQuotes, // we'll have to change the value manually--which forces us to // downcast the handle and use the SimpleQuote // interface. In any case, the point here is that a change in the // value contained in the Quote triggers a new bootstrapping // of the curve and a repricing of the swap. SimpleQuote fiveYearsRate = s5yRate as SimpleQuote; fiveYearsRate.setValue(0.0460); Console.WriteLine(dblrule); Console.WriteLine("5-year market swap-rate = {0:0.00%}", s5yRate.value()); Console.WriteLine(dblrule); Console.WriteLine(tab + "5-years swap paying {0:0.00%}", fixedRate); Console.WriteLine(headers[0] + separator + headers[1] + separator + headers[2] + separator + headers[3] + separator); Console.WriteLine(rule); // now get the updated results forecastingTermStructure.linkTo(depoSwapTermStructure); discountingTermStructure.linkTo(depoSwapTermStructure); NPV = spot5YearSwap.NPV(); fairSpread = spot5YearSwap.fairSpread(); fairRate = spot5YearSwap.fairRate(); Console.Write("{0," + headers[0].Length + ":0.00}" + separator, "depo-swap"); Console.Write("{0," + headers[1].Length + ":0.00}" + separator, NPV); Console.Write("{0," + headers[2].Length + ":0.00%}" + separator, fairSpread); Console.WriteLine("{0," + headers[3].Length + ":0.00%}" + separator, fairRate); if (!(Math.Abs(fairRate - s5yRate.value()) < 1e-8)) { throw new ApplicationException("5-years swap mispriced by " + Math.Abs(fairRate - s5yRate.value())); } forecastingTermStructure.linkTo(depoFutSwapTermStructure); discountingTermStructure.linkTo(depoFutSwapTermStructure); NPV = spot5YearSwap.NPV(); fairSpread = spot5YearSwap.fairSpread(); fairRate = spot5YearSwap.fairRate(); Console.Write("{0," + headers[0].Length + ":0.00}" + separator, "depo-fut-swap"); Console.Write("{0," + headers[1].Length + ":0.00}" + separator, NPV); Console.Write("{0," + headers[2].Length + ":0.00%}" + separator, fairSpread); Console.WriteLine("{0," + headers[3].Length + ":0.00%}" + separator, fairRate); if (!(Math.Abs(fairRate - s5yRate.value()) < 1e-8)) { throw new ApplicationException("5-years swap mispriced by " + Math.Abs(fairRate - s5yRate.value())); } forecastingTermStructure.linkTo(depoFRASwapTermStructure); discountingTermStructure.linkTo(depoFRASwapTermStructure); NPV = spot5YearSwap.NPV(); fairSpread = spot5YearSwap.fairSpread(); fairRate = spot5YearSwap.fairRate(); Console.Write("{0," + headers[0].Length + ":0.00}" + separator, "depo-FRA-swap"); Console.Write("{0," + headers[1].Length + ":0.00}" + separator, NPV); Console.Write("{0," + headers[2].Length + ":0.00%}" + separator, fairSpread); Console.WriteLine("{0," + headers[3].Length + ":0.00%}" + separator, fairRate); if (!(Math.Abs(fairRate - s5yRate.value()) < 1e-8)) { throw new ApplicationException("5-years swap mispriced by " + Math.Abs(fairRate - s5yRate.value())); } Console.WriteLine(rule); // the 1Y forward 5Y swap changes as well Console.WriteLine(tab + "5-years, 1-year forward swap paying {0:0.00%}", fixedRate); Console.WriteLine(headers[0] + separator + headers[1] + separator + headers[2] + separator + headers[3] + separator); Console.WriteLine(rule); forecastingTermStructure.linkTo(depoSwapTermStructure); discountingTermStructure.linkTo(depoSwapTermStructure); NPV = oneYearForward5YearSwap.NPV(); fairSpread = oneYearForward5YearSwap.fairSpread(); fairRate = oneYearForward5YearSwap.fairRate(); Console.Write("{0," + headers[0].Length + ":0.00}" + separator, "depo-swap"); Console.Write("{0," + headers[1].Length + ":0.00}" + separator, NPV); Console.Write("{0," + headers[2].Length + ":0.00%}" + separator, fairSpread); Console.WriteLine("{0," + headers[3].Length + ":0.00%}" + separator, fairRate); forecastingTermStructure.linkTo(depoFutSwapTermStructure); discountingTermStructure.linkTo(depoFutSwapTermStructure); NPV = oneYearForward5YearSwap.NPV(); fairSpread = oneYearForward5YearSwap.fairSpread(); fairRate = oneYearForward5YearSwap.fairRate(); Console.Write("{0," + headers[0].Length + ":0.00}" + separator, "depo-fut-swap"); Console.Write("{0," + headers[1].Length + ":0.00}" + separator, NPV); Console.Write("{0," + headers[2].Length + ":0.00%}" + separator, fairSpread); Console.WriteLine("{0," + headers[3].Length + ":0.00%}" + separator, fairRate); forecastingTermStructure.linkTo(depoFRASwapTermStructure); discountingTermStructure.linkTo(depoFRASwapTermStructure); NPV = oneYearForward5YearSwap.NPV(); fairSpread = oneYearForward5YearSwap.fairSpread(); fairRate = oneYearForward5YearSwap.fairRate(); Console.Write("{0," + headers[0].Length + ":0.00}" + separator, "depo-FRA-swap"); Console.Write("{0," + headers[1].Length + ":0.00}" + separator, NPV); Console.Write("{0," + headers[2].Length + ":0.00%}" + separator, fairSpread); Console.WriteLine("{0," + headers[3].Length + ":0.00%}" + separator, fairRate); Console.WriteLine(" \nRun completed in {0}", DateTime.Now - timer); Console.Write("Press any key to continue ..."); Console.ReadKey(); }
public void testYYTermStructure() { // Testing year-on-year inflation term structure... SavedSettings backup = new SavedSettings(); //IndexHistoryCleaner cleaner; // try the YY UK Calendar calendar = new UnitedKingdom(); BusinessDayConvention bdc = BusinessDayConvention.ModifiedFollowing; Date evaluationDate = new Date(13, Month.August, 2007); evaluationDate = calendar.adjust(evaluationDate); Settings.setEvaluationDate(evaluationDate); // fixing data Date from = new Date(1, Month.January, 2005); Date to = new Date(13, Month.August, 2007); Schedule rpiSchedule = new MakeSchedule().from(from).to(to) .withTenor(new Period(1, TimeUnit.Months)) .withCalendar(new UnitedKingdom()) .withConvention(BusinessDayConvention.ModifiedFollowing).value(); double[] fixData = { 189.9, 189.9, 189.6, 190.5, 191.6, 192.0, 192.2, 192.2, 192.6, 193.1, 193.3, 193.6, 194.1, 193.4, 194.2, 195.0, 196.5, 197.7, 198.5, 198.5, 199.2, 200.1, 200.4, 201.1, 202.7, 201.6, 203.1, 204.4, 205.4, 206.2, 207.3 }; RelinkableHandle <YoYInflationTermStructure> hy = new RelinkableHandle <YoYInflationTermStructure>(); bool interp = false; YYUKRPIr iir = new YYUKRPIr(interp, hy); for (int i = 0; i < fixData.Length; i++) { iir.addFixing(rpiSchedule[i], fixData[i]); } YieldTermStructure nominalTS = nominalTermStructure(); // now build the YoY inflation curve Datum[] yyData = { new Datum(new Date(13, Month.August, 2008), 2.95), new Datum(new Date(13, Month.August, 2009), 2.95), new Datum(new Date(13, Month.August, 2010), 2.93), new Datum(new Date(15, Month.August, 2011), 2.955), new Datum(new Date(13, Month.August, 2012), 2.945), new Datum(new Date(13, Month.August, 2013), 2.985), new Datum(new Date(13, Month.August, 2014), 3.01), new Datum(new Date(13, Month.August, 2015), 3.035), new Datum(new Date(13, Month.August, 2016), 3.055), // note that new Datum(new Date(13, Month.August, 2017), 3.075), // some dates will be on new Datum(new Date(13, Month.August, 2019), 3.105), // holidays but the payment new Datum(new Date(15, Month.August, 2022), 3.135), // calendar will roll them new Datum(new Date(13, Month.August, 2027), 3.155), new Datum(new Date(13, Month.August, 2032), 3.145), new Datum(new Date(13, Month.August, 2037), 3.145) }; Period observationLag = new Period(2, TimeUnit.Months); DayCounter dc = new Thirty360(); // now build the helpers ... List <BootstrapHelper <YoYInflationTermStructure> > helpers = makeHelpers(yyData, yyData.Length, iir, observationLag, calendar, bdc, dc); double baseYYRate = yyData[0].rate / 100.0; PiecewiseYoYInflationCurve <Linear> pYYTS = new PiecewiseYoYInflationCurve <Linear>( evaluationDate, calendar, dc, observationLag, iir.frequency(), iir.interpolated(), baseYYRate, new Handle <YieldTermStructure>(nominalTS), helpers); pYYTS.recalculate(); // validation // yoy swaps should reprice to zero // yy rates should not equal yySwap rates double eps = 0.000001; // usual swap engine Handle <YieldTermStructure> hTS = new Handle <YieldTermStructure>(nominalTS); IPricingEngine sppe = new DiscountingSwapEngine(hTS); // make sure that the index has the latest yoy term structure hy.linkTo(pYYTS); for (int j = 1; j < yyData.Length; j++) { from = nominalTS.referenceDate(); to = yyData[j].date; Schedule yoySchedule = new MakeSchedule().from(from).to(to) .withConvention(BusinessDayConvention.Unadjusted) // fixed leg gets calendar from .withCalendar(calendar) // schedule .withTenor(new Period(1, TimeUnit.Years)).value(); // .back YearOnYearInflationSwap yyS2 = new YearOnYearInflationSwap( YearOnYearInflationSwap.Type.Payer, 1000000.0, yoySchedule, //fixed schedule, but same as yoy yyData[j].rate / 100.0, dc, yoySchedule, iir, observationLag, 0.0, //spread on index dc, new UnitedKingdom()); yyS2.setPricingEngine(sppe); Assert.IsTrue(Math.Abs(yyS2.NPV()) < eps, "fresh yoy swap NPV!=0 from TS " + "swap quote for pt " + j + ", is " + yyData[j].rate / 100.0 + " vs YoY rate " + pYYTS.yoyRate(yyData[j].date - observationLag) + " at quote date " + (yyData[j].date - observationLag) + ", NPV of a fresh yoy swap is " + yyS2.NPV() + "\n fair rate " + yyS2.fairRate() + " payment " + yyS2.paymentConvention()); } int jj = 3; for (int k = 0; k < 14; k++) { from = nominalTS.referenceDate() - new Period(k, TimeUnit.Months); to = yyData[jj].date - new Period(k, TimeUnit.Months); Schedule yoySchedule = new MakeSchedule().from(from).to(to) .withConvention(BusinessDayConvention.Unadjusted) // fixed leg gets calendar from .withCalendar(calendar) // schedule .withTenor(new Period(1, TimeUnit.Years)) .value(); //backwards() YearOnYearInflationSwap yyS3 = new YearOnYearInflationSwap( YearOnYearInflationSwap.Type.Payer, 1000000.0, yoySchedule, //fixed schedule, but same as yoy yyData[jj].rate / 100.0, dc, yoySchedule, iir, observationLag, 0.0, //spread on index dc, new UnitedKingdom()); yyS3.setPricingEngine(sppe); Assert.IsTrue(Math.Abs(yyS3.NPV()) < 20000.0, "unexpected size of aged YoY swap, aged " + k + " months: YY aged NPV = " + yyS3.NPV() + ", legs " + yyS3.legNPV(0) + " and " + yyS3.legNPV(1) ); } // remove circular refernce hy.linkTo(new YoYInflationTermStructure()); }
public void testZeroTermStructure() { // Testing zero inflation term structure... SavedSettings backup = new SavedSettings(); // try the Zero UK Calendar calendar = new UnitedKingdom(); BusinessDayConvention bdc = BusinessDayConvention.ModifiedFollowing; Date evaluationDate = new Date(13, Month.August, 2007); evaluationDate = calendar.adjust(evaluationDate); Settings.setEvaluationDate(evaluationDate); // fixing data Date from = new Date(1, Month.January, 2005); Date to = new Date(13, Month.August, 2007); Schedule rpiSchedule = new MakeSchedule().from(from).to(to) .withTenor(new Period(1, TimeUnit.Months)) .withCalendar(new UnitedKingdom()) .withConvention(BusinessDayConvention.ModifiedFollowing) .value(); double[] fixData = { 189.9, 189.9, 189.6, 190.5, 191.6, 192.0, 192.2, 192.2, 192.6, 193.1, 193.3, 193.6, 194.1, 193.4, 194.2, 195.0, 196.5, 197.7, 198.5, 198.5, 199.2, 200.1, 200.4, 201.1, 202.7, 201.6, 203.1, 204.4, 205.4, 206.2, 207.3, 206.1, -999.0 }; RelinkableHandle <ZeroInflationTermStructure> hz = new RelinkableHandle <ZeroInflationTermStructure>(); bool interp = false; UKRPI iiUKRPI = new UKRPI(interp, hz); for (int i = 0; i < rpiSchedule.Count; i++) { iiUKRPI.addFixing(rpiSchedule[i], fixData[i]); } ZeroInflationIndex ii = iiUKRPI as ZeroInflationIndex; YieldTermStructure nominalTS = nominalTermStructure(); // now build the zero inflation curve Datum[] zcData = { new Datum(new Date(13, Month.August, 2008), 2.93), new Datum(new Date(13, Month.August, 2009), 2.95), new Datum(new Date(13, Month.August, 2010), 2.965), new Datum(new Date(15, Month.August, 2011), 2.98), new Datum(new Date(13, Month.August, 2012), 3.0), new Datum(new Date(13, Month.August, 2014), 3.06), new Datum(new Date(13, Month.August, 2017), 3.175), new Datum(new Date(13, Month.August, 2019), 3.243), new Datum(new Date(15, Month.August, 2022), 3.293), new Datum(new Date(14, Month.August, 2027), 3.338), new Datum(new Date(13, Month.August, 2032), 3.348), new Datum(new Date(15, Month.August, 2037), 3.348), new Datum(new Date(13, Month.August, 2047), 3.308), new Datum(new Date(13, Month.August, 2057), 3.228) }; Period observationLag = new Period(2, TimeUnit.Months); DayCounter dc = new Thirty360(); Frequency frequency = Frequency.Monthly; List <BootstrapHelper <ZeroInflationTermStructure> > helpers = makeHelpers(zcData, zcData.Length, ii, observationLag, calendar, bdc, dc); double baseZeroRate = zcData[0].rate / 100.0; PiecewiseZeroInflationCurve <Linear> pZITS = new PiecewiseZeroInflationCurve <Linear>( evaluationDate, calendar, dc, observationLag, frequency, ii.interpolated(), baseZeroRate, new Handle <YieldTermStructure>(nominalTS), helpers); pZITS.recalculate(); // first check that the zero rates on the curve match the data // and that the helpers give the correct impled rates const double eps = 0.00000001; bool forceLinearInterpolation = false; for (int i = 0; i < zcData.Length; i++) { Assert.IsTrue(Math.Abs(zcData[i].rate / 100.0 - pZITS.zeroRate(zcData[i].date, observationLag, forceLinearInterpolation)) < eps, "ZITS zeroRate != instrument " + pZITS.zeroRate(zcData[i].date, observationLag, forceLinearInterpolation) + " vs " + zcData[i].rate / 100.0 + " interpolation: " + ii.interpolated() + " forceLinearInterpolation " + forceLinearInterpolation); Assert.IsTrue(Math.Abs(helpers[i].impliedQuote() - zcData[i].rate / 100.0) < eps, "ZITS implied quote != instrument " + helpers[i].impliedQuote() + " vs " + zcData[i].rate / 100.0); } // now test the forecasting capability of the index. hz.linkTo(pZITS); from = hz.link.baseDate(); to = hz.link.maxDate() - new Period(1, TimeUnit.Months); // a bit of margin for adjustments Schedule testIndex = new MakeSchedule().from(from).to(to) .withTenor(new Period(1, TimeUnit.Months)) .withCalendar(new UnitedKingdom()) .withConvention(BusinessDayConvention.ModifiedFollowing).value(); // we are testing UKRPI which is not interpolated Date bd = hz.link.baseDate(); double bf = ii.fixing(bd); for (int i = 0; i < testIndex.Count; i++) { Date d = testIndex[i]; double z = hz.link.zeroRate(d, new Period(0, TimeUnit.Days)); double t = hz.link.dayCounter().yearFraction(bd, d); if (!ii.interpolated()) // because fixing constant over period { t = hz.link.dayCounter().yearFraction(bd, Utils.inflationPeriod(d, ii.frequency()).Key); } double calc = bf * Math.Pow(1 + z, t); if (t <= 0) { calc = ii.fixing(d, false); // still historical } if (Math.Abs(calc - ii.fixing(d, true)) / 10000.0 > eps) { Assert.Fail("ZC index does not forecast correctly for date " + d + " from base date " + bd + " with fixing " + bf + ", correct: " + calc + ", fix: " + ii.fixing(d, true) + ", t " + t); } } //=========================================================================================== // Test zero-inflation-indexed (i.e. cpi ratio) cashflow // just ordinary indexed cashflow with a zero inflation index Date baseDate = new Date(1, Month.January, 2006); Date fixDate = new Date(1, Month.August, 2014); Date payDate = new UnitedKingdom().adjust(fixDate + new Period(3, TimeUnit.Months), BusinessDayConvention.ModifiedFollowing); Index ind = ii as Index; Utils.QL_REQUIRE(ind != null, () => "dynamic_pointer_cast to Index from InflationIndex failed"); double notional = 1000000.0;//1m IndexedCashFlow iicf = new IndexedCashFlow(notional, ind, baseDate, fixDate, payDate); double correctIndexed = ii.fixing(iicf.fixingDate()) / ii.fixing(iicf.baseDate()); double calculatedIndexed = iicf.amount() / iicf.notional(); Assert.IsTrue(Math.Abs(correctIndexed - calculatedIndexed) < eps, "IndexedCashFlow indexing wrong: " + calculatedIndexed + " vs correct = " + correctIndexed); //=========================================================================================== // Test zero coupon swap // first make one ... ZeroInflationIndex zii = ii as ZeroInflationIndex; Utils.QL_REQUIRE(zii != null, () => "dynamic_pointer_cast to ZeroInflationIndex from UKRPI failed"); ZeroCouponInflationSwap nzcis = new ZeroCouponInflationSwap(ZeroCouponInflationSwap.Type.Payer, 1000000.0, evaluationDate, zcData[6].date, // end date = maturity calendar, bdc, dc, zcData[6].rate / 100.0, // fixed rate zii, observationLag); // N.B. no coupon pricer because it is not a coupon, effect of inflation curve via // inflation curve attached to the inflation index. Handle <YieldTermStructure> hTS = new Handle <YieldTermStructure>(nominalTS); IPricingEngine sppe = new DiscountingSwapEngine(hTS); nzcis.setPricingEngine(sppe); // ... and price it, should be zero Assert.IsTrue(Math.Abs(nzcis.NPV()) < 0.00001, "ZCIS does not reprice to zero " + nzcis.NPV() + evaluationDate + " to " + zcData[6].date + " becoming " + nzcis.maturityDate() + " rate " + zcData[6].rate + " fixed leg " + nzcis.legNPV(0) + " indexed-predicted inflated leg " + nzcis.legNPV(1) + " discount " + nominalTS.discount(nzcis.maturityDate())); //=========================================================================================== // Test multiplicative seasonality in price // //Seasonality factors NOT normalized //and UKRPI is not interpolated Date trueBaseDate = Utils.inflationPeriod(hz.link.baseDate(), ii.frequency()).Value; Date seasonallityBaseDate = new Date(31, Month.January, trueBaseDate.year()); List <double> seasonalityFactors = new List <double>(12); seasonalityFactors.Add(1.003245); seasonalityFactors.Add(1.000000); seasonalityFactors.Add(0.999715); seasonalityFactors.Add(1.000495); seasonalityFactors.Add(1.000929); seasonalityFactors.Add(0.998687); seasonalityFactors.Add(0.995949); seasonalityFactors.Add(0.994682); seasonalityFactors.Add(0.995949); seasonalityFactors.Add(1.000519); seasonalityFactors.Add(1.003705); seasonalityFactors.Add(1.004186); //Creating two different seasonality objects // MultiplicativePriceSeasonality seasonality_1 = new MultiplicativePriceSeasonality(); InitializedList <double> seasonalityFactors_1 = new InitializedList <double>(12, 1.0); seasonality_1.set(seasonallityBaseDate, Frequency.Monthly, seasonalityFactors_1); MultiplicativePriceSeasonality seasonality_real = new MultiplicativePriceSeasonality(seasonallityBaseDate, Frequency.Monthly, seasonalityFactors); //Testing seasonality correction when seasonality factors are = 1 // double[] fixing = { ii.fixing(new Date(14, Month.January, 2013), true), ii.fixing(new Date(14, Month.February, 2013), true), ii.fixing(new Date(14, Month.March, 2013), true), ii.fixing(new Date(14, Month.April, 2013), true), ii.fixing(new Date(14, Month.May, 2013), true), ii.fixing(new Date(14, Month.June, 2013), true), ii.fixing(new Date(14, Month.July, 2013), true), ii.fixing(new Date(14, Month.August, 2013), true), ii.fixing(new Date(14, Month.September, 2013), true), ii.fixing(new Date(14, Month.October, 2013), true), ii.fixing(new Date(14, Month.November, 2013), true), ii.fixing(new Date(14, Month.December, 2013), true) }; hz.link.setSeasonality(seasonality_1); Utils.QL_REQUIRE(hz.link.hasSeasonality(), () => "[44] incorrectly believes NO seasonality correction"); double[] seasonalityFixing_1 = { ii.fixing(new Date(14, Month.January, 2013), true), ii.fixing(new Date(14, Month.February, 2013), true), ii.fixing(new Date(14, Month.March, 2013), true), ii.fixing(new Date(14, Month.April, 2013), true), ii.fixing(new Date(14, Month.May, 2013), true), ii.fixing(new Date(14, Month.June, 2013), true), ii.fixing(new Date(14, Month.July, 2013), true), ii.fixing(new Date(14, Month.August, 2013), true), ii.fixing(new Date(14, Month.September, 2013), true), ii.fixing(new Date(14, Month.October, 2013), true), ii.fixing(new Date(14, Month.November, 2013), true), ii.fixing(new Date(14, Month.December, 2013), true) }; for (int i = 0; i < 12; i++) { if (Math.Abs(fixing[i] - seasonalityFixing_1[i]) > eps) { Assert.Fail("Seasonality doesn't work correctly when seasonality factors are set = 1"); } } //Testing seasonality correction when seasonality factors are different from 1 // //0.998687 is the seasonality factor corresponding to June (the base CPI curve month) // double[] expectedFixing = { ii.fixing(new Date(14, Month.January, 2013), true) * 1.003245 / 0.998687, ii.fixing(new Date(14, Month.February, 2013), true) * 1.000000 / 0.998687, ii.fixing(new Date(14, Month.March, 2013), true) * 0.999715 / 0.998687, ii.fixing(new Date(14, Month.April, 2013), true) * 1.000495 / 0.998687, ii.fixing(new Date(14, Month.May, 2013), true) * 1.000929 / 0.998687, ii.fixing(new Date(14, Month.June, 2013), true) * 0.998687 / 0.998687, ii.fixing(new Date(14, Month.July, 2013), true) * 0.995949 / 0.998687, ii.fixing(new Date(14, Month.August, 2013), true) * 0.994682 / 0.998687, ii.fixing(new Date(14, Month.September, 2013), true) * 0.995949 / 0.998687, ii.fixing(new Date(14, Month.October, 2013), true) * 1.000519 / 0.998687, ii.fixing(new Date(14, Month.November, 2013), true) * 1.003705 / 0.998687, ii.fixing(new Date(14, Month.December, 2013), true) * 1.004186 / 0.998687 }; hz.link.setSeasonality(seasonality_real); double[] seasonalityFixing_real = { ii.fixing(new Date(14, Month.January, 2013), true), ii.fixing(new Date(14, Month.February, 2013), true), ii.fixing(new Date(14, Month.March, 2013), true), ii.fixing(new Date(14, Month.April, 2013), true), ii.fixing(new Date(14, Month.May, 2013), true), ii.fixing(new Date(14, Month.June, 2013), true), ii.fixing(new Date(14, Month.July, 2013), true), ii.fixing(new Date(14, Month.August, 2013), true), ii.fixing(new Date(14, Month.September, 2013), true), ii.fixing(new Date(14, Month.October, 2013), true), ii.fixing(new Date(14, Month.November, 2013), true), ii.fixing(new Date(14, Month.December, 2013), true) }; for (int i = 0; i < 12; i++) { if (Math.Abs(expectedFixing[i] - seasonalityFixing_real[i]) > 0.01) { Assert.Fail("Seasonality doesn't work correctly when considering seasonality factors != 1 " + expectedFixing[i] + " vs " + seasonalityFixing_real[i]); } } //Testing Unset function // Utils.QL_REQUIRE(hz.link.hasSeasonality(), () => "[4] incorrectly believes NO seasonality correction"); hz.link.setSeasonality(); Utils.QL_REQUIRE(!hz.link.hasSeasonality(), () => "[5] incorrectly believes HAS seasonality correction"); double[] seasonalityFixing_unset = { ii.fixing(new Date(14, Month.January, 2013), true), ii.fixing(new Date(14, Month.February, 2013), true), ii.fixing(new Date(14, Month.March, 2013), true), ii.fixing(new Date(14, Month.April, 2013), true), ii.fixing(new Date(14, Month.May, 2013), true), ii.fixing(new Date(14, Month.June, 2013), true), ii.fixing(new Date(14, Month.July, 2013), true), ii.fixing(new Date(14, Month.August, 2013), true), ii.fixing(new Date(14, Month.September, 2013), true), ii.fixing(new Date(14, Month.October, 2013), true), ii.fixing(new Date(14, Month.November, 2013), true), ii.fixing(new Date(14, Month.December, 2013), true) }; for (int i = 0; i < 12; i++) { if (Math.Abs(seasonalityFixing_unset[i] - seasonalityFixing_1[i]) > eps) { Assert.Fail("UnsetSeasonality doesn't work correctly " + seasonalityFixing_unset[i] + " vs " + seasonalityFixing_1[i]); } } //============================================================================== // now do an INTERPOLATED index, i.e. repeat everything on a fake version of // UKRPI (to save making another term structure) bool interpYES = true; UKRPI iiUKRPIyes = new UKRPI(interpYES, hz); for (int i = 0; i < fixData.Length; i++) { iiUKRPIyes.addFixing(rpiSchedule[i], fixData[i]); } ZeroInflationIndex iiyes = iiUKRPIyes as ZeroInflationIndex; // now build the zero inflation curve // same data, bigger lag or it will be a self-contradiction Period observationLagyes = new Period(3, TimeUnit.Months); List <BootstrapHelper <ZeroInflationTermStructure> > helpersyes = makeHelpers(zcData, zcData.Length, iiyes, observationLagyes, calendar, bdc, dc); PiecewiseZeroInflationCurve <Linear> pZITSyes = new PiecewiseZeroInflationCurve <Linear>( evaluationDate, calendar, dc, observationLagyes, frequency, iiyes.interpolated(), baseZeroRate, new Handle <YieldTermStructure>(nominalTS), helpersyes); pZITSyes.recalculate(); // first check that the zero rates on the curve match the data // and that the helpers give the correct impled rates forceLinearInterpolation = false; // still for (int i = 0; i < zcData.Length; i++) { Assert.IsTrue(Math.Abs(zcData[i].rate / 100.0 - pZITSyes.zeroRate(zcData[i].date, observationLagyes, forceLinearInterpolation)) < eps, "ZITS INTERPOLATED zeroRate != instrument " + pZITSyes.zeroRate(zcData[i].date, observationLagyes, forceLinearInterpolation) + " date " + zcData[i].date + " observationLagyes " + observationLagyes + " vs " + zcData[i].rate / 100.0 + " interpolation: " + iiyes.interpolated() + " forceLinearInterpolation " + forceLinearInterpolation); Assert.IsTrue(Math.Abs(helpersyes[i].impliedQuote() - zcData[i].rate / 100.0) < eps, "ZITS INTERPOLATED implied quote != instrument " + helpersyes[i].impliedQuote() + " vs " + zcData[i].rate / 100.0); } //====================================================================================== // now test the forecasting capability of the index. hz.linkTo(pZITSyes); from = hz.link.baseDate() + new Period(1, TimeUnit.Months); // to avoid historical linear bit for rest of base month to = hz.link.maxDate() - new Period(1, TimeUnit.Months); // a bit of margin for adjustments testIndex = new MakeSchedule().from(from).to(to) .withTenor(new Period(1, TimeUnit.Months)) .withCalendar(new UnitedKingdom()) .withConvention(BusinessDayConvention.ModifiedFollowing).value(); // we are testing UKRPI which is FAKE interpolated for testing here bd = hz.link.baseDate(); bf = iiyes.fixing(bd); for (int i = 0; i < testIndex.Count; i++) { Date d = testIndex[i]; double z = hz.link.zeroRate(d, new Period(0, TimeUnit.Days)); double t = hz.link.dayCounter().yearFraction(bd, d); double calc = bf * Math.Pow(1 + z, t); if (t <= 0) { calc = iiyes.fixing(d); // still historical } if (Math.Abs(calc - iiyes.fixing(d)) > eps) { Assert.Fail("ZC INTERPOLATED index does not forecast correctly for date " + d + " from base date " + bd + " with fixing " + bf + ", correct: " + calc + ", fix: " + iiyes.fixing(d) + ", t " + t + ", zero " + z); } } //=========================================================================================== // Test zero coupon swap ZeroInflationIndex ziiyes = iiyes as ZeroInflationIndex; Utils.QL_REQUIRE(ziiyes != null, () => "dynamic_pointer_cast to ZeroInflationIndex from UKRPI-I failed"); ZeroCouponInflationSwap nzcisyes = new ZeroCouponInflationSwap(ZeroCouponInflationSwap.Type.Payer, 1000000.0, evaluationDate, zcData[6].date, // end date = maturity calendar, bdc, dc, zcData[6].rate / 100.0, // fixed rate ziiyes, observationLagyes); // N.B. no coupon pricer because it is not a coupon, effect of inflation curve via // inflation curve attached to the inflation index. nzcisyes.setPricingEngine(sppe); // ... and price it, should be zero Assert.IsTrue(Math.Abs(nzcisyes.NPV()) < 0.00001, "ZCIS-I does not reprice to zero " + nzcisyes.NPV() + evaluationDate + " to " + zcData[6].date + " becoming " + nzcisyes.maturityDate() + " rate " + zcData[6].rate + " fixed leg " + nzcisyes.legNPV(0) + " indexed-predicted inflated leg " + nzcisyes.legNPV(1) + " discount " + nominalTS.discount(nzcisyes.maturityDate()) ); // remove circular refernce hz.linkTo(new ZeroInflationTermStructure()); }
static void Main(string[] args) { double nominal = 575000000; Date _marketDate; Date _settlementDate; Dictionary <string, double> _depositRates; Dictionary <string, double> _swapRates; List <RateHelper> _rateHelpers; Calendar _calendar = new TARGET(); int _fixingDays = 2; _marketDate = new Date(new DateTime(2015, 12, 17)); Settings.setEvaluationDate(_marketDate); _depositRates = new Dictionary <string, double>(); _depositRates.Add("1M", 0.0045); _depositRates.Add("3M", 0.0070); _depositRates.Add("6M", 0.0090); _swapRates = new Dictionary <string, double>(); _swapRates.Add("1Y", 0.0080); _swapRates.Add("2Y", 0.0109); _swapRates.Add("3Y", 0.0134); _swapRates.Add("4Y", 0.0153); _swapRates.Add("5Y", 0.0169); _swapRates.Add("7Y", 0.0193); _swapRates.Add("10Y", 0.0218); _swapRates.Add("30Y", 0.0262); _rateHelpers = new List <RateHelper>(); foreach (var v in _depositRates) { SimpleQuote sq = new SimpleQuote(v.Value); _rateHelpers.Add(new DepositRateHelper(new Handle <Quote>(sq), new Period(v.Key), _fixingDays, _calendar, BusinessDayConvention.ModifiedFollowing, true, new Actual360())); } foreach (var v in _swapRates) { SimpleQuote sq = new SimpleQuote(v.Value); _rateHelpers.Add(new SwapRateHelper(new Handle <Quote>(sq), new Period(v.Key), _calendar, Frequency.Semiannual, BusinessDayConvention.Unadjusted, new Thirty360(Thirty360.Thirty360Convention.USA), new Euribor3M())); } _marketDate = _calendar.adjust(_marketDate); _settlementDate = _calendar.advance(_marketDate, _fixingDays, TimeUnit.Days); YieldTermStructure yieldTermStructure = new PiecewiseYieldCurve <Discount, LogLinear>( _settlementDate, _rateHelpers, new ActualActual(ActualActual.Convention.ISDA)); RelinkableHandle <YieldTermStructure> yieldTermStructureHandle = new RelinkableHandle <YieldTermStructure>(); Frequency fixedLegFrequency = Frequency.Semiannual; BusinessDayConvention fixedLegConvention = BusinessDayConvention.ModifiedFollowing; DayCounter fixedLegDayCounter = new Thirty360(Thirty360.Thirty360Convention.USA); double fixedRate = 0.0144; Frequency floatLegFrequency = Frequency.Quarterly; BusinessDayConvention floatLegConvention = BusinessDayConvention.ModifiedFollowing; DayCounter floatLegDayCounter = new Actual360(); IborIndex iborIndex = new Euribor3M(yieldTermStructureHandle); iborIndex.addFixing(new Date(18, Month.Aug, 2015), 0.0033285); iborIndex.addFixing(new Date(18, Month.Nov, 2015), 0.0036960); double floatSpread = 0.0; VanillaSwap.Type swapType = VanillaSwap.Type.Receiver; Date maturity = new Date(20, Month.Nov, 2018); Date effective = new Date(20, Month.Nov, 2013); Schedule fixedSchedule = new Schedule(effective, maturity, new Period(fixedLegFrequency), _calendar, fixedLegConvention, fixedLegConvention, DateGeneration.Rule.Forward, false); Schedule floatSchedule = new Schedule(effective, maturity, new Period(floatLegFrequency), _calendar, floatLegConvention, floatLegConvention, DateGeneration.Rule.Forward, false); VanillaSwap vanillaSwap = new VanillaSwap(swapType, nominal, fixedSchedule, fixedRate, fixedLegDayCounter, floatSchedule, iborIndex, floatSpread, floatLegDayCounter); InterestRate interestRate = new InterestRate(fixedRate, fixedLegDayCounter, Compounding.Simple, fixedLegFrequency); List <InterestRate> coupons = new List <InterestRate>(); for (int i = 0; i < fixedSchedule.Count; i++) { coupons.Add(interestRate); } FixedRateBond fixedBond = new FixedRateBond(_fixingDays, nominal, fixedSchedule, coupons, BusinessDayConvention.ModifiedFollowing); FloatingRateBond floatBond = new FloatingRateBond(_fixingDays, nominal, floatSchedule, iborIndex, floatLegDayCounter); IPricingEngine bondPricingEngine = new DiscountingBondEngine(yieldTermStructureHandle); fixedBond.setPricingEngine(bondPricingEngine); floatBond.setPricingEngine(bondPricingEngine); IPricingEngine swapPricingEngine = new DiscountingSwapEngine(yieldTermStructureHandle); vanillaSwap.setPricingEngine(swapPricingEngine); yieldTermStructureHandle.linkTo(yieldTermStructure); double swapNPV = vanillaSwap.NPV(); double swapFixedNPV = vanillaSwap.fixedLegNPV(); double swapFloatNPV = vanillaSwap.floatingLegNPV(); double bondFixedNPV = fixedBond.NPV(); double bondFloatNPV = floatBond.NPV(); int w = (swapType == VanillaSwap.Type.Receiver ? 1 : -1); double asBondsMarketValue = w * (bondFixedNPV - bondFloatNPV); double asBondsMarketValueNoAcc = w * (fixedBond.cleanPrice() - floatBond.cleanPrice()) / 100.0 * nominal; double asBondsAccruedInterest = asBondsMarketValue - asBondsMarketValueNoAcc; Console.WriteLine("Vanilla Swap Maket Value : {0:N}", swapNPV); Console.WriteLine("As Bonds Market Value : {0:N}", asBondsMarketValue); Console.WriteLine("As Bonds Market Value (no acc): {0:N}", asBondsMarketValueNoAcc); Console.WriteLine("As Bonds Accrued Interest : {0:N}", asBondsAccruedInterest); Date rollDate = new Date(1, Month.Nov, 2015); double bondFixedCash = 0; foreach (CashFlow cf in fixedBond.cashflows()) { if (cf.date() > rollDate & cf.date() <= _marketDate) { bondFixedCash += cf.amount(); } } double bondFloatCash = 0; foreach (CashFlow cf in floatBond.cashflows()) { if (cf.date() > rollDate & cf.date() <= _marketDate) { bondFloatCash += cf.amount(); } } double asBondsCash = w * (bondFixedCash - bondFloatCash); Console.WriteLine("As Bonds Settled Cash : {0:N}", asBondsCash); }
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 cpibondconsistency() { CommonVars common = new CommonVars(); // ZeroInflationSwap aka CPISwap CPISwap.Type type = CPISwap.Type.Payer; double nominal = 1000000.0; bool subtractInflationNominal = true; // float+spread leg double spread = 0.0; DayCounter floatDayCount = new Actual365Fixed(); BusinessDayConvention floatPaymentConvention = BusinessDayConvention.ModifiedFollowing; int fixingDays = 0; IborIndex floatIndex = new GBPLibor(new Period(6, TimeUnit.Months), common.nominalUK); // fixed x inflation leg double fixedRate = 0.1; //1% would be 0.01 double baseCPI = 206.1; // would be 206.13871 if we were interpolating DayCounter fixedDayCount = new Actual365Fixed(); BusinessDayConvention fixedPaymentConvention = BusinessDayConvention.ModifiedFollowing; Calendar fixedPaymentCalendar = new UnitedKingdom(); ZeroInflationIndex fixedIndex = common.ii; Period contractObservationLag = common.contractObservationLag; InterpolationType observationInterpolation = common.contractObservationInterpolation; // set the schedules Date startDate = new Date(2, Month.October, 2007); Date endDate = new Date(2, Month.October, 2052); Schedule floatSchedule = new MakeSchedule().from(startDate).to(endDate) .withTenor(new Period(6, TimeUnit.Months)) .withCalendar(new UnitedKingdom()) .withConvention(floatPaymentConvention) .backwards().value(); Schedule fixedSchedule = new MakeSchedule().from(startDate).to(endDate) .withTenor(new Period(6, TimeUnit.Months)) .withCalendar(new UnitedKingdom()) .withConvention(BusinessDayConvention.Unadjusted) .backwards().value(); CPISwap zisV = new CPISwap(type, nominal, subtractInflationNominal, spread, floatDayCount, floatSchedule, floatPaymentConvention, fixingDays, floatIndex, fixedRate, baseCPI, fixedDayCount, fixedSchedule, fixedPaymentConvention, contractObservationLag, fixedIndex, observationInterpolation); double[] floatFix = { 0.06255, 0.05975, 0.0637, 0.018425, 0.0073438, -1, -1 }; double[] cpiFix = { 211.4, 217.2, 211.4, 213.4, -2, -2 }; for (int i = 0; i < floatSchedule.Count; i++) { if (floatSchedule[i] < common.evaluationDate) { floatIndex.addFixing(floatSchedule[i], floatFix[i], true);//true=overwrite } CPICoupon zic = zisV.cpiLeg()[i] as CPICoupon; if (zic != null) { if (zic.fixingDate() < (common.evaluationDate - new Period(1, TimeUnit.Months))) { fixedIndex.addFixing(zic.fixingDate(), cpiFix[i], true); } } } // simple structure so simple pricing engine - most work done by index DiscountingSwapEngine dse = new DiscountingSwapEngine(common.nominalUK); zisV.setPricingEngine(dse); // now do the bond equivalent List <double> fixedRates = new InitializedList <double>(1, fixedRate); int settlementDays = 1;// cannot be zero! bool growthOnly = true; CPIBond cpiB = new CPIBond(settlementDays, nominal, growthOnly, baseCPI, contractObservationLag, fixedIndex, observationInterpolation, fixedSchedule, fixedRates, fixedDayCount, fixedPaymentConvention); DiscountingBondEngine dbe = new DiscountingBondEngine(common.nominalUK); cpiB.setPricingEngine(dbe); QAssert.IsTrue(Math.Abs(cpiB.NPV() - zisV.legNPV(0).GetValueOrDefault()) < 1e-5, "cpi bond does not equal equivalent cpi swap leg"); // remove circular refernce common.hcpi.linkTo(null); }
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()); }
static void Main(string[] args) { try { DateTime timer = DateTime.Now; Calendar calendar = new TARGET(); Date todaysDate = new Date(10, Month.March, 2004); // must be a business day todaysDate = calendar.adjust(todaysDate); Settings.setEvaluationDate(todaysDate); IborIndex yieldIndx = new Euribor3M(); int[] tenorsSwapMkt = { 5, 10, 15, 20, 25, 30 }; // rates ignoring counterparty risk: double[] ratesSwapmkt = { .03249, .04074, .04463, .04675, .04775, .04811 }; List <RateHelper> swapHelpers = new List <RateHelper>(); for (int i = 0; i < tenorsSwapMkt.Length; i++) { swapHelpers.Add(new SwapRateHelper(new Handle <Quote>(new SimpleQuote(ratesSwapmkt[i])), new Period(tenorsSwapMkt[i], TimeUnit.Years), new TARGET(), Frequency.Quarterly, BusinessDayConvention.ModifiedFollowing, new ActualActual(ActualActual.Convention.ISDA), yieldIndx)); } YieldTermStructure swapTS = new PiecewiseYieldCurve <Discount, LogLinear>(2, new TARGET(), swapHelpers, new ActualActual(ActualActual.Convention.ISDA)); swapTS.enableExtrapolation(); IPricingEngine riskFreeEngine = new DiscountingSwapEngine(new Handle <YieldTermStructure>(swapTS)); List <Handle <DefaultProbabilityTermStructure> > defaultIntensityTS = new List <Handle <DefaultProbabilityTermStructure> >(); int[] defaultTenors = { 0, 12, 36, 60, 84, 120, 180, 240, 300, 360 }; // months // Three risk levels: double[] intensitiesLow = { 0.0036, 0.0036, 0.0065, 0.0099, 0.0111, 0.0177, 0.0177, 0.0177, 0.0177, 0.0177, 0.0177 }; double[] intensitiesMedium = { 0.0202, 0.0202, 0.0231, 0.0266, 0.0278, 0.0349, 0.0349, 0.0349, 0.0349, 0.0349, 0.0349 }; double[] intensitiesHigh = { 0.0534, 0.0534, 0.0564, 0.06, 0.0614, 0.0696, 0.0696, 0.0696, 0.0696, 0.0696, 0.0696 }; // Recovery rates: double ctptyRRLow = 0.4, ctptyRRMedium = 0.35, ctptyRRHigh = 0.3; List <Date> defaultTSDates = new List <Date>(); List <double> intesitiesVLow = new List <double>(), intesitiesVMedium = new List <double>(), intesitiesVHigh = new List <double>(); for (int i = 0; i < defaultTenors.Length; i++) { defaultTSDates.Add(new TARGET().advance(todaysDate, new Period(defaultTenors[i], TimeUnit.Months))); intesitiesVLow.Add(intensitiesLow[i]); intesitiesVMedium.Add(intensitiesMedium[i]); intesitiesVHigh.Add(intensitiesHigh[i]); } defaultIntensityTS.Add(new Handle <DefaultProbabilityTermStructure>( new InterpolatedHazardRateCurve <BackwardFlat>( defaultTSDates, intesitiesVLow, new Actual360(), new TARGET()))); defaultIntensityTS.Add(new Handle <DefaultProbabilityTermStructure>( new InterpolatedHazardRateCurve <BackwardFlat>( defaultTSDates, intesitiesVMedium, new Actual360(), new TARGET()))); defaultIntensityTS.Add(new Handle <DefaultProbabilityTermStructure>( new InterpolatedHazardRateCurve <BackwardFlat>( defaultTSDates, intesitiesVHigh, new Actual360(), new TARGET()))); double blackVol = 0.15; IPricingEngine ctptySwapCvaLow = new CounterpartyAdjSwapEngine(new Handle <YieldTermStructure>(swapTS), blackVol, defaultIntensityTS[0], ctptyRRLow); IPricingEngine ctptySwapCvaMedium = new CounterpartyAdjSwapEngine(new Handle <YieldTermStructure>(swapTS), blackVol, defaultIntensityTS[1], ctptyRRMedium); IPricingEngine ctptySwapCvaHigh = new CounterpartyAdjSwapEngine(new Handle <YieldTermStructure>(swapTS), blackVol, defaultIntensityTS[2], ctptyRRHigh); defaultIntensityTS[0].link.enableExtrapolation(); defaultIntensityTS[1].link.enableExtrapolation(); defaultIntensityTS[2].link.enableExtrapolation(); // SWAP RISKY REPRICE---------------------------------------------- // fixed leg Frequency fixedLegFrequency = Frequency.Quarterly; BusinessDayConvention fixedLegConvention = BusinessDayConvention.ModifiedFollowing; DayCounter fixedLegDayCounter = new ActualActual(ActualActual.Convention.ISDA); DayCounter floatingLegDayCounter = new ActualActual(ActualActual.Convention.ISDA); VanillaSwap.Type swapType = //VanillaSwap::Receiver ; VanillaSwap.Type.Payer; IborIndex yieldIndxS = new Euribor3M(new Handle <YieldTermStructure>(swapTS)); List <VanillaSwap> riskySwaps = new List <VanillaSwap>(); for (int i = 0; i < tenorsSwapMkt.Length; i++) { riskySwaps.Add(new MakeVanillaSwap(new Period(tenorsSwapMkt[i], TimeUnit.Years), yieldIndxS, ratesSwapmkt[i], new Period(0, TimeUnit.Days)) .withSettlementDays(2) .withFixedLegDayCount(fixedLegDayCounter) .withFixedLegTenor(new Period(fixedLegFrequency)) .withFixedLegConvention(fixedLegConvention) .withFixedLegTerminationDateConvention(fixedLegConvention) .withFixedLegCalendar(calendar) .withFloatingLegCalendar(calendar) .withNominal(100.0) .withType(swapType).value()); } Console.WriteLine("-- Correction in the contract fix rate in bp --"); /* The paper plots correction to be substracted, here is printed * with its sign */ for (int i = 0; i < riskySwaps.Count; i++) { riskySwaps[i].setPricingEngine(riskFreeEngine); // should recover the input here: double nonRiskyFair = riskySwaps[i].fairRate(); Console.Write((tenorsSwapMkt[i]).ToString("0").PadLeft(6)); Console.Write(" | " + nonRiskyFair.ToString("P3").PadLeft(6)); // Low Risk: riskySwaps[i].setPricingEngine(ctptySwapCvaLow); Console.Write(" | " + (10000.0 * (riskySwaps[i].fairRate() - nonRiskyFair)).ToString("#0.00").PadLeft(6)); //cout << " | " << setw(6) << riskySwaps[i].NPV() ; // Medium Risk: riskySwaps[i].setPricingEngine(ctptySwapCvaMedium); Console.Write(" | " + (10000.0 * (riskySwaps[i].fairRate() - nonRiskyFair)).ToString("#0.00").PadLeft(6)); //cout << " | " << setw(6) << riskySwaps[i].NPV() ; riskySwaps[i].setPricingEngine(ctptySwapCvaHigh); Console.Write(" | " + (10000.0 * (riskySwaps[i].fairRate() - nonRiskyFair)).ToString("#0.00").PadLeft(6)); //cout << " | " << setw(6) << riskySwaps[i].NPV() ; Console.WriteLine(); } Console.WriteLine(); Console.WriteLine(" \nRun completed in {0}", DateTime.Now - timer); Console.WriteLine(); Console.Write("Press any key to continue ..."); Console.ReadKey(); } catch (Exception e) { Console.Write(e.Message); Console.Write("Press any key to continue ..."); Console.ReadKey(); } }
public static object eqInstIRGenericSwap( // trade info /*[ExcelArgument(Description = "trade id ")] string tradeid, * [ExcelArgument(Description = "Entity ")] string entity, * [ExcelArgument(Description = "Entity ID ")] string entityid, * [ExcelArgument(Description = "Counterparty ")] string counterparty, * [ExcelArgument(Description = "Counterparty ID ")] string counterpartyid, * [ExcelArgument(Description = "swap type ")] string swaptype, * [ExcelArgument(Description = "Fixing Days ")] object fixingdays, // use object to catch missing * [ExcelArgument(Description = "Trade Date ")] object tradedate, * [ExcelArgument(Description = "Start date ")] object startdate, * [ExcelArgument(Description = "Maturity date ")] object maturitydate, * [ExcelArgument(Description = "Tenor ")] string Tenor, * [ExcelArgument(Description = "is notional schedule given ")] bool isschedulegiven,*/ [ExcelArgument(Description = "swap type ")] object[] tradeinfo, // first leg /*[ExcelArgument(Description = "id of first leg index ")] string firstlegindex, * [ExcelArgument(Description = "first leg frequency ")] string firstlegfreq, * [ExcelArgument(Description = "first leg convention ")] string firstlegconv, * [ExcelArgument(Description = "first leg calendar ")] string firstlegcalendar, * [ExcelArgument(Description = "first leg day counter ")] string firstlegdc, * [ExcelArgument(Description = "first leg date generation rule ")] string firstlegdgrule, * [ExcelArgument(Description = "first leg end of month ")] bool firstlegeom, * [ExcelArgument(Description = "first leg fixed rate ")] double firstlegrate,*/ [ExcelArgument(Description = "first leg info ")] object[] firstleginfo, [ExcelArgument(Description = "first leg notional(s) ")] object[] firstlegnotionals, // only object[] works [ExcelArgument(Description = "first leg schedule(s) ")] object[,] firstlegschedule, // second leg /*[ExcelArgument(Description = "id of second leg index ")] string secondlegindex, * [ExcelArgument(Description = "second leg frequency ")] string secondlegfreq, * [ExcelArgument(Description = "second leg convention ")] string secondlegconv, * [ExcelArgument(Description = "second leg calendar ")] string secondlegcalendar, * [ExcelArgument(Description = "second leg day counter ")] string secondlegdc, * [ExcelArgument(Description = "second leg date generation rule ")] string secondlegdgrule, * [ExcelArgument(Description = "second leg end of month ")] bool secondlegeom, * [ExcelArgument(Description = "second leg spread ")] double secondlegspread,*/ [ExcelArgument(Description = "second leg info ")] object[] secondleginfo, [ExcelArgument(Description = "second leg notional(s) ")] object[] secondlegnotionals, [ExcelArgument(Description = "second leg schedule(s) ")] object[,] secondlegschedule, [ExcelArgument(Description = "id of discount curve ")] string discountId ) { if (ExcelUtil.CallFromWizard()) { return(""); } string callerAddress = ""; callerAddress = ExcelUtil.getActiveCellAddress(); try { Xl.Range rng = ExcelUtil.getActiveCellRange(); EliteQuant.Instruments.InterestRateGenericSwap genswap = new EliteQuant.Instruments.InterestRateGenericSwap(); #region parameters if (ExcelUtil.isNull(tradeinfo[0])) { return("#EQ_ERR!"); } else { genswap.ContractId = (string)tradeinfo[0]; } if (ExcelUtil.isNull(tradeinfo[1])) { genswap.Entity = "NA"; } else { genswap.Entity = (string)tradeinfo[1]; } if (ExcelUtil.isNull(tradeinfo[2])) { genswap.EntityID = "NA"; } else { genswap.EntityID = (string)tradeinfo[2]; } if (ExcelUtil.isNull(tradeinfo[3])) { genswap.Counterparty = "NA"; } else { genswap.Counterparty = (string)tradeinfo[3]; } if (ExcelUtil.isNull(tradeinfo[4])) { genswap.CounterpartyID = "NA"; } else { genswap.CounterpartyID = (string)tradeinfo[4]; } if (ExcelUtil.isNull(tradeinfo[5])) { genswap.SwapType = "Payer"; } else { genswap.SwapType = (string)tradeinfo[5]; } if (ExcelUtil.isNull(tradeinfo[6])) { genswap.FixingDays = 2; } else { genswap.FixingDays = (int)(double)tradeinfo[6]; } if (ExcelUtil.isNull(tradeinfo[7])) { genswap.TradeDate = EliteQuant.EQConverter.DateTimeToString(DateTime.Today); } else { genswap.TradeDate = EliteQuant.EQConverter.DateTimeToString(DateTime.FromOADate((double)tradeinfo[7])); } // set it temporarily to "" if (ExcelUtil.isNull(tradeinfo[8])) { genswap.SettlementDate = string.Empty; } else { genswap.SettlementDate = EliteQuant.EQConverter.DateTimeToString(DateTime.FromOADate((double)tradeinfo[8])); } // set it temporarily to today if (ExcelUtil.isNull(tradeinfo[9])) { genswap.MaturityDate = string.Empty; } else { genswap.MaturityDate = EliteQuant.EQConverter.DateTimeToString(DateTime.FromOADate((double)tradeinfo[9])); } // set it temporarily to blank if (ExcelUtil.isNull(tradeinfo[10])) { genswap.Tenor = string.Empty; } else { genswap.Tenor = (string)tradeinfo[10]; } if (ExcelUtil.isNull(tradeinfo[11])) { genswap.IsScheduleGiven = false; } else { //genswap.IsScheduleGiven = Convert.ToBoolean((string)tradeinfo[11]); genswap.IsScheduleGiven = (bool)tradeinfo[11]; } genswap.IsScheduleGiven = false; // set to false always, amortization currently not supported //*************** First Leg *************************// if (ExcelUtil.isNull(firstleginfo[0])) { genswap.FirstLegIndex = "FIXED"; } else { genswap.FirstLegIndex = (string)firstleginfo[0]; } if (ExcelUtil.isNull(firstleginfo[1])) { genswap.FirstLegFrequency = "SEMIANNUAL"; } else { genswap.FirstLegFrequency = (string)firstleginfo[1]; } if (ExcelUtil.isNull(firstleginfo[2])) { genswap.FirstLegConvention = "MODIFIEDFOLLOWING"; } else { genswap.FirstLegConvention = (string)firstleginfo[2]; } if (ExcelUtil.isNull(firstleginfo[3])) { genswap.FirstLegCalendar = "NYC|LON"; } else { genswap.FirstLegCalendar = (string)firstleginfo[3]; } if (ExcelUtil.isNull(firstleginfo[4])) { genswap.FirstLegDayCounter = "ACTUAL360"; } else { genswap.FirstLegDayCounter = (string)firstleginfo[4]; } if (ExcelUtil.isNull(firstleginfo[5])) { genswap.FirstLegDateGenerationRule = "BACKWARD"; } else { genswap.FirstLegDateGenerationRule = (string)firstleginfo[5]; } if (ExcelUtil.isNull(firstleginfo[6])) { genswap.FirstLegEOM = true; } else { genswap.FirstLegEOM = (bool)firstleginfo[6]; } if (ExcelUtil.isNull(firstleginfo[7])) { genswap.FirstLegSpread = 0.0; } else { genswap.FirstLegSpread = (double)firstleginfo[7]; } if (ExcelUtil.isNull(firstlegnotionals)) { genswap.FirstLegNotionals.Clear(); genswap.FirstLegNotionals.Add(0); // size = 1 } else { genswap.FirstLegNotionals.Clear(); foreach (var nl in firstlegnotionals) { if (ExcelUtil.isNull(nl)) { continue; } genswap.FirstLegNotionals.Add((double)nl); } } if (ExcelUtil.isNull(firstlegschedule) || (!genswap.IsScheduleGiven)) { genswap.FirstLegSchedules.Clear(); genswap.FirstLegSchedules.Add(genswap.SettlementDate); genswap.FirstLegSchedules.Add(genswap.MaturityDate); } else { genswap.FirstLegSchedules.Clear(); for (int a = 0; a < firstlegschedule.GetLength(0); a++) { DateTime d; if (ExcelUtil.isNull(firstlegschedule[a, 0])) { // add one more date d = DateTime.FromOADate((double)firstlegschedule[a - 1, 1]); genswap.FirstLegSchedules.Add(EliteQuant.EQConverter.DateTimeToString(d)); break; } d = DateTime.FromOADate((double)firstlegschedule[a, 0]); genswap.FirstLegSchedules.Add(EliteQuant.EQConverter.DateTimeToString(d)); } } //*************** Second Leg *************************// if (ExcelUtil.isNull(secondleginfo[0])) { genswap.SecondLegIndex = "USDLIB3M"; } else { genswap.SecondLegIndex = (string)secondleginfo[0]; } if (ExcelUtil.isNull(secondleginfo[1])) { genswap.SecondLegFrequency = "QUARTERLY"; } else { genswap.SecondLegFrequency = (string)secondleginfo[1]; } if (ExcelUtil.isNull(secondleginfo[2])) { genswap.SecondLegConvention = "MODIFIEDFOLLOWING"; } else { genswap.SecondLegConvention = (string)secondleginfo[2]; } if (ExcelUtil.isNull(secondleginfo[3])) { genswap.SecondLegCalendar = "NYC|LON"; // nor NYC|LON } else { genswap.SecondLegCalendar = (string)secondleginfo[3]; } if (ExcelUtil.isNull(secondleginfo[4])) { genswap.SecondLegDayCounter = "ACTUAL360"; } else { genswap.SecondLegDayCounter = (string)secondleginfo[4]; } if (ExcelUtil.isNull(secondleginfo[5])) { genswap.SecondLegDateGenerationRule = "BACKWARD"; } else { genswap.SecondLegDateGenerationRule = (string)secondleginfo[5]; } if (ExcelUtil.isNull(secondleginfo[6])) { genswap.SecondLegEOM = true; } else { genswap.SecondLegEOM = (bool)secondleginfo[6]; } if (ExcelUtil.isNull(secondleginfo[7])) { genswap.SecondLegSpread = 0.0; } else { genswap.SecondLegSpread = (double)secondleginfo[7]; } if (ExcelUtil.isNull(secondlegnotionals)) { genswap.SecondLegNotionals.Clear(); genswap.SecondLegNotionals.Add(0); } else { genswap.SecondLegNotionals.Clear(); foreach (var nl in secondlegnotionals) { if (ExcelUtil.isNull(nl)) { continue; } genswap.SecondLegNotionals.Add((double)nl); } } if (ExcelUtil.isNull(secondlegschedule) || (!genswap.IsScheduleGiven)) { genswap.SecondLegSchedules.Clear(); genswap.SecondLegSchedules.Add(genswap.SettlementDate); genswap.SecondLegSchedules.Add(genswap.MaturityDate); } else { genswap.SecondLegSchedules.Clear(); for (int a = 0; a < secondlegschedule.GetLength(0); a++) { DateTime d; if (ExcelUtil.isNull(secondlegschedule[a, 0])) { // add one more date d = DateTime.FromOADate((double)secondlegschedule[a - 1, 1]); genswap.SecondLegSchedules.Add(EliteQuant.EQConverter.DateTimeToString(d)); break; } d = DateTime.FromOADate((double)secondlegschedule[a, 0]); genswap.SecondLegSchedules.Add(EliteQuant.EQConverter.DateTimeToString(d)); } } #endregion #region convert Interest rate generic swap to swap obj string firstidx = genswap.FirstLegIndex, secondidx = genswap.SecondLegIndex; string firstidx_id = "IDX@" + firstidx; string secondidx_id = "IDX@" + secondidx; EliteQuant.IborIndex firstidx_obj = null; if (!firstidx.Contains("FIXED")) { firstidx_obj = OHRepository.Instance.getObject <EliteQuant.IborIndex>(firstidx_id); } EliteQuant.IborIndex secondidx_obj = OHRepository.Instance.getObject <EliteQuant.IborIndex>(secondidx_id); genswap.ConstructSwap(firstidx_obj, secondidx_obj); if (!discountId.Contains('@')) { discountId = "CRV@" + discountId; } YieldTermStructure discountcurve = OHRepository.Instance.getObject <YieldTermStructure>(discountId); YieldTermStructureHandle dch = new YieldTermStructureHandle(discountcurve); DiscountingSwapEngine engine = new DiscountingSwapEngine(dch); genswap.eqswap_.setPricingEngine(engine); #endregion string id = "SWP@" + genswap.ContractId; OHRepository.Instance.storeObject(id, genswap, callerAddress); id += "#" + (String)DateTime.Now.ToString(@"HH:mm:ss"); return(id); } catch (Exception e) { ExcelUtil.logError(callerAddress, System.Reflection.MethodInfo.GetCurrentMethod().Name.ToString(), e.Message); return("#EQ_ERR!"); } }