packages feed

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 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