コード例 #1
0
        /// <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);
                });
            }
        }
コード例 #2
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;

            BaseCliquetOption deal = (BaseCliquetOption)Deal;

            double scale = (deal.Buy_Sell == BuySell.Buy ? +1 : -1) * deal.GetUnits();

            VectorEngine.For(tgi, () =>
            {
                using (var cache = Vector.Cache(factors.NumScenarios))
                {
                    Vector pv   = cache.Get();
                    Vector cash = cache.Get();

                    PricingFunctions.CliquetOption(pv, cash, deal.Option_Type, tgi.T, fTimes, deal.Moneyness,
                                                   fKnownPrices, fAssetPrice, fFxRate, fPayoffFxRate,
                                                   fDiscountRate, fAssetPriceVol, fQuantoCompo, fPayoffType,
                                                   factors.PathDependent);
                    cashAccumulators.Accumulate(fPayoffFxRate, tgi.Date, scale * cash);
                    result.AppendVector(tgi.Date, scale * pv * fPayoffFxRate.Get(tgi.T));
                }
            }
                             );

            result.Complete(fT);
        }
コード例 #3
0
        /// <summary>
        /// Checks a sufficient condition for yStar to be the unique solution of F(y) = 0.
        /// </summary>
        private void IsSolutionUnique(Vector isYStarUnique, Vector yStar, Vector[] coefficient, Vector[] coupon, Vector[] stdDev)
        {
            using (var cache = Vector.CacheLike(yStar))
            {
                Vector sum           = cache.GetClear();
                Vector haveNegative  = cache.GetClear();
                Vector positiveValue = cache.Get();

                int count = coefficient.Length;

                // C_0 * f_0 (y*) - this term is negative.
                sum.Assign(CalcUtils.SafeExpMultiply(-stdDev[0] * yStar, coupon[0] * coefficient[0]));

                VectorEngine.For(1, count, LoopDirection.Backwards, i =>
                {
                    haveNegative.AssignConditional(coupon[i] <= -CalcUtils.TINY, 1.0, haveNegative);

                    positiveValue.Assign(CalcUtils.SafeExpMultiply(-stdDev[i] * yStar, coupon[i] * coefficient[i] * haveNegative));
                    positiveValue.AssignMax(positiveValue, 0.0);
                    sum.Add(positiveValue);

                    return(LoopAction.Continue);
                });

                isYStarUnique.AssignConditional(sum <= 0.0, 1.0, 0.0);
            }
        }
コード例 #4
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;

            FixedCashflowBaseDeal deal = (FixedCashflowBaseDeal)fDeal;
            double payDate             = deal.Payment_Date;
            double tPay = CalcUtils.DaysToYears(payDate - factors.BaseDate);

            VectorEngine.For(tgi, () =>
            {
                if (tgi.Date == payDate)
                {
                    result.AppendVector(tgi.Date, fFxRate.Get(tgi.T) * fAmount);
                }
                else
                {
                    result.AppendVector(tgi.Date, fFxRate.Get(tgi.T) * fDiscountRate.Get(tgi.T, tPay) * fAmount);
                }
            });

            if (!cashAccumulators.Ignore && factors.BaseDate <= payDate && payDate <= fT.fHorizon)
            {
                cashAccumulators.Accumulate(fFxRate, payDate, fAmount);
            }

            result.Complete(fT);
        }
コード例 #5
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);
            }
        }
コード例 #6
0
        private static void CreateVectorArrays(Vector[] df, VectorScopedCache.Scope cache, Vector[] coupon, Vector[] coefficient, Vector[] stdDev)
        {
            int count = df.Length;

            VectorEngine.For(0, count, i =>
            {
                df[i]          = cache.GetClear();
                coupon[i]      = cache.GetClear();
                coefficient[i] = cache.GetClear();
                stdDev[i]      = cache.GetClear();
                return(LoopAction.Continue);
            });
        }
