示例#1
0
        //internal use + keyPoint manipulation, i.e. solving zspread
        //Note: this api will bypass curve calibration
        public YieldCurve(
            string name,
            Date referenceDate,
            Tuple <Date, double>[] keyPoints,
            BusinessDayConvention bda,
            IDayCount dayCount,
            ICalendar calendar,
            CurrencyCode currency,
            Compound compound,
            Interpolation interpolation,
            YieldCurveTrait trait,
            IMarketCondition baseMarket = null,
            Expression <Func <IMarketCondition, object> >[] calibrateMktUpdateCondition = null,
            ISpread spread     = null,
            string[] keyTenors = null,
            InstrumentCurveDefinition rawDefinition = null
            )
        {
            Name          = name;
            ReferenceDate = referenceDate;
            Currency      = currency;
            Bda           = bda;
            DayCount      = dayCount;
            Compound      = compound;
            Calendar      = calendar;
            Interpolation = interpolation;
            Trait         = trait;
            BaseMarket    = baseMarket;
            Spread        = spread ?? new ZeroSpread(0.0);
            CalibrateMktUpdateCondition = calibrateMktUpdateCondition;
            MarketInstruments           = null;
            KeyPoints     = keyPoints.OrderBy(x => x.Item1).ToArray();
            KeyTenors     = keyTenors ?? KeyPoints.Select(x => new Term(x.Item1 - ReferenceDate, Period.Day)).Select(x => x.ToString()).ToArray();
            RawDefinition = rawDefinition;

            InputRateByTenor = KeyPoints.Select(x => Tuple.Create <string, double> (new Term(x.Item1 - ReferenceDate, Period.Day).ToString(), x.Item2)).
                               ToDictionary(v => v.Item1, v => v.Item2);

            //_curve = new Curve<Date>(ReferenceDate, KeyPoints, x => x.ToOADate(), interpolation);
            _curveXInYears = new Curve <double>(0.0,
                                                KeyPoints.Select(x => Tuple.Create(DayCount.CalcDayCountFraction(ReferenceDate, x.Item1), x.Item2)).ToArray(),
                                                x => x,
                                                Interpolation);
        }
示例#2
0
        public static Tuple <Date, double>[] Calibrate(
            string name,
            Date referenceDate,
            IMarketInstrument[] marketInstruments,
            BusinessDayConvention bda,
            IDayCount daycount,
            ICalendar calendar,
            Compound compound,
            Interpolation interpolation,
            YieldCurveTrait trait,
            CurrencyCode currency,
            Date[] knotPoints,
            out double fittingError,
            IMarketCondition baseMarket = null,
            Expression <Func <IMarketCondition, object> >[] expression = null,
            double initialValue = double.NaN,
            double initialGuess = 0.05,
            double xmin         = -3,
            double xmax         = 3.0
            )
        {
            var accuracy = 1.0e-13;

            if (marketInstruments.Any(x => !(x.Instrument is Bond)))
            {
                throw new PricingLibraryException("All instruments must be bond to build a bond curve!");
            }

            var keyTs = knotPoints.Select(x => daycount.CalcDayCountFraction(referenceDate, x)).ToArray();
            var len   = keyTs.Length;

            baseMarket =
                baseMarket
                ??
                new MarketCondition(
                    x => x.ValuationDate.Value        = referenceDate,
                    x => x.DiscountCurve.Value        = null,
                    x => x.FixingCurve.Value          = null,
                    x => x.HistoricalIndexRates.Value = new Dictionary <IndexType, SortedDictionary <Date, double> >()
                    );

            var bondYieldPricer = new BondYieldPricer();
            var bonds           = marketInstruments.Select(x => x.Instrument as Bond);
            var bondCf          = bonds.Select(x => x.GetCashflows(baseMarket, true)).ToList();
            var bondPrices      =
                bonds.Select(
                    (x, i) =>
                    bondYieldPricer.FullPriceFromYield(bondCf[i], x.PaymentDayCount, x.PaymentFreq, x.StartDate, referenceDate,
                                                       marketInstruments[i].TargetValue, x.BondTradeingMarket, x.IrregularPayment)).ToArray();

            var rand = new Random();
            // variables : alpha, b1, b2, b3, b4, b5 ...
            var    numVars     = 1 + 2 + len;
            var    lowerBounds = new double[numVars];
            var    upperBounds = new double[numVars];
            var    initials    = new double[numVars];
            double?finalScore  = double.NaN;

            for (var i = 0; i < numVars; ++i)
            {
                lowerBounds[i] = i == 0 ? 0.0 : xmin;
                upperBounds[i] = i == 0 ? 1.0 : xmax;
                initials[i]    = rand.NextDouble() > 0 ? rand.NextDouble() : -rand.NextDouble();
            }

            var globalSolver = new NLoptSolver(NLoptAlgorithm.GN_DIRECT, (ushort)numVars, accuracy, 100000, NLoptAlgorithm.LN_COBYLA);

            globalSolver.SetLowerBounds(lowerBounds);
            globalSolver.SetUpperBounds(upperBounds);
            globalSolver.SetMinObjective((variables, gradients) =>
            {
                var error =
                    bondCf.Select((cfs, i) => GetModelPrice(referenceDate, cfs, daycount, variables, keyTs) - bondPrices[i]).ToArray();
                return(error.Sum(x => x * x));
            });
            double?globalFinalScore;
            var    globalResult = globalSolver.Optimize(initials, out globalFinalScore);

            var localSolvers = new[] { NLoptAlgorithm.LN_BOBYQA, NLoptAlgorithm.LD_AUGLAG, NLoptAlgorithm.LN_COBYLA };

            for (var k = 0; k < 3; ++k)
            {
                var localSolver = new NLoptSolver(localSolvers[k], (ushort)numVars, accuracy, 100000, NLoptAlgorithm.LN_COBYLA);
                localSolver.SetLowerBounds(lowerBounds);
                localSolver.SetUpperBounds(upperBounds);
                localSolver.SetMinObjective((variables, gradients) =>
                {
                    var error = bondCf.Select((cfs, i) => GetModelPrice(referenceDate, cfs, daycount, variables, keyTs) - bondPrices[i]).ToArray();
                    return(error.Sum(x => x * x));
                });

                var result = localSolver.Optimize(initials, out finalScore);
            }
            fittingError = finalScore.Value;

            var coeffes = new[]
            {
                Tuple.Create(referenceDate, initials[0]),
                Tuple.Create(referenceDate, -1.0 - initials[1] - initials[2] - initials.Skip(3).Sum() * 1 / 3.0),
                Tuple.Create(referenceDate, initials[1]),
                Tuple.Create(referenceDate, initials[2]),
            }
            .Union(knotPoints.Select((x, i) => Tuple.Create(x, initials[i + 3])))
            .ToArray();

            //var errors = bondCf.Select((cfs, i) => GetModelPrice(referenceDate, cfs, daycount, initials, keyTs)).ToArray();

            //for (var i = 0; i < errors.Length; ++i)
            //{

            //	Console.WriteLine("{0},{1},{2}", errors[i], bondPrices[i], errors[i] - bondPrices[i]);
            //}

            return(coeffes);            // Insert 0D point to avoid interpolation jump at the beginning
        }
