internal static BondSpreadResult GetSpreads( OTBond bondType_, NodaTime.LocalDate maturity_, NodaTime.LocalDate issueDate_, NodaTime.LocalDate firstCouponDate_, QuoteValueType priceType_, double priceValue_, double coupon_, CurveMappings.Mapping pricingSetup_, DateTime asOf_, CarbonClient client_, ThrowBehavior behavior_=ThrowBehavior.DontThrow ) { var ret = new BondSpreadResult(); ret.Spreads = new BondSpread(); try { SLog.log.DebugFormat( "Calling PriceBondAsync with params: baseBondID={0} issueDate={1} maturity={2} coupon={3} asOf={4} pricingSetup={5} stubDate={6} priceValue={7}, priceType_={8}", ((long) bondType_).ToString(), issueDate_, maturity_, coupon_, asOf_, pricingSetup_.OT_BondPricingSetup, firstCouponDate_, priceValue_, priceType_); switch (priceType_) { case QuoteValueType.Price: { ret.Price = priceValue_; var result = client_.PriceBondAsync( baseBondId: (long)bondType_, issueDate: issueDate_, maturityDate: maturity_, coupon: coupon_, asof: asOf_, pricingSetup: pricingSetup_.OT_BondPricingSetup, quantity: 100000d, stubDate: firstCouponDate_, price: ret.Price.Value).Result; ret.Spreads.Spread = -result.Results[ServiceConstants.KEY_ASW_YY]; ret.Spreads.TrueSpread = -result.Results[ServiceConstants.KEY_ZSpread]; ret.Spreads.Yield = result.Results[ServiceConstants.KEY_Yield]; } break; case QuoteValueType.Yield: { var result = client_.GetBondPriceFromYieldAsync( baseBondId: (long)bondType_, issueDate: issueDate_, maturityDate: maturity_, coupon: coupon_, asof: asOf_, pricingSetup: pricingSetup_.OT_BondPricingSetup, quantity: 100000d, yield: priceValue_, stubDate: firstCouponDate_).Result; ret.Price = result.Results[ServiceConstants.KEY_Price]; ret.Spreads.Spread = -result.Results[ServiceConstants.KEY_ASW_YY]; ret.Spreads.TrueSpread = -result.Results[ServiceConstants.KEY_ZSpread]; ret.Spreads.Yield = priceValue_; } break; default: SLog.log.ErrorFormat("Cannot call Carbon to get spreads with priceType {0}", priceType_); break; } SLog.log.DebugFormat( "Calling PriceSwapAsync with params: curveName={0} startDate={1} endDate={2} asOf={3} pricingSetup={4}", pricingSetup_.OT_Swap, issueDate_, maturity_, asOf_, pricingSetup_.OT_BondPricingSetup); var mmsResult = client_.PriceSwapAsync( curveName: pricingSetup_.OT_Swap, startDate: asOf_.ToNodaLocalDate(), endDate: maturity_, asof: asOf_, pricingSetup: pricingSetup_.OT_BondPricingSetup).Result; ret.Spreads.MMS = mmsResult.Results[ServiceConstants.KEY_MMS]; SLog.log.DebugFormat("Result: y={0} m={1} s={2} t={3}", ret.Spreads.Yield, ret.Spreads.MMS, ret.Spreads.Spread, ret.Spreads.TrueSpread); postProcess(bondType_, ret.Spreads, pricingSetup_); } catch (Exception ex_) { Exceptions.Rethrow("GetCurves", behavior_, ex_); } return ret; }
private static void postProcess(OTBond bond_, BondSpread spread_, CurveMappings.Mapping pricingSetup_) { if(!string.IsNullOrEmpty(pricingSetup_.OT_BondPricingSetup)) switch (pricingSetup_.OT_BondPricingSetup) { case "Sym_OIS": { // 26th November 2015: // we've realised that the ASW returned by OT is always that over LIBOR, regardless of what pricing setup is passed in. // As such, we're calculating the spread by taking the difference ourselves. Obviously easy, but it maintains the need to have // 2 calls to the server (the second being to get the MMS). Obviously, if the ASW were correct, then the MMS could be calculated using // yield and ASW, and the second call could be removed. Alas, not yet... spread_.Spread = spread_.MMS - spread_.Yield; } break; } }