/// <summary>
        /// Prepare for valuation anything that is not dependent upon the scenario.
        /// </summary>
        public override void HeadNodeInitialize(PriceFactorList factors, BaseTimeGrid baseTimes, RequiredResults resultsRequired)
        {
            base.HeadNodeInitialize(factors, baseTimes, resultsRequired);
            var deal = (AverageForwardExplicitDealBase)Deal;

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

            fSamplingTimes          = new double[deal.Sampling_Data.Count];
            fSamplingTimesPlusTenor = new double[deal.Sampling_Data.Count];

            int  index       = 0;
            Term tenorAsTerm = Period.ValueToTerm(deal.Tenor);

            // Loop over sampling dates and generate relevant sampling times.
            foreach (SamplingEntryAsset sample in deal.Sampling_Data)
            {
                double endDate    = DateAdjuster.Add(sample.Date, tenorAsTerm, deal.GetHolidayCalendar());
                double sampleTime = CalcUtils.DaysToYears(sample.Date - factors.BaseDate);

                // Store the start time and the end time.
                fSamplingTimes[index]          = sampleTime; // Discount Factor and Forward Factor times are in Act365.
                fSamplingTimesPlusTenor[index] = CalcUtils.DaysToYears(endDate - factors.BaseDate);

                index++;
            }

            // Create a deep copy of the sampling data list and replace missing values with data from the rate fixings file
            var    assetPrice    = ((BaseAssetFxDealHelper)deal.GetDealHelper()).GetAssetPrice(factors);
            string assetCurrency = fPayoffType == PayoffType.Compo ? fPayoffCurrency : fCurrency;

            fSamplingData = deal.Sampling_Data.FillMissingDataFromFixings(factors.RateFixings, factors, assetPrice, assetCurrency, deal, "calculation of asset average");

            // Add to valuation time grid
            fT.AddPayDate(deal.Maturity_Date, resultsRequired.CashRequired());
        }
Пример #2
0
        /// <summary>
        /// Calculate forward price, discount factor and volatility.
        /// </summary>
        protected override void PriceAndVolatility(double baseDate, double valueDate, Vector forwardPrice, Vector discountFactor, Vector volatility)
        {
            CommodityFutureOption deal = (CommodityFutureOption)Deal;

            double t       = CalcUtils.DaysToYears(valueDate - baseDate);
            double tSettle = CalcUtils.DaysToYears(deal.Settlement_Date - baseDate);

            // Get spot price in contract currency
            forwardPrice.Assign(fCommodityPrice.Get(t) / fFxRate.Get(t));

            if (volatility != null)
            {
                double tExpiry = CalcUtils.DaysToYears(deal.Expiry_Date - baseDate);
                if (tExpiry > t)
                {
                    // temporary use of discountFactor vector to store strike
                    discountFactor.Assign(deal.Strike);
                    // Get volatility using spot price and strike
                    volatility.Assign(fCommodityPriceVol.Get(t, forwardPrice, discountFactor, tExpiry));
                }
                else
                {
                    volatility.Clear();
                }
            }

            fDiscountRate.GetValue(discountFactor, t, tSettle);

            // Get forward factor and complete calculation of forward price
            forwardPrice.MultiplyBy(fCommodityPrice.ForwardFactor(t, tSettle, fFxRate));
        }
        /// <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);
        }
Пример #4
0
        /// <inheritdoc />
        public override void HeadNodeInitialize(PriceFactorList factors, BaseTimeGrid baseTimes, RequiredResults requiredResults)
        {
            base.HeadNodeInitialize(factors, baseTimes, requiredResults);

            BaseCliquetOption deal = (BaseCliquetOption)fDeal;

            DateList accrualDates = CashflowGeneration.GenerateStripOfDates(deal.Effective_Date, deal.Maturity_Date, deal.Frequency, deal.GetHolidayCalendar());

            fTimes = new double[accrualDates.Count];
            for (int i = 0; i < accrualDates.Count; ++i)
            {
                fTimes[i] = CalcUtils.DaysToYears(accrualDates[i] - factors.BaseDate);
            }

            // Get the asset price from the deal helper
            var         dealHelper = (BaseAssetFxDealHelper)deal.GetDealHelper();
            IAssetPrice assetPrice = dealHelper.GetAssetPrice(factors);

            fKnownPrices = deal.GetKnownPrices(accrualDates, factors, assetPrice);

            // Add expiry dates to valuation time grid.
            if (accrualDates.Count > 1)
            {
                DateList expiryDates = new DateList(accrualDates);
                expiryDates.RemoveAt(0);

                fT.AddPayDates(expiryDates, requiredResults.CashRequired());
            }
        }
        /// <summary>
        /// Returns the payment amount on settlement date based on the cashflowlist.
        /// </summary>
        /// <remarks>
        /// The payment amount on settlement date will be either the dirty price of the bond or the clean price of the bond plus
        /// the accrued interest (two cashflows). Note that for a long position in a bond forward, this value is negative
        /// (indicating outgoing cashflow).
        /// </remarks>
        protected virtual void GetSettlementAmount(Vector amount, double valueDate, double baseDate, IInflationRate inflationRate, IPriceIndexVolatility indexVolatility)
        {
            amount.Clear();
            using (var cache = Vector.CacheLike(amount))
            {
                var    deal          = (IInflationCashflowListDeal)Deal;
                var    cashflows     = deal.GetCashflows();
                Vector settlementPay = cache.Get();

                for (int i = 0; i < cashflows.Count(); ++i)
                {
                    if (cashflows.GetCashflow(i).Payment_Date < deal.Settlement_Date)
                    {
                        continue;
                    }
                    else if (cashflows.GetCashflow(i).Payment_Date == deal.Settlement_Date)
                    {
                        cashflows.GetCashflow(i).ExpectedAmount(settlementPay, CalcUtils.DaysToYears(valueDate - baseDate), inflationRate, indexVolatility,
                                                                IntraValuationDiagnosticsWriterFactory.GetOrCreate(IntraValuationDiagnosticsLevel.None));
                        amount.Add(settlementPay);
                    }
                    else
                    {
                        break;
                    }
                }
            }
        }
