Reduce points.
[haskell-cryptsy-api.git] / Cryptsy / API / Public / MarketData.hs
blob9523d11ade0114f9d2a9c20d9ed0ac809de18e5b
1 {-# LANGUAGE FlexibleContexts #-}
2 module Cryptsy.API.Public.MarketData
3 ( GMarketData(..), MarketData
4 , extractMarketData, extractJSONMarketData
5 , withComponents, withMarket
6 , marketsKey
7 , module Cryptsy.API.Public
8 , module Cryptsy.API.Public.Market
9 -- |Re-exported from Data.Text
10 , Text
11 -- |Re-exported from Data.Aeson
12 , Value, Object, FromJSON(..)
13 -- |Re-exported from Data.Aeson.Types
14 , Parser
15 -- |Re-exported from Data.HashMap.Strict
16 , HashMap
18 where
20 -- aeson
21 import Data.Aeson ( FromJSON(..), Value, Object, withObject )
22 import Data.Aeson.Types (Parser, Result(..), parse)
24 -- base
25 import Control.Applicative ((<*>))
26 import Control.Monad (fail)
27 import Data.Either (Either(..))
28 import Data.Function (($), (.))
29 import Data.Functor (fmap, (<$>))
30 import Data.List ((++))
31 import Data.Maybe (maybe)
32 import Data.String (String)
33 import Data.Traversable (mapM)
34 import Prelude (Show(show))
36 -- either
37 import Control.Monad.Trans.Either (left, right)
39 -- text
40 import Data.Text (Text, pack)
42 -- unordered-containers
43 import Data.HashMap.Strict (HashMap)
44 import qualified Data.HashMap.Strict as HM (lookup)
46 -- this package
47 import Cryptsy.API.Public (CryptsyNum(..), CryptsyError(..), PubCryptsy)
48 import Cryptsy.API.Public.Market
49 ( GMarket(..), Market
50 -- for re-export
51 , GOrder(Order)
52 , GTrade(Trade, time)
53 , Vector
56 -- |general market data parameterized by types for prices, quantities,
57 -- date/time values, and totals (price * quantity)
58 newtype GMarketData p q dt t =
59 MarketData { markets :: HashMap Text (GMarket p q dt t) }
60 deriving Show
61 type MarketData = GMarketData CryptsyNum CryptsyNum Text CryptsyNum
63 instance (FromJSON p, FromJSON q, FromJSON dt, FromJSON t) =>
64 FromJSON (GMarketData p q dt t)
65 where
66 parseJSON = withObject "markets" $ withComponents parseJSON
68 marketsStr :: String
69 marketsStr = "markets"
71 missingMsg :: String
72 missingMsg = "Missing '" ++ marketsStr ++ "' key."
74 -- |Key in JSON object for market data
75 marketsKey :: Text
76 marketsKey = pack marketsStr
78 extractMarketDataEither :: (Value -> Parser (GMarketData p q dt t))
79 -> Value -- ^ API return data
80 -> Either String (GMarketData p q dt t)
81 extractMarketDataEither parseMarkets v =
82 case parse parser v of
83 Error err -> Left err
84 Success m -> Right m
85 where
86 parser = withObject "return" $
87 maybe (fail missingMsg) parseMarkets . HM.lookup marketsKey
89 extractMarketData :: (Object -> Parser (GMarketData p q dt t))
90 -> Value -- ^ API return data
91 -> PubCryptsy (GMarketData p q dt t)
92 extractMarketData parseMarkets =
93 hoistFailParseReturn
94 <*> extractMarketDataEither (withObject marketsStr parseMarkets)
96 extractJSONMarketData :: FromJSON (GMarketData p q dt t)
97 => Value -- ^ API return data
98 -> PubCryptsy (GMarketData p q dt t)
99 extractJSONMarketData =
100 hoistFailParseReturn <*> extractMarketDataEither parseJSON
102 hoistFailParseReturn :: Value -> Either String a -> PubCryptsy a
103 hoistFailParseReturn ret (Left err) = left $ FailParseReturn ret err
104 hoistFailParseReturn _ (Right m) = right m
106 -- |Build parser for multiple markets from parser for single market.
107 withComponents :: (Value -> Parser (GMarket p q dt t)) -- ^ market parser
108 -> Object -> Parser (GMarketData p q dt t)
109 withComponents parseMarket = fmap MarketData <$> mapM parseMarket
111 -- |Build parser for multiple markets from parser for single market object.
112 withMarket :: (Object -> Parser (GMarket p q dt t)) -- ^ market parser
113 -> Object -> Parser (GMarketData p q dt t)
114 withMarket parseMarket = withComponents (withObject "market" parseMarket)