Tuesday, 17 September 2013

Downloading stock prices

This post describes a little program to download Microsoft stock prices from Yahoo Finance. The program includes downloading a URL as a string, splitting the string at newlines and generating sequence elements when input lines can be parsed as floats.

We begin by defining the URL that we shall be downloading from:

let url = "http://ichart.finance.yahoo.com/table.csv?s="

The following function uses a WebClient to download a url as a string, splits it at newline characters and yields the resulting sequence:

let downloadLines (url: string) =
  seq { use wc = new System.Net.WebClient()
        yield! wc.DownloadString(url).Split '\n' }

The following active pattern wraps the built-in TryParse and will only match a string pattern if that string can be parsed as a float:

let (|Float|_|) s =
  let mutable x = 0.0
  if System.Double.TryParse(s, &x) then Some x else None

Stock prices are given in the form open, high, low and close which we encapsulate in a record type:

type Prices = { Open: float; High: float; Low: float; Close: float }

The following function downloads prices of the given stock:

let getStockPrices stock =
  seq { for line in downloadLines(url + stock) do
          match line.Split ',' |> List.ofSeq with
          | _::Float first::Float hi::Float lo::Float last::_ ->
              yield { Open=first; High=hi; Low=lo; Close=last }
          | _ -> () }

Note how easy it is to parse a line containing four floats using active patterns.

Now we can get the historical stock price data for Microsoft from Yahoo! Finance:

getStockPrices "MSFT"

Subscribe to the F# Journal today!


Gustavo Guerra said...

You could also leverage the CSV type providers to do the parsing for you:

open FSharp.Data

type Stocks = CsvProvider<"http://ichart.finance.yahoo.com/table.csv?s=GOOG">

let getStockPrices stock =
let csv = Stocks.Load("http://ichart.finance.yahoo.com/table.csv?s=" + stock)
seq { for line in csv.Data -> line.Open, line.High, line.Low, line.Close }

getStockPrices "MSFT"

More examples here: http://fsharp.github.io/FSharp.Data/library/CsvProvider.html

Jon Harrop said...

Hi Gustavo,

I actually tried the type provider first and found it harder to use because it required a reference CSV file so I ended up just writing vanilla F# code.

Your example seems to use a reference file from the web though (none of the example do, including the one you've cited), which begs the question why a reference file is needed at all...


Gustavo Guerra said...

You're right, nowhere in the documentation a url is used as the Sample parameter in any of the type providers.

We'll change that