The unofficial Python client for the Coinbase Pro API

danpaquin, updated 🕥 2023-03-20 06:15:13

coinbasepro-python

Build Status

The Python client for the Coinbase Pro API (formerly known as the GDAX)

Provided under MIT License by Daniel Paquin.

Note: this library may be subtly broken or buggy. The code is released under the MIT License – please take the following message to heart:

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Benefits

  • A simple to use python wrapper for both public and authenticated endpoints.
  • In about 10 minutes, you could be programmatically trading on one of the largest Bitcoin exchanges in the world!
  • Do not worry about handling the nuances of the API with easy-to-use methods for every API endpoint.
  • Gain an advantage in the market by getting under the hood of CB Pro to learn what and who is behind every tick.

Under Development

  • Test Scripts
  • Additional Functionality for the real-time order book
  • FIX API Client Looking for assistance

Getting Started

This README is documentation on the syntax of the python client presented in this repository. See function docstrings for full syntax details.
This API attempts to present a clean interface to CB Pro, but in order to use it to its full potential, you must familiarize yourself with the official CB Pro documentation.

  • https://docs.pro.coinbase.com/

  • You may manually install the project or use pip: ```python pip install cbpro

or

pip install git+git://github.com/danpaquin/coinbasepro-python.git ```

Public Client

Only some endpoints in the API are available to everyone. The public endpoints can be reached using PublicClient

python import cbpro public_client = cbpro.PublicClient()

PublicClient Methods

Get the order book at the default level.

public_client.get_product_order_book('BTC-USD')

Get the order book at a specific level.

public_client.get_product_order_book('BTC-USD', level=1) ```

Get the product ticker for a specific product.

public_client.get_product_ticker(product_id='ETH-USD') ```

Get the product trades for a specific product.

Returns a generator

public_client.get_product_trades(product_id='ETH-USD') ```

To include other parameters, see function docstring:

public_client.get_product_historic_rates('ETH-USD', granularity=3000) ```

Authenticated Client

Not all API endpoints are available to everyone. Those requiring user authentication can be reached using AuthenticatedClient. You must setup API access within your account settings. The AuthenticatedClient inherits all methods from the PublicClient class, so you will only need to initialize one if you are planning to integrate both into your script.

```python import cbpro auth_client = cbpro.AuthenticatedClient(key, b64secret, passphrase)

Use the sandbox API (requires a different set of API access credentials)

auth_client = cbpro.AuthenticatedClient(key, b64secret, passphrase, api_url="https://api-public.sandbox.pro.coinbase.com") ```

Pagination

Some calls are paginated, meaning multiple calls must be made to receive the full set of data. The CB Pro Python API provides an abstraction for paginated endpoints in the form of generators which provide a clean interface for iteration but may make multiple HTTP requests behind the scenes. The pagination options before, after, and limit may be supplied as keyword arguments if desired, but aren't necessary for typical use cases. ```python fills_gen = auth_client.get_fills()

Get all fills (will possibly make multiple HTTP requests)

all_fills = list(fills_gen) One use case for pagination parameters worth pointing out is retrieving only new data since the previous request. For the case of `get_fills()`, the `trade_id` is the parameter used for indexing. By passing `before=some_trade_id`, only fills more recent than that `trade_id` will be returned. Note that when using `before`, a maximum of 100 entries will be returned - this is a limitation of CB Pro.python from itertools import islice

Get 5 most recent fills

recent_fills = islice(auth_client.get_fills(), 5)

Only fetch new fills since last call by utilizing before parameter.

new_fills = auth_client.get_fills(before=recent_fills[0]['trade_id']) ```

AuthenticatedClient Methods

Returns generator:

auth_client.get_account_history("7d0f7d8e-dd34-4d9c-a846-06f431c381ba") ```

Returns generator:

