NAV Navbar
shell python java

BitMax API Documentation V2

This document contains new v2 APIs with improved features. At the moment, only limited functionality is supported. However, we plan to increase coverage extensively.

Meanwhile, please refer to BitMax | API Document for a more complete set of APIs.

RESTful APIs - Public

Get Market Trades

Response example (symbol=BTC/USDT, n=2)

{
  "m": "marketTrades",
  "s": "BTC/USDT",
  "trades": [
    {
     "bm": True,
     "id": 72057594043333564,
     "p":  "11406.35",
     "q":  "0.0305710",
     "t":  1565646523666
    },
    {
     "bm": True,
     "id": 72057594043333566,
     "p":  "11406.00",
     "q":  "1.4226290",
     "t":  1565646523666
    }
  ]
}

HTTP Request

GET api/v2/trades/symbol=<symbol>&n=<n>

Parameters

Name Data Type Description
symbol String a valid smbol, e.g. symbol=ETH-BTC
n Int number of trades to be included in the response. n is currently limited to 100 or fewer. e.g. n=10

Each element in trades is an object containing recent trade data with the following fields:

Field Data Type Description
bm Boolean if true, the buyer of the trade is the market maker
id Long Unique ID of the market trade
p String price
q String quantity
t Long timestamp

Authentication

The authentication process for v2 APIs are a bit different from the old version:

Creating a Request

To access private data, you must include the following headers:

Signing a Request

Signing a request

# bash 
APIPATH=user/info
APIKEY=CEcrjGyipqt0OflgdQQSRGdrDXdDUY2x
SECRET=hV8FgjyJtpvVeAcMAgzgAFQCN36wmbWuN7o3WPcYcYhFd8qvE43gzFGVsFcCqMNk
TIMESTAMP=`date +%s%N | cut -c -13` # 1562952827927
MESSAGE=$TIMESTAMP+$APIPATH
SIGNATURE=`echo -n $MESSAGE | openssl dgst -sha256 -hmac $SECRET -binary | base64`
echo $SIGNATURE  # vBZf8OQuiTJIVbNpNHGY3zcUsK5gJpwb5lgCgarpxYI=

curl -X GET -i \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -H "x-auth-key: $APIKEY" \
  -H "x-auth-signature: $SIGNATURE" \
  -H "x-auth-timestamp: $TIMESTAMP" \
  https://bitmax.io/api/v1/user/info
# python 3.6+
import time, hmac, hashlib, base64

api_path  = "user/info"
api_key   = "CEcrjGyipqt0OflgdQQSRGdrDXdDUY2x"
sec_key   = "hV8FgjyJtpvVeAcMAgzgAFQCN36wmbWuN7o3WPcYcYhFd8qvE43gzFGVsFcCqMNk"
timestamp = int(round(time.time() * 1e3)) # 1562952827927

message = bytes(f"{timestamp}+{api_path}", 'utf-8')
secret = bytes(sec_key, 'utf-8')

signature = base64.b64encode(hmac.new(secret, message, digestmod=hashlib.sha256).digest())

header = {
  "x-auth-key": api_key,
  "x-auth-signature": signature, 
  "x-auth-timestamp": timestamp,
}
print(signature)  # b'vBZf8OQuiTJIVbNpNHGY3zcUsK5gJpwb5lgCgarpxYI='
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;

public class SignatureExample {

  public static void main(String[] args) {
    try {
      long timestamp = System.currentTimeMillis(); // 1562952827927
      String api_path = "user/info";
      String secret = "hV8FgjyJtpvVeAcMAgzgAFQCN36wmbWuN7o3WPcYcYhFd8qvE43gzFGVsFcCqMNk";
      String message = timestamp + "+" + api_path;

      Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
      SecretKeySpec secret_key = new SecretKeySpec(secret.getBytes(), "HmacSHA256");
      sha256_HMAC.init(secret_key);

      String hash = Base64.encodeBase64String(sha256_HMAC.doFinal(message.getBytes()));
      System.out.println(hash); // vBZf8OQuiTJIVbNpNHGY3zcUsK5gJpwb5lgCgarpxYI=
    }
    catch (Exception e) {
      System.out.println("Error");
    }
  }
}