コード例 #7
0
        /// <summary>
        /// Calculate valuation profiles.
        /// </summary>
        public override void Value(ValuationResults valuationResults, PriceFactorList factors, BaseTimeGrid baseTimes)
        {
            base.PreValue(factors);

            IAssetPrice     commodityPrice;
            ISpotProcessVol dummyAssetPriceVol;

            ((BaseAssetFxDealHelper)GetDealHelper()).PreValueAsset(out commodityPrice, out dummyAssetPriceVol, out fBasketPricer, ref fQuantoCompo, factors);

            CommodityForwardDealBase deal = (CommodityForwardDealBase)fDeal;

            double scale     = (deal.Buy_Sell == BuySell.Buy ? +1 : -1) * deal.Units;
            double tMaturity = CalcUtils.DaysToYears(deal.Maturity_Date - factors.BaseDate);

            TimeGridIterator tgi    = new TimeGridIterator(fT);
            CashAccumulators cash   = valuationResults.Cash;
            PVProfiles       result = valuationResults.Profile;

            VectorEngine.For(tgi, () =>
            {
                using (var cache = Vector.Cache(factors.NumScenarios))
                {
                    Vector pv = cache.Get();

                    if (tgi.Date <= deal.Maturity_Date)
                    {
                        pv.Assign(commodityPrice.ForwardFactor(tgi.T, tMaturity, fFxRate) * commodityPrice.Get(tgi.T));     // assign forward * fxRate to pv
                        pv.Assign((pv - deal.Forward_Price * fFxRate.Get(tgi.T)) * fDiscountRate.Get(tgi.T, tMaturity) * scale);
                    }
                    else
                    {
                        pv.Clear();
                    }

                    result.AppendVector(tgi.Date, pv);

                    if (tgi.Date == deal.Maturity_Date)
                    {
                        cash.Accumulate(fFxRate, deal.Maturity_Date, (commodityPrice.Get(tMaturity) / fFxRate.Get(tMaturity) - deal.Forward_Price) * scale);
                    }
                }
            });

            result.Complete(fT);
        }
コード例 #8
0
        /// <summary>
        /// Calculates the PV using Gauss Hermite quadrature if at least one scenario needs it.
        /// </summary>
        private void CalculateNumericalPV(Vector numericalPv, Vector isUnique, Vector[] stdDev, Vector[] coefficient, Vector[] coupon)
        {
            if (isUnique.MinElement() == 0.0)
            {
                double delta = fSwaptionDeal.Payer_Receiver == PayerReceiver.Payer ? 1.0 : -1.0;

                // At least one scenario needs numerical integration
                CalcUtils.GaussianQuadratureIntegral(numericalPv, (vout, y) =>
                {
                    vout.Clear();

                    VectorEngine.For(0, coupon.Length, i =>
                    {
                        vout.Subtract(CalcUtils.SafeExpMultiply(stdDev[i] * y, delta * coupon[i] * coefficient[i]));
                        return(LoopAction.Continue);
                    });

                    vout.Assign(VectorMath.Max(vout, 0.0));
                }, fQuadrature.Value);
            }
        }
コード例 #9
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;
            CommitmentDeal   deal   = (CommitmentDeal)Deal;

            VectorEngine.For(tgi, () =>
            {
                if (tgi.Date < deal.Effective_Date)
                {
                    result.AppendZeroVector(tgi.Date);
                }
                else
                {
                    double amount = deal.Amortisation.GetPrincipal(deal.Amount, tgi.Date - 1.0);
                    result.AppendVector(tgi.Date, fFxRate.Get(tgi.T) * amount);
                }
            });

            result.Complete(fT);
        }
コード例 #10
0
        /// <summary>
        /// Calculate a valuation profile for a range of scenarios.
        /// </summary>
        public override void Value(ValuationResults valuationResults, PriceFactorList factors, BaseTimeGrid baseTimes)
        {
            IAssetPrice price  = GetAssetPrice(factors);
            PVProfiles  result = valuationResults.Profile;

            double scale = fDeal.Units * (fDeal.Buy_Sell == BuySell.Buy ? +1 : -1);

            var tgi = new TimeGridIterator(fT);

            VectorEngine.For(tgi, () => result.AppendVector(tgi.Date, scale * price.Get(tgi.T)));

            result.Complete(fT);

            CashAccumulators cashAccumulators = valuationResults.Cash;
            double           endDate          = Deal.EndDate();

            if (!cashAccumulators.Ignore && endDate <= fT.fHorizon)
            {
                double  tEnd   = CalcUtils.DaysToYears(endDate - factors.BaseDate);
                IFxRate fxRate = factors.GetInterface <IFxRate>(fDeal.Currency);
                cashAccumulators.Accumulate(fxRate, endDate, scale * price.Get(tEnd) / fxRate.Get(tEnd));
            }
        }
