/// <summary> /// Value the fixed and floating legs of the swap. /// </summary> private void ValueFixedAndFloatingLegs(TimeGridIterator tgi, Vector fixedPv, Vector fixedCash, double baseDate, Vector floatPv, Vector floatCash) { using (IntraValuationDiagnosticsHelper.StartCashflowsOnDate(fIntraValuationDiagnosticsWriter, tgi.Date)) { using (IntraValuationDiagnosticsHelper.StartSwaptionCashflows(fIntraValuationDiagnosticsWriter, fFxRate, tgi.T, CashflowType.FixedLeg, fSwaptionDeal.Floating_Margin)) { // Calculate value of fixed side fixedPv.Clear(); fixedCash.Clear(); fFixedCashflowList.Value(fixedPv, fixedCash, null, baseDate, tgi.Date, null, fDiscountRate, null, null, null, fIntraValuationDiagnosticsWriter, 0.0); IntraValuationDiagnosticsHelper.AddCashflowsPV(fIntraValuationDiagnosticsWriter, fixedPv); } using (IntraValuationDiagnosticsHelper.StartSwaptionCashflows(fIntraValuationDiagnosticsWriter, fFxRate, tgi.T, CashflowType.FloatingLeg, fSwaptionDeal.Floating_Margin)) { // Calculate value of floating side floatPv.Clear(); floatCash.Clear(); fFloatCashflowList.ValueSwap(floatPv, floatCash, null, baseDate, tgi.Date, null, 0.0, fDiscountRate, fForecastRate, false, fIntraValuationDiagnosticsWriter); IntraValuationDiagnosticsHelper.AddCashflowsPV(fIntraValuationDiagnosticsWriter, floatPv); } } }
/// <summary> /// Calculate vector valuation profile and vector realised cash profile. /// </summary> public override void Value(ValuationResults valuationResults, PriceFactorList factors, BaseTimeGrid baseTimes) { PreValue(factors); CalcUtils.CreateDealProfilesIfRequired(valuationResults, fItems, factors); double paySign = fSwaptionDeal.Payer_Receiver == PayerReceiver.Payer ? +1 : -1; double buySign = fSwaptionDeal.Buy_Sell == BuySell.Buy ? +1 : -1; bool isCashSettled = fSwaptionDeal.Settlement_Style == SettlementType.Cash; bool isPhysicallySettled = fSwaptionDeal.Settlement_Style == SettlementType.Physical; bool cashRequired = !valuationResults.Cash.Ignore; TimeGridIterator tgi = new TimeGridIterator(fT); PVProfiles result = valuationResults.Profile; using (IntraValuationDiagnosticsHelper.StartDeal(fIntraValuationDiagnosticsWriter, Deal)) { using (var outerCache = Vector.Cache(factors.NumScenarios)) { Vector pv = outerCache.Get(); Vector exerciseWeight = outerCache.GetClear(); Vector cash = cashRequired ? outerCache.GetClear() : null; // For a cash settled swaption, Settlement amount to be paid on Settlement Date. Vector settlementCash = isCashSettled ? outerCache.GetClear() : null; VectorEngine.For(tgi, () => { // Work out the PV if (tgi.Date < fSwaptionDeal.Option_Expiry_Date) { ValueBeforeExpiry(pv, factors, isCashSettled, tgi); } else { ValueOnOrAfterExpiry(pv, exerciseWeight, settlementCash, cash, factors, isCashSettled, isPhysicallySettled, cashRequired, tgi, paySign); } result.AppendVector(tgi.Date, buySign * pv * fFxRate.Get(tgi.T)); if (cashRequired) { valuationResults.Cash.Accumulate(fFxRate, tgi.Date, buySign * cash); } }); } result.Complete(fT); } }
/// <summary> /// Value the deal. /// </summary> /// <param name="pv">Present value to be updated.</param> /// <param name="cash">Realised cash to be updated.</param> public override void Value(Vector pv, Vector cash, double baseDate, double valueDate, ISACCRResult saccrResult, IIntraValuationDiagnosticsWriter intraValuationDiagnosticsWriter) { Value(pv, cash, baseDate, valueDate, null, fDiscountRate, null, fRepoRate, null, null, fSurvivalProb, saccrResult, intraValuationDiagnosticsWriter); // Add accruedInterest to Intra-valuation diagnostics if (intraValuationDiagnosticsWriter.Level > IntraValuationDiagnosticsLevel.None) { CFFixedInterestListDeal deal = (CFFixedInterestListDeal)Deal; using (var cache = Vector.CacheLike(pv)) { Vector accruedInterest = cache.Get(deal.Cashflows.CalculateAccrual(valueDate, false, deal.GetHolidayCalendar())); IntraValuationDiagnosticsHelper.AddCashflowsAccruedInterest(fIntraValuationDiagnosticsWriter, accruedInterest); } } }
/// <summary> /// Output Intra-Valuation Diagnostics (Base correlation at Attachment and Detachment) /// </summary> public override void AddIntraValuationDiagnostics(IIntraValuationDiagnosticsWriter intraValuationDiagnosticsWriter, CDOValuationParameters parameters, Vector adjustedAttachment, Vector adjustedDetachment, Vector remainingPool, double valueTime, double tPay) { if (intraValuationDiagnosticsWriter.Level == IntraValuationDiagnosticsLevel.None) { return; } using (var cache = Vector.CacheLike(adjustedAttachment)) { var paramsCDO = (CDOBottomUpValuationParameters)parameters; Vector rhoAttachment = cache.Get(); Vector rhoDetachment = cache.Get(); paramsCDO.IndexCDO.GetBaseCorrelation(rhoAttachment, adjustedAttachment, remainingPool, valueTime, tPay); paramsCDO.IndexCDO.GetBaseCorrelation(rhoDetachment, adjustedDetachment, remainingPool, valueTime, tPay); IntraValuationDiagnosticsHelper.AddBaseCorrelation(intraValuationDiagnosticsWriter, rhoAttachment, rhoDetachment); } }
/// <summary> /// Value a caplet or floorlet under the 1 factor Hull-White model. /// </summary> public override void Value(Vector pv, Vector cash, double baseDate, double valueDate, ISACCRResult saccrResult, IIntraValuationDiagnosticsWriter intraValuationDiagnosticsWriter) { int count = fCashflows.Count(); bool forecastIsDiscount = ReferenceEquals(fForecastRate, fDiscountRate); // time of dfStart and dfEnd double tDfStart = double.NegativeInfinity; double tDfEnd = double.NegativeInfinity; using (var cache = Vector.CacheLike(pv)) { // Shared between loops Vector dfStart = cache.Get(); Vector dfEnd = cache.Get(); VectorEngine.For(0, count, LoopDirection.Backwards, i => { using (var innerCache = Vector.CacheLike(pv)) { CFFloatingInterest cashflow = fCashflows[i]; if (cashflow.Payment_Date < valueDate || cashflow.Payment_Date <= fCutoffDate) { return(LoopAction.Break); } Vector rate = innerCache.Get(); Vector dfPay = innerCache.Get(); Vector stdDev = innerCache.GetClear(); Vector amount = innerCache.GetClear(); GeneralCashflowProperties properties = fCashflows.GetCashflowProperties(i); double tPay = CalcUtils.DaysToYears(cashflow.Payment_Date - baseDate); bool haveDfPay = false; if (forecastIsDiscount && tPay == tDfStart) { dfPay.Assign(dfStart); haveDfPay = true; } using (IntraValuationDiagnosticsHelper.StartCashflow(intraValuationDiagnosticsWriter)) using (var volatilitiesAtDateStore = IntraValuationDiagnosticsHelper.CreateVolatilitiesAtDateStore(intraValuationDiagnosticsWriter, pv.Count)) { cashflow.AddPropertiesToIntraValuationDiagnostics(intraValuationDiagnosticsWriter); // Standard Libor implies single reset. var reset = cashflow.Resets.Single(); if (reset.IsKnown(baseDate)) { rate.Assign(reset.Known_Rate); } else { double tValue = CalcUtils.DaysToYears(valueDate - baseDate); double tReset = CalcUtils.DaysToYears(reset.Reset_Date - baseDate); double tStart = CalcUtils.DaysToYears(reset.Rate_Start_Date - baseDate); double tEnd = CalcUtils.DaysToYears(reset.Rate_End_Date - baseDate); // Reset is a historical or forward Libor rate. InterestRateUtils.LiborRate(rate, fForecastRate, tValue, tReset, tStart, tEnd, reset.Rate_Year_Fraction, dfStart, ref tDfStart, dfEnd, ref tDfEnd); if (tReset > tValue) { GetStandardDeviation(stdDev, tValue, tReset, tStart, tEnd); volatilitiesAtDateStore.Add(valueDate, reset.Reset_Date, stdDev); } } if (!haveDfPay && forecastIsDiscount && tPay == tDfEnd) { dfPay.Assign(dfEnd); haveDfPay = true; } // Add swaplet value amount.AddProduct(properties.Swap_Multiplier, rate); double tau = reset.Rate_Year_Fraction; rate.Assign(1.0 + rate * tau); // Add cap and floor option values. AddOptionValue(amount, OptionType.Call, rate, properties.Cap_Strike, stdDev, tau, properties.Cap_Multiplier); AddOptionValue(amount, OptionType.Put, rate, properties.Floor_Strike, stdDev, tau, properties.Floor_Multiplier); amount.Assign(fBuySellSign * (cashflow.Fixed_Amount + cashflow.Notional * (amount + cashflow.Margin) * cashflow.Accrual_Year_Fraction)); IntraValuationDiagnosticsHelper.AddImpliedVolatilities(intraValuationDiagnosticsWriter, volatilitiesAtDateStore); CFFixedList.RoundCashflow(amount, Cashflow_Rounding); CFFixedList.UpdatePvAndCash(cashflow, baseDate, valueDate, haveDfPay ? null : fDiscountRate, null, amount, dfPay, pv, cash, intraValuationDiagnosticsWriter); } } return(LoopAction.Continue); }); } }
/// <summary> /// Valuation method. /// </summary> public override void Value(ValuationResults valuationResults, PriceFactorList factors, BaseTimeGrid baseTimes) { CDOValuationParameters parameters = GetValuationParameters(factors); double scale = (fDeal.Buy_Sell == BuySell.Buy) ? +fDeal.Principal : -fDeal.Principal; double trancheSize = fDeal.Detachment - fDeal.Attachment; if (trancheSize < CalcUtils.TINY) { return; } double tUpfront = CalcUtils.DaysToYears(fDeal.Upfront_Date - factors.BaseDate); TimeGridIterator tgi = new TimeGridIterator(fT); CashAccumulators accumulator = valuationResults.Cash; PVProfiles result = valuationResults.Profile; using (IntraValuationDiagnosticsHelper.StartDeal(fIntraValuationDiagnosticsWriter, Deal)) { VectorEngine.For(tgi, () => { using (var cache = Vector.Cache(factors.NumScenarios)) { Vector npv = cache.Get(); Vector expectedWritedownPremiumNotional = cache.Get(); Vector expectedLoss = cache.Get(); Vector expectedRecovery = cache.Get(); Vector discountFactor = cache.Get(); Vector realizedIndexLoss = cache.Get(); Vector realizedIndexRecovery = cache.Get(); Vector adjustedAttachment = cache.Get(); Vector adjustedDetachment = cache.Get(); Vector trancheRemainder = cache.Get(); // Handle upfront payment if (fDeal.Upfront_Date >= tgi.Date) { npv.Assign(scale * parameters.DF.Get(tgi.T, tUpfront) * fDeal.Upfront_Amount); } else { npv.Clear(); } // reinitialise running variables expectedWritedownPremiumNotional.Clear(); expectedLoss.Clear(); expectedRecovery.Clear(); discountFactor.Assign(parameters.DF.Get(tgi.T, tgi.T)); if (accumulator != null && tgi.Date == fDeal.Upfront_Date) { accumulator.Accumulate(parameters.X, tgi.Date, fDeal.Upfront_Amount); } // Check for realized loss and recovery and adjust the attachment and detachment accordingly parameters.RealizedLoss(realizedIndexLoss, realizedIndexRecovery, tgi.T, fDeal.Payoff_Is_Digital == YesNo.Yes, fDeal.Digital_Payoff_Percentage); adjustedDetachment.Assign(VectorMath.Max(0.0, VectorMath.Min(1.0 - realizedIndexRecovery, fDeal.Detachment) - realizedIndexLoss)); adjustedAttachment.Assign(VectorMath.Max(0.0, VectorMath.Min(1.0 - realizedIndexRecovery, fDeal.Attachment) - realizedIndexLoss)); trancheRemainder.Assign((adjustedDetachment - adjustedAttachment) / trancheSize); if (adjustedDetachment.MaxElement() > CalcUtils.TINY) { // Diagnostics double sumDefaultAccrual = 0; double sumPVPremium = 0; double sumPVProtection = 0; bool needDiagnostics = tgi.T == 0.0 && fIntraValuationDiagnosticsWriter.Level > IntraValuationDiagnosticsLevel.None; using (needDiagnostics ? IntraValuationDiagnosticsHelper.StartCDO(fIntraValuationDiagnosticsWriter, tgi.Date, fDeal.Principal) : null) { // Value future coupon periods VectorEngine.For(0, PayDates.Count, i => { if (PayDates[i] < tgi.Date) { return(LoopAction.Continue); } double tPay = CalcUtils.DaysToYears(PayDates[i] - factors.BaseDate); using (var innerCache = Vector.CacheLike(npv)) { Vector oldExpectedLoss = innerCache.Get(expectedLoss); Vector oldDiscountFactor = innerCache.Get(discountFactor); Vector oldExpectedWritedownPremiumNotional = innerCache.Get(expectedWritedownPremiumNotional); Vector expectedLossAttachment = innerCache.Get(); Vector expectedLossDetachment = innerCache.Get(); Vector premiumLeg = innerCache.Get(); Vector defaultLeg = innerCache.Get(); Vector accruedInDefault = innerCache.Get(); Vector expectedRecoveryAttachment = innerCache.Get(); Vector expectedRecoveryDetachment = innerCache.Get(); Vector avgDiscountFactor = innerCache.Get(); Vector pv = innerCache.Get(); // Get the expected loss and recovery for the tranche detachment and attachment parameters.ExpectedLossAndRecovery(expectedLossDetachment, expectedRecoveryDetachment, tgi.T, tPay, adjustedDetachment, realizedIndexLoss, realizedIndexRecovery); parameters.ExpectedLossAndRecovery(expectedLossAttachment, expectedRecoveryAttachment, tgi.T, tPay, adjustedAttachment, realizedIndexLoss, realizedIndexRecovery); expectedLoss.Assign((expectedLossDetachment - expectedLossAttachment) / trancheSize); expectedRecovery.Assign((expectedRecoveryDetachment - expectedRecoveryAttachment) / trancheSize); expectedWritedownPremiumNotional.Assign(expectedLoss + expectedRecovery); // Premium leg approximation: Accrued in default pays half the accrued. Remove expected loss and recovery (top down writeoff) premiumLeg.Assign(fDeal.Spread * (trancheRemainder - expectedWritedownPremiumNotional) * Accruals[i]); accruedInDefault.Assign(fDeal.Spread * (expectedWritedownPremiumNotional - oldExpectedWritedownPremiumNotional) * 0.5 * Accruals[i]); // Default leg approximation: account for default with bullet payment at end of period defaultLeg.Assign(expectedLoss - oldExpectedLoss); // Convention: bought CDO pays the premium to the buyer discountFactor.Assign(parameters.DF.Get(tgi.T, tPay)); avgDiscountFactor.Assign(0.5 * (discountFactor + oldDiscountFactor)); pv.Assign(scale * (premiumLeg * discountFactor + (accruedInDefault - defaultLeg) * avgDiscountFactor)); npv.Add(pv); if (accumulator != null && tgi.T == tPay) { accumulator.Accumulate(parameters.X, tgi.Date, scale * (premiumLeg + accruedInDefault - defaultLeg)); } if (needDiagnostics) { using (var innerCache1 = Vector.CacheLike(npv)) { Vector expectedPremium = innerCache1.Get(scale * premiumLeg); Vector expectedDefaultAccrual = innerCache1.Get(scale * accruedInDefault); Vector expectedDefaultLoss = innerCache1.Get(scale * defaultLeg); Vector pvDefaultAccrual = innerCache1.Get(expectedDefaultAccrual * avgDiscountFactor); Vector pvPremium = innerCache1.Get(expectedPremium * discountFactor); Vector pvProctection = innerCache1.Get(-expectedDefaultLoss * avgDiscountFactor); // accumulate sums if (i >= 0) { sumDefaultAccrual += pvDefaultAccrual[0]; sumPVPremium += pvPremium[0]; sumPVProtection += pvProctection[0]; } using (IntraValuationDiagnosticsHelper.StartCashflow(fIntraValuationDiagnosticsWriter, PayDates[i])) { var remainingPool = cache.Get(1.0 - realizedIndexLoss - realizedIndexRecovery); AddIntraValuationDiagnostics(fIntraValuationDiagnosticsWriter, parameters, adjustedAttachment, adjustedDetachment, remainingPool, tgi.T, tPay); IntraValuationDiagnosticsHelper.AddDetailedCDOCashflow(fIntraValuationDiagnosticsWriter, expectedPremium, expectedRecovery, expectedDefaultAccrual, expectedDefaultLoss, discountFactor, pv); } } } } return(LoopAction.Continue); }); if (needDiagnostics) { IntraValuationDiagnosticsHelper.AddSummaryCDOAmounts(fIntraValuationDiagnosticsWriter, npv, sumDefaultAccrual, sumPVPremium, sumPVProtection); } } result.AppendVector(tgi.Date, npv * parameters.X.Get(tgi.T)); } } }); } // After maturity result.Complete(fT); }
/// <summary> /// Calculate valuation profiles. /// </summary> public override void Value(ValuationResults valuationResults, PriceFactorList factors, BaseTimeGrid baseTimes) { PreValue(factors); TimeGridIterator tgi = new TimeGridIterator(fT); PVProfiles result = valuationResults.Profile; CashAccumulators cashAccumulators = valuationResults.Cash; BondOptionDeal deal = (BondOptionDeal)Deal; double baseDate = factors.BaseDate; double notional = deal.Notional; double interval = deal.Coupon_Interval; double buySign = (deal.Buy_Sell == BuySell.Buy) ? +1 : -1; double paySign = (deal.Option_Type == OptionType.Call) ? +1 : -1; double coupon = Percentage.PercentagePoint * deal.Coupon_Rate; double tExpiry = CalcUtils.DaysToYears(deal.Expiry_Date - baseDate); double tMaturity = CalcUtils.DaysToYears(deal.Bond_Maturity_Date - baseDate); IInterestYieldVol interestYieldVol = InterestVolBase.GetYieldVol(factors, deal.Yield_Volatility, fCurrency); if ((deal.Amortisation) != null && (deal.Amortisation.Count > 0)) { notional = deal.Amortisation.GetPrincipal(notional, deal.Expiry_Date); } bool respectDefault = Respect_Default == YesNo.Yes && fCreditRating != null; using (IntraValuationDiagnosticsHelper.StartDeal(fIntraValuationDiagnosticsWriter, Deal)) { using (var pricerCache = Vector.Cache(factors.NumScenarios)) { Vector defaultTime = null; Vector bondIsAlive = null; Vector historicalRecovery = null; if (respectDefault) { defaultTime = pricerCache.Get(); bondIsAlive = pricerCache.Get(1.0); historicalRecovery = pricerCache.GetClear(); fCreditRating.DefaultTime(defaultTime); } var defaultedBeforeBaseDate = respectDefault && CreditRating.DefaultedBeforeBaseDate(fCreditRating, baseDate); VectorEngine.For(tgi, () => { using (IntraValuationDiagnosticsHelper.StartValuation(fIntraValuationDiagnosticsWriter, tgi.Date)) { using (var cache = Vector.Cache(factors.NumScenarios)) { Vector optionValue = cache.GetClear(); Vector stdDev = cache.Get(); // Std.Dev of Price Vector stdDevYield = cache.Get(); //Std.Dev of Yield Vector price = cache.Get(); Vector yield = cache.Get(); Vector macaulayDuration = cache.Get(); Vector bondValue = cache.Get(); Vector df = cache.Get(); Vector dfr = fRepoIsDiscount ? null : cache.Get(); if (defaultedBeforeBaseDate) { result.AppendVector(tgi.Date, optionValue); return(LoopAction.Break); } // This BondPrice function returns the value of the bond cashflows after ExpiryDate, including accrual, discounted back to T.date double accrual, cash; PricingFunctions.BondPrice(bondValue, out accrual, out cash, baseDate, tgi.Date, deal.Expiry_Date, deal.Issue_Date, deal.Bond_Maturity_Date, notional, coupon, fPayDates, fAccruals, fDiscountRate, deal.Amortisation, fPrincipals, fFinalPrincipal, fSurvivalProb, +1.0); // Now check scenario by scenario for defaults, overwriting bondValue as necessary if (respectDefault) { AdjustBondValueForDefault(notional, tExpiry, bondValue, bondIsAlive, historicalRecovery, defaultTime, tgi.T, fDiscountRate, fRecoveryRate); } // convert price and duration to forward (tExpiry) basis if (tgi.Date == deal.Expiry_Date) { optionValue.Assign(buySign * VectorMath.Max(0.0, paySign * (bondValue - notional * fStrike))); cashAccumulators.Accumulate(fFxRate, tgi.Date, optionValue); } else { fDiscountRate.GetValue(df, tgi.T, tExpiry); if (fRepoIsDiscount) { dfr = df; } else { fRepoRate.GetValue(dfr, tgi.T, tExpiry); } // Need yield and duration to convert yield vol to price vol. PricingFunctions.BondForwardPriceAndAdjustedMacaulayDuration(price, macaulayDuration, tgi.T, tExpiry, tMaturity, coupon, interval, df, fDiscountRate, fSurvivalProb); PricingFunctions.BondYieldFromPrice(yield, tExpiry, tMaturity, coupon, interval, price); // Calculate Modified Duration from Macaulay Duration. Vector modifiedDuration = cache.GetClear(); PricingFunctions.GetModifiedDuration(modifiedDuration, macaulayDuration, yield, interval); // Calculate Std.Dev of Yield and Price interestYieldVol.GetStdDev(stdDevYield, tgi.T, yield, fStrikeYield, tExpiry, tMaturity - tExpiry); stdDev.Assign(modifiedDuration * stdDevYield); if (interestYieldVol.GetDistributionType() == ProbabilityDistribution.Lognormal) { stdDev.MultiplyBy(yield); } price.AssignQuotient(bondValue, df); PricingFunctions.BlackFunction(optionValue, deal.Option_Type, price, notional * fStrike, stdDev); optionValue.MultiplyBy(buySign * dfr); if (fIntraValuationDiagnosticsWriter.Level > IntraValuationDiagnosticsLevel.None) { // Add Intra-valuation Diagnostics using (var volatilitiesAtDateStore = IntraValuationDiagnosticsHelper.CreateVolatilitiesAtDateStore(fIntraValuationDiagnosticsWriter, factors.NumScenarios)) using (var volatilitiesYieldAtDateStore = IntraValuationDiagnosticsHelper.CreateVolatilitiesAtDateStore(fIntraValuationDiagnosticsWriter, factors.NumScenarios)) { volatilitiesAtDateStore.Add(tgi.Date, tgi.TimeGrid.fEndDate, stdDev); volatilitiesYieldAtDateStore.Add(tgi.Date, tgi.TimeGrid.fEndDate, stdDevYield); IntraValuationDiagnosticsHelper.AddBondOptionProperties(fIntraValuationDiagnosticsWriter, price, dfr, bondValue, accrual, volatilitiesAtDateStore, volatilitiesYieldAtDateStore); IntraValuationDiagnosticsHelper.AddCashflowsPV(fIntraValuationDiagnosticsWriter, optionValue); } } } result.AppendVector(tgi.Date, fFxRate.Get(tgi.T) * optionValue); return(LoopAction.Continue); } } }); } result.Complete(fT); } }
/// <summary> /// Calculate a valuation profile for the deal for the current scenario. /// </summary> public override void Value(ValuationResults valuationResults, PriceFactorList factors, BaseTimeGrid baseTimes) { PreValue(factors); var deal = (CFListBaseDeal <TCashflowList>)fDeal; double baseDate = factors.BaseDate; var tgi = new TimeGridIterator(fT); PVProfiles result = valuationResults.Profile; CashAccumulators cashAccumulators = valuationResults.Cash; double endDate = deal.EndDate(); using (IntraValuationDiagnosticsHelper.StartDeal(fIntraValuationDiagnosticsWriter, fDeal)) { using (var outerCache = Vector.Cache(factors.NumScenarios)) { Vector defaultDate = fCreditRating != null?outerCache.Get(CalcUtils.DateTimeMaxValueAsDouble) : null; var defaultedBeforeBaseDate = CreditRating.DefaultedBeforeBaseDate(fCreditRating, baseDate); bool collectCash = ValueOnCashflowDates(); var saccrResult = SACCRResultFactory.Create(valuationResults, deal.GetDealReferenceProvider().DealReference, () => new SACCROptionResult(factors.NumScenarios)); VectorEngine.For(tgi, () => { using (var cache = Vector.Cache(factors.NumScenarios)) { Vector pv = cache.GetClear(); Vector cash = collectCash ? cache.GetClear() : null; if (!defaultedBeforeBaseDate) { using (IntraValuationDiagnosticsHelper.StartCashflowsOnDate(fIntraValuationDiagnosticsWriter, tgi.Date)) { using (IntraValuationDiagnosticsHelper.StartCashflows(fIntraValuationDiagnosticsWriter, fFxRate, tgi.T, deal)) { Value(pv, cash, baseDate, tgi.Date, saccrResult, fIntraValuationDiagnosticsWriter); IntraValuationDiagnosticsHelper.AddCashflowsPV(fIntraValuationDiagnosticsWriter, pv); } } if (fCreditRating != null) { UpdateDefaultDate(fCreditRating, tgi.Date, tgi.T, defaultDate); GetDefaultValue(baseDate, tgi.Date, defaultDate, fRecoveryRate, pv, cash); } } result.AppendVector(tgi.Date, pv * fFxRate.Get(tgi.T)); if (!cashAccumulators.Ignore && cash != null) { // Realise all value as cash on deal end date if (tgi.Date == endDate) { cash.Assign(pv); } cashAccumulators.Accumulate(fFxRate, tgi.Date, cash); } } }); if (!cashAccumulators.Ignore && !collectCash) { CollectCashflows(cashAccumulators, baseDate, fT.fHorizon); // Consolidate and net in order to avoid getting Net incoming and outgoing cashflows with the same payment date, // e.g. for compounding swaps with both positive and negative rates. cashAccumulators.ConsolidateAndNet(fCurrency, factors); } result.Complete(fT); } } }
/// <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); } }