Пример #1
0
        /// <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);
        }
Пример #2
0
        /// <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();
        }
Пример #5
0
        /// <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;
            }
        }
Пример #6
0
        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);
        }
Пример #8
0
        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);
        }
Пример #9
0
        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);
        }
Пример #10
0
        //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.
            }
        }
Пример #11
0
        /// <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);
        }
Пример #12
0
        /// <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));
        }
Пример #14
0
        /// <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);
        }
Пример #16
0
        /// <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);
        }
Пример #17
0
        /// <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);
        }