public void function_fvec(double[] x, double[] fi, object obj)
    {
        // set up interpolator
        FWDInterpolator.Ini(FromDatesSerial, x);

        // Lambda expression
        SwapRate SwapCalc = BB =>
        {
            // floating leg data
            double[] yfFloatLeg = BB.scheduleLeg2.GetYFVect(BB.swapLeg2.DayCount);  // floating leg is leg 2
            double[] dfFloatLeg = (from c in BB.scheduleLeg2.payDates
                                   select DCurve.Df(c)).ToArray();
            double[] fwdFloatLeg = (from c in BB.scheduleLeg2.fromDates
                                    select FWDInterpolator.Solve(c.SerialValue)).ToArray();

            // fixed leg data
            double[] yfFixLeg = BB.scheduleLeg1.GetYFVect(BB.swapLeg1.DayCount);  // fixed is leg 1
            double[] dfFixLeg = (from c in BB.scheduleLeg1.payDates
                                 select DCurve.Df(c)).ToArray();

            // calculate par swap rate according to given data
            return(Formula.ParRateFormula(yfFloatLeg, dfFloatLeg, fwdFloatLeg, yfFixLeg, dfFixLeg));
        };

        // starting fixing should be match
        fi[fi.Length - 1] = (fixing - x[0]) * 10000;

        // iterate building block
        for (int i = 0; i < OnlyGivenSwap.Length; i++)
        {
            fi[i] = (SwapCalc(OnlyGivenSwap[i]) - OnlyGivenSwap[i].rateValue) * 10000;
        }
    }
예제 #2
0
        /// <summary>
        /// Calculate an ATM volatility given a Price Per Day (PPD) value and a swap curve
        /// The curve provides forward rates for the calculation
        /// </summary>
        /// <returns></returns>
        private static decimal CalculateCAPATMVolatility(SwapRate rates, DateTime spotDate, double tenorYearFraction, decimal ppd)
        {
            // Extract the forward rate
            var swapRate = rates.ComputeSwapRate(spotDate, tenorYearFraction);

            ppd /= 100.0m;
            // Calculate the volatility from the parameters
            var atmVolatility = ppd * (decimal)System.Math.Sqrt(250.0) / swapRate;

            return(atmVolatility);
        }
예제 #3
0
        /// <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()));
        }
예제 #4
0
        /// <summary>
        /// Calculate an ATM volatility given a Price Per Day (PPD) value and a swap curve
        /// The curve provides forward rates for the calculation
        /// </summary>
        private static decimal CalculateAtmVolatility(SwapRate rate, DateTime baseDate, SwaptionPPDGrid grid, double expiryYearFraction, double tenorYearFraction)
        {
            // Extract the forward rate
            var swapRate = rate.ComputeSwapRate(baseDate, tenorYearFraction);

            swapRate = swapRate * 100;

            // Extract the correct ppd from the grid (compensate for the swap rate being * 100)
            var ppd = grid.GetPPD(expiryYearFraction, tenorYearFraction) * 0.01m;

            // Calculate the volatility from the parameters
            var atmVolatility = (ppd * (decimal)System.Math.Sqrt(250.0)) / swapRate;

            return(atmVolatility);
        }
