Market Data API (WebSocket · Public Channels)

Introduction

Open Trade provides Quotes and Limit Order book for SPOT Crypto. This document describes Open Trade WebSocket communication with Open Trade trading services.

Open Trade Taker WEBSOCKET API provides the ability to connect to the venue server, subscribe to market data, place and control orders, receive executions and updates. The API is based on WEBSOCKET specification.

Key Features Real-time market data streams, unified order management across exchanges, portfolio tracking, and instant execution notifications.

WebSocket Server URLs

PROD: wss://opentrade.exchange/exchange/ws

Available Channels

Public Channels (No Authentication Required)
  • ASSET_LIST
  • INSTRUMENT_LIST
  • ORDER_BOOK_PUBLIC
  • TRADE_PUBLIC
  • ACTIVE_SUBSCRIPTIONS
Private Channels (Authentication Required)
  • BALANCE
  • TRADE_PRIVATE
See the Private Data API documentation for details on these channels.

Precision & Symbols

Price Precision

The precision level of all trading prices is based on significant figures. All pairs on Bitfinex use up to 7 significant digits and up to 8 decimals (e.g., 1.234567, 123.4567, 1234.567, 0.0001234567). Prices submitted with a precision larger than 7 will be cut by the API.

Amount Precision

The amount field allows up to 8 decimals. Anything exceeding this will be rounded to the 8th decimal.

Symbols

A symbol can be a trading pair or a margin currency.

Connection

Establishing Connection

Connect to the WebSocket endpoint using any standard WebSocket client. Upon connection, you'll receive a confirmation message.

JavaScript Example
const ws = new WebSocket('wss://opentrade.exchange/exchange/ws');

ws.onopen = () => {
    console.log('Connected to Open Trade');

    // Send ping every 30 seconds to keep connection alive
    setInterval(() => {
        ws.send(JSON.stringify({
            command: "PING",
            channel: "PING"
        }));
    }, 30000);
};

ws.onmessage = (event) => {
    const data = JSON.parse(event.data);
    console.log('Received:', data);
};

ws.onerror = (error) => {
    console.error('WebSocket error:', error);
};

ws.onclose = () => {
    console.log('Connection closed');
};

Subscription

Subscription is required to establish a data channel the server will push updates to. If private channels are required, the valid API key must be provided in every Subscribe request.

Subscription Structure
{
    "requestId": "123",
    "command": "SUBSCRIBE",
    "signature": "put your token here for private channels",
    "channel": "CHANNEL_NAME",
    "channelArgs": [
        {
            "name": "parameter_name",
            "value": "parameter_value"
        }
    ]
}

Example: Subscribe to Balance (Private Channel)

Request
{
    "command": "SUBSCRIBE",
    "signature": "eyJ...",
    "channelArgs": [
        {
            "name": "currency",
            "value": "[BTC, USDT]"
        }
    ],
    "channel": "BALANCE"
}
Response
{
    "command": "SUBSCRIBE",
    "event": "SNAPSHOT",
    "channel": "BALANCE",
    "channelArgs": [
        {
            "name": "currency",
            "value": "[BTC, USDT]"
        }
    ],
    "data": [
        {
            "class": "Balance",
            "currencyCode": "USDT",
            "balance": 313037.3739066097,
            "available": 313037.3739066097,
            "locked": 0.0
        },
        {
            "class": "Balance",
            "currencyCode": "BTC",
            "balance": 3.28944117,
            "available": 2.7886285699999998,
            "locked": 0.5008126
        }
    ]
}

Rate Limits

Connection Rate Limit The rate limit for wss://opentrade.exchange/exchange/ws is set at 5 connections per 15 seconds.

To ensure fair usage and system stability, rate limits are enforced on WebSocket connections. Exceeding these limits may result in temporary connection rejection.

Heartbeat / Ping

Critical! Failure to send a heartbeat within two minutes will lead to connection closure by the server!

Ping is a service that users need to upkeep to notify that WebSocket connection is still open.

PING Keep Alive

Maintains the WebSocket connection active. Must be sent at least once every 2 minutes.

Request
{
    "command": "PING",
    "channel": "PING"
}
Response
{
    "event": "PONG",
    "channel": "PING"
}

Public Channels

Public channels provide market data and instrument information without requiring authentication. These channels are available to all connected clients.

GET Asset List

Provides a list of supported assets and their trading specifications.

Request
{
    "command": "GET",
    "channel": "ASSET_LIST"
}
Response
{
    "event": "GET",
    "channel": "ASSET_LIST",
    "data": [
        {
            "class": "Currency",
            "code": "USC",
            "name": null
        },
        ...
    ]
}
GET Instrument List

Provides a list of supported Instruments and their trading specifications. When no symbol is provided, all Instruments are returned, a specific Instrument is provided only selected is returned.

Request
{
    "command": "GET",
    "channel": "INSTRUMENT_LIST"
}
Response
{
    "event": "GET",
    "channel": "INSTRUMENT_LIST",
    "data": [
        {
            "class": "Instrument",
            "quoteCurrencyCode": "BAT",
            "code": "BAT/ETH",
            "name": null
        },
        ...
    ]
}
Order Book (Price Book)

Provides streaming services an order book for selected symbol, user needs to provide levels of order book to receive. MAX is 20. MIN is 1. Order books are sorted based on NBBO price: BIDs best (Max) first then descending, ASKs best (MIN) first then ascending. The whole Order book is updated every 40ms regardless of changes.