Пример #6
0
        /// <summary>
        /// Generate CTD dates and set CTD coupon rate and conversion factor.
        /// </summary>
        protected void GenerateCTD(double baseDate, double issueDate, double maturityDate, double couponInterval, double firstCouponDate, double penultimateCouponDate, DayCount dayCount, IHolidayCalendar calendar, double couponRate, double conversionFactor)
        {
            if (conversionFactor <= 0.0)
            {
                return; // No CTD details or details invalid
            }
            BondFutureOption deal = (BondFutureOption)fDeal;

            // Validation of settlement date not done for CTD details on price factor
            if (deal.Settlement_Date >= maturityDate)
            {
                throw new AnalyticsException("Settlement date must be before cheapest-to-deliver maturity date.");
            }

            DateGenerationResults dateGenerationResults = deal.GetDateGenerationResults(issueDate, maturityDate, couponInterval, firstCouponDate, penultimateCouponDate, dayCount, calendar);

            fPayDates = dateGenerationResults.PayDates;
            fAccruals = dateGenerationResults.AccrualYearFractions;

            fIssueDate        = issueDate;
            fMaturityDate     = maturityDate;
            fCouponInterval   = couponInterval;
            fCouponRate       = couponRate;
            fConversionFactor = conversionFactor;

            fAccrual = PricingFunctions.AccruedInterest(deal.Settlement_Date, fIssueDate, fPayDates, fAccruals, fCouponRate, 1.0, null);

            double strike    = PriceTransform(deal.Strike);
            double tSettle   = CalcUtils.DaysToYears(deal.Settlement_Date - baseDate);
            double tMaturity = CalcUtils.DaysToYears(fMaturityDate - baseDate);

            fStrikeYield = PricingFunctions.BondYieldFromPrice(tSettle, tMaturity, couponRate, couponInterval, strike);
        }
Пример #7
0
        /// <summary>
        /// Calculate forward price.
        /// </summary>
        protected override void ForwardPrice(double baseDate, double valueDate, Vector forwardPrice)
        {
            CommodityFuture deal = (CommodityFuture)Deal;

            double t       = CalcUtils.DaysToYears(valueDate - baseDate);
            double tSettle = CalcUtils.DaysToYears(deal.Settlement_Date - baseDate);

            forwardPrice.Assign((fCommodityPrice.ForwardFactor(t, tSettle, fFxRate) * fCommodityPrice.Get(t)) / fFxRate.Get(t));
        }
        /// <summary>
        /// Modify the pv and cash taking the date of default into account.
        /// </summary>
        protected void GetDefaultValue(double baseDate, double valueDate, Vector defaultDate, IInflationRate inflationRate, IPriceIndexVolatility indexVolatility, IInterestRate repo, Vector pv, Vector cash)
        {
            IInflationCashflowListDeal deal = (IInflationCashflowListDeal)Deal;

            double settlementDate = deal.Settlement_Date;
            double t           = CalcUtils.DaysToYears(valueDate - baseDate);
            double buySellSign = deal.Buy_Sell == BuySell.Buy ? 1.0 : -1.0;

            if (repo == null)
            {
                repo = fDiscountRate;
            }

            using (var cache = Vector.CacheLike(pv))
            {
                Vector principal = cache.Get();
                GetCurrentExposure(principal, t, valueDate, inflationRate);

                // Approximation: recover only principal, neglecting accrued interest.
                Vector recovery = cache.Get(buySellSign * principal * fRecoveryRate.Get(t));

                if (valueDate <= settlementDate)
                {
                    // Set the pv to (recovery - |settlementAmount|) * df when defaultDate <= valueDate <= settlementDate.
                    // Set cash to (recovery - |settlementAmount|) when defaultDate <= valueDate = settlementDate (cash is always zero before settlementDate).
                    // Note that GetSettlementAmount(...) will return a negative value for a long bond position, indicating an outgoing cashflow.
                    double tSettle          = CalcUtils.DaysToYears(settlementDate - baseDate);
                    Vector settlementAmount = cache.Get();
                    GetSettlementAmount(settlementAmount, valueDate, baseDate, inflationRate, indexVolatility);
                    settlementAmount.MultiplyBy(buySellSign);

                    Vector hasDefaulted = cache.Get(defaultDate <= valueDate);

                    pv.AssignConditional(hasDefaulted, repo.Get(t, tSettle) * (recovery + settlementAmount), pv);

                    if (cash != null && valueDate == settlementDate)
                    {
                        cash.AssignConditional(hasDefaulted, pv, cash);
                    }
                }
                else
                {
                    // after settlement date
                    recovery.MultiplyBy(defaultDate >= valueDate); // set to zero if already defaulted
                    Vector notDefaulted = cache.Get(defaultDate > valueDate);

                    pv.AssignConditional(notDefaulted, pv, recovery);

                    if (cash != null)
                    {
                        cash.AssignConditional(notDefaulted, cash, recovery);
                    }
                }
            }
        }