예제 #5
0
    private delegate double SwapRate(SwapStyle S);  // used in function to calculate swap rate

    // used in Solve() function on which best fit works
    private void function_fvec(double[] x, double[] fi, object obj)
    {
        // This method will be repeated in iteration, to avoid to be too slow be careful with code
        // fi is output should be vector of zeros (i.e. swap calculated - swap from inputs, and the last is the condition of smoothness)

        // I update PreProcessedDate with new set of guess(x[]), I calculate a array of corresponding df
        Array.Copy(x, 0, fwdGuessLongerSwap, 1, N - 1);
        // According to fwdGuessLongerSwap I calculate df of floating leg of longer swap.
        // It will contain all df of shorter swap
        double[] dfFloatLegLongerSwap = Formula.DFsimpleVect(yfFloatLegLongerSwap, fwdGuessLongerSwap);

        // Lambda expression: calculate par rate
        SwapRate SwapCalc = BB =>
        {
            // fixed leg data
            // dfs array of fixed lag of BB specific swap
            double[] yfFixLeg = BB.scheduleLeg1.GetYFVect(BB.swapLeg1.DayCount); // fixed is leg 1
            double[] dfDates  = Date.GetSerialValue(BB.scheduleLeg1.payDates);   // serial date of fixed lag (each dates we should find df)
            double[] dfFixLeg = new double[dfDates.Count()];                     // will contain df of fixed leg of BB swap

            Interpolation I = new Interpolation();                               // Post process interpolator
            I.Ini(DatesDfLongerSwap, dfFloatLegLongerSwap);

            // transform interpolated value back to discount factor
            for (int i = 0; i < dfDates.Count(); i++)
            {
                dfFixLeg[i] = I.Solve(dfDates[i]);
            }
            return(Formula.ParRate(yfFixLeg, dfFixLeg)); // Calculate par rate
        };

        // iterate building block
        for (int i = 0; i < fi.Count() - 1; i++)
        {
            // Calculate difference from calculated rate and input rate. It should be zero at end of optimization
            fi[i] = (SwapCalc(OnlyGivenSwap[i]) - (OnlyGivenSwap[i]).rateValue) * 10000;
        }

        // Last constrain to match: smoothness condition: sum of square of consecutive fwd
        double sq = 0.0; // sum of square

        for (int i = 0; i < N - 1; i++)
        {
            sq += Math.Pow(fwdGuessLongerSwap[i] - fwdGuessLongerSwap[i + 1], 2);
        }
        // last element
        fi[fi.Count() - 1] = sq * 10000.0; // Sum of square should be zero
    }
    public void function_fvec(double[] x, double[] fi, object obj)
    {
        // set up interpolator
        FWDInterpolator.Ini(ToDatesSerial, x);

        // Lambda expression
        SwapRate SwapCalc = BB =>
        {
            // floating leg data
            double[] yfFloatLeg = BB.scheduleLeg2.GetYFVect(BB.swapLeg2.DayCount);  // floating leg is leg 2
            double[] dfFloatLeg = (from c in BB.scheduleLeg2.payDates
                                   select DCurve.Df(c)).ToArray();
            double[] df_end = (from c in BB.scheduleLeg2.toDates
                               select Math.Exp(FWDInterpolator.Solve(c.SerialValue))).ToArray();
            double[] df_ini = (from c in BB.scheduleLeg2.fromDates
                               select Math.Exp(FWDInterpolator.Solve(c.SerialValue))).ToArray();

            int      n           = yfFloatLeg.Length;
            double[] fwdFloatLeg = new double[n];
            for (int i = 0; i < n; i++)
            {
                fwdFloatLeg[i] = (df_ini[i] / df_end[i] - 1) / yfFloatLeg[i];
            }

            // fixed leg data
            double[] yfFixLeg = BB.scheduleLeg1.GetYFVect(BB.swapLeg1.DayCount);  // fixed is leg 1
            double[] dfFixLeg = (from c in BB.scheduleLeg1.payDates
                                 select DCurve.Df(c)).ToArray();

            // calculate par swap rate according to given data
            return(Formula.ParRateFormula(yfFloatLeg, dfFloatLeg, fwdFloatLeg, yfFixLeg, dfFixLeg));
        };

        // iterate building block
        for (int i = 0; i < OnlyGivenSwap.Length; i++)
        {
            fi[i] = (SwapCalc(OnlyGivenSwap[i]) - OnlyGivenSwap[i].rateValue) * 10000;
        }

        // starting fixing should be match
        fi[fi.Length - 1] = (fixing.rateValue - Fwd(refDate)) * 10000;

        // starting fixing should be match
        fi[fi.Length - 2] = Math.Exp(FWDInterpolator.Solve(refDate.SerialValue)) * 10000;  // initial df =0!
    }
예제 #7
0
    private delegate double SwapRate(SwapStyle S);  // used in function to calculate swap rate

    // used in Solve() function on which best fit works
    private void function_fvec(double[] x, double[] fi, object obj)
    {
        // fi is output should be vector of zeros (i.e. swap calculated - swap value from input)
        int N = x.Count(); // size of x (set of guess)

        // I update PreProcessedDate with new set of guess(x[]), for all Key (dates) in IniGuessData,
        for (int i = 0; i < N; i++)
        {
            PreProcessedData[IniGuessData.ElementAt(i).Key] = x[i];
        }

        // set up interpolator with updated data
        PostProcessInterpo.Ini(PreProcessedData.Keys.ToArray(), PreProcessedData.Values.ToArray());

        // Lambda expression: calculate Par Rate given a SwapStyle building block
        SwapRate SwapCalc = BB =>
        {
            // fixed leg data
            double[] yfFixLeg = BB.scheduleLeg1.GetYFVect(BB.swapLeg1.DayCount); // fixed is leg 1

            // dfs array of fixed lag
            double[] dfDates = Date.GetSerialValue(BB.scheduleLeg1.payDates); // serial date of fixed lag (each dates we should find df)
            // Vector<double> k = PostProcessInterpo.Curve(new Vector<double>(dfDates, 0));

            double[] dfFixLeg = PostProcessInterpo.Curve(dfDates); // get interpolated value (i.e. log df or log r or...
            // transform interpolated value back to discount factor
            for (int i = 0; i < yfFixLeg.Length; i++)
            {
                dfFixLeg[i] = interpAdapter.FromInterpToDf(dfFixLeg[i], dfDates[i]);
            }

            // Interpolation Methods for Curve Construction PATRICK S. HAGAN & GRAEME WEST Applied Mathematical Finance,Vol. 13, No. 2, 89–129, June 2006
            // Formula 2) page 4
            return(Formula.ParRate(yfFixLeg, dfFixLeg)); // Calculate par rate
        };

        // iterate building block and calculate difference between starting data and recalculated data: best fit if each fi[i]==0
        for (int i = 0; i < N; i++)
        {
            // SwapCalc((SwapStyle)SwapStyleArray[i]) is recalculated data
            // SwapStyleArray[i].rateValue is starting data to match
            fi[i] = (SwapCalc((SwapStyle)OnlyGivenSwap[i]) - OnlyGivenSwap[i].rateValue) * 10000; // best fit if fi[i] ==0!, for each i
        }
    }
