/// <summary> /// Generate CTD dates and set CTD coupon rate and conversion factor. /// </summary> protected void GenerateCTD(double baseDate, double issueDate, double maturityDate, double couponInterval, double firstCouponDate, double penultimateCouponDate, DayCount dayCount, IHolidayCalendar calendar, double couponRate, double conversionFactor) { if (conversionFactor <= 0.0) { return; // No CTD details or details invalid } BondFutureOption deal = (BondFutureOption)fDeal; // Validation of settlement date not done for CTD details on price factor if (deal.Settlement_Date >= maturityDate) { throw new AnalyticsException("Settlement date must be before cheapest-to-deliver maturity date."); } DateGenerationResults dateGenerationResults = deal.GetDateGenerationResults(issueDate, maturityDate, couponInterval, firstCouponDate, penultimateCouponDate, dayCount, calendar); fPayDates = dateGenerationResults.PayDates; fAccruals = dateGenerationResults.AccrualYearFractions; fIssueDate = issueDate; fMaturityDate = maturityDate; fCouponInterval = couponInterval; fCouponRate = couponRate; fConversionFactor = conversionFactor; fAccrual = PricingFunctions.AccruedInterest(deal.Settlement_Date, fIssueDate, fPayDates, fAccruals, fCouponRate, 1.0, null); double strike = PriceTransform(deal.Strike); double tSettle = CalcUtils.DaysToYears(deal.Settlement_Date - baseDate); double tMaturity = CalcUtils.DaysToYears(fMaturityDate - baseDate); fStrikeYield = PricingFunctions.BondYieldFromPrice(tSettle, tMaturity, couponRate, couponInterval, strike); }
/// <summary> /// Prepare for valuation anything that is dependent upon the scenario. /// </summary> public override void PreValue(PriceFactorList factors) { base.PreValue(factors); BondFutureOption deal = (BondFutureOption)Deal; fInterestYieldVol = InterestVolBase.GetYieldVol(factors, deal.Yield_Volatility, fCurrency); var bfb = (BondFuturesBasis)fFuturesBasis; GenerateCTD(factors.BaseDate, bfb.CTD_Issue_Date, bfb.CTD_Maturity_Date, bfb.CTD_Coupon_Interval, bfb.CTD_First_Coupon_Date, bfb.CTD_Penultimate_Coupon_Date, bfb.CTD_Day_Count, Deal.GetHolidayCalendar(), bfb.CTD_Coupon_Rate, bfb.CTD_Conversion_Factor); if (NeedRating(Respect_Default, deal.Issuer)) { fCreditRating = factors.Get <CreditRating>(deal.Issuer); fRecoveryRate = factors.Get <RecoveryRate>(InterestRateUtils.GetRateId(deal.Recovery_Rate, deal.Issuer)); } else { fCreditRating = null; fRecoveryRate = null; } if (NeedSurvivalProbability(Use_Survival_Probability, deal.Issuer)) { fSurvivalProb = factors.GetInterface <ISurvivalProb>(InterestRateUtils.GetRateId(deal.Survival_Probability, deal.Issuer)); } else { fSurvivalProb = null; } }
/// <inheritdoc /> protected override void RegisterFuturesPriceFactor(PriceFactorList factors, ErrorList errors) { BondFutureOption deal = (BondFutureOption)fDeal; BondFuturesBasis bfb = factors.Register <BondFuturesBasis>(FutureBase.GetFactorID(deal.Contract, deal.Settlement_Date)); if (deal.Settlement_Date >= bfb.CTD_Maturity_Date) { errors.Add(ErrorLevel.Error, "Settlement date must be before cheapest-to-deliver maturity date of the Bond Future Basis price factor."); } }
/// <summary> /// Register price factors. /// </summary> public override void RegisterFactors(PriceFactorList factors, ErrorList errors) { BondFutureOption deal = (BondFutureOption)Deal; base.RegisterFactors(factors, errors); InterestVolBase.RegisterInterestYieldVol(factors, deal.Yield_Volatility, fCurrency); if (NeedRating(Respect_Default, deal.Issuer)) { factors.Register <CreditRating>(deal.Issuer); // register realized recovery rate. factors.Register <RecoveryRate>(InterestRateUtils.GetRateId(deal.Recovery_Rate, deal.Issuer)); } if (NeedSurvivalProbability(Use_Survival_Probability, deal.Issuer)) { factors.RegisterInterface <ISurvivalProb>(InterestRateUtils.GetRateId(deal.Survival_Probability, deal.Issuer)); } }
/// <summary> /// Calculate forward price, discount factor and volatility /// </summary> protected override void PriceAndVolatility(double baseDate, double valueDate, Vector forwardPrice, Vector discountFactor, Vector volatility) { BondFutureOption deal = (BondFutureOption)fDeal; double t = CalcUtils.DaysToYears(valueDate - baseDate); double tSettle = CalcUtils.DaysToYears(deal.Settlement_Date - baseDate); double tMaturity = CalcUtils.DaysToYears(fMaturityDate - baseDate); fDiscountRate.GetValue(discountFactor, t, tSettle); if (volatility != null) { double tExpiry = deal.GetTimeToExpiry(baseDate); if (tExpiry > t) { // Calculate price volatility using (var cache = Vector.CacheLike(forwardPrice)) { Vector macaulayDuration = cache.Get(); Vector yield = cache.Get(); Vector yieldStrike = cache.Get(fStrikeYield); // Calculate forwrad price, yield and adjusted duration using simple bond price functions PricingFunctions.BondForwardPriceAndAdjustedMacaulayDuration(forwardPrice, macaulayDuration, t, tSettle, tMaturity, fCouponRate, fCouponInterval, discountFactor, fDiscountRate, fSurvivalProb); PricingFunctions.BondYieldFromPrice(yield, tSettle, tMaturity, fCouponRate, fCouponInterval, forwardPrice); // Calculate Modified Duration from Macaulay Duration. Vector modifiedDuration = cache.Get(); PricingFunctions.GetModifiedDuration(modifiedDuration, macaulayDuration, yield, fCouponInterval); // Get yield volatility fInterestYieldVol.GetValue(volatility, t, yield, yieldStrike, tExpiry, tMaturity - tSettle); // Convert (normal) yield vol to lognormal price vol volatility.MultiplyBy(modifiedDuration); if (fInterestYieldVol.GetDistributionType() == ProbabilityDistribution.Lognormal) { // Convert lognormal yield vol to lognormal price vol. volatility.MultiplyBy(yield); } } } else { volatility.Clear(); } } // Recalculate forward price using fAccruals double accrual, cash; PricingFunctions.BondPrice(forwardPrice, out accrual, out cash, baseDate, valueDate, deal.Settlement_Date, fIssueDate, fMaturityDate, 1.0, fCouponRate, fPayDates, fAccruals, fDiscountRate, null, null, 0.0, fSurvivalProb, 1.0); BondFutureValuation.AdjustForDefault(baseDate, valueDate, forwardPrice, deal.Expiry_Date, Respect_Default == YesNo.Yes && !string.IsNullOrEmpty(deal.Issuer), fUnderlyingIsAlive, fHistoricalRecovery, fDefaultTime, fDiscountRate, fRecoveryRate); forwardPrice.AssignQuotient(forwardPrice, discountFactor); if (!fRepoIsDiscount) { fRepoRate.GetValue(discountFactor, t, tSettle); } }
/// <inheritdoc /> protected override void GetFuturesPriceFactor(PriceFactorList factors) { BondFutureOption deal = (BondFutureOption)fDeal; fFuturesBasis = factors.Get <BondFuturesBasis>(FutureBase.GetFactorID(deal.Contract, deal.Settlement_Date)); }