Пример #9
0
        private void ValueOnOrAfterExpiry(Vector pv, Vector exerciseWeight, Vector settlementCash, Vector cash, PriceFactorList factors, bool isCashSettled, bool isPhysicallySettled, bool cashRequired, TimeGridIterator tgi, double paySign)
        {
            double baseDate    = factors.BaseDate;
            double tSettlement = isCashSettled ? CalcUtils.DaysToYears(fSwaptionDeal.Settlement_Date - baseDate) : 0.0;

            using (var cache = Vector.Cache(factors.NumScenarios))
            {
                Vector fixedPv   = cache.Get();
                Vector fixedCash = cache.Get();
                Vector floatPv   = cache.Get();
                Vector floatCash = cache.Get();

                ValueFixedAndFloatingLegs(tgi, fixedPv, fixedCash, baseDate, floatPv, floatCash);

                if (tgi.Date == fSwaptionDeal.Option_Expiry_Date)
                {
                    pv.Assign(VectorMath.Max(0.0, paySign * (floatPv - fixedPv)));

                    if (isPhysicallySettled)
                    {
                        exerciseWeight.Assign(pv > 0.0); // 1 if exercised and otherwise 0
                    }
                    else if (isCashSettled)
                    {
                        settlementCash.Assign(pv);                                         // Records cash settlement amount on Option Expiry Date.
                        pv.Assign(settlementCash * fDiscountRate.Get(tgi.T, tSettlement)); // Factor in time value of money due to settlement delay.
                    }
                }
                else
                {
                    // After expiry
                    if (isPhysicallySettled)
                    {
                        pv.Assign(paySign * (floatPv - fixedPv) * exerciseWeight);

                        if (cashRequired)
                        {
                            cash.Assign(paySign * (floatCash - fixedCash) * exerciseWeight);
                        }
                    }
                    else if (isCashSettled)
                    {
                        pv.Assign(settlementCash * fDiscountRate.Get(tgi.T, tSettlement));

                        if (tgi.Date == fSwaptionDeal.Settlement_Date && cashRequired)
                        {
                            cash.Assign(settlementCash);
                        }
                    }
                }
            }
        }
Пример #10
0
        /// <summary>
        /// Value the swaption before expiry using a Jamshidian style decomposition to value the swaption analytically.
        /// Checks for the validity of the decomposition and falls back on numerical integration when necessary.
        /// </summary>
        private void ValueBeforeExpiry(Vector pv, PriceFactorList factors, bool isCashSettled, TimeGridIterator tgi)
        {
            double baseDate = factors.BaseDate;
            double tExpiry  = fSwaptionDeal.GetTimeToExpiry(baseDate);
            double tValue   = CalcUtils.DaysToYears(tgi.Date - baseDate);
            int    count    = fDates.Count;

            using (var cache = Vector.Cache(factors.NumScenarios))
            {
                Vector dfTExpiry   = cache.Get();
                Vector yStar       = cache.Get();
                Vector isUnique    = cache.Get();
                Vector analyticPv  = cache.GetClear();
                Vector numericalPv = cache.GetClear();

                // Theory guide mappings for the vector arrays are:
                //     df          <=> D(0, T_i)
                //     coupons     <=> C_i
                //     stdDev      <=> v_i
                //     coefficient <=> D(0, T_i)/D(0, T) exp (- v_i^2 / 2)
                Vector[] df          = new Vector[count];
                Vector[] coupons     = new Vector[count];
                Vector[] stdDev      = new Vector[count];
                Vector[] coefficient = new Vector[count];

                CreateVectorArrays(df, cache, coupons, coefficient, stdDev);

                fDiscountRate.GetValue(dfTExpiry, tValue, tExpiry);

                GetSwapQuantities(coupons, stdDev, coefficient, df, tValue, tExpiry, baseDate, dfTExpiry);

                // Find the value of y which makes the underlying swap value to 0, used for Jamshidian style decomposition
                SolveForYStar(yStar, coefficient, coupons, stdDev);

                // Calculate the scenarios in which the yStar values are guaranteed unique
                IsSolutionUnique(isUnique, yStar, coefficient, coupons, stdDev);

                CalculateAnalyticPV(analyticPv, isUnique, stdDev, yStar, coefficient, coupons, dfTExpiry, df);
                CalculateNumericalPV(numericalPv, isUnique, stdDev, coefficient, coupons);

                pv.AssignConditional(isUnique >= 1.0, analyticPv, numericalPv);

                if (isCashSettled)
                {
                    double tSettlement = CalcUtils.DaysToYears(fSwaptionDeal.Settlement_Date - baseDate);

                    // Factor in time value of money due to settlement delay.
                    pv.MultiplyBy(fDiscountRate.Get(tgi.T, tSettlement) / fDiscountRate.Get(tgi.T, tExpiry));
                }
            }
        }
Пример #11
0
        /// <summary>
        /// This method Adjusts the bond price vector by taking the default into account give the default time vector.
        /// </summary>
        public static void AdjustForDefault(double baseDate, double valueDate, Vector bondPrice, TDate expiryDate, bool respectDefault, Vector underlyingIsAlive, Vector historicalRecovery, Vector defaultTime, IInterestRate discountRate, RecoveryRate recoveryRate)
        {
            // Adjust the bond price for default: check scenario by scenario for defaults, overwriting bondPrice as necessary
            if (!respectDefault)
            {
                return;
            }

            double currentTime = CalcUtils.DaysToYears(valueDate - baseDate);
            double tExpiry     = CalcUtils.DaysToYears(expiryDate - baseDate);

            BondOptionValuation.AdjustBondValueForDefault(1.0, tExpiry, bondPrice, underlyingIsAlive,
                                                          historicalRecovery, defaultTime, currentTime, discountRate,
                                                          recoveryRate);
        }