예제 #8
0
        /// <summary>
        /// Convert the cap/floor PPD values to an ATM parVols structure
        /// This method then calls the bootstrapper <see cref="ProcessCapFloorPpd"/>
        /// to generate the capvol curve
        /// </summary>
        /// <param name="logger">The logger</param>
        /// <param name="cache">The cache.</param>
        /// <param name="rateCurve"></param>
        /// <param name="capFloor"></param>
        /// <param name="nameSpace"></param>
        /// <returns></returns>
        private static Market ProcessCapFloorPpd(ILogger logger, ICoreCache cache, string nameSpace, Market rateCurve, CapFloorATMMatrix capFloor)
        {
            var expiry          = capFloor.GetExpiries();
            var vols            = capFloor.GetVolatilities();
            var mkt             = rateCurve;
            var curve           = new SimpleRateCurve(mkt);
            var rawOffsets      = curve.GetDiscountFactorOffsets();
            var offsets         = Array.ConvertAll(rawOffsets, IntToDouble);
            var discountFactors = curve.GetDiscountFactors();
            var volType         = capFloor.GetVolatilityTypes();
            var atmVols         = new Dictionary <string, decimal>();
            var settings        = CreateCapFloorProperties(capFloor.GetVolatilitySettings());
            var bc = BusinessCenterHelper.ToBusinessCalendar(cache, new[] { "AUSY" }, nameSpace);

            // Use some logic to get the spot date to use
            // Step through each vol and convert ppd to ATM vol
            for (var i = 0; i < expiry.Length; i++)
            {
                // Create a Swaprate for each expiry
                // Assume frequency = 4 months until 4 years tenor is reached
                Period tv = PeriodHelper.Parse(expiry[i]);
                //double tvYearFraction = tv.ToYearFraction();
                //int frequency = tvYearFraction < 4 ? 4 : 2;
                const int frequency = 4;
                var       rates     = new SwapRate(logger, cache, nameSpace, "AUSY", curve.GetBaseDate(), "ACT/365.FIXED", discountFactors, curve.GetDiscountFactorOffsets(), frequency, BusinessDayConventionEnum.MODFOLLOWING);
                switch (volType[i])
                {
                case "ETO":
                {
                    DateTime spotDate       = settings.GetValue("Calculation Date", DateTime.MinValue);
                    var      rollConvention = settings.GetValue("RollConvention", BusinessDayConventionEnum.MODFOLLOWING);
                    DateTime etoDate        = bc.Roll(tv.Add(spotDate), rollConvention);
                    atmVols[expiry[i]] = CalculateATMVolatility(settings, spotDate, etoDate, offsets, discountFactors, vols[i][0]);
                }
                break;

                case "Cap/Floor":
                {
                    DateTime spotDate          = settings.GetValue("Calculation Date", DateTime.MinValue);
                    var      rollConvention    = settings.GetValue("RollConvention", BusinessDayConventionEnum.MODFOLLOWING);
                    DateTime expiryDate        = bc.Roll(tv.Add(spotDate), rollConvention);
                    string   tenor             = DateToTenor(spotDate, expiryDate);
                    double   tenorYearFraction = PeriodHelper.Parse(tenor).ToYearFraction();
                    // Add the caplet maturity to the expiry and then calculate the vol
                    atmVols[expiry[i]] = CalculateCAPATMVolatility(rates, spotDate, tenorYearFraction, vols[i][0]);
                }
                break;
                }
            }
            // Fudge to switch the PPD header to ATM
            // We've converted so we want the new name
            var headers = capFloor.GetHeaders();

            for (var i = 0; i < headers.Length; i++)
            {
                if (!headers[i].Contains("PPD"))
                {
                    continue;
                }
                headers[i] = "ATM";
                break;
            }
            // Convert our lovely dictionary to a grubby array of arrays
            var volatilities = new object[atmVols.Keys.Count][];
            var row          = 0;

            foreach (var key in atmVols.Keys)
            {
                volatilities[row]    = new object[3];
                volatilities[row][0] = key;
                volatilities[row][1] = atmVols[key];
                volatilities[row][2] = volType[row++];
            }
            var convertedCapFloor = new CapFloorATMMatrix(headers, volatilities, capFloor.GetVolatilitySettings(),
                                                          capFloor.baseDate.Value, capFloor.id);

            return(ProcessCapFloorATM(logger, cache, nameSpace, rateCurve, convertedCapFloor));
        }