To query APIs with private data, you must include a signature using base64 encoded HMAC sha256 algorithm.

Error Code

Example: HTTP response when authentication failed

// HTTP Response Status Code: 405 - Method Not Allowed
{
  "code":  21001,
  "msg": "xxx", 
}

If authentication failed, the server will response with status code other than 200 OK. The respond body will contain more details including the code field with value other than 0 and a message field with text explaining why the authentication failed.

The table below lists all possible server responses if the request is rejected due to authentication failure.

HTTP Status Code ErrorCode Description
405 Method Not Allowed 21001 API Access is currently disabled.
400 Bad Request 21002 API header is missing.
400 Bad Request 21003 Request ID Mismatch.
400 Bad Request 21004 API request header error: invalid timestamp. This typically means the timestamp in request header differs from system time by more than 60 seconds.
400 Bad Request 21006 Unable to find API key.
410 Gone 21005 Unable to verify API signature: expired timestamp.
403 Forbidden 21007 API key does not have view permission.
403 Forbidden 21010 API key does not have withdraw permission.
403 Forbidden 21009 API key does not have trade permission.
403 Forbidden 21008 API key does not have transfer permission.
401 Unauthorized 2012 Account group mismatch.
401 Unauthorized 21011 Unable to verify API signature: signature mismatch.

RESTful APIs - Wallet(Deposit and Withdraw)

Get Deposit address of one Asset

Response example (asset = USDT which has two blockchains)

{
  "code": 0,
  "data": [
    {
     "asset": "USDT",
     "blockChain": "Omni",
     "addressData": {"address": "17nbKg26jBStZHmdq9jLETHPh8EzjiaQ9J"}
    },
    {
     "asset": "USDT",
     "blockChain": "ERC20",
     "addressData": {"address": "0x7dcf0192e4a78593fd360dbc2fa50855a3f4505a"}
    }
  ],
  "email": "xxx@xxx.com",
  "status": "success" // the request has been submitted to the server
}

Response example (asset = XRP which requires both Tag and deposit address for deposit)

{
  "code": 0,
  "data": [
    {
     "asset": "XRP",
     "blockChain": "Ripple",
     "addressData": 
         {
         "address": "rpinhtY4p35bPmVXPbfWRUtZ1w1K1gYShB",
         "destTag": "54301"
         }
    }
  ],
  "email": "xxx@xxx.com",
  "status": "success" // the request has been submitted to the server
}

HTTP Request

GET <account-group>/api/v2/deposit?asset=<asset>

Authentication

You must have view permission enabled for the API key.

You must sign message <timestamp>+deposit and included the signature in the header.

Parameters

Name Data Type Description
asset String Asset code, e.g. "BTC"

RESTful APIs - Margin Trading

A margin account allows you to increase your purchasing power beyond the account total balance by borrowing assets. Compare to cash trading, margin trading has more complicated trading rules and may carry much greater risks. Please refer to BitMax.io Margin Trading Rules for more details.

Get Balance of one Asset of the Margin Account

Margin Balance - Single Balance V1

List all Balance of the Margin Account

Margin Balance - All V1

Get Risk(Summary) of one Symbol of the Margin Account

Response

{
  "code": 0,
  "data": {
    "totalBalanceInUSDT": "111300.232045955",             //Total Asset (in USDT)
    "netBalanceInUSDT": "106348.644635388",               //Net Asset (in USDT)
    "effectiveInitialMargin": "551.54026784",             //Init. Margin Req.
    "effectiveMaintenanceMargin": "261.184132719",        //Min Margin Req.
    "currentLeverage": "1.0466",                          //Current Leverage
    "accountMaxLeverage": "10",                           //Maximum Leverage
    "cushion": "100",                                     //Cushion Rate
    "pointsBalance": "1.466680936"                        //Available(Pts)
  },
  "email": "xxx@xxx.com",
  "status": "success" // the request has been submitted to the server
}

HTTP Request

GET <account-group>/api/v2/margin/risk?symbol=<symbol>

Authentication

You must have view permission enabled for the API key.

