public static double GetModifiedDuration(Cashflow[] cashflows, IDayCount dayCount, Frequency frequency, Date startDate, Date valueDate, double yield, TradingMarket tradeingMarket, bool irregularPayment = false, IBondYieldPricer bondYieldPricer = null) { const double dy = 1e-4; if (bondYieldPricer == null) { bondYieldPricer = new BondYieldPricer(); } var priceUp = bondYieldPricer.FullPriceFromYield(cashflows, dayCount, frequency, startDate, valueDate, yield - dy, tradeingMarket, irregularPayment); var priceDown = bondYieldPricer.FullPriceFromYield(cashflows, dayCount, frequency, startDate, valueDate, yield + dy, tradeingMarket, irregularPayment); return((priceUp - priceDown) / dy / (priceDown + priceUp)); }
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 }