/// <summary> /// Sets the interpolator. /// </summary> /// <param name="baseDate">The base date.</param> /// <param name="holder">The holder.</param> private void SetInterpolator(DateTime baseDate, PricingStructureAlgorithmsHolder holder) { // The underlying curve and associated compounding frequency (compounding frequency required when underlying curve is a ZeroCurve) var curveInterpolationMethod = InterpolationMethodHelper.Parse(holder.GetValue("CurveInterpolation")); var dayCounter = DayCounterHelper.Parse(holder.GetValue("DayCounter")); UnderlyingInterpolatedCurve = holder.GetValue("UnderlyingCurve"); //TODO this redundant. // Retrieve the Discount factor curve and assign the curve interpolation we want to initiate // This dependends on the underyling curve type (i.e. rate or discount factor) var termCurve = GetFxCurveValuation().fxForwardCurve; termCurve.interpolationMethod = curveInterpolationMethod; // interpolate the DiscountFactor curve based on the respective curve interpolation Interpolator = new CommodityCurveInterpolator(termCurve, baseDate, dayCounter); }
/// <summary> /// Sets the interpolator. /// </summary> private void SetInterpolator(DateTime baseDate) { // The underlying curve and associated compounding frequency (compounding frequency required when underlying curve is a ZeroCurve) InterpolationMethod curveInterpolationMethod = InterpolationMethodHelper.Parse(Holder.GetValue("CurveInterpolation")); IDayCounter dayCounter = DayCounterHelper.Parse(Holder.GetValue("DayCounter")); UnderlyingInterpolatedCurve = Holder.GetValue("UnderlyingCurve"); // Retrieve the Discount factor curve and assign the curve interpolation we want to initiate // This dependends on the underyling curve type (i.e. rate or discount factor) TermCurve termCurve = GetEquityCurveValuation().fxForwardCurve; termCurve.interpolationMethod = curveInterpolationMethod; // interpolate the DiscountFactor curve based on the respective curve interpolation Interpolator = new FxCurveInterpolator(termCurve, baseDate, dayCounter); }
/// <summary> /// Create a surface from an FpML /// </summary> /// <param name="logger"></param> /// <param name="cache"></param> /// <param name="nameSpace"></param> /// <param name="fpmlData"></param> /// <param name="properties"></param> public ExpiryTermTenorStrikeVolatilityCube(ILogger logger, ICoreCache cache, String nameSpace, Pair <PricingStructure, PricingStructureValuation> fpmlData, NamedValueSet properties) { var surfaceId = new VolatilitySurfaceIdentifier(properties); Algorithm = surfaceId.Algorithm; PricingStructureIdentifier = surfaceId; var holder = new PricingStructureAlgorithmsHolder(logger, cache, nameSpace, surfaceId.PricingStructureType, surfaceId.Algorithm); Algorithm = "Linear"; //Add as a propert in the id. var curveInterpolationMethod = InterpolationMethodHelper.Parse(holder.GetValue("CurveInterpolation")); var data = (VolatilityMatrix)fpmlData.Second; DateTime baseDate = data.baseDate.Value; Interpolator = new VolSurfaceInterpolator(data.dataPoints, curveInterpolationMethod, true, baseDate); SetFpMLData(fpmlData); }
/// <summary> /// Create a surface from an FpML /// </summary> /// <param name="logger">The logger.</param> /// <param name="cache">The cache.</param> /// <param name="nameSpace">The nameSpace</param> /// <param name="fpmlData">The data.</param> /// <param name="properties">The properties.</param> protected ExpiryTermStrikeVolatilitySurface(ILogger logger, ICoreCache cache, String nameSpace, Pair <PricingStructure, PricingStructureValuation> fpmlData, NamedValueSet properties) { var data = (VolatilityMatrix)fpmlData.Second; Algorithm = "Linear";//Add as a property in the id. //Creates the property collection. This should be backward compatable with V1. var surfaceId = new VolatilitySurfaceIdentifier(properties); PricingStructureIdentifier = surfaceId; var holder = new PricingStructureAlgorithmsHolder(logger, cache, nameSpace, surfaceId.PricingStructureType, surfaceId.Algorithm); var curveInterpolationMethod = InterpolationMethodHelper.Parse(holder.GetValue("CurveInterpolation")); Interpolator = new VolSurfaceInterpolator(data.dataPoints, curveInterpolationMethod, true, PricingStructureIdentifier.BaseDate); SetFpmlData(fpmlData); _matrixIndexHelper = new SortedList <ExpiryTenorStrikeKey, int>(new ExpiryTenorStrikeKey()); ProcessVolatilityRepresentation(); }
/// <summary> /// Initializes a new instance of the <see cref="RateBasisCurve"/> class. /// </summary> /// <param name="referenceCurve">The reference curve.</param> /// <param name="spreadAssets">The spreads by asset.</param> /// <param name="properties">The properties of the new spread curve.</param> /// <param name="algorithm">The algorithm holder. </param> public RateBasisCurve(NamedValueSet properties, IRateCurve referenceCurve, List <IPriceableRateSpreadAssetController> spreadAssets, PricingStructureAlgorithmsHolder algorithm) : base(properties, algorithm) { PricingStructureData = new PricingStructureData(CurveType.Child, AssetClass.Rates, properties); //Set the identifier. var pricingStructureId = GetRateCurveId(); if (pricingStructureId.PricingStructureType != PricingStructureTypeEnum.RateBasisCurve) { return; } //Set the reference curve BaseCurve = referenceCurve; ReferenceCurveId = BaseCurve.GetPricingStructureId(); PriceableRateSpreadAssets = spreadAssets; //Order the assets. PriceableRateSpreadAssets = PriceableRateSpreadAssets.OrderBy(a => a.GetRiskMaturityDate()).ToList(); var termCurve = SetConfigurationData(); //Get the reference interpolated curve. termCurve.point = RateSpreadBootstrapper.Bootstrap(PriceableRateSpreadAssets, BaseCurve, pricingStructureId.BaseDate, termCurve.extrapolationPermitted, Tolerance); CreatePricingStructure(pricingStructureId, termCurve, PriceableAssetFactory.Parse(PriceableRateSpreadAssets)); SetInterpolator(BaseCurve, pricingStructureId.PricingStructureType); // Set the Zero curve, just for reference YieldCurveValuation yieldCurveValuation = GetYieldCurveValuation(); if (yieldCurveValuation.zeroCurve?.rateCurve == null) { //var curveId = (RateCurveIdentifier)PricingStructureIdentifier; //var psType = PricingStructureIdentifier.PricingStructureType; TermCurve curve = YieldCurveAnalytics.ToZeroCurve(termCurve, GetBaseDate(), CompoundingFrequency, DayCounter); curve.interpolationMethod = InterpolationMethodHelper.Parse(Holder.GetValue("CurveInterpolation")); var zeroCurve = new ZeroRateCurve { rateCurve = curve, compoundingFrequency = FpML.V5r3.Reporting.CompoundingFrequency.Create(CompoundingFrequency) }; yieldCurveValuation.zeroCurve = zeroCurve; } }
private static IRateCurve GetDiscountFactorCurveFromObject(object discountFactorCurveObject, string paramName) { IRateCurve curve; if (discountFactorCurveObject is IRateCurve o) { curve = o; } else { if (discountFactorCurveObject is object[,] array) { // extract from [ , ] // [ , ] // [ , ] // [ , ] array var discountFactorCurveObjectAsArray = array; int dim0LowerBound = (discountFactorCurveObjectAsArray).GetLowerBound(0); int dim1LowerBound = (discountFactorCurveObjectAsArray).GetLowerBound(1); int dim0UpperBound = (discountFactorCurveObjectAsArray).GetUpperBound(0); var listDt = new List <DateTime>(); var listDf = new List <double>(); for (int i = dim0LowerBound; i <= dim0UpperBound; ++i) { var dt = (DateTime)discountFactorCurveObjectAsArray[i, dim1LowerBound]; var df = (double)discountFactorCurveObjectAsArray[i, dim1LowerBound + 1]; listDt.Add(dt); listDf.Add(df); } DateTime baseDate = listDt[0]; InterpolationMethod interp = InterpolationMethodHelper.Parse("LinearInterpolation"); //SimpleDFToZeroRateCurve curve = new SimpleDFToZeroRateCurve(baseDate, interp, false, dates, dfs); curve = new SimpleDiscountFactorCurve(baseDate, interp, false, listDt.ToArray(), listDf.ToArray()); } else { var message = $"{paramName} is invalid"; throw new ArgumentException(message, paramName); } } return(curve); }
/// <summary> /// Takes a range of volatilities, an array of tenor expiries and an /// array of strikes to create a VolatilitySurface /// </summary> /// <param name="logger"></param> /// <param name="cache"></param> /// <param name="nameSpace"></param> /// <param name="expiryTenors"></param> /// <param name="strikes"></param> /// <param name="volSurface"></param> /// <param name="surfaceId"></param> public ExpiryTermTenorStrikeVolatilityCube(ILogger logger, ICoreCache cache, String nameSpace, String[] expiryTenors, Double[] strikes, Double[,] volSurface, VolatilitySurfaceIdentifier surfaceId) { Algorithm = surfaceId.Algorithm; var holder = new PricingStructureAlgorithmsHolder(logger, cache, nameSpace, surfaceId.PricingStructureType, surfaceId.Algorithm); var curveInterpolationMethod = InterpolationMethodHelper.Parse(holder.GetValue("CurveInterpolation")); var points = ProcessRawSurface(expiryTenors, strikes, volSurface); PricingStructure = new VolatilityRepresentation { name = surfaceId.Name, id = surfaceId.Id, asset = new AnyAssetReference { href = "Unknown" }, }; var datapoints = new MultiDimensionalPricingData { point = points }; PricingStructureValuation = new VolatilityMatrix { dataPoints = datapoints , objectReference = new AnyAssetReference { href = PricingStructure.id } , baseDate = new IdentifiedDate { Value = surfaceId.BaseDate } , buildDateTime = DateTime.Now , buildDateTimeSpecified = true }; var expiries = new double[expiryTenors.Length]; var index = 0; foreach (var term in expiryTenors)//TODO include business day holidays and roll conventions. { expiries[index] = PeriodHelper.Parse(term).ToYearFraction(); index++; } // Generate an interpolator to use Interpolator = new VolSurfaceInterpolator(expiries, strikes, new Matrix(volSurface), curveInterpolationMethod, true); }
private void CreateYieldCurve() { var curveId = (RateCurveIdentifier)PricingStructureIdentifier; InterpolationMethod interpolationMethod = InterpolationMethodHelper.Parse(Holder.GetValue("BootstrapperInterpolation")); bool extrapolationPermitted = bool.Parse(Holder.GetValue("ExtrapolationPermitted")); TermPoint[] points = BaseCurve != null ? new RateBootstrapperNewtonRaphson().Bootstrap(PriceableRateAssets, BaseCurve, Holder) : null; //TermPoint[] points = BaseCurve != null ? RateXccySpreadBootstrapper.Bootstrap(PriceableRateAssets, BaseCurve, Holder) : null; var termCurve = new TermCurve { extrapolationPermitted = extrapolationPermitted, extrapolationPermittedSpecified = true, interpolationMethod = interpolationMethod, point = points }; CreatePricingStructure(curveId, termCurve, PriceableRateAssets, null); }
private void InitialiseInstance(ILogger logger, ICoreCache cache, string nameSpace, NamedValueSet properties, FxRateSet assetSet, IBusinessCalendar fixingCalendar, IBusinessCalendar rollCalendar) { PricingStructureData = new PricingStructureData(CurveType.Parent, AssetClass.Equity, properties); var curveId = new EquityCurveIdentifier(properties); PricingStructureIdentifier = curveId; Holder = new PricingStructureAlgorithmsHolder(logger, cache, nameSpace, curveId.PricingStructureType, curveId.Algorithm); DateTime baseDate = PricingStructureIdentifier.BaseDate; //Set the spot date; SettlementDate = GetSettlementDate(logger, cache, nameSpace, GetEquityCurveId(), fixingCalendar, rollCalendar, baseDate); //TODO //FixingCalendar = null; //RollCalendar = null; // The bootstrapper to use BootstrapperName = Holder.GetValue("Bootstrapper"); Tolerance = double.Parse(Holder.GetValue("Tolerance")); bool extrapolationPermitted = bool.Parse(Holder.GetValue("ExtrapolationPermitted")); InterpolationMethod interpolationMethod = InterpolationMethodHelper.Parse(Holder.GetValue("BootstrapperInterpolation")); var termCurve = new TermCurve { extrapolationPermitted = extrapolationPermitted, extrapolationPermittedSpecified = true, interpolationMethod = interpolationMethod }; PriceableEquityAssets = PriceableAssetFactory.CreatePriceableEquityAssets(logger, cache, nameSpace, baseDate, assetSet, fixingCalendar, rollCalendar); termCurve.point = EquityBootstrapper.Bootstrap(PriceableEquityAssets, baseDate, termCurve.extrapolationPermitted, termCurve.interpolationMethod, Tolerance); // Pull out the fx curve and fx curve valuation Pair <PricingStructure, PricingStructureValuation> fpmlData = CreateFpmlPair(logger, cache, nameSpace, baseDate, (EquityCurveIdentifier)PricingStructureIdentifier, assetSet, termCurve, fixingCalendar, rollCalendar); SetFpmlData(fpmlData); // Interpolate the DiscountFactor curve based on the respective curve interpolation SetInterpolator(baseDate); }
//TODO this is not yet implemented. FIX IT! internal void SetSpreadInterpolator(TermCurve discountFactorCurve, string algorithm, PricingStructureTypeEnum psType) { var curveId = (RateCurveIdentifier)PricingStructureIdentifier; // The underlying curve and associated compounding frequency (compounding frequency required when underlying curve is a ZeroCurve) CompoundingFrequency = EnumHelper.Parse <CompoundingFrequencyEnum>(Holder.GetValue("CompoundingFrequency")); UnderlyingInterpolatedCurve = Holder.GetValue("UnderlyingCurve"); //TODO this redundant. var interpDayCounter = Actual365.Instance; var underlyingCurve = ParseUnderlyingCurve(UnderlyingInterpolatedCurve); // interpolate the DiscountFactor curve based on the respective curve interpolation if (underlyingCurve != UnderlyingCurveTypes.ZeroCurve) { Interpolator = new TermCurveInterpolator(discountFactorCurve, GetBaseDate(), interpDayCounter); } // otherwise interpolate our underlying curve will be a zero curve else { var zeroCurve = new ZeroRateCurve { rateCurve = YieldCurveAnalytics.ToZeroCurve(discountFactorCurve, GetBaseDate(), CompoundingFrequency, DayCounter) }; zeroCurve.rateCurve.interpolationMethod = InterpolationMethodHelper.Parse(Holder.GetValue("CurveInterpolation")); zeroCurve.compoundingFrequency = FpML.V5r3.Reporting.CompoundingFrequency.Create(CompoundingFrequency); GetYieldCurveValuation().zeroCurve = zeroCurve; if (curveId.Algorithm == "SpreadInterpolation") { } else { Interpolator = new TermCurveInterpolator(GetYieldCurveValuation().zeroCurve.rateCurve, GetBaseDate(), interpDayCounter); }//TODO this is where to add the spread stuff. } }
/// <summary> /// Create a Sortedlist of bootstrap engines from the data matrix /// </summary> /// <param name="logger">The logger</param> /// <param name="cache">The cache.</param> /// <param name="nameSpace"></param> /// <param name="engineHandle">The engine collection name</param> /// <param name="matrix">The internal data structure used in conversion</param> /// <param name="properties">The properties object to use</param> /// <returns></returns> private static SortedList <decimal, CapVolatilityCurve> CreateEngines(ILogger logger, ICoreCache cache, string nameSpace, string engineHandle, CapFloorVolatilityMatrix matrix, NamedValueSet properties) { var engines = new SortedList <decimal, CapVolatilityCurve>(); // Check there is a valid settings object if (properties == null) { return(null); } var currency = properties.GetString("Currency", true); var baseDate = properties.GetValue("Calculation Date", DateTime.MinValue); properties.Set("EngineHandle", engineHandle); matrix.ValuationDate = baseDate; var valuationDate = properties.GetValue("ValuationDate", DateTime.MinValue); if (valuationDate == DateTime.MinValue) { properties.Set("ValuationDate", baseDate); } properties.Set("PricingStructureType", PricingStructureTypeEnum.CapVolatilityCurve.ToString()); var strikeQuoteUnits = properties.GetString("StrikeQuoteUnits", null); if (strikeQuoteUnits == null) { properties.Set("StrikeQuoteUnits", StrikeQuoteUnitsEnum.ATMFlatMoneyness.ToString()); } var measureType = properties.GetString("MeasureType", null); if (measureType == null) { properties.Set("MeasureType", MeasureTypesEnum.Volatility.ToString()); } var quoteUnits = properties.GetString("QuoteUnits", null); if (quoteUnits == null) { properties.Set("QuoteUnits", QuoteUnitsEnum.LogNormalVolatility.ToString()); } var algorithm = properties.GetString("Algorithm", null); if (algorithm == null) { properties.Set("Algorithm", "Default"); } InterpolationMethod interp = InterpolationMethodHelper.Parse("LogLinearInterpolation"); var dfs = matrix.DiscountFactorsAsDoubles(); // Check there are valid strikes IRateCurve discountCurve = new SimpleDiscountFactorCurve(baseDate, interp, true, dfs); //TODO //The quoted asset set var volTypes = matrix.CapVolatilities(); var instruments = new List <string>(); var volatilties = new List <decimal>(); foreach (var volType in volTypes) { string tempName; string tenor; var type = volType.VolatilityType; if (type == VolatilityDataType.ETO) { tempName = currency + "-Caplet-"; tenor = volType.Expiry + "D-90D"; } else { tempName = currency + "-IRCap-"; tenor = volType.Expiry + "Y"; } instruments.Add(tempName + tenor); volatilties.Add(volType.Volatility); } var qas = AssetHelper.Parse(instruments.ToArray(), volatilties.ToArray()); //The volatilities // Create a new ATM CapletBootstrap engine. The default decimal should be 0 var engine = new CapVolatilityCurve(logger, cache, nameSpace, properties, qas, discountCurve, discountCurve, null, null); // Add engine engines.Add(0, engine); return(engines); }
/// <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 <IPriceableCommodityAssetController> priceableAssets, DateTime baseDate, Boolean extrapolationPermitted, InterpolationMethod interpolationMethod, Double tolerance) { //const Double cSolveRateGap = 0.015d;//should we need more precising perhaps??? //const double Min = 0.000000001; //const double max = 2; const double defaultGuess = 0.9; //const Double accuracy = 0.000001d; priceableAssets.Sort ( (priceableAssetController1, priceableAssetController2) => priceableAssetController1.GetRiskMaturityDate().CompareTo(priceableAssetController2.GetRiskMaturityDate()) ); // Add the first element (date : discount factor) to the list // // 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) } } bool first = true; foreach (var priceableAsset in priceableAssets) { //TODO check if the maturity date is already in the list. If not contimue. var assetMaturityDate = priceableAsset.GetRiskMaturityDate(); if (points.Keys.Contains(assetMaturityDate)) { continue; } // do we really need that guess step??? I don't think so... // //if (assetMaturityDate < points.Keys.Last()) //{ // throw new InvalidOperationException("The maturity dates of the assets must be consecutive order"); //} //only works for linear on zero. var interp = InterpolationMethodHelper.Parse("LinearInterpolation"); decimal dfam; if (first) { first = false; // Add the first point points.Add(assetMaturityDate, defaultGuess); var curve = new SimpleCommodityCurve(baseDate, interp, extrapolationPermitted, points); dfam = priceableAsset.CalculateImpliedQuote(curve); points[assetMaturityDate] = (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. var curve = new SimpleCommodityCurve(baseDate, interp, extrapolationPermitted, points); //The first guess, which should be correct for all priceable assets with analytical solutions that have been implemented. dfam = priceableAsset.CalculateImpliedQuote(curve); points.Add(assetMaturityDate, (double)dfam); } //Add a check on the dfam so that the solver is only called if outside tyhe tolerance. //var objectiveFunction = new CommodityAssetQuote(priceableAsset, baseDate, interpolationMethod, // extrapolationPermitted, points, tolerance); //// Check whether the guess was close enough //if (!objectiveFunction.InitialValue()) //{ // 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; // double guess = Math.Max(min, points[assetMaturityDate]); // var solver = new Brent(); // 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> /// 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="extrapolationPermitted">The extrapolationPermitted flag.</param> /// <param name="tolerance">The tolerance for the solver</param> /// <returns></returns> public static TermPoint[] Bootstrap(IEnumerable <IPriceableRateSpreadAssetController> priceableAssets, IRateCurve referenceCurve, DateTime baseDate, bool extrapolationPermitted, 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; foreach (var 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); IRateCurve curve = IsSpreadAsset(priceableAsset) ? referenceCurve : 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. IRateCurve curve = IsSpreadAsset(priceableAsset) ? referenceCurve : 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)); } IObjectiveFunction objectiveFunction; bool initialValue; if (IsSpreadAsset(priceableAsset)) { objectiveFunction = new RateSpreadAssetQuote(priceableAsset, referenceCurve, baseDate, extrapolationPermitted, points, tolerance); initialValue = ((RateSpreadAssetQuote)objectiveFunction).InitialValue(); } else { objectiveFunction = new RateAssetQuote(priceableAsset, baseDate, interp, extrapolationPermitted, points, tolerance); initialValue = ((RateAssetQuote)objectiveFunction).InitialValue(); } // Check whether the guess was close enough if (!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> /// 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)); }
/// <summary> /// /// </summary> /// <param name="logger"></param> /// <param name="cache"></param> /// <param name="nameSpace"></param> /// <param name="properties"></param> /// <param name="expiries"></param> /// <param name="vols"></param> /// <param name="inputInstruments"></param> /// <param name="inputSwapRates"></param> /// <param name="inputBlackVolRates"></param> protected ExpiryTermStrikeVolatilitySurface(ILogger logger, ICoreCache cache, String nameSpace, NamedValueSet properties, DateTime[] expiries, double[] vols, string[] inputInstruments, double[] inputSwapRates, double[] inputBlackVolRates) { Algorithm = PropertyHelper.ExtractAlgorithm(properties); PricingStructureIdentifier = new VolatilitySurfaceIdentifier(properties); var surfaceId = (VolatilitySurfaceIdentifier)PricingStructureIdentifier; var expiryLength = expiries.Length; var pointIndex = 0; var points = new PricingStructurePoint[expiryLength]; _matrixIndexHelper = new SortedList <ExpiryTenorStrikeKey, int>(new ExpiryTenorStrikeKey()); for (var expiryIndex = 0; expiryIndex < expiryLength; expiryIndex++) { // extract the current expiry var expiryKeyPart = expiries[expiryIndex]; var key = new ExpiryTenorStrikeKey(expiryKeyPart.ToString(CultureInfo.InvariantCulture), 0); _matrixIndexHelper.Add(key, pointIndex); // Add the value to the points array (dataPoints entry in the matrix) var coordinates = new PricingDataPointCoordinate[1]; coordinates[0] = new PricingDataPointCoordinate { expiration = new TimeDimension[1] }; coordinates[0].expiration[0] = new TimeDimension { Items = new object[] { expiries[expiryIndex] } }; var pt = new PricingStructurePoint { value = (decimal)vols[expiryIndex], valueSpecified = true, coordinate = coordinates, }; points[pointIndex++] = pt; } // Record the row/column sizes of the inputs _matrixRowCount = expiries.Length; _matrixColumnCount = 1; PricingStructure = CreateVolatilityRepresentation(surfaceId); PricingStructureValuation = CreateDataPoints(points, surfaceId); if (inputInstruments != null) { int inputCount = inputInstruments.GetUpperBound(0); var assetQuotes = new List <BasicAssetValuation>(); var assetSet = new List <Asset>(); var itemsList = new List <ItemsChoiceType19>(); for (int i = 0; i <= inputCount; i++) { var assetProperties = new PriceableAssetProperties(inputInstruments[i]); assetSet.Add(new SimpleIRSwap { id = inputInstruments[i], term = assetProperties.TermTenor }); var rateQuote = BasicQuotationHelper.Create((decimal)inputSwapRates[i], AssetMeasureEnum.MarketQuote, PriceQuoteUnitsEnum.DecimalRate); var volQuote = BasicQuotationHelper.Create((decimal)inputBlackVolRates[i], AssetMeasureEnum.Volatility, PriceQuoteUnitsEnum.LogNormalVolatility); assetQuotes.Add(new BasicAssetValuation { objectReference = new AnyAssetReference { href = inputInstruments[i] }, definitionRef = assetProperties.TermTenor.ToString(), quote = new[] { rateQuote, volQuote } }); itemsList.Add(ItemsChoiceType19.simpleIrSwap);//TODO NOt actually correct. } var instrumentSet = new InstrumentSet { Items = assetSet.ToArray(), ItemsElementName = itemsList.ToArray() }; ((VolatilityMatrix)PricingStructureValuation).inputs = new QuotedAssetSet { assetQuote = assetQuotes.ToArray(), instrumentSet = instrumentSet }; } // Generate an interpolator to use double[] expiryTerms = expiries.Select(a => (surfaceId.BaseDate - a).TotalDays / 365d).ToArray(); var holder = new PricingStructureAlgorithmsHolder(logger, cache, nameSpace, surfaceId.PricingStructureType, surfaceId.Algorithm); var curveInterpolationMethod = InterpolationMethodHelper.Parse(holder.GetValue("CurveInterpolation")); Interpolator = new VolSurfaceInterpolator(expiryTerms, new double[] { 1 }, new Matrix(vols), curveInterpolationMethod, true); }
/// <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> /// Create a series of CapFloor engines from a raw volatility grid and a DF curve /// </summary> /// <param name="logger">The logger.</param> /// <param name="cache">The cache.</param> /// <param name="nameSpace">The client namespace</param> /// <param name="properties">The properties of the engine, including the reference handle to access this engine collection</param> /// <param name="instruments">An array of instrument types.</param> /// <param name="rawVolatilityGrid">The raw grid used to build the engines. Assume that all volatility and strike values are 100x true</param> /// <param name="dfDataTimeGrid">The discount factor dates array.</param> /// <param name="dfGrid">The discount factors required for bootstrapping</param> /// <returns>The engine handle or an error message</returns> public string CreateCapFloorCurve(ILogger logger, ICoreCache cache, string nameSpace, NamedValueSet properties, String[] instruments, Decimal[] rawVolatilityGrid, DateTime[] dfDataTimeGrid, Decimal[] dfGrid) { var volatilityCheck = CheckVolatilities(rawVolatilityGrid); if (volatilityCheck != null) { throw new ArgumentException(volatilityCheck); } var id = properties.GetString("EngineHandle", true); var baseDate = properties.GetValue <DateTime>("BaseDate", true); var valuationDate = properties.GetValue("ValuationDate", DateTime.MinValue); if (valuationDate == DateTime.MinValue) { properties.Set("ValuationDate", baseDate); } properties.Set("PricingStructureType", PricingStructureTypeEnum.CapVolatilityCurve.ToString()); var strikeQuoteUnits = properties.GetString("StrikeQuoteUnits", null); if (strikeQuoteUnits == null) { properties.Set("StrikeQuoteUnits", StrikeQuoteUnitsEnum.ATMFlatMoneyness.ToString()); } var measureType = properties.GetString("MeasureType", null); if (measureType == null) { properties.Set("MeasureType", MeasureTypesEnum.Volatility.ToString()); } var quoteUnits = properties.GetString("QuoteUnits", null); if (quoteUnits == null) { properties.Set("QuoteUnits", QuoteUnitsEnum.LogNormalVolatility.ToString()); } var algorithm = properties.GetString("Algorithm", null); if (algorithm == null) { properties.Set("Algorithm", "Default"); } InterpolationMethod interp = InterpolationMethodHelper.Parse("LogLinearInterpolation"); // Check there are valid strikes IRateCurve discountCurve = new SimpleDiscountFactorCurve(baseDate, interp, true, dfDataTimeGrid, dfGrid); // Create the engines and either add to, or overwrite the existing, collection if (_capFloorEngine.ContainsKey(id)) { _capFloorEngine[id] = CreateCurves(logger, cache, nameSpace, properties, discountCurve, discountCurve, instruments, rawVolatilityGrid); } else { _capFloorEngine.Add(id, CreateCurves(logger, cache, nameSpace, properties, discountCurve, discountCurve, instruments, rawVolatilityGrid)); } return(id); }
/// <summary> /// Takes a range of volatilities, an array of tenor expiries and an /// array of strikes to create a VolatilitySurface /// </summary> /// <param name="logger">The logger.</param> /// <param name="cache">The cache.</param> /// <param name="nameSpace"></param> /// <param name="expiryTenors"></param> /// <param name="tenors"></param> /// <param name="volSurface"></param> /// <param name="surfaceId"></param> /// <param name="baseDate"></param> /// <param name="algorithm">The algorithm for interpolation.</param> protected ExpiryTermTenorATMVolatilitySurface(ILogger logger, ICoreCache cache, String nameSpace, String[] expiryTenors, String[] tenors, Double[,] volSurface, VolatilitySurfaceIdentifier surfaceId, DateTime baseDate, string algorithm) { Algorithm = algorithm; PricingStructureIdentifier = surfaceId; var holder = new PricingStructureAlgorithmsHolder(logger, cache, nameSpace, surfaceId.PricingStructureType, surfaceId.Algorithm); var curveInterpolationMethod = InterpolationMethodHelper.Parse(holder.GetValue("CurveInterpolation")); _matrixIndexHelper = new SortedList <ExpiryTenorStrikeKey, int>(new ExpiryTenorStrikeKey()); var points = ProcessRawSurface(expiryTenors, tenors, volSurface, surfaceId.UnderlyingAssetReference); PricingStructure = new VolatilityRepresentation { name = surfaceId.Name, id = surfaceId.Id, currency = surfaceId.Currency, asset = new AnyAssetReference { href = surfaceId.Instrument }, }; var datapoints = new MultiDimensionalPricingData { point = points }; PricingStructureValuation = new VolatilityMatrix { dataPoints = datapoints , objectReference = new AnyAssetReference { href = surfaceId.Instrument } , baseDate = new IdentifiedDate { Value = baseDate } , buildDateTime = DateTime.Now , buildDateTimeSpecified = true }; var expiries = new double[expiryTenors.Length]; var index = 0; foreach (var term in expiryTenors)//TODO include business day holidays and roll conventions. { expiries[index] = PeriodHelper.Parse(term).ToYearFraction(); index++; } var tenor = new double[tenors.Length]; index = 0; foreach (var term in tenors)//TODO include business day holidays and roll conventions. { tenor[index] = PeriodHelper.Parse(term).ToYearFraction(); index++; } // Record the row/column sizes of the inputs _matrixRowCount = expiryTenors.Length; _matrixRowCount *= tenors.Length; // Columns includes expiry and term (tenor) if it exists. _matrixColumnCount = 1; // Generate an interpolator to use Interpolator = new VolSurfaceInterpolator(expiries, tenor, new Matrix(volSurface), curveInterpolationMethod, true); }
/// <summary> /// Takes a range of volatilities, an array of tenor expiries and an /// array of strikes to create a VolatilitySurface /// </summary> /// <param name="logger">The logger.</param> /// <param name="cache">The cache.</param> /// <param name="expiryTenors">the expiry tenors.</param> /// <param name="tenors">The tenors.</param> /// <param name="volSurface">The vol surface.</param> /// <param name="nameSpace">The namespace</param> /// <param name="properties">The properties.</param> protected ExpiryTermTenorATMVolatilitySurface(ILogger logger, ICoreCache cache, String nameSpace, NamedValueSet properties, String[] expiryTenors, String[] tenors, Double[,] volSurface) { Algorithm = PropertyHelper.ExtractAlgorithm(properties); PricingStructureIdentifier = new VolatilitySurfaceIdentifier(properties); var surfaceId = (VolatilitySurfaceIdentifier)PricingStructureIdentifier; var holder = new PricingStructureAlgorithmsHolder(logger, cache, nameSpace, surfaceId.PricingStructureType, surfaceId.Algorithm); var curveInterpolationMethod = InterpolationMethodHelper.Parse(holder.GetValue("CurveInterpolation")); _matrixIndexHelper = new SortedList <ExpiryTenorStrikeKey, int>(new ExpiryTenorStrikeKey()); var points = ProcessRawSurface(expiryTenors, tenors, volSurface, surfaceId.UnderlyingAssetReference); PricingStructure = new VolatilityRepresentation { name = surfaceId.Name, id = surfaceId.Id, currency = surfaceId.Currency, asset = new AnyAssetReference { href = surfaceId.Instrument }, }; var datapoints = new MultiDimensionalPricingData { point = points, businessCenter = surfaceId.BusinessCenter, timing = surfaceId.QuoteTiming, currency = surfaceId.Currency, cashflowType = surfaceId.CashflowType, informationSource = surfaceId.InformationSources, measureType = surfaceId.MeasureType, quoteUnits = surfaceId.QuoteUnits }; if (surfaceId.ExpiryTime != null) { datapoints.expiryTime = (DateTime)surfaceId.ExpiryTime; datapoints.expiryTimeSpecified = true; } if (surfaceId.ValuationDate != null) { datapoints.valuationDate = (DateTime)surfaceId.ValuationDate; datapoints.valuationDateSpecified = true; } if (surfaceId.Time != null) { datapoints.time = (DateTime)surfaceId.Time; datapoints.timeSpecified = true; } if (surfaceId.QuotationSide != null) { datapoints.side = (QuotationSideEnum)surfaceId.QuotationSide; datapoints.sideSpecified = true; } PricingStructureValuation = new VolatilityMatrix { dataPoints = datapoints, objectReference = new AnyAssetReference { href = surfaceId.Instrument }, baseDate = new IdentifiedDate { Value = surfaceId.BaseDate }, buildDateTime = surfaceId.BuildDateTime, buildDateTimeSpecified = true }; var expiries = new double[expiryTenors.Length]; var index = 0; foreach (var term in expiryTenors)//TODO include business day holidays and roll conventions. { expiries[index] = PeriodHelper.Parse(term).ToYearFraction(); index++; } var tenor = new double[tenors.Length]; index = 0; foreach (var term in tenors)//TODO include business day holidays and roll conventions. { tenor[index] = PeriodHelper.Parse(term).ToYearFraction(); index++; } // Record the row/column sizes of the inputs _matrixRowCount = expiryTenors.Length; _matrixRowCount *= tenors.Length; // Columns includes expiry and term (tenor) if it exists. _matrixColumnCount = 1; // Generate an interpolator to use Interpolator = new VolSurfaceInterpolator(expiries, tenor, new Matrix(volSurface), curveInterpolationMethod, true); }