{-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RecordWildCards #-} module Coinbase.Exchange.Types.MarketData where import Control.Applicative import Control.DeepSeq import Control.Monad.Except import Data.Aeson.Casing import Data.Aeson.Types import Data.Data import Data.Hashable import Data.Int import Data.Scientific import Data.String import Data.Text (Text) import Data.Time import Data.Time.Clock.POSIX import Data.UUID.Aeson () import qualified Data.Vector as V import Data.Word import GHC.Generics import Coinbase.Exchange.Types.Core hiding (OrderStatus (..)) -- Products data Product = Product { prodId :: ProductId , prodBaseCurrency :: CurrencyId , prodQuoteCurrency :: CurrencyId , prodBaseMinSize :: Scientific , prodBaseMaxSize :: Scientific , prodQuoteIncrement :: Scientific , prodDisplayName :: Text } deriving (Show, Data, Typeable, Generic) instance NFData Product instance ToJSON Product where toJSON = genericToJSON coinbaseAesonOptions instance FromJSON Product where parseJSON = genericParseJSON coinbaseAesonOptions -- Order Book data Book a = Book { bookSequence :: Word64 , bookBids :: [Bid a] , bookAsks :: [Ask a] } deriving (Show, Data, Typeable, Generic) instance (NFData a) => NFData (Book a) instance (ToJSON a) => ToJSON (Book a) where toJSON = genericToJSON coinbaseAesonOptions instance (FromJSON a) => FromJSON (Book a) where parseJSON = genericParseJSON coinbaseAesonOptions data Ask a = Ask Price Size a deriving (Eq, Ord, Show, Read, Data, Typeable, Generic) instance (NFData a) => NFData (Ask a) instance (ToJSON a) => ToJSON (Ask a) where toJSON = genericToJSON defaultOptions instance (FromJSON a) => FromJSON (Ask a) where parseJSON = genericParseJSON defaultOptions data Bid a = Bid Price Size a deriving (Eq, Ord, Show, Read, Data, Typeable, Generic) instance (NFData a) => NFData (Bid a) instance (ToJSON a) => ToJSON (Bid a) where toJSON = genericToJSON defaultOptions instance (FromJSON a) => FromJSON (Bid a) where parseJSON = genericParseJSON defaultOptions -- Product Ticker data Tick = Tick { tickTradeId :: Word64 , tickPrice :: Price , tickSize :: Size , tickTime :: Maybe UTCTime } deriving (Show, Data, Typeable, Generic) instance NFData Tick instance ToJSON Tick where toJSON = genericToJSON coinbaseAesonOptions instance FromJSON Tick where parseJSON = genericParseJSON coinbaseAesonOptions -- Product Trades data Trade = Trade { tradeTime :: UTCTime , tradeTradeId :: TradeId , tradePrice :: Price , tradeSize :: Size , tradeSide :: Side } deriving (Show, Data, Typeable, Generic) instance NFData Trade instance ToJSON Trade where toJSON Trade{..} = object [ "time" .= CoinbaseTime tradeTime , "trade_id" .= tradeTradeId , "price" .= tradePrice , "size" .= tradeSize , "side" .= tradeSide ] instance FromJSON Trade where parseJSON (Object m) = Trade <$> liftM unCoinbaseTime (m .: "time") <*> m .: "trade_id" <*> m .: "price" <*> m .: "size" <*> m .: "side" parseJSON _ = mzero -- Historic Rates (Candles) data Candle = Candle UTCTime Low High Open Close Volume deriving (Show, Data, Typeable, Generic) instance NFData Candle instance FromJSON Candle where parseJSON (Array v) = case V.length v of 6 -> Candle <$> liftM (posixSecondsToUTCTime . fromIntegral) (parseJSON (v V.! 0) :: Parser Int64) <*> parseJSON (v V.! 1) <*> parseJSON (v V.! 2) <*> parseJSON (v V.! 3) <*> parseJSON (v V.! 4) <*> parseJSON (v V.! 5) _ -> mzero parseJSON _ = mzero newtype Low = Low { unLow :: Double } deriving (Eq, Ord, Num, Fractional, Real, RealFrac, Show, Read, Data, Typeable, Generic, NFData, Hashable, FromJSON, ToJSON) newtype High = High { unHigh :: Double } deriving (Eq, Ord, Num, Fractional, Real, RealFrac, Show, Read, Data, Typeable, Generic, NFData, Hashable, FromJSON, ToJSON) newtype Open = Open { unOpen :: Double } deriving (Eq, Ord, Num, Fractional, Real, RealFrac, Show, Read, Data, Typeable, Generic, NFData, Hashable, FromJSON, ToJSON) newtype Close = Close { unClose :: Double } deriving (Eq, Ord, Num, Fractional, Real, RealFrac, Show, Read, Data, Typeable, Generic, NFData, Hashable, FromJSON, ToJSON) newtype Volume = Volume { unVolume :: Double } deriving (Eq, Ord, Num, Fractional, Real, RealFrac, Show, Read, Data, Typeable, Generic, NFData, Hashable, FromJSON, ToJSON) -- Product Stats data Stats = Stats { statsOpen :: Open , statsHigh :: High , statsLow :: Low , statsVolume :: Volume } deriving (Show, Data, Typeable, Generic) instance NFData Stats instance ToJSON Stats where toJSON Stats{..} = object [ "open" .= show statsOpen , "high" .= show statsHigh , "low" .= show statsLow , "volume" .= show statsVolume ] instance FromJSON Stats where parseJSON (Object m) = Stats <$> liftM (Open . read) (m .: "open") <*> liftM (High . read) (m .: "high") <*> liftM (Low . read) (m .: "low") <*> liftM (Volume . read) (m .: "volume") parseJSON _ = mzero -- Exchange Currencies data Currency = Currency { curId :: CurrencyId , curName :: Text , curMinSize :: CoinScientific } deriving (Show, Data, Typeable, Generic) instance NFData Currency instance ToJSON Currency where toJSON = genericToJSON coinbaseAesonOptions instance FromJSON Currency where parseJSON = genericParseJSON coinbaseAesonOptions -- Exchange Time data ExchangeTime = ExchangeTime { timeIso :: UTCTime , timeEpoch :: Double } deriving (Show, Data, Typeable, Generic) instance ToJSON ExchangeTime where toJSON = genericToJSON coinbaseAesonOptions instance FromJSON ExchangeTime where parseJSON = genericParseJSON coinbaseAesonOptions