コード例 #11
0
        /// <summary>
        /// Calculates the PV using analytic formula if at least one scenario needs it.
        /// </summary>
        private void CalculateAnalyticPV(Vector analyticPv, Vector isUnique, Vector[] stdDev, Vector yStar, Vector[] coefficient, Vector[] coupon, Vector dfTExpiry, Vector[] df)
        {
            if (isUnique.MaxElement() == 1.0)
            {
                OptionType optionType = fSwaptionDeal.Payer_Receiver == PayerReceiver.Payer ? OptionType.Call : OptionType.Put;

                // Value by summing the of the caplets or floorlets
                analyticPv.Clear();

                using (var cache = Vector.CacheLike(yStar))
                {
                    // f_i(y*) plays the role of price and dfTPay[i] the strike.
                    Vector optionletPrice = cache.Get();

                    VectorEngine.For(0, stdDev.Length, i =>
                    {
                        // Performs optionletPrice = dfExpiry * fCoefficient[i] * Exp(-stdDev[i] * yStar)
                        optionletPrice.Assign(CalcUtils.SafeExpMultiply(-stdDev[i] * yStar, coefficient[i] * dfTExpiry));
                        analyticPv.Add(coupon[i] * PricingFunctions.BlackFunction(optionType, optionletPrice, df[i], stdDev[i]));
                        return(LoopAction.Continue);
                    });
                }
            }
        }
コード例 #12
0
        /// <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);
                }
            }
        }
コード例 #13
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);
                });
            }
        }
コード例 #14
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);
        }
コード例 #15
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);
            }
        }
