Beispiel #1
0
        /// <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);
                }
            }
        }
Beispiel #2
0
        /// <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);
            }
        }
Beispiel #3
0
        /// <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);
                }
            }
        }
Beispiel #4
0
        /// <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);
            }
        }
Beispiel #5
0
        /// <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);
                });
            }
        }
Beispiel #6
0
        /// <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);
        }
Beispiel #7
0
        /// <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);
            }
        }