示例#3
0
        //swap curve building for both pricing and pnl,   bond curve building only,  not for pnl
        public YieldCurve(
            string name,
            Date referenceDate,
            MarketInstrument[] marketInstruments,
            BusinessDayConvention bda,
            IDayCount dayCount,
            ICalendar calendar,
            CurrencyCode currency,
            Compound compound,
            Interpolation interpolation,
            YieldCurveTrait trait,
            IMarketCondition baseMarket = null,
            Expression <Func <IMarketCondition, object> >[] calibrateMktUpdateCondition = null,
            ISpread spread     = null,
            Date[] knotPoints  = null,
            string[] keyTenors = null,
            InstrumentCurveDefinition rawDefinition = null
            )
        {
            Name          = name;
            ReferenceDate = referenceDate;
            Currency      = currency;
            Bda           = bda;
            DayCount      = dayCount;
            Compound      = compound;
            Calendar      = calendar;
            Interpolation = interpolation;
            Trait         = trait;
            RawDefinition = rawDefinition;
            var tempMarketInstruments     = marketInstruments.OrderBy(x => x.Instrument.UnderlyingMaturityDate).ToArray();
            var uniqueTenorMktInstruments = new List <MarketInstrument> {
                tempMarketInstruments[0]
            };

            for (var i = 1; i < tempMarketInstruments.Length; ++i)
            {
                if (tempMarketInstruments[i].Instrument.GetCalibrationDate() != tempMarketInstruments[i - 1].Instrument.GetCalibrationDate())
                {
                    uniqueTenorMktInstruments.Add(tempMarketInstruments[i]);
                }
            }
            MarketInstruments = uniqueTenorMktInstruments.ToArray();
            InputRateByTenor  = MarketInstruments.ToDictionary(p => p.Instrument.Tenor, p => p.TargetValue);

            BaseMarket = baseMarket;
            Spread     = spread ?? new ZeroSpread(0.0);
            CalibrateMktUpdateCondition = calibrateMktUpdateCondition;

            if (MarketInstruments.Any(x => x.Instrument is Bond))
            {
                var err = double.NaN;
                KeyPoints    = BondCurveCalibrator.Calibrate(Name, ReferenceDate, MarketInstruments.ToArray(), Bda, DayCount, Calendar, Compound, Interpolation, Trait, Currency, knotPoints, out err, baseMarket, CalibrateMktUpdateCondition);
                fittingError = err;
            }
            else
            {
                KeyPoints = YieldCurveCalibrator.Calibrate(name, ReferenceDate, MarketInstruments.ToArray(), Bda, DayCount, Calendar, Compound, Interpolation, Trait, Currency, baseMarket, CalibrateMktUpdateCondition);
            }


            //if (KeyPoints.Select(x => x.Item1).Any(z => z is Date))
            //{
            //	_curve = new Curve<Date>(ReferenceDate, KeyPoints, x => x.ToOADate(), interpolation);
            //}
            _curveXInYears = new Curve <double>(0.0,
                                                KeyPoints.Select(x => Tuple.Create(DayCount.CalcDayCountFraction(ReferenceDate, x.Item1), x.Item2)).ToArray(),
                                                x => x,
                                                Interpolation);
        }