auth_client.get_account_holds("7d0f7d8e-dd34-4d9c-a846-06f431c381ba") ```

Buy 0.01 BTC @ 100 USD

auth_client.buy(price='100.00', #USD size='0.01', #BTC order_type='limit', product_id='BTC-USD') python

Sell 0.01 BTC @ 200 USD

auth_client.sell(price='200.00', #USD size='0.01', #BTC order_type='limit', product_id='BTC-USD') python

Limit order-specific method

auth_client.place_limit_order(product_id='BTC-USD', side='buy', price='200.00', size='0.01') python

Place a market order by specifying amount of USD to use.

Alternatively, size could be used to specify quantity in BTC amount.

auth_client.place_market_order(product_id='BTC-USD', side='buy', funds='100.00') python

Stop order. funds can be used instead of size here.

auth_client.place_stop_order(product_id='BTC-USD', stop_type='loss', price='200.00', size='0.01') ```

  • cancel_order python auth_client.cancel_order("d50ec984-77a8-460a-b958-66f114b0de9b")
  • cancel_all python auth_client.cancel_all(product_id='BTC-USD')

  • get_orders (paginated) ```python

Returns generator:

auth_client.get_orders() ```

  • get_order python auth_client.get_order("d50ec984-77a8-460a-b958-66f114b0de9b")

  • get_fills (paginated) ```python

All return generators

auth_client.get_fills()

Get fills for a specific order

auth_client.get_fills(order_id="d50ec984-77a8-460a-b958-66f114b0de9b")

Get fills for a specific product

auth_client.get_fills(product_id="ETH-BTC") ```

  • deposit & withdraw python depositParams = { 'amount': '25.00', # Currency determined by account specified 'coinbase_account_id': '60680c98bfe96c2601f27e9c' } auth_client.deposit(depositParams) ```python

Withdraw from CB Pro into Coinbase Wallet

withdrawParams = { 'amount': '1.00', # Currency determined by account specified 'coinbase_account_id': '536a541fa9393bb3c7000023' } auth_client.withdraw(withdrawParams) ```

WebsocketClient

If you would like to receive real-time market updates, you must subscribe to the websocket feed.

Subscribe to a single product

```python import cbpro

Parameters are optional

wsClient = cbpro.WebsocketClient(url="wss://ws-feed.pro.coinbase.com", products="BTC-USD", channels=["ticker"])

Do other stuff...

wsClient.close() ```

Subscribe to multiple products

```python import cbpro

Parameters are optional

wsClient = cbpro.WebsocketClient(url="wss://ws-feed.pro.coinbase.com", products=["BTC-USD", "ETH-USD"], channels=["ticker"])

Do other stuff...

wsClient.close() ```

WebsocketClient + Mongodb

The WebsocketClient now supports data gathering via MongoDB. Given a MongoDB collection, the WebsocketClient will stream results directly into the database collection. ```python

import PyMongo and connect to a local, running Mongo instance

from pymongo import MongoClient import cbpro mongo_client = MongoClient('mongodb://localhost:27017/')

specify the database and collection

db = mongo_client.cryptocurrency_database BTC_collection = db.BTC_collection

instantiate a WebsocketClient instance, with a Mongo collection as a parameter

wsClient = cbpro.WebsocketClient(url="wss://ws-feed.pro.coinbase.com", products="BTC-USD", mongo_collection=BTC_collection, should_print=False) wsClient.start() ```

WebsocketClient Methods

The WebsocketClient subscribes in a separate thread upon initialization. There are three methods which you could overwrite (before initialization) so it can react to the data streaming in. The current client is a template used for illustration purposes only.

  • onOpen - called once, immediately before the socket connection is made, this is where you want to add initial parameters.
  • onMessage - called once for every message that arrives and accepts one argument that contains the message of dict type.
  • on_close - called once after the websocket has been closed.
  • close - call this method to close the websocket connection (do not overwrite). ```python import cbpro, time class myWebsocketClient(cbpro.WebsocketClient): def on_open(self): self.url = "wss://ws-feed.pro.coinbase.com/" self.products = ["LTC-USD"] self.message_count = 0 print("Lets count the messages!") def on_message(self, msg): self.message_count += 1 if 'price' in msg and 'type' in msg: print ("Message type:", msg["type"], "\[email protected] {:.3f}".format(float(msg["price"]))) def on_close(self): print("-- Goodbye! --")

wsClient = myWebsocketClient() wsClient.start() print(wsClient.url, wsClient.products) while (wsClient.message_count < 500): print ("\nmessage_count =", "{} \n".format(wsClient.message_count)) time.sleep(1) wsClient.close() ```

Testing

A test suite is under development. Tests for the authenticated client require a set of sandbox API credentials. To provide them, rename api_config.json.example in the tests folder to api_config.json and edit the file accordingly. To run the tests, start in the project directory and run python -m pytest

Real-time OrderBook

The OrderBook is a convenient data structure to keep a real-time record of the orderbook for the product_id input. It processes incoming messages from an already existing WebsocketClient. Please provide your feedback for future improvements.

```python import cbpro, time, Queue class myWebsocketClient(cbpro.WebsocketClient): def on_open(self): self.products = ['BTC-USD', 'ETH-USD'] self.order_book_btc = OrderBookConsole(product_id='BTC-USD') self.order_book_eth = OrderBookConsole(product_id='ETH-USD') def on_message(self, msg): self.order_book_btc.process_message(msg) self.order_book_eth.process_message(msg)

wsClient = myWebsocketClient() wsClient.start() time.sleep(10) while True: print(wsClient.order_book_btc.get_ask()) print(wsClient.order_book_eth.get_bid()) time.sleep(1) ```

Testing

Unit tests are under development using the pytest framework. Contributions are welcome!

To run the full test suite, in the project directory run: bash python -m pytest

Change Log

1.1.2 Current PyPI release - Refactor project for Coinbase Pro - Major overhaul on how pagination is handled

1.0 - The first release that is not backwards compatible - Refactored to follow PEP 8 Standards - Improved Documentation

0.3 - Added crypto and LTC deposit & withdraw (undocumented). - Added support for Margin trading (undocumented). - Enhanced functionality of the WebsocketClient. - Soft launch of the OrderBook (undocumented). - Minor bug squashing & syntax improvements.

0.2.2 - Added additional API functionality such as cancelAll() and ETH withdrawal.

0.2.1 - Allowed WebsocketClient to operate intuitively and restructured example workflow.

0.2.0 - Renamed project to GDAX-Python - Merged Websocket updates to handle errors and reconnect.

0.1.2 - Updated JSON handling for increased compatibility among some users. - Added support for payment methods, reports, and Coinbase user accounts. - Other compatibility updates.

0.1.1b2 - Original PyPI Release.

Issues

Coinbase API change

opened on 2023-03-20 11:44:53 by segurac

Many changes in Coinbase's API have been rolled out in the last year. https://docs.cloud.coinbase.com/exchange/docs/changelog

In particular, this change https://docs.cloud.coinbase.com/exchange/docs/changelog#2022-jun-27 makes the websocket to disconnect, whenever new_price or old_price fields appear.

I fixed this part in my fork, but I didn't submit a PR because of lack of time. It would be great if someone could work on this and check that everything works fine.

https://github.com/segurac/coinbasepro-python/commit/f91977da44d76d036f0bcad8702484af2d7ad608

Now that I see some activity in the repo I remembered my patches. It could be a good time to create a small community and maintain this awesome library together.

Bump certifi from 2018.10.15 to 2022.12.7

opened on 2022-12-08 01:19:01 by dependabot[bot]

Bumps certifi from 2018.10.15 to 2022.12.7.

Commits


Dependabot compatibility score

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) - `@dependabot use these labels` will set the current labels as the default for future PRs for this repo and language - `@dependabot use these reviewers` will set the current reviewers as the default for future PRs for this repo and language - `@dependabot use these assignees` will set the current assignees as the default for future PRs for this repo and language - `@dependabot use this milestone` will set the current milestone as the default for future PRs for this repo and language You can disable automated security fix PRs for this repo from the [Security Alerts page](https://github.com/danpaquin/coinbasepro-python/network/alerts).

websocket connection resets every two minutes

opened on 2022-08-01 11:33:00 by jepessen

I've the following class for retrieving data from websocket and convert them in a format usable by my program:

``` from curses import cbreak import cbpro import logging import schedule import time import sys

Setting log

log_formatter = logging.Formatter("%(asctime)s [%(threadName)-12.12s] [%(levelname)-5.5s] %(message)s") root_logger = logging.getLogger() file_handler = logging.FileHandler("cbpro.log") file_handler.setFormatter(log_formatter) root_logger.addHandler(file_handler)

console_handler = logging.StreamHandler(sys.stdout) console_handler.setFormatter(log_formatter) root_logger.addHandler(console_handler) root_logger.setLevel(logging.DEBUG)

class CBProFeed(cbpro.WebsocketClient): def init(self): cbpro.WebsocketClient.init(self) self.public_client = cbpro.PublicClient() self.main_currency = 'EUR' self.crypto_currencies = ['AUCTION'] self.products = ['AUCTION-EUR']

def on_open(self): self.url = "wss://ws-feed.pro.coinbase.com/" self.channels=["ticker"]

def on_message(self, msg): if 'price' in msg and 'type' in msg and msg['type'] == 'ticker': product_id = msg['product_id'] price = float(msg['price']) volume = float(msg['volume_24h']) logging.info("Received " + product_id + ", Price is " + str(price) + ". Volume 24H is " + str(volume));

def on_close(self): logging.info("Websocket connection closed")

def run_forever(self): logging.info("Starting feed") schedule.every().minute.at(':00').do(self._handle_candle_callback) self.start() while True: schedule.run_pending() time.sleep(.1); if (self.error): logging.error("Connection closed. Error is " + str(self.error) + ". Restarting...") self.close() self.error = None self.start()

def _handle_candle_callback(self): logging.debug("Minute processed")

feed = CBProFeed() feed.run_forever() logging.info("End of the script") ```

It works, except for the fact that the connection resets about every two minutes. This is the log when I run it:

... 2022-08-01 14:20:39,367 [MainThread ] [INFO ] Starting feed 2022-08-01 14:20:40,016 [Thread-1 ] [INFO ] Received AUCTION-EUR, Price is 7.52. Volume 24H is 7511.306 2022-08-01 14:21:00,003 [MainThread ] [DEBUG] Running job Job(interval=1, unit=minutes, do=_handle_candle_callback, args=(), kwargs={}) 2022-08-01 14:21:00,003 [MainThread ] [DEBUG] Minute processed 2022-08-01 14:22:00,023 [MainThread ] [DEBUG] Running job Job(interval=1, unit=minutes, do=_handle_candle_callback, args=(), kwargs={}) 2022-08-01 14:22:00,023 [MainThread ] [DEBUG] Minute processed Connection is already closed. - data: None 2022-08-01 14:22:20,089 [Thread-1 ] [INFO ] Websocket connection closed 2022-08-01 14:22:20,147 [MainThread ] [ERROR] Connection closed. Error is Connection is already closed.. Restarting... 2022-08-01 14:22:20,829 [Thread-2 ] [INFO ] Received AUCTION-EUR, Price is 7.52. Volume 24H is 7511.306 2022-08-01 14:22:34,593 [Thread-2 ] [INFO ] Received AUCTION-EUR, Price is 7.53. Volume 24H is 7667.951 2022-08-01 14:22:41,850 [Thread-2 ] [INFO ] Received AUCTION-EUR, Price is 7.53. Volume 24H is 7668.243 2022-08-01 14:22:46,204 [Thread-2 ] [INFO ] Received AUCTION-EUR, Price is 7.54. Volume 24H is 7667.951 2022-08-01 14:22:46,247 [Thread-2 ] [INFO ] Received AUCTION-EUR, Price is 7.55. Volume 24H is 7670.651 2022-08-01 14:22:46,798 [Thread-2 ] [INFO ] Received AUCTION-EUR, Price is 7.56. Volume 24H is 7673.351 2022-08-01 14:22:46,996 [Thread-2 ] [INFO ] Received AUCTION-EUR, Price is 7.57. Volume 24H is 7676.051 2022-08-01 14:23:00,014 [MainThread ] [DEBUG] Running job Job(interval=1, unit=minutes, do=_handle_candle_callback, args=(), kwargs={}) 2022-08-01 14:23:00,015 [MainThread ] [DEBUG] Minute processed 2022-08-01 14:24:00,052 [MainThread ] [DEBUG] Running job Job(interval=1, unit=minutes, do=_handle_candle_callback, args=(), kwargs={}) 2022-08-01 14:24:00,052 [MainThread ] [DEBUG] Minute processed Connection is already closed. - data: None 2022-08-01 14:24:27,123 [Thread-2 ] [INFO ] Websocket connection closed 2022-08-01 14:24:27,129 [MainThread ] [ERROR] Connection closed. Error is Connection is already closed.. Restarting... 2022-08-01 14:24:27,788 [Thread-3 ] [INFO ] Received AUCTION-EUR, Price is 7.57. Volume 24H is 7679.043 ...

That are logs that appear when on_close is called. What I'm doing wrong and how can solve the problem?

Incompatible problens

opened on 2022-06-20 20:38:19 by luizlacerdam

I've been doing CS50 and now I'm in my final project. I need this library so much for it but I keep getting so many erros after install. Please help me

https://stackoverflow.com/questions/72680275/can-i-make-this-requires-compatible

Cannot create PublicClient with Python 3.10

opened on 2022-06-15 19:40:09 by adebsa2401

Hi, I wanna use this wrapping of coinbase pro api in an application written using python 3.10. But I got an issue while creating a PublicClient. This seems to be related to the python version cause when I made tests in a python 3.9 env everything works fine. An update will be welcome so. Thanks

Add timeout parameter for auth client

opened on 2022-04-11 00:08:27 by mikemikehe

Adding timeout parameters support

Dan Paquin

Onward and Upward

GitHub Repository

python-client websocket-client coinbase exchange wrapper libaray orderbook bitcoin ethereum trading coinbasepro coinbasepro-api cbpro