module Program
open System
open System.Drawing
open System.Net
open System.Windows.Forms
open System.Windows.Forms.DataVisualization.Charting
open MathNet.Numerics.Distributions
open Microsoft.FSharp.Control.WebExtensions
let normalDistribution = new Normal(0.0, 1.0)
// create series for stock price
let getWienerProcessChartSeries () =
let wienerProcess = new Series("process")
wienerProcess.ChartType <- SeriesChartType.Line
wienerProcess.BorderWidth <- 2
wienerProcess.Color <- Color.Red
wienerProcess
// define an infinite Wiener Series
let WienerSeries scalingFactor =
let T = 1.0
let n = 500.0
let Δt = T / n
let rec loop x =
seq {
yield x
yield! loop (x + sqrt(Δt) * normalDistribution.Sample() * scalingFactor)
}
loop scalingFactor
[<STAThread>]
do
let wienerProcess = getWienerProcessChartSeries()
// create chart and form
let chart = new Chart(Dock = DockStyle.Fill)
let chartArea = new ChartArea("Main")
chart.ChartAreas.Add chartArea
chart.Series.Add wienerProcess
let mainForm = new Form(Visible = true, TopMost = true, Width = 700, Height = 500)
mainForm.Text <- "Wiener process in F#"
mainForm.Controls.Add chart
WienerSeries 55.00
|> Seq.take 100
|> Seq.iter (wienerProcess.Points.Add >> ignore)
Application.Run mainForm
module BlackScholes
let private pow x n = exp(n * log(x))
type PutCallFlag = Put | Call
/// <summary>
/// Cumulative Distribution function
/// </summary>
/// <param name="x"></param>
let private cnd x =
let a1 = +0.31938153
let a2 = -0.356563782
let a3 = +1.781477937
let a4 = -1.821255978
let a5 = +1.330274429
let pi = +3.141592654
let l = abs x
let k = 1.0 / (1.0 + 0.2316419 * l)
let w = (1.0 - 1.0 / sqrt(2.0 * pi) * exp(-l * l / 2.0) * (a1 * (pow k 1.0) + a2 * (pow k 2.0) + a3 * (pow k 3.0) + a4 * (pow k 4.0) + a5 * (pow k 5.0)))
if x < 0.0
then
1.0 - w
else
w
let BlackScholes callPutFlag stockPrice strikePriceOfOption timeToExpirationInYears riskFreeInterestRate volatility =
let d1 = (log(stockPrice / strikePriceOfOption) + (riskFreeInterestRate + volatility * volatility * 0.5) * timeToExpirationInYears) / (volatility * sqrt(timeToExpirationInYears))
let d2 = d1 - volatility * sqrt(timeToExpirationInYears)
match callPutFlag with
| Put -> strikePriceOfOption * exp(-riskFreeInterestRate * timeToExpirationInYears) * cnd(-d2) - stockPrice * cnd(-d1)
| Call -> stockPrice * cnd(d1) - strikePriceOfOption * exp(-riskFreeInterestRate * timeToExpirationInYears) * cnd(d2)
open System
open System.Drawing
open System.Net
open System.Windows.Forms
open System.Windows.Forms.DataVisualization.Charting
open Microsoft.FSharp.Control.WebExtensions
open BlackScholes
let getOptionPriceCall () =
let optionPriceCall = new Series "Call option price"
optionPriceCall.ChartType <- SeriesChartType.Line
optionPriceCall.BorderWidth <- 2
optionPriceCall.Color <- Color.Red
optionPriceCall
let getOptionPricePut () =
let optionPricePut = new Series "Put option price"
optionPricePut.ChartType <- SeriesChartType.Line
optionPricePut.BorderWidth <- 2
optionPricePut.Color <- Color.Blue
optionPricePut
[<STAThread>]
do
let optionPricePut = getOptionPricePut()
let optionPriceCall = getOptionPriceCall()
let chart = new Chart(Dock = DockStyle.Fill)
let chartArea = new ChartArea("Main")
chart.ChartAreas.Add chartArea
chart.Legends.Add(new Legend())
chart.Series.Add optionPriceCall
chart.Series.Add optionPricePut
let mainForm = new Form(Visible = true, TopMost = true, Width = 700, Height = 500)
mainForm.Text <- "Option price as a function of time"
mainForm.Controls.Add chart
let daysToYears days = (float days) / 365.25
let timeSpan = [(daysToYears 20)..(-(daysToYears 1)) .. 0.0]
let opc = [for x in timeSpan do yield BlackScholes Call 58.60 60.0 x 0.01 0.3]
opc |> Seq.iter (optionPriceCall.Points.Add >> ignore)
let opp = [for x in timeSpan do yield BlackScholes Put 58.60 60.0 x 0.01 0.3]
opp |> Seq.iter (optionPricePut.Points.Add >> ignore)
Application.Run mainForm
module BlackScholesGreeks
open BlackScholes
open MathNet.Numerics.Distributions
let private normd = new Normal(0.0, 1.0)
let private d s x t r v = (log(s / x) + (r + v * v * 0.5) * t)/(v * sqrt(t))
/// <summary>
/// Black-Scholes Delta
/// </summary>
/// <param name="callPutFlag">Put | Call</param>
/// <param name="s">stock price</param>
/// <param name="x">strike price of option</param>
/// <param name="t">time to expiration in years</param>
/// <param name="r">risk free interest rate</param>
/// <param name="v">volatility</param>
let blackScholesDelta callPutFlag s x t r v =
let d1 = d s x t r v
match callPutFlag with
| Put -> cnd(d1) - 1.0
| Call -> cnd(d1)
/// <summary>
/// Black-Scholes Gamma
/// </summary>
/// <param name="s">stock price</param>
/// <param name="x">strike price of option</param>
/// <param name="t">time to expiration in years</param>
/// <param name="r">risk free interest rate</param>
/// <param name="v">volatility</param>
let blackScholesGamma s x t r v =
let d1 = d s x t r v
normd.Density(d1) / (s * v * sqrt(t))
/// <summary>
/// Black-Scholes Vega
/// </summary>
/// <param name="s">stock price</param>
/// <param name="x">strike price of option</param>
/// <param name="t">time to expiration in years</param>
/// <param name="r">risk free interest rate</param>
/// <param name="v">volatility</param>
let blackScholesVega s x t r v =
let d1 = d s x t r v
s * normd.Density(d1) * sqrt(t)
/// <summary>
/// Black-Scholes Theta
/// </summary>
/// <param name="callPutFlag">Put | Call</param>
/// <param name="s">stock price</param>
/// <param name="x">strike price of option</param>
/// <param name="t">time to expiration in years</param>
/// <param name="r">risk free interest rate</param>
/// <param name="v">volatility</param>
let blackScholesTheta callPutFlag s x t r v =
let d1 = d s x t r v
let d2 = d1 - v * sqrt(t)
let res = ref 0.0
match callPutFlag with
| Put -> -(s * normd.Density(d1) * v) / (2.0 * sqrt(t)) + r * x * exp(r * t) * cnd(-d2)
| Call -> -(s * normd.Density(d1) * v) / (2.0 * sqrt(t)) - r * x * exp(-r * t) * cnd(d2)
/// <summary>
/// Black-Scholes Rho
/// </summary>
/// <param name="callPutFlag">Put | Call</param>
/// <param name="s">stock price</param>
/// <param name="x">strike price of option</param>
/// <param name="t">time to expiration in years</param>
/// <param name="r">risk free interest rate</param>
/// <param name="v">volatility</param>
let blackSholesRho callPutFlag s x t r v =
let d1 = d s x t r v
let d2 = d1 - v * sqrt(t)
let res = ref 0.0
match callPutFlag with
| Put -> -x * t * -exp(-r * t) * cnd(-d2)
| Call -> x * t * exp(-r * t) * cnd(d2)
open System
open System.Drawing
open System.Net
open System.Windows.Forms
open System.Windows.Forms.DataVisualization.Charting
open Microsoft.FSharp.Control.WebExtensions
open BlackScholes
open BlackScholesGreeks
let range = [10.0..1.0..70.0]
let getOptionCallDelta () =
let series = new Series("Call option delta")
series.ChartType <- SeriesChartType.Line
series.BorderWidth <- 2
series.Color <- Color.Red
[for x in range do yield blackScholesDelta Call x 60.0 0.5 0.01 0.3]
|> Seq.iter (series.Points.Add >> ignore)
series
let getOptionCallGamma () =
let series = new Series("Call option gamma")
series.ChartType <- SeriesChartType.Line
series.BorderWidth <- 2
series.Color <- Color.DarkBlue
[for x in range do yield blackScholesGamma x 60.0 0.5 0.01 0.3]
|> Seq.iter (series.Points.Add >> ignore)
series
let getOptionCallTheta () =
let series = new Series("Call option theta")
series.ChartType <- SeriesChartType.Line
series.BorderWidth <- 2
series.Color <- Color.DarkGreen
[for x in range do yield blackScholesTheta Call x 60.0 0.5 0.01 0.3]
|> Seq.iter (series.Points.Add >> ignore)
series
let getOptionCallVega () =
let series = new Series("Call option vega")
series.ChartType <- SeriesChartType.Line
series.BorderWidth <- 2
series.Color <- Color.DarkViolet
[for x in range do yield blackScholesVega x 60.0 0.5 0.01 0.3]
|> Seq.iter (series.Points.Add >> ignore)
series
[<STAThread>]
do
let chartArea = new ChartArea("Main")
let chart = new Chart(Dock = DockStyle.Fill)
chart.ChartAreas.Add chartArea
chart.Legends.Add(new Legend())
chart.Series.Add(getOptionCallDelta())
chart.Series.Add(getOptionCallGamma())
chart.Series.Add(getOptionCallTheta())
chart.Series.Add(getOptionCallVega())
let mainForm = new Form(Visible = true, TopMost = true, Width = 700, Height = 500)
mainForm.Text <- "Option delta as a function of underlying price"
mainForm.Controls.Add chart
Application.Run mainForm
module MonteCarlo
open System
open Microsoft.FSharp.Data.UnitSystems
[<Measure>] type Day
[<Measure>] type Year
[<Measure>] type Price
/// <summary>
/// Convert days to years
/// </summary>
/// <param name="days"></param>
let daysToYears (days:float<Day>) : float<Year> = days / 365.25<Day/Year>
/// <summary>
/// Asset price at maturity for sample rnd
/// </summary>
/// <param name="s">stock price</param>
/// <param name="t">time to expiration in years</param>
/// <param name="r">risk free interest rate</param>
/// <param name="v">volatility</param>
/// <param name="rnd">sample</param>
let priceForSample (s:float<Price>) (t:float<Year>) (r:float) (v:float) (rnd:float) : float<Price> =
s * exp((r - v * v / 2.0) * (t * 1.0<1/Year>) + v * rnd * sqrt(t * 1.0<1/Year>))
/// <summary>
/// For each sample we run the monte carlo simulation
/// </summary>
/// <param name="s">stock price</param>
/// <param name="x">strike price of option</param>
/// <param name="t">time to expiration in years</param>
/// <param name="r">risk free interest rate</param>
/// <param name="v">volatility</param>
/// <param name="samples">random samples as input to simulation</param>
let monteCarlo (s:float<Price>) x (t:float<Year>) (r:float) (v:float) (samples:seq<float>) : float<Price> =
samples
|> Seq.map (fun rnd -> (priceForSample s t r v rnd) - x)
|> Seq.average
let random = new Random()
let rnd = random.NextDouble
let data = [for _ in 1..1000 -> rnd()]
let calculatedCallOptionPrices = monteCarlo 58.60<Price> 60.0<Price> 0.5<Year> 0.01 0.3 data