/// <summary> /// Register price factors used in valuation. /// </summary> public override void RegisterFactors(PriceFactorList factors, ErrorList errors) { base.RegisterFactors(factors, errors); CFFloatingInterestListDeal deal = (CFFloatingInterestListDeal)Deal; // Deal validation specific to CFFloatingInterestListValuation foreach (var cashflow in deal.Cashflows) { if (!cashflow.Resets.Any()) { continue; } var lastResetDate = cashflow.Resets.Last().Reset_Date; if (cashflow.FX_Reset_Date > 0.0 && cashflow.FX_Reset_Date < lastResetDate) { errors.Add(ErrorLevel.Warning, string.Format("Quanto adjustments for cashflow paying on {0} are not supported when the FX reset date {1} is before interest rate reset date {2}", cashflow.Payment_Date, cashflow.FX_Reset_Date, lastResetDate)); } } // Get characteristics CashflowListCharacteristics characteristics = deal.Cashflows.Analyze(factors.BaseDate); bool quanto = fForecastIsForeign && characteristics.HasQuanto && Quanto_Correction == YesNo.Yes; bool convexity = !characteristics.IsStandardLibor && Convexity_Correction == YesNo.Yes; var requirements = new VolatilityRequirements( characteristics.HasCms, characteristics.HasLibor && (characteristics.HasOptionlet || convexity || quanto), characteristics.HasCms && convexity, characteristics.HasLibor && convexity); // Collect registered volatility price factors to check they have the same distribution type var volPriceFactors = new List <IInterestVol>(); // register forecast rate volatility surfaces if (requirements.NeedForecastYieldVol) { volPriceFactors.Add(InterestVolBase.RegisterInterestYieldVol(factors, deal.Forecast_Rate_Swaption_Volatility, fForecastCurrency)); } if (requirements.NeedForecastRateVol) { volPriceFactors.Add(InterestVolBase.RegisterInterestRateVol(factors, deal.Forecast_Rate_Cap_Volatility, fForecastCurrency)); } if (requirements.NeedDiscountYieldVol) { volPriceFactors.Add(InterestVolBase.RegisterInterestYieldVol(factors, deal.Discount_Rate_Swaption_Volatility, fCurrency)); } if (requirements.NeedDiscountRateVol) { volPriceFactors.Add(InterestVolBase.RegisterInterestRateVol(factors, deal.Discount_Rate_Cap_Volatility, fCurrency)); } if (fForecastIsForeign) { // Register factor for translation from forecast rate currency to settlement currency for cashflows with FX reset date if (characteristics.HasFXReset) { factors.RegisterInterface <IFxRate>(fForecastCurrency); } if (quanto) { FXVolHelper.Register(factors, fForecastCurrency, fCurrency); CorrelationHelper.Register(factors, typeof(IInterestRate), fForecastCurrency, null, typeof(IFxRate), fForecastCurrency, fCurrency); CorrelationHelper.Register(factors, typeof(IInterestRate), fForecastCurrency, null, typeof(IInterestRate), fCurrency, null); } } if (volPriceFactors.Select(pf => pf.GetDistributionType()).Distinct().Count() > 1) { deal.AddToErrors(errors, "Volatility price factors must have the same distribution type."); } ValidateUnnecessaryVolatilities(deal, requirements, errors); }
/// <summary> /// Warn of unnecessary volatility surface definitions. /// </summary> /// <remarks> /// Test differently if the cap and swaption volatility definitions are the same or /// distinct because they may have been set by a single property or two distinct ones. /// </remarks> private static void ValidateUnnecessaryVolatilities(CFFloatingInterestListDeal deal, VolatilityRequirements requirements, ErrorList errors) { if (deal.Discount_Rate_Cap_Volatility == deal.Discount_Rate_Swaption_Volatility) { if (!requirements.NeedDiscountRateVol && !requirements.NeedDiscountYieldVol && !string.IsNullOrEmpty(deal.Discount_Rate_Cap_Volatility)) { deal.AddToErrors(errors, ErrorLevel.Info, $"Unnecessary {nameof(deal.Discount_Rate_Cap_Volatility)} and {nameof(deal.Discount_Rate_Swaption_Volatility)} {deal.Discount_Rate_Cap_Volatility}."); } } else { if (!requirements.NeedDiscountRateVol && !string.IsNullOrEmpty(deal.Discount_Rate_Cap_Volatility)) { deal.AddToErrors(errors, ErrorLevel.Info, $"Unnecessary {nameof(deal.Discount_Rate_Cap_Volatility)} {deal.Discount_Rate_Cap_Volatility}."); } if (!requirements.NeedDiscountYieldVol && !string.IsNullOrEmpty(deal.Discount_Rate_Swaption_Volatility)) { deal.AddToErrors(errors, ErrorLevel.Info, $"Unnecessary {nameof(deal.Discount_Rate_Swaption_Volatility)} {deal.Discount_Rate_Swaption_Volatility}."); } } if (deal.Forecast_Rate_Cap_Volatility == deal.Forecast_Rate_Swaption_Volatility) { if (!requirements.NeedForecastRateVol && !requirements.NeedForecastYieldVol && !string.IsNullOrEmpty(deal.Forecast_Rate_Cap_Volatility)) { deal.AddToErrors(errors, ErrorLevel.Info, $"Unnecessary {nameof(deal.Forecast_Rate_Cap_Volatility)} and {nameof(deal.Forecast_Rate_Swaption_Volatility)} {deal.Forecast_Rate_Cap_Volatility}."); } } else { if (!requirements.NeedForecastRateVol && !string.IsNullOrEmpty(deal.Forecast_Rate_Cap_Volatility)) { deal.AddToErrors(errors, ErrorLevel.Info, $"Unnecessary {nameof(deal.Forecast_Rate_Cap_Volatility)} {deal.Forecast_Rate_Cap_Volatility}."); } if (!requirements.NeedForecastYieldVol && !string.IsNullOrEmpty(deal.Forecast_Rate_Swaption_Volatility)) { deal.AddToErrors(errors, ErrorLevel.Info, $"Unnecessary {nameof(deal.Forecast_Rate_Swaption_Volatility)} {deal.Forecast_Rate_Swaption_Volatility}."); } } }