コード例 #16
0
        /// <summary>
        /// Value the deal from given base date, price factors and time grid.
        /// </summary>
        public void Value(PVProfiles pvResults, CashAccumulators cashResults, double baseDate, IInterestRate discountRate, IInterestRate forecastRate1, IInterestRate forecastRate2, IFxRate fxRate, TimeGrid timeGrid, int numScenarios)
        {
            var tgi  = new TimeGridIterator(timeGrid);
            var deal = (FloatingInterestCashflowInterpolatedDeal)Deal;

            bool   hasRate1          = deal.HasRate1();
            bool   hasRate2          = deal.HasRate2();
            double scale             = deal.Buy_Sell == BuySell.Buy ? +deal.Principal : -deal.Principal;
            double tPay              = CalcUtils.DaysToYears(fPaymentDate - baseDate);
            double tReset            = CalcUtils.DaysToYears(deal.Reset_Date - baseDate);
            double tRateStart        = CalcUtils.DaysToYears(deal.Rate_Start_Date - baseDate);
            double tRateEnd1         = hasRate1 ? CalcUtils.DaysToYears(fRate1EndDate - baseDate) : 0.0;
            double tRateEnd2         = hasRate2 ? CalcUtils.DaysToYears(fRate2EndDate - baseDate) : 0.0;
            double tRateEnd12        = tRateEnd2 - tRateEnd1;                                                                    // Time from rate 1 end date to rate 2 end date.
            double tAccrualEnd       = CalcUtils.DaysToYears(deal.Accrual_End_Date - baseDate);
            double interpCoefficient = Math.Abs(tRateEnd12) >= CalcUtils.MinTime ? (tAccrualEnd - tRateEnd1) / tRateEnd12 : 0.0; // Coefficient used to calculate interpolated rate.

            VectorEngine.For(tgi, () =>
            {
                using (var cache = Vector.Cache(numScenarios))
                {
                    Vector pv = cache.Get();

                    if (tgi.Date <= fPaymentDate && fPaymentDate > fCutoffDate)
                    {
                        Vector interpRate = cache.GetClear();
                        Vector rate1      = cache.GetClear();
                        Vector rate2      = cache.GetClear();

                        if (hasRate1)
                        {
                            if (fKnownResetRate1.HasValue)
                            {
                                rate1.Assign(fKnownResetRate1.Value);
                            }
                            else
                            {
                                InterestRateUtils.LiborRate(rate1, forecastRate1, tgi.T, tReset, tRateStart, tRateEnd1, fRate1YearFraction);
                            }
                        }

                        if (hasRate2)
                        {
                            if (fKnownResetRate2.HasValue)
                            {
                                rate2.Assign(fKnownResetRate2.Value);
                            }
                            else
                            {
                                InterestRateUtils.LiborRate(rate2, forecastRate2, tgi.T, tReset, tRateStart, tRateEnd2, fRate2YearFraction);
                            }
                        }

                        if (hasRate1 && hasRate2)
                        {
                            if (Math.Abs(tRateEnd12) >= CalcUtils.MinTime)
                            {
                                interpRate.Assign(rate1 + interpCoefficient * (rate2 - rate1));
                            }
                            else
                            {
                                interpRate.Assign(0.5 * rate1 + 0.5 * rate2);
                            }
                        }
                        else
                        {
                            interpRate.Assign(hasRate1 ? rate1 : rate2);
                        }

                        // Round the calculated rate, regardless whether the valuation date is before or after the reset date.
                        CFFloatingInterestList.RoundRateTo(deal.Interpolated_Rate_Rounding, interpRate);

                        pv.Assign(scale * (interpRate + deal.Margin) * fAccrualYearFraction);

                        CFFixedList.RoundCashflow(pv, Cashflow_Rounding);

                        if (tgi.Date < fPaymentDate)
                        {
                            pv.MultiplyBy(discountRate.Get(tgi.T, tPay));
                        }
                        else if (tgi.Date == fPaymentDate)
                        {
                            cashResults.Accumulate(fxRate, fPaymentDate, pv);
                        }
                    }
                    else
                    {
                        pv.Clear();
                    }

                    pvResults.AppendVector(tgi.Date, pv * fxRate.Get(tgi.T));
                }
            });

            // After maturity
            pvResults.Complete(timeGrid);
        }
コード例 #17
0
        /// <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);
        }
コード例 #18
0
        /// <summary>
        /// Value the deal on all dates within the valuation grid (vectorised).
        /// </summary>
        public override void Value(ValuationResults valuationResults, PriceFactorList factors, BaseTimeGrid baseTimes)
        {
            var    deal             = (AverageForwardExplicitDealBase)Deal;
            double tMaturity        = CalcUtils.DaysToYears(deal.Maturity_Date - factors.BaseDate); // Discount Factor and Forward Factor times are in Act365.
            int    numSamplingDates = fSamplingTimes.Length;

            PreValue(factors);

            PVProfiles       result = valuationResults.Profile;
            CashAccumulators cash   = valuationResults.Cash;
            var tgi = new TimeGridIterator(fT);

            using (var pricerCache = Vector.Cache(factors.NumScenarios))
            {
                double historicalObservations;
                double futureObservations;
                int    currentDateCount;
                Vector realisedSum  = pricerCache.GetClear();             // sum to value date.
                Vector forecastSum  = pricerCache.Get();
                Vector spotPrice    = pricerCache.Get();
                Vector forwardPrice = pricerCache.Get();

                double tSpotPrice = double.NegativeInfinity;
                GetForwardPrice(0.0, deal.Tenor, true, ref tSpotPrice, spotPrice, forwardPrice);
                fSamplingData.GetInitialSum(null, factors.BaseDate, forwardPrice, realisedSum, out historicalObservations, out futureObservations, out currentDateCount);

                VectorEngine.For(tgi, () =>
                {
                    using (var cache = Vector.Cache(factors.NumScenarios))
                    {
                        Vector overallAverage = cache.Get();
                        Vector value          = cache.Get();
                        Vector payoffRate     = cache.Get();

                        UpdateSum(tgi.Date, realisedSum, ref tSpotPrice, spotPrice, ref historicalObservations, ref futureObservations, ref currentDateCount);
                        forecastSum.Clear();

                        // all the sampling dates that are in the future (compared to our valuation date)
                        VectorEngine.For(currentDateCount, numSamplingDates, i =>
                        {
                            GetForwardPrice(tgi.T, fSamplingTimesPlusTenor[i], false, ref tSpotPrice, spotPrice,
                                            forwardPrice);
                            forecastSum.AddProduct(fSamplingData[i].Weight, forwardPrice);

                            return(LoopAction.Continue);
                        });

                        forecastSum.MultiplyBy(spotPrice);
                        double totalWeight = historicalObservations + futureObservations;
                        if (totalWeight > 0.0)
                        {
                            overallAverage.Assign((realisedSum + forecastSum) / totalWeight);
                        }
                        else
                        {
                            overallAverage.Clear();
                        }

                        PayoffRate(payoffRate, overallAverage, ref tSpotPrice, spotPrice, tgi.T, tMaturity);
                        value.Assign(fScale * fDiscountRate.Get(tgi.T, tMaturity) * payoffRate);

                        if (tgi.Date == deal.Maturity_Date)
                        {
                            cash.Accumulate(fPayoffFxRate, tgi.Date, value);
                        }

                        result.AppendVector(tgi.Date, value * fPayoffFxRate.Get(tgi.T));
                    }
                });

                result.Complete(fT);
            }
        }
