Listen for Order Updates with the WebSocket SDK
This quickstart explains how to set up and subscribe to WebSocket channels with the Advanced API Python WebSocket Client.
This WebSocket Client is a Python package that makes it easy to interact with the WebSocket API.
Introduction
Consider going through the REST SDK quickstart first as it is referenced in this tutorial.
See the SDK README for detailed instructions, plus the full suite of SDK functions.
Prerequisites
Creating API Keys
To you use the SDK, you must first create your own API key on the Coinbase Developer Platform (CDP).
Installing the SDK
To install the Coinbase Advanced API Python SDK, run the following command in a terminal:
pip3 install coinbase-advanced-py
Completing the REST Quickstart
Part of this tutorial refers to the REST SDK Quickstart so you should go through that one first.
Setting up your Client
Create a Python project with the following code we have set up for you. Replace the api_key
and api_secret
with your own CDP API Key and Secret.
You must specify an on_message
function that is called when a message is received from the WebSocket API. This function takes in a single argument, which is the raw message received from the WebSocket API.
In the following example, we simply print the message to the console.
from coinbase.websocket import WSClient
api_key = "organizations/{org_id}/apiKeys/{key_id}"
api_secret = "-----BEGIN EC PRIVATE KEY-----\nYOUR PRIVATE KEY\n-----END EC PRIVATE KEY-----\n"
def on_message(msg):
print(msg)
ws_client = WSClient(api_key=api_key, api_secret=api_secret, on_message=on_message, verbose=True)
You are now ready to start subscribing to channels!
Subscribing to your First Channels
Let's start by opening a connection to the WebSocket API. Add the following call to open
to your code, using the same client you just created.
ws_client.open()
With an open connection, you can now subscribe to channels.
- The Heartbeats channel receives heartbeats messages for specific products every second, which is used to keep the connection alive.
- The Ticker channel provides real-time price updates every time a match happens for a given product.
Using your same client, send the following message to subscribe to the heartbeats
and ticker
channels for the BTC-USD
product. The received message is printed to the console.
ws_client.subscribe(["BTC-USD"], ["heartbeats", "ticker"])
Running the Client for 10 Seconds
The above code only runs once and then exits. Use the sleep_with_exception_check
method to run the client for a specified number of seconds. This method checks for exceptions every second, and exits if an exception is raised.
Run the following code to keep the client open for 10 seconds. It prints all of the messages it receives, then closes the connection:
def on_message(msg):
print(msg)
ws_client = WSClient(api_key=api_key, api_secret=api_secret, on_message=on_message, verbose=True)
ws_client.open()
ws_client.subscribe(["BTC-USD"], ["heartbeats", "ticker"])
ws_client.sleep_with_exception_check(10)
ws_client.close()
Running the Client Indefinitely
To keep the client open indefinitely, use the run_forever_with_exception_check
method. This method runs the client forever, and exits if an exception is raised.
def on_message(msg):
print(msg)
ws_client = WSClient(api_key=api_key, api_secret=api_secret, on_message=on_message, verbose=True)
ws_client.open()
ws_client.subscribe(["BTC-USD"], ["heartbeats", "ticker"])
ws_client.run_forever_with_exception_check()
Listening for Order Updates
Now let’s get a bit more... advanced!
In this final section, we integrate both the REST and WebSocket APIs to:
- Place a limit-buy order 5% below said price (in the REST SDK tutorial).
- Subscribe to the user channel for updates on a Limit order.
- Print when the order is filled.
Placing an Order 5% below Price
This section assumes that you used the REST SDK Client to place a limit-buy order 5% below the current price of a product.
Subscribing to the User Channel
Now let's integrate the WebSocket SDK!
Let's call the User channel to receive updates on the order. This channel sends updates on all of a user's open orders.
First, let's define the on_message
function. This function:
- Checks for all messages from the
user
channel' - Checks if the message is an update on our order.
- Sets the
order_filled
variable toTrue
if the order is filled.
def on_message(msg):
global order_filled
global limit_order_id
message_data = json.loads(msg)
if 'channel' in message_data and message_data['channel'] == 'user':
orders = message_data['events'][0]['orders']
for order in orders:
order_id = order['order_id']
if order_id == limit_order_id and order['status'] == 'FILLED':
order_filled = True
Now, let's subscribe to the user
and heartbeats
channels and run the client in a while
loop to wait for the order to be filled before closing the connection.
limit_order_id = ""
order_filled = False
ws_client = WSClient(api_key=api_key, api_secret=api_secret, on_message=on_message, verbose=True)
ws_client.open()
ws_client.subscribe(["BTC-USD"], ["heartbeats", "user"])
while not order_filled:
ws_client.sleep_with_exception_check(1)
print(f"order {limit_order_id} filled!")
ws_client.close()
Lastly, let's put it all together! We will integrate the REST SDK code from the Placing a Limit-buy Order exercise with the WebSocket SDK code from the previous section.
Don’t forget to add your own custom client_order_id
. For learning purposes, we’ve pre-filled it to an arbitrary string.
from coinbase.rest import RESTClient
from coinbase.websocket import WSClient
import json
import math
api_key = "organizations/{org_id}/apiKeys/{key_id}"
api_secret = "-----BEGIN EC PRIVATE KEY-----\nYOUR PRIVATE KEY\n-----END EC PRIVATE KEY-----\n"
limit_order_id = ""
order_filled = False
def on_message(msg):
global order_filled
global limit_order_id
message_data = json.loads(msg)
if 'channel' in message_data and message_data['channel'] == 'user':
orders = message_data['events'][0]['orders']
for order in orders:
order_id = order['order_id']
if order_id == limit_order_id and order['status'] == 'FILLED':
order_filled = True
# initialize REST and WebSocket clients
rest_client = RESTClient(api_key=api_key, api_secret=api_secret, verbose=True)
ws_client = WSClient(api_key=api_key, api_secret=api_secret, on_message=on_message, verbose=True)
# open WebSocket connection and subscribe to channels
ws_client.open()
ws_client.subscribe(["BTC-USD"], ["heartbeats", "user"])
# get current price of BTC-USD and place limit-buy order 5% below
product = rest_client.get_product("BTC-USD")
btc_usd_price = float(product["price"])
adjusted_btc_usd_price = str(math.floor(btc_usd_price - (btc_usd_price * 0.05)))
limit_order = rest_client.limit_order_gtc_buy(
client_order_id="00000003",
product_id="BTC-USD",
base_size="0.0002",
limit_price=adjusted_btc_usd_price
)
limit_order_id = limit_order["order_id"]
# wait for order to fill
while not order_filled:
ws_client.sleep_with_exception_check(1)
print(f"order {limit_order_id} filled!")
ws_client.close()
And we are done!
You can now use the WebSocket SDK to subscribe to channels and receive real-time updates from the Coinbase Advanced API.