packages feed

coinbase-pro 0.6.0.0 → 0.7.0.0

raw patch · 12 files changed

+331/−108 lines, 12 files

Files

README.md view
@@ -1,50 +1,83 @@ # coinbase-pro -## Request API+Client for Coinabse Pro REST and Websocket APIS. -```haskell-{-# LANGUAGE OverloadedStrings #-}+Here is a list of implemented/unimplemented features: -module Main where+- Market Data+    - [x] Products+        - [x] Get Products+        - [x] Get Product Order Book+        - [x] Get Product Ticker+        - [x] Get Trades+        - [x] Get Historic Rates+        - [x] Get 24hr Stats+    - [x] Currencies+        - [x] Get Currencies+    - [x] Time+- Private+    - [ ] Accounts+        - [x] List Accounts+        - [x] Get An Account+        - [ ] Get Account History+        - [ ] Get Holds+    - [ ] Orders+        - [x] Place a New Order+        - [x] Cancel an Order+        - [x] Cancel all+        - [x] List Orders+        - [ ] Get an Order+    - [x] Fills+        - [x] List Fills+    - [ ] Deposits+        - [ ] Payment Method+        - [ ] Coinbase+    - [ ] Withdrawals+        - [ ] Payment Method+        - [ ] Coinbase+        - [ ] Crypto+    - [ ] Stablecoin Conversions+        - [ ] Create Conversion+    - [ ] Payment Methods+        - [ ] List Payment Methods+    - [x] Fees+        - [x] Get Current Fees+    - [ ] Reports+        - [ ] Create a new report+        - [ ] Get report status+    - [x] User Account+        - [x] Trailing Volume+- Websocket Feed+    - [x] Channels+        - [x] The heartbeat channel+        - [ ] The status channel+        - [x] The ticker channel+        - [x] The level2 channel+        - [ ] The user channel+        - [x] The matches channel+        - [x] The full channel+- FIX API+    - [ ] Messages -import           Control.Monad.IO.Class             (liftIO) -import           CoinbasePro.Authenticated-import           CoinbasePro.Authenticated.Accounts-import           CoinbasePro.Authenticated.Orders-import           CoinbasePro.Headers-import           CoinbasePro.MarketData.Types       hiding (time)-import           CoinbasePro.Request-import           CoinbasePro.Types                  hiding (time)-import           CoinbasePro.Unauthenticated+## Request API +### Market Data Requests -main :: IO ()-main = do-    stats btcusd >>= print-    candles btcusd Nothing Nothing Minute >>= print-    trades btcusd >>= print-    time >>= print-    products >>= print-    aggregateOrderBook btcusd (Just Best) >>= print-    aggregateOrderBook btcusd (Just TopFifty) >>= print-    fullOrderBook btcusd >>= print-    runCbAuthT cpc $ do-        accounts >>= liftIO . print-        account accountId >>= liftIO . print-        fills (Just btcusd) Nothing >>= liftIO . print-        listOrders (Just [All]) (Just btcusd) >>= liftIO . print-        placeOrder btcusd Sell (Size 0.001) (Price 99999.00) True Nothing Nothing Nothing >>= liftIO . print-        placeOrder btcusd Buy (Size 1.0) (Price 1.00) True Nothing Nothing Nothing >>= liftIO . print-        cancelOrder (OrderId "<cancel-order-id>")-        cancelAll (Just btcusd) >>= liftIO . print+```haskell+run (trades (ProductId "BTC-USD")) >>= print+```++### Authenticated Private Requests++```haskell+runCbAuthT cpc $ do+    fills (Just btcusd) Nothing >>= liftIO . print   where     accessKey  = CBAccessKey "<access-key>"     secretKey  = CBSecretKey "<secret-key>"     passphrase = CBAccessPassphrase "<passphrase>"     cpc        = CoinbaseProCredentials accessKey secretKey passphrase-    accountId  = AccountId "<account-id>"-    btcusd     = ProductId "BTC-USD" ```  ## Websocket API@@ -53,17 +86,6 @@   ```haskell-{-# LANGUAGE OverloadedStrings #-}--module Main where--import           Control.Monad                     (forever)-import qualified System.IO.Streams                 as Streams--import           CoinbasePro.Types                 (ProductId (..))-import           CoinbasePro.WebSocketFeed         (subscribeToFeed)-import           CoinbasePro.WebSocketFeed.Request (ChannelName (..))- main :: IO () main = do     msgs <- subscribeToFeed [ProductId "BTC-USD"] [Ticker]
+ changelog.md view
@@ -0,0 +1,8 @@+# Version 0.7.0.0+ - Unauthenticated requests are now all in the `ClientM` monad. `CoinbasePro.Request.run` is now required+   to operate in the IO monad.++   Example: `run (trades (ProductId "BTC-USD")) >>= print`++- Added `run_`, `runSandbox`, `runSandboxWithManager` in `CoinbasePro.Request`+- Added `currencies`, `fees`, and `trailingVolume` queries
coinbase-pro.cabal view
@@ -4,10 +4,10 @@ -- -- see: https://github.com/sol/hpack ----- hash: bf03411c07a63b43dbdda3129795b4e4da28379155e97759420fa4908122050c+-- hash: 1ab32e4b55d042111e39fa8c604bf0b9bfeae0e5462638e322911b1ae0a0b59a  name:           coinbase-pro-version:        0.6.0.0+version:        0.7.0.0 synopsis:       Client for Coinbase Pro description:    Client for Coinbase Pro REST and Websocket APIs category:       Web, Finance
src/example/request/Main.hs view
@@ -10,32 +10,39 @@ import           CoinbasePro.Authenticated.Orders import           CoinbasePro.Authenticated.Request import           CoinbasePro.MarketData.Types       hiding (time)+import           CoinbasePro.Request import           CoinbasePro.Types                  hiding (time) import           CoinbasePro.Unauthenticated   main :: IO () main = do-    stats btcusd >>= print-    candles btcusd Nothing Nothing Minute >>= print-    trades btcusd >>= print-    time >>= print-    products >>= print-    aggregateOrderBook btcusd (Just Best) >>= print-    aggregateOrderBook btcusd (Just TopFifty) >>= print-    fullOrderBook btcusd >>= print-    runCbAuthT cpc $ do-        accounts >>= liftIO . print-        account aid >>= liftIO . print-        fills (Just btcusd) Nothing >>= liftIO . print-        listOrders (Just [All]) (Just btcusd) >>= liftIO . print-        placeOrder btcusd Sell (Size 0.001) (Price 99999.00) True Nothing Nothing Nothing >>= liftIO . print-        placeOrder btcusd Buy (Size 1.0) (Price 1.00) True Nothing Nothing Nothing >>= liftIO . print-        cancelAll (Just btcusd) >>= liftIO . print+    run (stats btcusd) >>= print+    run (stats btcusd) >>= print+    run (candles btcusd Nothing Nothing Minute) >>= print+    run (trades btcusd) >>= print+    run time >>= print+    run products >>= print+    run (aggregateOrderBook btcusd (Just Best)) >>= print+    run (aggregateOrderBook btcusd (Just TopFifty)) >>= print+    run (fullOrderBook btcusd) >>= print+    run_ $ do+        currencies+        products+    -- runCbAuthT cpc $ do+        -- accounts >>= liftIO . print+        -- fees >>= liftIO . print+        -- trailingVolume >>= liftIO . print+        -- account aid >>= liftIO . print+        -- fills (Just btcusd) Nothing >>= liftIO . print+        -- listOrders (Just [All]) (Just btcusd) >>= liftIO . print+        -- placeOrder btcusd Sell (Size 0.001) (Price 99999.00) True Nothing Nothing Nothing >>= liftIO . print+        -- placeOrder btcusd Buy (Size 1.0) (Price 1.00) True Nothing Nothing Nothing >>= liftIO . print+        -- cancelAll (Just btcusd) >>= liftIO . print   where-    accessKey  = CBAccessKey "accesskey"-    secretKey  = CBSecretKey "secretkey"-    passphrase = CBAccessPassphrase "passphrase"+    accessKey  = CBAccessKey "315dd0794fd50876e0c3235e79fb7a92"+    secretKey  = CBSecretKey "M37/sDmlZtI+Qxm9ODr6RNWzfoW+4w/fyyx5x8LxSRg8keHjt8Aepr+RmlprYzUaOQoi/ZHsYu0bNGiMUDl35g=="+    passphrase = CBAccessPassphrase "test123"     cpc        = CoinbaseProCredentials accessKey secretKey passphrase-    aid        = AccountId "accountid"+    accountId  = AccountId "e4a37481-12e7-4564-b073-90627d202c2a"     btcusd     = ProductId "BTC-USD"
src/lib/CoinbasePro/Authenticated.hs view
@@ -6,10 +6,12 @@   ( accounts   , account   , listOrders-  , fills   , placeOrder   , cancelOrder   , cancelAll+  , fills+  , fees+  , trailingVolume   ) where  @@ -28,7 +30,8 @@                                                      simpleQueryToQuery) import           Servant.Client                     (ClientM) -import           CoinbasePro.Authenticated.Accounts (Account, AccountId (..))+import           CoinbasePro.Authenticated.Accounts (Account, AccountId (..),+                                                     Fees, TrailingVolume (..)) import qualified CoinbasePro.Authenticated.API      as API import           CoinbasePro.Authenticated.Fills    (Fill) import           CoinbasePro.Authenticated.Orders   (Order, PlaceOrderBody (..),@@ -108,6 +111,22 @@      mkSimpleQuery :: Maybe ProductId -> Maybe OrderId -> SimpleQuery     mkSimpleQuery p o = mkProductQuery p <> mkOrderIdQuery o+++-- | https://docs.pro.coinbase.com/?javascript#get-current-fees+fees :: CBAuthT ClientM Fees+fees = authRequest methodGet mkRequestPath "" API.fees+  where+    mkRequestPath :: RequestPath+    mkRequestPath = "/fees"+++-- | https://docs.pro.coinbase.com/?javascript#trailing-volume+trailingVolume :: CBAuthT ClientM [TrailingVolume]+trailingVolume = authRequest methodGet mkRequestPath "" API.trailingVolume+  where+    mkRequestPath :: RequestPath+    mkRequestPath = "/users/self/trailing-volume"   mkSimpleQueryItem :: String -> Text -> SimpleQueryItem
src/lib/CoinbasePro/Authenticated/API.hs view
@@ -10,6 +10,8 @@     , cancelOrder     , cancelAll     , fills+    , fees+    , trailingVolume     ) where  import           Data.Proxy                         (Proxy (..))@@ -20,7 +22,8 @@ import           Servant.Client import           Servant.Client.Core                (AuthenticatedRequest) -import           CoinbasePro.Authenticated.Accounts (Account, AccountId (..))+import           CoinbasePro.Authenticated.Accounts (Account, AccountId (..),+                                                     Fees, TrailingVolume) import           CoinbasePro.Authenticated.Fills    (Fill) import           CoinbasePro.Authenticated.Orders   (Order, PlaceOrderBody (..),                                                      Status (..))@@ -37,6 +40,8 @@          :<|> "orders" :> Capture "order_id" OrderId :> AuthDelete NoContent          :<|> "orders" :> QueryParam "product_id" ProductId :> AuthDelete [OrderId]          :<|> "fills" :> QueryParam "product_id" ProductId :> QueryParam "order_id" OrderId :> AuthGet [Fill]+         :<|> "fees" :> AuthGet Fees+         :<|> "users" :> "self" :> "trailing-volume" :> AuthGet [TrailingVolume]   api :: Proxy API@@ -50,4 +55,6 @@ cancelOrder :: OrderId -> AuthenticatedRequest (AuthProtect "CBAuth") -> ClientM NoContent cancelAll :: Maybe ProductId -> AuthenticatedRequest (AuthProtect "CBAuth") -> ClientM [OrderId] fills :: Maybe ProductId -> Maybe OrderId -> AuthenticatedRequest (AuthProtect "CBAuth") -> ClientM [Fill]-accounts :<|> singleAccount :<|> listOrders :<|> placeOrder :<|> cancelOrder :<|> cancelAll :<|> fills = client api+fees :: AuthenticatedRequest (AuthProtect "CBAuth") -> ClientM Fees+trailingVolume :: AuthenticatedRequest (AuthProtect "CBAuth") -> ClientM [TrailingVolume]+accounts :<|> singleAccount :<|> listOrders :<|> placeOrder :<|> cancelOrder :<|> cancelAll :<|> fills :<|> fees :<|> trailingVolume = client api
src/lib/CoinbasePro/Authenticated/Accounts.hs view
@@ -1,4 +1,6 @@-{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE OverloadedStrings          #-}+{-# LANGUAGE TemplateHaskell            #-}  module CoinbasePro.Authenticated.Accounts     ( Account (..)@@ -6,13 +8,21 @@     , Currency (..)     , Balance (..)     , ProfileId (..)+    , Fees (..)+    , TrailingVolume (..)     ) where -import           Data.Aeson      (FromJSON (..), withObject, (.:))-import           Data.Text       (Text)-import           Web.HttpApiData (ToHttpApiData (..))+import           Data.Aeson        (FromJSON (..), ToJSON, withObject, (.:))+import           Data.Aeson.Casing (snakeCase)+import           Data.Aeson.TH     (defaultOptions, deriveJSON,+                                    fieldLabelModifier)+import           Data.Text         (Text)+import           Data.Time.Clock   (UTCTime)+import           Web.HttpApiData   (ToHttpApiData (..)) +import           CoinbasePro.Types (ProductId, Volume (..)) + newtype AccountId = AccountId Text     deriving (Eq, Show) @@ -52,3 +62,32 @@         <*> (Balance . read <$> o .: "available")         <*> (Balance . read <$> o .: "hold")         <*> (ProfileId <$> o .: "profile_id")+++newtype FeeRate = FeeRate { unFeeRate :: Double }+    deriving (Eq, Show, FromJSON, ToJSON)+++data Fees = Fees+    { makerFeeRate :: FeeRate+    , takerFeeRate :: FeeRate+    , usdVolume    :: Volume+    } deriving (Eq, Show)+++instance FromJSON Fees where+    parseJSON = withObject "fees" $ \o -> Fees+        <$> (FeeRate . read <$> o .: "maker_fee_rate")+        <*> (FeeRate . read <$> o .: "taker_fee_rate")+        <*> (Volume . read <$> o .: "usd_volume")+++data TrailingVolume = TrailingVolume+    { productId      :: ProductId+    , exchangeVolume :: Volume+    , volume         :: Volume+    , recordedAt     :: UTCTime+    } deriving (Eq, Show)+++deriveJSON defaultOptions { fieldLabelModifier = snakeCase } ''TrailingVolume
src/lib/CoinbasePro/Headers.hs view
@@ -24,7 +24,7 @@   userAgent :: UserAgent-userAgent = UserAgent "coinbase-pro/0.6"+userAgent = UserAgent "coinbase-pro/0.7"   type UserAgentHeader = RequiredHeader "User-Agent" UserAgent
src/lib/CoinbasePro/Request.hs view
@@ -10,12 +10,20 @@     , CBGet     , CBRequest +    -- * Production     , run-    , apiEndpoint+    , run_+    , runWithManager++    -- * Sandbox+    , runSandbox+    , runSandbox_+    , runSandboxWithManager     ) where  import           Control.Exception       (throw)-import           Network.HTTP.Client     (newManager)+import           Control.Monad           (void)+import           Network.HTTP.Client     (Manager, newManager) import           Network.HTTP.Client.TLS (tlsManagerSettings) import           Servant.API             ((:>), Get, JSON) import           Servant.Client@@ -33,12 +41,65 @@ type Body        = String  -apiEndpoint :: String-apiEndpoint = "api.pro.coinbase.com"+------------------------------------------------------------------------------+-- | Runs a coinbase pro HTTPS request and returns the result `a`+--+-- > run products >>= print+--+run :: ClientM a -> IO a+run f = flip runWithManager f =<< newManager tlsManagerSettings  -run :: ClientM a -> IO a-run f = do-    mgr <- newManager tlsManagerSettings-    result <- runClientM f (mkClientEnv mgr (BaseUrl Https apiEndpoint 443 mempty))-    either throw return result+------------------------------------------------------------------------------+-- | Same as 'run', except uses `()` instead of a type `a`+run_ :: ClientM a -> IO ()+run_ = void . run+++------------------------------------------------------------------------------+-- | Allows the user to use their own 'Network.HTTP.Client.Types.ManagerSettings`+-- with 'run'+--+-- @+-- do $+-- mgr  <- newManager tlsManagerSettings+-- prds <- runWithManager mgr products+-- print prds+-- @+--+runWithManager :: Manager -> ClientM a -> IO a+runWithManager mgr f = either throw return =<<+    runClientM f (mkClientEnv mgr (BaseUrl Https production 443 mempty))+  where+    production = "api.pro.coinbase.com"++------------------------------------------------------------------------------+-- | Runs a coinbase pro HTTPS request in sandbox and returns the result 'a'+--+-- > run products >>= print+--+runSandbox :: ClientM a -> IO a+runSandbox f = flip runSandboxWithManager f =<< newManager tlsManagerSettings+++------------------------------------------------------------------------------+-- | Same as 'runSandbox', except uses '()' instead of a type 'a'+runSandbox_ :: ClientM a -> IO ()+runSandbox_ = void . runSandbox+++------------------------------------------------------------------------------+-- | Allows the user to use their own 'Network.HTTP.Client.Types.ManagerSettings`+--+-- @+-- do $+-- mgr  <- newManager tlsManagerSettings+-- prds <- runSandboxWithManager mgr products+-- print prds+-- @+--+runSandboxWithManager :: Manager -> ClientM a -> IO a+runSandboxWithManager mgr f = either throw return =<<+    runClientM f (mkClientEnv mgr (BaseUrl Https sandbox 443 mempty))+  where+    sandbox = "api-public.sandbox.pro.coinbase.com"
src/lib/CoinbasePro/Types.hs view
@@ -10,6 +10,7 @@     , Sequence     , Side (..)     , Size (..)+    , Volume (..)     , TradeId (..)     , Funds     , OrderType (..)@@ -17,12 +18,14 @@     , Candle (..)     , CandleGranularity (..)     , TwentyFourHourStats (..)+    , Currency (..)      , filterOrderFieldName     ) where -import           Data.Aeson            (FromJSON, ToJSON, parseJSON, toJSON,-                                        withArray, withText)+import           Data.Aeson            (FromJSON, ToJSON, Value (Null),+                                        parseJSON, toJSON, withArray,+                                        withObject, withText, (.:), (.:?)) import qualified Data.Aeson            as A import           Data.Aeson.Casing     (camelCase, snakeCase) import           Data.Aeson.TH         (constructorTagModifier, defaultOptions,@@ -209,3 +212,47 @@   deriveJSON defaultOptions { fieldLabelModifier = init . init } ''TwentyFourHourStats+++data CurrencyDetails = CurrencyDetails+    { cdType               :: Text+    , symbol               :: Maybe Text+    , networkConfirmations :: Maybe Int+    , sortOrder            :: Maybe Int+    , cryptoAddressLink    :: Maybe Text+    , pushPaymentMethods   :: [Text]+    , groupTypes           :: Maybe [Text]+    , maxPrecision         :: Maybe Double+    } deriving (Eq, Show)+++instance FromJSON CurrencyDetails where+    parseJSON = withObject "currency details" $ \o -> CurrencyDetails+        <$> o .: "type"+        <*> o .:? "symbol"+        <*> o .:? "network_confirmations"+        <*> o .:? "set_order"+        <*> o .:? "crypto_address_link"+        <*> o .: "push_payment_methods"+        <*> o .:? "group_types"+        <*> o .:? "max_precision"+++data Currency = Currency+    { id      :: Text+    , name    :: Text+    , minSize :: Double+    , status  :: Text+    , message :: Maybe Text+    , details :: CurrencyDetails+    } deriving (Eq, Show)+++instance FromJSON Currency where+    parseJSON = withObject "currency" $ \o -> Currency+        <$> o .: "id"+        <*> o .: "name"+        <*> (read <$> o .: "min_size")+        <*> o .: "status"+        <*> o .:? "message"+        <*> o .: "details"
src/lib/CoinbasePro/Unauthenticated.hs view
@@ -3,15 +3,17 @@  module CoinbasePro.Unauthenticated    ( products-   , time    , aggregateOrderBook    , fullOrderBook    , trades    , candles    , stats+   , currencies+   , time    ) where  import           Data.Time.Clock                           (UTCTime)+import           Servant.Client                            (ClientM)  import           CoinbasePro.Headers                       (userAgent) import           CoinbasePro.MarketData.AggregateOrderBook (AggregateOrderBook)@@ -23,41 +25,46 @@ import           CoinbasePro.Request                       (run) import           CoinbasePro.Types                         (Candle,                                                             CandleGranularity,-                                                            ProductId,+                                                            Currency, ProductId,                                                             TwentyFourHourStats) import qualified CoinbasePro.Unauthenticated.API           as API   -- | https://docs.pro.coinbase.com/#get-products-products :: IO [Product]-products = run $ API.products userAgent----- | https://docs.pro.coinbase.com/#time-time :: IO CBTime-time = run $ API.time userAgent+products :: ClientM [Product]+products = API.products userAgent   -- | https://docs.pro.coinbase.com/#get-product-order-book-aggregateOrderBook :: ProductId -> Maybe AggregateBookLevel -> IO AggregateOrderBook-aggregateOrderBook prid agg = run $ API.aggregateOrderBook prid agg userAgent+aggregateOrderBook :: ProductId -> Maybe AggregateBookLevel -> ClientM AggregateOrderBook+aggregateOrderBook prid agg = API.aggregateOrderBook prid agg userAgent   -- | https://docs.pro.coinbase.com/#get-product-order-book-fullOrderBook :: ProductId -> IO FullOrderBook-fullOrderBook prid = run $ API.fullOrderBook prid (Just FullBookLevel) userAgent+fullOrderBook :: ProductId -> ClientM FullOrderBook+fullOrderBook prid = API.fullOrderBook prid (Just FullBookLevel) userAgent   -- | https://docs.pro.coinbase.com/#get-trades-trades :: ProductId -> IO [Trade]-trades prid = run $ API.trades prid userAgent+trades :: ProductId -> ClientM [Trade]+trades prid = API.trades prid userAgent   -- | https://docs.pro.coinbase.com/#get-historic-rates-candles :: ProductId -> Maybe UTCTime -> Maybe UTCTime -> CandleGranularity -> IO [Candle]-candles prid start end cg = run $ API.candles prid start end cg userAgent+candles :: ProductId -> Maybe UTCTime -> Maybe UTCTime -> CandleGranularity -> ClientM [Candle]+candles prid start end cg = API.candles prid start end cg userAgent   -- | https://docs.pro.coinbase.com/#get-24hr-stats-stats :: ProductId -> IO TwentyFourHourStats-stats prid = run $ API.stats prid userAgent+stats :: ProductId -> ClientM TwentyFourHourStats+stats prid = API.stats prid userAgent+++-- | https://docs.pro.coinbase.com/?javascript#get-currencies+currencies :: ClientM [Currency]+currencies = API.currencies userAgent+++-- | https://docs.pro.coinbase.com/#time+time :: ClientM CBTime+time = API.time userAgent
src/lib/CoinbasePro/Unauthenticated/API.hs view
@@ -8,6 +8,7 @@     , trades     , candles     , stats+    , currencies     , time     ) where @@ -28,7 +29,7 @@ import           CoinbasePro.Request                       (CBGet, CBRequest) import           CoinbasePro.Types                         (Candle,                                                             CandleGranularity,-                                                            ProductId,+                                                            Currency, ProductId,                                                             TwentyFourHourStats)  @@ -64,6 +65,9 @@             :> "stats"             :> CBGet TwentyFourHourStats +type Currencies = "currencies"+                :> CBGet [Currency]+ type Time = "time" :> CBGet CBTime  type API =    Products@@ -72,6 +76,7 @@          :<|> Trades          :<|> Candles          :<|> Stats+         :<|> Currencies          :<|> Time  @@ -85,5 +90,6 @@ trades :: ProductId -> CBRequest [Trade] candles :: ProductId -> Maybe UTCTime -> Maybe UTCTime -> CandleGranularity -> CBRequest [Candle] stats :: ProductId -> CBRequest TwentyFourHourStats+currencies :: CBRequest [Currency] time :: CBRequest CBTime-products :<|> aggregateOrderBook :<|> fullOrderBook :<|> trades :<|> candles :<|> stats :<|> time = client api+products :<|> aggregateOrderBook :<|> fullOrderBook :<|> trades :<|> candles :<|> stats :<|> currencies :<|> time = client api