Пример #12
0
        /// <summary>
        /// Modify the pv and cash taking the date of default into account.
        /// </summary>
        public override void GetDefaultValue(double baseDate, double valueDate, Vector defaultDate, RecoveryRate recoveryRate, Vector pv, Vector cash)
        {
            var deal = (CFFloatingInterestListDeal)Deal;

            double principal      = GetPrincipal(fCashflows, valueDate);
            double settlementDate = deal.Settlement_Date;
            double t = CalcUtils.DaysToYears(valueDate - baseDate);

            using (var cache = Vector.CacheLike(pv))
            {
                // Approximation: recover only principal, neglecting accrued interest
                Vector recovery = cache.Get(fBuySellSign * principal * recoveryRate.Get(t));

                if (valueDate <= settlementDate)
                {
                    // Set the pv to (recovery - settlementAmount) * df when defaultDate <= valueDate <= settlementDate.
                    // Set cash to (recovery - settlementAmount) when defaultDate <= valueDate = settlementDate (cash is always zero before settlementDate).
                    double tSettle = CalcUtils.DaysToYears(settlementDate - baseDate);

                    Vector settlementAmount = cache.GetClear();
                    if (deal.Settlement_Amount_Is_Clean == YesNo.Yes)
                    {
                        fCashflows.CalculateAccrual(settlementAmount, baseDate, settlementDate, false, deal.AccrualHolidayCalendar(), fForecastRate);
                    }
                    settlementAmount.Add(deal.Settlement_Amount);

                    Vector hasDefaulted = cache.Get(defaultDate <= valueDate);

                    pv.AssignConditional(hasDefaulted, fRepoRate.Get(t, tSettle) * (recovery - fBuySellSign * settlementAmount), pv);

                    if (cash != null && valueDate == settlementDate)
                    {
                        cash.AssignConditional(hasDefaulted, pv, cash);
                    }
                }
                else
                {
                    // after settlement date
                    recovery.MultiplyBy(defaultDate >= valueDate); // set to zero if already defaulted
                    Vector notDefaulted = cache.Get(defaultDate > valueDate);
                    pv.AssignConditional(notDefaulted, pv, recovery);
                    if (cash != null)
                    {
                        cash.AssignConditional(notDefaulted, cash, recovery);
                    }
                }
            }
        }
Пример #13
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);
        }
Пример #14
0
        /// <inheritdoc />
        protected override void ForwardPrice(double baseDate, double valueDate, Vector forwardPrice)
        {
            BondFuture deal = (BondFuture)fDeal;

            double t       = CalcUtils.DaysToYears(valueDate - baseDate);
            double tSettle = CalcUtils.DaysToYears(deal.Settlement_Date - baseDate);

            double accrual, cash;

            PricingFunctions.BondPrice(forwardPrice, out accrual, out cash, baseDate, valueDate, deal.Settlement_Date,
                                       fIssueDate, fMaturityDate, 1.0, fCouponRate, fPayDates,
                                       fAccruals, fDiscountRate, null, null, 0.0, fSurvivalProb, 1.0);

            AdjustForDefault(baseDate, valueDate, forwardPrice, deal.Expiry_Date, Respect_Default == YesNo.Yes && !string.IsNullOrEmpty(deal.Issuer), fUnderlyingIsAlive, fHistoricalRecovery, fDefaultTime, fDiscountRate, fRecoveryRate);

            // If deal.Repo_Rate is null or empty then fRepoRate will default to the DiscountRate
            forwardPrice.Assign(Percentage.OverPercentagePoint * ((forwardPrice / fRepoRate.Get(t, tSettle) - accrual)) / fConversionFactor);
        }
Пример #15
0
        /// <summary>
        /// Prepare for valuation anything that will be shared between scenarios.
        /// </summary>
        public override void PreCloneInitialize(PriceFactorList factors, BaseTimeGrid baseTimes, RequiredResults requiredResults)
        {
            base.PreCloneInitialize(factors, baseTimes, requiredResults);

            var deal = (BondOptionDeal)Deal;

            var tExpiry               = deal.GetTimeToExpiry(factors.BaseDate);
            var tMaturity             = CalcUtils.DaysToYears(deal.Bond_Maturity_Date - factors.BaseDate);
            var dateGenerationResults = deal.GetDateGenerationResults();

            fPayDates       = dateGenerationResults.PayDates;
            fAccruals       = dateGenerationResults.AccrualYearFractions;
            fPrincipals     = dateGenerationResults.Principals;
            fFinalPrincipal = dateGenerationResults.FinalPrincipal;

            fStrike      = deal.Strike_Price;
            fStrikeYield = deal.GetStrikeYield(ref fStrike, tExpiry, tMaturity, fPayDates, fAccruals);
            fT.AddPayDate(deal.Expiry_Date, requiredResults.CashRequired());
        }
Пример #16
0
        /// <summary>
        /// Single date valuation function.
        /// </summary>
        public void Value(Vector pv, Vector cash, double baseDate, double valueDate, Vector settlementDate, IInterestRate discount,
                          IInterestRate forecast, IInterestRate repo, IInterestRateVol interestRateVol, IInterestYieldVol interestYieldVol,
                          ISurvivalProb survivalProb, ISACCRResult saccrResult, IIntraValuationDiagnosticsWriter intraValuationDiagnosticsWriter)
        {
            FixedCashflowBaseDeal deal = (FixedCashflowBaseDeal)fDeal;
            double payDate             = deal.Payment_Date;

            if (payDate < valueDate)
            {
                return;
            }

            using (var cache = Vector.CacheLike(pv))
            {
                Vector amount = cache.Get(fAmount);
                if (settlementDate != null)
                {
                    amount.MultiplyBy(settlementDate < payDate);
                }

                if (payDate == valueDate)
                {
                    pv.Assign(amount);
                    if (cash != null)
                    {
                        cash.Assign(amount);
                    }
                }
                else
                {
                    double t    = CalcUtils.DaysToYears(valueDate - baseDate);
                    double tPay = CalcUtils.DaysToYears(payDate - baseDate);
                    if (survivalProb != null)
                    {
                        pv.Assign(amount * discount.Get(t, tPay) * survivalProb.Get(t, tPay));
                    }
                    else
                    {
                        pv.Assign(amount * discount.Get(t, tPay));
                    }
                }
            }
        }
