/// <summary> /// Calculate valuation profiles. /// </summary> public override void Value(ValuationResults valuationResults, PriceFactorList factors, BaseTimeGrid baseTimes) { base.Value(valuationResults, factors, baseTimes); var accruedResults = valuationResults.Results <AccruedInterest>(); if (accruedResults == null) { return; } using (var cache = Vector.Cache(factors.NumScenarios)) { Vector accruedInterest = cache.Get(); var deal = (CFEquityFloatingInterestListDeal)Deal; var tgi = new TimeGridIterator(fT); var equityParams = new EquityCashflowParams((EquityPrice)fEquity, (EquityPriceVol)fEquityVol, fEquityFXRate, fEquityPayoffFXRate, deal.GetEquityPayoffType(), fEquityQuantoCompo, null, null); while (tgi.Next()) { deal.Cashflows.CalculateAccrual(accruedInterest, equityParams, factors.BaseDate, tgi.Date, accruedResults.AccrueFromToday, deal.GetHolidayCalendar(), deal.Accrual_Day_Count, fForecastRate, fFxRate); accruedResults.SetValue(tgi.Date, fBuySellSign * accruedInterest); } } }
/// <summary> /// Calculate valuation profiles. /// </summary> public override void Value(ValuationResults valuationResults, PriceFactorList factors, BaseTimeGrid baseTimes) { base.Value(valuationResults, factors, baseTimes); var deal = (CFFloatingInterestListDeal)Deal; CalculateMetrics(valuationResults, factors, deal); var accruedResults = valuationResults.Results <AccruedInterest>(); if (accruedResults == null) { return; } using (var cache = Vector.Cache(factors.NumScenarios)) { Vector accruedInterest = cache.Get(); var tgi = new TimeGridIterator(fT); VectorEngine.For(tgi, () => { fCashflows.CalculateAccrual(accruedInterest, factors.BaseDate, tgi.Date, accruedResults.AccrueFromToday, deal.GetHolidayCalendar(), fForecastRate); accruedResults.SetValue(tgi.Date, fBuySellSign * accruedInterest); }); } }
/// <summary> /// Calculate valuation metrics requested by the Base Valuation calculation. /// </summary> private void CalculateMetrics(ValuationResults valuationResults, PriceFactorList factors, CFFixedInterestListDeal deal) { var results = valuationResults.Results <ValuationMetrics>(); if (results == null) { return; } if (results.IsMetricRequested(ValuationMetricConstants.Duration)) { using (var cache = Vector.Cache(factors.NumScenarios)) { Vector duration = cache.GetClear(); Vector settlementDate = cache.Get(deal.Settlement_Date); deal.Cashflows.Duration(duration, factors.BaseDate, factors.BaseDate, settlementDate, fDiscountRate, fCutoffDate); results.SetMetricValue(ValuationMetricConstants.Duration, new ValuationId(this), duration[0]); } } if (results.IsMetricRequested(ValuationMetricConstants.AccruedInterest)) { double?parameter = results.GetMetricParameter(ValuationMetricParameterConstants.AccrueFromToday); bool accrueFromToday = parameter.HasValue && parameter.Value == 1.0; double accruedInterest = deal.Cashflows.CalculateAccrual(factors.BaseDate, accrueFromToday, deal.GetHolidayCalendar()); double buySellSign = deal.Buy_Sell == BuySell.Buy ? 1.0 : -1.0; results.SetMetricValue(ValuationMetricConstants.AccruedInterest, new ValuationId(this), buySellSign * accruedInterest); } }
/// <summary> /// Calculate valuation metrics requested by the Base Valuation calculation. /// </summary> private void CalculateMetrics(ValuationResults valuationResults, PriceFactorList factors, CFFloatingInterestListDeal deal) { var results = valuationResults.Results <ValuationMetrics>(); if (results == null) { return; } if (results.IsMetricRequested(ValuationMetricConstants.AccruedInterest)) { using (var cache = Vector.Cache(factors.NumScenarios)) { double?parameter = results.GetMetricParameter(ValuationMetricParameterConstants.AccrueFromToday); bool accrueFromToday = parameter.HasValue && parameter.Value == 1.0; Vector accruedInterest = cache.GetClear(); fCashflows.CalculateAccrual(accruedInterest, factors.BaseDate, factors.BaseDate, accrueFromToday, deal.AccrualHolidayCalendar(), fForecastRate); double buySellSign = deal.Buy_Sell == BuySell.Buy ? 1.0 : -1.0; results.SetMetricValue(ValuationMetricConstants.AccruedInterest, new ValuationId(this), buySellSign * accruedInterest[0]); } } }
/// <summary> /// Calculate valuation profiles. /// </summary> public override void Value(ValuationResults valuationResults, PriceFactorList factors, BaseTimeGrid baseTimes) { base.Value(valuationResults, factors, baseTimes); var deal = (CFFixedInterestListDeal)Deal; CalculateMetrics(valuationResults, factors, deal); var accruedResults = valuationResults.Results <AccruedInterest>(); if (accruedResults == null) { return; } var tgi = new TimeGridIterator(fT); while (tgi.Next()) { double accruedInterest = deal.Cashflows.CalculateAccrual(tgi.Date, accruedResults.AccrueFromToday, fDeal.GetHolidayCalendar()); accruedResults.SetValue(tgi.Date, fBuySellSign * accruedInterest); } }
/// <summary> /// Value the deal. /// </summary> public override void Value(ValuationResults valuationResults, PriceFactorList factors, BaseTimeGrid baseTimes) { PreValue(factors); CallableBondForward deal = (CallableBondForward)Deal; double baseDate = factors.BaseDate; double settlementDate = deal.Settlement_Date; double tSettle = CalcUtils.DaysToYears(settlementDate - baseDate); TimeGridIterator tgi = new TimeGridIterator(fT); PVProfiles result = valuationResults.Profile; AccruedInterest accrued = valuationResults.Results <AccruedInterest>(); var intraValuationDiagnosticsWriter = IntraValuationDiagnosticsWriterFactory.GetOrCreate(IntraValuationDiagnosticsLevel.None); using (var outerCache = Vector.Cache(factors.NumScenarios)) { // SwapOptionPricerObject is null when there are no valid exercise dates. SwaptionPricer.WorkingArrays arrays = fSwaptionPricer != null?fSwaptionPricer.PreValue(fDiscountRate, outerCache) : null; Vector tExercise = outerCache.Get(double.PositiveInfinity); // time of exercise int numberScenariosExercised = 0; Vector defaultDate = fCreditRating != null?outerCache.Get(CalcUtils.DateTimeMaxValueAsDouble) : null; var defaultedBeforeBaseDate = fNeedsCreditRating && CreditRating.DefaultedBeforeBaseDate(fCreditRating, baseDate); VectorEngine.For(tgi, () => { using (var cache = Vector.Cache(factors.NumScenarios)) { Vector cash = cache.GetClear(); Vector pv = cache.GetClear(); if (defaultedBeforeBaseDate || numberScenariosExercised == factors.NumScenarios) { // already defaulted before base date or All scenarios exercised result.AppendVector(tgi.Date, pv); return(LoopAction.Break); } else { // Value of the bond cashflows after the settlement. fCashflowList.Value(pv, cash, null, baseDate, tgi.Date, null, fDiscountRate, fSurvivalProb, null, null, intraValuationDiagnosticsWriter, 0.0); // Add the value of the principal and amortization cashflows. fFixedCashflowList.Value(pv, cash, baseDate, tgi.Date, null, fDiscountRate, fSurvivalProb, intraValuationDiagnosticsWriter, 0.0); if (fSurvivalProb != null) { fRecoveryList.Value(pv, baseDate, tgi.Date, fDiscountRate, fSurvivalProb, intraValuationDiagnosticsWriter); } if (fNeedsCreditRating) { UpdateDefaultDate(fCreditRating, tgi.Date, tgi.T, defaultDate); } // Add/subtract value of option if (fSwaptionPricer != null) { using (var innerCache = Vector.Cache(factors.NumScenarios)) { Vector optionPv = innerCache.Get(); Vector exerciseStrike = innerCache.GetClear(); // strike of underlying at exercise Vector exerciseFee = innerCache.GetClear(); // fee paid on exercise fSwaptionPricer.Value(optionPv, tgi.T, fDiscountRate, fInterestYieldVol, fSurvivalProb, arrays, tExercise, exerciseStrike, exerciseFee, Early_Exercise_Today == YesNo.Yes, ref numberScenariosExercised); // Ignore optionality if in default. if (fNeedsCreditRating) { optionPv.AssignConditional(defaultDate > tgi.Date, optionPv, 0.0); } pv.Add(optionPv); } } if (tgi.Date < settlementDate) { // Forward deal before settlement date if (deal.Is_Defaultable == YesNo.No) { pv.Assign((pv / fDiscountRate.Get(tgi.T, tSettle) - fSettlementAmount) * fRepoRate.Get(tgi.T, tSettle)); } else { pv.Subtract((fSettlementAmount - fAccrued) * fRepoRate.Get(tgi.T, tSettle) + fAccrued * fDiscountRate.Get(tgi.T, tSettle)); // discount accrued with bond rate; accrued interest must cancel } } else if (tgi.Date == settlementDate) { // Forward deal at settlement date pv.Subtract(fSettlementAmount); cash.Subtract(fSettlementAmount); } if (deal.IsForward()) { // Cash settled forward if (tgi.Date == settlementDate) { cash.Assign(pv); } else { cash.Clear(); } } else if (tgi.Date >= settlementDate) { using (var innerCache = Vector.Cache(factors.NumScenarios)) { Vector afterExercise = innerCache.Get(tExercise < tgi.T); Vector beforeExercise = innerCache.Get(tExercise > tgi.T); Vector exercisedToday = innerCache.GetClear(); exercisedToday.Assign(afterExercise.Or(beforeExercise)); exercisedToday.Assign(!exercisedToday); double callAmount = deal.Notional * Percentage.PercentagePoint * deal.Call_Prices.GetRate(tgi.Date); // Before exercise: pv is bondPV + optionPv and cash is bondCash. // On exercise: pv and cash are bondCash + callAmount. // After exercise: pv and cash are zero. cash.AssignConditional(exercisedToday, cash + callAmount, beforeExercise * cash); pv.AssignConditional(exercisedToday, cash, beforeExercise * pv); } } // Apply leg sign to results int buySellSign = deal.Buy_Sell == BuySell.Buy ? +1 : -1; ApplySign(pv, cash, buySellSign); if (fNeedsCreditRating) { Vector beforeExercise = cache.Get(tExercise > tgi.T); Vector modifiedDefaultDate = cache.Get(); // If default occurs after the call option has been exercise, default is irrelevant. // If default occurs on the same date that the call option is exercised, the assumption // is that the bond has been paid back in full, otherwise it wouldn''t be considered exercised. modifiedDefaultDate.AssignConditional(beforeExercise, defaultDate, double.PositiveInfinity); GetDefaultValue(baseDate, tgi.Date, modifiedDefaultDate, fRecoveryRate, pv, cash); } valuationResults.Cash.Accumulate(fFxRate, tgi.Date, cash); result.AppendVector(tgi.Date, pv * fFxRate.Get(tgi.T)); if (accrued != null) { accrued.SetValue(tgi.Date, fCashflowList.CalculateAccrual(tgi.Date, accrued.AccrueFromToday, fDeal.GetHolidayCalendar()) * buySellSign); } } } return(LoopAction.Continue); }); } result.Complete(fT); }
/// <summary> /// Aggregate the valuation profile onto a set of result curves to support result partitioning. /// </summary> protected override void ProcessResults(ValuationResults valResults, DealPartitionAssociations assoc, PriceFactorList factors, BaseTimeGrid baseTimes, ValuationOptions options, int partition) { var pvProfiles = valResults.Results <PVProfiles>(); var addOnProfiles = valResults.Results <AddOnProfiles>(); var positiveMtmProfiles = valResults.Results <PositiveMtmProfiles>(); Debug.Assert(addOnProfiles != null, "No Add-On profiles. Cannot proceed with valuation."); Debug.Assert(positiveMtmProfiles != null, "No Positive mtM profiles. Cannot proceed with valuation."); fT = Deal.ValuationGrid(factors, baseTimes, Deal.EndDate()); var tgi = new TimeGridIterator(fT); var nettedExposure = new PVProfiles(factors.NumScenarios); var collateralExposure = new PVProfiles(factors.NumScenarios); var addOnsProfile = new PVProfiles(factors.NumScenarios); var mtmTermProfile = new PVProfiles(factors.NumScenarios); DealBaselNettingCollateralSet nettingSetDeal = Deal as DealBaselNettingCollateralSet; bool collateralised = nettingSetDeal.Collateralised == YesNo.Yes; using (var cache = Vector.Cache(factors.NumScenarios)) { Vector sumMtm = cache.Get(); Vector sumPositiveMtm = cache.Get(); Vector addOns = cache.Get(); Vector netGrossRatio = cache.Get(); Vector value = cache.Get(); Vector term1 = cache.Get(); Vector term2 = cache.Get(); // Collateral related vectors. Vector mtmTermStart = cache.Get(); Vector addOnHp = cache.Get(); // Loop to get the netting set exposure. while (tgi.Next()) { sumMtm.Clear(); sumPositiveMtm.Clear(); addOns.Clear(); value.Clear(); double date = tgi.Date; // For MtM Plus Add-On deals PV profiles represents the sum of the MtM profile and Add-On profile. // Subtract the Add-On profile to recover the MtM profile before flooring. sumMtm.Assign(VectorMath.Max(pvProfiles[date] - addOnProfiles[date], 0.0)); addOns.Assign(addOnProfiles[date]); sumPositiveMtm.Assign(positiveMtmProfiles[date]); netGrossRatio.AssignConditional(sumPositiveMtm > 0, sumMtm / sumPositiveMtm, 0.0); netGrossRatio.MultiplyBy(this.fNetGrossRatioCorrelation); netGrossRatio.Add(1 - this.fNetGrossRatioCorrelation); term2.AssignProduct(addOns, netGrossRatio); term1.Assign(VectorMath.Max(sumMtm, 0.0)); value.AssignSum(term1, term2); nettedExposure.AppendVector(date, value); if (collateralised) { mtmTermProfile.AppendVector(date, term1); addOnsProfile.AppendVector(date, term2); } } nettedExposure.Complete(this.fT); var exposureResults = valResults.Results <Exposure>(); if (exposureResults != null) { exposureResults.Assign(nettedExposure); } // Collateral cases. if (collateralised) { mtmTermProfile.Complete(this.fT); addOnsProfile.Complete(this.fT); double date = factors.BaseDate; mtmTermProfile.GetValue(mtmTermStart, date); addOnsProfile.GetValue(addOnHp, date + nettingSetDeal.Holding_Period); // Assume we have post haircut collateral. double collateral = nettingSetDeal.Balance; double threshold = nettingSetDeal.Threshold; tgi.Reset(); // Loop to get the netting set exposure. while (tgi.Next()) { bool inHoldingPeriod = tgi.T < CalcUtils.DaysToYears(nettingSetDeal.Holding_Period); CollateralBasel3(mtmTermStart, collateral, addOnHp, threshold, inHoldingPeriod, tgi.Date, nettedExposure, collateralExposure); } collateralExposure.Complete(this.fT); if (exposureResults != null) { exposureResults.Assign(collateralExposure); } } } if (options.PartitionCollateralMode != PartitionCollateralMode.Suppress_Collateral_And_Flooring || partition < options.NumTotalPartitions) { valResults.FloorResult(assoc.AggregationMode, options); } CollateralPlugIn.CollateralBalancesContainer coProfiles = valResults.Results <CollateralPlugIn.CollateralBalancesContainer>(); // Store collateral information according to diagnostic collection rules. if (coProfiles != null) { coProfiles.StoreInformation(this); } }
/// <summary> /// Calculate valuation profiles. /// </summary> public override void Value(ValuationResults valuationResults, PriceFactorList factors, BaseTimeGrid baseTimes) { PreValue(factors); var result = valuationResults.Profile; var cashAccumulator = valuationResults.Cash; var accruedResults = valuationResults.Results <AccruedInterest>(); var deal = (IInflationCashflowListDeal)Deal; double sign = deal.Buy_Sell == BuySell.Buy ? 1.0 : -1.0; var cashflows = deal.GetCashflows(); var calendar = deal.GetHolidayCalendar(); double baseDate = factors.BaseDate; var tgi = new TimeGridIterator(fT); CalculateMetrics(valuationResults, factors, deal); using (IntraValuationDiagnosticsHelper.StartDeal(fIntraValuationDiagnosticsWriter, fDeal)) { using (var cache = Vector.Cache(factors.NumScenarios)) { Vector defaultDate = null; if (!fIsDefaultNever) { defaultDate = fCreditRating != null?cache.Get(CalcUtils.DateTimeMaxValueAsDouble) : null; } Vector pv = cache.GetClear(); Vector cash = cashAccumulator.Ignore ? null : cache.Get(); Vector accruedInterest = cache.GetClear(); VectorEngine.For(tgi, () => { if (!fIsDefaultNever && CreditRating.DefaultedBeforeBaseDate(fCreditRating, baseDate)) { result.AppendVector(tgi.Date, pv); return(LoopAction.Break); } using (IntraValuationDiagnosticsHelper.StartCashflowsOnDate(fIntraValuationDiagnosticsWriter, tgi.Date)) { using (IntraValuationDiagnosticsHelper.StartCashflows(fIntraValuationDiagnosticsWriter, fFxRate, tgi.T, fDeal)) { cashflows.Value(pv, cash, baseDate, tgi.Date, deal.Settlement_Date, fInflationRate, fIndexVolatility, fDiscountRate, fRepoRate, fSurvivalProb, sign, fIntraValuationDiagnosticsWriter); IntraValuationDiagnosticsHelper.AddCashflowsPV(fIntraValuationDiagnosticsWriter, pv); if (fRecoveryCashflowList != null && fRecoveryCashflowList.Items.Count > 0) { fRecoveryCashflowList.Value(pv, cash, baseDate, tgi.Date, deal.Settlement_Date, fDiscountRate, fRepoRate, fInflationRate, fSurvivalProb, sign); } // Temporary fix up to avoid calculating default when we know the model doesn't support default if (!fIsDefaultNever) { UpdateDefaultDate(fCreditRating, tgi.Date, tgi.T, defaultDate); GetDefaultValue(baseDate, tgi.Date, defaultDate, fInflationRate, fIndexVolatility, fRepoRate, pv, cash); } result.AppendVector(tgi.Date, fFxRate.Get(tgi.T) * pv); if (cash != null) { cashAccumulator.Accumulate(fFxRate, tgi.Date, cash); } if (accruedResults != null) { cashflows.CalculateAccrual(accruedInterest, baseDate, tgi.Date, accruedResults.AccrueFromToday, calendar, fInflationRate, fIndexVolatility, sign); accruedResults.SetValue(tgi.Date, accruedInterest); } else if (fIntraValuationDiagnosticsWriter.Level > IntraValuationDiagnosticsLevel.None) { cashflows.CalculateAccrual(accruedInterest, baseDate, tgi.Date, false, calendar, fInflationRate, fIndexVolatility, sign); } IntraValuationDiagnosticsHelper.AddCashflowsAccruedInterest(fIntraValuationDiagnosticsWriter, accruedInterest); } } return(LoopAction.Continue); }); // On investment horizon or a bond forward's Settlement Date, the deal value is liquidated as cash. double endDate = Deal.EndDate(); if (cash != null && endDate <= fT.fHorizon) { // If endDate on a payment date, cashflow has already been accummulated (as cash), otherwise is 0. // Value liquidated is the value of the pv remaining after accummulating the cashflow. cash.AssignDifference(pv, cash); cashAccumulator.Accumulate(fFxRate, endDate, cash); } } result.Complete(fT); } }