public double ShortEndTargetFunction(double guess)
        {
            DateTime baseDate      = _baseCurve.GetBaseDate();
            DateTime date0         = _assetDates.First();
            DateTime date1         = _assetDates.Last();
            double   d0            = _baseCurve.GetDiscountFactor(date0);
            double   d1            = _baseCurve.GetDiscountFactor(date1);
            double   y             = _dayCounter.YearFraction(date0, date1);
            double   y0            = _dayCounter.YearFraction(baseDate, date0);
            double   y1            = _dayCounter.YearFraction(baseDate, date1);
            double   z0            = RateAnalytics.DiscountFactorToZeroRate(d0, y0, _compoundingPeriod);
            double   z1            = RateAnalytics.DiscountFactorToZeroRate(d1, y1, _compoundingPeriod);
            double   projectedRate = 1 / y * (d0 / d1 - 1);
            double   basisSpread   = (double)_asset.MarketQuote.value;
            double   term1         = Math.Pow(1 + 0.25 * (z0 + guess), -4 * y0);
            double   term2         = Math.Pow(1 + 0.25 * (z1 + guess), -4 * y1);
            double   term3         = y * term2 * (projectedRate + basisSpread);
            double   result        = -term1 + term2 + term3;

            return(result);
        }
Exemplo n.º 2
0
        /// <summary>
        /// Bootstraps the specified priceable assets.
        /// </summary>
        /// <param name="priceableAssets">The priceable assets.</param>
        /// <param name="baseZeroCurve">The base Zero Curve</param>
        /// <param name="algorithmHolder">The algorithmHolder</param>
        /// <returns></returns>
        public TermPoint[] Bootstrap(List <IPriceableRateAssetController> priceableAssets,
                                     IRateCurve baseZeroCurve, PricingStructureAlgorithmsHolder algorithmHolder)
        {
            var      items    = new SortedDictionary <DateTime, Pair <string, decimal> >();
            DateTime baseDate = baseZeroCurve.GetBaseDate();

            items.Add(baseDate, new Pair <string, decimal>(null, 1m));
            bool         firstTime         = true;
            const double compoundingPeriod = 0.25;
            IPriceableRateAssetController previousAsset = null;
            IEnumerable <TermPoint>       basePillars   = baseZeroCurve.GetTermCurve().point;
            IDayCounter dayCounter = null;

            foreach (IPriceableRateAssetController priceableAsset in priceableAssets)
            {
                List <DateTime> assetDates;
                if (priceableAsset is PriceableSwapRateAsset swap)
                {
                    dayCounter = DayCounterHelper.Parse(swap.DayCountFraction.Value);
                    assetDates = swap.AdjustedPeriodDates;
                }
                else
                {
                    PriceableDeposit deposit = priceableAsset as PriceableDeposit;
                    if (deposit == null)
                    {
                        throw new ArgumentException(
                                  $"PriceableAsset must be a PriceableSwapRateAsset or PriceableDeposit, '{priceableAsset.GetType()}' is not implemented.");
                    }
                    dayCounter = DayCounterHelper.Parse(deposit.Deposit.dayCountFraction.Value);
                    assetDates = new List <DateTime> {
                        deposit.AdjustedStartDate, deposit.GetRiskMaturityDate()
                    };
                }
                DateTime maturityDate = priceableAsset.GetRiskMaturityDate();
                if (items.Keys.Contains(maturityDate))
                {
                    throw new ArgumentException(
                              $"Duplicate priceable asset on '{maturityDate:yyyy-MM-dd}'", nameof(priceableAssets));
                }
                //The min and max values to use with the solver.
                const int xmin     = -1;
                const int xmax     = 1;
                var       accuracy = 10 ^ -12;
                if (firstTime)
                {
                    firstTime = false;
                    // Solve to find the quarterly compounded zero rate spread
                    var solverFunctions
                        = new NewtonRaphsonSolverFunctions(priceableAsset, null, algorithmHolder, baseZeroCurve,
                                                           baseDate, items, compoundingPeriod, ZeroRateSpreads, dayCounter, assetDates);
                    var solver       = new Newton();
                    var initialGuess = (double)priceableAsset.MarketQuote.value;
                    //var solution = new CenteredFiniteDifferenceDerivative();
                    Func <double, double> f           = solverFunctions.ShortEndTargetFunction;
                    var    derivativeOfTargetFunction = new NumericalDerivative().CreateDerivativeFunctionHandle(f, 1);
                    double zeroRateSpread             = solver.Solve(f, derivativeOfTargetFunction, accuracy, initialGuess, xmin, xmax);
                    // add first point
                    DateTime startDate = assetDates.First();
                    decimal  df        = (decimal)GetAdjustedDiscountFactor(baseDate, startDate, dayCounter, zeroRateSpread, baseZeroCurve);
                    if (startDate != baseDate)
                    {
                        items.Add(startDate, new Pair <string, decimal>(null, df));
                    }
                    ZeroRateSpreads.Add(maturityDate, zeroRateSpread);
                    // add extra points
                    IEnumerable <TermPoint> extraPoints = basePillars.Where(b => (DateTime)b.term.Items[0] > startDate && (DateTime)b.term.Items[0] < maturityDate);
                    // Extrapolate the preceding extra points
                    foreach (TermPoint extraPoint in extraPoints)
                    {
                        DateTime date = (DateTime)extraPoint.term.Items[0];
                        df = (decimal)GetAdjustedDiscountFactor(baseDate, date, dayCounter, zeroRateSpread, baseZeroCurve);
                        items.Add(date, new Pair <string, decimal>(extraPoint.id, df));
                    }
                    // add final point
                    df = (decimal)GetAdjustedDiscountFactor(baseDate, maturityDate, dayCounter, zeroRateSpread, baseZeroCurve);
                    items.Add(maturityDate, new Pair <string, decimal>(priceableAsset.Id, df));
                }
                else
                {
                    items.Add(maturityDate, new Pair <string, decimal>(priceableAsset.Id, 0));
                    ZeroRateSpreads.Add(maturityDate, (double)priceableAsset.MarketQuote.value);
                    // Solve to find the quarterly compounded zero rate spread
                    var solverFunctions
                        = new NewtonRaphsonSolverFunctions(priceableAsset, previousAsset, algorithmHolder, baseZeroCurve,
                                                           baseDate, items, compoundingPeriod, ZeroRateSpreads, dayCounter, assetDates);
                    Func <double, double> f           = solverFunctions.LongEndTargetFunction;
                    var    solver                     = new Newton();
                    var    initialGuess               = (double)priceableAsset.MarketQuote.value;
                    var    derivativeOfTargetFunction = new NumericalDerivative().CreateDerivativeFunctionHandle(f, 1);
                    double zeroRateSpread             = solver.Solve(f, derivativeOfTargetFunction, accuracy, initialGuess, xmin, xmax);
                    // Update discount factor value
                    decimal df = (decimal)GetAdjustedDiscountFactor(baseDate, maturityDate, dayCounter, zeroRateSpread, baseZeroCurve);
                    items[maturityDate].Second    = df;
                    ZeroRateSpreads[maturityDate] = zeroRateSpread;
                    solverFunctions.UpdateDiscountFactors(baseDate);
                }
                previousAsset = priceableAsset;
            }
            // Extrapolate the following extra points
            IEnumerable <TermPoint>         finalPoints         = basePillars.Where(b => (DateTime)b.term.Items[0] > items.Last().Key);
            KeyValuePair <DateTime, double> zeroRateSpreadFinal = ZeroRateSpreads.Last();

            foreach (TermPoint extraPoint in finalPoints)
            {
                DateTime date = (DateTime)extraPoint.term.Items[0];
                decimal  df   = (decimal)GetAdjustedDiscountFactor(baseDate, date, dayCounter, zeroRateSpreadFinal.Value, baseZeroCurve);
                items.Add(date, new Pair <string, decimal>(extraPoint.id, df));
            }
            return(TermPointsFactory.Create(items));
        }