So how we get the stock prices for our F# program?
Well Yahoo of course.
Luca Bolognese's WebLog has a great writeup of how to download stock prices from Yahoo's finance site. I have borrowed liberally from his work and made some tweaks of my own.
The first part of my F# code is:
#light
open System
open System.Collections.Generic
open System.IO
open System.Data.SqlClient
open System.Text.RegularExpressions
open System.Net
[<Measure>] type dollars
[<Measure>] type volume
We immediately run into two statements for setting up units of measure. The statement [<Measure>] type dollars identifies a unit of measure named dollars in our program.
Now what are units of measure?
In F#, you can set up floating point numbers as certain unit of measure types. The F# compiler will ensure that certain mathematical operations are only performed on variables with the same measure type. For example, if I try to add apples and oranges:
let a = 10.0<dollars>
let b = 20.0<volume>
let c = a + b
I get a compiler error: "The unit of measure 'volume' does not match the unit of measure 'dollars'"
Now this is legal:
let a = 100.0<dollars>
let b = 20.0<volume>
let c = a / b
and the result c would be 5.0 of type <dollars> per <volume>.
Also, the F# compiler is smart enough to allow:
let d = 500.0<volume> * c
and it knows that if I multiply a <volume> times a number expressed as <dollars> per <volume> that the result must be of type <dollars>.
Also, according to our friends at Microsoft:
"Units of measure are used for compile-time unit checking but are not persisted in the run-time environment. Therefore, they do not affect performance."
Now a piece of trivia: Do you remember NASA's Mars Climate Orbiter? It was lost in September 1999 because some engineer messed up the converting metric to English units of measurement. With the introduction of units of measure in F# we can prevent operations that use inconsistent units of measure. This is very cool.
The one gotcha I ran into was with the printfn function:
printfn "d = %8.2f" d
This expression throws a type mismatch because d is not a float, but of type <dollars>
What I finally ended up doing was writing a function toFloat:
let toFloat (someBucks : float<dollars>) =
someBucks / 1.0<dollars>
printfn "d = %8.2f" (toFloat d)
and then this works. In the toFloat function I just divide an input of type <dollars> by 1.0<dollar> which F# then know is just a floating point number. I couldn't find another way around this problem. Anyone know a better answer?
The next part of my code creates several useful types.
type Span = { Start: DateTime; End: DateTime }
type Price = { Open: float<dollars>; High: float<dollars>; Low:float<dollars>; Close:float<dollars>; Volume: float<volume>}
type Event =
| StkPrice of Price
| Split of float
| Dividend of float<dollars>
type Observation = { Date: DateTime; Event: Event}
The 'Span' type is basically used to create a date range variable type.
The 'Price' type defines a daily stock price: the opening price, the high for the day, the low for the day, the closing price, and the volume.
The 'Event' type needs a little explaining. It is not a Record type, but It is what is called a "Discriminated Union." What the heck is that?
From what I can figure, it is a variable that can morph itself into any of the listed options. Thus, the type Event can be a StkPrice (which is of type Price), or a Split (which is of type float), or a Dividend (which is of type <dollars>
If you look at the next line:
type Observation = { Date: DateTime; Event: Event}
We have a type called observation which consists of a date and an event. But, an event can have one of three types: a stock price, a dividend, or a split. Thus, we could have a list of Observations (that are by definition of the same type, but they can each represent one of three events. Or, we could have a function that takes an Event type as an argument that would allow a stock price, a dividend, or a split to be passed in. I will explain more of this latter when we actually use the Event type.
Now let's look at some code. The following three statements have the identical meaning:
let aSplit0 : Event = Event. Split(2.0)
let aSplit1 = Event.Split(2.0)
let aSplit2 = Split(2.0)
They all say assign the value of 2.0 to a variable of type Event that masks a float named Split. Note that in the first two examples, I use the dot (.) notation, which in the .Net editor uses Intellisense. The third example is too terse for my liking, buy you can see that the F# compiler can look through the Event type and resolve it's type to the float named Split.
Here are two examples how how to instantiate Event values:
let aPrice : Event = Event.StkPrice{Open = 48.25<dollars>; High = 50.50<dollars>; Low = 47.25<dollars>; Close = 50.0<dollars>; Volume =21221.0<volume>}
let aDiv = Event.Dividend(2.50<dollars>)
I suppose a Discriminated Union is like a Variant (in VB6) or an Object in .Net whose underlying type is limited to those that you specify, instead of anything. I presume this allows the compiler to early bind instead of late bind the variables.