/// <summary> /// Creates synthetic swaps from FX curve for period under 1 year /// </summary> /// <param name="rateCurve"></param> /// <returns></returns> public TermPoint[] RemovePoints(IRateCurve rateCurve) { var fxTermCurve = rateCurve.GetTermCurve(); var curveId = GetRateCurveId(); var termDate = CutOverTerm.Add(curveId.BaseDate); return((from point in fxTermCurve.point let pillarPoint = (DateTime)point.term.Items[0] where pillarPoint <= termDate select point).ToArray()); }
public NewtonRaphsonSolverFunctions(IPriceableAssetController asset, IPriceableAssetController previousAsset, PricingStructureAlgorithmsHolder algorithmHolder, IRateCurve baseCurve, DateTime baseDate, SortedDictionary <DateTime, Pair <string, decimal> > items, double compoundingPeriod, IDictionary <DateTime, double> zeroRateSpreads, IDayCounter dayCounter, List <DateTime> assetDates) { _asset = asset; _baseCurve = baseCurve; _zeroRateSpreads = zeroRateSpreads; string currency = PropertyHelper.ExtractCurrency(baseCurve.GetPricingStructureId().Properties); _algorithm = algorithmHolder; _properties = new NamedValueSet(new Dictionary <string, object> { { CurveProp.PricingStructureType, "RateCurve" }, { CurveProp.Market, "DiscountCurveConstruction" }, { CurveProp.IndexTenor, "0M" }, { CurveProp.Currency1, currency }, { "Index", "XXX-XXX" }, { "Algorithm", "FastLinearZero" }, { "BaseDate", baseDate }, }); _items = items; _compoundingPeriod = compoundingPeriod; _dayCounter = dayCounter; _assetDates = assetDates; if (previousAsset != null) { DateTime previousAssetMaturity = previousAsset.GetRiskMaturityDate(); DateTime assetMaturity = asset.GetRiskMaturityDate(); IEnumerable <KeyValuePair <DateTime, string> > points = from b in baseCurve.GetTermCurve().point where (DateTime)b.term.Items[0] > previousAssetMaturity && (DateTime)b.term.Items[0] < assetMaturity select new KeyValuePair <DateTime, string>((DateTime)b.term.Items[0], b.id); foreach (KeyValuePair <DateTime, string> point in points) { _extraPoints.Add(point.Key, point.Value); Pair <string, decimal> pair = new Pair <string, decimal>(point.Value, 0); items.Add(point.Key, pair); } } }
/// <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)); }