Last active
March 2, 2016 20:53
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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