You must sign message <timestamp>+margin/risk and included the signature in the header.

Parameters

Name Data Type Description
symbol String symbol, e.g. "BTC/USDT"

Transfer Asset from Cash Account to Margin Account

Request Body - Transfer Asset from Cash Account to Margin Account

{
  "asset":  "BTC",
  "amount": "1.05"
}

Response

{
  "code": 0,
  "data": {
    "requestId": "ftWU30JpY08Eu8MwmfYPzUX47QkUtsys"
  },
  "email": "xxx@xxx.com",
  "status": "success" // the request has been submitted to the server
}

HTTP Request

POST <account-group>/api/v2/margin/transfer/deposit

Authentication

You must have transfer permission enabled for the API key.

You must sign message <timestamp>+margin/transfer/deposit and included the signature in the header.

Parameters

Name Data Type Description
asset String Asset code, e.g. "BTC"
amount String The amount to transfer in string format

Transfer Asset from Margin Account to Cash Account

Request Body - Transfer Asset from Margin Account to Cash Account

{
  "asset":  "BTC",
  "amount": "1.05"
}

Response

{
  "code": 0,
  "data": {
    "requestId": "L00HCI4uUQvFLFpguNC8B9zWANGZsJKV"
  },
  "email": "xxx@xxx.com",
  "status": "success" // the request has been submitted to the server
}

HTTP Request

POST <account-group>/api/v2/margin/transfer/withdraw

Authentication

You must have transfer permission enabled for the API key.

You must sign message <timestamp>+margin/transfer/withdraw and included the signature in the header.

Parameters

Name Data Type Description
asset String Asset code, e.g. "BTC"
amount String The amount to transfer in string format

WebSocket API (Beta Version)

WebSocket Data Feed

websocket URL examples:

wss://bitmax.io/3/api/stream/cash-beta/ETH-BTC
wss://bitmax.io/3/api/stream/margin-beta/ETH-BTC

WebSocket URL

Note: <symbol> in URLs above must be seperated by hyphen (-), e.g, ETH-BTC. Symbols separated by slash (/) are not allowed.

Authorization

You must have view permission enabled for your API key to open websocket connection. If you want to place orders, you will need trade permission enabled as well.

You must sign the following messages and included the signature in the header:

WebSocket Authentication

Connecting to websocket API follows almost the same authentication process as authenticated RESTful APIs. You need to include the following fields in the request header:

Subscribe to WebSocket Streams

After connecting to websocket, you need to send an subscribe message to start receiving data. (Note that unlike V1, you will not receive any data unless you sent the subscribe in V2) The subscribe message is a JSON object in plain text format and contains the following fields:

Subscribe Message

{
  "messageType": "subscribe",
  "marketDepthLevel": 20,
  "recentTradeMaxCount": 20,
  "skipSummary": false,
  "skipBars": false
}
Field Name Data Type Description
messageType String set this field to subscribe in the subscribe message.
marketDepthLevel Integer optional, default value 20. This field specifies the max number of price levels on each side to be included in the first market depth message.
recentTradeMaxCount Integer optional, default value 20. This field specifies the max number of recent trades to be included in the first market trades message.
skipSummary Boolean optional, default value false. If false, client will receive market summary data with rolling 24 hour O/H/L/C price data for all symbols every 30 seconds.
skipBars Boolean optional, default value false. If false, client will receive bar data of all frequencies (1 minute, 5 minutes, etc.) for the current symbol every 30 seconds.

After sending subscribe message, you will receive a message indicating the subscription is successful or not.

Success Subscribe Message (Success Response)

{
"m": "subscribe",
"msg": "success"
}
Field Name Data Type Description
m String subscribe if the subscription succeeds, error if it fails
msg String success if the subscrioption succeeds, or it will print out the error message

Ping/Pong

After connected to websocket, you can send a ping message to the server. After receiving the ping message, the server will response with a pong message. The pong message has a ts field indicating the server time .

Ping Message

{
"messageType": "ping"
}

Pong Message

{
"m": "pong",
"ts": 1569016717541
}
Field Name Data Type Description
m String pong
ts Long timestamp of the server time in milliseconds

