packages feed

coinbase-exchange 0.2.0.2 → 0.3.0.0

raw patch · 9 files changed

+502/−114 lines, 9 filesdep +asyncdep +randomdep +unordered-containersdep ~aesondep ~mtldep ~timePVP ok

version bump matches the API change (PVP)

Dependencies added: async, random, unordered-containers

Dependency ranges changed: aeson, mtl, time

API changes (from Hackage documentation)

- Coinbase.Exchange.Types.Core: CoinbaseTime :: UTCTime -> CoinbaseTime
- Coinbase.Exchange.Types.Core: [unCoinbaseTime] :: CoinbaseTime -> UTCTime
- Coinbase.Exchange.Types.Core: coinbaseTimeFormat :: String
- Coinbase.Exchange.Types.Core: instance Control.DeepSeq.NFData Coinbase.Exchange.Types.Core.CoinbaseTime
- Coinbase.Exchange.Types.Core: instance Data.Aeson.Types.Class.FromJSON Coinbase.Exchange.Types.Core.CoinbaseTime
- Coinbase.Exchange.Types.Core: instance Data.Aeson.Types.Class.ToJSON Coinbase.Exchange.Types.Core.CoinbaseTime
- Coinbase.Exchange.Types.Core: instance Data.Data.Data Coinbase.Exchange.Types.Core.CoinbaseTime
- Coinbase.Exchange.Types.Core: instance GHC.Classes.Eq Coinbase.Exchange.Types.Core.CoinbaseTime
- Coinbase.Exchange.Types.Core: instance GHC.Classes.Ord Coinbase.Exchange.Types.Core.CoinbaseTime
- Coinbase.Exchange.Types.Core: instance GHC.Read.Read Coinbase.Exchange.Types.Core.CoinbaseTime
- Coinbase.Exchange.Types.Core: instance GHC.Show.Show Coinbase.Exchange.Types.Core.CoinbaseTime
- Coinbase.Exchange.Types.Core: maybeRead :: (Read a) => String -> Maybe a
- Coinbase.Exchange.Types.Core: newtype CoinbaseTime
- Coinbase.Exchange.Types.Private: NewOrder :: Size -> Price -> Side -> ProductId -> Maybe ClientOrderId -> Maybe SelfTrade -> NewOrder
- Coinbase.Exchange.Types.Private: Order :: OrderId -> Size -> Price -> ProductId -> OrderStatus -> Maybe Size -> Maybe Price -> Bool -> Side -> UTCTime -> Maybe UTCTime -> Maybe Reason -> Order
- Coinbase.Exchange.Types.Private: instance Data.Aeson.Types.Class.FromJSON Coinbase.Exchange.Types.Private.NewOrder
- Coinbase.Exchange.Types.Socket: Change :: UTCTime -> Sequence -> OrderId -> ProductId -> Size -> Size -> Price -> Side -> ExchangeMessage
- Coinbase.Exchange.Types.Socket: Done :: UTCTime -> ProductId -> Sequence -> Price -> OrderId -> Reason -> Side -> ExchangeMessage
- Coinbase.Exchange.Types.Socket: Received :: UTCTime -> ProductId -> Sequence -> OrderId -> Size -> Price -> Side -> Maybe ClientOrderId -> ExchangeMessage
- Coinbase.Exchange.Types.Socket: Sequence :: Word64 -> Sequence
- Coinbase.Exchange.Types.Socket: [unSequence] :: Sequence -> Word64
- Coinbase.Exchange.Types.Socket: instance Control.DeepSeq.NFData Coinbase.Exchange.Types.Socket.Sequence
- Coinbase.Exchange.Types.Socket: instance Data.Aeson.Types.Class.FromJSON Coinbase.Exchange.Types.Socket.Sequence
- Coinbase.Exchange.Types.Socket: instance Data.Aeson.Types.Class.ToJSON Coinbase.Exchange.Types.Socket.Sequence
- Coinbase.Exchange.Types.Socket: instance Data.Data.Data Coinbase.Exchange.Types.Socket.Sequence
- Coinbase.Exchange.Types.Socket: instance Data.Hashable.Class.Hashable Coinbase.Exchange.Types.Socket.Sequence
- Coinbase.Exchange.Types.Socket: instance GHC.Classes.Eq Coinbase.Exchange.Types.Socket.Sequence
- Coinbase.Exchange.Types.Socket: instance GHC.Classes.Ord Coinbase.Exchange.Types.Socket.Sequence
- Coinbase.Exchange.Types.Socket: instance GHC.Generics.Constructor Coinbase.Exchange.Types.Socket.C1_0Sequence
- Coinbase.Exchange.Types.Socket: instance GHC.Generics.Datatype Coinbase.Exchange.Types.Socket.D1Sequence
- Coinbase.Exchange.Types.Socket: instance GHC.Generics.Generic Coinbase.Exchange.Types.Socket.Sequence
- Coinbase.Exchange.Types.Socket: instance GHC.Generics.Selector Coinbase.Exchange.Types.Socket.S1_0_0Sequence
- Coinbase.Exchange.Types.Socket: instance GHC.Num.Num Coinbase.Exchange.Types.Socket.Sequence
- Coinbase.Exchange.Types.Socket: instance GHC.Read.Read Coinbase.Exchange.Types.Socket.Sequence
- Coinbase.Exchange.Types.Socket: instance GHC.Show.Show Coinbase.Exchange.Types.Socket.Sequence
- Coinbase.Exchange.Types.Socket: newtype Sequence
+ Coinbase.Exchange.Types.Core: Cost :: CoinScientific -> Cost
+ Coinbase.Exchange.Types.Core: Limit :: OrderType
+ Coinbase.Exchange.Types.Core: Market :: OrderType
+ Coinbase.Exchange.Types.Core: Sequence :: Word64 -> Sequence
+ Coinbase.Exchange.Types.Core: [unCost] :: Cost -> CoinScientific
+ Coinbase.Exchange.Types.Core: [unSequence] :: Sequence -> Word64
+ Coinbase.Exchange.Types.Core: data OrderType
+ Coinbase.Exchange.Types.Core: instance Control.DeepSeq.NFData Coinbase.Exchange.Types.Core.Cost
+ Coinbase.Exchange.Types.Core: instance Control.DeepSeq.NFData Coinbase.Exchange.Types.Core.OrderType
+ Coinbase.Exchange.Types.Core: instance Control.DeepSeq.NFData Coinbase.Exchange.Types.Core.Sequence
+ Coinbase.Exchange.Types.Core: instance Data.Aeson.Types.Class.FromJSON Coinbase.Exchange.Types.Core.Cost
+ Coinbase.Exchange.Types.Core: instance Data.Aeson.Types.Class.FromJSON Coinbase.Exchange.Types.Core.OrderType
+ Coinbase.Exchange.Types.Core: instance Data.Aeson.Types.Class.FromJSON Coinbase.Exchange.Types.Core.Sequence
+ Coinbase.Exchange.Types.Core: instance Data.Aeson.Types.Class.ToJSON Coinbase.Exchange.Types.Core.Cost
+ Coinbase.Exchange.Types.Core: instance Data.Aeson.Types.Class.ToJSON Coinbase.Exchange.Types.Core.OrderType
+ Coinbase.Exchange.Types.Core: instance Data.Aeson.Types.Class.ToJSON Coinbase.Exchange.Types.Core.Sequence
+ Coinbase.Exchange.Types.Core: instance Data.Data.Data Coinbase.Exchange.Types.Core.Cost
+ Coinbase.Exchange.Types.Core: instance Data.Data.Data Coinbase.Exchange.Types.Core.OrderType
+ Coinbase.Exchange.Types.Core: instance Data.Data.Data Coinbase.Exchange.Types.Core.Sequence
+ Coinbase.Exchange.Types.Core: instance Data.Hashable.Class.Hashable Coinbase.Exchange.Types.Core.Cost
+ Coinbase.Exchange.Types.Core: instance Data.Hashable.Class.Hashable Coinbase.Exchange.Types.Core.OrderType
+ Coinbase.Exchange.Types.Core: instance Data.Hashable.Class.Hashable Coinbase.Exchange.Types.Core.Sequence
+ Coinbase.Exchange.Types.Core: instance GHC.Classes.Eq Coinbase.Exchange.Types.Core.Cost
+ Coinbase.Exchange.Types.Core: instance GHC.Classes.Eq Coinbase.Exchange.Types.Core.OrderType
+ Coinbase.Exchange.Types.Core: instance GHC.Classes.Eq Coinbase.Exchange.Types.Core.Sequence
+ Coinbase.Exchange.Types.Core: instance GHC.Classes.Ord Coinbase.Exchange.Types.Core.Cost
+ Coinbase.Exchange.Types.Core: instance GHC.Classes.Ord Coinbase.Exchange.Types.Core.OrderType
+ Coinbase.Exchange.Types.Core: instance GHC.Classes.Ord Coinbase.Exchange.Types.Core.Sequence
+ Coinbase.Exchange.Types.Core: instance GHC.Generics.Constructor Coinbase.Exchange.Types.Core.C1_0Cost
+ Coinbase.Exchange.Types.Core: instance GHC.Generics.Constructor Coinbase.Exchange.Types.Core.C1_0OrderType
+ Coinbase.Exchange.Types.Core: instance GHC.Generics.Constructor Coinbase.Exchange.Types.Core.C1_0Sequence
+ Coinbase.Exchange.Types.Core: instance GHC.Generics.Constructor Coinbase.Exchange.Types.Core.C1_1OrderType
+ Coinbase.Exchange.Types.Core: instance GHC.Generics.Datatype Coinbase.Exchange.Types.Core.D1Cost
+ Coinbase.Exchange.Types.Core: instance GHC.Generics.Datatype Coinbase.Exchange.Types.Core.D1OrderType
+ Coinbase.Exchange.Types.Core: instance GHC.Generics.Datatype Coinbase.Exchange.Types.Core.D1Sequence
+ Coinbase.Exchange.Types.Core: instance GHC.Generics.Generic Coinbase.Exchange.Types.Core.Cost
+ Coinbase.Exchange.Types.Core: instance GHC.Generics.Generic Coinbase.Exchange.Types.Core.OrderType
+ Coinbase.Exchange.Types.Core: instance GHC.Generics.Generic Coinbase.Exchange.Types.Core.Sequence
+ Coinbase.Exchange.Types.Core: instance GHC.Generics.Selector Coinbase.Exchange.Types.Core.S1_0_0Cost
+ Coinbase.Exchange.Types.Core: instance GHC.Generics.Selector Coinbase.Exchange.Types.Core.S1_0_0Sequence
+ Coinbase.Exchange.Types.Core: instance GHC.Num.Num Coinbase.Exchange.Types.Core.Cost
+ Coinbase.Exchange.Types.Core: instance GHC.Num.Num Coinbase.Exchange.Types.Core.Sequence
+ Coinbase.Exchange.Types.Core: instance GHC.Read.Read Coinbase.Exchange.Types.Core.Cost
+ Coinbase.Exchange.Types.Core: instance GHC.Read.Read Coinbase.Exchange.Types.Core.OrderType
+ Coinbase.Exchange.Types.Core: instance GHC.Read.Read Coinbase.Exchange.Types.Core.Sequence
+ Coinbase.Exchange.Types.Core: instance GHC.Real.Fractional Coinbase.Exchange.Types.Core.Cost
+ Coinbase.Exchange.Types.Core: instance GHC.Real.Real Coinbase.Exchange.Types.Core.Cost
+ Coinbase.Exchange.Types.Core: instance GHC.Real.RealFrac Coinbase.Exchange.Types.Core.Cost
+ Coinbase.Exchange.Types.Core: instance GHC.Show.Show Coinbase.Exchange.Types.Core.Cost
+ Coinbase.Exchange.Types.Core: instance GHC.Show.Show Coinbase.Exchange.Types.Core.OrderType
+ Coinbase.Exchange.Types.Core: instance GHC.Show.Show Coinbase.Exchange.Types.Core.Sequence
+ Coinbase.Exchange.Types.Core: newtype Cost
+ Coinbase.Exchange.Types.Core: newtype Sequence
+ Coinbase.Exchange.Types.Private: FillOrKill :: OrderContigency
+ Coinbase.Exchange.Types.Private: GoodTillCanceled :: OrderContigency
+ Coinbase.Exchange.Types.Private: ImmediateOrCancel :: OrderContigency
+ Coinbase.Exchange.Types.Private: LimitOrder :: OrderId -> ProductId -> OrderStatus -> SelfTrade -> Bool -> Side -> UTCTime -> Maybe Size -> Maybe Price -> Maybe UTCTime -> Maybe Reason -> Price -> Size -> OrderContigency -> Bool -> Order
+ Coinbase.Exchange.Types.Private: MarketOrder :: OrderId -> ProductId -> OrderStatus -> SelfTrade -> Bool -> Side -> UTCTime -> Maybe Size -> Maybe Price -> Maybe UTCTime -> Maybe Reason -> Either Size (Maybe Size, Cost) -> Order
+ Coinbase.Exchange.Types.Private: NewLimitOrder :: ProductId -> Side -> SelfTrade -> Maybe ClientOrderId -> Price -> Size -> OrderContigency -> Bool -> NewOrder
+ Coinbase.Exchange.Types.Private: NewMarketOrder :: ProductId -> Side -> SelfTrade -> Maybe ClientOrderId -> Either Size (Maybe Size, Cost) -> NewOrder
+ Coinbase.Exchange.Types.Private: [noPostOnly] :: NewOrder -> Bool
+ Coinbase.Exchange.Types.Private: [noSizeAndOrFunds] :: NewOrder -> Either Size (Maybe Size, Cost)
+ Coinbase.Exchange.Types.Private: [noTimeInForce] :: NewOrder -> OrderContigency
+ Coinbase.Exchange.Types.Private: [orderPostOnly] :: Order -> Bool
+ Coinbase.Exchange.Types.Private: [orderSelfTrade] :: Order -> SelfTrade
+ Coinbase.Exchange.Types.Private: [orderSizeAndOrFunds] :: Order -> Either Size (Maybe Size, Cost)
+ Coinbase.Exchange.Types.Private: [orderTimeInForce] :: Order -> OrderContigency
+ Coinbase.Exchange.Types.Private: data OrderContigency
+ Coinbase.Exchange.Types.Private: instance Control.DeepSeq.NFData Coinbase.Exchange.Types.Private.OrderContigency
+ Coinbase.Exchange.Types.Private: instance Data.Aeson.Types.Class.FromJSON Coinbase.Exchange.Types.Private.OrderContigency
+ Coinbase.Exchange.Types.Private: instance Data.Aeson.Types.Class.ToJSON Coinbase.Exchange.Types.Private.OrderContigency
+ Coinbase.Exchange.Types.Private: instance Data.Data.Data Coinbase.Exchange.Types.Private.OrderContigency
+ Coinbase.Exchange.Types.Private: instance Data.Hashable.Class.Hashable Coinbase.Exchange.Types.Private.OrderContigency
+ Coinbase.Exchange.Types.Private: instance GHC.Classes.Eq Coinbase.Exchange.Types.Private.Account
+ Coinbase.Exchange.Types.Private: instance GHC.Classes.Eq Coinbase.Exchange.Types.Private.OrderContigency
+ Coinbase.Exchange.Types.Private: instance GHC.Classes.Ord Coinbase.Exchange.Types.Private.OrderContigency
+ Coinbase.Exchange.Types.Private: instance GHC.Generics.Constructor Coinbase.Exchange.Types.Private.C1_0OrderContigency
+ Coinbase.Exchange.Types.Private: instance GHC.Generics.Constructor Coinbase.Exchange.Types.Private.C1_1NewOrder
+ Coinbase.Exchange.Types.Private: instance GHC.Generics.Constructor Coinbase.Exchange.Types.Private.C1_1Order
+ Coinbase.Exchange.Types.Private: instance GHC.Generics.Constructor Coinbase.Exchange.Types.Private.C1_1OrderContigency
+ Coinbase.Exchange.Types.Private: instance GHC.Generics.Constructor Coinbase.Exchange.Types.Private.C1_2OrderContigency
+ Coinbase.Exchange.Types.Private: instance GHC.Generics.Datatype Coinbase.Exchange.Types.Private.D1OrderContigency
+ Coinbase.Exchange.Types.Private: instance GHC.Generics.Generic Coinbase.Exchange.Types.Private.OrderContigency
+ Coinbase.Exchange.Types.Private: instance GHC.Generics.Selector Coinbase.Exchange.Types.Private.S1_0_12Order
+ Coinbase.Exchange.Types.Private: instance GHC.Generics.Selector Coinbase.Exchange.Types.Private.S1_0_13Order
+ Coinbase.Exchange.Types.Private: instance GHC.Generics.Selector Coinbase.Exchange.Types.Private.S1_0_14Order
+ Coinbase.Exchange.Types.Private: instance GHC.Generics.Selector Coinbase.Exchange.Types.Private.S1_0_6NewOrder
+ Coinbase.Exchange.Types.Private: instance GHC.Generics.Selector Coinbase.Exchange.Types.Private.S1_0_7NewOrder
+ Coinbase.Exchange.Types.Private: instance GHC.Generics.Selector Coinbase.Exchange.Types.Private.S1_1_0NewOrder
+ Coinbase.Exchange.Types.Private: instance GHC.Generics.Selector Coinbase.Exchange.Types.Private.S1_1_0Order
+ Coinbase.Exchange.Types.Private: instance GHC.Generics.Selector Coinbase.Exchange.Types.Private.S1_1_10Order
+ Coinbase.Exchange.Types.Private: instance GHC.Generics.Selector Coinbase.Exchange.Types.Private.S1_1_11Order
+ Coinbase.Exchange.Types.Private: instance GHC.Generics.Selector Coinbase.Exchange.Types.Private.S1_1_1NewOrder
+ Coinbase.Exchange.Types.Private: instance GHC.Generics.Selector Coinbase.Exchange.Types.Private.S1_1_1Order
+ Coinbase.Exchange.Types.Private: instance GHC.Generics.Selector Coinbase.Exchange.Types.Private.S1_1_2NewOrder
+ Coinbase.Exchange.Types.Private: instance GHC.Generics.Selector Coinbase.Exchange.Types.Private.S1_1_2Order
+ Coinbase.Exchange.Types.Private: instance GHC.Generics.Selector Coinbase.Exchange.Types.Private.S1_1_3NewOrder
+ Coinbase.Exchange.Types.Private: instance GHC.Generics.Selector Coinbase.Exchange.Types.Private.S1_1_3Order
+ Coinbase.Exchange.Types.Private: instance GHC.Generics.Selector Coinbase.Exchange.Types.Private.S1_1_4NewOrder
+ Coinbase.Exchange.Types.Private: instance GHC.Generics.Selector Coinbase.Exchange.Types.Private.S1_1_4Order
+ Coinbase.Exchange.Types.Private: instance GHC.Generics.Selector Coinbase.Exchange.Types.Private.S1_1_5Order
+ Coinbase.Exchange.Types.Private: instance GHC.Generics.Selector Coinbase.Exchange.Types.Private.S1_1_6Order
+ Coinbase.Exchange.Types.Private: instance GHC.Generics.Selector Coinbase.Exchange.Types.Private.S1_1_7Order
+ Coinbase.Exchange.Types.Private: instance GHC.Generics.Selector Coinbase.Exchange.Types.Private.S1_1_8Order
+ Coinbase.Exchange.Types.Private: instance GHC.Generics.Selector Coinbase.Exchange.Types.Private.S1_1_9Order
+ Coinbase.Exchange.Types.Private: instance GHC.Read.Read Coinbase.Exchange.Types.Private.OrderContigency
+ Coinbase.Exchange.Types.Private: instance GHC.Show.Show Coinbase.Exchange.Types.Private.OrderContigency
+ Coinbase.Exchange.Types.Socket: (.:??) :: (FromJSON a) => Object -> Text -> Parser (Maybe a)
+ Coinbase.Exchange.Types.Socket: ChangeLimit :: UTCTime -> ProductId -> Sequence -> OrderId -> Side -> Price -> Size -> Size -> ExchangeMessage
+ Coinbase.Exchange.Types.Socket: ChangeMarket :: UTCTime -> ProductId -> Sequence -> OrderId -> Side -> Price -> Cost -> Cost -> ExchangeMessage
+ Coinbase.Exchange.Types.Socket: DoneLimit :: UTCTime -> ProductId -> Sequence -> OrderId -> Side -> Size -> Price -> Reason -> OrderType -> ExchangeMessage
+ Coinbase.Exchange.Types.Socket: DoneMarket :: UTCTime -> ProductId -> Sequence -> OrderId -> Side -> Reason -> OrderType -> ExchangeMessage
+ Coinbase.Exchange.Types.Socket: ReceivedLimit :: UTCTime -> ProductId -> Sequence -> OrderId -> Side -> Maybe ClientOrderId -> Price -> Size -> ExchangeMessage
+ Coinbase.Exchange.Types.Socket: ReceivedMarket :: UTCTime -> ProductId -> Sequence -> OrderId -> Side -> Maybe ClientOrderId -> (Either Size (Maybe Size, Cost)) -> ExchangeMessage
+ Coinbase.Exchange.Types.Socket: [msgMarketBounds] :: ExchangeMessage -> (Either Size (Maybe Size, Cost))
+ Coinbase.Exchange.Types.Socket: [msgNewFunds] :: ExchangeMessage -> Cost
+ Coinbase.Exchange.Types.Socket: [msgOldFunds] :: ExchangeMessage -> Cost
+ Coinbase.Exchange.Types.Socket: [msgOrderType] :: ExchangeMessage -> OrderType
+ Coinbase.Exchange.Types.Socket: instance GHC.Generics.Constructor Coinbase.Exchange.Types.Socket.C1_7ExchangeMessage
+ Coinbase.Exchange.Types.Socket: instance GHC.Generics.Constructor Coinbase.Exchange.Types.Socket.C1_8ExchangeMessage
+ Coinbase.Exchange.Types.Socket: instance GHC.Generics.Constructor Coinbase.Exchange.Types.Socket.C1_9ExchangeMessage
+ Coinbase.Exchange.Types.Socket: instance GHC.Generics.Selector Coinbase.Exchange.Types.Socket.S1_5_8ExchangeMessage
+ Coinbase.Exchange.Types.Socket: instance GHC.Generics.Selector Coinbase.Exchange.Types.Socket.S1_6_1ExchangeMessage
+ Coinbase.Exchange.Types.Socket: instance GHC.Generics.Selector Coinbase.Exchange.Types.Socket.S1_6_2ExchangeMessage
+ Coinbase.Exchange.Types.Socket: instance GHC.Generics.Selector Coinbase.Exchange.Types.Socket.S1_6_3ExchangeMessage
+ Coinbase.Exchange.Types.Socket: instance GHC.Generics.Selector Coinbase.Exchange.Types.Socket.S1_6_4ExchangeMessage
+ Coinbase.Exchange.Types.Socket: instance GHC.Generics.Selector Coinbase.Exchange.Types.Socket.S1_6_5ExchangeMessage
+ Coinbase.Exchange.Types.Socket: instance GHC.Generics.Selector Coinbase.Exchange.Types.Socket.S1_6_6ExchangeMessage
+ Coinbase.Exchange.Types.Socket: instance GHC.Generics.Selector Coinbase.Exchange.Types.Socket.S1_7_0ExchangeMessage
+ Coinbase.Exchange.Types.Socket: instance GHC.Generics.Selector Coinbase.Exchange.Types.Socket.S1_7_1ExchangeMessage
+ Coinbase.Exchange.Types.Socket: instance GHC.Generics.Selector Coinbase.Exchange.Types.Socket.S1_7_2ExchangeMessage
+ Coinbase.Exchange.Types.Socket: instance GHC.Generics.Selector Coinbase.Exchange.Types.Socket.S1_7_3ExchangeMessage
+ Coinbase.Exchange.Types.Socket: instance GHC.Generics.Selector Coinbase.Exchange.Types.Socket.S1_7_4ExchangeMessage
+ Coinbase.Exchange.Types.Socket: instance GHC.Generics.Selector Coinbase.Exchange.Types.Socket.S1_7_5ExchangeMessage
+ Coinbase.Exchange.Types.Socket: instance GHC.Generics.Selector Coinbase.Exchange.Types.Socket.S1_7_6ExchangeMessage
+ Coinbase.Exchange.Types.Socket: instance GHC.Generics.Selector Coinbase.Exchange.Types.Socket.S1_7_7ExchangeMessage
+ Coinbase.Exchange.Types.Socket: instance GHC.Generics.Selector Coinbase.Exchange.Types.Socket.S1_8_0ExchangeMessage
+ Coinbase.Exchange.Types.Socket: instance GHC.Generics.Selector Coinbase.Exchange.Types.Socket.S1_8_1ExchangeMessage
+ Coinbase.Exchange.Types.Socket: instance GHC.Generics.Selector Coinbase.Exchange.Types.Socket.S1_8_2ExchangeMessage
+ Coinbase.Exchange.Types.Socket: instance GHC.Generics.Selector Coinbase.Exchange.Types.Socket.S1_8_3ExchangeMessage
+ Coinbase.Exchange.Types.Socket: instance GHC.Generics.Selector Coinbase.Exchange.Types.Socket.S1_8_4ExchangeMessage
+ Coinbase.Exchange.Types.Socket: instance GHC.Generics.Selector Coinbase.Exchange.Types.Socket.S1_8_5ExchangeMessage
+ Coinbase.Exchange.Types.Socket: instance GHC.Generics.Selector Coinbase.Exchange.Types.Socket.S1_8_6ExchangeMessage
+ Coinbase.Exchange.Types.Socket: instance GHC.Generics.Selector Coinbase.Exchange.Types.Socket.S1_8_7ExchangeMessage
+ Coinbase.Exchange.Types.Socket: instance GHC.Generics.Selector Coinbase.Exchange.Types.Socket.S1_9_0ExchangeMessage
- Coinbase.Exchange.Socket: subscribe :: ApiType -> ProductId -> ClientApp () -> IO ()
+ Coinbase.Exchange.Socket: subscribe :: ApiType -> ProductId -> ClientApp a -> IO a
- Coinbase.Exchange.Types.MarketData: Book :: Word64 -> [Bid a] -> [Ask a] -> Book a
+ Coinbase.Exchange.Types.MarketData: Book :: Sequence -> [Bid a] -> [Ask a] -> Book a
- Coinbase.Exchange.Types.MarketData: Product :: ProductId -> CurrencyId -> CurrencyId -> Scientific -> Scientific -> Scientific -> Text -> Product
+ Coinbase.Exchange.Types.MarketData: Product :: ProductId -> CurrencyId -> CurrencyId -> CoinScientific -> CoinScientific -> CoinScientific -> Text -> Product
- Coinbase.Exchange.Types.MarketData: [bookSequence] :: Book a -> Word64
+ Coinbase.Exchange.Types.MarketData: [bookSequence] :: Book a -> Sequence
- Coinbase.Exchange.Types.MarketData: [prodBaseMaxSize] :: Product -> Scientific
+ Coinbase.Exchange.Types.MarketData: [prodBaseMaxSize] :: Product -> CoinScientific
- Coinbase.Exchange.Types.MarketData: [prodBaseMinSize] :: Product -> Scientific
+ Coinbase.Exchange.Types.MarketData: [prodBaseMinSize] :: Product -> CoinScientific
- Coinbase.Exchange.Types.MarketData: [prodQuoteIncrement] :: Product -> Scientific
+ Coinbase.Exchange.Types.MarketData: [prodQuoteIncrement] :: Product -> CoinScientific
- Coinbase.Exchange.Types.Private: [noSelfTrade] :: NewOrder -> Maybe SelfTrade
+ Coinbase.Exchange.Types.Private: [noSelfTrade] :: NewOrder -> SelfTrade
- Coinbase.Exchange.Types.Socket: Match :: TradeId -> Sequence -> OrderId -> OrderId -> UTCTime -> ProductId -> Size -> Price -> Side -> ExchangeMessage
+ Coinbase.Exchange.Types.Socket: Match :: UTCTime -> ProductId -> Sequence -> Side -> TradeId -> OrderId -> OrderId -> Size -> Price -> ExchangeMessage
- Coinbase.Exchange.Types.Socket: Open :: UTCTime -> ProductId -> Sequence -> OrderId -> Price -> Size -> Side -> ExchangeMessage
+ Coinbase.Exchange.Types.Socket: Open :: UTCTime -> ProductId -> Sequence -> OrderId -> Side -> Size -> Price -> ExchangeMessage

