Table of Contents generated with DocToc
- Private stream for bitbank
A private stream is a feature that allows you to receive real-time user data (such as order and asset change information) from the bitbank server. This feature is useful when you want to trade using real-time user data. User data is sent using PubNub and can be received in real-time.
PubNub is a service that provides real-time data streaming. bitbank uses PubNub to provide users with real-time user data.
Using the PubNub SDK, you can connect to the PubNub server based on the information obtained from the API and receive user data.
To use the private stream, please get your API key and secret from the bitbank website.
To connect to the private stream, you need to get the channel name and token from REST API GET /v1/user/subscribe endpoint.
Refer to "Get channel and token for private stream" in rest-api.
To connect to the private stream, you need to use the PubNub SDK. You can connect to the private stream by following the steps below:
- Install the PubNub SDK for your language. ex. JavaScript:
npm install pubnub
- Create a PubNub configuration. ex. JavaScript
- Receive user data from the private stream. ex. JavaScript
Use sub-c-ecebae8e-dd60-11e6-b6b1-02ee2ddab7fe
as the subscribeKey.
Refer to the Example code for detailed implementation.
Once you have connected to the private stream, you can start receiving user data. The user data is sent in JSON format and contains the following information:
Receive information about changes in owned assets.
Name | Type | Description |
---|---|---|
asset | string | Asset name: Asset list |
amount_precision | number | Precision |
free_amount | string | Available amount |
locked_amount | string | Locked amount |
onhand_amount | string | On-hand amount |
withdrawing_amount | string | Withdrawing amount |
Response format:
{
"message": {
"method": "asset_update",
"params": [
{
"asset": "string",
"amountPrecision": 0,
"freeAmount": "string",
"lockedAmount": "string",
"onhandAmount": "string",
"withdrawingAmount": "string"
}
]
}
}
Receive information about new orders.
If you are managing active orders locally, when you receive a notification with the status FULLY_FILLED
, CANCELED_UNFILLED
, or CANCELED_PARTIALLY_FILLED
, it indicates that the order has been executed or canceled, so please remove it from your order information.
Name | Type | Description |
---|---|---|
average_price | string | avg executed price |
canceled_at | number | canceled at unix timestamp (milliseconds) |
executed_amount | string | qty executed |
executed_at | number | order executed at unix timestamp (milliseconds) |
order_id | number | order ID |
ordered_at | number | ordered at unix timestamp (milliseconds) |
pair | string | pair enum: pair list |
price | string | order price |
trigger_price | string | undefined | trigger price(present only if type = stop , stop_limit , take_profit , stop_loss ) |
remaining_amount | string | null | qty not executed |
position_side | string | undefined | long or short (only for margin trading) |
side | string | buy or sell |
start_amount | string | null | order qty when placed |
status | string | status enum: INACTIVE , UNFILLED , PARTIALLY_FILLED , FULLY_FILLED , CANCELED_UNFILLED , CANCELED_PARTIALLY_FILLED |
type | string | one of limit , market , stop , stop_limit , take_profit , stop_loss , losscut |
expire_at | number | null | expiration time in unix timestamp (milliseconds) |
triggered_at | number | undefined | triggered at unix timestamp (milliseconds) (present only if type = stop , stop_limit , take_profit , stop_loss ) |
post_only | boolean | undefined | whether Post Only or not (present only if type = limit ) |
user_cancelable | boolean | User cancelable |
is_just_triggered | boolean | Just triggered |
Response format:
{
"message": {
"method": "spot_order_new",
"params": [
{
"average_price": "string",
"canceled_at": 0,
"executed_amount": "string",
"executed_at": 0,
"order_id": 0,
"ordered_at": 0,
"pair": "string",
"price": "string",
"trigger_price": "string",
"remaining_amount": "string",
"position_side": "string",
"side": "string",
"start_amount": "string",
"status": "string",
"type": "string",
"expire_at": 0,
"triggered_at": 0,
"post_only": false,
"user_cancelable": true,
"is_just_triggered": false
}
]
}
}
Receive information about order updates.
The content is the same as spot_order_new
.
If you are managing active orders locally, when you receive a notification with the status FULLY_FILLED
, CANCELED_UNFILLED
, or CANCELED_PARTIALLY_FILLED
, it indicates that the order has been executed or canceled, so please remove it from your order information.
Response format:
{
"message": {
"method": "spot_order",
"params": [
{
"average_price": "string",
"canceled_at": 0,
"executed_amount": "string",
"executed_at": 0,
"order_id": 0,
"ordered_at": 0,
"pair": "string",
"price": "string",
"trigger_price": "string",
"remaining_amount": "string",
"position_side": "string",
"side": "string",
"start_amount": "string",
"status": "string",
"type": "string",
"expire_at": 0,
"triggered_at": 0,
"post_only": false,
"user_cancelable": true,
"is_just_triggered": false
}
]
}
}
Receive information about order invalidation.
This notification is sent when an order is invalidated due to asset shortages within our matching engine.
Therefore, this notification does not occur frequently.
Immediate cancellations of orders that typically occur are notified via spot_order_new
, spot_order
, or error responses from the REST API.
If you are managing active orders locally, please remove the notified order from your order information.
Name | Type | Description |
---|---|---|
order_id | number | order ID |
Response format:
{
"message": {
"method": "spot_order_invalidation",
"params": {
"order_id": [1, 2, 3]
}
}
}
Receive information about trades.
Name | Type | Description |
---|---|---|
amount | string | executed amount |
executed_at | number | order executed at unix timestamp (milliseconds) |
fee_amount_base | string | base asset fee amount |
fee_amount_quote | string | quote asset fee amount |
fee_occurred_amount_quote | string | Quote fee occurred. Collected on close orders for margin trading. For spot trading, it is collected immediately and is the same as fee_amount_quote . |
maker_taker | string | maker or taker |
order_id | number | order ID |
pair | string | pair enum: pair list |
price | string | order price |
position_side | string | undefined | long or short (only for margin trading) |
side | string | buy or sell |
trade_id | number | trade ID |
type | string | one of limit , market , stop , stop_limit , take_profit , stop_loss , losscut |
profit_loss | string | undefined | realized profit and loss |
interest | string | undefined | interest |
Response format:
{
"message": {
"method": "spot_trade",
"params": [
{
"amount": "string",
"executed_at": 0,
"fee_amount_base": "string",
"fee_amount_quote": "string",
"fee_occurred_amount_quote": "string",
"maker_taker": "string",
"order_id": 0,
"pair": "string",
"price": "string",
"position_side": "string",
"side": "string",
"trade_id": 0,
"type": "string",
"profit_loss": "string",
"interest": "string"
}
]
}
}
Receive information about new dealer orders.
Name | Type | Description |
---|---|---|
order_id | string | order ID |
asset | string | enum: asset list |
side | string | buy or sell |
price | string | price |
amount | string | amount |
ordered_at | number | ordered at unix timestamp (milliseconds) |
Response format:
{
"message": {
"method": "dealer_order_new",
"params": [
{
"order_id": 0,
"asset": "string",
"side": "string",
"price": "string",
"amount": "string",
"ordered_at": 0
}
]
}
}
Receive information about withdrawals.
Name | Type | Description |
---|---|---|
uuid | string | withdrawal ID |
network | string | enum: network list(only for crypto assets) |
asset | string | enum: asset list |
account_uuid | string | account UUID |
asset | string | enum: asset list |
fee | string | withdrawal fee |
label | string | withdrawal account label (only for crypto assets) |
address | string | withdrawal destination address (only for crypto assets) |
txid | string | null | withdrawal transaction id (only for crypto assets) |
bank_name | string | bank of withdrawal account (only for fiat assets) |
branch_name | string | bank branch of withdrawal account (only for fiat assets) |
account_type | string | type of withdrawal account (only for fiat assets) |
account_number | string | withdrawal account number (only for fiat assets) |
account_owner | string | owner of withdrawal account (only for fiat assets) |
status | string | withdrawal status enum: CONFIRMING , EXAMINING , SENDING , DONE , REJECTED , CANCELED , CONFIRM_TIMEOUT |
requested_at | number | requested at unix timestamp (milliseconds) |
Response format:
{
"message": {
"method": "withdrawal",
"params": [
{
"uuid": "string",
"asset": "string",
"account_uuid": "string",
"amount": "string",
"fee": "string",
"bank_name": "string",
"branch_name": "string",
"account_type": "string",
"account_number": "string",
"account_owner": "string",
"status": "string",
"requested_at": 0
}
]
}
}
Receive information about deposits.
Name | Type | Description |
---|---|---|
uuid | string | deposit ID |
asset | string | enum: asset list |
amount | number | deposit amount |
network | string | enum: network list(only for crypto assets) |
address | string | deposit address(only for crypto assets) |
txid | string | null | deposit transaction id (only for crypto assets) |
found_at | number | found at unix timestamp (milliseconds) |
confirmed_at | number | confirmed (about to be added to your balance) at unix timestamp (milliseconds, exists only for confirmed one) |
status | string | deposit status enum: FOUND , CONFIRMED , DONE |
Response format:
{
"message": {
"method": "deposit",
"params": [
{
"uuid": "string",
"asset": "string",
"amount": "string",
"network": "string",
"address": "string",
"txid": "string",
"found_at": 0,
"confirmed_at": 0,
"status": "string"
}
]
}
}
Receive information about margin positions.
Name | Type | Description |
---|---|---|
pair | string | pair enum: pair list |
position_side | string | long or short |
average_price | string | avg executed price |
open_amount | string | open amount |
locked_amount | string | locked amount |
product | string | average executed price x open amount |
unrealized_fee_amount | string | unrealized fee amount |
unrealized_interest_amount | string | unrealized interest amount |
Response format:
{
"message": {
"method": "margin_position_update",
"params": [
{
"pair": "string",
"position_side": "string",
"average_price": "string",
"open_amount": "string",
"locked_amount": "string",
"product": "string",
"unrealized_fee_amount": "string",
"unrealized_interest_amount": "string"
}
]
}
}
Receive information about margin payables.
Name | Type | Description |
---|---|---|
amount | string | payable amount |
Response format:
{
"message": {
"method": "margin_payable_update",
"params": [
{
"amount": "string"
}
]
}
}
Receive information about margin notices.
This is published when a margin call or insufficient funds occur, or when they are partially deposited or partially repaid.
Additionally, if these are resolved or fully settled, a message with all properties set to null
will be published.
Name | Type | Description |
---|---|---|
what | string | null | what the notice is for (marginCall, debt, or settled) |
occurred_at | number | null | occurrence time |
amount | string | null | amount |
due_date_at | number | null | due date |
Response format:
{
"message": {
"method": "margin_notice_update",
"params": [
{
"what": "string",
"occurred_at": 0,
"amount": "string",
"due_date_at": 0
}
]
}
}
If the connection to the private stream is lost, you can reconnect to PubNub by following the steps below:
- Detect that the connection to PubNub has been lost from the status event.
- Reconnect to PubNub.
Refer to the Example code for detailed implementation.
Here is an example code that shows how to connect to the private stream and receive user data:
// npm install pubnub
const PubNub = require('pubnub');
const crypto = require('crypto');
const API_KEY = '<your_api_key>';
const API_SECRET = '<your_api_secret>';
const PUBNUB_SUB_KEY = 'sub-c-ecebae8e-dd60-11e6-b6b1-02ee2ddab7fe';
const main = async () => {
const { channel, token } = await getChannelAndToken();
const pubnub = getPubNubAndAddListener(channel, token);
subscribePrivateChannel(pubnub, channel, token);
setInterval(() => {
// Keep connection alive
}, 10000);
}
const toSha256 = (key, value) =>{
return crypto
.createHmac('sha256', key)
.update(Buffer.from(value))
.digest('hex')
.toString();
}
const getPubNubAndAddListener = (channel, token) => {
const pubnub = new PubNub({
subscribeKey: PUBNUB_SUB_KEY,
userId: channel,
ssl: true,
});
pubnub.addListener({
status: async (status) => {
switch (status.category) {
/**
* When pubnub channel connection established successfully.
* This is called once after trying to start to connect.
*/
case 'PNConnectedCategory': {
console.info('pubnub connection established');
break;
}
/**
* When connection restored.
*/
case 'PNNetworkUpCategory':
case 'PNReconnectedCategory': {
console.info('pubnub connection restored');
// When network down, pubnub disposes subscribers so we need to re-subscribe manually.
subscribePrivateChannel(pubnub_channel, token);
break;
}
/**
* When connection failed by timeout.
* In this case, we need to reconnect manually.
*/
case 'PNTimeoutCategory': {
console.warn('pubnub connection Failed by timeout.');
await reconnect();
break;
}
/**
* When connection failed due to network error.
*/
case 'PNNetworkDownCategory':
case 'PNNetworkIssuesCategory': {
console.error('pubnub connection network error', status);
await reconnect();
break;
}
/**
* This will be called when token is expired.
*/
case 'PNAccessDeniedCategory': {
console.error('pubnub access denied', status);
await reconnect();
break;
}
/**
* This will not be called.
* Maybe pubnub-library is not implement these events.
*/
case 'PNBadRequestCategory':
case 'PNMalformedResponseCategory':
case 'PNDecryptionErrorCategory': {
console.error('pubnub connection failed', status);
break;
}
/**
* This will not be called.
* If this called, implement new handling for the event.
*/
default: {
console.warn('default');
}
}
},
message: (data) => {
if (data && data.message) {
console.info('message received', JSON.stringify(data.message));
}
},
});
return pubnub;
}
const getChannelAndToken = async () => {
const nonce = new Date().getTime();
const timeWindow = '5000';
const message = `${nonce}${timeWindow}/v1/user/subscribe`;
// Get channel and token from API
const res = await fetch('https://api.bitbank.cc/v1/user/subscribe', {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'ACCESS-KEY': API_KEY,
'ACCESS-REQUEST-TIME': nonce.toString(),
'ACCESS-TIME-WINDOW': timeWindow,
'ACCESS-SIGNATURE': toSha256(API_SECRET, message),
},
}).then((res) => res.json());
const channel = res.data.pubnub_channel;
const token = res.data.pubnub_token;
return { channel, token };
}
const subscribePrivateChannel = (pubnub, channel, token) => {
pubnub.setToken(token);
pubnub.subscribe({
channels: [channel],
});
}
const reconnect = async () => {
// Reconnect to pubnub
const { channel, token } = await getChannelAndToken();
const pubnub = getPubNubAndAddListener(channel, token);
subscribePrivateChannel(pubnub, channel, token);
}
main().catch(console.error);