WebSocket for Cash Trading

WebSocket URL

wss://bitmax.io/<account-group>/api/stream/cash-beta/<symbol>

Data Channel - Market Depth

Market Depth Data

{
   "m":      "depth",
   "s":      "ETH/BTC",
   "ts":     1557422548511,
   "seqnum": 604599926,
   "asks": [
       ["13.45", "59.16"],
       ["13.37", "95.04"],   
       // ...
   ],
   "bids": [
       ["13.21", "60.17"],
       ["13.10", "13.39"],
       // ...
   ]
}

Each market depth message is a JSON object containing the current quantity at specific prices levels. There is no direct way of getting the top-of-the-book data through websocket. You need to maintain the current depth book and derive the best bid/ask. This can be done by two steps:

Each market depth message contains the following field:

Field Data Type Description
m String message type, "depth"
s String symbol
ts Long timestamp when the message is generated
seqnum Long sequence number
asks Sequence ask levels, each element in the sequence contains [price, quantity]. price and quantity are of String type.
bids Sequence bid levels

Data Channel - Market Trades

Market Trades Data

{
  "m": "marketTrades",
  "s": "ETH/BTC",
  "trades": [
    {
      "p":  "13.75",
      "q":  "6.68",
      "t":  1528988084944,
      "bm": false
    },
    {
      "p":  "13.75",
      "q":  "6.68",
      "t":  1528988084944,
      "bm": false
    },
    // ...
  ]
}

Each start receiving continuous market trade stream. All market trades messages follow the same structure, which contains one or more trades.

Each market depth message contains the following field:

Field Data Type Description
m String message type, "marketTrades"
s String symbol
trades Sequence List of objects containing recent trade data (see below)

Each element in trades is an object containing recent trade data with the following fields:

Field Data Type Description
p String price
q String quantity
t Long timestamp
bm Boolean if true, the buyer of the trade is the market maker

Data Channel - Market Summary

Market Summary Data

{
  "m":  "summary",
  "s":  "ETH/BTC",
  "ba": "ETH",
  "qa": "BTC",
  "i":  "1d",
  "t":  1528988000000,
  "o":  "3.24",
  "c":  "3.56",
  "h":  "3.77",
  "l":  "3.21",
  "v":  "10.234"
}

Each market summary data record contains current information about a single product. The data is streamed in batches - we stream out market data of all products every 30 seconds. Set skipSummary = true in the subscribe message to turn it on.

Field Data Type Description
m String "summary"
s String product symbol
ba String base asset
qa String quote asset
i String bar interval, for market summary data, the interval is always 1d
t Long UTC timestamp in milliseconds
o String open
c String close
h String high
l String low
v String volume

Data Channel - Bar Data

Bar Chart Data

{
  "m":  "bar",
  "s":  "ETH/BTC",
  "ba": "ETH",
  "qa": "BTC",
  "i":  "5",
  "t":  1528988500000, 
  "o":  "3.24",
  "c":  "3.56",
  "h":  "3.77",
  "l":  "3.21",
  "v":  "10.234" 
}

Bar data is almost the same as the market summary data, except that:

Message type is bar There is only one symbol per websocket session The interval field i may take multiple values: 1, 5, 30, 160, 360, 1d. We stream bar data in batches. Every 30 seconds, we stream bar data messages at all interval levels. You may use these data to update bar chart directly (replace bars). However, you should also update the bar chart using the market trade messages.

Field Data Type Description
m String "bar"
s String symbol, e.g. "BTC/USDT"
ba String base asset
qa String quote asset
i String bar interval, e.g. "1", "5", "30", "60", "360", "1d"
t Long UTC timestamp in milliseconds
o String open
c String close
h String high
l String low
v String volume

Data Channel - Order Updates

Order Update Data