Subscribe Request
{
    "command": "SUBSCRIBE",
    "channel": "ORDER_BOOK_PUBLIC",
    "channelArgs": [
        {
            "name": "instrument",
            "value": "[USD/ADA,ETH/BTC]"
        }
    ]
}
Acknowledgment
{
    "command": "SUBSCRIBE",
    "event": "ACK",
    "channel": "ORDER_BOOK_PUBLIC"
}
Data Update
{
    "command": "SUBSCRIBE",
    "event": "UPDATE",
    "channel": "ORDER_BOOK_PUBLIC",
    "data": [
        {
            "class": "OrderBook",
            "exchange": "CROSSTOWER",
            "symbol": "BTC/USD",
            "bids": [
                [19292.21, 0.0124],
                [19242.45, 3.0516],
                [10000.0, 0.0002]
            ],
            "asks": [
                [85100.0, 0.01009],
                [19397.85, 21.6067],
                [84300.0, 0.00854]
            ],
            "eventTime": 1664651366635
        },
        ...
    ]
}
eventTime The Open Trade gateway's clock, in Unix epoch milliseconds UTC, at the moment the push was built. It is not the venue's matching-engine time, and it advances on every push whether or not the book changed. For the current time on its own, call GET /public/time.
Trade Book

Provides streaming services a trading book (public trades) for selected symbol. Once subscribed updates will be pushed to user as they appear at Open Trade.

Subscribe Request
{
    "command": "SUBSCRIBE",
    "channel": "TRADE_PUBLIC",
    "channelArgs": [
        {
            "name": "instrument",
            "value": "[USD/ADA,ETH/BTC]"
        }
    ]
}
Acknowledgment
{
    "command": "SUBSCRIBE",
    "event": "ACK",
    "channel": "TRADE_PUBLIC"
}
Data Update
{
    "command": "SUBSCRIBE",
    "event": "UPDATE",
    "channel": "TRADE_PUBLIC",
    "data": [
        {
            "class": "PublicTrade",
            "exchange": "OKCOIN",
            "symbol": "BTC/USD",
            "price": 19308.6,
            "quantity": 0.0103,
            "tradeSide": "BUY",
            "eventTime": 1664651920827
        },
        ...
    ]
}

Authentication

To access private channels (Balance, Private Trades, Order Management), you need to obtain an authentication token through a two-step process.

Authentication Steps
  1. Login with your API key’s API username and password to obtain a session cookie
  2. Use the session cookie to obtain a JWT token
  3. Use the JWT token as the "signature" parameter in private channel requests

Authentication Flow

Before You Start: Create an API Key

Create a key under Account → API Keys: name it, choose its permissions and confirm with your second factor. The platform generates the key's API username, password and secret and shows them once, so store all three straight away.

CredentialExampleWhere it goes
API username100123_mybotThe username field in Step 1, and the {api-username} in the Step 2 URL — the same value both times
Password—The password field in Step 1
Secret—The clientSecret header in Step 2

The password expires one year after the key is created, and login is refused from then on — create a new key before that date.

Step 1: Login with the API Username and Password

Using POST method, send the API username and password to the login endpoint. Note that the credentials must be sent as form-data with keys in lowercase. This returns a SESSION cookie (not JSESSIONID).

Login Endpoints
POST https://auth.opentrade.exchange/login

// Form Data (lowercase keys!)
username: {api-username}
password: {password}
Important! The username and password keys MUST be in lowercase. The login answers HTTP 302 whether or not it succeeded, so check where it redirects: a successful login redirects to the platform, a failed one back to /login. Only the SESSION cookie of a successful login can obtain a token in the next step.

Step 2: Obtain JWT Token

Use the SESSION cookie from Step 1 to obtain your JWT token. This is a POST with the client secret sent as a header, not a query parameter, and an empty body.

Token Endpoints
POST https://auth.opentrade.exchange/auth/jwt/clients/{api-username}/token

// Headers
Cookie: SESSION={session_cookie_from_step_1}
clientSecret: {secret}

// Body: empty
Note the plural The path is /auth/jwt/clients/ (plural) — not /client/. And note this is a single /auth/, not the doubled /auth/auth/ some older references show.

Complete Authentication Flow with cURL

cURL Example
curl -s --cookie-jar cookies.txt -X POST \
    "https://auth.opentrade.exchange/login" \
    -d "username=[API_USERNAME]&password=[PASSWORD]" \
    -o /dev/null -w "login redirected to %{redirect_url}\n" \
    --next -s -b cookies.txt -X POST \
    "https://auth.opentrade.exchange/auth/jwt/clients/[API_USERNAME]/token" \
    -H "accept: */*" \
    -H "clientSecret: [SECRET]" \
    -d ""
Success! The response body is your token, prefixed with Bearer : Bearer eyJ.... Use it as the "signature" parameter in all private channel requests, either exactly as returned or without the prefix — both are accepted. The response also includes a jwt-expire-at header (when the token expires; run both steps again before then) and a jwt-scope header.

Using Your Token

Once you have obtained your JWT token from the authentication process, include it in every private channel request as the "signature" field.

Example with Token
{
    "command": "SUBSCRIBE",
    "signature": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
    "channel": "BALANCE",
    "channelArgs": [
        {
            "name": "currency",
            "value": "[BTC,USD]"
        }
    ]
}
Token Management Tips:
  • Store your token securely and never expose it in client-side code
  • Read jwt-expire-at from the token response and run the login + token exchange again before that time, rather than waiting for authentication errors
  • Use environment variables to manage tokens in different environments
Next Steps For information on Private Channels, Order Management, and Trading operations, please see the Private Data API documentation. For the REST equivalents of these commands, see the REST API documentation.