├── Chapter08
├── log.sql
└── tradehistory.sql
├── Chapter05
├── Chapter5
│ ├── packages.config
│ ├── App.config
│ ├── mc1.fsx
│ ├── Script2.fsx
│ ├── Script3.fsx
│ ├── Script1.fsx
│ ├── Chapter5.fsproj
│ └── chapter5.fsx
└── Chapter5.sln
├── Chapter04
├── Chapter4
│ ├── Script1.fsx
│ ├── App.config
│ ├── Script4.fsx
│ ├── Agent.fs
│ ├── GUI.fs
│ ├── Script2.fsx
│ ├── Script3.fsx
│ └── Chapter4.fsproj
└── Chapter4.sln
├── README.md
├── Chapter01
├── program1.fsx
├── program2.fsx
└── table.csv
├── Chapter06
├── Script8.fsx
├── Script5.fsx
├── Script4.fsx
├── volsmile.fsx
└── smile_data.csv
├── Chapter07
├── Quote.fsx
├── OrderType.fsx
└── FIX.fs
├── Chapter09
├── Script1.fsx
├── Script2.fsx
└── smile_data.csv
├── Chapter03
└── Chapter3.fsx
└── Chapter02
└── Chapter2.fsx
/Chapter08/log.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE LOG
2 | (
3 | log_id int IDENTITY PRIMARY KEY,
4 | log_datetime datetime DEFAULT CURRENT_TIMESTAMP,
5 | log_level nvarchar(12) DEFAULT 'info',
6 | log_msg ntext
7 | )
--------------------------------------------------------------------------------
/Chapter05/Chapter5/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/Chapter04/Chapter4/Script1.fsx:
--------------------------------------------------------------------------------
1 | open System.Windows.Forms
2 |
3 | let form = new Form(Text = "First F# form")
4 | let button = new Button(Text = "Click me to close!", Dock = DockStyle.Fill)
5 |
6 | button.Click.Add(fun _ -> Application.Exit() |> ignore)
7 | form.Controls.Add(button)
8 | form.Show()
--------------------------------------------------------------------------------
/Chapter08/tradehistory.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE TRADEHISTORY
2 | (
3 | tradehistory_id int IDENTITY PRIMARY KEY,
4 | tradehistory_datetime datetime DEFAULT CURRENT_TIMESTAMP,
5 | tradehistory_instrument nvarchar(12),
6 | tradehistory_qty int,
7 | tradehistory_type nvarchar(12),
8 | tradehistory_price float
9 | )
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | fsharp-for-quantitative-finance
2 | ===============================
3 |
4 | The example source code for the Packt's "F# for Quantitative Finance" by Johan Astborg
5 |
6 | [More info about the book](http://www.packtpub.com/fsharp-for-quantitative-finance/book)
7 |
8 | # Versions
9 | The code in this repository is kept up to date with errata corrections.
10 |
--------------------------------------------------------------------------------
/Chapter04/Chapter4/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/Chapter05/Chapter5/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/Chapter01/program1.fsx:
--------------------------------------------------------------------------------
1 | /// Open the System.IO namespace
2 | open System.IO
3 |
4 | /// Sample stock data, from Yahoo Finance
5 | let stockData = [
6 | "2013-06-06,51.15,51.66,50.83,51.52,9848400,51.52";
7 | "2013-06-05,52.57,52.68,50.91,51.36,14462900,51.36";
8 | "2013-06-04,53.74,53.75,52.22,52.59,10614700,52.59";
9 | "2013-06-03,53.86,53.89,52.40,53.41,13127900,53.41";
10 | "2013-05-31,54.70,54.91,53.99,54.10,12809700,54.10";
11 | "2013-05-30,55.01,55.69,54.96,55.10,8751200,55.10";
12 | "2013-05-29,55.15,55.40,54.53,55.05,8693700,55.05"
13 | ]
14 |
15 | /// Split row on commas
16 | let splitCommas (l:string) =
17 | l.Split(',')
18 |
19 |
20 | /// Get the row with lowest trading volume
21 | let lowestVolume =
22 | stockData
23 | |> List.map splitCommas
24 | |> List.minBy (fun x -> (int x.[5]))
--------------------------------------------------------------------------------
/Chapter01/program2.fsx:
--------------------------------------------------------------------------------
1 | /// Open the System.IO namespace
2 | open System.IO
3 |
4 | let filePath = "table.csv"
5 |
6 | /// Split row on commas
7 | let splitCommas (l:string) =
8 | l.Split(',')
9 |
10 | /// Read a file into a string array
11 | let openFile (name : string) =
12 | try
13 | let content = File.ReadAllLines(name)
14 | content |> Array.toList
15 | with
16 | | :? System.IO.FileNotFoundException as e -> printfn "Exception! %s " e.Message; ["empty"]
17 |
18 | /// Get the row with lowest trading volume, from file
19 | let lowestVolume =
20 | openFile filePath
21 | |> List.map splitCommas
22 | |> Seq.skip 1
23 | |> Seq.minBy (fun x -> (int x.[5]))
24 |
25 | /// Use printfn with generic formatter, %A
26 | printfn "Lowest volume, found in row: %A" lowestVolume
27 | lowestVolume.[0]
28 |
--------------------------------------------------------------------------------
/Chapter04/Chapter4/Script4.fsx:
--------------------------------------------------------------------------------
1 | #r "System.Windows.Forms.DataVisualization.dll"
2 |
3 | // The form
4 | open System
5 | open System.Net
6 | open System.Windows.Forms
7 | open System.Drawing
8 |
9 | let form = new Form(Visible = true, Text = "Data grid #1",
10 | TopMost = true, Size = Drawing.Size(600,600))
11 |
12 | let textBox =
13 | new RichTextBox(Dock = DockStyle.Fill, Text = "F# Programming is Fun!",
14 | Font = new Font("Lucida Console",16.0f,FontStyle.Bold),
15 | ForeColor = Color.DarkBlue)
16 |
17 | let show x =
18 | textBox.Text <- sprintf "%30A" x
19 |
20 |
21 | form.Controls.Add textBox
22 |
23 | show (1,2)
24 | show [ 0 .. 100 ]
25 | show [ 0.0 .. 2.0 .. 100.0 ]
26 |
27 | (1,2,3) |> show
28 |
29 | [ 0 .. 99 ] |> show
30 |
31 | [ for i in 0 .. 99 -> (i, i*i) ] |> show
32 |
--------------------------------------------------------------------------------
/Chapter04/Chapter4.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 2012
4 | Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Chapter4", "Chapter4\Chapter4.fsproj", "{7F1AD7E2-45C6-4685-A5F6-6A2EC8F92769}"
5 | EndProject
6 | Global
7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
8 | Debug|Any CPU = Debug|Any CPU
9 | Release|Any CPU = Release|Any CPU
10 | EndGlobalSection
11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
12 | {7F1AD7E2-45C6-4685-A5F6-6A2EC8F92769}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
13 | {7F1AD7E2-45C6-4685-A5F6-6A2EC8F92769}.Debug|Any CPU.Build.0 = Debug|Any CPU
14 | {7F1AD7E2-45C6-4685-A5F6-6A2EC8F92769}.Release|Any CPU.ActiveCfg = Release|Any CPU
15 | {7F1AD7E2-45C6-4685-A5F6-6A2EC8F92769}.Release|Any CPU.Build.0 = Release|Any CPU
16 | EndGlobalSection
17 | GlobalSection(SolutionProperties) = preSolution
18 | HideSolutionNode = FALSE
19 | EndGlobalSection
20 | EndGlobal
21 |
--------------------------------------------------------------------------------
/Chapter05/Chapter5.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 2012
4 | Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Chapter5", "Chapter5\Chapter5.fsproj", "{0F38272D-8BC4-4E8E-8168-083E60C0CBF7}"
5 | EndProject
6 | Global
7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
8 | Debug|Any CPU = Debug|Any CPU
9 | Release|Any CPU = Release|Any CPU
10 | EndGlobalSection
11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
12 | {0F38272D-8BC4-4E8E-8168-083E60C0CBF7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
13 | {0F38272D-8BC4-4E8E-8168-083E60C0CBF7}.Debug|Any CPU.Build.0 = Debug|Any CPU
14 | {0F38272D-8BC4-4E8E-8168-083E60C0CBF7}.Release|Any CPU.ActiveCfg = Release|Any CPU
15 | {0F38272D-8BC4-4E8E-8168-083E60C0CBF7}.Release|Any CPU.Build.0 = Release|Any CPU
16 | EndGlobalSection
17 | GlobalSection(SolutionProperties) = preSolution
18 | HideSolutionNode = FALSE
19 | EndGlobalSection
20 | EndGlobal
21 |
--------------------------------------------------------------------------------
/Chapter04/Chapter4/Agent.fs:
--------------------------------------------------------------------------------
1 | namespace Agents
2 |
3 | open System
4 |
5 | // Type for our agent
6 | type Agent<'T> = MailboxProcessor<'T>
7 |
8 | // Control messages to be sent to agent
9 | type CounterMessage =
10 | | Update of float
11 | | Reset
12 |
13 | module Helpers =
14 | let genRandomNumber (n) =
15 | let rnd = new System.Random()
16 | float (rnd.Next(n, 100))
17 |
18 | module MaxAgent =
19 | // Agent to keep track of max value and update GUI
20 | let sampleAgent = Agent.Start(fun inbox ->
21 | let rec loop max = async {
22 | let! msg = inbox.Receive()
23 | match msg with
24 | | Reset ->
25 | return! loop 0.0
26 | | Update value ->
27 | let max = Math.Max(max, value)
28 |
29 | Console.WriteLine("Max: " + max.ToString())
30 |
31 | do! Async.Sleep(1000)
32 | return! loop max
33 | }
34 | loop 0.0)
--------------------------------------------------------------------------------
/Chapter06/Script8.fsx:
--------------------------------------------------------------------------------
1 | open System
2 | open MathNet.Numerics
3 | open MathNet.Numerics.LinearAlgebra
4 | open MathNet.Numerics.LinearAlgebra.Double
5 | open MathNet.Numerics.Distributions
6 |
7 | /// Sample points
8 | let xdata = [ 0.0; 1.0; 2.0; 3.0; 4.0 ]
9 | let ydata = [ 1.0; 1.4; 1.6; 1.3; 0.9 ]
10 |
11 | let N = xdata.Length
12 | let order = 2
13 |
14 | /// Generating a Vandermonde row given input v
15 | let vandermondeRow v = [for x in [0..order] do yield v ** (float x)]
16 |
17 | /// Creating Vandermonde rows for each element in the list
18 | let vandermonde = xdata |> Seq.map vandermondeRow |> Seq.toList
19 |
20 | /// Create the A Matrix
21 | let A = vandermonde |> DenseMatrix.ofRowsList N (order + 1)
22 | A.Transpose()
23 |
24 | /// Create the Y Matrix
25 | let createYVector order l = [for x in [0..order] do yield l]
26 | let Y = (createYVector order ydata |> DenseMatrix.ofRowsList (order + 1) N).Transpose()
27 |
28 | /// Calculate coefficients using least squares
29 | let coeffs = (A.Transpose() * A).LU().Solve(A.Transpose() * Y).Column(0)
30 |
31 | let calculate x = (vandermondeRow(x) |> DenseVector.ofList) * coeffs
32 |
33 | let fitxs = [(Seq.min xdata).. 0.5 ..(Seq.max xdata)]
34 | let fitys = fitxs |> List.map calculate
--------------------------------------------------------------------------------
/Chapter04/Chapter4/GUI.fs:
--------------------------------------------------------------------------------
1 | namespace GUI
2 |
3 | open System
4 | open System.Drawing
5 | open System.Windows.Forms
6 | open Agents
7 |
8 | // User interface form
9 | type public SampleForm() as form =
10 | inherit Form()
11 |
12 | let valueLabel = new Label(Location=new Point(25,15), AutoSize=true)
13 | let sendButton = new Button(Location=new Point(25,75))
14 | let agent = MaxAgent.sampleAgent
15 |
16 | let initControls =
17 | valueLabel.Text <- "Press button to send value to agent."
18 | sendButton.Text <- "Send value to agent"
19 | do
20 | initControls
21 |
22 | form.Controls.Add(valueLabel)
23 | form.Controls.Add(sendButton)
24 |
25 | form.Text <- "SampleApp F#"
26 |
27 | sendButton.Click.AddHandler(new System.EventHandler
28 | (fun sender e -> form.eventStartButton_Click(sender, e)))
29 |
30 | // Event handlers
31 | member form.eventStartButton_Click(sender:obj, e:EventArgs) =
32 | let random = Helpers.genRandomNumber 5
33 | Console.WriteLine("Sending value to agent: " + random.ToString())
34 | agent.Post(Update random)
35 | ()
--------------------------------------------------------------------------------
/Chapter05/Chapter5/mc1.fsx:
--------------------------------------------------------------------------------
1 | /// Monte Carlo implementation
2 |
3 | /// Convert the nr of days to years
4 | let days_to_years d =
5 | (float d) / 365.25
6 |
7 | /// Asset price at maturity for sample rnd
8 | // s: stock price
9 | // t: time to expiration in years
10 | // r: risk free interest rate
11 | // v: volatility
12 | // rnd: sample
13 | let price_for_sample s t r v rnd =
14 | s*exp((r-v*v/2.0)*t+v*rnd*sqrt(t))
15 |
16 | /// For each sample we run the monte carlo simulation
17 | // s: stock price
18 | // x: strike price of option
19 | // t: time to expiration in years
20 | // r: risk free interest rate
21 | // v: volatility
22 | // samples: random samples as input to simulation
23 | let monte_carlo s x t r v (samples:seq) =
24 | samples
25 | |> Seq.map (fun rnd -> (price_for_sample s t r v rnd) - x)
26 | |> Seq.average
27 |
28 | ///// Generate sample sequence
29 | //let random = new System.Random()
30 | //let rnd() = random.NextDouble()
31 | //let data = [for i in 1 .. 1000 -> rnd() * 1.0]
32 |
33 | /// Monte carlo for call option
34 | //monte_carlo 58.60 60.0 0.5 0.01 0.3 data
35 |
36 | /// Generate sample sequence
37 | let random = new System.Random()
38 | let rnd() = random.NextDouble()
39 | let data = [for i in 1 .. 1000 -> rnd() * 1.0]
40 |
41 | /// Monte carlo for call option
42 | monte_carlo 58.60 60.0 0.5 0.01 0.3 data
--------------------------------------------------------------------------------
/Chapter05/Chapter5/Script2.fsx:
--------------------------------------------------------------------------------
1 | #r "System.Windows.Forms.DataVisualization.dll"
2 |
3 | open System
4 | open System.Net
5 | open System.Windows.Forms
6 | open System.Windows.Forms.DataVisualization.Charting
7 | open Microsoft.FSharp.Control.WebExtensions
8 | open MathNet.Numerics.Distributions;
9 |
10 | // A normally distributed random generator
11 | let normd = new Normal(0.0, 1.0)
12 |
13 | // Create chart and form
14 | let chart = new Chart(Dock = DockStyle.Fill)
15 | let area = new ChartArea("Main")
16 | chart.ChartAreas.Add(area)
17 |
18 | let mainForm = new Form(Visible = true, TopMost = true,
19 | Width = 700, Height = 500)
20 |
21 | do mainForm.Text <- "Wiener process in F#"
22 | mainForm.Controls.Add(chart)
23 |
24 | // Create serie for stock price
25 | let wienerProcess = new Series("process")
26 | do wienerProcess.ChartType <- SeriesChartType.Line
27 | do wienerProcess.BorderWidth <- 2
28 | do wienerProcess.Color <- Drawing.Color.Red
29 | chart.Series.Add(wienerProcess)
30 |
31 | let random = new System.Random()
32 | let rnd() = random.NextDouble()
33 | //let data = [for i in 1 .. 10 -> rnd()]
34 | let T = 1.0
35 | let N = 500.0
36 | let dt:float = T / N
37 |
38 | /// Sequences represent infinite number of elements
39 | let W s =
40 | let rec loop x = seq { yield x; yield! loop (x + sqrt(dt)*normd.Sample()*s)}
41 | loop s
42 |
43 | wienerProcess.Points.Clear()
44 | do (Seq.take 100 (W 55.00)) |> Seq.iter (wienerProcess.Points.Add >> ignore)
--------------------------------------------------------------------------------
/Chapter04/Chapter4/Script2.fsx:
--------------------------------------------------------------------------------
1 | #r "System.Windows.Forms.DataVisualization.dll"
2 |
3 | open System
4 | open System.Net
5 | open System.Windows.Forms
6 | open System.Windows.Forms.DataVisualization.Charting
7 | open Microsoft.FSharp.Control.WebExtensions
8 |
9 | // Create chart and form
10 | let chart = new Chart(Dock = DockStyle.Fill)
11 | let area = new ChartArea("Main")
12 | chart.ChartAreas.Add(area)
13 |
14 | let mainForm = new Form(Visible = true, TopMost = true,
15 | Width = 700, Height = 500)
16 |
17 | do mainForm.Text <- "Yahoo Finance data in F#"
18 | mainForm.Controls.Add(chart)
19 |
20 | // Create serie for stock price
21 | let stockPrice = new Series("stockPrice")
22 | do stockPrice.ChartType <- SeriesChartType.Line
23 | do stockPrice.BorderWidth <- 2
24 | do stockPrice.Color <- Drawing.Color.Red
25 | chart.Series.Add(stockPrice)
26 |
27 | // Create serie for moving average
28 | let movingAvg = new Series("movingAvg")
29 | do movingAvg.ChartType <- SeriesChartType.Line
30 | do movingAvg.BorderWidth <- 2
31 | do movingAvg.Color <- Drawing.Color.Blue
32 | chart.Series.Add(movingAvg)
33 |
34 | // Syncronous fetching (just one stock here)
35 | let fetchOne() =
36 | let uri = new System.Uri("http://ichart.finance.yahoo.com/table.csv?s=ORCL&d=9&e=23&f=2012&g=d&a=2&b=13&c=1986&ignore=.csv")
37 | let client = new WebClient()
38 | let html = client.DownloadString(uri)
39 | html
40 |
41 | // Parse CSV
42 | let getPrices() =
43 | let data = fetchOne()
44 | data.Split('\n')
45 | |> Seq.skip 1
46 | |> Seq.map (fun s -> s.Split(','))
47 | |> Seq.map (fun s -> float s.[4])
48 | |> Seq.truncate 2500
49 |
50 | // Calc moving average
51 | let movingAverage n (prices:seq) =
52 | prices
53 | |> Seq.windowed n
54 | |> Seq.map Array.sum
55 | |> Seq.map (fun a -> a / float n)
56 |
57 | // The plotting
58 | let sp = getPrices()
59 | do sp |> Seq.iter (stockPrice.Points.Add >> ignore)
60 |
61 | let ma = movingAverage 100 sp
62 | do ma |> Seq.iter (movingAvg.Points.Add >> ignore)
--------------------------------------------------------------------------------
/Chapter04/Chapter4/Script3.fsx:
--------------------------------------------------------------------------------
1 | #r "System.Windows.Forms.DataVisualization.dll"
2 |
3 | open System
4 | open System.Net
5 | open System.Windows.Forms
6 | open System.Windows.Forms.DataVisualization.Charting
7 | open Microsoft.FSharp.Control.WebExtensions
8 |
9 | // Create chart and form
10 | let chart = new Chart(Dock = DockStyle.Fill)
11 | let area = new ChartArea("Main")
12 | chart.ChartAreas.Add(area)
13 |
14 | let mainForm = new Form(Visible = true, TopMost = true,
15 | Width = 700, Height = 500)
16 |
17 | do mainForm.Text <- "Yahoo Finance data in F#"
18 | mainForm.Controls.Add(chart)
19 |
20 | // Create serie for stock price
21 | let stockPrice = new Series("stockPrice")
22 | do stockPrice.ChartType <- SeriesChartType.Line
23 | do stockPrice.BorderWidth <- 2
24 | do stockPrice.Color <- Drawing.Color.Red
25 | chart.Series.Add(stockPrice)
26 |
27 | // Create serie for moving average
28 | let movingAvg = new Series("movingAvg")
29 | do movingAvg.ChartType <- SeriesChartType.Line
30 | do movingAvg.BorderWidth <- 2
31 | do movingAvg.Color <- Drawing.Color.Blue
32 | chart.Series.Add(movingAvg)
33 |
34 | // Syncronous fetching (just one stock here)
35 | let fetchOne() =
36 | let uri = new System.Uri("http://ichart.finance.yahoo.com/table.csv?s=ORCL&d=9&e=23&f=2012&g=d&a=2&b=13&c=1986&ignore=.csv")
37 | let client = new WebClient()
38 | let html = client.DownloadString(uri)
39 | html
40 |
41 | // Parse CSV
42 | let getPrices() =
43 | let data = fetchOne()
44 | data.Split('\n')
45 | |> Seq.skip 1
46 | |> Seq.map (fun s -> s.Split(','))
47 | |> Seq.map (fun s -> float s.[4])
48 | |> Seq.truncate 2500
49 |
50 | // Calc moving average
51 | let movingAverage n (prices:seq) =
52 | prices
53 | |> Seq.windowed n
54 | |> Seq.map Array.sum
55 | |> Seq.map (fun a -> a / float n)
56 |
57 | // The plotting
58 | let sp = getPrices()
59 | do sp |> Seq.iter (stockPrice.Points.Add >> ignore)
60 |
61 | let ma = movingAverage 100 sp
62 | do ma |> Seq.iter (movingAvg.Points.Add >> ignore)
--------------------------------------------------------------------------------
/Chapter05/Chapter5/Script3.fsx:
--------------------------------------------------------------------------------
1 | /// Normal distribution
2 |
3 | open System
4 | open System.Net
5 | open System.Windows.Forms
6 | open System.Windows.Forms.DataVisualization.Charting
7 | open Microsoft.FSharp.Control.WebExtensions
8 | open MathNet.Numerics.Distributions;
9 |
10 | let normd = new Normal(0.0, 1.0)
11 |
12 | // Create chart and form
13 | let chart = new Chart(Dock = DockStyle.Fill)
14 | let area = new ChartArea("Main")
15 | chart.ChartAreas.Add(area)
16 |
17 | let mainForm = new Form(Visible = true, TopMost = true,
18 | Width = 700, Height = 500)
19 |
20 | do mainForm.Text <- "VIX-index 2000-01-01 to 2013-11-01"
21 | mainForm.Controls.Add(chart)
22 |
23 | // Create serie for stock price
24 | let stockPrice = new Series("stockPrice")
25 | do stockPrice.ChartType <- SeriesChartType.Line
26 | do stockPrice.BorderWidth <- 2
27 | do stockPrice.Color <- Drawing.Color.Red
28 | chart.Series.Add(stockPrice)
29 |
30 | // Create serie for moving average
31 | let movingAvg = new Series("movingAvg")
32 | do movingAvg.ChartType <- SeriesChartType.Line
33 | do movingAvg.BorderWidth <- 2
34 | do movingAvg.Color <- Drawing.Color.Blue
35 | chart.Series.Add(movingAvg)
36 |
37 | // Syncronous fetching (just one stock here)
38 | let fetchOne() =
39 | let uri = new System.Uri("http://ichart.finance.yahoo.com/table.csv?s=%5EVIX&a=00&b=1&c=2000&d=10&e=1&f=2013&g=d&ignore=.csv")
40 | let client = new WebClient()
41 | let html = client.DownloadString(uri)
42 | html
43 |
44 | // Parse CSV
45 | let getPrices() =
46 | let data = fetchOne()
47 | data.Split('\n')
48 | |> Seq.skip 1
49 | |> Seq.map (fun s -> s.Split(','))
50 | |> Seq.map (fun s -> float s.[4])
51 | |> Seq.truncate 2500
52 |
53 | // Calc moving average
54 | let movingAverage n (prices:seq) =
55 | prices
56 | |> Seq.windowed n
57 | |> Seq.map Array.sum
58 | |> Seq.map (fun a -> a / float n)
59 |
60 | // The plotting
61 | let sp = getPrices()
62 | do sp |> Seq.iter (stockPrice.Points.Add >> ignore)
63 |
64 | let ma = movingAverage 100 sp
65 | do ma |> Seq.iter (movingAvg.Points.Add >> ignore)
--------------------------------------------------------------------------------
/Chapter07/Quote.fsx:
--------------------------------------------------------------------------------
1 | /// Type to represent market data, bid ask, latest aggregation
2 | type Quote =
3 | {
4 | bid : float
5 | ask : float
6 | }
7 | member this.midpoint() = (this.bid + this.ask) / 2.0
8 |
9 | let q = {bid = 1.40; ask = 1.45} : Quote
10 | q.midpoint()
11 |
12 | type Quote2 =
13 | {
14 | bid : float
15 | ask : float
16 | }
17 | member this.midpoint() = (this.bid + this.ask) / 2.0
18 | member this.spread() = abs(this.bid - this.ask)
19 |
20 |
21 | /// Change
22 | // Often data is just sent from the feed handler, as bid or ask
23 | type LightQuote =
24 | | Bid of float | Ask of float
25 |
26 |
27 | /// Brownian motion / Wiener process
28 | let random = new System.Random()
29 | let rnd() = random.NextDouble()
30 | let data = [for i in 1 .. 10 -> rnd()]
31 | let T = 1.0
32 | let N = 500.0
33 | let dt:float = T / N
34 |
35 | /// Recursion
36 | let primes =
37 | Seq.initInfinite (fun i -> i + 2) //need to skip 0 and 1 for isPrime
38 | |> Seq.map (fun i -> bigint(i))
39 |
40 | let allEvens =
41 | let rec loop x = seq { yield x; yield! loop (x + 2) }
42 | loop 0;;
43 |
44 | Seq.take 5 allEvens
45 |
46 | /// Sequences represent infinite number of elements
47 | // p -> probability mean
48 | // s -> scaling factor
49 | let W p s =
50 | let rec loop x = seq { yield x; yield! loop (x + sqrt(dt)*(rnd()-(1.0-p))*s)}
51 | loop 0.0;;
52 |
53 | Seq.take 50 (W 0.6 10.0)
54 |
55 | #r "System.Windows.Forms.DataVisualization.dll"
56 |
57 | open System
58 | open System.Net
59 | open System.Windows.Forms
60 | open System.Windows.Forms.DataVisualization.Charting
61 | open Microsoft.FSharp.Control.WebExtensions
62 |
63 | // Create chart and form
64 | let chart = new Chart(Dock = DockStyle.Fill)
65 | let area = new ChartArea("Main")
66 | chart.ChartAreas.Add(area)
67 |
68 | let mainForm = new Form(Visible = true, TopMost = true,
69 | Width = 700, Height = 500)
70 |
71 | do mainForm.Text <- "Wiener process in F#"
72 | mainForm.Controls.Add(chart)
73 |
74 | // Create serie for stock price
75 | let wienerProcess = new Series("process")
76 | do wienerProcess.ChartType <- SeriesChartType.Line
77 | do wienerProcess.BorderWidth <- 2
78 | do wienerProcess.Color <- Drawing.Color.Red
79 | chart.Series.Add(wienerProcess)
80 |
81 | do (Seq.take 100 (W 0.55 100.0)) |> Seq.iter (wienerProcess.Points.Add >> ignore)
82 |
83 |
--------------------------------------------------------------------------------
/Chapter09/Script1.fsx:
--------------------------------------------------------------------------------
1 | open System.IO
2 | open FSharp.Charting
3 | open System.Windows.Forms.DataVisualization.Charting
4 |
5 | let mlist = [for x in [0..10] do yield (x, x*2)]
6 |
7 | /// Plot values using FSharpChart
8 | fsi.AddPrinter(fun (ch:FSharp.Charting.ChartTypes.GenericChart) -> ch.ShowChart(); "FSharpChartingSmile")
9 | Chart.Line(mlist)
10 |
11 | //Chart.Line(fits).WithTitle("Volatility Smile")
12 |
13 | /// Payoff for European call option
14 | // s: stock price
15 | // k: strike price of option
16 | let payoffCall k s =
17 | max (s-k) 0.0
18 |
19 | /// Payoff for European Put option
20 | // s: stock price
21 | // k: strike price of option
22 | let payoffPut k s =
23 | max (k-s) 0.0
24 |
25 | // Calculate the payoff of a given option
26 | let payoff payoffFunction =
27 | [ for s in 0.0 .. 10.0 .. 100.0 -> s, payoffFunction s ]
28 |
29 | // Compare the payoff of call and put options
30 | let callPayoff = payoff (payoffCall 50.0)
31 | let putPayoff = payoff (payoffPut 50.0)
32 |
33 | let chart = Chart.Combine [Chart.Line(callPayoff); Chart.Line(putPayoff).WithTitle("Payoff diagram")]
34 |
35 | //Chart.Line(callPayoff).WithTitle("Payoff - Call Option")
36 | Chart.Line(putPayoff).WithTitle("Payoff - Put Option")
37 |
38 | // Display the payoff of European call and put options
39 | let chart = Chart.Combine [ Chart.Line(callPayoff, Name="Call option").WithLegend(); Chart.Line(putPayoff, Name="Put option").WithLegend().WithTitle("Payoff diagram") ]
40 | chart.WithTitle("Payoff diagram")
41 |
42 | ////////////
43 |
44 | /// Payoff for long straddle
45 | // s: stock price
46 | // k: strike price of option
47 | let longStraddle k s =
48 | (payoffCall k s) +
49 | (payoffPut k s)
50 |
51 | /// Payoff for Short straddle
52 | // s: stock price
53 | // k: strike price of option
54 | let shortStraddle k s =
55 | -(payoffCall k s) +
56 | -(payoffPut k s)
57 |
58 | /// Payoff for long butterfly
59 | // s: stock price
60 | // h: high price
61 | // l: low price
62 | let longButterfly l h s =
63 | (payoffCall l s) +
64 | (payoffCall h s) -
65 | 2.0 * (payoffCall ((l + h) / 2.0) s)
66 |
67 | /// Payoff for short butterfly
68 | // s: stock price
69 | // h: high price
70 | // l: low price
71 | let shortButterfly l h s =
72 | -(payoffCall l s) +
73 | -(payoffCall h s) -
74 | 2.0 * -(payoffCall ((l + h) / 2.0) s)
75 |
76 | Chart.Line(payoff (longStraddle 50.0)).WithTitle("Payoff - Long straddle")
77 |
78 | Chart.Line(payoff (shortStraddle 50.0)).WithTitle("Payoff - Short straddle")
79 |
80 | Chart.Line(payoff (longButterfly 20.0 80.0)).WithTitle("Payoff - Long butterfly")
81 |
82 | Chart.Line(payoff (shortButterfly 20.0 80.0)).WithTitle("Payoff - Short butterfly")
--------------------------------------------------------------------------------
/Chapter06/Script5.fsx:
--------------------------------------------------------------------------------
1 | open System.IO
2 | open FSharp.Charting
3 | open System.Windows.Forms.DataVisualization.Charting
4 |
5 | open MathNet.Numerics
6 | open MathNet.Numerics.LinearAlgebra
7 | open MathNet.Numerics.LinearAlgebra.Double
8 | open MathNet.Numerics.Distributions
9 |
10 | let filePath = @"smile_data.csv"
11 |
12 | /// Split row on commas
13 | let splitCommas (l:string) =
14 | l.Split(',')
15 |
16 | /// Read a file into a string array
17 | let openFile (name : string) =
18 | try
19 | let content = File.ReadAllLines(name)
20 | content |> Array.toList
21 | with
22 | | :? System.IO.FileNotFoundException as e -> printfn "Exception! %s " e.Message; ["empty"]
23 |
24 | /// Read the data from a CSV file and returns
25 | /// a tuple of strike price and implied volatility%
26 | let readVolatilityData =
27 | openFile filePath
28 | |> List.map splitCommas
29 | |> List.map (fun cols -> (cols.[2], cols.[3]))
30 |
31 | /// 83.2
32 | /// Calculates moneyness and parses strings into numbers
33 | let calcMoneyness spot list =
34 | list
35 | |> List.map (fun (strike, imp) -> (spot / (float strike), (float imp)))
36 |
37 | let list = readVolatilityData
38 | let mlist = calcMoneyness 83.2 list
39 |
40 | /// Plot values using FSharpChart
41 | fsi.AddPrinter(fun (ch:FSharp.Charting.ChartTypes.GenericChart) -> ch.ShowChart(); "FSharpChartingSmile")
42 | Chart.Point(mlist)
43 |
44 | /// Final step - Plot data
45 |
46 | /// Sample points
47 | //let xdata = [ 0.0; 1.0; 2.0; 3.0; 4.0 ]
48 | //let ydata = [ 1.0; 1.4; 1.6; 1.3; 0.9 ]
49 |
50 | let xdata = mlist |> Seq.map (fun (x, _) -> x) |> Seq.toList
51 | let ydata = mlist |> Seq.map (fun (_, y) -> y) |> Seq.toList
52 |
53 | let N = xdata.Length
54 | let order = 2
55 |
56 | /// Generating a Vandermonde row given input v
57 | let vandermondeRow v = [for x in [0..order] do yield v ** (float x)]
58 |
59 | /// Creating Vandermonde rows for each element in the list
60 | let vandermonde = xdata |> Seq.map vandermondeRow |> Seq.toList
61 |
62 | /// Create the A Matrix
63 | let A = vandermonde |> DenseMatrix.ofRowsList N (order + 1)
64 | A.Transpose()
65 |
66 | /// Create the Y Matrix
67 | let createYVector order l = [for x in [0..order] do yield l]
68 | let Y = (createYVector order ydata |> DenseMatrix.ofRowsList (order + 1) N).Transpose()
69 |
70 | /// Calculate coefficients using least squares
71 | let coeffs = (A.Transpose() * A).LU().Solve(A.Transpose() * Y).Column(0)
72 |
73 | let calculate x = (vandermondeRow(x) |> DenseVector.ofList) * coeffs
74 |
75 | let fitxs = [(Seq.min xdata).. 0.01 ..(Seq.max xdata)]
76 | let fitys = fitxs |> List.map calculate
77 | let fits = [for x in [(Seq.min xdata).. 0.01 ..(Seq.max xdata)] do yield (x, calculate x)]
78 |
79 | let chart = Chart.Combine [Chart.Point(mlist); Chart.Line(fits).WithTitle("Volatility Smile")]
--------------------------------------------------------------------------------
/Chapter09/Script2.fsx:
--------------------------------------------------------------------------------
1 | open System.IO
2 | open FSharp.Charting
3 | open System.Windows.Forms.DataVisualization.Charting
4 |
5 | open MathNet.Numerics
6 | open MathNet.Numerics.LinearAlgebra
7 | open MathNet.Numerics.LinearAlgebra.Double
8 | open MathNet.Numerics.Distributions
9 |
10 | let filePath = @"smile_data.csv"
11 |
12 | /// Split row on commas
13 | let splitCommas (l:string) =
14 | l.Split(',')
15 |
16 | /// Read a file into a string array
17 | let openFile (name : string) =
18 | try
19 | let content = File.ReadAllLines(name)
20 | content |> Array.toList
21 | with
22 | | :? System.IO.FileNotFoundException as e -> printfn "Exception! %s " e.Message; ["empty"]
23 |
24 | /// Read the data from a CSV file and returns
25 | /// a tuple of strike price and implied volatility%
26 | // Filter for just one expiration date
27 | let readVolatilityData date =
28 | openFile filePath
29 | |> List.map splitCommas
30 | |> List.filter (fun cols -> cols.[1] = date)
31 | |> List.map (fun cols -> (cols.[2], cols.[3]))
32 |
33 | /// 83.2
34 | /// Calculates moneyness and parses strings into numbers
35 | let calcMoneyness spot list =
36 | list
37 | |> List.map (fun (strike, imp) -> (spot / (float strike), (float imp)))
38 |
39 | // Filter out one expiration date -- 2013-12-20
40 | let list = readVolatilityData "2013-12-20"
41 |
42 | // Filter on moneyness, 0.5 to 1.5
43 | let mlist = calcMoneyness 83.2 list |> List.filter (fun (x, y) -> x > 0.5 && x < 1.5)
44 |
45 | /// Plot values using FSharpChart
46 | fsi.AddPrinter(fun (ch:FSharp.Charting.ChartTypes.GenericChart) -> ch.ShowChart(); "FSharpChartingSmile")
47 | Chart.Point(mlist)
48 |
49 | /// Final step - Plot data
50 |
51 | let xdata = mlist |> Seq.map (fun (x, _) -> x) |> Seq.toList
52 | let ydata = mlist |> Seq.map (fun (_, y) -> y) |> Seq.toList
53 |
54 | let N = xdata.Length
55 | let order = 2
56 |
57 | /// Generating a Vandermonde row given input v
58 | let vandermondeRow v = [for x in [0..order] do yield v ** (float x)]
59 |
60 | /// Creating Vandermonde rows for each element in the list
61 | let vandermonde = xdata |> Seq.map vandermondeRow |> Seq.toList
62 |
63 | /// Create the A Matrix
64 | let A = vandermonde |> DenseMatrix.ofRowsList N (order + 1)
65 | A.Transpose()
66 |
67 | /// Create the Y Matrix
68 | let createYVector order l = [for x in [0..order] do yield l]
69 | let Y = (createYVector order ydata |> DenseMatrix.ofRowsList (order + 1) N).Transpose()
70 |
71 | /// Calculate coefficients using least squares
72 | let coeffs = (A.Transpose() * A).LU().Solve(A.Transpose() * Y).Column(0)
73 |
74 | let calculate x = (vandermondeRow(x) |> DenseVector.ofList) * coeffs
75 |
76 | let fitxs = [(Seq.min xdata).. 0.01 ..(Seq.max xdata)]
77 | let fitys = fitxs |> List.map calculate
78 | let fits = [for x in [(Seq.min xdata).. 0.01 ..(Seq.max xdata)] do yield (x, calculate x)]
79 |
80 | let chart = Chart.Combine [Chart.Point(mlist); Chart.Line(fits).WithTitle("Volatility Smile - 2nd degree polynomial")]
--------------------------------------------------------------------------------
/Chapter06/Script4.fsx:
--------------------------------------------------------------------------------
1 | open System
2 | open System.Net
3 |
4 | /// Calculate the standard deviation
5 | let stddev(values:seq) =
6 | values
7 | |> Seq.fold (fun acc x -> acc + (1.0 / float (Seq.length values)) * (x - (Seq.average values)) ** 2.0) 0.0
8 | |> sqrt
9 |
10 | /// Calculate logarithmic returns
11 | let calcDailyReturns(prices:seq) =
12 | prices
13 | |> Seq.pairwise
14 | |> Seq.map (fun (x, y) -> log (x / y))
15 |
16 | /// Annualized volatility
17 | let annualVolatility(returns:seq) =
18 | let sd = stddev(calcDailyReturns(returns))
19 | let days = Seq.length(returns)
20 | sd * sqrt(float days)
21 |
22 | let formatLeadingZero(number:int):String =
23 | String.Format("{0:00}", number)
24 |
25 | /// Helper function to create the Yahoo-finance URL
26 | let constructURL(symbol, fromDate:DateTime, toDate:DateTime) =
27 | let fm = formatLeadingZero(fromDate.Month-1)
28 | let fd = formatLeadingZero(fromDate.Day)
29 | let fy = formatLeadingZero(fromDate.Year)
30 | let tm = formatLeadingZero(toDate.Month-1)
31 | let td = formatLeadingZero(toDate.Day)
32 | let ty = formatLeadingZero(toDate.Year)
33 | "http://ichart.finance.yahoo.com/table.csv?s=" + symbol + "&d=" + tm + "&e=" + td + "&f=" + ty + "&g=d&a=" + fm + "&b=" + fd + "&c=" + fy + "&ignore=.csv"
34 |
35 | /// Synchronous fetching (just one request)
36 | let fetchOne symbol fromDate toDate =
37 | let url = constructURL(symbol, fromDate, toDate)
38 | let uri = new System.Uri(url)
39 | let client = new WebClient()
40 | let html = client.DownloadString(uri)
41 | html
42 |
43 | /// Parse CSV
44 | let getPrices stock fromDate toDate =
45 | let data = fetchOne stock fromDate toDate
46 | data.Trim().Split('\n')
47 | |> Seq.skip 1
48 | |> Seq.map (fun s -> s.Split(','))
49 | |> Seq.map (fun s -> float s.[4])
50 | |> Seq.takeWhile (fun s -> s >= 0.0)
51 |
52 | /// Returns a formatted string with volatility for a stock
53 | let getAnnualizedVol stock fromStr toStr =
54 | let prices = getPrices stock (System.DateTime.Parse fromStr) (System.DateTime.Parse toStr)
55 | let vol = Math.Round(annualVolatility(prices) * 100.0, 2)
56 | sprintf "Volatility for %s is %.2f %%" stock vol
57 |
58 | getAnnualizedVol "MSFT" "2013-01-01" "2013-08-29"
59 | // val it : string = "Volatility for MSFT is 21.30 %"
60 |
61 | getAnnualizedVol "ORCL" "2013-01-01" "2013-08-29"
62 | // val it : string = "Volatility for ORCL is 20.44 %"
63 |
64 | getAnnualizedVol "GOOG" "2013-01-01" "2013-08-29"
65 | // val it : string = "Volatility for GOOG is 14.80 %"
66 |
67 | getAnnualizedVol "EBAY" "2013-01-01" "2013-08-29"
68 | // val it : string = "Volatility for EBAY is 20.82 %"
69 |
70 | getAnnualizedVol "AAPL" "2013-01-01" "2013-08-29"
71 | // val it : string = "Volatility for AAPL is 25.16 %"
72 |
73 | getAnnualizedVol "AMZN" "2013-01-01" "2013-08-29"
74 | // val it : string = "Volatility for AMZN is 21.10 %"
75 |
76 | getAnnualizedVol "^GSPC" "2013-01-01" "2013-08-29"
77 | // val it : string = "Volatility for ^GSPC is 9.15 %"
--------------------------------------------------------------------------------
/Chapter05/Chapter5/Script1.fsx:
--------------------------------------------------------------------------------
1 | // Another example with Bollinger Bands
2 | #r "System.Windows.Forms.DataVisualization.dll"
3 |
4 | open System
5 | open System.Net
6 | open System.Windows.Forms
7 | open System.Windows.Forms.DataVisualization.Charting
8 | open Microsoft.FSharp.Control.WebExtensions
9 |
10 | // Create chart and form
11 | let chart = new Chart(Dock = DockStyle.Fill)
12 | let area = new ChartArea("Main")
13 | chart.ChartAreas.Add(area)
14 |
15 | // Add legends
16 | chart.Legends.Add(new Legend())
17 |
18 | let mainForm = new Form(Visible = true, TopMost = true,
19 | Width = 700, Height = 500)
20 |
21 | do mainForm.Text <- "Yahoo Finance data in F# - Bollinger Bands"
22 | mainForm.Controls.Add(chart)
23 |
24 | // Create serie for stock price
25 | let stockPrice = new Series("stockPrice")
26 | do stockPrice.ChartType <- SeriesChartType.Line
27 | do stockPrice.BorderWidth <- 2
28 | do stockPrice.Color <- Drawing.Color.DarkGray
29 | chart.Series.Add(stockPrice)
30 |
31 | // Create serie for moving average
32 | let movingAvg = new Series("movingAvg")
33 | do movingAvg.ChartType <- SeriesChartType.Line
34 | do movingAvg.BorderWidth <- 2
35 | do movingAvg.Color <- Drawing.Color.Blue
36 | chart.Series.Add(movingAvg)
37 |
38 | // Create serie for upper band
39 | let upperBand = new Series("upperBand")
40 | do upperBand.ChartType <- SeriesChartType.Line
41 | do upperBand.BorderWidth <- 2
42 | do upperBand.Color <- Drawing.Color.Red
43 | chart.Series.Add(upperBand)
44 |
45 | // Create serie for lower band
46 | let lowerBand = new Series("lowerBand")
47 | do lowerBand.ChartType <- SeriesChartType.Line
48 | do lowerBand.BorderWidth <- 2
49 | do lowerBand.Color <- Drawing.Color.Green
50 | chart.Series.Add(lowerBand)
51 |
52 | // Syncronous fetching (just one stock here)
53 | let fetchOne() =
54 | let uri = new System.Uri("http://ichart.finance.yahoo.com/table.csv?s=ORCL&d=9&e=23&f=2012&g=d&a=2&b=13&c=2012&ignore=.csv")
55 | let client = new WebClient()
56 | let html = client.DownloadString(uri)
57 | html
58 |
59 | // Parse CSV
60 | let getPrices() =
61 | let data = fetchOne()
62 | data.Split('\n')
63 | |> Seq.skip 1
64 | |> Seq.map (fun s -> s.Split(','))
65 | |> Seq.map (fun s -> float s.[4])
66 | |> Seq.truncate 2500
67 |
68 | // Calc moving average
69 | let movingAverage n (prices:seq) =
70 | prices
71 | |> Seq.windowed n
72 | |> Seq.map Array.sum
73 | |> Seq.map (fun a -> a / float n)
74 |
75 | // Stddev
76 | let stddev2(values:seq) =
77 | let avg = Seq.average values
78 | values
79 | |> Seq.fold (fun acc x -> acc + (1.0 / float (Seq.length values)) * (x - avg) ** 2.0) 0.0
80 | |> sqrt
81 |
82 | let movingStdDev n (prices:seq) =
83 | prices
84 | |> Seq.windowed n
85 | |> Seq.map stddev2
86 |
87 | // The plotting
88 | let sp = getPrices()
89 | do sp |> Seq.iter (stockPrice.Points.Add >> ignore)
90 |
91 | let ma = movingAverage 100 sp
92 | do ma |> Seq.iter (movingAvg.Points.Add >> ignore)
93 |
94 | // Bollinger bands, K = 2.0
95 | let ub = movingStdDev 100 sp
96 | // Upper
97 | Seq.zip ub ma |> Seq.map (fun (a,b) -> b + 2.0 * a) |> Seq.iter (upperBand.Points.Add >> ignore)
98 | // Lower
99 | Seq.zip ub ma |> Seq.map (fun (a,b) -> b - 2.0 * a) |> Seq.iter (lowerBand.Points.Add >> ignore)
--------------------------------------------------------------------------------
/Chapter04/Chapter4/Chapter4.fsproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | 2.0
8 | 7f1ad7e2-45c6-4685-a5f6-6a2ec8f92769
9 | Exe
10 | Chapter4
11 | Chapter4
12 | v4.5
13 | Chapter4
14 |
15 |
16 | true
17 | full
18 | false
19 | false
20 | bin\Debug\
21 | DEBUG;TRACE
22 | 3
23 | AnyCPU
24 | bin\Debug\Chapter4.XML
25 | true
26 |
27 |
28 | pdbonly
29 | true
30 | true
31 | bin\Release\
32 | TRACE
33 | 3
34 | AnyCPU
35 | bin\Release\Chapter4.XML
36 | true
37 |
38 |
39 |
40 |
41 | True
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 | 11
59 |
60 |
61 |
68 |
--------------------------------------------------------------------------------
/Chapter05/Chapter5/Chapter5.fsproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | 2.0
8 | 0f38272d-8bc4-4e8e-8168-083e60c0cbf7
9 | Exe
10 | Chapter5
11 | Chapter5
12 | v4.5
13 | Chapter5
14 |
15 |
16 | true
17 | full
18 | false
19 | false
20 | bin\Debug\
21 | DEBUG;TRACE
22 | 3
23 | AnyCPU
24 | bin\Debug\Chapter5.XML
25 | true
26 |
27 |
28 | pdbonly
29 | true
30 | true
31 | bin\Release\
32 | TRACE
33 | 3
34 | AnyCPU
35 | bin\Release\Chapter5.XML
36 | true
37 |
38 |
39 |
40 | ..\packages\MathNet.Numerics.2.6.1\lib\net40\MathNet.Numerics.dll
41 | True
42 |
43 |
44 | ..\packages\MathNet.Numerics.2.6.1\lib\net40\MathNet.Numerics.IO.dll
45 | True
46 |
47 |
48 |
49 | True
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 | 11
62 |
63 |
64 |
71 |
--------------------------------------------------------------------------------
/Chapter05/Chapter5/chapter5.fsx:
--------------------------------------------------------------------------------
1 | // FSChart
2 | #r @"System.Windows.Forms.DataVisualization.dll"
3 |
4 | open System
5 | open System.Net
6 | open FSharp.Charting
7 | open Microsoft.FSharp.Control.WebExtensions
8 | open System.Windows.Forms.DataVisualization.Charting
9 |
10 | module FSharpCharting =
11 | fsi.AddPrinter(fun (ch:FSharp.Charting.ChartTypes.GenericChart) -> ch.ShowChart(); "FSharpCharting")
12 |
13 | // Syncronous fetching (just one stock here)
14 | let fetchOne() =
15 | let uri = new System.Uri("http://ichart.finance.yahoo.com/table.csv?s=ORCL&d=9&e=23&f=2012&g=d&a=2&b=13&c=2012&ignore=.csv")
16 | let client = new WebClient()
17 | let html = client.DownloadString(uri)
18 | html
19 |
20 | // Parse CSV and re-arrange O,H,L,C - > H,L,O,C
21 | let getOHLCPrices() =
22 | let data = fetchOne()
23 | data.Split('\n')
24 | |> Seq.skip 1
25 | |> Seq.map (fun s -> s.Split(','))
26 | |> Seq.map (fun s -> s.[0], float s.[2], float s.[3], float s.[1], float s.[4])
27 | |> Seq.truncate 50
28 |
29 | // Candlestick chart price range specified
30 | let ohlcPrices = getOHLCPrices() |> Seq.toList
31 | Chart.Candlestick(ohlcPrices).WithYAxis(Max = 34.0, Min = 30.0)
32 |
33 | /// Histogram
34 | #r @"System.Windows.Forms.DataVisualization.dll"
35 | #r @"C:\Users\Niklas\Documents\Visual Studio 2012\Projects\Chapter5\packages\FSharp.Charting.0.87\lib\net40\FSharp.Charting.dll"
36 | #r @"C:\Users\Niklas\Documents\Visual Studio 2012\Projects\Chapter5\packages\MathNet.Numerics.2.6.1\lib\net40\MathNet.Numerics.dll"
37 |
38 | open System
39 | open MathNet.Numerics
40 | open MathNet.Numerics.Distributions
41 | open MathNet.Numerics.Statistics
42 | open FSharp.Charting
43 |
44 | module FSharpCharting2 =
45 | fsi.AddPrinter(fun (ch:FSharp.Charting.ChartTypes.GenericChart) -> ch.ShowChart(); "FSharpCharting")
46 |
47 | let dist = new Normal(0.0, 1.0)
48 | let samples = dist.Samples() |> Seq.take 10000 |> Seq.toList
49 | let histogram = new Histogram(samples, 35);
50 |
51 | let getValues =
52 | let bucketWidth = Math.Abs(histogram.LowerBound - histogram.UpperBound) / (float histogram.BucketCount)
53 | [0..(histogram.BucketCount-1)]
54 | |> Seq.map (fun i -> (histogram.Item(i).LowerBound + histogram.Item(i).UpperBound)/2.0, histogram.Item(i).Count)
55 |
56 | Chart.Column getValues
57 |
58 | //
59 | type Quote =
60 | {
61 | bid : float
62 | ask : float
63 | }
64 |
65 | let q1 : Quote = {bid = 100.0; ask = 200.0}
66 |
67 | let (didParse, value) = Int32.TryParse("123")
68 |
69 | let (bid, ask) = (100.0, 110.0)
70 | bid
71 | ask
72 |
73 | let (x, y, _) = (3.0, 2.0, 4.0)
74 |
75 | let (|RegexContains|_|) pattern input =
76 | let matches = System.Text.RegularExpressions.Regex.Matches(input, pattern)
77 | if matches.Count > 0 then Some [ for m in matches -> m.Value ]
78 | else None
79 |
80 | let testString = function
81 | | RegexContains "http://\S+" urls -> printfn "Got urls: %A" urls
82 | | RegexContains "[^@]@[^.]+\.\W+" emails -> printfn "Got email address: %A" emails
83 | | RegexContains "\d+" numbers -> printfn "Got numbers: %A" numbers
84 | | _ -> printfn "Didn't find anything."
85 |
86 | let (|RegexNumber|_|) input =
87 | let matches = System.Text.RegularExpressions.Regex.Matches(input, "\d+.\d+")
88 | if matches.Count > 0 then Some [ for m in matches -> m.Value ]
89 | else None
90 |
91 | let testNumbers = function
92 | | RegexNumber "1.21" -> printfn "Got urls: %A" 1
93 | | RegexNumber "not a number"
94 | | _ -> "nothing"
95 |
96 | let (|Integer|_|) str =
97 | match System.Int32.TryParse(str) with
98 | | (true, int) -> Some(int)
99 | | _ -> None
100 |
101 | let (|Double|_|) str =
102 | match System.Double.TryParse(str) with
103 | | (true, num) -> Some(num)
104 | | _ -> None
105 |
106 | let testNumbers a = function
107 | | Double a -> printfn "apa %A" a
108 | | Integer a -> printfn "apa %A" a
109 | | _ -> printfn "nothing"
110 |
111 | testNumbers "1.0"
112 | testNumbers "1"
113 |
114 | // create an active pattern
115 | let (|Integer|_|) str =
116 | match System.Int32.TryParse(str) with
117 | | (true,num) -> Some(num)
118 | | _ -> None
119 |
120 | // create an active pattern
121 | let (|Double|_|) str =
122 | match System.Double.TryParse(str) with
123 | | (true,num) -> Some(num)
124 | | _ -> None
125 |
126 | let testParse numberStr =
127 | match numberStr with
128 | | Integer num -> printfn "Parsed an integer '%A'" num
129 | | Double num -> printfn "Parsed a double '%A'" num
130 | | _ -> printfn "Couldn't parse string: %A" numberStr
131 |
132 | testParse "1.0"
133 | testParse "1"
--------------------------------------------------------------------------------
/Chapter03/Chapter3.fsx:
--------------------------------------------------------------------------------
1 | /// Linear regression using least squares
2 |
3 | open System
4 | open MathNet.Numerics
5 | open MathNet.Numerics.LinearAlgebra
6 | open MathNet.Numerics.LinearAlgebra.Double
7 | open MathNet.Numerics.Distributions
8 |
9 | let X = DenseMatrix.ofColumnsList 5 2 [ List.init 5 (fun i -> 1.0); [ 10.0; 20.0; 30.0; 40.0; 50.0 ] ]
10 | X
11 | let y = DenseVector [| 8.0; 21.0; 32.0; 40.0; 49.0 |]
12 | let p = X.QR().Solve(y)
13 |
14 | printfn "X: %A" X
15 | printfn "y: %s" (y.ToString())
16 | printfn "p: %s" (p.ToString())
17 |
18 | let (a, b) = (p.[0], p.[1])
19 |
20 |
21 | ///////////////////////// Statistics
22 |
23 | let random = new System.Random()
24 | let rnd() = random.NextDouble()
25 | let data = [for i in 1 .. 5 -> rnd() * 10.0]
26 |
27 | let avg = data |> Seq.average
28 | let sum = data |> Seq.sum
29 |
30 | let min = data |> Seq.min
31 | let max = data |> Seq.max
32 |
33 | ////
34 | let calcDailyReturns(prices:seq) =
35 | prices
36 | |> Seq.pairwise
37 | |> Seq.map (fun (x, y) -> log (x / y))
38 |
39 | let variance(values:seq) =
40 | values
41 | |> Seq.map (fun x -> (1.0 / float (Seq.length values)) * (x - (Seq.average values)) ** 2.0)
42 | |> Seq.sum
43 |
44 | variance [1.0 .. 6.0]
45 |
46 | let stddev1(values:seq) =
47 | sqrt(variance(values))
48 |
49 | let stddev2(values:seq) =
50 | values
51 | |> Seq.fold (fun acc x -> acc + (1.0 / float (Seq.length values)) * (x - (Seq.average values)) ** 2.0) 0.0
52 | |> sqrt
53 |
54 | stddev1 [2.0; 4.0; 4.0; 4.0; 5.0; 5.0; 7.0; 9.0]
55 | stddev2 [2.0; 4.0; 4.0; 4.0; 5.0; 5.0; 7.0; 9.0]
56 |
57 | let random = new System.Random()
58 | let rnd() = random.NextDouble()
59 | let data = [for i in 1 .. 100 -> rnd() * 10.0]
60 |
61 | let var = variance data
62 | let std = stddev2 data
63 |
64 |
65 | ///////////////////////// Regression with noisy data
66 |
67 | open System
68 | open MathNet.Numerics
69 | open MathNet.Numerics.LinearAlgebra
70 | open MathNet.Numerics.LinearAlgebra.Double
71 | open MathNet.Numerics.Distributions
72 |
73 | /// Define our target functions
74 | let f1 x = Math.Sqrt(Math.Exp(x))
75 | let f2 x = SpecialFunctions.DiGamma(x*x)
76 |
77 | /// Sample points
78 | let xdata = [ 1.0 .. 1.0 .. 10.0 ]
79 |
80 | /// Create data samples, with chosen parameters and with gaussian noise added
81 | let fy (noise:IContinuousDistribution) x = 2.5*f1(x) - 4.0*f2(x) + noise.Sample()
82 | let ydata = xdata |> List.map (fy (Normal.WithMeanVariance(0.0,2.0)))
83 |
84 | /// Build matrix form
85 | let X =
86 | [
87 | xdata |> List.map f1
88 | xdata |> List.map f2
89 | ] |> DenseMatrix.ofColumnsList 10 2
90 | let y = DenseVector.ofList ydata
91 |
92 | /// Solve
93 | let p = X.QR().Solve(y)
94 |
95 | printfn "X: %A" X
96 | printfn "y: %s" (y.ToString())
97 | printfn "p: %s" (p.ToString())
98 |
99 | (p.[0], p.[1])
100 |
101 | ///////////////////////// Implementing algorithms
102 |
103 | let rec bisect n N (f:float -> float) (a:float) (b:float) (t:float) : float =
104 | if n >= N then -1.0
105 | else
106 | let c = (a + b) / 2.0
107 | if f(c) = 0.0 || (b - a) / 2.0 < t then
108 | // Solution found
109 | c
110 | else
111 | if sign(f(c)) = sign(f(a)) then
112 | bisect (n + 1) N f c b t
113 | else
114 | bisect (n + 1) N f a c t
115 |
116 | let f = (fun x -> (x**2.0 - x - 6.0))
117 | f(-2.0)
118 | f(3.0)
119 |
120 | let first = bisect 0 25 f -10.0 0.0 0.01
121 | let second = bisect 0 25 f 0.0 10.0 0.01
122 |
123 | first;;
124 | second;;
125 |
126 | /// Secant methods (Updated version)
127 |
128 | let rec secant n N (f:float -> float) (x0:float) (x1:float) (x2:float) : float =
129 | if n >= N then x0
130 | else
131 | let x = x1 - (f(x1))*((x1 - x0)/(f(x1) - f(x0)))
132 | secant (n + 1) N f x x0 x2
133 |
134 | let f = (fun x -> (x**2.0 - 612.0))
135 |
136 | secant 0 10 f 0.0 10.0 30.0
137 |
138 | ///////////////////////// Statistics
139 |
140 | /// Helpers to generate random numbers
141 | let random = new Random()
142 | let rnd() = random.NextDouble()
143 | let data = [for i in 1 .. 500 -> rnd() * 10.0]
144 |
145 | /// Calculates the variance of a sequence
146 | let variance(values:seq) =
147 | values
148 | |> Seq.map (fun x -> (1.0 / float (Seq.length values)) * (x - (Seq.average values)) ** 2.0)
149 | |> Seq.sum
150 |
151 | /// Calculates the standard deviation of a sequence
152 | let stddev(values:seq) =
153 | values
154 | |> Seq.fold (fun acc x -> acc + (1.0 / float (Seq.length values)) * (x - (Seq.average values)) ** 2.0) 0.0
155 | |> sqrt
156 |
157 | let avg = data |> Seq.average
158 | let sum = data |> Seq.sum
159 | let min = data |> Seq.min
160 | let max = data |> Seq.max
161 | let var = data |> variance
162 | let std = data |> stddev
--------------------------------------------------------------------------------
/Chapter01/table.csv:
--------------------------------------------------------------------------------
1 | Date,Open,High,Low,Close,Volume,Adj Close
2 | 2013-06-06,51.15,51.66,50.83,51.52,9848400,51.52
3 | 2013-06-05,52.57,52.68,50.91,51.36,14462900,51.36
4 | 2013-06-04,53.74,53.75,52.22,52.59,10614700,52.59
5 | 2013-06-03,53.86,53.89,52.40,53.41,13127900,53.41
6 | 2013-05-31,54.70,54.91,53.99,54.10,12809700,54.10
7 | 2013-05-30,55.01,55.69,54.96,55.10,8751200,55.10
8 | 2013-05-29,55.15,55.40,54.53,55.05,8693700,55.05
9 | 2013-05-28,55.25,56.25,55.21,55.53,9747600,55.53
10 | 2013-05-24,53.80,54.65,53.57,54.64,7310000,54.64
11 | 2013-05-23,53.69,54.56,53.32,54.48,9468900,54.48
12 | 2013-05-22,55.32,55.82,54.13,54.40,11451600,54.40
13 | 2013-05-21,55.96,56.11,54.94,54.95,13019300,54.95
14 | 2013-05-20,56.56,56.66,55.76,55.95,8759600,55.95
15 | 2013-05-17,56.49,57.11,56.47,56.71,11558600,56.71
16 | 2013-05-16,56.80,56.90,55.72,55.80,8521500,55.80
17 | 2013-05-15,56.27,56.68,56.06,56.65,8568100,56.65
18 | 2013-05-14,55.15,56.41,55.14,56.27,9227100,56.27
19 | 2013-05-13,55.79,55.80,55.09,55.33,7220600,55.33
20 | 2013-05-10,55.39,55.82,55.21,55.65,7125400,55.65
21 | 2013-05-09,54.99,55.99,54.79,55.17,9298100,55.17
22 | 2013-05-08,54.01,54.98,53.77,54.96,7027500,54.96
23 | 2013-05-07,53.93,54.13,53.10,53.94,9680000,53.94
24 | 2013-05-06,54.06,54.82,53.76,54.09,6354000,54.09
25 | 2013-05-03,54.00,54.51,53.60,54.21,7207400,54.21
26 | 2013-05-02,52.42,53.70,52.03,53.55,9885100,53.55
27 | 2013-05-01,52.38,52.87,51.92,52.40,7917200,52.40
28 | 2013-04-30,52.67,53.14,52.13,52.39,9056900,52.39
29 | 2013-04-29,52.61,52.99,52.21,52.84,7171300,52.84
30 | 2013-04-26,52.40,52.86,51.89,52.54,10612400,52.54
31 | 2013-04-25,53.31,53.36,52.07,52.36,11477200,52.36
32 | 2013-04-24,53.00,53.33,52.64,52.97,10227600,52.97
33 | 2013-04-23,51.96,52.77,51.85,52.49,12678600,52.49
34 | 2013-04-22,52.14,52.32,51.16,51.63,13761200,51.63
35 | 2013-04-19,52.77,53.24,51.90,52.39,15600000,52.39
36 | 2013-04-18,53.85,54.24,52.73,52.82,25357100,52.82
37 | 2013-04-17,56.49,56.83,55.65,56.10,14684600,56.10
38 | 2013-04-16,56.19,57.15,56.00,57.01,8629600,57.01
39 | 2013-04-15,56.98,57.48,55.69,55.84,9197900,55.84
40 | 2013-04-12,57.90,57.90,56.81,57.31,6315400,57.31
41 | 2013-04-11,57.42,58.04,57.21,57.78,7291200,57.78
42 | 2013-04-10,56.33,57.58,56.28,57.30,8001300,57.30
43 | 2013-04-09,55.44,56.45,55.32,56.07,6264200,56.07
44 | 2013-04-08,55.42,56.84,55.29,55.87,10187600,55.87
45 | 2013-04-05,54.73,55.59,54.50,55.52,7236300,55.52
46 | 2013-04-04,55.34,55.87,55.10,55.79,5906800,55.79
47 | 2013-04-03,55.81,56.00,55.32,55.50,11496400,55.50
48 | 2013-04-02,56.26,56.79,55.95,56.16,15229100,56.16
49 | 2013-04-01,55.64,56.75,55.44,55.71,20619900,55.71
50 | 2013-03-28,52.04,54.51,51.45,54.22,24210600,54.22
51 | 2013-03-27,51.66,52.58,50.95,52.07,12416500,52.07
52 | 2013-03-26,51.67,52.14,51.10,52.09,10759300,52.09
53 | 2013-03-25,53.40,53.40,51.13,51.31,18177500,51.31
54 | 2013-03-22,53.01,53.46,52.96,53.27,8501200,53.27
55 | 2013-03-21,52.20,53.05,51.94,52.92,14056500,52.92
56 | 2013-03-20,51.67,52.61,51.05,52.42,14632700,52.42
57 | 2013-03-19,51.00,51.38,50.46,51.10,14623700,51.10
58 | 2013-03-18,49.86,50.55,49.55,50.11,14339000,50.11
59 | 2013-03-15,51.72,52.08,50.33,50.41,21767000,50.41
60 | 2013-03-14,51.79,52.90,51.60,51.80,17144800,51.80
61 | 2013-03-13,52.96,53.00,50.62,50.98,19805200,50.98
62 | 2013-03-12,51.70,53.10,50.90,52.96,16123900,52.96
63 | 2013-03-11,53.10,53.34,52.67,52.76,8965000,52.76
64 | 2013-03-08,53.18,53.46,52.26,53.13,13077000,53.13
65 | 2013-03-07,53.69,53.87,52.75,52.98,9450000,52.98
66 | 2013-03-06,54.98,55.00,53.44,53.57,14560300,53.57
67 | 2013-03-05,55.55,56.00,54.76,55.26,9812600,55.26
68 | 2013-03-04,54.34,55.49,54.25,55.48,9750900,55.48
69 | 2013-03-01,54.59,55.10,54.02,54.90,6422900,54.90
70 | 2013-02-28,54.50,55.18,54.26,54.71,9575500,54.71
71 | 2013-02-27,54.02,54.56,53.67,54.15,7662300,54.15
72 | 2013-02-26,53.77,53.97,53.12,53.82,8463000,53.82
73 | 2013-02-25,55.41,55.65,53.60,53.61,7336400,53.61
74 | 2013-02-22,54.96,55.13,54.57,55.02,5087300,55.02
75 | 2013-02-21,55.34,55.58,53.90,54.62,10728400,54.62
76 | 2013-02-20,56.90,57.10,55.48,55.53,7396000,55.53
77 | 2013-02-19,56.86,56.98,56.36,56.68,5702100,56.68
78 | 2013-02-15,56.81,57.15,56.41,56.70,9130200,56.70
79 | 2013-02-14,56.79,57.12,56.63,56.83,7054800,56.83
80 | 2013-02-13,56.86,57.26,56.41,57.05,9096000,57.05
81 | 2013-02-12,56.40,57.18,56.11,56.78,10023700,56.78
82 | 2013-02-11,56.52,56.58,55.75,56.41,5150900,56.41
83 | 2013-02-08,56.46,57.08,56.39,56.62,8066900,56.62
84 | 2013-02-07,56.17,56.39,55.35,56.13,7646600,56.13
85 | 2013-02-06,56.01,56.50,55.72,56.11,7003300,56.11
86 | 2013-02-05,56.03,56.87,55.80,56.42,6184900,56.42
87 | 2013-02-04,56.65,56.73,55.63,55.69,8659200,55.69
88 | 2013-02-01,56.41,57.27,56.13,57.21,8471400,57.21
89 | 2013-01-31,55.36,56.26,55.31,55.97,7946400,55.97
90 | 2013-01-30,55.98,56.50,55.52,55.78,6979300,55.78
91 | 2013-01-29,55.66,55.84,55.29,55.66,7037200,55.66
92 | 2013-01-28,56.19,56.34,55.73,55.95,7876400,55.95
93 | 2013-01-25,56.00,56.66,55.92,56.53,13330200,56.53
94 | 2013-01-24,53.58,55.34,53.57,55.19,12751200,55.19
95 | 2013-01-23,53.39,54.02,53.33,53.38,9036800,53.38
96 | 2013-01-22,54.15,54.32,53.06,53.37,10678200,53.37
97 | 2013-01-18,54.17,54.50,53.70,54.21,10558700,54.21
98 | 2013-01-17,54.13,54.88,53.75,54.17,24458600,54.17
99 | 2013-01-16,52.93,53.46,51.88,52.90,22253100,52.90
100 | 2013-01-15,53.19,53.46,52.36,52.51,9624400,52.51
101 | 2013-01-14,53.58,53.67,52.83,53.18,10600100,53.18
102 | 2013-01-11,53.14,53.83,53.06,53.70,11445200,53.70
103 | 2013-01-10,53.34,53.50,52.43,53.00,7331300,53.00
104 | 2013-01-09,52.82,53.42,52.45,52.76,8099900,52.76
105 | 2013-01-08,53.36,54.20,52.51,52.68,11528200,52.68
106 | 2013-01-07,52.53,53.58,52.06,53.51,10185600,53.51
107 | 2013-01-04,52.46,53.12,52.22,52.78,6486300,52.78
108 | 2013-01-03,53.49,53.65,52.15,52.45,10831400,52.45
109 | 2013-01-02,52.40,53.70,52.04,53.59,13798900,53.59
--------------------------------------------------------------------------------
/Chapter06/volsmile.fsx:
--------------------------------------------------------------------------------
1 | /// Black-Scholes implementation
2 |
3 | /// Helper function
4 | let pow x n = exp(n * log(x))
5 |
6 | /// Cumulative distribution function
7 | let cnd x =
8 | let a1 = 0.31938153
9 | let a2 = -0.356563782
10 | let a3 = 1.781477937
11 | let a4 = -1.821255978
12 | let a5 = 1.330274429
13 | let pi = 3.141592654
14 | let l = abs(x)
15 | let k = 1.0 / (1.0 + 0.2316419 * l)
16 | let w = ref (1.0-1.0/sqrt(2.0*pi)*exp(-l*l/2.0)*(a1*k+a2*k*k+a3*(pow k 3.0)+a4*(pow k 4.0)+a5*(pow k 5.0)))
17 | if (x < 0.0) then w := 1.0 - !w
18 | !w
19 |
20 | /// Black-Scholes
21 | // call_put_flag: 'c' if call option; otherwise put option
22 | // s: stock price
23 | // x: strike price of option
24 | // t: time to expiration in years
25 | // r: risk free interest rate
26 | // v: volatility
27 | let black_scholes call_put_flag s x t r v =
28 | let d1=(log(s / x) + (r+v*v*0.5)*t)/(v*sqrt(t))
29 | let d2=d1-v*sqrt(t)
30 | let res = ref 0.0
31 |
32 | if (call_put_flag = 'c') then
33 | res := s*cnd(d1)-x*exp(-r*t)*cnd(d2)
34 | else
35 | res := x*exp(-r*t)*cnd(-d2)-s*cnd(-d1)
36 | !res
37 |
38 | /// Convert the nr of days to years
39 | let days_to_years d =
40 | (float d) / 365.25
41 |
42 | #r @"C:\Users\Niklas\Documents\Visual Studio 2012\Projects\Chapter3\packages\MathNet.Numerics.FSharp.2.5.0\lib\net40\MathNet.Numerics.FSharp.dll"
43 | #r @"C:\Users\Niklas\Documents\Visual Studio 2012\Projects\Chapter5\packages\MathNet.Numerics.2.6.1\lib\net40\MathNet.Numerics.dll"
44 |
45 | open MathNet.Numerics.Distributions;
46 |
47 | /// Normal distribution
48 | let normd = new Normal(0.0, 1.0)
49 | normd.Density(100.0)
50 |
51 | type PutCallFlag = Put | Call
52 |
53 | /// Delta
54 | // call_put_flag: 'c' if call option; otherwise put option
55 | // s: stock price
56 | // x: strike price of option
57 | // t: time to expiration in years
58 | // r: risk free interest rate
59 | // v: volatility
60 | let black_scholes_delta call_put_flag s x t r v =
61 | let d1=(log(s / x) + (r+v*v*0.5)*t)/(v*sqrt(t))
62 | match call_put_flag with
63 | | Put -> cnd(d1) - 1.0
64 | | Call -> cnd(d1)
65 |
66 | /// Gamma
67 | // s: stock price
68 | // x: strike price of option
69 | // t: time to expiration in years
70 | // r: risk free interest rate
71 | // v: volatility
72 | let black_scholes_gamma s x t r v =
73 | let d1=(log(s / x) + (r+v*v*0.5)*t)/(v*sqrt(t))
74 | normd.Density(d1)
75 |
76 | /// Vega
77 | // s: stock price
78 | // x: strike price of option
79 | // t: time to expiration in years
80 | // r: risk free interest rate
81 | // v: volatility
82 | let black_scholes_vega s x t r v =
83 | let d1=(log(s / x) + (r+v*v*0.5)*t)/(v*sqrt(t))
84 | s*normd.Density(d1)*sqrt(t)
85 |
86 | /// Theta
87 | // call_put_flag: 'c' if call option; otherwise put option
88 | // s: stock price
89 | // x: strike price of option
90 | // t: time to expiration in years
91 | // r: risk free interest rate
92 | // v: volatility
93 | let black_scholes_theta call_put_flag s x t r v =
94 | let d1=(log(s / x) + (r+v*v*0.5)*t)/(v*sqrt(t))
95 | let d2=d1-v*sqrt(t)
96 | let res = ref 0.0
97 | match call_put_flag with
98 | | Put -> -(s*normd.Density(d1)*v)/(2.0*sqrt(t))+r*x*exp(-r*t)*cnd(-d2)
99 | | Call -> -(s*normd.Density(d1)*v)/(2.0*sqrt(t))-r*x*exp(-r*t)*cnd(d2)
100 |
101 | /// Rho
102 | // call_put_flag: 'c' if call option; otherwise put option
103 | // s: stock price
104 | // x: strike price of option
105 | // t: time to expiration in years
106 | // r: risk free interest rate
107 | // v: volatility
108 | let black_scholes_rho call_put_flag s x t r v =
109 | let d1=(log(s / x) + (r+v*v*0.5)*t)/(v*sqrt(t))
110 | let d2=d1-v*sqrt(t)
111 | let res = ref 0.0
112 | match call_put_flag with
113 | | Put -> -x*t*exp(-r*t)*cnd(-d2)
114 | | Call -> x*t*exp(-r*t)*cnd(d2)
115 |
116 |
117 | /// Plot delta of call option as function of underlying price
118 | #r "System.Windows.Forms.DataVisualization.dll"
119 |
120 | open System
121 | open System.Net
122 | open System.Windows.Forms
123 | open System.Windows.Forms.DataVisualization.Charting
124 | open Microsoft.FSharp.Control.WebExtensions
125 |
126 | /// Create chart and form
127 | let chart = new Chart(Dock = DockStyle.Fill)
128 | let area = new ChartArea("Main")
129 | chart.ChartAreas.Add(area)
130 | chart.Legends.Add(new Legend())
131 |
132 | let mainForm = new Form(Visible = true, TopMost = true,
133 | Width = 700, Height = 500)
134 |
135 | do mainForm.Text <- "Option delta as a function of underlying price"
136 | mainForm.Controls.Add(chart)
137 |
138 | /// Create serie for call option delta
139 | let optionDeltaCall = new Series("Call option delta")
140 | do optionDeltaCall.ChartType <- SeriesChartType.Line
141 | do optionDeltaCall.BorderWidth <- 2
142 | do optionDeltaCall.Color <- Drawing.Color.Red
143 | chart.Series.Add(optionDeltaCall)
144 |
145 | /// Create serie for call option gamma
146 | let optionGammaCall = new Series("Call option gamma")
147 | do optionGammaCall.ChartType <- SeriesChartType.Line
148 | do optionGammaCall.BorderWidth <- 2
149 | do optionGammaCall.Color <- Drawing.Color.Blue
150 | chart.Series.Add(optionGammaCall)
151 |
152 | /// Create serie for call option theta
153 | let optionThetaCall = new Series("Call option theta")
154 | do optionThetaCall.ChartType <- SeriesChartType.Line
155 | do optionThetaCall.BorderWidth <- 2
156 | do optionThetaCall.Color <- Drawing.Color.Green
157 | chart.Series.Add(optionThetaCall)
158 |
159 | /// Create serie for call option vega
160 | let optionVegaCall = new Series("Call option vega")
161 | do optionVegaCall.ChartType <- SeriesChartType.Line
162 | do optionVegaCall.BorderWidth <- 2
163 | do optionVegaCall.Color <- Drawing.Color.Purple
164 | chart.Series.Add(optionVegaCall)
165 |
166 | /// Calculate and plot call delta
167 | let opd = [for x in [10.0..1.0..70.0] do yield black_scholes_delta Call x 60.0 0.5 0.01 0.3]
168 | do opd |> Seq.iter (optionDeltaCall.Points.Add >> ignore)
169 |
170 | /// Calculate and plot call gamma
171 | let opg = [for x in [10.0..1.0..70.0] do yield black_scholes_gamma x 60.0 0.5 0.01 0.3]
172 | do opg |> Seq.iter (optionGammaCall.Points.Add >> ignore)
173 |
174 | /// Calculate and plot call theta
175 | let opt = [for x in [10.0..1.0..70.0] do yield black_scholes_theta Call x 60.0 0.5 0.01 0.3]
176 | do opt |> Seq.iter (optionThetaCall.Points.Add >> ignore)
177 |
178 | /// Calculate and plot call vega
179 | let opv = [for x in [10.0..1.0..70.0] do yield black_scholes_vega x 60.0 0.1 0.01 0.3]
180 | do opv |> Seq.iter (optionVegaCall.Points.Add >> ignore)
181 |
--------------------------------------------------------------------------------
/Chapter06/smile_data.csv:
--------------------------------------------------------------------------------
1 | ERICB3L100,2013-12-20,100,28.5
2 | ERICB3L34,2013-12-20,34,138.6
3 | ERICB3L38,2013-12-20,38,122.3
4 | ERICB3L42,2013-12-20,42,107.6
5 | ERICB3L46,2013-12-20,46,94.3
6 | ERICB3L50,2013-12-20,50,82.1
7 | ERICB3L62.50,2013-12-20,62.5,49.1
8 | ERICB3L65,2013-12-20,65,43.2
9 | ERICB3L67.50,2013-12-20,67.5,37.5
10 | ERICB3L75,2013-12-20,75,24.8
11 | ERICB3L80,2013-12-20,80,20.9
12 | ERICB3L85,2013-12-20,85,19.6
13 | ERICB3L90,2013-12-20,90,21.2
14 | ERICB3L95,2013-12-20,95,23.1
15 | ERICB3X100,2013-12-20,100,34.1
16 | ERICB3X105,2013-12-20,105,33
17 | ERICB3X110,2013-12-20,110,39.1
18 | ERICB3X115,2013-12-20,115,60
19 | ERICB3X120,2013-12-20,120,66.3
20 | ERICB3X130,2013-12-20,130,77.8
21 | ERICB3X140,2013-12-20,140,81.5
22 | ERICB3X50,2013-12-20,50,76.2
23 | ERICB3X60,2013-12-20,60,51.5
24 | ERICB3X62.50,2013-12-20,62.5,40
25 | ERICB3X65,2013-12-20,65,37.6
26 | ERICB3X67.50,2013-12-20,67.5,33
27 | ERICB3X70,2013-12-20,70,30.7
28 | ERICB3X75,2013-12-20,75,23
29 | ERICB3X80,2013-12-20,80,20.2
30 | ERICB3X85,2013-12-20,85,19
31 | ERICB3X90,2013-12-20,90,22.6
32 | ERICB3X95,2013-12-20,95,19.7
33 | ERICB4A100,2014-01-17,100,22.7
34 | ERICB4A105,2014-01-17,105,27.3
35 | ERICB4A110,2014-01-17,110,41.2
36 | ERICB4A115,2014-01-17,115,33.8
37 | ERICB4A120,2014-01-17,120,50.8
38 | ERICB4A34,2014-01-17,34,100.7
39 | ERICB4A38,2014-01-17,38,88.5
40 | ERICB4A42,2014-01-17,42,77.6
41 | ERICB4A46,2014-01-17,46,67.6
42 | ERICB4A50,2014-01-17,50,58.6
43 | ERICB4A62.50,2014-01-17,62.5,34.2
44 | ERICB4A65,2014-01-17,65,35.5
45 | ERICB4A75,2014-01-17,75,21.9
46 | ERICB4A80,2014-01-17,80,20.6
47 | ERICB4A85,2014-01-17,85,19.1
48 | ERICB4A90,2014-01-17,90,19.4
49 | ERICB4A95,2014-01-17,95,21
50 | ERICB4B100,2014-02-21,100,23
51 | ERICB4B105,2014-02-21,105,23.6
52 | ERICB4B62.50,2014-02-21,62.5,34.3
53 | ERICB4B65,2014-02-21,65,30.3
54 | ERICB4B67.50,2014-02-21,67.5,30.9
55 | ERICB4B70,2014-02-21,70,26.7
56 | ERICB4B75,2014-02-21,75,25.6
57 | ERICB4B80,2014-02-21,80,23.5
58 | ERICB4B85,2014-02-21,85,22.6
59 | ERICB4B90,2014-02-21,90,22.3
60 | ERICB4B95,2014-02-21,95,22.4
61 | ERICB4C100,2014-03-21,100,22.3
62 | ERICB4C105,2014-03-21,105,22.9
63 | ERICB4C110,2014-03-21,110,30.6
64 | ERICB4C115,2014-03-21,115,34.2
65 | ERICB4C120,2014-03-21,120,28.1
66 | ERICB4C130,2014-03-21,130,33.2
67 | ERICB4C140,2014-03-21,140,37.8
68 | ERICB4C38,2014-03-21,38,77.8
69 | ERICB4C42,2014-03-21,42,49.1
70 | ERICB4C46,2014-03-21,46,41.6
71 | ERICB4C60,2014-03-21,60,32.9
72 | ERICB4C62.50,2014-03-21,62.5,25.6
73 | ERICB4C65,2014-03-21,65,28.3
74 | ERICB4C67.50,2014-03-21,67.5,26.7
75 | ERICB4C70,2014-03-21,70,26
76 | ERICB4C75,2014-03-21,75,25
77 | ERICB4C80,2014-03-21,80,23.3
78 | ERICB4C85,2014-03-21,85,22.4
79 | ERICB4C90,2014-03-21,90,22
80 | ERICB4C95,2014-03-21,95,22
81 | ERICB4F100,2014-06-19,100,20.7
82 | ERICB4F110,2014-06-19,110,24.2
83 | ERICB4F120,2014-06-19,120,22.4
84 | ERICB4F130,2014-06-19,130,25.3
85 | ERICB4F140,2014-06-19,140,27.5
86 | ERICB4F38,2014-06-19,38,47.1
87 | ERICB4F42,2014-06-19,42,40.3
88 | ERICB4F46,2014-06-19,46,34.1
89 | ERICB4F50,2014-06-19,50,28.3
90 | ERICB4F60,2014-06-19,60,25.2
91 | ERICB4F70,2014-06-19,70,21.8
92 | ERICB4F80,2014-06-19,80,21
93 | ERICB4F85,2014-06-19,85,20.5
94 | ERICB4F90,2014-06-19,90,20.5
95 | ERICB4I100,2014-09-19,100,21
96 | ERICB4I110,2014-09-19,110,21.3
97 | ERICB4I120,2014-09-19,120,22.3
98 | ERICB4I130,2014-09-19,130,23.1
99 | ERICB4I60,2014-09-19,60,21.1
100 | ERICB4I70,2014-09-19,70,20.5
101 | ERICB4I80,2014-09-19,80,20.8
102 | ERICB4I90,2014-09-19,90,20.3
103 | ERICB4L100,2014-12-19,100,21.3
104 | ERICB4L110,2014-12-19,110,21.7
105 | ERICB4L120,2014-12-19,120,22.1
106 | ERICB4L130,2014-12-19,130,23.1
107 | ERICB4L90,2014-12-19,90,21.2
108 | ERICB4M100,2014-01-17,100,23.3
109 | ERICB4M105,2014-01-17,105,28.6
110 | ERICB4M110,2014-01-17,110,41.4
111 | ERICB4M115,2014-01-17,115,46.6
112 | ERICB4M120,2014-01-17,120,51.5
113 | ERICB4M130,2014-01-17,130,60.5
114 | ERICB4M140,2014-01-17,140,68.6
115 | ERICB4M50,2014-01-17,50,56.7
116 | ERICB4M60,2014-01-17,60,36.3
117 | ERICB4M62.50,2014-01-17,62.5,37
118 | ERICB4M65,2014-01-17,65,28.8
119 | ERICB4M67.50,2014-01-17,67.5,26.9
120 | ERICB4M70,2014-01-17,70,24.3
121 | ERICB4M75,2014-01-17,75,21.3
122 | ERICB4M80,2014-01-17,80,19.3
123 | ERICB4M85,2014-01-17,85,18.4
124 | ERICB4M90,2014-01-17,90,18.9
125 | ERICB4M95,2014-01-17,95,23.3
126 | ERICB4N100,2014-02-21,100,23.2
127 | ERICB4N105,2014-02-21,105,28
128 | ERICB4N62.50,2014-02-21,62.5,30.6
129 | ERICB4N65,2014-02-21,65,28.4
130 | ERICB4N67.50,2014-02-21,67.5,26.5
131 | ERICB4N70,2014-02-21,70,25.8
132 | ERICB4N75,2014-02-21,75,24.1
133 | ERICB4N80,2014-02-21,80,22.6
134 | ERICB4N85,2014-02-21,85,21.8
135 | ERICB4N90,2014-02-21,90,21.5
136 | ERICB4N95,2014-02-21,95,21.1
137 | ERICB4O100,2014-03-21,100,21.3
138 | ERICB4O105,2014-03-21,105,25.7
139 | ERICB4O110,2014-03-21,110,27.6
140 | ERICB4O115,2014-03-21,115,33.6
141 | ERICB4O120,2014-03-21,120,37.2
142 | ERICB4O130,2014-03-21,130,44
143 | ERICB4O140,2014-03-21,140,50.1
144 | ERICB4O46,2014-03-21,46,49.4
145 | ERICB4O50,2014-03-21,50,43.2
146 | ERICB4O60,2014-03-21,60,30.6
147 | ERICB4O62.50,2014-03-21,62.5,28.2
148 | ERICB4O65,2014-03-21,65,27.3
149 | ERICB4O67.50,2014-03-21,67.5,26
150 | ERICB4O70,2014-03-21,70,25
151 | ERICB4O75,2014-03-21,75,23.7
152 | ERICB4O80,2014-03-21,80,22.7
153 | ERICB4O85,2014-03-21,85,21.9
154 | ERICB4O90,2014-03-21,90,20.8
155 | ERICB4O95,2014-03-21,95,21.3
156 | ERICB4R100,2014-06-19,100,34
157 | ERICB4R110,2014-06-19,110,40.2
158 | ERICB4R120,2014-06-19,120,46.1
159 | ERICB4R130,2014-06-19,130,51.7
160 | ERICB4R140,2014-06-19,140,55.8
161 | ERICB4R38,2014-06-19,38,60.1
162 | ERICB4R42,2014-06-19,42,53.3
163 | ERICB4R46,2014-06-19,46,47.1
164 | ERICB4R50,2014-06-19,50,41.6
165 | ERICB4R60,2014-06-19,60,29.4
166 | ERICB4R70,2014-06-19,70,27.7
167 | ERICB4R80,2014-06-19,80,27.7
168 | ERICB4R90,2014-06-19,90,29.5
169 | ERICB4U100,2014-09-19,100,30
170 | ERICB4U110,2014-09-19,110,35.6
171 | ERICB4U120,2014-09-19,120,40.8
172 | ERICB4U130,2014-09-19,130,45.2
173 | ERICB4U140,2014-09-19,140,50.1
174 | ERICB4U42,2014-09-19,42,35
175 | ERICB4U46,2014-09-19,46,33.9
176 | ERICB4U50,2014-09-19,50,32.1
177 | ERICB4U60,2014-09-19,60,29.6
178 | ERICB4U70,2014-09-19,70,28
179 | ERICB4U80,2014-09-19,80,27.8
180 | ERICB4U90,2014-09-19,90,28.1
181 | ERICB4X42,2014-12-19,42,34.4
182 | ERICB4X46,2014-12-19,46,33.1
183 | ERICB4X50,2014-12-19,50,32
184 | ERICB4X60,2014-12-19,60,29.3
185 | ERICB4X70,2014-12-19,70,27.8
186 | ERICB4X80,2014-12-19,80,27.3
187 | ERICB5A100,2015-01-16,100,21
188 | ERICB5A110,2015-01-16,110,21.3
189 | ERICB5A120,2015-01-16,120,21.7
190 | ERICB5A130,2015-01-16,130,22.3
191 | ERICB5A140,2015-01-16,140,23.3
192 | ERICB5A90,2015-01-16,90,20.5
193 | ERICB5M38,2015-01-16,38,35.7
194 | ERICB5M42,2015-01-16,42,33.5
195 | ERICB5M46,2015-01-16,46,32
196 | ERICB5M50,2015-01-16,50,31.2
197 | ERICB5M60,2015-01-16,60,29
198 | ERICB5M70,2015-01-16,70,27.8
199 | ERICB5M80,2015-01-16,80,26.5
--------------------------------------------------------------------------------
/Chapter09/smile_data.csv:
--------------------------------------------------------------------------------
1 | ERICB3L100,2013-12-20,100,28.5
2 | ERICB3L34,2013-12-20,34,138.6
3 | ERICB3L38,2013-12-20,38,122.3
4 | ERICB3L42,2013-12-20,42,107.6
5 | ERICB3L46,2013-12-20,46,94.3
6 | ERICB3L50,2013-12-20,50,82.1
7 | ERICB3L62.50,2013-12-20,62.5,49.1
8 | ERICB3L65,2013-12-20,65,43.2
9 | ERICB3L67.50,2013-12-20,67.5,37.5
10 | ERICB3L75,2013-12-20,75,24.8
11 | ERICB3L80,2013-12-20,80,20.9
12 | ERICB3L85,2013-12-20,85,19.6
13 | ERICB3L90,2013-12-20,90,21.2
14 | ERICB3L95,2013-12-20,95,23.1
15 | ERICB3X100,2013-12-20,100,34.1
16 | ERICB3X105,2013-12-20,105,33
17 | ERICB3X110,2013-12-20,110,39.1
18 | ERICB3X115,2013-12-20,115,60
19 | ERICB3X120,2013-12-20,120,66.3
20 | ERICB3X130,2013-12-20,130,77.8
21 | ERICB3X140,2013-12-20,140,81.5
22 | ERICB3X50,2013-12-20,50,76.2
23 | ERICB3X60,2013-12-20,60,51.5
24 | ERICB3X62.50,2013-12-20,62.5,40
25 | ERICB3X65,2013-12-20,65,37.6
26 | ERICB3X67.50,2013-12-20,67.5,33
27 | ERICB3X70,2013-12-20,70,30.7
28 | ERICB3X75,2013-12-20,75,23
29 | ERICB3X80,2013-12-20,80,20.2
30 | ERICB3X85,2013-12-20,85,19
31 | ERICB3X90,2013-12-20,90,22.6
32 | ERICB3X95,2013-12-20,95,19.7
33 | ERICB4A100,2014-01-17,100,22.7
34 | ERICB4A105,2014-01-17,105,27.3
35 | ERICB4A110,2014-01-17,110,41.2
36 | ERICB4A115,2014-01-17,115,33.8
37 | ERICB4A120,2014-01-17,120,50.8
38 | ERICB4A34,2014-01-17,34,100.7
39 | ERICB4A38,2014-01-17,38,88.5
40 | ERICB4A42,2014-01-17,42,77.6
41 | ERICB4A46,2014-01-17,46,67.6
42 | ERICB4A50,2014-01-17,50,58.6
43 | ERICB4A62.50,2014-01-17,62.5,34.2
44 | ERICB4A65,2014-01-17,65,35.5
45 | ERICB4A75,2014-01-17,75,21.9
46 | ERICB4A80,2014-01-17,80,20.6
47 | ERICB4A85,2014-01-17,85,19.1
48 | ERICB4A90,2014-01-17,90,19.4
49 | ERICB4A95,2014-01-17,95,21
50 | ERICB4B100,2014-02-21,100,23
51 | ERICB4B105,2014-02-21,105,23.6
52 | ERICB4B62.50,2014-02-21,62.5,34.3
53 | ERICB4B65,2014-02-21,65,30.3
54 | ERICB4B67.50,2014-02-21,67.5,30.9
55 | ERICB4B70,2014-02-21,70,26.7
56 | ERICB4B75,2014-02-21,75,25.6
57 | ERICB4B80,2014-02-21,80,23.5
58 | ERICB4B85,2014-02-21,85,22.6
59 | ERICB4B90,2014-02-21,90,22.3
60 | ERICB4B95,2014-02-21,95,22.4
61 | ERICB4C100,2014-03-21,100,22.3
62 | ERICB4C105,2014-03-21,105,22.9
63 | ERICB4C110,2014-03-21,110,30.6
64 | ERICB4C115,2014-03-21,115,34.2
65 | ERICB4C120,2014-03-21,120,28.1
66 | ERICB4C130,2014-03-21,130,33.2
67 | ERICB4C140,2014-03-21,140,37.8
68 | ERICB4C38,2014-03-21,38,77.8
69 | ERICB4C42,2014-03-21,42,49.1
70 | ERICB4C46,2014-03-21,46,41.6
71 | ERICB4C60,2014-03-21,60,32.9
72 | ERICB4C62.50,2014-03-21,62.5,25.6
73 | ERICB4C65,2014-03-21,65,28.3
74 | ERICB4C67.50,2014-03-21,67.5,26.7
75 | ERICB4C70,2014-03-21,70,26
76 | ERICB4C75,2014-03-21,75,25
77 | ERICB4C80,2014-03-21,80,23.3
78 | ERICB4C85,2014-03-21,85,22.4
79 | ERICB4C90,2014-03-21,90,22
80 | ERICB4C95,2014-03-21,95,22
81 | ERICB4F100,2014-06-19,100,20.7
82 | ERICB4F110,2014-06-19,110,24.2
83 | ERICB4F120,2014-06-19,120,22.4
84 | ERICB4F130,2014-06-19,130,25.3
85 | ERICB4F140,2014-06-19,140,27.5
86 | ERICB4F38,2014-06-19,38,47.1
87 | ERICB4F42,2014-06-19,42,40.3
88 | ERICB4F46,2014-06-19,46,34.1
89 | ERICB4F50,2014-06-19,50,28.3
90 | ERICB4F60,2014-06-19,60,25.2
91 | ERICB4F70,2014-06-19,70,21.8
92 | ERICB4F80,2014-06-19,80,21
93 | ERICB4F85,2014-06-19,85,20.5
94 | ERICB4F90,2014-06-19,90,20.5
95 | ERICB4I100,2014-09-19,100,21
96 | ERICB4I110,2014-09-19,110,21.3
97 | ERICB4I120,2014-09-19,120,22.3
98 | ERICB4I130,2014-09-19,130,23.1
99 | ERICB4I60,2014-09-19,60,21.1
100 | ERICB4I70,2014-09-19,70,20.5
101 | ERICB4I80,2014-09-19,80,20.8
102 | ERICB4I90,2014-09-19,90,20.3
103 | ERICB4L100,2014-12-19,100,21.3
104 | ERICB4L110,2014-12-19,110,21.7
105 | ERICB4L120,2014-12-19,120,22.1
106 | ERICB4L130,2014-12-19,130,23.1
107 | ERICB4L90,2014-12-19,90,21.2
108 | ERICB4M100,2014-01-17,100,23.3
109 | ERICB4M105,2014-01-17,105,28.6
110 | ERICB4M110,2014-01-17,110,41.4
111 | ERICB4M115,2014-01-17,115,46.6
112 | ERICB4M120,2014-01-17,120,51.5
113 | ERICB4M130,2014-01-17,130,60.5
114 | ERICB4M140,2014-01-17,140,68.6
115 | ERICB4M50,2014-01-17,50,56.7
116 | ERICB4M60,2014-01-17,60,36.3
117 | ERICB4M62.50,2014-01-17,62.5,37
118 | ERICB4M65,2014-01-17,65,28.8
119 | ERICB4M67.50,2014-01-17,67.5,26.9
120 | ERICB4M70,2014-01-17,70,24.3
121 | ERICB4M75,2014-01-17,75,21.3
122 | ERICB4M80,2014-01-17,80,19.3
123 | ERICB4M85,2014-01-17,85,18.4
124 | ERICB4M90,2014-01-17,90,18.9
125 | ERICB4M95,2014-01-17,95,23.3
126 | ERICB4N100,2014-02-21,100,23.2
127 | ERICB4N105,2014-02-21,105,28
128 | ERICB4N62.50,2014-02-21,62.5,30.6
129 | ERICB4N65,2014-02-21,65,28.4
130 | ERICB4N67.50,2014-02-21,67.5,26.5
131 | ERICB4N70,2014-02-21,70,25.8
132 | ERICB4N75,2014-02-21,75,24.1
133 | ERICB4N80,2014-02-21,80,22.6
134 | ERICB4N85,2014-02-21,85,21.8
135 | ERICB4N90,2014-02-21,90,21.5
136 | ERICB4N95,2014-02-21,95,21.1
137 | ERICB4O100,2014-03-21,100,21.3
138 | ERICB4O105,2014-03-21,105,25.7
139 | ERICB4O110,2014-03-21,110,27.6
140 | ERICB4O115,2014-03-21,115,33.6
141 | ERICB4O120,2014-03-21,120,37.2
142 | ERICB4O130,2014-03-21,130,44
143 | ERICB4O140,2014-03-21,140,50.1
144 | ERICB4O46,2014-03-21,46,49.4
145 | ERICB4O50,2014-03-21,50,43.2
146 | ERICB4O60,2014-03-21,60,30.6
147 | ERICB4O62.50,2014-03-21,62.5,28.2
148 | ERICB4O65,2014-03-21,65,27.3
149 | ERICB4O67.50,2014-03-21,67.5,26
150 | ERICB4O70,2014-03-21,70,25
151 | ERICB4O75,2014-03-21,75,23.7
152 | ERICB4O80,2014-03-21,80,22.7
153 | ERICB4O85,2014-03-21,85,21.9
154 | ERICB4O90,2014-03-21,90,20.8
155 | ERICB4O95,2014-03-21,95,21.3
156 | ERICB4R100,2014-06-19,100,34
157 | ERICB4R110,2014-06-19,110,40.2
158 | ERICB4R120,2014-06-19,120,46.1
159 | ERICB4R130,2014-06-19,130,51.7
160 | ERICB4R140,2014-06-19,140,55.8
161 | ERICB4R38,2014-06-19,38,60.1
162 | ERICB4R42,2014-06-19,42,53.3
163 | ERICB4R46,2014-06-19,46,47.1
164 | ERICB4R50,2014-06-19,50,41.6
165 | ERICB4R60,2014-06-19,60,29.4
166 | ERICB4R70,2014-06-19,70,27.7
167 | ERICB4R80,2014-06-19,80,27.7
168 | ERICB4R90,2014-06-19,90,29.5
169 | ERICB4U100,2014-09-19,100,30
170 | ERICB4U110,2014-09-19,110,35.6
171 | ERICB4U120,2014-09-19,120,40.8
172 | ERICB4U130,2014-09-19,130,45.2
173 | ERICB4U140,2014-09-19,140,50.1
174 | ERICB4U42,2014-09-19,42,35
175 | ERICB4U46,2014-09-19,46,33.9
176 | ERICB4U50,2014-09-19,50,32.1
177 | ERICB4U60,2014-09-19,60,29.6
178 | ERICB4U70,2014-09-19,70,28
179 | ERICB4U80,2014-09-19,80,27.8
180 | ERICB4U90,2014-09-19,90,28.1
181 | ERICB4X42,2014-12-19,42,34.4
182 | ERICB4X46,2014-12-19,46,33.1
183 | ERICB4X50,2014-12-19,50,32
184 | ERICB4X60,2014-12-19,60,29.3
185 | ERICB4X70,2014-12-19,70,27.8
186 | ERICB4X80,2014-12-19,80,27.3
187 | ERICB5A100,2015-01-16,100,21
188 | ERICB5A110,2015-01-16,110,21.3
189 | ERICB5A120,2015-01-16,120,21.7
190 | ERICB5A130,2015-01-16,130,22.3
191 | ERICB5A140,2015-01-16,140,23.3
192 | ERICB5A90,2015-01-16,90,20.5
193 | ERICB5M38,2015-01-16,38,35.7
194 | ERICB5M42,2015-01-16,42,33.5
195 | ERICB5M46,2015-01-16,46,32
196 | ERICB5M50,2015-01-16,50,31.2
197 | ERICB5M60,2015-01-16,60,29
198 | ERICB5M70,2015-01-16,70,27.8
199 | ERICB5M80,2015-01-16,80,26.5
--------------------------------------------------------------------------------
/Chapter07/OrderType.fsx:
--------------------------------------------------------------------------------
1 |
2 | /// Order side
3 | type OrderSide =
4 | Buy | Sell | Sellshort
5 |
6 | /// Order type
7 | type OrderType =
8 | Market | Limit | Stop | StopLimit
9 |
10 | /// Order status, according to FIX standard 4.2
11 | type OrderStatus =
12 | Created | New | Filled | PartiallyFilled | DoneForDay | Cancelled | Replaced | PendingCancel | Stopped | Rejected | Suspended | PendingNew | Calculated | Expired
13 |
14 | /// Time in force
15 | type Tif =
16 | GoodForDay | GoodTilCancelled | ImmediateOrCancel | FillorKill
17 |
18 | /// Order class
19 | type Order(side: OrderSide, t: OrderType, p: float, tif: Tif, q: int, i: string, sp: float) =
20 | // Init order with status created
21 | let mutable St = OrderStatus.Created
22 | let mutable S = side
23 | member private this.Ts = System.DateTime.Now
24 | member private this.T = t
25 | member private this.P = p
26 | member private this.tif = tif
27 | member private this.Q = q
28 | member private this.I = i
29 | member private this.Sp = sp
30 |
31 | member this.Status
32 | with get() = St
33 | and set(st) = St <- st
34 |
35 | member this.Side
36 | with get() = S
37 | and set(s) = S <- s
38 |
39 | member this.Timestamp
40 | with get() = this.Ts
41 |
42 | member this.Type
43 | with get() = this.T
44 |
45 | member this.Qty
46 | with get() = this.Q
47 |
48 | member this.Price
49 | with get() = this.P
50 |
51 | member this.Tif
52 | with get() = this.tif
53 |
54 | member this.Instrument
55 | with get() = this.I
56 |
57 | member this.StopPrice
58 | with get() = this.Sp
59 |
60 | member this.toggleOrderSide() =
61 | S <- this.toggleOrderSide(S)
62 |
63 | member private this.toggleOrderSide(s: OrderSide) =
64 | match s with
65 | | Buy -> Sell
66 | | Sell -> Buy
67 | | Sellshort -> Sellshort
68 |
69 | static member (~-) (o : Order) =
70 | Order(o.toggleOrderSide(o.Side), o.Type, o.Price, o.tif, o.Q, o.I, o.Sp)
71 |
72 | /// Validation result, ok or failed with message
73 | type Result = Valid of Order | Error of string
74 |
75 | /// Validates an order for illustrative purposes
76 | let validateOrder (result:Result) : Result =
77 | match result with
78 | | Error s -> Error s
79 | | Valid order ->
80 | let orderType = order.Type
81 | let orderPrice = order.Price
82 | let stopPrice = order.StopPrice
83 | match orderType with
84 | | OrderType.Limit ->
85 | match orderPrice with
86 | | p when p > 0.0 -> Valid order
87 | | _ -> Error "Limit orders must have a price > 0"
88 | | OrderType.Market -> Valid order
89 | | OrderType.Stop ->
90 | match stopPrice with
91 | | p when p > 0.0 -> Valid order
92 | | _ -> Error "Stop orders must have price > 0"
93 | | OrderType.StopLimit ->
94 | match stopPrice with
95 | | p when p > 0.0 && orderPrice > 0.0 -> Valid order
96 | | _ -> Error "Stop limit orders must both price > 0 and stop price > 0"
97 |
98 | // Limit buy order
99 | let buyOrder = Order(OrderSide.Buy, OrderType.Limit, 54.50, Tif.FillorKill, 100, "MSFT", 0.0)
100 |
101 | // Limit buy order, no price
102 | let buyOrderNoPrice = Order(OrderSide.Buy, OrderType.Limit, 0.0, Tif.FillorKill, 100, "MSFT", 0.0)
103 |
104 | // Stop order that will be converted to limit order, no limit price
105 | let stopLimitNoPrice = Order(OrderSide.Buy, OrderType.StopLimit, 0.0, Tif.FillorKill, 100, "MSFT", 45.50)
106 |
107 | // Stop order that will be converted to market order
108 | let stopNoPrice = Order(OrderSide.Buy, OrderType.Stop, 0.0, Tif.FillorKill, 100, "MSFT", 45.50)
109 |
110 | // Stop order that will be converted to market order
111 | let stopNoPriceNoInstrument = Order(OrderSide.Buy, OrderType.Stop, 0.0, Tif.FillorKill, 100, "", 45.50)
112 |
113 | let buyOrderExceetsPreTradeRisk = Order(OrderSide.Sell, OrderType.Limit, 26.50, Tif.GoodForDay, 1000, "MSFT", 0.0)
114 | let buyOrderBelowPricePreTradeRisk = Order(OrderSide.Sell, OrderType.Limit, 26.50, Tif.GoodForDay, 500, "MSFT", 0.0)
115 |
116 | // Validate sample orders
117 | validateOrder (Valid buyOrder) // Ok
118 | validateOrder (Valid buyOrderNoPrice) // Failed
119 | validateOrder (Valid stopLimitNoPrice) // Failed
120 | validateOrder (Valid stopNoPrice) // Ok
121 |
122 | /// Modify above to work with function composition
123 |
124 | let validateInstrument (result:Result) : Result =
125 | match result with
126 | | Error l -> Error l
127 | | Valid order ->
128 | let orderInstrument = order.Instrument
129 | match orderInstrument.Length with
130 | | l when l > 0 -> Valid order
131 | | _ -> Error "Must specify order Instrument"
132 |
133 |
134 | validateInstrument (Valid stopNoPriceNoInstrument)
135 |
136 | // Add check for specified Instrument
137 | let validateOrderAndInstrument = validateOrder >> validateInstrument
138 |
139 | validateOrderAndInstrument (Valid stopNoPriceNoInstrument)
140 |
141 | let orderValueMax = 25000.0; // Order value max of $25,000
142 |
143 | /// Add simple pre trade risk
144 | let preTradeRiskRuleOne (result:Result) : Result =
145 | match result with
146 | | Error l -> Error l
147 | | Valid order ->
148 | let orderValue = (float order.Qty) * order.Price
149 | match orderValue with
150 | | v when orderValue > orderValueMax -> Error "Order value exceeded limit"
151 | | _ -> Valid order
152 |
153 | // Using currying
154 | let preTradeRiskRuleTwo (marketPrice:float) (result:Result) : Result =
155 | match result with
156 | | Error l -> Error l
157 | | Valid order ->
158 | let orderLimit = (float order.Qty) * order.Price
159 | match orderLimit with
160 | | v when orderLimit < marketPrice && order.Side = OrderSide.Buy -> Error "Order limit price below market price"
161 | | v when orderLimit > marketPrice && order.Side = OrderSide.Sell -> Error "Order limit price above market price"
162 | | _ -> Valid order
163 |
164 | let validateOrderAndInstrumentAndPreTradeRisk = validateOrderAndInstrument >> preTradeRiskRuleOne
165 | let validateOrderAndInstrumentAndPreTradeRisk2 marketPrice = validateOrderAndInstrument >> preTradeRiskRuleOne >> (preTradeRiskRuleTwo marketPrice)
166 |
167 | validateOrderAndInstrumentAndPreTradeRisk (Valid stopNoPriceNoInstrument)
168 | validateOrderAndInstrumentAndPreTradeRisk (Valid buyOrderExceetsPreTradeRisk)
169 | validateOrderAndInstrumentAndPreTradeRisk2 25.0 (Valid buyOrderBelowPricePreTradeRisk)
170 |
171 | /// Chain using List.reduce
172 | let preTradeRiskRules marketPrice = [
173 | preTradeRiskRuleOne
174 | (preTradeRiskRuleTwo marketPrice)
175 | ]
176 |
177 | /// Create function composition using reduce, >>, composite operator
178 | let preTradeComposite = List.reduce (>>) (preTradeRiskRules 25.0)
179 |
180 | preTradeComposite (Valid buyOrderExceetsPreTradeRisk)
181 | preTradeComposite (Valid buyOrderBelowPricePreTradeRisk)
--------------------------------------------------------------------------------
/Chapter07/FIX.fs:
--------------------------------------------------------------------------------
1 | namespace TradingSystem
2 |
3 | (*
4 | If used in F# Interactive
5 | #r @"PATH_TO\QuickFix.dll"
6 | *)
7 |
8 | open QuickFix
9 | open QuickFix.Transport
10 | open QuickFix.FIX42
11 | open System.Globalization
12 | open System
13 | open Orders
14 | open QuickFix.Fields
15 | open System.ComponentModel
16 |
17 | module FIX =
18 | type ClientInitiator(orders:BindingList) =
19 | member this.findOrder str =
20 | try
21 | Some (orders |> Seq.find (fun o -> o.Timestamp = str))
22 | with | _ as ex -> printfn "Exception: %A" ex.Message; None
23 | interface IApplication with
24 | member this.OnCreate(sessionID : SessionID) : unit = printfn "OnCreate"
25 | member this.ToAdmin(msg : QuickFix.Message, sessionID : SessionID) : unit = printfn "ToAdmin %A" msg
26 | member this.FromAdmin(msg : QuickFix.Message, sessionID : SessionID) : unit = printfn "FromAdmin %A" msg
27 | member this.ToApp(msg : QuickFix.Message, sessionID : SessionID) : unit = printfn "FromAdmin - Report: %A" msg
28 | member this.FromApp(msg : QuickFix.Message, sessionID : QuickFix.SessionID) : unit =
29 | match msg with
30 | | :? ExecutionReport as report ->
31 | let qty = report.CumQty
32 | let avg = report.AvgPx
33 | let sta = report.OrdStatus
34 | let oid = report.ClOrdID
35 | let lqty = report.LeavesQty
36 | let eqty = report.CumQty
37 | let debug = fun str -> printfn "ExecutionReport (%s) # avg price: %s | qty: %s | status: %s | orderId: %s" str (avg.ToString()) (qty.ToString()) (sta.ToString()) (oid.ToString())
38 | match sta.getValue() with
39 | | OrdStatus.NEW ->
40 | match this.findOrder(oid.ToString()) with
41 | | Some(o) ->
42 | o.Status <- OrderStatus.New
43 | | _ -> printfn "ERROR: The order was not found in OMS"
44 | debug "NEW"
45 | | OrdStatus.FILLED ->
46 | /// Update avg price, open price, ex price
47 | match this.findOrder(oid.ToString()) with
48 | | Some(o) ->
49 | o.Status <- OrderStatus.Filled
50 | o.AveragePrice <- double (avg.getValue())
51 | o.OpenQty <- int (lqty.getValue())
52 | o.ExecutedQty <- int (eqty.getValue())
53 | | _ -> printfn "ERROR: The order was not found in OMS"
54 | debug "FILLED"
55 | | OrdStatus.PARTIALLY_FILLED ->
56 | /// Update avg price, open price, ex price
57 | match this.findOrder(oid.ToString()) with
58 | | Some(o) ->
59 | o.Status <- OrderStatus.PartiallyFilled
60 | o.AveragePrice <- double (avg.getValue())
61 | o.OpenQty <- int (lqty.getValue())
62 | o.ExecutedQty <- int (eqty.getValue())
63 | | _ -> printfn "ERROR: The order was not found in OMS"
64 | debug "PARTIALLY_FILLED"
65 | | OrdStatus.CANCELED ->
66 | match this.findOrder(oid.ToString()) with
67 | | Some(o) ->
68 | o.Status <- OrderStatus.Cancelled
69 | | _ -> printfn "ERROR: The order was not found in OMS"
70 | debug "CANCELED"
71 | | OrdStatus.REJECTED ->
72 | match this.findOrder(oid.ToString()) with
73 | | Some(o) ->
74 | o.Status <- OrderStatus.Rejected
75 | | _ -> printfn "ERROR: The order was not found in OMS"
76 | debug "REJECTED"
77 | | OrdStatus.REPLACED ->
78 | match this.findOrder(oid.ToString()) with
79 | | Some(o) ->
80 | o.Status <- OrderStatus.Replaced
81 | | _ -> printfn "ERROR: The order was not found in OMS"
82 | debug "REPLACED"
83 | | OrdStatus.EXPIRED ->
84 | printfn "ExecutionReport (EXPIRED) %A" report
85 | | _ -> printfn "ExecutionReport (other) %A" report
86 | | _ -> ()
87 |
88 | member this.OnLogout(sessionID : SessionID) : unit = printf "OnLogout"
89 | member this.OnLogon(sessionID : SessionID) : unit = printf "OnLogon"
90 |
91 | type ConsoleLog() =
92 | interface ILog with
93 | member this.Clear() : unit = printf "hello"
94 | member this.OnEvent(str : string) : unit = printfn "%s" str
95 | member this.OnIncoming(str : string) : unit = printfn "%s" str
96 | member this.OnOutgoing(str : string) : unit = printfn "%s" str
97 |
98 | type ConsoleLogFactory(settings : SessionSettings) =
99 | interface ILogFactory with
100 | member this.Create(sessionID : SessionID) : ILog = new NullLog() :> ILog
101 |
102 | type FIXEngine(orders:BindingList) =
103 | let settings = new SessionSettings(@"conf\config.cfg")
104 | let application = new ClientInitiator(orders)
105 | let storeFactory = FileStoreFactory(settings)
106 | let logFactory = new ConsoleLogFactory(settings)
107 | let messageFactory = new MessageFactory()
108 | let initiator = new SocketInitiator(application, storeFactory, settings)
109 | let currentID = initiator.GetSessionIDs() |> Seq.head
110 | let orders = orders
111 | member this.init() : unit =
112 | ()
113 | member this.start() : unit =
114 | initiator.Start()
115 | member this.stop() : unit =
116 | initiator.Stop()
117 | member this.sendOrder(order:Order) : unit =
118 | let fixOrder = new NewOrderSingle()
119 | // Convert to Order to NewOrderSingle
120 | fixOrder.Symbol <- new Symbol(order.Instrument)
121 | fixOrder.ClOrdID <- new ClOrdID(order.Timestamp)
122 | fixOrder.OrderQty <- new OrderQty(decimal order.Qty)
123 | fixOrder.OrdType <- new OrdType('2'); // Limit order
124 | fixOrder.Side <- new Side('1');
125 | fixOrder.Price <- new Price(decimal order.Price);
126 | fixOrder.TransactTime <- new TransactTime();
127 | fixOrder.HandlInst <- new HandlInst('2');
128 | fixOrder.SecurityType <- new SecurityType("OPT"); // Option
129 | fixOrder.Currency <- new Currency("USD");
130 | // Add to OMS
131 | orders.Add(order)
132 | // Send order to target
133 | Session.SendToTarget(fixOrder, currentID) |> ignore
134 |
135 | module Apa =
136 | // Use a list of NewOrderSingle as first step
137 | let orders = new BindingList()
138 | let fixEngine = new FIX.FIXEngine(orders)
139 | fixEngine.init()
140 | fixEngine.start()
141 | let buyOrder1 = new Order(OrderSide.Buy, OrderType.Limit, 24.50, Tif.GoodForDay, 100, "ERICB4A115", 0.0)
142 | let buyOrder2 = new Order(OrderSide.Buy, OrderType.Limit, 34.50, Tif.GoodForDay, 100, "ERICB4A116", 0.0)
143 | let buyOrder3 = new Order(OrderSide.Buy, OrderType.Limit, 44.50, Tif.GoodForDay, 100, "ERICB4A117", 0.0)
144 | fixEngine.sendOrder(buyOrder1)
145 | fixEngine.sendOrder(buyOrder2)
146 | fixEngine.sendOrder(buyOrder3)
--------------------------------------------------------------------------------
/Chapter02/Chapter2.fsx:
--------------------------------------------------------------------------------
1 | /// Background workers (1)
2 |
3 | open System.Threading
4 | open System.ComponentModel
5 |
6 | let worker = new BackgroundWorker()
7 | worker.DoWork.Add(fun args ->
8 | for i in 1 .. 50 do
9 | // Simulates heavy calculation
10 | Thread.Sleep(1000)
11 | printfn "%A" i
12 | )
13 |
14 | worker.RunWorkerCompleted.Add(fun args ->
15 | printfn "Completed..."
16 | )
17 |
18 | worker.RunWorkerAsync()
19 |
20 | /// Background workers (2)
21 |
22 | open System.Threading
23 | open System.ComponentModel
24 |
25 | let worker = new BackgroundWorker()
26 | worker.DoWork.Add(fun args ->
27 | for i in 1 .. 50 do
28 | // Simulates heavy calculation
29 | Thread.Sleep(1000)
30 | printfn "A: %A" i
31 | )
32 |
33 | worker.DoWork.Add(fun args ->
34 | for i in 1 .. 10 do
35 | // Simulates heavy calculation
36 | Thread.Sleep(500)
37 | printfn "B: %A" i
38 | )
39 |
40 | worker.RunWorkerCompleted.Add(fun args ->
41 | printfn "Completed..."
42 | )
43 |
44 | worker.RunWorkerAsync()
45 |
46 | /// Background workers (3)
47 | open System.ComponentModel
48 |
49 | let workerCancel = new BackgroundWorker(WorkerSupportsCancellation = true)
50 | workerCancel.DoWork.Add(fun args ->
51 | printfn "apan %A" args
52 | for i in 1 .. 50 do
53 | if (workerCancel.CancellationPending = false) then
54 | Thread.Sleep(1000)
55 | printfn "%A" i
56 | )
57 |
58 | workerCancel.RunWorkerCompleted.Add(fun args ->
59 | printfn "Completed..."
60 | )
61 |
62 | workerCancel.RunWorkerAsync()
63 | workerCancel.CancelAsync()
64 |
65 | /// Threads (1)
66 | open System.Threading
67 |
68 | let runMe() =
69 | for i in 1 .. 10 do
70 | try
71 | Thread.Sleep(1000)
72 | with
73 | | :? System.Threading.ThreadAbortException as ex -> printfn "Exception %A" ex
74 | printfn "I'm still running..."
75 |
76 | let thread = new Thread(runMe)
77 | thread.Start()
78 |
79 | /// Threads (2)
80 | open System.Threading
81 |
82 | let runMe() =
83 | for i in 1 .. 10 do
84 | try
85 | Thread.Sleep(1000)
86 | with
87 | | :? System.Threading.ThreadAbortException as ex -> printfn "Exception %A" ex
88 | printfn "I'm still running..."
89 |
90 | let createThread() =
91 | let thread = new Thread(runMe)
92 | thread.Start()
93 |
94 | createThread()
95 | createThread()
96 |
97 | /// Thread pools (1)
98 | open System.Threading
99 |
100 | let runMe(arg:obj) =
101 | for i in 1 .. 10 do
102 | try
103 | Thread.Sleep(1000)
104 | with
105 | | :? System.Threading.ThreadAbortException as ex -> printfn "Exception %A" ex
106 | printfn "%A still running..." arg
107 |
108 | ThreadPool.QueueUserWorkItem(new WaitCallback(runMe), "One")
109 | ThreadPool.QueueUserWorkItem(new WaitCallback(runMe), "Two")
110 | ThreadPool.QueueUserWorkItem(new WaitCallback(runMe), "Three")
111 |
112 | /// Async example (1)
113 | open System.Net
114 | open Microsoft.FSharp.Control.WebExtensions
115 |
116 | /// Stock symbol and URL to Yahoo finance
117 | let urlList = [ "MSFT", "http://ichart.finance.yahoo.com/table.csv?s=MSFT&d=6&e=6&f=2013&g=d&a=1&b=1&c=2010&ignore=.csv"
118 | "GOOG", "http://ichart.finance.yahoo.com/table.csv?s=GOOG&d=6&e=6&f=2013&g=d&a=1&b=1&c=2010&ignore=.csv"
119 | "EBAY", "http://ichart.finance.yahoo.com/table.csv?s=EBAY&d=6&e=6&f=2013&g=d&a=1&b=1&c=2010&ignore=.csv"
120 | "AAPL", "http://ichart.finance.yahoo.com/table.csv?s=AAPL&d=6&e=6&f=2013&g=d&a=1&b=1&c=2010&ignore=.csv"
121 | "ADBE", "http://ichart.finance.yahoo.com/table.csv?s=ADBE&d=6&e=6&f=2013&g=d&a=1&b=1&c=2010&ignore=.csv"
122 | ]
123 |
124 | /// Async fetch of CSV data
125 | let fetchAsync(name, url:string) =
126 | async {
127 | try
128 | let uri = new System.Uri(url)
129 | let webClient = new WebClient()
130 | let! html = webClient.AsyncDownloadString(uri)
131 | printfn "Downloaded historical data for %s, recieved %d characters" name html.Length
132 | with
133 | | ex -> printfn "Exception: %s" ex.Message
134 | }
135 |
136 | /// Helper function to run in async parallel
137 | let runAll() =
138 | urlList
139 | |> Seq.map fetchAsync
140 | |> Async.Parallel
141 | |> Async.RunSynchronously
142 | |> ignore
143 |
144 | /// Get max closing price from 2010-01-01 for each stock
145 | runAll()
146 |
147 | /// Async example (2)
148 | open System.Net
149 | open Microsoft.FSharp.Control.WebExtensions
150 |
151 | /// Stock symbol and URL to Yahoo finance
152 | let urlList = [ "MSFT", "http://ichart.finance.yahoo.com/table.csv?s=MSFT&d=6&e=6&f=2013&g=d&a=1&b=1&c=2010&ignore=.csv"
153 | "GOOG", "http://ichart.finance.yahoo.com/table.csv?s=GOOG&d=6&e=6&f=2013&g=d&a=1&b=1&c=2010&ignore=.csv"
154 | "EBAY", "http://ichart.finance.yahoo.com/table.csv?s=EBAY&d=6&e=6&f=2013&g=d&a=1&b=1&c=2010&ignore=.csv"
155 | "AAPL", "http://ichart.finance.yahoo.com/table.csv?s=AAPL&d=6&e=6&f=2013&g=d&a=1&b=1&c=2010&ignore=.csv"
156 | "ADBE", "http://ichart.finance.yahoo.com/table.csv?s=ADBE&d=6&e=6&f=2013&g=d&a=1&b=1&c=2010&ignore=.csv"
157 | ]
158 |
159 | /// Parse CSV and extract max price
160 | let getMaxPrice(data:string) =
161 | let rows = data.Split('\n')
162 | rows
163 | |> Seq.skip 1
164 | |> Seq.map (fun s -> s.Split(','))
165 | |> Seq.map (fun s -> float s.[4])
166 | |> Seq.take (rows.Length - 2)
167 | |> Seq.max
168 |
169 | /// Async fetch of CSV data
170 | let fetchAsync(name, url:string) =
171 | async {
172 | try
173 | let uri = new System.Uri(url)
174 | let webClient = new WebClient()
175 | let! html = webClient.AsyncDownloadString(uri)
176 | let maxprice = (getMaxPrice(html.ToString()))
177 | printfn "Downloaded historical data for %s, max closing price since 2010-01-01: %f" name maxprice
178 | with
179 | | ex -> printfn "Exception: %s" ex.Message
180 | }
181 |
182 | /// Helper function to run in async parallel
183 | let runAll() =
184 | urlList
185 | |> Seq.map fetchAsync
186 | |> Async.Parallel
187 | |> Async.RunSynchronously
188 | |> ignore
189 |
190 | /// Get max closing price from 2010-01-01 for each stock
191 | runAll()
192 |
193 | /// MailboxProcessor (1) - Max agent
194 | open System
195 |
196 | // Type for our agent
197 | type Agent<'T> = MailboxProcessor<'T>
198 |
199 | // Control messages to be sent to agent
200 | type CounterMessage =
201 | | Update of float
202 | | Reset
203 |
204 | module Helpers =
205 | let genRandomNumber (n) =
206 | let rnd = new System.Random()
207 | float (rnd.Next(n, 100))
208 |
209 | module MaxAgent =
210 | // Agent to keep track of max value and update GUI
211 | let sampleAgent = Agent.Start(fun inbox ->
212 | let rec loop max = async {
213 | let! msg = inbox.Receive()
214 | match msg with
215 | | Reset ->
216 | return! loop 0.0
217 | | Update value ->
218 | let max = Math.Max(max, value)
219 |
220 | Console.WriteLine("Max: " + max.ToString())
221 |
222 | do! Async.Sleep(1000)
223 | return! loop max
224 | }
225 | loop 0.0)
226 |
227 | let agent = MaxAgent.sampleAgent
228 | let random = Helpers.genRandomNumber 5
229 | agent.Post(Update random)
230 |
231 | /// OOP (1)
232 | type Order(s: OrderSide, t: OrderType, p: float) =
233 | let mutable S = s
234 | member this.T = t
235 | member this.P = p
236 |
237 | member this.Side
238 | with get() = S
239 | and set(s) = S <- s
240 |
241 | member this.Type
242 | with get() = this.T
243 |
244 | member this.Price
245 | with get() = this.P
246 |
247 | member this.toggleOrderSide() =
248 | match S with
249 | | Buy -> S <- Sell
250 | | Sell -> S <- Buy
251 |
252 | /// OOP - Overloaded operators (1)
253 | type Order(s: OrderSide, t: OrderType, p: float) =
254 | let mutable S = s
255 | member this.T = t
256 | member this.P = p
257 |
258 | member this.Side
259 | with get() = S
260 | and set(s) = S <- s
261 |
262 | member this.Type
263 | with get() = this.T
264 |
265 | member this.Price
266 | with get() = this.P
267 |
268 | member this.toggleOrderSide() =
269 | S <- this.toggleOrderSide(S)
270 |
271 | member private this.toggleOrderSide(s: OrderSide) =
272 | match s with
273 | | Buy -> Sell
274 | | Sell -> Buy
275 |
276 | static member (~-) (o : Order) =
277 | Order(o.toggleOrderSide(o.Side), o.Type, o.Price)
--------------------------------------------------------------------------------