{
  "m":           "order",
  "execId":      "31137230",
  "coid":        "FCmKQLPtKb7ciJitM0TSj9f5oLysa1iW",
  "orderType":   "Limit",
  "s":           "BTC/USDT",
  "t":           1565200977389, 
  "p":           "11000.00",
  "q":           "1.0000000",
  "l":           "0",
  "lp":          "0",
  "f":           "0",
  "ap":          "0",
  "bb":          "1000.497910329",
  "bpb":         "1000.497910329",
  "qb":          "188504.592479229",
  "qpb":         "177493.592479229",
  "fee":         "0",
  "fa":          "",
  "bc":          "0",
  "btmxBal":     "1912.000000000",
  "side":        "Buy",
  "status":      "New",
  "errorCode":   "NULL_VAL",
  "cat":         "CASH",
  "ei":          "NULL_VAL"
}

Once connected to websocket streams, you will start receiving real time updates of all your own orders (not only the orders of the subscribtion symbol). It contains both order execution report and current balances. Since only new order updates will be streamed, it is recommendated that you load the initial snap of all you orders using the RESTful API GET api/v1/order/open. Note that if you only connect to cash trading web socket, you won't receive order update messages of your margin account and vice versa.

Field Data Type Description
m String "order"
execId String for each user, this is a strictly increasing long integer
coid String client order id
origCoid String optional, the original order id, see canceling orders for more details
orderType String "Limit", "Market", "StopLimit", "StopMarket"
s String symbol, e.g. "BTC/USDT"
t Long UTC timestamp in milliseconds
p String optional, limit price, only available for "Limit" and "StopLimit" orders
sp String optional, stop price, only available for stop market and stop limit orders
q String order quantity
l String last quantity, the quantity executed by the last fill
lp String last price, the price executed by the last fill
f String filled quantity, this is the aggregated quantity executed by all past fills
ap String average filled price
bb String base asset total balance
bpb String base asset available balance
qb String quote asset total balance
qpb String quote asset available balance
fee String fee
fa String fee asset
bc String if possitive, this is the BTMX commission charged by reverse mining, if negative, this is the mining output of the current fill.
btmxBal String optional, the BTMX balance of the current account.
side String side
status String order status
errorCode String if the order is rejected, this field explains why
cat String category
ei String execution instruction, "POST" for post-only orders

Data Channel - Balance Updates

Balance Update Data

{
  "m":  "balance",
  "execId":  "31428578",
  "account": "cshnHfBk4eytjL23VBZ0mRTY2Dre6Tcr",
  "a": "USDT",
  "b":  "177718.014527793",
  "pb":  "166707.014527793" 
}

Once connected to websocket streams, you will start receiving real time balance updates. Trade related balance updates will be included in the order update message, all other updates (deposit/withdraw/transfer between cash and margin accounts, etc) will be included in the balance message.

Field Data Type Description
m String "balance"
execId String for each user, this is a strictly increasing long integer
account String account ID
a String asset
b String total balance of the asset
pb String available balance of the asset

Client Request - Placing New Order

New Order Request

{
  "messageType": "newOrderRequest",
  "time":        1528988500000,
  "coid":        "G4afqeetOz34Wh4SqtJUye6vpYqhe7TH",
  "symbol":      "BTC/USDT",
  "orderPrice":  "5000",
  "orderQty":    "0.35",
  "orderType":   "limit",
  "side":        "buy"
}

You can place orders by sending newOrderRequest messages to the server.

Key Data Type Value
messageType String required, "newOrderRequest"
time Long required, UTC timestamp in milliseconds
coid String required, unique ID string of length 32
symbol String required, symbol, e.g. "BTC/USDT"
orderPrice String optional, the limit price of the order
orderQty String required, the order quantity as a string, e.g. "1.23"
orderType String required, "limie", "market", "stop_limit", "stop_market"
side String
postOnly Boolean Optional, true or false
stopPrice String the stop price as a string, e.g "10000.50"
timeInForce String GTC (Good-till-canceled, default) or IOC (immediate-or-cancel)

Invalid Order Rejection Message

{
  "m":         "order",
  "coid":      "G4afqeetOz34Wh4SqtJUye6vpYqhe7TH",
  "status":    "Rejected",
  "errorCode": "600533",
  "reason":    "Price is too low from market price."
}

If the order is valid, you will receive an order update message in which Status is New.

If the order is invalid, you will receive an rejection message immediately with coid the same as the new order request message.