Files

coinbase-exchange.cabal view
@@ -1,5 +1,5 @@ name:                coinbase-exchange-version:             0.2.0.2+version:             0.3.0.0 synopsis:            Connector library for the coinbase exchange. description:         Access library for the coinbase exchange. Allows the use                      of both the public market data API as well as the private@@ -11,7 +11,7 @@ maintainer:          andrewrademacher@gmail.com category:            Web build-type:          Simple-cabal-version:       >=1.10+cabal-version:       >=1.20  library     hs-source-dirs:     src@@ -29,19 +29,19 @@     other-modules:      Coinbase.Exchange.Rest      build-depends:      base                ==4.*-                    ,   mtl+                    ,   mtl                 >=2.2                     ,   resourcet                     ,   transformers-base                     ,   conduit                     ,   conduit-extra                     ,   http-conduit-                    ,   aeson+                    ,   aeson               >=0.10.0                     ,   aeson-casing                     ,   http-types                     ,   text                     ,   bytestring                     ,   base64-bytestring-                    ,   time+                    ,   time                >=1.5                     ,   scientific                     ,   uuid                     ,   uuid-aeson@@ -54,6 +54,7 @@                     ,   cryptohash                     ,   byteable                     ,   exceptions+                    ,   unordered-containers                      ,   old-locale @@ -68,7 +69,7 @@                      ,   uuid                     ,   text-                    ,   aeson+                    ,   aeson               >=0.10.0                     ,   bytestring                     ,   time                     ,   old-locale@@ -81,6 +82,7 @@                     ,   network                     ,   wuss                     ,   scientific+                    ,   unordered-containers                      ,   coinbase-exchange @@ -88,6 +90,7 @@     type:               exitcode-stdio-1.0     main-is:            Main.hs     hs-source-dirs:     test+    ghc-options:        -threaded     default-language:   Haskell2010      build-depends:      base                ==4.*@@ -103,5 +106,11 @@                     ,   http-client-tls                     ,   http-conduit                     ,   transformers+                    ,   random+                    ,   scientific+                    ,   async+                    ,   websockets+                    ,   aeson               >=0.10.0+                    ,   unordered-containers                      ,   coinbase-exchange
sbox/Main.hs view
@@ -24,10 +24,7 @@ import           Coinbase.Exchange.Types.Socket  main :: IO ()-main = putStrLn "Use GHCi."--testCoinbaseTime :: String-testCoinbaseTime = "2015-05-06 21:58:22.84227+0000"+main = printSocket -- putStrLn "Use GHCi."  btc :: ProductId btc = "BTC-USD"@@ -38,9 +35,6 @@ end :: Maybe UTCTime end = Just $ parseTimeOrError True defaultTimeLocale "%FT%X%z" "2015-04-23T20:22:37+0000" -accountId :: AccountId-accountId = AccountId $ fromJust $ fromString "52072cbb-4e76-496f-a479-166cb4d177fa"- withCoinbase :: Exchange a -> IO a withCoinbase act = do         mgr     <- newManager tlsManagerSettings@@ -49,7 +43,7 @@         tPass   <- liftM CBS.pack $ getEnv "COINBASE_PASSPHRASE"          case mkToken tKey tSecret tPass of-            Right tok -> do res <- runExchange (ExchangeConf mgr (Just tok) Sandbox) act+            Right tok -> do res <- runExchange (ExchangeConf mgr (Just tok) Live) act                             case res of                                 Right s -> return s                                 Left  f -> error $ show f
src/Coinbase/Exchange/Rest.hs view
@@ -32,6 +32,8 @@  import           Coinbase.Exchange.Types +-- import Debug.Trace+ type Signed = Bool  voidBody :: Maybe ()@@ -122,7 +124,7 @@                 => Response (ResumableSource m BS.ByteString) -> m b processResponse res =     case responseStatus res of-        s | s == status200 -> do body <- responseBody res $$+- sinkParser (fmap fromJSON json)+        s | s == status200 -> do body <- responseBody res $$+- sinkParser (fmap {-(\x -> trace (show x) fromJSON x)-} fromJSON json)                                  case body of                                      Success b -> return b                                      Error  er -> throwError $ ParseFailure $ T.pack er
src/Coinbase/Exchange/Socket.hs view
@@ -14,7 +14,7 @@ import           Coinbase.Exchange.Types.Core import           Coinbase.Exchange.Types.Socket -subscribe :: ApiType -> ProductId -> WS.ClientApp () -> IO ()+subscribe :: ApiType -> ProductId -> WS.ClientApp a -> IO a subscribe atype pid app = withSocketsDo $         runSecureClient location 443 "/" $ \conn -> do             WS.sendBinaryData conn $ encode (Subscribe pid)
src/Coinbase/Exchange/Types/Core.hs view
@@ -23,6 +23,7 @@ import           Data.UUID.Aeson     () import           Data.Word import           GHC.Generics+import           Text.Read           (readMaybe)   newtype ProductId = ProductId { unProductId :: Text }@@ -34,12 +35,18 @@ newtype Size = Size { unSize :: CoinScientific }     deriving (Eq, Ord, Num, Fractional, Real, RealFrac, Show, Read, Data, Typeable, Generic, NFData, Hashable, FromJSON, ToJSON) +newtype Cost = Cost { unCost :: CoinScientific }+    deriving (Eq, Ord, Num, Fractional, Real, RealFrac, Show, Read, Data, Typeable, Generic, NFData, Hashable, FromJSON, ToJSON)+ newtype OrderId = OrderId { unOrderId :: UUID }     deriving (Eq, Ord, Show, Read, Data, Typeable, Generic, NFData, Hashable, FromJSON, ToJSON)  newtype Aggregate = Aggregate { unAggregate :: Int64 }     deriving (Eq, Ord, Show, Read, Num, Data, Typeable, Generic, NFData, Hashable, FromJSON, ToJSON) +newtype Sequence = Sequence { unSequence :: Word64 }+    deriving (Eq, Ord, Num, Show, Read, Data, Typeable, Generic, NFData, Hashable, FromJSON, ToJSON)+ --  data Side = Buy | Sell@@ -53,7 +60,18 @@     parseJSON = genericParseJSON coinbaseAesonOptions  --+data OrderType = Limit | Market+    deriving (Eq, Ord, Show, Read, Data, Typeable, Generic) +instance NFData OrderType+instance Hashable OrderType+instance ToJSON OrderType where+    toJSON = genericToJSON coinbaseAesonOptions+instance FromJSON OrderType where+    parseJSON = genericParseJSON coinbaseAesonOptions++--+ newtype TradeId = TradeId { unTradeId :: Word64 }     deriving (Eq, Ord, Num, Show, Read, Data, Typeable, Generic, NFData, Hashable) @@ -111,29 +129,9 @@     toJSON (CoinScientific v) = String . T.pack . show $ v instance FromJSON CoinScientific where     parseJSON = withText "CoinScientific" $ \t ->-        case maybeRead (T.unpack t) of+        case readMaybe (T.unpack t) of             Just  n -> pure $ CoinScientific n             Nothing -> fail "Could not parse string scientific."--maybeRead :: (Read a) => String -> Maybe a-maybeRead = fmap fst . listToMaybe . reads--------newtype CoinbaseTime = CoinbaseTime { unCoinbaseTime :: UTCTime }-    deriving (Eq, Ord, Show, Read, Data, Typeable, NFData)--instance ToJSON CoinbaseTime where-    toJSON (CoinbaseTime t) = String $ T.pack $-        formatTime defaultTimeLocale coinbaseTimeFormat t ++ "00"-instance FromJSON CoinbaseTime where-    parseJSON = withText "Coinbase Time" $ \t ->-        case parseTimeM True defaultTimeLocale coinbaseTimeFormat (T.unpack t ++ "00") of-            Just d -> pure $ CoinbaseTime d-            _      -> fail "could not parse coinbase time format."--coinbaseTimeFormat :: String-coinbaseTimeFormat = "%F %T%Q%z"  ---- 
src/Coinbase/Exchange/Types/MarketData.hs view
@@ -16,7 +16,6 @@ import           Data.Data import           Data.Hashable import           Data.Int-import           Data.Scientific import           Data.String import           Data.Text                    (Text) import           Data.Time@@ -35,9 +34,9 @@         { prodId             :: ProductId         , prodBaseCurrency   :: CurrencyId         , prodQuoteCurrency  :: CurrencyId-        , prodBaseMinSize    :: Scientific-        , prodBaseMaxSize    :: Scientific-        , prodQuoteIncrement :: Scientific+        , prodBaseMinSize    :: CoinScientific+        , prodBaseMaxSize    :: CoinScientific+        , prodQuoteIncrement :: CoinScientific         , prodDisplayName    :: Text         }     deriving (Show, Data, Typeable, Generic)@@ -52,7 +51,7 @@  data Book a     = Book-        { bookSequence :: Word64+        { bookSequence :: Sequence         , bookBids     :: [Bid a]         , bookAsks     :: [Ask a]         }@@ -113,14 +112,14 @@  instance NFData Trade instance ToJSON Trade where-    toJSON Trade{..} = object [ "time"      .= CoinbaseTime tradeTime+    toJSON Trade{..} = object [ "time"      .= tradeTime                               , "trade_id"  .= tradeTradeId                               , "price"     .= tradePrice                               , "size"      .= tradeSize                               , "side"      .= tradeSide                               ] instance FromJSON Trade where-    parseJSON (Object m) = Trade <$> liftM unCoinbaseTime (m .: "time")+    parseJSON (Object m) = Trade <$> m .: "time"                                  <*> m .: "trade_id"                                  <*> m .: "price"                                  <*> m .: "size"
src/Coinbase/Exchange/Types/Private.hs view
@@ -37,7 +37,7 @@         , accAvailable :: CoinScientific         , accCurrency  :: CurrencyId         }-    deriving (Show, Data, Typeable, Generic)+    deriving (Show, Eq, Data, Typeable, Generic)  instance NFData Account instance ToJSON Account where@@ -64,7 +64,7 @@ instance NFData Entry instance ToJSON Entry where     toJSON Entry{..} = object [ "id"         .= entryId-                              , "created_at" .= CoinbaseTime entryCreatedAt+                              , "created_at" .= entryCreatedAt                               , "amount"     .= entryAmount                               , "balance"    .= entryBalance                               , "type"       .= entryType@@ -73,7 +73,7 @@ instance FromJSON Entry where     parseJSON (Object m) = Entry         <$> m .: "id"-        <*> liftM unCoinbaseTime (m .: "created_at")+        <*> m .: "created_at"         <*> m .: "amount"         <*> m .: "balance"         <*> m .: "type"@@ -138,7 +138,25 @@     parseJSON = genericParseJSON coinbaseAesonOptions  -- Orders+data OrderContigency+    = GoodTillCanceled+    | ImmediateOrCancel+    | FillOrKill+    deriving (Eq, Ord, Show, Read, Data, Typeable, Generic) +instance NFData   OrderContigency+instance Hashable OrderContigency++instance ToJSON OrderContigency where+    toJSON GoodTillCanceled  = String "GTC"+    toJSON ImmediateOrCancel = String "IOC"+    toJSON FillOrKill        = String "FOK"+instance FromJSON OrderContigency where+    parseJSON (String "GTC") = return GoodTillCanceled+    parseJSON (String "IOC") = return ImmediateOrCancel+    parseJSON (String "FOK") = return FillOrKill+    parseJSON _ = mzero+ data SelfTrade     = DecrementAndCancel     | CancelOldest@@ -161,22 +179,61 @@     parseJSON _ = mzero  data NewOrder-    = NewOrder-        { noSize      :: Size+    = NewLimitOrder+        { noProductId :: ProductId+        , noSide      :: Side+        , noSelfTrade :: SelfTrade+        , noClientOid :: Maybe ClientOrderId+        ---         , noPrice     :: Price+        , noSize      :: Size+        ,noTimeInForce:: OrderContigency+        , noPostOnly  :: Bool+        }+    | NewMarketOrder+        { noProductId :: ProductId         , noSide      :: Side-        , noProductId :: ProductId+        , noSelfTrade :: SelfTrade         , noClientOid :: Maybe ClientOrderId-        , noSelfTrade :: Maybe SelfTrade+        ---+        , noSizeAndOrFunds  :: Either Size (Maybe Size, Cost)         }     deriving (Show, Data, Typeable, Generic)  instance NFData NewOrder instance ToJSON NewOrder where-    toJSON = genericToJSON coinbaseAesonOptions-instance FromJSON NewOrder where-    parseJSON = genericParseJSON coinbaseAesonOptions+        toJSON NewLimitOrder{..} = object+           ([ "type" .= ("limit" :: Text)+            , "product_id"    .= noProductId+            , "side"          .= noSide+            , "stp"           .= noSelfTrade+            , "price"         .= noPrice+            , "size"          .= noSize+            , "time_in_force" .= noTimeInForce+            , "post_only"     .= noPostOnly+            ] ++ clientID )+            where+                clientID = case noClientOid of+                                Just cid -> [ "client_oid" .= cid ]+                                Nothing  -> [] +        toJSON NewMarketOrder{..} = object+           ([ "type" .= ("market" :: Text)+            , "product_id"    .= noProductId+            , "side"          .= noSide+            , "stp"           .= noSelfTrade+            ] ++ clientID ++ size ++ funds )+            where+                clientID = case noClientOid of+                                Just cid -> [ "client_oid" .= cid ]+                                Nothing  -> []+                (size,funds) = case noSizeAndOrFunds of+                                Left  s -> (["size" .= s],[])+                                Right (ms,f) -> case ms of+                                            Nothing -> ( []            , ["funds" .= f] )+                                            Just s' -> ( ["size" .= s'], ["funds" .= f] )++ data OrderConfirmation     = OrderConfirmation         { ocId :: OrderId@@ -190,52 +247,127 @@     parseJSON = genericParseJSON coinbaseAesonOptions  data Order-    = Order+    = LimitOrder         { orderId         :: OrderId-        , orderSize       :: Size-        , orderPrice      :: Price         , orderProductId  :: ProductId         , orderStatus     :: OrderStatus+        , orderSelfTrade  :: SelfTrade+        , orderSettled    :: Bool+        , orderSide       :: Side+        , orderCreatedAt  :: UTCTime         , orderFilledSize :: Maybe Size         , orderFilledFees :: Maybe Price+        , orderDoneAt     :: Maybe UTCTime+        , orderDoneReason :: Maybe Reason++        , orderPrice      :: Price+        , orderSize       :: Size+        , orderTimeInForce:: OrderContigency+        , orderPostOnly   :: Bool+        }+    | MarketOrder+        { orderId         :: OrderId+        , orderProductId  :: ProductId+        , orderStatus     :: OrderStatus+        , orderSelfTrade  :: SelfTrade         , orderSettled    :: Bool         , orderSide       :: Side         , orderCreatedAt  :: UTCTime+        , orderFilledSize :: Maybe Size+        , orderFilledFees :: Maybe Price         , orderDoneAt     :: Maybe UTCTime         , orderDoneReason :: Maybe Reason++        , orderSizeAndOrFunds  :: Either Size (Maybe Size, Cost)         }     deriving (Show, Data, Typeable, Generic)  instance NFData Order instance ToJSON Order where-    toJSON Order{..} = object-        [ "id"          .= orderId-        , "size"        .= orderSize-        , "price"       .= orderPrice-        , "product_id"  .= orderProductId-        , "status"      .= orderStatus-        , "filled_size" .= orderFilledSize-        , "filled_fees" .= orderFilledFees-        , "settled"     .= orderSettled-        , "side"        .= orderSide-        , "created_at"  .= CoinbaseTime orderCreatedAt-        , "done_at"     .= liftM CoinbaseTime orderDoneAt-        , "done_reason" .= orderDoneReason+    toJSON LimitOrder{..} = object+        [ "type" .= ("limit" :: Text)+        , "id"            .= orderId+        , "product_id"    .= orderProductId+        , "status"        .= orderStatus+        , "stp"           .= orderSelfTrade+        , "settled"       .= orderSettled+        , "side"          .= orderSide+        , "created_at"    .= orderCreatedAt+        , "filled_size"   .= orderFilledSize+        , "filled_fees"   .= orderFilledFees+        , "done_at"       .= orderDoneAt+        , "done_reason"   .= orderDoneReason++        , "price"         .= orderPrice+        , "size"          .= orderSize+        , "time_in_force" .= orderTimeInForce+        , "post_only"     .= orderPostOnly         ]+    toJSON MarketOrder{..} = object+       ([ "type" .= ("market" :: Text)+        , "id"            .= orderId+        , "product_id"    .= orderProductId+        , "status"        .= orderStatus+        , "stp"           .= orderSelfTrade+        , "settled"       .= orderSettled+        , "side"          .= orderSide+        , "created_at"    .= orderCreatedAt+        , "filled_size"   .= orderFilledSize+        , "filled_fees"   .= orderFilledFees+        , "done_at"       .= orderDoneAt+        , "done_reason"   .= orderDoneReason+        ] ++ size ++ funds )+            where (size,funds) = case orderSizeAndOrFunds of+                        Left  s -> (["size" .= s],[])+                        Right (ms,f) -> case ms of+                                    Nothing -> ( []            , ["funds" .= f] )+                                    Just s' -> ( ["size" .= s'], ["funds" .= f] )++ instance FromJSON Order where-    parseJSON (Object m) = Order-        <$> m .: "id"-        <*> m .: "size"-        <*> m .: "price"-        <*> m .: "product_id"-        <*> m .: "status"-        <*> m .:? "filled_size"-        <*> m .:? "filled_fees"-        <*> m .: "settled"-        <*> m .: "side"-        <*> liftM unCoinbaseTime (m .: "created_at")-        <*> liftM (liftM unCoinbaseTime) (m .:? "done_at")-        <*> m .:? "done_reason"+    parseJSON (Object m) = do+        ordertype <- m .: "type"+        case (ordertype :: String) of+            "limit" -> LimitOrder+                <$> m .: "id"+                <*> m .: "product_id"+                <*> m .: "status"+                <*> m .: "stp"+                <*> m .: "settled"+                <*> m .: "side"+                <*> m .: "created_at"+                <*> m .:? "filled_size"+                <*> m .:? "filled_fees"+                <*> m .:? "done_at"+                <*> m .:? "done_reason"+                <*> m .: "price"+                <*> m .: "size"+                <*> m .:? "time_in_force" .!= GoodTillCanceled -- older orders don't seem to have this field+                <*> m .: "post_only"++            "market" -> MarketOrder+                <$> m .: "id"+                <*> m .: "product_id"+                <*> m .: "status"+                <*> m .: "stp"+                <*> m .: "settled"+                <*> m .: "side"+                <*> m .: "created_at"+                <*> m .:? "filled_size"+                <*> m .:? "filled_fees"+                <*> m .:? "done_at"+                <*> m .:? "done_reason"+                <*> (do+                        ms <- m .:? "size"+                        mf <- m .:? "funds"+                        case (ms,mf) of+                            (Nothing, Nothing) -> mzero+                            (Just s , Nothing) -> return $ Left  s+                            (Nothing, Just f ) -> return $ Right (Nothing, f)+                            (Just s , Just f ) -> return $ Right (Just s , f)+                            )+            _ -> mzero+     parseJSON _ = mzero  -- Fills@@ -278,7 +410,7 @@         , "price"       .= fillPrice         , "size"        .= fillSize         , "order_id"    .= fillOrderId-        , "created_at"  .= CoinbaseTime fillCreatedAt+        , "created_at"  .= fillCreatedAt         , "liquidity"   .= fillLiquidity         , "fee"         .= fillFee         , "settled"     .= fillSettled@@ -291,7 +423,7 @@         <*> m .: "price"         <*> m .: "size"         <*> m .: "order_id"-        <*> liftM unCoinbaseTime (m .: "created_at")+        <*> m .: "created_at"         <*> m .: "liquidity"         <*> m .: "fee"         <*> m .: "settled"
src/Coinbase/Exchange/Types/Socket.hs view
@@ -2,75 +2,108 @@ {-# LANGUAGE DeriveGeneric              #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE OverloadedStrings          #-}+{-# LANGUAGE RecordWildCards            #-} + module Coinbase.Exchange.Types.Socket where  import           Control.DeepSeq-import           Data.Aeson.Types+import           Control.Monad+import           Data.Aeson.Types      hiding (Error) import           Data.Data import           Data.Hashable import           Data.Text                    (Text) import           Data.Time import           Data.Word import           GHC.Generics--import           Coinbase.Exchange.Types.Core+import qualified Data.HashMap.Strict as H -newtype Sequence = Sequence { unSequence :: Word64 }-    deriving (Eq, Ord, Num, Show, Read, Data, Typeable, Generic, NFData, Hashable, FromJSON, ToJSON)+import           Coinbase.Exchange.Types.Core  hiding (OrderStatus(..))  data ExchangeMessage     = Subscribe         { msgProductId :: ProductId         }-    | Received+    | ReceivedLimit         { msgTime      :: UTCTime         , msgProductId :: ProductId         , msgSequence  :: Sequence         , msgOrderId   :: OrderId-        , msgSize      :: Size+        , msgSide      :: Side+        , msgClientOid :: Maybe ClientOrderId+        --         , msgPrice     :: Price+        , msgSize      :: Size+        }+    | ReceivedMarket+        { msgTime      :: UTCTime+        , msgProductId :: ProductId+        , msgSequence  :: Sequence+        , msgOrderId   :: OrderId         , msgSide      :: Side         , msgClientOid :: Maybe ClientOrderId+        -- market orders have no price and are bounded by either size, funds or both+        , msgMarketBounds :: (Either Size (Maybe Size, Cost))         }     | Open         { msgTime          :: UTCTime         , msgProductId     :: ProductId         , msgSequence      :: Sequence         , msgOrderId       :: OrderId-        , msgPrice         :: Price-        , msgRemainingSize :: Size         , msgSide          :: Side-        }-    | Done-        { msgTime      :: UTCTime-        , msgProductId :: ProductId-        , msgSequence  :: Sequence-        , msgPrice     :: Price-        , msgOrderId   :: OrderId-        , msgReason    :: Reason-        , msgSide      :: Side+        , msgRemainingSize :: Size+        , msgPrice         :: Price         }     | Match-        { msgTradeId      :: TradeId+        { msgTime         :: UTCTime+        , msgProductId    :: ProductId         , msgSequence     :: Sequence+        , msgSide         :: Side+        , msgTradeId      :: TradeId         , msgMakerOrderId :: OrderId         , msgTakerOrderId :: OrderId-        , msgTime         :: UTCTime-        , msgProductId    :: ProductId         , msgSize         :: Size         , msgPrice        :: Price-        , msgSide         :: Side         }-    | Change+    | DoneLimit         { msgTime      :: UTCTime+        , msgProductId :: ProductId         , msgSequence  :: Sequence         , msgOrderId   :: OrderId+        , msgSide      :: Side+        , msgRemainingSize :: Size+        , msgPrice     :: Price+        , msgReason    :: Reason+        , msgOrderType :: OrderType+        }+    | DoneMarket+        { msgTime      :: UTCTime         , msgProductId :: ProductId+        , msgSequence  :: Sequence+        , msgOrderId   :: OrderId+        , msgSide      :: Side+        , msgReason    :: Reason+        , msgOrderType :: OrderType+        }+    | ChangeLimit+        { msgTime      :: UTCTime+        , msgProductId :: ProductId+        , msgSequence  :: Sequence+        , msgOrderId   :: OrderId+        , msgSide      :: Side+        , msgPrice     :: Price         , msgNewSize   :: Size         , msgOldSize   :: Size-        , msgPrice     :: Price+        }+    | ChangeMarket+        { msgTime      :: UTCTime+        , msgProductId :: ProductId+        , msgSequence  :: Sequence+        , msgOrderId   :: OrderId         , msgSide      :: Side+        , msgPrice     :: Price+        , msgNewFunds  :: Cost+        , msgOldFunds  :: Cost         }     | Error         { msgMessage :: Text@@ -78,7 +111,225 @@     deriving (Eq, Show, Read, Data, Typeable, Generic)  instance NFData ExchangeMessage-instance ToJSON ExchangeMessage where-    toJSON = genericToJSON coinbaseAesonOptions++----------------------------- instance FromJSON ExchangeMessage where-    parseJSON = genericParseJSON coinbaseAesonOptions+    parseJSON (Object m) = do+        msgtype <- m .: "type"+        case (msgtype :: String) of+            "open" -> Open+                <$> m .: "time"+                <*> m .: "product_id"+                <*> m .: "sequence"+                <*> m .: "order_id"+                <*> m .: "side"+                <*> m .: "remaining_size"+                <*> m .: "price"+            "done" -> do+                typ  <- m .: "order_type"+                case typ of+                    Limit -> DoneLimit+                        <$> m .: "time"+                        <*> m .: "product_id"+                        <*> m .: "sequence"+                        <*> m .: "order_id"+                        <*> m .: "side"+                        <*> m .: "remaining_size"+                        <*> m .: "price"+                        <*> m .: "reason"+                        <*> m .: "order_type"+                    Market -> DoneMarket+                        <$> m .: "time"+                        <*> m .: "product_id"+                        <*> m .: "sequence"+                        <*> m .: "order_id"+                        <*> m .: "side"+                        <*> m .: "reason"+                        <*> m .: "order_type"+            "match" -> Match+                <$> m .: "time"+                <*> m .: "product_id"+                <*> m .: "sequence"+                <*> m .: "side"+                <*> m .: "trade_id"+                <*> m .: "maker_order_id"+                <*> m .: "taker_order_id"+                <*> m .: "size"+                <*> m .: "price"+            "change" -> do+                ms <- m .:? "new_size"+                case (ms :: Maybe Size) of+                    Nothing -> ChangeMarket+                                <$> m .: "time"+                                <*> m .: "product_id"+                                <*> m .: "sequence"+                                <*> m .: "order_id"+                                <*> m .: "side"+                                <*> m .: "price"+                                <*> m .: "new_funds"+                                <*> m .: "old_funds"+                    Just _ -> ChangeLimit+                                <$> m .: "time"+                                <*> m .: "product_id"+                                <*> m .: "sequence"+                                <*> m .: "order_id"+                                <*> m .: "side"+                                <*> m .: "price"+                                <*> m .: "new_size"+                                <*> m .: "old_size"+            "received" -> do+                typ  <- m .:  "order_type"+                mcid <- m .:? "client_id"+                case typ of+                    Limit -> ReceivedLimit+                                <$> m .: "time"+                                <*> m .: "product_id"+                                <*> m .: "sequence"+                                <*> m .: "order_id"+                                <*> m .: "side"+                                <*> pure (mcid :: Maybe ClientOrderId)+                                <*> m .: "price"+                                <*> m .: "size"+                    Market -> ReceivedMarket+                                <$> m .: "time"+                                <*> m .: "product_id"+                                <*> m .: "sequence"+                                <*> m .: "order_id"+                                <*> m .: "side"+                                <*> pure mcid+                                <*> (do+                                        -- I can't try to parse "size" or "funds" with (.:?) here, their type is CoinScientific+                                        -- but the fields may be "size":null and that will fail the (m .:? "size") parser.+                                        ms <- m .:?? "size"+                                        mf <- m .:?? "funds"+                                        case (ms,mf) of+                                            (Nothing, Nothing) -> mzero+                                            (Just s , Nothing) -> return $ Left  s+                                            (Nothing, Just f ) -> return $ Right (Nothing, f)+                                            (Just s , Just f ) -> return $ Right (Just s , f)+                                            )++    parseJSON _ = mzero++---------------------------+-- This is based on the code for Aeson's (.:?) operator. Except, we're more+-- lax than (.:?) and also return 'Nothing' when the field is (JSON) null.+(.:??) :: (FromJSON a) => Object -> Text -> Parser (Maybe a)+obj .:?? key = case H.lookup key obj of+               Nothing -> pure Nothing+               Just v  -> if v == Null+                   then pure Nothing+                   else obj .:? key++---------------------------++instance ToJSON ExchangeMessage where+    toJSON Subscribe{..} = object+        [ "type"       .= ("subscribe" :: Text)+        , "product_id" .= msgProductId+        ]+    toJSON Open{..} = object+        [ "type"       .= ("open" :: Text)+        , "time"       .= msgTime+        , "product_id" .= msgProductId+        , "sequence"   .= msgSequence+        , "order_id"   .= msgOrderId+        , "side"       .= msgSide+        , "remaining_size" .= msgRemainingSize+        , "price"      .= msgPrice+        ]+    toJSON DoneLimit{..} = object+        [ "type"       .= ("done" :: Text)+        , "time"       .= msgTime+        , "product_id" .= msgProductId+        , "sequence"   .= msgSequence+        , "order_id"   .= msgOrderId+        , "side"       .= msgSide+        , "remaining_size" .= msgRemainingSize+        , "price"      .= msgPrice+        , "reason"     .= msgReason+        , "order_type" .= Limit+        ]+    toJSON DoneMarket{..} = object+        [ "type"       .= ("done" :: Text)+        , "time"       .= msgTime+        , "product_id" .= msgProductId+        , "sequence"   .= msgSequence+        , "order_id"   .= msgOrderId+        , "side"       .= msgSide+        , "reason"     .= msgReason+        , "order_type" .= Market+        ]+    toJSON Match{..} = object+        [ "type"       .= ("match" :: Text)+        , "time"       .= msgTime+        , "product_id" .= msgProductId+        , "sequence"   .= msgSequence+        , "side"       .= msgSide+        , "trade_id"   .= msgTradeId+        , "maker_order_id" .= msgMakerOrderId+        , "taker_order_id" .= msgTakerOrderId+        , "size"       .= msgSize+        , "price"      .= msgPrice+        ]+    toJSON Error{..} = object+        [ "type" .= ("error" :: Text)+        , "message" .= msgMessage+        ]+    toJSON ChangeLimit{..} = object+        [ "type"       .= ("change" :: Text)+        , "time"       .= msgTime+        , "product_id" .= msgProductId+        , "sequence"   .= msgSequence+        , "order_id"   .= msgOrderId+        , "side"       .= msgSide+        , "new_size"   .= msgNewSize+        , "old_size"   .= msgOldSize+        , "price"      .= msgPrice+        ]+    toJSON ChangeMarket{..} = object+        [ "type"       .= ("change" :: Text)+        , "time"       .= msgTime+        , "product_id" .= msgProductId+        , "sequence"   .= msgSequence+        , "order_id"   .= msgOrderId+        , "side"       .= msgSide+        , "price"      .= msgPrice+        , "new_funds"  .= msgNewFunds+        , "old_funds"  .= msgOldFunds+        ]++    toJSON ReceivedLimit{..} = object (+        [ "type"       .= ("received" :: Text)+        , "time"       .= msgTime+        , "product_id" .= msgProductId+        , "sequence"   .= msgSequence+        , "order_id"   .= msgOrderId+        , "side"       .= msgSide+        , "size"       .= msgSize+        , "price"      .= msgPrice+        , "order_type" .= Limit+        ] ++ clientID)+            where+                clientID = case msgClientOid of+                    Nothing -> []+                    Just ci -> ["client_id" .= msgClientOid ]++    toJSON ReceivedMarket{..} = object (+        ["type"       .= ("received" :: Text)+        , "time"       .= msgTime+        , "product_id" .= msgProductId+        , "sequence"   .= msgSequence+        , "order_id"   .= msgOrderId+        , "side"       .= msgSide+        , "order_type" .= Market+        ] ++ clientID ++ size ++ funds)+            where+                clientID = case msgClientOid of+                    Nothing -> []+                    Just ci -> ["client_id" .= msgClientOid ]+                (size,funds) = case msgMarketBounds of+                    Left  s -> (["size" .= s],[])+                    Right (ms,f) -> case ms of+                                Nothing -> ( []            , ["funds" .= f] )+                                Just s' -> ( ["size" .= s'], ["funds" .= f] )
test/Main.hs view
@@ -11,6 +11,8 @@  import qualified Coinbase.Exchange.MarketData.Test as MarketData import qualified Coinbase.Exchange.Private.Test    as Private+import qualified Coinbase.Exchange.Socket.Test     as Socket+ main :: IO () main = do         mgr     <- newManager tlsManagerSettings@@ -19,11 +21,12 @@         tPass   <- liftM CBS.pack $ getEnv "COINBASE_PASSPHRASE"          case mkToken tKey tSecret tPass of-            Right tok -> defaultMain (tests $ ExchangeConf mgr (Just tok) Sandbox)+            Right tok -> defaultMain (tests $ ExchangeConf mgr (Just tok) Live)             Left   er -> error $ show er  tests :: ExchangeConf -> TestTree tests conf = testGroup "Tests"         [ MarketData.tests conf-        , Private.tests conf+        , Private.tests    conf+        , Socket.tests     conf         ]