public static object DupireSsviVolatility([ExcelArgument(Description = "the current risky asset price")] double underlyingPrice,
                                                  [ExcelArgument(Description = "constant continuously compounded rate of return")] double riskFreeRate,
                                                  [ExcelArgument(Description = "parameter in theta(t) := alpha^2(e^(beta^2 t)  - 1)")] double alpha,
                                                  [ExcelArgument(Description = "parameter in theta(t) := alpha^2(e^(beta^2 t)  - 1)")] double beta,
                                                  [ExcelArgument(Description = "SSVI parameter")] double gamma,
                                                  [ExcelArgument(Description = "SSVI parameter")] double eta,
                                                  [ExcelArgument(Description = "SSVI parameter")] double rho,
                                                  [ExcelArgument(Description = "option maturity (time to expiry)")] double maturity,
                                                  [ExcelArgument(Description = "option strike")] double strike)
        {
            // This is useful for methods that take a while to run.
            if (ExcelDnaUtil.IsInFunctionWizard())
            {
                return(null);
            }

            try
            {
                double k           = Math.Log(strike * Math.Exp(-riskFreeRate * maturity) / underlyingPrice);
                Ssvi   SsviSurface = new Ssvi(alpha, beta, gamma, eta, rho);
                return(Math.Sqrt(SsviSurface.OmegaSsvi(maturity, k) / maturity));
            }
            catch (Exception e)
            {
                XLInterfaceBase.AddErrorMessage("DupireSsviVolatility error: " + e.Message);
            }

            return(FunctionError);
        }
        public static object DupireSsviEuropeanVanillaOptionPrice([ExcelArgument(Description = "the current risky asset price")] double S0,
                                                                  [ExcelArgument(Description = "constant continuously compounded rate of return")] double riskFreeRate,
                                                                  [ExcelArgument(Description = "parameter in theta(t) := alpha^2(e^(beta^2 t)  - 1)")] double alpha,
                                                                  [ExcelArgument(Description = "parameter in theta(t) := alpha^2(e^(beta^2 t)  - 1)")] double beta,
                                                                  [ExcelArgument(Description = "SSVI parameter")] double gamma,
                                                                  [ExcelArgument(Description = "SSVI parameter")] double eta,
                                                                  [ExcelArgument(Description = "SSVI parameter")] double rho,
                                                                  [ExcelArgument(Description = "option maturity (time to expiry)")] double maturity,
                                                                  [ExcelArgument(Description = "option strike")] double strike,
                                                                  [ExcelArgument(Description = "option type, 'C' for call 'P' for put")] string type)
        {
            try
            {
                Ssvi   SsviSurface = new Ssvi(alpha, beta, gamma, eta, rho);
                double k           = Math.Log(strike * Math.Exp(-riskFreeRate * maturity) / S0);
                double sigmaBs     = Math.Sqrt(SsviSurface.OmegaSsvi(maturity, k) / maturity);

                if (type == "Call" || type == "call" || type == "C" || type == "c")
                {
                    return(BlackScholesFormula.CalculateCallOptionPrice(sigmaBs, S0, k, riskFreeRate, maturity));
                }
                else if (type == "Put" || type == "put" || type == "P" || type == "p")
                {
                    return(BlackScholesFormula.CalculatePutOptionPrice(sigmaBs, S0, k, riskFreeRate, maturity));
                }
                else
                {
                    throw new ArgumentException("Input must be either Call, call, C, c, Put, put, P or p.");
                }
            }
            catch (Exception e)
            {
                XLInterfaceBase.AddErrorMessage("DupireSsviEuropeanVanillaOptionPrice error: " + e.Message);
            }

            return(FunctionError);
        }
        public static object DupireSsviCalculateSigmaDup([ExcelArgument(Description = "the current risky asset price")] double S0,
                                                         [ExcelArgument(Description = "constant continuously compounded rate of return")] double riskFreeRate,
                                                         [ExcelArgument(Description = "parameter in theta(t) := alpha^2(e^(beta^2 t)  - 1)")] double alpha,
                                                         [ExcelArgument(Description = "parameter in theta(t) := alpha^2(e^(beta^2 t)  - 1)")] double beta,
                                                         [ExcelArgument(Description = "SSVI parameter")] double gamma,
                                                         [ExcelArgument(Description = "SSVI parameter")] double eta,
                                                         [ExcelArgument(Description = "SSVI parameter")] double rho,
                                                         [ExcelArgument(Description = "The value of S for which we want the Dupire Local Vol")] double S,
                                                         [ExcelArgument(Description = "The value of t for which we want the Dupire Local Vol")] double t)

        {
            try
            {
                Ssvi   SsviSurface = new Ssvi(alpha, beta, gamma, eta, rho);
                double k           = Math.Log(S * Math.Exp(-riskFreeRate * t) / S0);
                return(SsviSurface.VolatilityDup(t, k));
            }
            catch (Exception e)
            {
                XLInterfaceBase.AddErrorMessage("DupireSsviCalculateSigmaDup error: " + e.Message);
            }

            return(FunctionError);
        }
        public static object[,] CalibrateDupireSsviParametersNonATM(
            [ExcelArgument(Description = "A 3x2 XL Range with guess values for gamma, eta, rho")] object guessModelParameters,
            [ExcelArgument(Description = "constant continuously compounded rate of return")] double riskFreeRate,
            [ExcelArgument(Description = "the current risky asset price")] double underlyingPrice,
            [ExcelArgument(Description = "the SSVI alpha from ATM calibration")] double alpha,
            [ExcelArgument(Description = "the SSVI beta from ATM calibration")] double beta,
            [ExcelArgument(Description = "An Nx1 XL Range of option strikes")] object strikes,
            [ExcelArgument(Description = "An Nx1 XL Range of option maturities")] object maturities,
            [ExcelArgument(Description = "An Nx1 XL Range of option either C or P for Calls and Puts")] object type,
            [ExcelArgument(Description = "An Nx1 XL Range of option prices")] object observedPrices,
            [ExcelArgument(Description = "Accuracy parameter for calibration")] double accuracy,
            [ExcelArgument(Description = "Number of iterations parameter for calibration")] int maxIterations)
        {
            try
            {
                if (ExcelDnaUtil.IsInFunctionWizard())
                {
                    return(null);
                }

                double[] strikesArray        = XLInterfaceBase.ConvertToVector <double>(strikes);
                double[] maturitesArray      = XLInterfaceBase.ConvertToVector <double>(maturities);
                string[] typeArray           = XLInterfaceBase.ConvertToVector <string>(type);
                double[] observedPricesArray = XLInterfaceBase.ConvertToVector <double>(observedPrices);

                if (strikesArray.Length != maturitesArray.Length ||
                    maturitesArray.Length != typeArray.Length ||
                    typeArray.Length != observedPricesArray.Length)
                {
                    XLInterfaceBase.AddErrorMessage("CalibrateSsviParameters: strikes, maturites, types and observedPrices must be of same length.");
                    return(null);
                }

                KeyValuePair <string, double>[] paramPairs = XLInterfaceBase.ConvertToKeyValuePairs(guessModelParameters);
                if (paramPairs.Length != 3)
                {
                    XLInterfaceBase.AddErrorMessage("CalibrateSsviParameters: guessModelParameters must be three key - value pairs.");
                    return(null);
                }

                double eta = 0; double gamma = 0; double rho = 0;
                for (int paramIdx = 0; paramIdx < paramPairs.Length; ++paramIdx)
                {
                    KeyValuePair <string, double> pair = paramPairs[paramIdx];
                    string key   = pair.Key;
                    double value = pair.Value;
                    if (key.Equals("eta", StringComparison.CurrentCultureIgnoreCase))
                    {
                        eta = value;
                    }
                    else if (key.Equals("gamma", StringComparison.CurrentCultureIgnoreCase))
                    {
                        gamma = value;
                    }
                    else if (key.Equals("rho", StringComparison.CurrentCultureIgnoreCase))
                    {
                        rho = value;
                    }
                    else
                    {
                        XLInterfaceBase.AddErrorMessage("CalibrateSsviParameters: guessModelParameters: unknown key: " + key);
                        return(null);
                    }
                }

                SsviCalibrator ssviCalibrator = new SsviCalibrator(riskFreeRate, underlyingPrice, accuracy, maxIterations);
                ssviCalibrator.SetGuessParameters(alpha, beta, gamma, eta, rho);

                int numObservedOptions        = strikesArray.Length;
                for (int optionIdx = 0; optionIdx < numObservedOptions; ++optionIdx)
                {
                    ssviCalibrator.AddObservedOption(maturitesArray[optionIdx], strikesArray[optionIdx], observedPricesArray[optionIdx], typeArray[optionIdx]);
                }
                ssviCalibrator.CalibrateEtaGammaRhoNonATM();
                CalibrationOutcome outcome          = CalibrationOutcome.NotStarted;
                double             calibrationError = 0;
                ssviCalibrator.GetCalibrationStatus(ref outcome, ref calibrationError);

                Ssvi calibratedModel = ssviCalibrator.GetCalibratedModel();

                // for output
                const int numCols = 2;
                const int numRows = 5;
                object[,] output = new object[numRows, numCols];
                output[0, 0]     = "Gamma"; output[0, 1] = calibratedModel.GetGamma();
                output[1, 0]     = "Eta"; output[1, 1] = calibratedModel.GetEta();
                output[2, 0]     = "Rho"; output[2, 1] = calibratedModel.GetRho();

                output[3, 0] = "Minimizer Status";
                if (outcome == CalibrationOutcome.FinishedOK)
                {
                    output[3, 1] = "OK";
                }
                else if (outcome == CalibrationOutcome.FailedMaxItReached)
                {
                    output[3, 1] = "Reached max. num. iterations.";
                }
                else if (outcome == CalibrationOutcome.FailedOtherReason)
                {
                    output[3, 1] = "Failed.";
                }
                else
                {
                    output[3, 1] = "Unknown outcome.";
                }

                output[4, 0] = "Pricing error"; output[4, 1] = Math.Sqrt(calibrationError);
                return(output);
            }
            catch (Exception e)
            {
                XLInterfaceBase.AddErrorMessage("CalibrateParameters: unknown error: " + e.Message);
            }

            return(null);
        }