Пример #17
0
        /// <summary>
        /// Modify the pv and cash taking the date of default into account.
        /// </summary>
        public override void GetDefaultValue(double baseDate, double valueDate, Vector defaultDate, RecoveryRate recoveryRate, Vector pv, Vector cash)
        {
            CFFixedInterestListDeal deal = (CFFixedInterestListDeal)fDeal;

            double principal      = GetPrincipal(deal.Cashflows, valueDate);
            double settlementDate = deal.Settlement_Date;
            double t = CalcUtils.DaysToYears(valueDate - baseDate);

            using (var cache = Vector.CacheLike(pv))
            {
                // Approximation: recover only principal, neglecting accrued interest
                Vector recovery = cache.Get(fBuySellSign * principal * recoveryRate.Get(t));

                if (valueDate <= settlementDate)
                {
                    // Set the pv to (recovery - settlementAmount) * df when defaultDate <= valueDate <= settlementDate.
                    // Set cash to (recovery - settlementAmount) when defaultDate <= valueDate = settlementDate (cash is always zero before settlementDate).
                    double tSettle          = CalcUtils.DaysToYears(settlementDate - baseDate);
                    double settlementAmount = fBuySellSign * fSettlementAmount;

                    Vector hasDefaulted = cache.Get(defaultDate <= valueDate);

                    pv.AssignConditional(hasDefaulted, fRepoRate.Get(t, tSettle) * (recovery - settlementAmount), pv);

                    if (cash != null && valueDate == settlementDate)
                    {
                        cash.AssignConditional(hasDefaulted, pv, cash);
                    }
                }
                else
                {
                    // after settlement date
                    recovery.MultiplyBy(defaultDate >= valueDate); // set to zero if already defaulted
                    Vector notDefaulted = cache.Get(defaultDate > valueDate);
                    pv.AssignConditional(notDefaulted, pv, recovery);
                    if (cash != null)
                    {
                        cash.AssignConditional(notDefaulted, cash, recovery);
                    }
                }
            }
        }
Пример #18
0
        /// <summary>
        /// Validations.
        /// </summary>
        public override void Validate(ICalendarData calendar, ErrorList errors)
        {
            base.Validate(calendar, errors);

            CalcUtils.ValidateDates(errors, Effective_Date, Maturity_Date, true);

            // pay frequency (period) must not be greater than entire swap tenor
            double swapTenor = CalcUtils.DaysToYears(fMaturityDate - fEffectiveDate);

            if (fPayFrequency > swapTenor)
            {
                AddToErrors(errors, "Period between payments cannot be greater than period from Effective Date to Maturity Date (pay side)");
            }

            // attachment must be on [0,1), detachment on (0,1], attachment < detachment
            if ((fAttachment < 0) || (fAttachment >= 1))
            {
                AddToErrors(errors, "Attachment point must be less than one and cannot be less than zero");
            }

            if ((fDetachment <= 0) || (fDetachment > 1))
            {
                AddToErrors(errors, "Detachment point must be greater than zero and cannot be greater than one");
            }

            if (fDetachment <= fAttachment)
            {
                AddToErrors(errors, "Attachment point must be less than detachment point");
            }

            if (Upfront_Amount != 0 && Upfront_Date == 0.0)
            {
                AddToErrors(errors, "Upfront date must be specified if there is an upfront payment");
            }

            if (string.IsNullOrEmpty(Reference_Index))
            {
                AddToErrors(errors, "Reference Index must be specified");
            }
        }
Пример #19
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));
            }
        }
