Yahoo Finance API Wrapper in Haskell (updated to v0.2.0.0)

2016-10-15

I recently released a Haskell wrapper for the Yahoo Finance API. You can use it to get real-time stock quotes.

Yahoo used to provide three different APIs for obtaining different kinds of stock data, but it recently discontinued the API this package was relying on.

This package has been updated to v0.2.0.0 and changed to use the YQL Finance API, which is still supported.

Much of the hard work was done by James Haver II, a Haskeller living in Taiwan. I had the opportunity to meet James at ICFP 2016.

Usage

NOTE: The following usage is for servant-client>0.9 It is possible to use yahoo-finance-api with earlier versions of servant-client, but the return type of getQuotes will be slightly different.

One function is provided in the Web.Yahoo.Finance.YQL module to get stock quotes, getQuotes:

getQuotes :: YQLQuery -> ClientM YQLResponse

A YQLQuery is a wrapper around a list of StockSymbols.

If you pass in a YQLQuery to getQuotes, it will return a YQLResponse. A YQLResponse is a wrapper around a list of Quotes.

Here is an example of how to use getQuotes:

{-# LANGUAGE OverloadedStrings #-}

import Network.HTTP.Client.TLS (getGlobalManager)
import Servant.Client (ClientEnv(ClientEnv), runClientM)
import Web.Yahoo.Finance.YQL
       (StockSymbol(StockSymbol), YQLQuery(YQLQuery), getQuotes,
        yahooFinanceJsonBaseUrl)

example :: IO ()
example = do
  -- get a 'Manager' for performing the HTTPS connection.
  manager <- getGlobalManager
  res <-
    runClientM
      (getQuotes (YQLQuery [StockSymbol "GOOG", StockSymbol "AA"]))
      (ClientEnv manager yahooFinanceJsonBaseUrl)
  print res

This gets stock quotes for two different stocks: GOOG (Alphabet Inc.) and AA (Alcoa Inc. Common Stock). Here is the result of the previous code:

Right
  ( YQLResponse
    { responseCount = 2
    , responseCreated = 2016-10-09 13:44:49 UTC
    , responseLang = "en-US"
    , responseQuotes =
      [ Just
        ( Quote
          { quoteAverageDailyVolume = "1296480"
          , quoteChange = "-1.78"
          , quoteDaysLow = "770.75"
          , quoteDaysHigh = "779.66"
          , quoteYearLow = "639.01"
          , quoteYearHigh = "789.87"
          , quoteMarketCapitalization = "532.69B"
          , quoteLastTradePriceOnly = "775.08"
          , quoteDaysRange = "770.75 - 779.66"
          , quoteName = "Alphabet Inc."
          , quoteSymbol = "GOOG"
          , quoteVolume = "933158"
          , quoteStockExchange = "NMS"
          }
        )
      , Just
        (Quote
          { quoteAverageDailyVolume = "5999180"
          , quoteChange = "-0.41"
          , quoteDaysLow = "31.03"
          , quoteDaysHigh = "32.10"
          , quoteYearLow = "18.42"
          , quoteYearHigh = "34.50"
          , quoteMarketCapitalization = "41.26B"
          , quoteLastTradePriceOnly = "31.37"
          , quoteDaysRange = "31.03 - 32.10"
          , quoteName = "Alcoa Inc. Common Stock"
          , quoteSymbol = "AA"
          , quoteVolume = "7858603"
          , quoteStockExchange = "NYQ"
          }
        )
      ]
    }
  )

Future Work

It might be interesting to try to make getQuotes type-safe. The user would be able to pass in a type-level list of stock symbols, and get back a type-level list of stock quotes. The user could be sure that the stock symbols requested are actually the same as the quotes returned.

Conclusion

If you're interested in adding other funtionality, don't hesitate to submit an issue or send a pull-request.

tags: haskell