コード例 #19
0
        /// <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);
            }
        }
コード例 #20
0
        private void SolveForYStar(Vector yStar, Vector[] coefficient, Vector[] coupon, Vector[] stdDev)
        {
            const int MaxIterations = 10;

            using (var cache = Vector.CacheLike(yStar))
            {
                Vector y           = cache.Get();
                Vector value       = cache.Get();
                Vector deriv       = cache.Get();
                Vector factor      = cache.Get();
                Vector dy          = cache.Get();
                Vector product     = cache.Get();
                Vector numerator   = cache.GetClear();
                Vector demoninator = cache.GetClear();

                int numberOfCoupons = coupon.Length;

                // Solve the equation to first order for the initial guess
                VectorEngine.For(0, numberOfCoupons, i =>
                {
                    product.Assign(coupon[i] * coefficient[i]);
                    numerator.Add(product);
                    demoninator.Add(product * stdDev[i]);
                    return(LoopAction.Continue);
                });

                y.Assign(numerator / demoninator);

                var dyAbs = cache.Get();

                // Newton-Raphson loop to find yStar
                VectorEngine.For(0, MaxIterations, iteration =>
                {
                    value.Clear();
                    deriv.Clear();

                    VectorEngine.For(0, numberOfCoupons, i =>
                    {
                        // Performs factor = c[i] * fCoefficient[i] * Exp(-stdDev[i] * y)
                        factor.Assign(CalcUtils.SafeExpMultiply(-stdDev[i] * y, coupon[i] * coefficient[i]));
                        value.Add(factor);
                        deriv.Subtract(stdDev[i] * factor);
                        return(LoopAction.Continue);
                    });

                    // Could get divide by zero
                    dy.Assign(value / deriv);

                    // Terminate if solution reached.
                    dyAbs.AssignAbs(dy);
                    if (dyAbs.MaxElement() == 0)
                    {
                        return(LoopAction.Break);
                    }

                    y.Subtract(dy);

                    return(LoopAction.Continue);
                });

                yStar.Assign(y);
            }
        }