Пример #20
0
        /// <summary>
        /// Vector valuation function.
        /// </summary>
        public override void Value(ValuationResults valuationResults, PriceFactorList factors, BaseTimeGrid baseTimes)
        {
            PreValue(factors);

            TimeGridIterator         tgi         = new TimeGridIterator(fT);
            PVProfiles               result      = valuationResults.Profile;
            CashAccumulators         accumulator = valuationResults.Cash;
            DealCreditLinkedNoteBase deal        = (DealCreditLinkedNoteBase)fDeal;

            ISurvivalProb SP = GetSurvivalProbability(factors);
            RecoveryRate  RR = GetRecoveryRate(factors);
            CreditRating  CR = GetCreditRating(factors);

            double tEffective    = CalcUtils.DaysToYears(deal.Effective_Date - factors.BaseDate);
            double scale         = (deal.Buy_Sell == BuySell.Buy) ? +deal.Notional_Amount : -deal.Notional_Amount;
            double purchasePrice = Percentage.PercentagePoint * deal.Price;
            double couponRate    = (deal.Coupon_Type == InterestRateType.Fixed) ? Percentage.PercentagePoint * deal.Coupon_Rate : 0.0;
            double couponSpread  = (deal.Coupon_Type == InterestRateType.Fixed) ? 0.0 : BasisPoint.BasisPointValue * deal.Coupon_Spread;
            double indexTenor    = (deal.Index_Tenor > 0.0) ? deal.Index_Tenor : deal.Coupon_Interval;

            using (var cache = Vector.Cache(factors.NumScenarios))
            {
                bool[] hasDefaulted       = (Respect_Default == YesNo.Yes) ? new bool[factors.NumScenarios] : null;
                Vector defaultTime        = (Respect_Default == YesNo.Yes) ? cache.Get() : null;
                Vector historicalRecovery = (Respect_Default == YesNo.Yes) ? cache.GetClear() : null;

                if (hasDefaulted != null && CR != null)
                {
                    DefaultTime(defaultTime, CR);
                }

                Vector npv      = cache.Get();
                Vector cash     = cache.Get();
                Vector pStart   = cache.Get();
                Vector pEnd     = cache.Get();
                Vector amount   = cache.Get();
                Vector recovery = cache.Get();
                Vector dfLast   = cache.Get();
                Vector df       = cache.Get();

                cash.Clear();
                var defaultedBeforeTheBaseDate = Respect_Default == YesNo.Yes &&
                                                 CreditRating.DefaultedBeforeBaseDate(CR, factors.BaseDate);
                while (tgi.Next())
                {
                    if (defaultedBeforeTheBaseDate)
                    {
                        npv.Clear();
                        result.AppendVector(tgi.Date, npv);
                        break;
                    }

                    if (!deal.Principal_Guaranteed && Respect_Default == YesNo.Yes)
                    {
                        RealizedRecoveryRate(recovery, RR, tgi.T);
                    }

                    // Assume defaults are rare and start by valuing under all scenarios without realized defaults

                    // Value of principal repayment
                    SurvivalProbability(pEnd, factors, SP, tgi.T, fT.fLast);
                    fDiscountRate.GetValue(dfLast, tgi.T, fT.fLast);
                    if (deal.Principal_Guaranteed)
                    {
                        npv.Assign(dfLast);
                    }
                    else
                    {
                        npv.Assign(dfLast * pEnd);
                    }
                    if (accumulator != null && tgi.T == fT.fLast)
                    {
                        cash.Assign(npv);
                    }

                    // Value of coupons
                    for (int i = PayDates.Count - 1; i >= 0 && tgi.Date <= PayDates[i]; --i)
                    {
                        double tPay      = CalcUtils.DaysToYears(PayDates[i] - factors.BaseDate);
                        double tReset    = CalcUtils.DaysToYears(ResetDates[i] - factors.BaseDate);
                        double tPrevious = Math.Max(tgi.T, tReset);
                        SurvivalProbability(pStart, factors, SP, tgi.T, tPrevious);

                        if (deal.Coupon_Type == InterestRateType.Floating)
                        {
                            // Forecast a coupon, add the spread
                            InterestRateUtils.LiborRate(amount, fForecastRate, tgi.T, tReset, tReset, tReset + indexTenor, deal.Index_Day_Count);
                            amount.Add(couponSpread);
                            amount.MultiplyBy(Accruals[i]);
                        }
                        else
                        {
                            // Fixed coupon
                            amount.Assign(couponRate * Accruals[i]);
                        }

                        // The value of the coupon if no default
                        npv.Add(amount * fDiscountRate.Get(tgi.T, tPay) * pEnd);
                        if (accumulator != null && tgi.T == tPay)
                        {
                            cash.Assign(amount);
                        }

                        // The recovery value on default - assume guaranteed principal paid at end, recovery paid immediately
                        if (!deal.Principal_Guaranteed)
                        {
                            npv.Add(fDiscountRate.Get(tgi.T, 0.5 * (tPay + tPrevious)) * (pStart - pEnd) * PricingRecoveryRate(SP));
                        }

                        pEnd.DestructiveAssign(pStart);
                    }

                    // Now check for realized default scenario by scenario, overwriting NPV and cash as appropriate
                    if (Respect_Default == YesNo.Yes && defaultTime != null)
                    {
                        if (tgi.T < tEffective)
                        {
                            fDiscountRate.GetValue(df, tgi.T, tEffective);
                        }

                        for (int i = 0; i < npv.Count; ++i)
                        {
                            if (defaultTime[i] > tgi.T)
                            {
                                continue;
                            }

                            if (deal.Principal_Guaranteed)
                            {
                                npv[i] = dfLast[i];   // full principal paid at maturity
                            }
                            else
                            {
                                if (!hasDefaulted[i])
                                {
                                    historicalRecovery[i] = recovery[i];   // record the historical recovery rate
                                }
                                if (tgi.T < tEffective)
                                {
                                    npv[i] = df[i] * historicalRecovery[i];   // The discounted recovery value of the principal will be paid out on the effective date
                                }
                                else if (tgi.T == tEffective || !hasDefaulted[i])
                                {
                                    npv[i] = historicalRecovery[i];           // The full recovery amount is paid out
                                }
                                else
                                {
                                    npv[i] = 0.0;                             // default is in the past but we are after effective date; settlement has already occurred.
                                }
                            }

                            hasDefaulted[i] = true;
                        }
                    }

                    // Value of purchase price
                    if (tgi.T < tEffective)
                    {
                        npv.Add(-purchasePrice * fDiscountRate.Get(tgi.T, tEffective));
                    }
                    else if (tgi.T == tEffective)
                    {
                        npv.Add(-purchasePrice);
                        if (accumulator != null)
                        {
                            cash.Add(-purchasePrice);
                        }
                    }

                    result.AppendVector(tgi.Date, scale * npv * fFxRate.Get(tgi.T));
                    if (accumulator != null)
                    {
                        accumulator.Accumulate(fFxRate, tgi.Date, scale * cash);
                    }
                }

                // After maturity
                result.Complete(fT);
            }
        }
Пример #21
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);
                });
            }
        }
