Created
April 27, 2021 08:53
-
-
Save ColinEberhardt/3df974c557881ae4319034d4fc4c9f12 to your computer and use it in GitHub Desktop.
barrier.ts
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
// the code from this gist: https://gist.github.com/jdunkerley/323b0d1d2a9b7f96d570778402389566 | |
// re-implemented in AssemblyScript | |
import "wasi"; | |
import { Console, FileSystem, Descriptor } from "as-wasi"; | |
class Nullable<T> { | |
constructor(public value: T, public isNull: bool = false) {} | |
get notNull(): bool { | |
return !this.isNull; | |
} | |
} | |
const NullF64 = new Nullable<f64>(0, true); | |
class Val { | |
current: f64; | |
min: f64; | |
max: f64; | |
} | |
function boxMullerRand(): f64 { | |
while (true) { | |
let x = Math.random() * 2.0 - 1; | |
let y = Math.random() * 2.0 - 1; | |
let d = x * x + y * y; | |
if (d < 1) { | |
return x * sqrt((-2 * Math.log(d)) / d); | |
} | |
} | |
} | |
function pathFinalMinMax( | |
initial: f64, | |
time: f64, | |
steps: i32, | |
volatility: f64, | |
riskfree: f64 | |
): Val { | |
let dt = time / f64(steps); | |
let sdt = sqrt(dt); | |
let drift = Math.exp((riskfree - 0.5 * volatility * volatility) * dt); | |
let current = initial; | |
let min = current; | |
let max = current; | |
for (let i = 0; i < steps - 1; i++) { | |
current = current * drift * Math.exp(sdt * volatility * boxMullerRand()); | |
if (min > current) min = current; | |
if (max < current) max = current; | |
} | |
return { current: current, min: min, max: max }; | |
} | |
function priceOption( | |
strike: f64, | |
spot: f64, | |
time: i32, | |
volatility: f64, | |
risk_free: f64, | |
knockin: Nullable<f64> = NullF64, | |
knockout: Nullable<f64> = NullF64, | |
simulations: i32 = 2000, | |
steps_per_unit: i32 = 365 | |
): f64 { | |
if (knockin.notNull && knockout.notNull) | |
throw new Error("Unable to cope with 2 barriers!"); | |
let cp = 1; // if call_or_put == 'c' else -1 | |
let total = 0.0; | |
for (let i = 0; i < simulations; i++) { | |
const val = pathFinalMinMax( | |
spot, | |
time, | |
time * steps_per_unit, | |
volatility, | |
risk_free | |
); | |
if (knockin.notNull && knockin.value > spot && val.max < knockin.value) { | |
// Up and In | |
} else if ( | |
knockin.notNull && | |
knockin.value < spot && | |
val.min > knockin.value | |
) { | |
// Down and In | |
} else if ( | |
knockout.notNull && | |
knockout.value < spot && | |
val.min < knockin.value | |
) { | |
// Down and Out | |
} else if ( | |
knockout.notNull && | |
knockout.value > spot && | |
val.max > knockout.value | |
) { | |
// Up and Out | |
} else { | |
total += Math.max(0, cp * (val.current - strike)); | |
} | |
} | |
return (total / simulations) * Math.exp(-time * risk_free); | |
} | |
const spot = 100.0; | |
const strike = 105.0; | |
const vol = 0.2; | |
const risk_free = 0.05; | |
const price = priceOption(strike, spot, 1, vol, risk_free); | |
Console.log(price.toString()); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment