packages feed

stooq-api 0.3.1.0 → 0.4.1.0

raw patch · 4 files changed

+50/−22 lines, 4 filesdep +cassavadep −aesondep −stringsearchdep ~vector

Dependencies added: cassava

Dependencies removed: aeson, stringsearch

Dependency ranges changed: vector

Files

CHANGELOG.md view
@@ -1,5 +1,9 @@ # Revision history for stooq +## 0.4.0.0 -- 2022-11-27++* Switching to XML format, which seems more reliable than JSON.+ ## 0.3.1.0 -- 2022-07-07  * Migrating to nixpkgs 22.05.
src/lib/Web/Data/Stooq/API.hs view
@@ -49,9 +49,10 @@  -- | 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 :: StooqSymbol -> IO (Either String [StooqPrice]) fetchPrice ticker = do-    r <- get (queryUrl ticker)+    let url = queryUrl ticker+    r <- get url     return $ fmap (map toApiType . Impl.symbols) (Impl.parseResponse (r ^. responseBody))      where@@ -59,7 +60,7 @@         baseUrl = "https://stooq.pl/q/l/?s="          queryUrl :: StooqSymbol -> String-        queryUrl (StooqSymbol ticker) = baseUrl ++ ticker ++ "&e=json"+        queryUrl (StooqSymbol ticker) = baseUrl ++ ticker ++ "&e=xml"          toApiType :: Impl.StooqRow -> StooqPrice         toApiType row = StooqPrice {@@ -84,12 +85,12 @@  -- | Sends a request for multiple tickers at once. -- The function makes only a single HTTP call.-fetchPrices :: [StooqSymbol] -> IO (Maybe [StooqPrice])+fetchPrices :: [StooqSymbol] -> IO (Either String [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 :: String -> IO (Either String [StooqPrice]) fetch = fetchPrice . StooqSymbol
src/utils/Web/Data/Stooq/Internals.hs view
@@ -1,14 +1,16 @@ {-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE FlexibleInstances #-}  module Web.Data.Stooq.Internals where -import Data.Aeson (FromJSON, decode)-import Data.ByteString.Lazy (ByteString, empty)-import Data.ByteString.Char8 (pack)-import Data.ByteString.Lazy.Search (replace)+import Data.ByteString.Lazy (ByteString)+import Data.Maybe (fromMaybe, catMaybes) import Data.Text (Text) import GHC.Generics (Generic) +import Data.Csv (decode, HasHeader(NoHeader), FromField, parseField, runParser)+import qualified Data.Vector as V+ data StooqRow =     StooqRow {         symbol  :: !Text,@@ -21,16 +23,38 @@         volume  :: Int     } deriving (Show, Generic) -data StooqResponse =+newtype StooqResponse =     StooqResponse {         symbols :: [StooqRow]     } deriving (Show, Generic) -instance FromJSON StooqRow-instance FromJSON StooqResponse+data TryField a = FieldValue a | NoValue -parseResponse :: ByteString -> Maybe StooqResponse-parseResponse = decode . replace searchedSubstring replacement+instance FromField (TryField Text) where+    parseField s = case runParser (parseField s) of+        Left err -> pure NoValue+        Right v  -> pure $ FieldValue v++instance FromField (TryField Double) where+    parseField s = case runParser (parseField s) of+        Left err -> pure NoValue+        Right v  -> pure $ FieldValue v++instance FromField (TryField Int) where+    parseField s = case runParser (parseField s) of+        Left err -> pure NoValue+        Right v  -> pure $ FieldValue v++parseResponse :: ByteString -> Either String StooqResponse+parseResponse input =+    fmap (StooqResponse . catMaybes . V.toList . V.map tupleToStooqRow) (decode NoHeader input)+     where-        searchedSubstring = pack ",\"openint\":}"-        replacement = pack "}"+        tupleToStooqRow :: (Text, TryField Int, TryField Text, TryField Double, TryField Double, TryField Double, TryField Double, TryField Int, Text) -> Maybe StooqRow+        tupleToStooqRow (name, FieldValue date, FieldValue time, FieldValue open, FieldValue high, FieldValue low, FieldValue close, volume, _) =+            Just $ StooqRow name date time open high low close (defaultToZero volume)+        tupleToStooqRow (name, _, _, _, _, _, _, _, _) = Nothing++        defaultToZero :: TryField Int -> Int+        defaultToZero (FieldValue x) = x+        defaultToZero NoValue = 0
stooq-api.cabal view
@@ -1,7 +1,7 @@ cabal-version:      2.0  name:               stooq-api-version:            0.3.1.0+version:            0.4.1.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.@@ -24,11 +24,11 @@ library stooq-api-utils   exposed-modules:    Web.Data.Stooq.Internals   build-depends:      base,-                      aeson,                       bytestring,-                      stringsearch,+                      cassava,                       text,-                      time+                      time,+                      vector   hs-source-dirs:     src/utils   default-language:   Haskell2010 @@ -36,14 +36,13 @@     exposed-modules:  Web.Data.Stooq.API     build-depends:    base          >= 4.13     && < 4.16,                       bytestring    >= 0.10.10  && < 0.11,-                      aeson         >= 2.0      && < 2.1,+                      cassava       >= 0.5.2    && < 0.5.3,                       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,-                      stringsearch  >= 0.3      && < 0.4,                       stooq-api-utils     hs-source-dirs:   src/lib     default-language: Haskell2010