Пример #22
0
        /// <summary>
        /// Value the deal using the cashflow list.
        /// </summary>
        /// <param name="pv">Present value to be updated.</param>
        /// <param name="cash">Realised cash to be updated.</param>
        public void Value(Vector pv, Vector cash, double baseDate, double valueDate, Vector settlementDate, IInterestRate discount,
                          IInterestRate forecast, IInterestRate repo, IInterestRateVol interestRateVol, IInterestYieldVol interestYieldVol,
                          ISurvivalProb survivalProb, ISACCRResult saccrResult, IIntraValuationDiagnosticsWriter intraValuationDiagnosticsWriter)
        {
            CFFixedInterestListDeal deal = (CFFixedInterestListDeal)Deal;

            pv.Clear();
            if (cash != null)
            {
                cash.Clear();
            }

            deal.Cashflows.Value(pv, cash, null, baseDate, valueDate, settlementDate, discount, survivalProb, fFxRate, fRateFxRate, intraValuationDiagnosticsWriter, fCutoffDate);

            using (var cache = Vector.CacheLike(pv))
            {
                Vector sp = cache.Get(1.0);

                double dealSettlementDate = deal.Settlement_Date;
                double t       = CalcUtils.DaysToYears(valueDate - baseDate);
                double tSettle = CalcUtils.DaysToYears(dealSettlementDate - baseDate);

                if (Use_Survival_Probability == YesNo.Yes && survivalProb != null)
                {
                    survivalProb.GetValue(sp, t, tSettle);
                    fRecoveryList.Value(pv, baseDate, valueDate, discount, survivalProb, intraValuationDiagnosticsWriter);
                }

                if (valueDate < dealSettlementDate)
                {
                    // Forward deal before settlement date
                    if (deal.Is_Defaultable == YesNo.No)
                    {
                        pv.Assign((pv / discount.Get(t, tSettle) - fSettlementAmount) * repo.Get(t, tSettle));
                    }
                    else
                    {
                        pv.Subtract(fAccruedInterest * discount.Get(t, tSettle) * sp + (fSettlementAmount - fAccruedInterest) * repo.Get(t, tSettle));
                    }
                }
                else if (valueDate == dealSettlementDate)
                {
                    // Forward deal at settlement date
                    pv.Subtract(fSettlementAmount);
                    if (cash != null)
                    {
                        if (deal.Settlement_Style == SettlementType.Cash)
                        {
                            cash.Assign(pv);
                        }
                        else
                        {
                            cash.Subtract(fSettlementAmount);
                        }
                    }
                }
            }

            pv.AssignProduct(fBuySellSign, pv);
            if (cash != null)
            {
                cash.AssignProduct(fBuySellSign, cash);
            }
        }
Пример #23
0
        /// <summary>
        /// Generic Deal Valuation - derived objects override the ValueFn() method.
        /// </summary>
        public override void Value(ValuationResults valuationResults, PriceFactorList factors, BaseTimeGrid baseTimes)
        {
            PreValue(factors);

            var              deal        = (CalendarSpreadOption)Deal;
            var              tgi         = new TimeGridIterator(fT);
            PVProfiles       result      = valuationResults.Profile;
            CashAccumulators accumulator = valuationResults.Cash;

            fTimeToSettlement = CalcUtils.DaysToYears(deal.Settlement_Date - factors.BaseDate);
            fPeriodEnd1       = CalcUtils.DaysToYears(deal.Period_End_1 - factors.BaseDate);
            fPeriodEnd2       = CalcUtils.DaysToYears(deal.Period_End_2 - factors.BaseDate);

            // The time to expiry is the time to the end of the first expiring contract.
            fTimeToExpiry = CalcUtils.DaysToYears(deal.Period_End_1 - factors.BaseDate);

            using (var cache = Vector.Cache(factors.NumScenarios))
            {
                EnergySpreadOptionPricer pricer1 = GetEnergyOptionPricer(fForwardSample,
                                                                         fReferencePrice1,
                                                                         fReferenceVol1,
                                                                         factors.BaseDate,
                                                                         fPeriodEnd1,
                                                                         deal.Period_Start_1,
                                                                         deal.Period_End_1,
                                                                         deal.Realized_Average_1,
                                                                         deal.Realized_Average_Date_1,
                                                                         cache);

                EnergySpreadOptionPricer pricer2 = GetEnergyOptionPricer(fForwardSample,
                                                                         fReferencePrice2,
                                                                         fReferenceVol2,
                                                                         factors.BaseDate,
                                                                         fPeriodEnd2,
                                                                         deal.Period_Start_2,
                                                                         deal.Period_End_2,
                                                                         deal.Realized_Average_2,
                                                                         deal.Realized_Average_Date_2,
                                                                         cache);

                Vector pv               = cache.Get();
                Vector realizedPrice1   = cache.Get();
                Vector realizedPrice2   = cache.Get();
                Vector unrealizedPrice1 = cache.Get();
                Vector unrealizedPrice2 = cache.Get();
                Vector vol1             = cache.Get();
                Vector vol2             = cache.Get();
                Vector correlation      = cache.Get();
                Vector discountFactor   = cache.Get();

                // Calculate correlation between forward prices for two different (dereferenced) maturities (e.g. Apr2012 and Jan2013).
                TDate forwardDate1 = fReferencePrice1.GetPriceDate(deal.Period_End_1, 0);
                TDate forwardDate2 = fReferencePrice2.GetPriceDate(deal.Period_End_2, 0);
                fCorrelations.GetValue(correlation, tgi.T, forwardDate1, forwardDate2);

                while (tgi.Next())
                {
                    pv.Clear();

                    if (tgi.T <= fTimeToExpiry)
                    {
                        // Get unrealised reference forward prices (which also age the pricer to time t and update the realized average at time t)
                        pricer1.GetUnrealizedPrice(tgi.T, unrealizedPrice1);
                        pricer2.GetUnrealizedPrice(tgi.T, unrealizedPrice2);

                        // Get the realized averages for both reference prices.
                        pricer1.GetRealizedPrice(realizedPrice1);
                        pricer2.GetRealizedPrice(realizedPrice2);

                        int numSamples1           = pricer1.GetNumSamples();
                        int numRealizedSamples1   = pricer1.GetNumRealizedSamples();
                        int numUnrealizedSamples1 = pricer1.GetNumUnrealizedSamples();

                        int numSamples2           = pricer2.GetNumSamples();
                        int numRealizedSamples2   = pricer2.GetNumRealizedSamples();
                        int numUnrealizedSamples2 = pricer2.GetNumUnrealizedSamples();

                        // Modify the strike
                        Vector kStar = cache.Get(deal.Strike_Price
                                                 - realizedPrice1 * numRealizedSamples1 / numSamples1
                                                 + realizedPrice2 * numRealizedSamples2 / numSamples2);
                        Vector refPriceStar1 = cache.Get(unrealizedPrice1 * numUnrealizedSamples1 / numSamples1);
                        Vector refPriceStar2 = cache.Get(unrealizedPrice2 * numUnrealizedSamples2 / numSamples2);

                        // Get ATM volatilities of the forward price at different maturities (given as time in years with respect to base date).
                        pricer1.GetVol(tgi.T, unrealizedPrice2, vol1);
                        pricer2.GetVol(tgi.T, unrealizedPrice1, vol2);

                        // value is intrinsic - pricing with volatility 0 and realized price if there are no future sample.
                        if (numUnrealizedSamples1 == 0)
                        {
                            vol1.Clear();
                        }

                        // value is intrinsic - pricing with volatility 0 and realized price if there are no future sample.
                        if (numUnrealizedSamples2 == 0)
                        {
                            vol2.Clear();
                        }

                        // CSO pricing: exp(-rT) * E{max(F1(T) - F2(T) - K, 0)}
                        // For the European CSO,  we set multiplier1 = sign, multiplier2 = -sign, constant = -sign * strike,
                        // where sign = +1 for a call and -1 for a put in the SpreadOptionBS function.
                        double rootTime = Math.Sqrt(fTimeToExpiry - tgi.T);
                        Vector volStar1 = cache.Get(vol1 * rootTime);
                        Vector volStar2 = cache.Get(vol2 * rootTime);
                        PricingFunctions.SpreadOptionBS(pv, fCallPutSign, -fCallPutSign, cache.Get(-fCallPutSign * kStar), fCallPutSign,
                                                        refPriceStar1, refPriceStar2, kStar, volStar1, volStar2, correlation);

                        // The option itself cannot be worth less than zero (for long positions).
                        // However, due to that the Bjerksund & Stensland is a type of non-optimal exercise, it is possible to end up with negative PV via
                        // its pricing formula.
                        pv.AssignMax(pv, 0.0);

                        // Discount payment made at settlement date
                        pv.MultiplyBy(fScale * fDiscountRate.Get(tgi.T, fTimeToSettlement));
                    }

                    // Cash settlement at settlement date
                    if (tgi.T == fTimeToSettlement && accumulator != null && !accumulator.Ignore)
                    {
                        accumulator.Accumulate(fFxPayoffRate, tgi.Date, pv);
                    }

                    result.AppendVector(tgi.Date, pv * fFxPayoffRate.Get(tgi.T));
                }

                result.Complete(fT);
            }
        }