コード例 #21
0
        /// <summary>
        /// Fills the arrays of coupon, pay date discount factors, standard deviations and coefficient by running through the cashflows
        /// </summary>
        private void GetSwapQuantities(Vector[] coupon, Vector[] stdDev, Vector[] coefficient, Vector[] df, double tValue, double tExpiry, double baseDate, Vector dfTExpiry)
        {
            int                count             = coupon.Length;
            double             tLastEnd          = double.NegativeInfinity;
            double             tLastPay          = double.NegativeInfinity;
            int                floatIndex        = 0;
            CFFloatingInterest cfFloating        = fFloatCashflowList[floatIndex];
            TDate              floatingStartDate = cfFloating.Resets[0].Rate_Start_Date;

            // We will minimise the number of discount factors we get.
            bool[] haveDF = new bool[count];

            using (var cache = Vector.CacheLike(dfTExpiry))
            {
                Vector bTExpiry = cache.Get();
                Vector rootZeta = cache.Get();
                Vector bT       = cache.Get();
                Vector dfTStart = cache.Get();
                Vector dfTPay   = cache.Get();
                Vector ffTStart = cache.Get();
                Vector ffTEnd   = cache.Get();
                Vector beta     = cache.Get();

                fModelParameters.GetB(bTExpiry, tValue, tExpiry);
                fModelParameters.GetZeta(rootZeta, tValue, tExpiry);
                rootZeta.AssignSqrt(rootZeta);

                // Loop over copuons calculating useful quantities.
                VectorEngine.For(0, count, i =>
                {
                    double tDf = CalcUtils.DaysToYears(fDates[i] - baseDate);

                    // if this date is associated with a floating start date include beta contribution
                    if (fDates[i] == floatingStartDate)
                    {
                        var floatingEndDate = cfFloating.Resets[0].Rate_End_Date;
                        var paymentDate     = cfFloating.Payment_Date;

                        double tStart = CalcUtils.DaysToYears(floatingStartDate - baseDate);
                        double tEnd   = CalcUtils.DaysToYears(floatingEndDate - baseDate);
                        double tPay   = CalcUtils.DaysToYears(paymentDate - baseDate);

                        GetDiscountAndForecastFactors(dfTStart, dfTPay, ffTStart, ffTEnd, tValue, tStart, tEnd, tPay, tLastEnd, tLastPay);

                        beta.Assign(dfTPay * ffTStart / (dfTStart * ffTEnd));

                        double rateYearFraction  = cfFloating.Resets[0].Rate_Year_Fraction;
                        double yearFractionRatio = (rateYearFraction < CalcUtils.TINY) ? 1.0 : cfFloating.Accrual_Year_Fraction / rateYearFraction;
                        coupon[i].Assign(-beta * yearFractionRatio * cfFloating.Notional);

                        // Store new discount factors.
                        int payIndex = fDates.IndexOf(paymentDate);
                        df[payIndex].Assign(dfTPay);
                        haveDF[payIndex] = true;

                        if (!haveDF[i])
                        {
                            df[i].Assign(dfTStart);
                            haveDF[i] = true;
                        }

                        // Update for next pass
                        tLastEnd = tEnd;
                        tLastPay = tPay;
                        floatIndex++;

                        if (floatIndex < fFloatCashflowList.Count())
                        {
                            cfFloating        = fFloatCashflowList[floatIndex];
                            floatingStartDate = cfFloating.Resets[0].Rate_Start_Date;
                        }
                        else
                        {
                            floatingStartDate = double.PositiveInfinity;
                        }
                    }

                    // Work out coupon, stdDev, coefficient and dfTPay
                    coupon[i].Add(fFloatingCouponWeight[i]);

                    if (fSwapRate != null)
                    {
                        coupon[i].Add(fSwapRate * fFixedCouponWeight[i]);
                    }
                    else
                    {
                        coupon[i].Add(fFixedCouponRate[i] * fFixedCouponWeight[i]);
                    }

                    fModelParameters.GetB(bT, tValue, tDf);
                    stdDev[i].Assign((bT - bTExpiry) * rootZeta);

                    // Make sure we get all the discount factors.
                    if (!haveDF[i])
                    {
                        fDiscountRate.GetValue(df[i], tValue, tDf);
                        haveDF[i] = true;
                    }

                    // Performs coefficient[i] = dfTPay[i] / dfTExpiry * Exp(-0.5 * stdDev[i] * stdDev[i])
                    coefficient[i].Assign(CalcUtils.SafeExpMultiply(-0.5 * stdDev[i] * stdDev[i], df[i] / dfTExpiry));

                    return(LoopAction.Continue);
                });
            }
        }