Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Option Pricing using Explicit Finite Difference Method, converted to F# from VBA code in Paul Wilmott Introduces Quantitative Finance book. http://taumuon-jabuka.blogspot.co.uk/2013/02/option-pricing-in-f-using-explicit.html
open System
let callPayoff strike spot = max (spot - strike) 0.0
let putPayoff strike spot = max (strike - spot) 0.0
let triplewise (source: seq<_>) =
source
|> Seq.windowed 3
|> Seq.map (fun triple -> (triple.[0], triple.[1], triple.[2]))
let calcAssetStep strike numberAssetSteps =
2.0 * strike / float numberAssetSteps // 'infinity' is twice the strike
let calcTimeStep vol numberAssetSteps expiration =
let timeStep = 0.9 / (vol * vol) / float (numberAssetSteps * numberAssetSteps) // For stability
let numberTimeSteps = (int (expiration / timeStep)) + 1
let dT = (expiration / float numberTimeSteps) // ensure expiration is an integer number of time steps away
(dT, numberTimeSteps)
let optionValue vol intRate payoff strike expiration numberAssetSteps =
let payoffForStrike = payoff strike // partially apply
let dS = calcAssetStep strike numberAssetSteps
let timeStep = calcTimeStep vol numberAssetSteps expiration
let dT = fst timeStep
let numberTimeSteps = snd timeStep
let S = [|for i in 0 .. numberAssetSteps -> float i * dS|]
let initialValues = [|for i in 0 .. numberAssetSteps -> payoffForStrike S.[i]|]
let calc (prev, curr, next) S =
let delta = (next - prev) / 2.0 / dS; // central difference
let gamma = (next - 2.0 * curr + prev) / dS / dS // central difference
let theta = -0.5 * vol * vol * S * S * gamma - intRate * S * delta + intRate * curr // Black-Scholes
curr - float dT * theta
let calc (k, prevValues:float[]) =
if k = (numberTimeSteps + 1) then
None
else
let values = prevValues
|> Seq.ofArray
|> triplewise
|> Seq.mapi (fun idx vals -> calc vals S.[idx + 1])
let b0 = prevValues.[0] * (1.0 - intRate * float dT) // boundary condition at S=0
let placeHolder = 0.0
let valuesSeq = seq {
yield b0
yield! values
yield placeHolder }
let valuesArray = Seq.toArray valuesSeq
let b1 = 2.0 * valuesArray.[numberAssetSteps - 1] - valuesArray.[numberAssetSteps - 2] // boundary condition at S=infinity
valuesArray.[valuesArray.Length - 1] <- b1
Some(valuesArray, (k+1, valuesArray))
seq
{ yield initialValues
yield! Seq.unfold calc (1, initialValues) }
// use gnuplot with the following:
// set zrange [0:120]
// set xlabel "Time"
// set ylabel "Asset"
// set zlabel "Option value"
// splot "out.dat"
let outputVals (filename:string) (dS:float) (dT:float) (vals:seq<float[]>) =
use textWriter = new System.IO.StreamWriter(filename)
vals |> Seq.iteri (fun i s ->
for j = 0 to (s.Length - 1) do
textWriter.WriteLine("{0} {1} {2}", dT * float i, dS * float j, s.[j]))
[<EntryPoint>]
[<STAThread>]
let main argv =
let vol = 0.2
let interestRate = 0.05
let strike = 100.0
let expiry = 1.0
let numberAssetSteps = 20
let vCall = optionValue vol interestRate callPayoff strike expiry numberAssetSteps
let dS = calcAssetStep strike numberAssetSteps
let timeStep = calcTimeStep vol numberAssetSteps expiry
let dT = fst timeStep
vCall |> outputVals "E:\\temp\\Call.dat" dS dT
let vPut = optionValue vol interestRate putPayoff strike expiry numberAssetSteps
vPut |> outputVals "E:\\temp\\Put.dat" dS dT
0 // return an integer exit code
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.