stooq-api (empty) → 0.1.0.0
raw patch · 5 files changed
+200/−0 lines, 5 filesdep +aesondep +basedep +bytestring
Dependencies added: aeson, base, bytestring, lens, stooq-api, text, time, utf8-string, vector, wreq
Files
- CHANGELOG.md +5/−0
- LICENSE +20/−0
- src/lib/Web/Data/Stooq/API.hs +96/−0
- src/utils/Web/Data/Stooq/Internals.hs +32/−0
- stooq-api.cabal +47/−0
+ CHANGELOG.md view
@@ -0,0 +1,5 @@+# Revision history for stooq++## 0.1.0.0 -- 2022-03-30++* Initial release.
+ LICENSE view
@@ -0,0 +1,20 @@+Copyright (c) 2022 Alojzy Leszcz++Permission is hereby granted, free of charge, to any person obtaining+a copy of this software and associated documentation files (the+"Software"), to deal in the Software without restriction, including+without limitation the rights to use, copy, modify, merge, publish,+distribute, sublicense, and/or sell copies of the Software, and to+permit persons to whom the Software is furnished to do so, subject to+the following conditions:++The above copyright notice and this permission notice shall be included+in all copies or substantial portions of the Software.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ src/lib/Web/Data/Stooq/API.hs view
@@ -0,0 +1,96 @@+{-# LANGUAGE OverloadedStrings #-}++-- | Here's a simple wrapper around API offered by Stooq.pl.+-- It's capable of returning the latest price for the given instrument.+-- For more information about tickers available, visit the service.+-- Keep in mind that in some situations their ticker convention is different to what's known e.g. from Yahoo Finance+-- e.g.+--+-- xxxx.UK: London Stock Exchange (LSE)+--+-- xxxx.US: NYSE (OTC market not available, so a lot of ADRs like `OGZPY` or `SBRCY` can't be fetched)+--+-- xxxx.DE: Deutsche Börse+--+-- xxxx: (no exchange code after full stop) Warsaw Stock Exchange (GPW)+--+-- Use:+--+-- >>> fetch "SPY.US"+-- Just [StooqPrice {symbol = "SPY.US", time = ..., ...}]+module Web.Data.Stooq.API where++import Control.Lens ((^.))+import Data.Text (Text, unpack)+import Data.Time.Calendar (fromGregorian, Day)+import Data.Time.Clock (UTCTime(..))+import Data.Time.LocalTime (LocalTime(LocalTime), TimeOfDay(TimeOfDay), TimeZone, localTimeToUTC, hoursToTimeZone)+import Network.Wreq (get, responseBody)++import qualified Web.Data.Stooq.Internals as Impl++-- | A single-case DU that represents a ticker.+newtype StooqSymbol = StooqSymbol String+ deriving (Show, Read, Eq, Ord)++-- | A type representing market price data returned by Stooq.+data StooqPrice =+ StooqPrice {+ symbol :: String,+ time :: UTCTime,+ open :: Double,+ high :: Double,+ low :: Double,+ close :: Double,+ volume :: Int,+ openint :: Int+ } deriving Show++-- | Sends a request for the specified ticker and returns its latest price.+-- Returns "Nothing" if the response is invalid (this is most likely due to using a non-existent ticker).+fetchPrice :: StooqSymbol -> IO (Maybe [StooqPrice])+fetchPrice ticker = do+ r <- get (queryUrl ticker)+ return $ fmap (map toApiType . Impl.symbols) (Impl.parseResponse (r ^. responseBody))++ where+ baseUrl :: String+ baseUrl = "https://stooq.pl/q/l/?s="++ queryUrl :: StooqSymbol -> String+ queryUrl (StooqSymbol ticker) = baseUrl ++ ticker ++ "&e=json"++ toApiType :: Impl.StooqRow -> StooqPrice+ toApiType row = StooqPrice {+ symbol = (unpack . Impl.symbol) row,+ time = localTimeToUTC stooqTimeZone $ LocalTime ((stooqIntToDay . Impl.date) row) ((stooqStringToTime . unpack . Impl.time) row),+ open = Impl.open row,+ high = Impl.high row,+ low = Impl.low row,+ close = Impl.close row,+ volume = Impl.volume row,+ openint = Impl.openint row+ }++ stooqIntToDay :: Int -> Day+ stooqIntToDay date = fromGregorian (toInteger $ (date `div` 10000) `mod` 10000) ((date `div` 100) `mod` 100) (date `mod` 100)++ stooqStringToTime :: String -> TimeOfDay+ stooqStringToTime [h1,h2,m1,m2,s1,s2] = TimeOfDay (read [h1,h2]) (read [m1,m2]) (read [s1,s2])+ stooqStringToTime x = error $ "Unexpected time format: " ++ x++ stooqTimeZone :: TimeZone+ stooqTimeZone = hoursToTimeZone 1++-- | Sends a request for multiple tickers at once.+-- The function makes only a single HTTP call.+fetchPrices :: [StooqSymbol] -> IO (Maybe [StooqPrice])+fetchPrices tickers = fetchPrice (concatTickers tickers)+ where+ concatTickers :: [StooqSymbol] -> StooqSymbol+ concatTickers = foldl1 (\(StooqSymbol t1) (StooqSymbol t2) -> StooqSymbol (t1 ++ " " ++ t2))++-- | A shorthand around "fetchPrice" that allows to call the function using a plain String, without converting it to a `StooqSymbol` first.+fetch :: String -> IO (Maybe [StooqPrice])+fetch = fetchPrice . StooqSymbol+
+ src/utils/Web/Data/Stooq/Internals.hs view
@@ -0,0 +1,32 @@+{-# LANGUAGE DeriveGeneric #-}++module Web.Data.Stooq.Internals where++import Data.Aeson (FromJSON, decode)+import Data.ByteString.Lazy.Internal (ByteString)+import Data.Text (Text)+import GHC.Generics (Generic)++data StooqRow =+ StooqRow {+ symbol :: !Text,+ date :: Int,+ time :: !Text,+ open :: Double,+ high :: Double,+ low :: Double,+ close :: Double,+ volume :: Int,+ openint :: Int+ } deriving (Show, Generic)++data StooqResponse =+ StooqResponse {+ symbols :: [StooqRow]+ } deriving (Show, Generic)++instance FromJSON StooqRow+instance FromJSON StooqResponse++parseResponse :: ByteString -> Maybe StooqResponse+parseResponse = decode
+ stooq-api.cabal view
@@ -0,0 +1,47 @@+cabal-version: >= 2.0++name: stooq-api+version: 0.1.0.0+synopsis: A simple wrapper around stooq.pl API for downloading market data.+description:+ Here's a simple wrapper around API offered by Stooq.pl.+ It's capable of returning the latest price for the given instrument.+ .+ For more information about tickers available, visit the service.++bug-reports: https://github.com/bratfizyk/stooq-api/issues+license: MIT+license-file: LICENSE+author: Alojzy Leszcz+maintainer: alojzy.leszcz@gmail.com+category: Web+build-type: Simple+extra-source-files: CHANGELOG.md+Source-repository head+ type: git+ location: https://github.com/bratfizyk/stooq-api++library stooq-api-utils+ exposed-modules: Web.Data.Stooq.Internals+ build-depends: base,+ aeson,+ bytestring,+ text,+ time+ hs-source-dirs: src/utils+ default-language: Haskell2010++library+ exposed-modules: Web.Data.Stooq.API+ build-depends: base >= 4.13 && < 4.15,+ bytestring >= 0.10.10 && < 0.11,+ aeson >= 1.5.6 && < 1.6,+ lens >= 4.18.1 && < 5.1,+ text >= 1.2 && < 1.3,+ time >= 1.9.3 && < 1.10,+ utf8-string >= 1.0.2 && < 1.1,+ vector >= 0.12.1 && < 0.13,+ wreq >= 0.5.3 && < 0.6,+ stooq-api-utils+ hs-source-dirs: src/lib+ default-language: Haskell2010