/// <summary> /// Generates a 2d array of N stock paths over M time steps. /// </summary> /// <returns></returns> public static double[,] GenerateMcPaths(int N, int M, double T, double r, double S0, double[] ssviParams) { Ssvi ssvi = new Ssvi(ssviParams); // N = number of samples, M = number of time steps double[,] pathOfS = new double[N, M]; double[] Z = new double[N]; double tau = T / M; for (int m = 1; m < M; ++m) // foreach time step { Normal.Samples(Z, 0, 1); //Fill Z with normal 0,1 samples double sqrtTau = Math.Sqrt(tau); for (int n = 0; n < N; ++n) // foreach sample { pathOfS[n, 0] = S0; double s_n_m = pathOfS[n, m - 1]; if (s_n_m < 0) { s_n_m = 1e-10; } double dw = sqrtTau * Z[n]; double k = Math.Log(s_n_m * Math.Exp(-r * T) / S0); pathOfS[n, m] = s_n_m + r * s_n_m * tau + ssvi.VolatilityDup(tau * m, k) * s_n_m * dw; } } return(pathOfS); }
public void GetCalibrationStatus(ref CalibrationOutcome calibOutcome, ref double pricingError) { calibOutcome = outcome; Ssvi m = new Ssvi(calibratedParams); pricingError = CalcMeanSquareErrorBetweenOmegaAndMarketNonATM(m); }
public static void RunVolatilityTest() { double alpha = Math.Sqrt(0.1); double beta = 1; double gamma = 0.7; double eta = 0.2; double rho = 0.3; double r = 0.025; double S = 100; double K = 102.5313; double T = 1; double k = Math.Log(K * Math.Exp(-r * T) / S); Ssvi SsviTest = new Ssvi(alpha, beta, gamma, eta, rho); Console.WriteLine("SSVI Volatility = {0}", SsviTest.VolatilityDup(T, k)); }
public static void RunEurOptionPricing() { double[] ssviParams = new double[] { Math.Sqrt(0.1), 1, 0.7, 0.2, 0.3 }; double r = 0.025; double S0 = 100; double T = 1; int N = 10000; int M = 128; double K = 102; double k = Math.Log(K * Math.Exp(-r * T) / S0); MonteCarloPricingLocalVol pricer = new MonteCarloPricingLocalVol(r, N, M, ssviParams); double McPriceCall = pricer.CalculateEurPutOptionPrice(S0, K, T); Ssvi SsviSurface = new Ssvi(ssviParams[0], ssviParams[1], ssviParams[2], ssviParams[3], ssviParams[4]); double sigmaBs = Math.Sqrt(SsviSurface.OmegaSsvi(T, k) / T); double BsPriceCall = BlackScholesFormula.CalculatePutOptionPrice(sigmaBs, 100, k, r, T); Console.WriteLine("Call price: MC: £{0}, BS £{1}", McPriceCall, BsPriceCall); }
public static double[][] ParallelGenerateMcPaths(int N, int M, double T, double r, double S0, double[] ssviParams) { Ssvi ssvi = new Ssvi(ssviParams); // N = number of samples 10000, M = number of time steps 128 double[][] pathOfS = new double[N][]; double[] Z = new double[M]; double tau = T / M; ConcurrentBag <double[]> paths = new ConcurrentBag <double[]>(); object mylock = new object(); Parallel.For(0, N, n => { double[] vec = new double[M]; Normal.Samples(Z, 0, 1); //Fill Z with normal 0,1 samples double sqrtTau = Math.Sqrt(tau); for (int m = 0; m < (M - 1); ++m) // foreach sample { vec[0] = S0; double s_n = vec[m]; if (s_n < 0) { s_n = 1e-10; } double dw = sqrtTau * Z[m]; double k = Math.Log(s_n * Math.Exp(-r * T) / S0); vec[m + 1] = s_n + r * s_n * tau + ssvi.VolatilityDup(tau * m, k) * s_n * dw; } paths.Add(vec); } ); pathOfS = paths.ToArray(); return(pathOfS); }
public double CalcMeanSquareErrorBetweenOmegaAndMarketNonATM(Ssvi m) { double meanSqErr = 0; int nElements = 0; foreach (OptionMarketData option in marketOptionsList) { double maturity = option.maturity; string type = option.type; double strike = option.strike; double k = Math.Log(strike * Math.Exp(-r0) / S0); double omega = m.OmegaSsvi(maturity, k); double bsImpliedVolatility; if (option.type == "Call" || option.type == "call" || option.type == "C" || option.type == "c") { bsImpliedVolatility = BlackScholesImpliedVolatility.CalculateImpliedVolCall(option.marketPrice, S0, k, r0, maturity); } else if (option.type == "Put" || option.type == "put" || option.type == "P" || option.type == "p") { bsImpliedVolatility = BlackScholesImpliedVolatility.CalculateImpliedVolPut(option.marketPrice, S0, k, r0, maturity); } else { throw new CalibrationFailedException("Option type in marketOptionsList was not Call, call, C, c, Put, put, P or p"); } double difference = omega - bsImpliedVolatility * bsImpliedVolatility * maturity; meanSqErr += difference * difference; nElements++; } if (nElements > 0) { return(meanSqErr / nElements); } else { throw new ArgumentNullException("There is no market data to use for error calculation."); } }
// Must ensure calibration of all Parameters alpha, beta, eta, gamma & rho public Ssvi GetCalibratedModel() { Ssvi m = new Ssvi(calibratedParams); return(m); }
// Used by Alglib minimisation algorithm public void CalibrationObjectiveFunctionNonATM(double[] x, ref double func, object obj) { Ssvi m = new Ssvi(x); func = CalcMeanSquareErrorBetweenOmegaAndMarketNonATM(m); }
// Used by Alglib minimisation algorithm public void CalibrationObjectiveFunctionATM(double[] ssviParams, ref double func, object obj) { Ssvi m = new Ssvi(ssviParams); func = CalcMeanSquareErrorBetweenThetaAndMarketATM(m); }