/// <summary>
        /// Process a PPD Grid. The result is a Market structure that camn be published.
        /// </summary>
        /// <param name="logger">The logger</param>
        /// <param name="cache">The cache.</param>
        /// <param name="swapCurve">The latest rate curve</param>
        /// <param name="ppdGrid">The raw Points Per Day matrix supplied from the subscriber</param>
        /// <param name="id">The id to use in publishing the curve</param>
        /// <param name="nameSpace">The client namespace</param>
        /// <returns></returns>
        public static Market ProcessSwaption(ILogger logger, ICoreCache cache, Market swapCurve, SwaptionPPDGrid ppdGrid, string id, string nameSpace)
        {
            var mkt   = swapCurve;
            var curve = new SimpleRateCurve(mkt);
            // List the values so we can build our ATM vols
            var atmVols = new Dictionary <SimpleKey, decimal>();
            // Create a calendar to use to modify the date
            // default to be Sydney...
            IBusinessCalendar bc = BusinessCenterHelper.ToBusinessCalendar(cache, new[] { "AUSY" }, nameSpace); //BusinessCalendarHelper("AUSY");
            // Use some logic to get the spot date to use
            // LPM Spot lag is 2 days (modfollowing)
            DateTime spotDate = curve.GetSpotDate();

            // Extract each surface and build an ATM engine therefrom
            // Build a list of all possible engines
            foreach (string e in ExpiryKeys)
            {
                // Assume frequency = 4 months until 3 years tenor is reached
                Period expiration         = PeriodHelper.Parse(e);
                double expiryYearFraction = expiration.ToYearFraction();
                foreach (string t in TenorKeys)
                {
                    // Create a Swaprate for each expiry/tenor pair
                    // Assume frequency = 4 months until 3 years tenor is reached
                    double tenorYearFraction = PeriodHelper.Parse(t).ToYearFraction();
                    int    frequency         = tenorYearFraction < 4 ? 4 : 2;
                    // Calculation date
                    // Discount factors
                    // Offsets (elapsed days)
                    var rates = new SwapRate(logger, cache, nameSpace, "AUSY", curve.BaseDate, "ACT/365.FIXED", curve.GetDiscountFactors(), curve.GetDiscountFactorOffsets(), frequency, BusinessDayConventionEnum.MODFOLLOWING);
                    // Calculate the volatility given PPD and swap curve
                    DateTime expiry = bc.Roll(expiration.Add(spotDate), BusinessDayConventionEnum.FOLLOWING);
                    decimal  vol    = CalculateAtmVolatility(rates, expiry, ppdGrid, expiryYearFraction, tenorYearFraction);
                    atmVols.Add(new SimpleKey(e, t), vol);
                }
            }
            var vols = new object[atmVols.Count + 1, 3];
            var i    = 1;

            vols[0, 0] = "Expiry";
            vols[0, 1] = "Tenor";
            vols[0, 2] = "0";
            foreach (var key in atmVols.Keys)
            {
                vols[i, 0] = key.Expiry;
                vols[i, 1] = key.Tenor;
                vols[i, 2] = atmVols[key];
                i++;
            }
            DateTime buildDateTime = swapCurve.Items1[0].buildDateTime;
            var      volSurface    = new VolatilitySurface(vols, new VolatilitySurfaceIdentifier(id), curve.BaseDate, buildDateTime);

            return(CreateMarketDocument(volSurface.GetFpMLData()));
        }
        /// <summary>
        /// Process a CapFloor ATM parvVols structure.
        /// The process Bootstraps the parVols using the supplied ratecurve
        /// </summary>
        /// <param name="logger">The logger</param>
        /// <param name="cache">The cache.</param>
        /// <param name="nameSpace"></param>
        /// <param name="rateCurve"></param>
        /// <param name="capFloor"></param>
        /// <returns></returns>
        private static Market ProcessCapFloorATM(ILogger logger, ICoreCache cache, string nameSpace, Market rateCurve, CapFloorATMMatrix capFloor)
        {
            var id     = capFloor.id;
            var expiry = capFloor.GetExpiries();
            var vols   = capFloor.GetVolatilities();
            var mkt    = rateCurve;
            var curve  = new SimpleRateCurve(mkt);
            var discountFactorDates = curve.GetDiscountFactorDates();
            var discountFactors     = curve.GetDiscountFactors();
            var volType             = capFloor.GetVolatilityTypes();
            var atmVols             = new Dictionary <string, decimal>();
            var settings            = CreateCapFloorProperties(capFloor.GetVolatilitySettings());
            // Create an internal matrix object from the raw data
            var matrix = new CapFloorVolatilityMatrix(id, expiry, volType, vols, null,
                                                      discountFactorDates, ArrayUtilities.ArrayToDecimal(discountFactors));
            // Create an ATM engine from the matrix
            var engines = CreateEngines(logger, cache, nameSpace, id, matrix, settings);
            // Add the default interpolation to use
            const ExpiryInterpolationType volatilityInterpolation = ExpiryInterpolationType.Linear;

            if (engines != null)
            {
                var vol = new CapletExpiryInterpolatedVolatility(engines[0], volatilityInterpolation);
                // List the values so we can build our ATM vols
                var keys = ExpiryKeys.Split(',');
                // Create a calendar to use to modify the date
                var businessCalendar = settings.GetValue("BusinessCalendar", "AUSY");
                var bc = BusinessCenterHelper.ToBusinessCalendar(cache, new[] { businessCalendar }, nameSpace);
                // Use some logic to get the spot date to use
                // LPM Spot lag is 2 days (modfollowing)
                var spotDate       = curve.GetSpotDate();
                var rollConvention = settings.GetValue("RollConvention", BusinessDayConventionEnum.FOLLOWING);
                spotDate = spotDate == curve.GetBaseDate() ? bc.Roll(spotDate.Add(new TimeSpan(2, 0, 0, 0)), rollConvention) : spotDate;
                //// Extract each surface and build an ATM engine therefrom
                //// Build a list of all possible engines
                foreach (var key in keys)
                {
                    // Calculate the volatility for each target key
                    var tv     = PeriodHelper.Parse(key);
                    var target = tv.period == PeriodEnum.D ? bc.Roll(spotDate.AddDays(Convert.ToInt32(tv.periodMultiplier)), rollConvention) :
                                 bc.Roll(spotDate.AddMonths(Convert.ToInt32(tv.periodMultiplier)), rollConvention);
                    atmVols.Add(key, vol.ComputeCapletVolatility(target));
                }
            }
            var outputVols = new object[atmVols.Count + 1, 2];
            var i          = 1;

            //Expiry	0
            outputVols[0, 0] = "Expiry";
            outputVols[0, 1] = "0";
            foreach (var key in atmVols.Keys)
            {
                outputVols[i, 0] = key;
                outputVols[i, 1] = atmVols[key];
                i++;
            }
            DateTime buildDateTime = rateCurve.Items1[0].buildDateTime;
            var      volSurface    = new VolatilitySurface(outputVols, new VolatilitySurfaceIdentifier(id), curve.BaseDate, buildDateTime);

            return(CreateMarketDocument(volSurface.GetFpMLData()));
        }