Пример #24
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);
        }
Пример #25
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);
            }
        }
Пример #26
0
 /// <summary>
 /// Calculates time to expiry for a given baseDate.
 /// </summary>
 public double GetTimeToExpiry(double baseDate)
 {
     return(CalcUtils.DaysToYears(Expiry_Date - baseDate));
 }
        /// <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);
            }
        }
Пример #28
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);
        }
Пример #29
0
        /// <summary>
        /// Calculate forward price, discount factor and volatility
        /// </summary>
        protected override void PriceAndVolatility(double baseDate, double valueDate, Vector forwardPrice, Vector discountFactor, Vector volatility)
        {
            BondFutureOption deal = (BondFutureOption)fDeal;

            double t         = CalcUtils.DaysToYears(valueDate - baseDate);
            double tSettle   = CalcUtils.DaysToYears(deal.Settlement_Date - baseDate);
            double tMaturity = CalcUtils.DaysToYears(fMaturityDate - baseDate);

            fDiscountRate.GetValue(discountFactor, t, tSettle);

            if (volatility != null)
            {
                double tExpiry = deal.GetTimeToExpiry(baseDate);
                if (tExpiry > t)
                {
                    // Calculate price volatility
                    using (var cache = Vector.CacheLike(forwardPrice))
                    {
                        Vector macaulayDuration = cache.Get();
                        Vector yield            = cache.Get();
                        Vector yieldStrike      = cache.Get(fStrikeYield);

                        // Calculate forwrad price, yield and adjusted duration using simple bond price functions
                        PricingFunctions.BondForwardPriceAndAdjustedMacaulayDuration(forwardPrice, macaulayDuration, t, tSettle, tMaturity, fCouponRate, fCouponInterval, discountFactor, fDiscountRate, fSurvivalProb);
                        PricingFunctions.BondYieldFromPrice(yield, tSettle, tMaturity, fCouponRate, fCouponInterval, forwardPrice);

                        // Calculate Modified Duration from Macaulay Duration.
                        Vector modifiedDuration = cache.Get();
                        PricingFunctions.GetModifiedDuration(modifiedDuration, macaulayDuration, yield, fCouponInterval);

                        // Get yield volatility
                        fInterestYieldVol.GetValue(volatility, t, yield, yieldStrike, tExpiry, tMaturity - tSettle);

                        // Convert (normal) yield vol to lognormal price vol
                        volatility.MultiplyBy(modifiedDuration);

                        if (fInterestYieldVol.GetDistributionType() == ProbabilityDistribution.Lognormal)
                        {
                            // Convert lognormal yield vol to lognormal price vol.
                            volatility.MultiplyBy(yield);
                        }
                    }
                }
                else
                {
                    volatility.Clear();
                }
            }

            // Recalculate forward price using fAccruals
            double accrual, cash;

            PricingFunctions.BondPrice(forwardPrice, out accrual, out cash, baseDate, valueDate, deal.Settlement_Date, fIssueDate, fMaturityDate, 1.0, fCouponRate, fPayDates, fAccruals, fDiscountRate, null, null, 0.0, fSurvivalProb, 1.0);

            BondFutureValuation.AdjustForDefault(baseDate, valueDate, forwardPrice, deal.Expiry_Date, Respect_Default == YesNo.Yes && !string.IsNullOrEmpty(deal.Issuer), fUnderlyingIsAlive, fHistoricalRecovery, fDefaultTime, fDiscountRate, fRecoveryRate);

            forwardPrice.AssignQuotient(forwardPrice, discountFactor);

            if (!fRepoIsDiscount)
            {
                fRepoRate.GetValue(discountFactor, t, tSettle);
            }
        }
Пример #30
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);
        }