示例#4
0
        public static Tuple <Date, double>[] Calibrate(
            string name,
            Date referenceDate,
            IMarketInstrument[] marketInstruments,
            BusinessDayConvention bda,
            IDayCount daycount,
            ICalendar calendar,
            Compound compound,
            Interpolation interpolation,
            YieldCurveTrait trait,
            CurrencyCode currency,
            IMarketCondition baseMarket = null,
            Expression <Func <IMarketCondition, object> >[] expression = null,
            double initialValue = double.NaN,
            double initialGuess = 0.05,
            //double xmin = -0.9999,
            double xmin = -0.5,
            double xmax = 1.0
            )
        {
            var accuracy = 1.0e-14;

            if (marketInstruments.Any(x => x.Instrument is CreditDefaultSwap) || trait == YieldCurveTrait.DiscountCurve)
            {
                initialValue = 1.0;
                initialGuess = 1.0;
                xmin         = 1.0e-64;
            }

            var len    = marketInstruments.Length;
            var points = marketInstruments.Select(x => Tuple.Create(x.Instrument.GetCalibrationDate(), initialGuess)).ToList();

            var calibrationStartIndex = 0;

            if (!double.IsNaN(initialValue))
            {
                points.Insert(0, Tuple.Create(referenceDate, initialValue));
                calibrationStartIndex = 1;
            }

            if (interpolation == Interpolation.ForwardFlat)
            {
                //forward flat interpolation, the final instrument is not needed in calibration
                points = points.Take(len - 1).ToList();
                points.Insert(0, Tuple.Create(referenceDate, 0.05));
                calibrationStartIndex = 0;
            }
            else if (trait == YieldCurveTrait.ForwardCurve)
            {
                points.Insert(0, Tuple.Create(referenceDate, 0.05));
                calibrationStartIndex = 1;
            }

            baseMarket = baseMarket ?? new MarketCondition(x => x.ValuationDate.Value = referenceDate);
            expression = expression ?? new Expression <Func <IMarketCondition, object> >[]
            {
                x => x.DiscountCurve,
                x => x.FixingCurve
            };

            IYieldCurve calibratedCurve = new YieldCurve(name, referenceDate, points.ToArray(), bda, daycount, calendar, currency, compound, interpolation, trait, baseMarket);
            var         finalInstrument = marketInstruments.Last();
            var         smooth          = (finalInstrument.Instrument is InterestRateSwap);

            double preCalibrationValue = 0.0;

            if (smooth)
            {
                preCalibrationValue = finalInstrument.Instrument.ModelValue(
                    baseMarket.UpdateCondition(expression.Select(ex => (IUpdateMktConditionPack) new UpdateMktConditionPack <IYieldCurve>(ex, calibratedCurve)).ToArray()),
                    finalInstrument.CalibMethod);
            }

            while (true)
            {
                for (var i = 0; i < len; ++i)
                {
                    var calibrateFunc = new CalibrateMarketInstrument(marketInstruments[i], calibratedCurve, baseMarket, i + calibrationStartIndex, expression);
                    //Note: alternative brent solver gives same result, but slower convergence,
                    //var calibrateFunc = new CalibrateMarketInstrument2(marketInstruments[i], calibratedCurve, baseMarket, i + calibrationStartIndex, expression);
                    double finalR;
                    try
                    {
                        finalR = BrentZero.Solve(calibrateFunc, xmin, xmax, accuracy);
                        //finalR = BrentZero2<IUnivariateFunction>.DoSolve(calibrateFunc, xmin, xmax, 0.05, 0);
                    }
                    catch (Exception ex)
                    {
                        throw new PricingLibraryException(string.Format("Error when bootstrapping {0}th point", i));
                    }
                    calibratedCurve = UpdateKeyRate(calibratedCurve, i + calibrationStartIndex, finalR);
                }

                if (!smooth)
                {
                    break;
                }
                else
                {
                    var postCalibrationValue = finalInstrument.Instrument.ModelValue(
                        baseMarket.UpdateCondition(expression.Select(ex => (IUpdateMktConditionPack) new UpdateMktConditionPack <IYieldCurve>(ex, calibratedCurve)).ToArray()),
                        finalInstrument.CalibMethod);
                    if (Math.Abs(postCalibrationValue - preCalibrationValue) < 1e-12)
                    {
                        break;
                    }
                    preCalibrationValue = postCalibrationValue;
                }
            }

            //if initial value is provided for 0D, 不插0D
            if (!double.IsNaN(initialValue))
            {
                return(calibratedCurve.KeyPoints.ToArray());
            }

            //NEVER EVER insert points at the end, inset at MOST ONE point at the beginning
            return(new[] { Tuple.Create(referenceDate, calibratedCurve.KeyPoints[0].Item2) }            // Insert 0D point to avoid interpolation jump at the beginning
                   .Union(calibratedCurve.KeyPoints)
                   .ToArray());
        }