browse by category or date

If the previous example haven’t really impresses you yet, Luca gave us more serious example. This time we are going to retrieve and analyze stock informations.
The CSV data source will be obtained from Yahoo! Finance. To find out the URL to download, we need to:

  1. Visit Yahoo! Finance
  2. Enter the stock symbol in the search box, and press the “Get Quotes” button.
  3. On the new page, click Historical Prices menu on the left side of your screen.
  4. Scroll down, and obtain the CSV download URL.

Once you download and open it with text editor, you’ll see that the CSV data will looks something like this:

Date,Open,High,Low,Close,Volume,Adj Close
2012-09-07,31.04,31.07,30.73,30.95,42649100,30.95
2012-09-06,30.50,31.36,30.46,31.35,48371700,31.35
2012-09-05,30.22,30.53,30.21,30.39,33650000,30.39
2012-09-04,30.45,30.66,30.15,30.39,48556700,30.39

Now we will write the code to automatically retrieve and parse the CSV data:

open System.IO
open System.Net 

let ticker = "msft"
let url = "http://ichart.finance.yahoo.com/table.csv?s=" + ticker + "&d=8&e=10&f=2012&g=d&a=2&b=13&c=1986&ignore=.csv"

let req = WebRequest.Create(url)
let resp = req.GetResponse()
let stream = resp.GetResponseStream()
let reader = new StreamReader(stream)
let csv = reader.ReadToEnd()

let prices =
    //split list of lines
    csv.Split([|'\n'|])
    //Skip the first line
    |> Seq.skip 1
    //For each line, split the line using the comma
    |> Seq.map (fun line -> line.Split([|','|]))
    //Now we have list that consists of list of String
    //We then filter it out, only selecting list that have 7 string values in it
    |> Seq.filter (fun values -> values |> Seq.length = 7)
    //Create a new tuple of (DateTime, Float) as the final result
    |> Seq.map (fun values -> System.DateTime.Parse(values.[0]), float values.[6])    

To make above example reusable, we need to convert it into a function

let loadPrices ticker = 
	let url = "http://ichart.finance.yahoo.com/table.csv?s=" + ticker + "&d=8&e=10&f=2012&g=d&a=2&b=13&c=1986&ignore=.csv"

	let req = WebRequest.Create(url)
	let resp = req.GetResponse()
	let stream = resp.GetResponseStream()
	let reader = new StreamReader(stream)
	let csv = reader.ReadToEnd()

	let prices =
		csv.Split([|'\n'|])
		|> Seq.skip 1
		|> Seq.map (fun line -> line.Split([|','|]))
		|> Seq.filter (fun values -> values |> Seq.length = 7)
		|> Seq.map (fun values -> System.DateTime.Parse(values.[0]), float values.[6])
        //return the list of tuples (DateTime, float)
        prices

Now we are going to create a class that analyze the output of loadPrices function.

type StockAnalyzer(lprices, days) =
    let prices =
        lprices
        //snd is a function that return the second element of a tuple
        |> Seq.map snd
        //return the first N element of the list
        |> Seq.take days
    //This is a factory method
    static member GetAnalyzers(tickers, days) =
        tickers
        |> Seq.map loadPrices
        |> Seq.map (fun prices -> new StockAnalyzer(prices, days))
    member s.Return =
        let lastPrice = prices |> Seq.nth 0
        let startPrice = prices |> Seq.nth (days-1)
        lastPrice/startPrice-1.
    //Calculate standard-deviation
    member s.StdDev =
        let logRets =
            prices
            |> Seq.pairwise
            |> Seq.map (fun (x,y) -> log (x/y))
        let mean = logRets |> Seq.average 
        let sqr x = x * x
        //calculate variance
        let var = logRets |> Seq.averageBy (fun r -> sqr(r-mean))
        //return sqrt(variance)
        sqrt var

Now we can combine both into a proper API that can be used in other .NET languages. Note that I made some changes here because Luca’s code taken from the talk didn’t compile in Visual Studio 2012

namespace StockLibrary
open System.IO
open System.Net

type internal StockLoader =
    static member loadPrices ticker =
        let url = "http://ichart.finance.yahoo.com/table.csv?s=" + ticker + "&d=8&e=10&f=2012&g=d&a=2&b=13&c=1986&ignore=.csv"
 
        let req = WebRequest.Create(url)
        let resp = req.GetResponse()
        let stream = resp.GetResponseStream()
        let reader = new StreamReader(stream)
        let csv = reader.ReadToEnd()
 
        let prices =
            csv.Split([|'\n'|])
            |> Seq.skip 1
            |> Seq.map (fun line -> line.Split([|','|]))
            |> Seq.filter (fun values -> values |> Seq.length = 7)
            |> Seq.map (fun values -> System.DateTime.Parse(values.[0]), float values.[6])
        //return the list of tuples (DateTime, float)
        prices

type StockAnalyzer(lprices, days) =
    let prices =
        lprices
        //snd is a function that return the second element of a tuple
        |> Seq.map snd
        //return the first N element of the list
        |> Seq.take days
    //This is a factory method
    static member GetAnalyzers(tickers, days) =
        tickers
        |> Seq.map StockLoader.loadPrices
        |> Seq.map (fun prices -> new StockAnalyzer(prices, days))
    member s.Return =
        let lastPrice = prices |> Seq.nth 0
        let startPrice = prices |> Seq.nth (days-1)
        lastPrice/startPrice-1.
    //Calculate standard-deviation
    member s.StdDev =
        let logRets =
            prices
            |> Seq.pairwise
            |> Seq.map (fun (x,y) -> log (x/y))
        let mean = logRets |> Seq.average 
        let sqr x = x * x
        //calculate variance
        let var = logRets |> Seq.averageBy (fun r -> sqr(r-mean))
        //return sqrt(variance)
        sqrt var

GD Star Rating
loading...
Falling in Love to F#, 3.0 out of 5 based on 1 rating

About Hardono

Howdy! I'm Hardono. I am working as a Software Developer. I am working mostly in Windows, dealing with .NET, conversing in C#. But I know a bit of Linux, mainly because I need to keep this blog operational. I've been working in Logistics/Transport industry for more than 11 years.

Incoming Search

f#

1 Trackback

 

No Comment

Add Your Comment