API Reference

WebSocket Rooms & Events

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:

RoomEvent NameResponse
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)
  1. Add a connection_callback to the listener for the connect 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 the Subscribe 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()