NNStopping

Solving for optimal strategy and expected payoff of a Bermudan Max-Call option

We will calculate optimal strategy for Bermudan Max-Call option with following drift, diffusion and payoff:

\[μ(x) =(r − δ) x, σ(x) = β diag(x1, ... , xd),\\ g(t, x) = e^{-rt}max\lbrace max\lbrace x1, ... , xd \rbrace − K, 0\rbrace\]

We define the parameters, drift function and the diffusion function for the dynamics of the option.

using HighDimPDE, Flux, StochasticDiffEq
d = 3 # Number of assets in the stock
r = 0.05 # interest rate
beta = 0.2 # volatility
T = 3.0 # maturity
u0 = fill(90.0, d) # initial stock value
delta = 0.1 # delta
f(du, u, p, t) = du .= (r - delta) * u # drift
sigma(du, u, p, t) = du .= beta * u # diffusion
tspan = (0.0, T)
N = 9 # discretization parameter
dt = T / (N)
K = 100.00 # strike price

# payoff function
function g(x, t)
    return exp(-r * t) * (max(maximum(x) - K, 0))
end
g (generic function with 1 method)

We then define a ParabolicPDEProblem with no non linear term:

prob = ParabolicPDEProblem(f, sigma, u0, tspan; payoff = g)
ParabolicPDEProblem with uType Float64 and tType Float64. In-place: false
timespan: (0.0, 3.0)
u0: 0.0
Note

We provide the payoff function with a keyword argument payoff

And now we define our models:

models = [Chain(Dense(d + 1, 32, tanh), BatchNorm(32, tanh), Dense(32, 1, sigmoid))
          for i in 1:N]
9-element Vector{Flux.Chain{Tuple{Flux.Dense{typeof(tanh), Matrix{Float32}, Vector{Float32}}, Flux.BatchNorm{typeof(tanh), Vector{Float32}, Float32, Vector{Float32}}, Flux.Dense{typeof(NNlib.σ), Matrix{Float32}, Vector{Float32}}}}}:
 Chain(Dense(4 => 32, tanh), BatchNorm(32, tanh), Dense(32 => 1, σ))  # 257 parameters, plus 64 non-trainable
 Chain(Dense(4 => 32, tanh), BatchNorm(32, tanh), Dense(32 => 1, σ))  # 257 parameters, plus 64 non-trainable
 Chain(Dense(4 => 32, tanh), BatchNorm(32, tanh), Dense(32 => 1, σ))  # 257 parameters, plus 64 non-trainable
 Chain(Dense(4 => 32, tanh), BatchNorm(32, tanh), Dense(32 => 1, σ))  # 257 parameters, plus 64 non-trainable
 Chain(Dense(4 => 32, tanh), BatchNorm(32, tanh), Dense(32 => 1, σ))  # 257 parameters, plus 64 non-trainable
 Chain(Dense(4 => 32, tanh), BatchNorm(32, tanh), Dense(32 => 1, σ))  # 257 parameters, plus 64 non-trainable
 Chain(Dense(4 => 32, tanh), BatchNorm(32, tanh), Dense(32 => 1, σ))  # 257 parameters, plus 64 non-trainable
 Chain(Dense(4 => 32, tanh), BatchNorm(32, tanh), Dense(32 => 1, σ))  # 257 parameters, plus 64 non-trainable
 Chain(Dense(4 => 32, tanh), BatchNorm(32, tanh), Dense(32 => 1, σ))  # 257 parameters, plus 64 non-trainable
Note

The number of models should be equal to the time discritization.

And finally we define our optimizer and algorithm, and call solve:

opt = Flux.Optimisers.Adam(0.01)
alg = NNStopping(models, opt)

sol = solve(
    prob, alg, SRIW1(); dt = dt, trajectories = 1000, maxiters = 1000, verbose = true)
(payoff = 12.244713988249366, stopping_time = [3.0, 3.0, 3.0, 2.0, 3.0, 2.0, 2.6666666666666665, 3.0, 3.0, 3.0  …  3.0, 1.3333333333333333, 3.0, 2.3333333333333335, 3.0, 1.0, 3.0, 3.0, 3.0, 3.0])