Key Data Type Value
m String "order"
coid String the coid in the order request
status String "Rejected"
errorCode String a numeric error code as a string. (We use string format to be consistent with other order messages)
reason String

Client Request - Cancel an Order

Cancel an Order

{
  "messageType": "cancelOrderRequest",
  "time":        1528988100000, 
  "coid":        "Zgu7EabVbGNnnGsCid0MydDA4pa7ighE",
  "origCoid":    "dHKTlw3Mh4W4Zg9RjkU5cnFopwjC9uWU",
  "symbol":      "BTC/USDT"
}

You can cancel an open order by sending cancelOrderRequest messages to the server. If the order is successfully canceled, you will receive an order update message in which Status is Canceled.

Key Data Type Value
messageType String required, "cancelOrderRequest"
time Long required, UTC timestamp in milliseconds
coid String required, unique ID string of length 32
origCoid String required, the original coid of the order
symbol String required, symbol, e.g. "BTC/USDT"

WebSocket for Margin Trading

WebSocket URL

wss://bitmax.io/<account-group>/api/stream/margin-beta/<symbol>

Data Channel - Market Depth

See cash trading market depth

Data Channel - Market Trades

See cash trading market trades

Data Channel - Market Summary

See cash trading market summary

Data Channel - Bar Data

See cash trading market bar data

Data Channel - Reference Prices

Reference Prices

{
  "m":  "ref-px",  // message
  "ba": "XRP",     // base asset
  "qa": "USDT",    // quote asset
  "p":  "0.3406"   // price 
}

Reference prices are composite price indices for the calculation of margin requirement and forced liquidation. The reference price is computed by taking an average last trade price from the following five exchanges (upon availability at the time of computation) - BitMax.io, Binance, Huobi, OKEx and Poloniex , and removing the highest and lowest price.

BitMax.io reserves the right of updating pricing sources without notice.

The server sends out ref-px message every 10 seconds.

Data Channel - Order Updates

See cash trading order updates

Data Channel - Margin Summary

Margin Summary

{
  "m":"margin-summary", // message
  "data": {
    "b":   "100000",  // total balance
    "pb":  "99499.5", // pending (available) balance 
    "nb":  "100000",  // net asset  
    "eim": "0",       // effective initial margin
    "emm": "0",       // effective maintanence margin
    "clv": "1",       // current leverage
    "ilv": "3.0303",  // deprecated, will be removed shortly
    "alv": "10",      // account maximum leverage
    "cus": "-1",      // cusion rate
    "pts": "346"      // point card balance
  }
}

The margin-summary message contains risk metrics of the overall account. It is important to monitor the risk metrics closely and adjust your positions accordingly to avoid forced account liquidation.

The server emits the margin-summary message along with reference prices updates.

Data Channel - Margin Balance

Margin Balance

{
  "m":"margin-balance", 
  "data": {
    "baseAsset": {
      "a":  "BTC",         // asset code 
      "b":  "0",           // total balance
      "pb": "0",           // pending (available) balance
      "br": "0",           // borrowed amount
      "i":  "0",           // interest owed
      "ms": "0",           // maximum sellable amount
      "r":  "0.00062"      // daily interest rate 
    },
    "quoteAsset": {
      "a":  "USDT",        // asset code 
      "b":  "100000",      // total balance
      "pb": "99499.5",     // pending (available) balance
      "br": "0",           // borrowed amount
      "i":  "0",           // interest owed
      "ms": "117109.454",  // maximum sellable amount
      "r":  "0.0012"       // daily interest rate 
    }
  }
}

The margin-balance message contains the balance data regarding the current symbol - the symbol specified in the URL of the API call.

The server emits the margin-balance message along with reference prices updates.

Error Codes

(Work in progress)

Code Message
1900 Invalid Http Request Input.
21008 API key does not have transfer permission
6010 Not enough balance

FAQ

1900 - Invalid Http Request Input.

This usually happens when numeric values are provided for parameters of string type. For instance, when placing new orders, we require both order price and order quantity to be strings. You will receive error = 1900 if you use numeric value for either of them.