This guide will help you connect to Bluefin's WebSocket API, subscribe to event rooms, and listen to specific events in real-time using plain WebSockets or Bluefin TypeScript and Python client.
If connecting via plain WebSockets, the connection url is: wss://notifications.api.sui-prod.bluefin.io/
If connecting via Bluefin's TypeScript or Python clients, the connection is internally established via Socket.IO and comes out of the box with features for connection, reconnection and subscription.
Rooms & Events
There are two rooms a client can subscribe to, globalUpdates
for all public information and userUpdates
for private user information. Once subscribed, clients can listen to the following events in each room:
Room | Event Name | Response |
---|---|---|
Global | "MarketDataUpdate" | See GET / marketData |
Global | "RecentTrades" | See GET /recentTrades |
Global | "OrderbookUpdate" | See Orderbook Diff. Depth Stream |
OrderbookDepthStream | "OrderbookDepthUpdate" | See Orderbook Partial Depth Stream |
Global | "{symbol}@kline@{interval}" | See /candlestickData |
User | "AccountDataUpdate" | See /account |
User | "OrderUpdate" | See /orders |
User | "OrderCancellationFailed" | See /orders |
User | "PositionUpdate" | See /userPosition |
User | "UserTrade" | See /userTradesHistory |
User | "OrderSettlementUpdate" | See OrderSettlementUpdate |
User | "OrderRequeueUpdate" | See OrderRequeueUpdate |
User | "OrderCancelledOnReversionUpdate" | See OrderCancelledOnReversionUpdate |
Plain WebSockets
1. Open Connection
const WebSocket = require("ws");
const socketInstance: WebSocket = new WebSocket('wss://notifications.api.sui-prod.bluefin.io/');
socketInstance.onopen = function () {
console.log('Connected to Bluefin WebSocket API');
};
socketInstance.onerror = function (err: any) {
console.error('WebSocket Error:', err);
};
#install the `websocket-client`, `websockets` library beforehand: `# pip install websocket-client==1.5.1 websockets==9.1`
import websocket
websocket_url = "wss://notifications.api.sui-prod.bluefin.io/"
ws = websocket.create_connection(websocket_url)
print("WebSocket connection has been established: ", websocket_url)
2. Subscribe To Rooms
There are two rooms a client can connect to, globalUpdates
for all public information and userUpdates
for private user information.
Global Updates Room:
To subscribe to the globalUpdates room for a specific market, specify the symbol (e.g., "ETH-PERP"):
let globalSubscriptionMessage = [
"SUBSCRIBE",
[
{
e: "globalUpdates",
p: "ETH-PERP", // You can replace "ETH-PERP" with any other valid market symbol
},
],
];
socketInstance.send(JSON.stringify(globalSubscriptionMessage));
def subscribe_to_global_updates(ws):
subscriptionMessage = [
"SUBSCRIBE",
[
{
"e": "globalUpdates",
"p": "ETH-PERP", # You can replace "ETH-PERP" with any other valid market symbol
}
]
]
ws.send(json.dumps(subscriptionMessage))
User Updates Room:
Similarly, to subscribe to the userUpdates room for a specific user by specifying the auth token
let userSubscriptionMessage = [
"SUBSCRIBE",
[
{
e: "userUpdates",
t: "YOUR_AUTH_TOKEN", // Replace with your actual token
},
],
];
socketInstance.send(JSON.stringify(userSubscriptionMessage));
def subscribe_to_user_updates(ws):
subscriptionMessage = [
"SUBSCRIBE",
[
{
"e": "userUpdates",
"t": "YOUR_AUTH_TOKEN", # Replace with your actual token
}
]
]
ws.send(json.dumps(subscriptionMessage))
3. Listen To Events
Once subscribed you can begin listening to the room's events:
socketInstance.addEventListener('message', (event) => {
const data = JSON.parse(event.data);
switch (data.eventName) {
case "MarketDataUpdate":
// Handle MarketDataUpdate event
break;
case "RecentTrades":
// Handle RecentTrades event
break;
case "OrderbookUpdate":
break
// Add cases for other events like OrderbookUpdate, MarketHealth, etc.
default:
break;
}
});
import websocket
import json
def on_message(ws, message):
data = json.loads(message)
event_name = data["eventName"]
if event_name == 'MarketDataUpdate':
# Handle RecentTrades event
pass
elif event_name == 'RecentTrades':
# Handle RecentTrades event
pass
elif event_name == 'OrderbookUpdate':
# Handle OrderbookUpdate event
pass
else:
# Add cases for other events like OrderbookUpdate, MarketHealth, etc.
pass
while True:
op_code, frame = ws.recv_data_frame(True)
if op_code == websocket.ABNF.OPCODE_CLOSE:
print("CLOSE frame received, closing websocket connection")
elif op_code == websocket.ABNF.OPCODE_PING:
ws.pong("")
print("Received Ping; PONG frame sent back")
elif op_code == websocket.ABNF.OPCODE_PONG:
print("Received PONG frame")
else:
data = frame.data
if op_code == websocket.ABNF.OPCODE_TEXT:
data = data.decode("utf-8")
on_message(ws, data)
4. Unsubscribe To Rooms
To unsubscribe to the room, just amend the type to be "UNSUBSCRIBE" like so for the Global Updates room:
let globalUnsubscriptionMessage = [
"UNSUBSCRIBE",
[
{
e: "globalUpdates",
p: "ETH-PERP", // You can replace "ETH-PERP" with any other valid market symbol
},
],
];
socketInstance.send(JSON.stringify(globalUnsubscriptionMessage));
def unsubscribe_to_global_updates(ws):
unsubscriptionMessage = [
"UNSUBSCRIBE",
[
{
"e": "globalUpdates",
"p": "ETH-PERP", # You can replace "ETH-PERP" with any other valid market symbol
}
]
]
ws.send(json.dumps(unsubscriptionMessage))
And User Updates Room:
let userUnsubscriptionMessage = [
"UNSUBSCRIBE",
[
{
e: "userUpdates",
t: "YOUR_AUTH_TOKEN", // Replace with your actual token
},
],
];
socketInstance.send(JSON.stringify(userUnsubscriptionMessage));
def unsubscribe_to_user_updates(ws):
unsubscriptionMessage = [
"UNSUBSCRIBE",
[
{
"e": "userUpdates",
"t": "YOUR_AUTH_TOKEN", # Replace with your actual token
}
]
]
ws.send(json.dumps(unsubscriptionMessage))
5. Running and Closing the Connection:
For Python, to establish and maintain the WebSocket connection:
while True:
op_code, frame = ws.recv_data_frame(True)
if op_code == websocket.ABNF.OPCODE_CLOSE:
print("CLOSE frame received, closing websocket connection")
elif op_code == websocket.ABNF.OPCODE_PING:
ws.pong("")
print("Received Ping; PONG frame sent back")
elif op_code == websocket.ABNF.OPCODE_PONG:
print("Received PONG frame")
else:
data = frame.data
if op_code == websocket.ABNF.OPCODE_TEXT:
data = data.decode("utf-8")
on_message(ws, data)
Once you're done or if you wish to manually terminate the connection:
socketInstance.close();
ws.send_close()
Tying It All Together
const WebSocket = require("ws");
const socketInstance: WebSocket = new WebSocket('wss://notifications.api.sui-prod.bluefin.io/');
socketInstance.onopen = function () {
console.log('Connected to Bluefin WebSocket API');
let subscriptionMessage = [
"SUBSCRIBE",[{ e: "globalUpdates", p: "ETH-PERP" }]
];
socketInstance.send(JSON.stringify(subscriptionMessage));
};
socketInstance.onerror = function (err: any) {
console.error('WebSocket Error:', err);
};
socketInstance.addEventListener('message', (event) => {
const data = JSON.parse(event.data);
switch (data.eventName) {
case "MarketDataUpdate":
// Handle MarketDataUpdate event
break;
case "RecentTrades":
// Handle RecentTrades event
break;
case "OrderbookUpdate":
break
// Add cases for other events like OrderbookUpdate, MarketHealth, etc.
default:
break;
}
});
#install the `websocket-client`, `websockets` library beforehand: `# pip install websocket-client==1.5.1 websockets==9.1`
import websocket
import json
def subscribe_to_global_updates(ws):
subscriptionMessage = [
"SUBSCRIBE",
[
{
"e": "globalUpdates",
"p": "ETH-PERP", # You can replace "ETH-PERP" with any other valid market symbol
}
]
]
ws.send(json.dumps(subscriptionMessage))
def on_message(ws, message):
data = json.loads(message)
event_name = data["eventName"]
if event_name == 'MarketDataUpdate':
# Handle RecentTrades event
pass
elif event_name == 'RecentTrades':
# Handle RecentTrades event
pass
elif event_name == 'OrderbookUpdate':
# Handle OrderbookUpdate event
pass
else:
# Add cases for other events like OrderbookUpdate, MarketHealth, etc.
pass
websocket_url = "wss://notifications.api.arbitrum-prod.firefly.exchange/"
ws = websocket.create_connection(websocket_url)
print("WebSocket connection has been established: ", websocket_url)
subscribe_to_global_updates(ws)
while True:
op_code, frame = ws.recv_data_frame(True)
if op_code == websocket.ABNF.OPCODE_CLOSE:
print("CLOSE frame received, closing websocket connection")
elif op_code == websocket.ABNF.OPCODE_PING:
ws.pong("")
print("Received Ping; PONG frame sent back")
elif op_code == websocket.ABNF.OPCODE_PONG:
print("Received PONG frame")
else:
data = frame.data
if op_code == websocket.ABNF.OPCODE_TEXT:
data = data.decode("utf-8")
on_message(ws, data)
Bluefin Client Library
1. Create a connection_callback
function that encapsulates the following:
- Subscribe to the global market room. If the user wishes to listen to global events, then use
client.sockets.subscribeGlobalUpdatesBySymbol(marketSymbol)
# subscribe to global event updates for ETH market
status = await client.socket.subscribe_global_updates_by_symbol(MARKET_SYMBOLS.ETH)
- Subscribe to the orderbook partial depth events room. If the user wishes to listen to orderbook depth stream events, then use
client.sockets.subscribeOrderBookDepthStreamBySymbol(marketSymbol,depth)
or
client.sockets.subscribeOrderBookDepthStreamBySymbol(marketSymbol) //With default depth being 5
# subscribe to orderbook partial depth event
status = await client.socket.subscribe_orderbook_depth_streams_by_symbol(MARKET_SYMBOLS.ETH,depth)
or
status = await client.socket.subscribe_orderbook_depth_streams_by_symbol(MARKET_SYMBOLS.ETH) # With default depth being 5
- Both of these methods must be invoked separately for every market.
- Subscribe to the local user events room. If you wish to listen to events pertaining to your account, use
client.sockets.subscribeUserUpdateByToken()
# subscribe to local user events
status = await client.socket.subscribe_user_update_by_token()
- You can write a callback function and pass it as an argument to any of the event listeners like this:
const callback = ({ order }: { order: PlaceOrderResponse }) => {
console.log(order);
};
client.sockets.onUserOrderUpdate(callback);
def callback(event):
global event_received
print(event)
event_received = True
# triggered when user order updates are received
await client.socket.listen(SOCKET_EVENTS.ORDER_UPDATE.value, callback)
- Add a
connection_callback
to the listener for theconnect
event
await client.sockets.listen("connect", connection_callback)
await client.socket.listen("connect", connection_callback)
- This function will be executed when a socket connection is established.
-
The
connect
event also gets triggered when the socket client attempts auto-reconnection; therefore, it is important to add theSubscribe
calls to this callback function to avoid manual intervention when the connection re-establishes.
3. You can also choose to perform any action when the socket client disconnects from the server by adding a disconnection_callback
to the listener for.disconnect
event
await client.sockets.listen("disconnect", disconnection_callback)
await client.socket.listen("disconnect", disconnection_callback)
4. After defining the listener for the connection event using the connection_callback
function, open up a socket connection
client.sockets.open()
await client.socket.open()
5. Terminate the connection once done
client.sockets.close()
await client.socket.close()
Tying It All Together
/**
* Places a market order on exchange and listens to emitted events
*/
/* eslint-disable no-console */
import {
BluefinClient,
MARKET_SYMBOLS,
Networks,
ORDER_SIDE,
ORDER_TYPE,
PlaceOrderResponse
} from "@bluefin-exchange/bluefin-v2-client";
async function main() {
const ed25519Wallet =
"trigger swim reunion gate hen black real deer light nature trial dust";
const client = new BluefinClient(
true,
Networks.TESTNET_SUI,
ed25519Wallet,
"ED25519"
);
await client.init();
const callback = ({ order }: { order: PlaceOrderResponse }) => {
console.log(order);
// kill sockets in order to stop script
client.sockets.close();
};
const connection_callback = async () => {
// This callback will be invoked as soon as the socket connection is established
// start listening to global market and local user events
client.sockets.subscribeGlobalUpdatesBySymbol(MARKET_SYMBOLS.ETH);
client.sockets.subscribeUserUpdateByToken();
// triggered when order updates are received
client.sockets.onUserOrderUpdate(callback);
};
const disconnection_callback = async () => {
console.log("Sockets disconnected, performing actions...")
const resp = await client.cancelAllOpenOrders(MARKET_SYMBOLS.ETH);
console.log(resp);
};
// must specify connection_callback before opening the sockets below
await client.sockets.listen("connect", connection_callback);
await client.sockets.listen("disconnect", disconnection_callback);
console.log("Making socket connection to firefly exchange");
client.sockets.open();
/****** Placing an Order ******/
// default leverage of account is set to 3 on Bluefin
const leverage = await client.getUserDefaultLeverage(MARKET_SYMBOLS.ETH)
// post order
const response = await client.postOrder({
symbol: symbol,
price: 50,
quantity: 0.5,
side: ORDER_SIDE.BUY,
orderType: ORDER_TYPE.LIMIT,
leverage: leverage,
});
console.log(response.data);
}
main().then().catch(console.warn);
import time
from config import TEST_ACCT_KEY, TEST_NETWORK
from bluefin_v2_client import BluefinClient, Networks, MARKET_SYMBOLS, SOCKET_EVENTS
import asyncio
event_received = False
def callback(event):
global event_received
print("Event data:", event)
event_received = True
async def main():
client = BluefinClient(True, Networks[TEST_NETWORK], TEST_ACCT_KEY)
await client.init(True)
response = await client.generate_readonly_token()
readOnlyclient = BluefinClient(True, Networks[TEST_NETWORK])
await readOnlyclient.init(True, response)
async def my_callback():
print("Subscribing To Rooms")
# subscribe to global event updates for BTC market
status = await readOnlyclient.socket.subscribe_global_updates_by_symbol(
MARKET_SYMBOLS.BTC
)
print("Subscribed to global BTC events: {}".format(status))
# subscribe to local user events
status = await readOnlyclient.socket.subscribe_user_update_by_token()
print("Subscribed to user events: {}".format(status))
# triggered when order book updates
print("Listening to exchange health updates")
await readOnlyclient.socket.listen(
SOCKET_EVENTS.EXCHANGE_HEALTH.value, callback
)
# triggered when status of any user order updates
print("Listening to user order updates")
await readOnlyclient.socket.listen(SOCKET_EVENTS.ORDER_UPDATE.value, callback)
await readOnlyclient.socket.listen("connect", my_callback)
# must open socket before subscribing
print("Making socket connection to Bluefin exchange")
await readOnlyclient.socket.open()
# SOCKET_EVENTS contains all events that can be listened to
# logs event name and data for all markets and users that are subscribed.
# helpful for debugging
# client.socket.listen("default",callback)
timeout = 30
end_time = time.time() + timeout
while not event_received and time.time() < end_time:
time.sleep(1)
# # unsubscribe from global events
status = await readOnlyclient.socket.unsubscribe_global_updates_by_symbol(
MARKET_SYMBOLS.BTC
)
print("Unsubscribed from global BTC events: {}".format(status))
status = await readOnlyclient.socket.unsubscribe_user_update_by_token()
print("Unsubscribed from user events: {}".format(status))
# # close socket connection
print("Closing sockets!")
await readOnlyclient.socket.close()
await readOnlyclient.apis.close_session()
if __name__ == "__main__":
loop = asyncio.new_event_loop()
loop.run_until_complete(main())
loop.close()