/// <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> /// Output Intra-Valuation Diagnostics /// </summary> public virtual void AddIntraValuationDiagnostics(IIntraValuationDiagnosticsWriter intraValuationDiagnosticsWriter, CDOValuationParameters parameters, Vector adjustedAttachment, Vector adjustedDetachment, Vector remainingPool, double valueTime, double tPay) { }
/// <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); }