/// <summary> /// Bootstraps the specified priceable assets. /// </summary> /// <param name="priceableAssets">The priceable assets.</param> /// <param name="baseDate">The base date.</param> /// <param name="extrapolationPermitted">The extrapolationPermitted flag.</param> /// <param name="interpolationMethod">The interpolationMethod.</param> /// <param name="tolerance">Solver tolerance to use.</param> /// <returns></returns> public static TermPoint[] Bootstrap(IEnumerable <IPriceableRateAssetController> priceableAssets, DateTime baseDate, Boolean extrapolationPermitted, InterpolationMethod interpolationMethod, Double tolerance) { const double defaultGuess = 0.9; const double min = 0.000000001; const double max = 2; //only works for linear on zero. InterpolationMethod interp = InterpolationMethodHelper.Parse("LogLinearInterpolation"); // Add the first element (date : discount factor) to the list var points = new Dictionary <DateTime, double> { { baseDate, 1d } }; var items = new Dictionary <DateTime, Pair <string, decimal> > { { baseDate, new Pair <string, decimal>("", 1m) } }; var solver = new Brent(); bool first = true; // Add the rest foreach (IPriceableRateAssetController priceableAsset in priceableAssets) { DateTime assetMaturityDate = priceableAsset.GetRiskMaturityDate(); if (points.Keys.Contains(assetMaturityDate)) { continue; } if (assetMaturityDate < points.Keys.Last()) { throw new InvalidOperationException("The maturity dates of the assets must be consecutive order"); } if (first) { first = false; // Add the first point points.Add(assetMaturityDate, defaultGuess); var curve = new SimpleDiscountFactorCurve(baseDate, interp, extrapolationPermitted, points); points[assetMaturityDate] = (double)priceableAsset.CalculateDiscountFactorAtMaturity(curve); } else { //This now should automatically extrapolate the required discount factor on a flat rate basis. var curve = new SimpleDiscountFactorCurve(baseDate, interp, extrapolationPermitted, points); //The first guess, which should be correct for all priceable assets with analytical solutions that have been implemented. points.Add(assetMaturityDate, (double)priceableAsset.CalculateDiscountFactorAtMaturity(curve)); } var objectiveFunction = new RateAssetQuote(priceableAsset, baseDate, interpolationMethod, extrapolationPermitted, points, tolerance); // Check whether the guess was close enough if (!objectiveFunction.InitialValue()) { double guess = Math.Max(min, points[assetMaturityDate]); points[assetMaturityDate] = solver.Solve(objectiveFunction, tolerance, guess, min, max); } items.Add(assetMaturityDate, new Pair <string, decimal>(priceableAsset.Id, (decimal)points[assetMaturityDate])); } return(TermPointsFactory.Create(items)); }
///<summary> ///</summary> ///<param name="maturityDate">redemption date</param> ///<param name="lastCouponDate">last coupon date</param> ///<param name="couponRate">coupon rate</param> ///<param name="couponFrequency">coupons per year,1 for annual, 2 for semi, 4 for quarterly</param> ///<param name="faceValue">The face value of the bond.</param> ///<param name="dirtyPrice">dirty price</param> ///<returns></returns> public static double CalculateBondYTM(DateTime maturityDate, DateTime lastCouponDate, double couponRate, int couponFrequency, double faceValue, double dirtyPrice) { var c = new CalculateBondYTMObjectiveFunctionClass(maturityDate, lastCouponDate, couponRate, couponFrequency, faceValue, dirtyPrice); // Instantiate and initialise the equation solver. var solver = new Brent(); return(solver.Solve(c, .0000001, couponRate, 0.01)); }
/// <summary> /// Bootstraps the specified priceable assets. /// </summary> /// <param name="priceableAssets">The priceable assets.</param> /// <param name="baseDate">The base date.</param> /// <param name="extrapolationPermitted">The extrapolationPermitted flag.</param> /// <param name="interpolationMethod">The interpolationMethod.</param> /// <param name="tolerance">Solver tolerance to use.</param> /// <returns></returns> public static TermPoint[] Bootstrap(List <IPriceableFxAssetController> priceableAssets, DateTime baseDate, Boolean extrapolationPermitted, InterpolationMethod interpolationMethod, Double tolerance) { const Double solveRateGap = 0.015d;//should we need more precising perhaps??? const Decimal dfamMinThreshold = 0.0m; const Decimal defaultGuess = 0.9m; const Double accuracy = 0.000001d; InterpolationMethod interp = InterpolationMethodHelper.Parse("LinearInterpolation"); //only works for linear on zero. priceableAssets = priceableAssets.OrderBy(a => a.GetRiskMaturityDate()).ToList(); var dates = new List <DateTime>(); var discountFactors = new List <double>(); var items = new Dictionary <DateTime, Pair <string, decimal> >(); bool firstTime = true; foreach (var asset in priceableAssets) { DateTime assetMaturityDate = asset.GetRiskMaturityDate(); //check if the maturity date is already in the list. If not contimue. if (items.ContainsKey(assetMaturityDate)) { continue; } decimal guess = asset.ForwardAtMaturity > dfamMinThreshold ? asset.ForwardAtMaturity : defaultGuess; decimal dfam; if (firstTime) { firstTime = false; dates.Add(assetMaturityDate); discountFactors.Add(Convert.ToDouble(guess)); dfam = asset.CalculateImpliedQuote(new SimpleFxCurve(baseDate, interp, extrapolationPermitted, dates, discountFactors)); discountFactors[0] = (double)dfam; } else { //The first guess, which should be correct for all priceable assets with analytical solutions that have been implemented. //So far this is only wrt Depos and Futures...This now should automatically extrapolate the required discount factor on a flat rate basis. dfam = asset.CalculateImpliedQuote(new SimpleFxCurve(baseDate, interp, extrapolationPermitted, dates, discountFactors)); discountFactors.Add((double)dfam); dates.Add(assetMaturityDate); } //Add a check on the dfam so that the solver is only called if outside the tolerance. var objectiveFunction = new FxAssetQuote(asset, baseDate, interpolationMethod, extrapolationPermitted, dates, discountFactors, tolerance); if (!objectiveFunction.InitialValue()) { var timeInterval = Actual365.Instance.YearFraction(baseDate, assetMaturityDate); var solveInterval = Math.Exp(-solveRateGap * timeInterval); var min = Math.Max(0, (double)dfam * solveInterval); var max = (double)dfam / solveInterval; var solver = new Brent(); dfam = (decimal)solver.Solve(objectiveFunction, accuracy, (double)dfam, min, max); } items.Add(assetMaturityDate, new Pair <string, decimal>(asset.Id, dfam)); } return(TermPointsFactory.Create(items)); }
/// <summary> /// Bootstraps the specified priceable assets. /// </summary> /// <param name="priceableAssets">The priceable assets.</param> /// <param name="referenceCurve">The reference curve.</param> /// <param name="baseDate">The base date.</param> /// <param name="termCurve">The term Curve with pre-existing points. This will not work if there are no points.</param> /// <param name="tolerance">Solver tolerance to use.</param> /// <returns></returns> public static TermPoint[] Bootstrap(IList <IPriceableRateSpreadAssetController> priceableAssets, IRateCurve referenceCurve, DateTime baseDate, TermCurve termCurve, Double tolerance) { const double min = 0.000000001; const double max = 1; Dictionary <DateTime, Pair <string, decimal> > items = new Dictionary <DateTime, Pair <string, decimal> > (); // Add the elements (date : discount factor) to the list IDictionary <DateTime, double> dfs = new Dictionary <DateTime, double>(); foreach (var point in termCurve.point) { dfs.Add((DateTime)point.term.Items[0], (double)point.mid); items.Add((DateTime)point.term.Items[0], new Pair <string, decimal>(point.id, point.mid)); } var solver = new Brent(); foreach (var priceableAsset in priceableAssets) { var assetMaturityDate = priceableAsset.GetRiskMaturityDate(); if (dfs.ContainsKey(assetMaturityDate)) { continue; } //The first guess, which should be correct for all priceable assets with analytical solutions that have been implemented. //So far this is only wrt Depos and Futures...This now should automatically extrapolate the required discount factor on a flat rate basis. dfs.Add(assetMaturityDate, (double)priceableAsset.CalculateDiscountFactorAtMaturity(referenceCurve)); var objectiveFunction = new RateSpreadAssetQuote(priceableAsset, referenceCurve, baseDate, termCurve.extrapolationPermitted, dfs, tolerance); // check accuracy so that solver is only called if outside the tolerance. if (!objectiveFunction.InitialValue()) { dfs[assetMaturityDate] = solver.Solve(objectiveFunction, tolerance, dfs[assetMaturityDate], min, max); } items.Add(assetMaturityDate, new Pair <string, decimal>(priceableAsset.Id, (decimal)dfs[assetMaturityDate])); } return(TermPointsFactory.Create(items)); }
/// <summary> /// <remarks> /// Always: /// pay floating /// receive fixed /// </remarks> /// </summary> /// <param name="logger"></param> /// <param name="cache"></param> /// <param name="nameSpace"></param> /// <param name="valueDate"></param> /// <param name="effectiveDate"></param> /// <param name="terminationDate"></param> /// <param name="interpolationMethod"></param> /// <param name="margineAboveFloatingRate"></param> /// <param name="resetRate"></param> /// <param name="directionDateGenerationPayLeg"></param> /// <param name="cashFlowFrequencyPayLeg"></param> /// <param name="accrualMethodPayLeg"></param> /// <param name="holidaysPayLeg"></param> /// <param name="discountFactorCurvePayLeg"></param> /// <param name="directionDateGenerationRecLeg"></param> /// <param name="cashFlowFrequencyRecLeg"></param> /// <param name="accrualMethodRecLeg"></param> /// <param name="holidaysRecLeg"></param> /// <param name="discountFactorCurveRecLeg"></param> /// <returns></returns> public double GetSwapParRateWithoutCurves ( ILogger logger, ICoreCache cache, String nameSpace, DateTime valueDate, DateTime effectiveDate, DateTime terminationDate, string interpolationMethod, //1 is linear on forward rates => make sure that the right curve is provided ... double margineAboveFloatingRate, // use 0 initially double resetRate, int directionDateGenerationPayLeg, string cashFlowFrequencyPayLeg, string accrualMethodPayLeg, string holidaysPayLeg, IRateCurve discountFactorCurvePayLeg, int directionDateGenerationRecLeg, string cashFlowFrequencyRecLeg, string accrualMethodRecLeg, string holidaysRecLeg, IRateCurve discountFactorCurveRecLeg ) { const decimal dummyNotional = 1000000.0m; // received fixed leg // var recFixedCashflows = InterestRateSwapPricer.GenerateCashflows(logger, cache, nameSpace, null, valueDate, effectiveDate, terminationDate, interpolationMethod, margineAboveFloatingRate, resetRate, dummyNotional, directionDateGenerationRecLeg, cashFlowFrequencyRecLeg, accrualMethodRecLeg, holidaysRecLeg, discountFactorCurveRecLeg, true); recFixedCashflows.PayingFixedRate = false; // pay floating leg // var payFloatingCashflows = InterestRateSwapPricer.GenerateCashflows(logger, cache, nameSpace, null, valueDate, effectiveDate, terminationDate, interpolationMethod, margineAboveFloatingRate, resetRate, dummyNotional, directionDateGenerationPayLeg, cashFlowFrequencyPayLeg, accrualMethodPayLeg, holidaysPayLeg, discountFactorCurvePayLeg, false); payFloatingCashflows.PayingFixedRate = false; var objectiveFunction = new InterestRateSwapPricer { ReceiveLeg = recFixedCashflows, PayLeg = payFloatingCashflows }; var solver = new Brent { LowerBound = -100.0, UpperBound = 100.0 }; return(solver.Solve(objectiveFunction, Accuracy, Guess, Step)); }
/// <summary> /// /// </summary> /// <param name="logger"></param> /// <param name="cache"></param> /// <param name="nameSpace"></param> /// <param name="valueDate"></param> /// <param name="effectiveDate"></param> /// <param name="terminationDate"></param> /// <param name="interpolationMethod"></param> /// <param name="margineAboveFloatingRate"></param> /// <param name="resetRate"></param> /// <param name="notional"></param> /// <param name="directionDateGenerationPayLeg"></param> /// <param name="cashFlowFrequencyPayLeg"></param> /// <param name="accrualMethodPayLeg"></param> /// <param name="holidaysPayLeg"></param> /// <param name="rateCurvePayLeg"></param> /// <param name="directionDateGenerationRecLeg"></param> /// <param name="cashFlowFrequencyRecLeg"></param> /// <param name="accrualMethodRecLeg"></param> /// <param name="holidaysRecLeg"></param> /// <param name="rateCurveRecLeg"></param> /// <param name="layout"> /// if 0 - cashflows displayed one under another, /// if 1 - cashflows displayed side by side. /// </param> /// <returns> /// Pay cashflows: /// /// /// /// Rec cashflows: /// /// /// </returns> public object[,] GetSwapCashflowsWithoutCurves ( ILogger logger, ICoreCache cache, String nameSpace, DateTime valueDate, DateTime effectiveDate, DateTime terminationDate, string interpolationMethod, //1 is linear on forward rates => make sure that the right curve is provided ... double margineAboveFloatingRate, // use 0 initially double resetRate, decimal notional, int directionDateGenerationPayLeg, string cashFlowFrequencyPayLeg, string accrualMethodPayLeg, string holidaysPayLeg, IRateCurve rateCurvePayLeg, int directionDateGenerationRecLeg, string cashFlowFrequencyRecLeg, string accrualMethodRecLeg, string holidaysRecLeg, IRateCurve rateCurveRecLeg, int layout ) { // received fixed leg // var recFixedCashflows = InterestRateSwapPricer.GenerateCashflows(logger, cache, nameSpace, null, valueDate, effectiveDate, terminationDate, interpolationMethod, margineAboveFloatingRate, resetRate, notional, directionDateGenerationRecLeg, cashFlowFrequencyRecLeg, accrualMethodRecLeg, holidaysRecLeg, rateCurvePayLeg, true); // pay floating leg // var payFloatingCashflows = InterestRateSwapPricer.GenerateCashflows(logger, cache, nameSpace, null, valueDate, effectiveDate, terminationDate, interpolationMethod, margineAboveFloatingRate, resetRate, notional, directionDateGenerationPayLeg, cashFlowFrequencyPayLeg, accrualMethodPayLeg, holidaysPayLeg, rateCurveRecLeg, false); var objectiveFunction = new InterestRateSwapPricer { ReceiveLeg = recFixedCashflows, PayLeg = payFloatingCashflows }; var solver = new Brent { LowerBound = -100.0, UpperBound = 100.0 }; solver.Solve(objectiveFunction, Accuracy, Guess, Step); // bool bothLegsHaveTheSameStructure = // directionDateGenerationPayLeg == directionDateGenerationRecLeg && // cashFlowFrequencyPayLeg == cashFlowFrequencyRecLeg && // holidaysPayLeg == holidaysRecLeg; // if 0 - cashflows displayed one under another, // if 1 - cashflows displayed side by side. var result = 1 == layout?Utilities.GetCashflowsSideBySideExcelRange(payFloatingCashflows.Coupons, recFixedCashflows.Coupons) : Utilities.GetCashflowsOneUnderAnotherExcelRange(payFloatingCashflows.Coupons, recFixedCashflows.Coupons); return(result); }
/// <summary> /// Bootstraps the specified priceable assets. /// </summary> /// <param name="priceableAssets">The priceable assets.</param> /// <param name="forecastCurve">The forecast rate curve.</param> /// <param name="baseDate">The base date.</param> /// <param name="extrapolationPermitted">The extrapolationPermitted flag.</param> /// <param name="interpolationMethod">The interpolationMethod.</param> /// <param name="tolerance">Solver tolerance to use.</param> /// <param name="discountCurve">The discount rate curve.</param> /// <param name="curveProperties">The properties.</param> /// <returns></returns> public static SortedList <DateTime, Decimal> Bootstrap(IEnumerable <IPriceableOptionAssetController> priceableAssets, NamedValueSet curveProperties, IRateCurve discountCurve, IRateCurve forecastCurve, DateTime baseDate, Boolean extrapolationPermitted, InterpolationMethod interpolationMethod, Double tolerance) { const double min = 0.000000001; const double max = 2; if (interpolationMethod == null) { interpolationMethod = InterpolationMethodHelper.Parse("LinearInterpolation"); } var points = new SortedList <DateTime, Decimal>(); var solver = new Brent(); bool first = true; // Add the rest foreach (var priceableOptionAssetController in priceableAssets) { var priceableAsset = (IPriceableRateOptionAssetController)priceableOptionAssetController; DateTime assetMaturityDate = priceableAsset.GetExpiryDate(); if (points.Keys.Contains(assetMaturityDate)) { continue; } if (priceableAsset is PriceableRateFuturesOptionAsset || priceableAsset is PriceableSimpleRateOptionAsset) { points[assetMaturityDate] = priceableAsset.VolatilityAtRiskMaturity; first = false; } if (priceableAsset is PriceableCapRateAsset asset) { //Some new code which creates flat volatilities out to the first expisry when no ETO's are supplied. if (first) { var maturityDate = priceableAsset.GetRiskMaturityDate(); int weeks = DateHelper.GetWeeks(baseDate, maturityDate); for (var i = 1; i <= weeks; i++) { var shortEndDate = baseDate.AddDays(7 * i); points[shortEndDate] = priceableAsset.VolatilityAtRiskMaturity; } points[assetMaturityDate] = priceableAsset.VolatilityAtRiskMaturity; } else { //The first guess, which should be correct for all priceable assets with analytical solutions that have been implemented. points[assetMaturityDate] = priceableAsset.VolatilityAtRiskMaturity; //Set the ATM strike asset.DiscountCurve = discountCurve; asset.ForecastCurve = forecastCurve; asset.Strike = asset.CalculateImpliedParRate(baseDate); var objectiveFunction = new CapFloorAssetQuote(asset, discountCurve, forecastCurve, baseDate, interpolationMethod, extrapolationPermitted, points, tolerance); // Check whether the guess was close enough var initialValue = objectiveFunction.InitialValue(); if (initialValue) { continue; } var tempMax = (double)points[assetMaturityDate]; double guess = Math.Max(min, tempMax); var result = solver.Solve(objectiveFunction, tolerance, guess, min, max); points[assetMaturityDate] = (decimal)result; } } } return(points); }
/// <summary> /// Bootstraps the specified priceable assets. /// </summary> /// <param name="priceableAssets">The priceable assets.</param> /// <param name="baseDate">The base date.</param> /// <param name="extrapolationPermitted">The extrapolationPermitted flag.</param> /// <param name="interpolationMethod">The interpolationMethod.</param> /// <param name="tolerance">Solver tolerance to use.</param> /// <returns></returns> public static TermPoint[] Bootstrap(List <IPriceableCreditAssetController> priceableAssets, DateTime baseDate, Boolean extrapolationPermitted, InterpolationMethod interpolationMethod, Double tolerance) { const Double cSolveRateGap = 0.015d;//should be need more precise perhaps??? const Decimal cDfamMinThreshold = 0.0m; const Decimal cDefaultGuess = 0.9m; const Double accuracy = 0.000001d; priceableAssets.Sort ( (priceableAssetController1, priceableAssetController2) => priceableAssetController1.GetRiskMaturityDate().CompareTo(priceableAssetController2.GetRiskMaturityDate()) ); // Add the first element (date : discount factor) to the list // IList <DateTime> dates = new List <DateTime> { baseDate }; IList <double> discountFactors = new List <double> { 1.0 }; var index = 0; foreach (var priceableAsset in priceableAssets) { //TODO check if the maturity date is already in the list. If not contimue. var assetMaturityDate = priceableAsset.GetRiskMaturityDate(); if (dates.Contains(assetMaturityDate)) { continue; } // do we really need that guess step??? I don't think so... // var guess = priceableAsset.SurvivalProbabilityAtMaturity; if (guess <= cDfamMinThreshold) { guess = cDefaultGuess; } //dates.Add(priceableAsset.GetRiskMaturityDate()); decimal dfam; double[] values; //var position = dates.IndexOf(priceableAsset.GetRiskMaturityDate()); //discountFactors.CopyTo(values, 0); //only works for linear on zero. var interp = InterpolationMethodHelper.Parse("LogLinearInterpolation"); if (index == 0) { dates.Add(priceableAsset.GetRiskMaturityDate()); values = new double[dates.Count]; var position = dates.IndexOf(priceableAsset.GetRiskMaturityDate()); discountFactors.CopyTo(values, 0); values[position] = Convert.ToDouble(guess); dfam = priceableAsset.CalculateImpliedQuote(new SimpleDiscountFactorCurve(baseDate, interp, extrapolationPermitted, dates, values)); values[position] = (double)dfam; index++; } else { //The first guess, which should be correct for all priceable assets with analytical solutions that have been implemented. //So far this is only wrt Depos and Futures...This now should automatically extrapolate the required discount factor on a flat rate basis. var tempvalues = new List <double>(discountFactors); dfam = priceableAsset.CalculateImpliedQuote(new SimpleDiscountFactorCurve(baseDate, interp, extrapolationPermitted, dates, tempvalues.ToArray())); tempvalues.Add((double)dfam); dates.Add(priceableAsset.GetRiskMaturityDate()); values = new double[dates.Count]; tempvalues.CopyTo(values, 0); index++; } //Add a check on the dfam so that the solver is only called if outside tyhe tolerance. var objectiveFunction = new CreditAssetQuote(priceableAsset, baseDate, interpolationMethod, extrapolationPermitted, dates, values, tolerance); if (objectiveFunction.InitialValue()) { discountFactors.Add((double)dfam); } else { var timeInterval = Actual365.Instance.YearFraction(baseDate, assetMaturityDate); var cSolveInterval = Math.Exp(-cSolveRateGap * timeInterval); var min = Math.Max(0, (double)dfam * cSolveInterval); var max = (double)dfam / cSolveInterval; var solver2 = new Brent(); var solvedFiscountFactor = solver2.Solve(objectiveFunction, accuracy, (double)dfam, min, max); //TODO check that this is the correct usage of the optimizer. discountFactors.Add(solvedFiscountFactor); } } return(TermPointsFactory.Create(dates, discountFactors)); }