(* :Title: Options *) (* :Context: QuantLib`Options` *) (* :Author: Niels Elken Sønderby *) (* :Mathematica Version: 4.0 *) (* :Copyright: Copyright (C) 2003 Niels Elken Sønderby *) (* :License: This file is part of QuantLib for Mathematica, a Mathematica extension for QuantLib, a free-software/open-source financial C++ library - http://www.nielses.dk/quantlib/mma/ - http://quantlib.org/ QuantLib for Mathematica is free software: you can redistribute it and/or modify it under the terms of the QuantLib license. You should have received a copy of the license along with this program; if not, please email ferdinando@ametrano.net The license is also available online at http://quantlib.org/html/license.html This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the license for more details. *) BeginPackage["QuantLib`Options`", "QuantLib`Common`QuantLibCommon`" (* Needs SymbolToNumber functionality *) ] (* Usage messages *) Keyfigures::usage = "Keyfigures[instrument, model] gives all keyfigures (including Value) for the given instrument under the given model." Value::usage = "Value[instrument, model] is a short form for Value /. Keyfigures[instrument, model] and gives the value of the instrument under the given model." CallOption::usage = "CallOption is an option type where the buyer has the right to buy the underlying at maturity." PutOption::usage = "PutOption is an option type where the buyer has the right to sell the underlying at maturity." Straddle::usage = "Straddle is the sum of a call option and a put option (see CallOption, PutOption)." EuropeanOption::usage = "EuropeanOption[strike, residualtime, type] represents a European option of the given type (CallOption, PutOption or Straddle), exercise price (strike) and time to maturity (residualtime)." AmericanOption::usage = "AmericanOption[strike, residualtime, type] represents an American option of the given type (CallOption, PutOption or Straddle), exercise price (strike) and time to maturity (residualtime)." BlackScholesModel::usage = "BlackScholesModel[stockprice, riskfreerate, dividend, vol] represents a model where the underlying asset is worth stockprice at time zero and the risk free rate, dividend yield and volatility are as given." SVJDModel::usage = "SVJDModel[underlying, riskFreeRate, dividendYield, volatility, volatilityOfVolatility, steadyStateVolatility, meanReversionRate, correlationUnderlyingVolatility, jumpIntensity, jumpMean, jumpStandardDeviation] represents a SVJD (stochastic volatility / jump diffusion) model with the given parameters." AntitheticPaths::usage = "AntitheticPaths is an option for Value and Keyfigures (when Method -> MonteCarlo is chosen) and MonteCarloPath to specifiy whether antithetic paths should be used in the simulation." ControlVariate::usage = "ControlVariate is an option used in conjunction with Method -> MonteCarlo that specifies whether a control variate should be used." Samples::usage = "Samples is an option used in conjunction with Method -> MonteCarlo that specifies how many sample paths should be simulated." ImpliedVolatility::usage = "ImpliedVolatility[price, instr, bsmodel] gives the volatility which makes the price equal the price calculated in the given Black-Scholes model for the given instrument ." PDF::usage = "PDF[instr, model, z] gives the probability density function for the return of the underlying instrument in the given model at expiry evaluated at z." Mean::usage = "Mean of PDF" Variance::usage = "Variance of PDF" Skewness::usage = "Skewness of PDF" KurtosisExcess::usage = "KurtosisExcess of PDF" GridPoints::usage = "GridPoints is an option used in connection with Method -> FiniteDifferences that specifies the number of grid points for the price of the underlier." TimeSteps::usage = "TimeSteps is an option used in connection with Method -> FiniteDifferences and Method -> MonteCarlo that specifies how many time intervals are used in the calculation." ExerciseTimes::usage = "ExerciseTimes is an option used in connection with Method -> MonteCarlo for an AmericanOption that specifies the number of times the option can be exercised. This number must divisible with TimeSteps." FiniteDifferences::usage = "FiniteDifferences is an option for Value and Keyfigures specifying that the finite differences method should be used. GridPoints and TimeSteps can be used to adjust the accuracy." PolynomialDegree::usage = "PolynomialDegree is an option used when valuing an AmericanOption with Method -> MonteCarlo that specifies the number of polynomials used in the regression in the least-squares Monte Carlo method." StandardError::usage = "StandardError is the standard error returned from Keyfigures when using Method -> MonteCarlo. It is calculated as the sample standard deviation divided with the square root of the number of paths." Begin["`Private`"] (* Give access to QuantLib`Private` context as LinkPatterns for external program are there. Does a more elegant solution exist? *) AppendTo[$ContextPath, "QuantLib`Private`"] (* Translation table for passing "enum"-values to C++ *) OptionTypeNumbers = { { CallOption, 0 }, { PutOption, 1 }, { Straddle, 2 } } Keyfigures[EuropeanOption[strike_, maturity_, type_], BlackScholesModel[underlying_, riskFreeRate_, dividendYield_, volatility_], opts___?OptionQ] ^:= Module[{meth = Method /. {opts} /. Options[Keyfigures], samples = Samples /. {opts} /. Options[Keyfigures], antith = AntitheticPaths /. {opts} /. Options[Keyfigures]}, meth = If[meth === Automatic, Analytic, meth]; Switch[meth, Analytic, qlEuropeanOption[SymbolToNumber[type, OptionTypeNumbers], underlying, strike, dividendYield, riskFreeRate, maturity, volatility], MonteCarlo, If[samples == Automatic, samples = 100000]; qlEuropeanOptionMC[SymbolToNumber[type, OptionTypeNumbers], underlying, strike, dividendYield, riskFreeRate, maturity, volatility, samples, If[antith,1,0]] ] ] Keyfigures[AmericanOption[strike_, maturity_, type_], BlackScholesModel[underlying_, riskFreeRate_, dividendYield_, volatility_], opts___?OptionQ] ^:= Module[{meth = Method /. {opts} /. Options[Keyfigures], timeSteps = TimeSteps /. {opts} /. Options[Keyfigures], gridPoints = GridPoints /. {opts} /. Options[Keyfigures], samples = Samples /. {opts} /. Options[Keyfigures], degree = PolynomialDegree /. {opts} /. Options[Keyfigures], antithetic = AntitheticPaths /. {opts} /. Options[Keyfigures], controlVariate = ControlVariate /. {opts} /. Options[Keyfigures] }, meth = If[meth === Automatic, FiniteDifferences, meth]; Switch[meth, FiniteDifferences, qlAmericanOptionFD[SymbolToNumber[type, OptionTypeNumbers], underlying, strike, dividendYield, riskFreeRate, maturity, volatility, timeSteps, gridPoints], MonteCarlo, If[samples == Automatic, samples = 10000]; nqAmericanOptionLSM[SymbolToNumber[type, OptionTypeNumbers], underlying, strike, dividendYield, riskFreeRate, maturity, volatility, timeSteps, samples, degree, If[antithetic,1,0], If[controlVariate,1,0]] ] ] Keyfigures[AmericanOption[strike_, maturity_, type_], SVJDModel[underlying_, riskFreeRate_, dividendYield_, volatility_, volatilityOfVolatility_, steadyStateVolatility_, meanReversionRate_, correlationUnderlyingVolatility_, jumpIntensity_, jumpMean_, jumpStandardDeviation_], opts___?OptionQ] ^:= Module[{meth = Method /. {opts} /. Options[Keyfigures], timeSteps = TimeSteps /. {opts} /. Options[Keyfigures], exerciseTimes = ExerciseTimes /. {opts} /. Options[Keyfigures], samples = Samples /. {opts} /. Options[Keyfigures], degree = PolynomialDegree /. {opts} /. Options[Keyfigures], antithetic = AntitheticPaths /. {opts} /. Options[Keyfigures], controlVariate = ControlVariate /. {opts} /. Options[Keyfigures] }, meth = If[meth === Automatic, MonteCarlo, meth]; Switch[meth, MonteCarlo, If[samples == Automatic, samples = 10000]; If[exerciseTimes == Automatic, exerciseTimes = timeSteps]; nqAmericanOptionSVJDLSM[SymbolToNumber[type, OptionTypeNumbers], underlying, strike, dividendYield, riskFreeRate, maturity, volatility, volatilityOfVolatility, steadyStateVolatility, meanReversionRate, correlationUnderlyingVolatility, jumpIntensity, jumpMean, jumpStandardDeviation, timeSteps, exerciseTimes, samples, degree, If[antithetic,1,0], If[controlVariate,1,0]] ] ] ImpliedVolatility[value_, EuropeanOption[strike_, maturity_, type_], BlackScholesModel[underlying_, riskFreeRate_, dividendYield_, volatility_], opts___?OptionQ] ^:= qlImpliedVolatility[value, SymbolToNumber[type, OptionTypeNumbers], underlying, strike, dividendYield, riskFreeRate, maturity] Keyfigures[EuropeanOption[strike_, maturity_, type_], SVJDModel[underlying_, riskFreeRate_, dividendYield_, volatility_, volatilityOfVolatility_, steadyStateVolatility_, meanReversionRate_, correlationUnderlyingVolatility_, jumpIntensity_, jumpMean_, jumpStandardDeviation_], opts___?OptionQ] ^:= Module[{meth = Method /. {opts} /. Options[Keyfigures], timeSteps = TimeSteps /. {opts} /. Options[Keyfigures], samples = Samples /. {opts} /. Options[Keyfigures], antithetic = AntitheticPaths /. {opts} /. Options[Keyfigures], controlVariate = ControlVariate /. {opts} /. Options[Keyfigures] }, meth = If[meth === Automatic, Analytic, meth]; Switch[meth, Analytic, nqSVJDOption[SymbolToNumber[type, OptionTypeNumbers], underlying, strike, dividendYield, riskFreeRate, maturity, volatility, volatilityOfVolatility, steadyStateVolatility, meanReversionRate, correlationUnderlyingVolatility, jumpIntensity, jumpMean, jumpStandardDeviation], MonteCarlo, If[samples == Automatic, samples = 100000]; nqSVJDOptionMC[SymbolToNumber[type, OptionTypeNumbers], underlying, strike, dividendYield, riskFreeRate, maturity, volatility, volatilityOfVolatility, steadyStateVolatility, meanReversionRate, correlationUnderlyingVolatility, jumpIntensity, jumpMean, jumpStandardDeviation, timeSteps, samples, If[antithetic,1,0], If[controlVariate,1,0]] ] ] PDF[EuropeanOption[strike_, maturity_, type_], SVJDModel[underlying_, riskFreeRate_, dividendYield_, volatility_, volatilityOfVolatility_, steadyStateVolatility_, meanReversionRate_, correlationUnderlyingVolatility_, jumpIntensity_, jumpMean_, jumpStandardDeviation_], x_, opts___?OptionQ] ^:= nqSVJDPDF[x, SymbolToNumber[type, OptionTypeNumbers], underlying, strike, dividendYield, riskFreeRate, maturity, volatility, volatilityOfVolatility, steadyStateVolatility, meanReversionRate, correlationUnderlyingVolatility, jumpIntensity, jumpMean, jumpStandardDeviation ] CDFN[x_] := (1 + Erf[x/Sqrt[2]])/2 PDFN[x_] := 1 / Sqrt[2 Pi] * Exp[-x^2 / 2] PDFN[m_,s_,x_] := 1/(E^((-m + x)^2/(2*s^2))*Sqrt[2*Pi]*s) PDF[EuropeanOption[strike_, maturity_, type_], BlackScholesModel[underlying_, riskFreeRate_, dividendYield_, volatility_], x_, opts___?OptionQ] ^:= PDFN[(riskFreeRate - dividendYield - (volatility^2) / 2)maturity, volatility Sqrt[maturity], x] Options[Keyfigures] := { Method -> Automatic, Samples -> Automatic, AntitheticPaths -> False, ControlVariate -> False, GridPoints -> 100, TimeSteps -> 100, ExerciseTimes -> Automatic, PolynomialDegree -> 2 } Value[x___] := Value /. Keyfigures[x] (* Formel *) TranslateSVJDModel[model_] := model /. SVJDModel[underlying_, riskFreeRate_, dividendYield_, volatility_, volatilityOfVolatility_, steadyStateVolatility_, meanReversionRate_, correlationUnderlyingVolatility_, jumpIntensity_, jumpMean_, jumpStandardDeviation_] :> {S = underlying, r = riskFreeRate, rf = dividendYield, V = volatility^2, sigmav = volatilityOfVolatility, alpha = (steadyStateVolatility^2)*meanReversionRate, betastar = meanReversionRate, rho = correlationUnderlyingVolatility, lambdastar = jumpIntensity, kmeanstar = jumpMean, delta = jumpStandardDeviation} TranslateInstrument[instr_] := instr /. EuropeanOption[strike_, residualTime_, typ_] :> {K = strike, T = residualTime, type = typ} (* Keyfigures[EuropeanOption[instrpar__], SVJDModel[modelpar__], opts___?OptionQ] ^:= Module[{}, TranslateSVJDModel[SVJDModel[modelpar]]; TranslateInstrument[EuropeanOption[instrpar]]; Switch[type, CallOption, {Value -> S Exp[-rf T] P[1, Log[K/S], V, T, K] - Exp[-r T] K P[2, Log[K/S], V, T, K]}, PutOption, {Value -> S Exp[-rf T] (P[1, Log[K/S], V, T, K] - 1) - Exp[-r T] K (P[2, Log[K/S], V, T, K] - 1)} ] ] *) P[j_, x_, V_, T_, K_] := 0.5 + (1/Pi) NIntegrate[integr[j, u, x], {u, 0, 300}] integr[j_, u_, x_] := Im[F[j, I u] Exp[-I u x]] / u F[j_, u_] := Exp[CC[j, u] + DD[j, u] V + EE[j, u]] CC[j_, u_] := ((r - rf - lambdastar kmeanstar) u T - ((alpha T) / sigmav^2) (rho sigmav u - beta[j] - gamma[j, u]) - ((2 alpha) / sigmav^2) * Log[1 + 0.5 (rho sigmav u - beta[j] - gamma[j, u]) * ((1 - Exp[gamma[j, u] T]) / gamma[j, u])]) DD[j_, u_] := -2 (my[j] u + 0.5 u^2) / (rho sigmav u - beta[j] + gamma[j, u] * (1 + Exp[gamma[j, u] T]) / (1 - Exp[gamma[j, u] T])) EE[j_, u_] := lambdastar T (1 + kmeanstar)^(my[j] + 0.5) * ((((1 + kmeanstar)^u) Exp[delta^2 (my[j] u + u^2 / 2)]) - 1) gamma[j_, u_] := Sqrt[(rho sigmav u - beta[j])^2 - 2 sigmav^2 (my[j] u + 0.5 u^2)] my[1] = 0.5; my[2] = -0.5; beta[1] := betastar - rho sigmav; beta[2] := betastar; (* Nielsen (1999) p. 49 *) R[u_] := CC[2, u] + DD[2, u] V + EE[2, u] Mean[EuropeanOption[instrpar__], SVJDModel[modelpar__], opts___?OptionQ] ^:= Module[{}, TranslateSVJDModel[SVJDModel[modelpar]]; TranslateInstrument[EuropeanOption[instrpar]]; D[R[u], u] /. u -> 0 ] Variance[EuropeanOption[instrpar__], SVJDModel[modelpar__], opts___?OptionQ] ^:= Module[{}, TranslateSVJDModel[SVJDModel[modelpar]]; TranslateInstrument[EuropeanOption[instrpar]]; D[R[u], u, u] /. u -> 0 ] Skewness[EuropeanOption[instrpar__], SVJDModel[modelpar__], opts___?OptionQ] ^:= Module[{}, TranslateSVJDModel[SVJDModel[modelpar]]; TranslateInstrument[EuropeanOption[instrpar]]; (D[R[u], u, u, u] / (D[R[u], u, u]^(3/2)) ) /. u -> 0 ] KurtosisExcess[EuropeanOption[instrpar__], SVJDModel[modelpar__], opts___?OptionQ] ^:= Module[{}, TranslateSVJDModel[SVJDModel[modelpar]]; TranslateInstrument[EuropeanOption[instrpar]]; (D[R[u], u, u, u, u] / (D[R[u], u, u]^2)) /. u -> 0 ] BlackScholesVolatility[EuropeanOption[instrpar__], SVJDModel[modelpar__], opts___?OptionQ] ^:= Module[{}, TranslateSVJDModel[SVJDModel[modelpar]]; TranslateInstrument[EuropeanOption[instrpar]]; Sqrt[(D[R[u], u, u] /. u -> 0) / T] ] BlackScholesModel[EuropeanOption[instrpar__], model_SVJDModel, opts___?OptionQ] ^:= BlackScholesModel[model[[1]], model[[2]], model[[3]], BlackScholesVolatility[EuropeanOption[instrpar], model]] End[] EndPackage[]