Custom

Custom Exchange #

The custom exchange is an interface that connects the application to a custom exchange implementation through the HTTP and WebSocket APIs.

Configuration #

{
	"type": "custom",
	"url": {
		"http": "http://custom-exchange.com/api",
		"ws": "ws://custom-exchange.com/api/ws"
	},
	"key": "cQoRSm21nyovtTcufM8Si2IBHtN",
	"secret": "qXN4yR2KXQzs7c0DcXWVEOSNIhTrvG"
}
  • type - string
    The type of the exchange configuration.

    Exchange configuration types are described in detail here.

  • url - object
    The URL information of the custom exchange.

    • http - string
      The URL to which HTTP requests are sent. It must be a valid URL as described here.

    • ws - string (optional; default: unused)
      The URL that is used to open a WebSocket connection. It must be a valid URL as described here.

      If this property is omitted or left empty, a WebSocket connection is not opened, which means only the HTTP API is used for data retrieval.

  • key - string (optional; default: unused)
    The authentication key that is sent in the CUSTOM-KEY header. It may be used to authenticate requests in the custom exchange’s system.

  • secret - string (optional; default: unused)
    The secret key that is used to sign requests before sending them to the custom exchange. The generated signature is sent in the CUSTOM-SIGNATURE header.

    The signature generation process is described in detail here.

HTTP API #

For the application to function properly, all the required HTTP endpoints should be implemented as described below. If a resource (e.g., account information) is not available, the 404 status code should be returned.

The CUSTOM-TIMESTAMP header is used to send a timestamp of each request’s creation. The custom exchange may use it to reject a request if it arrives later than expected.

A timestamp is a number of seconds since the Unix Epoch in UTC.

Errors #

In case of an error, the server should respond with an appropriate HTTP status code (4XX or 5XX) and a body containing the following JSON object:

{
	"message": "internal error"
}
  • message - string
    The message of the error.

Cooldown #

The 429 status code can be sent to force the application to enter a cooldown mode. A Retry-After header should be sent in the same response to indicate how long the application should remain in this state. The Retry-After value should be a positive integer representing seconds as described here.

Signature #

If the secret configuration option is provided, a request’s signature is generated and included in the CUSTOM-SIGNATURE header. It may be used to verify the integrity and authenticity of the request’s data.

The following steps are taken to generate a signature for each request:

var crypto = require('crypto');

var timestamp = Date.now() / 1000; // this value is sent in the CUSTOM-TIMESTAMP header
var method = 'POST';
var requestPath  = '/orders'
var body = JSON.stringify({
    price: '1.0'
});
var secret = "<value from the config>"

// the order of the elements here is important
// the body is omitted if it is empty
var message = timestamp + method + requestPath + body;

var hmac = crypto.createHmac('sha256', secret);
var signature = hmac.update(message).digest('base64');
// the signature is sent in the CUSTOM-SIGNATURE header
The signature is generated for all requests, including the initial WebSocket connection request.

Exchange Traits Retrieval #

GET /traits

Retrieves the meta information (also known as the traits) of the exchange.

Query parameters: none

Request body: none

Response body:

{
	"http_max_candles": 500,
	"ws_trades_instead_of_candles": false,
	"candle_ttl": "10s",
	"ticker_ttl": "30s",
	"position_ttl": "5s",
	"account_info_ttl": "5s"
}
  • http_max_candles - unsigned int
    The maximum number of candles that can be returned when making a single HTTP request.

  • ws_trades_instead_of_candles - boolean (optional; default: false)
    Specifies whether public trade data instead of candle data should be expected to be sent via an open WebSocket connection.

  • candle_ttl - string (duration)
    The amount of time that has to pass since a candle’s retrieval before it is deleted from the cache. When a candle is not found in the cache, an HTTP request is performed to retrieve it. If a non-positive value is returned, the data is kept indefinitely.

    Both HTTP and WebSocket candle data is cached, so it is best to send as much data via a WebSocket connection as possible.

  • ticker_ttl - string (duration)
    The amount of time that has to pass since a ticker’s retrieval before it is deleted from the cache. When a ticker is not found in the cache, an HTTP request is performed to retrieve it. If a non-positive value is returned, the data is kept indefinitely.

    Both HTTP and WebSocket ticker data is cached, so it is best to send as much data via a WebSocket connection as possible.

  • position_ttl - string (duration)
    The amount of time that has to pass since a position’s retrieval before it is deleted from the cache. When a position is not found in the cache, an HTTP request is performed to retrieve it. If a non-positive value is returned, the data is kept indefinitely.

    Both HTTP and WebSocket position data is cached, so it is best to send as much data via a WebSocket connection as possible.

  • account_info_ttl - string (duration)
    The amount of time that has to pass since account information’s retrieval before it is deleted from the cache. When account information is not found in the cache, an HTTP request is performed to retrieve it. If a non-positive value is returned, the data is kept indefinitely.

    Both HTTP and WebSocket account information is cached, so it is best to send as much data via a WebSocket connection as possible.

Multiple Intervals Retrieval #

GET /intervals

Retrieves all available exchange intervals.

Query parameters: none

Request body: none

Response body:

[
	"1hour",
	"4hours",
	"1day",
	"1week"
]

The returned array should contain interval strings. Possible values:

  • 1min
  • 3mins
  • 5mins
  • 15mins
  • 30mins
  • 1hour
  • 2hours
  • 4hours
  • 6hours
  • 8hours
  • 12hours
  • 1day
  • 3days
  • 1week
  • 1month
  • 1year

Multiple Symbols Retrieval #

GET /symbols

Retrieves all available exchange symbols.

Query parameters: none

Request body: none

Response body:

[
	"BTC_USDT",
	"ETH_USDT",
	"LTC_USDT"
]

The returned array should contain symbol strings. The allowed symbol formats are:

  • BASE_QUOTE
  • BASE/QUOTE
  • ASSET

Multiple Candles Retrieval #

GET /candles

Retrieves multiple exchange candles.

Query parameters:

  • symbol - string
    The symbol of candles.

  • interval - string
    The interval of candles.

  • limit - unsigned int
    The number of candles.

  • end-time - string (RFC 3339; optional; default: current time)
    If specified, only candles whose timestamps are not greater than this value should be returned.

Request body: none

Response body:

[
	{
		"opened_at": "2020-09-10T21:00:20Z",
		"open": "2",
		"high": "3",
		"low": "4",
		"close": "5",
		"volume": "6"
	},
	{
		"opened_at": "2020-09-10T21:05:20Z",
		"open": "3",
		"high": "4",
		"low": "5",
		"close": "6",
		"volume": "7"
	},
	{
		"opened_at": "2020-09-10T21:10:20Z",
		"open": "4",
		"high": "5",
		"low": "6",
		"close": "7",
		"volume": "8"
	}
]
The candles should be ordered in ascending order, which means that the latest candle should always be the last one.

The returned array should contain candle objects belonging to a specific symbol and interval. Candle object properties are:

  • opened_at - string (RFC 3339)
    The exact time when the candle was opened. It may be used to uniquely identify the candle.

  • open - string (decimal)
    The open price of the candle.

  • high - string (decimal)
    The high price of the candle.

  • low - string (decimal)
    The low price of the candle.

  • close - string (decimal)
    The close price of the candle.

  • volume - string (decimal)
    The transaction volume of the candle.

Multiple Tickers Retrieval #

GET /tickers

Retrieves multiple exchange tickers.

Query parameters:

  • symbols - array of strings
    The array of ticker symbols.

Request body: none

Response body:

{
	"BTC_USDT": {
		"last": "31211.45",
		"ask": "32211.45",
		"bid": "30211.45",
		"change": "1201.12",
		"percent_change": "7",
		"volume": "31234512.1"
	},
	"ETH_USDT": {
		"last": "3111.45",
		"ask": "3221.45",
		"bid": "3021.45",
		"change": "1201.12",
		"percent_change": "12",
		"volume": "3124512.1"
	}
}

The returned object is a map that should contain symbols along with their ticker data. Ticker object properties are:

  • last - string (decimal)
    The last (most recent) price of the asset.

  • ask - string (decimal)
    The ask price of the asset.

  • bid - string (decimal)
    The bid price of the asset.

  • change - string (decimal)
    The 24-hour price change.

  • percent_change - string (decimal)
    The 24-hour price change percentage.

  • volume - string (decimal)
    The 24-hour transaction volume.

Account Information Retrieval #

GET /account

Retrieves exchange account information.

Query parameters: none

Request body: none

Response body:

{
	"cash": {
		"asset": "USD",
		"quantity": "31.0"
	}
}
  • cash - object
    The information about cash resources.
    • asset - string
      The asset that is being used as cash. If the cash resources are not being used, the asset should be returned as an empty string.

    • quantity - string (decimal)
      The available quantity of the cash asset.

Exchange Positions Retrieval #

GET /positions

Retrieves all exchange positions.

Query parameters: none

Request body: none

Response body:

{
	"BTC": {
		"quantity": "0.31"
	},
	"ETH": {
		"quantity": "1203.12"
	}
}

The returned object is a map that should contain assets along with their position data. Position object properties are:

  • quantity - string (decimal)
    The number of asset units that are owned.

Multiple Orders Retrieval #

GET /orders

Retrieves multiple orders.

Query parameters:

  • symbol - string
    The symbol of orders.

  • side - string (enum; optional; default: both)
    The side of orders. Possible values:

    • buy
    • sell
  • status - string (enum)
    The status of orders. Possible values:

    • open

Request body: none

Response body:

[
	{
		"id": "9bsv0s78ajk0036f3m60",
		"side": "buy",
		"price": "38012.123",
		"total_quantity": "0.0541",
		"filled_quantity": "0.0241"
	},
	{
		"id": "1bsv0s78ajk0036f3m60",
		"side": "buy",
		"price": "18012.123",
		"total_quantity": "1.0541",
		"filled_quantity": "1.0241"
	}
]

The returned array should contain order objects belonging to a specific symbol. Order object properties are:

  • id - string
    The ID of the order that is used by the exchange.

  • side - string (enum)
    The side of the order. Possible values:

    • buy
    • sell
  • price - string (decimal)
    The price of the asset.

  • total_quantity - string (decimal)
    The total quantity of the asset.

  • filled_quantity - string (decimal)
    The quantity of the asset that is already filled/traded.

Order Placement #

POST /orders

Places a new order.

Query parameters: none

Request body:

{
	"symbol": "BTC_USDT",
	"side": "buy",
	"price": "39131.012",
	"quantity": "0.134"
}
  • symbol - string
    The symbol of the order.

  • side - string (enum)
    The side of the order. Possible values:

    • buy
    • sell
  • price - string (decimal)
    The price of the asset.

  • quantity - string (decimal)
    The quantity of the asset.

Response body:

{
	"id": "9bsv0s78ajk0036f3m60",
	"price": "38012.123",
	"total_quantity": "0.0541",
	"filled_quantity": "0.0241"
}
  • id - string
    The ID of the order that is used by the exchange.

  • price - string (decimal)
    The price of the asset.

  • total_quantity - string (decimal)
    The total quantity of the asset.

  • filled_quantity - string (decimal)
    The quantity of the asset that is already filled/traded.

Order Cancellation #

DELETE /orders

Cancels open orders.

Query parameters:

  • symbol - string
    The symbol of an order.

  • ids - array of strings
    The array of order IDs.

Request body: none

Response body: none

WebSocket API #

For the application to function properly, all the required WebSocket topics should be handled as described below. If a resource (e.g., account information) is not available, it should not be published.

Event Payloads and Subscriptions #

All events should be sent in the following format:

{
	"topic": "[email protected]",
	"payload": {
		// <event payload>
	}
}

To receive events of a certain topic, a subscription WebSocket request with a request ID of an unsigned int type is sent:

{
	"topic": "[email protected]",
	"id": 1
}

Likewise, to unsubscribe from a certain topic, an unsubscription WebSocket request is sent:

{
	"topic": "[email protected]",
	"id": 1
}

On successful subscription or unsubscription, a response with the same request ID should be given:

{
	"success": true,
	"id": 1
}
Duplicate subscriptions and unsubscriptions targeting nonexistent subscriptions should be permitted without producing any results afterwards.

Candle Update #

update@candles.{symbol}.{interval}

Sends a notification when a specific symbol and interval’s candle data is updated.

Payload:

{
	"opened_at": "2020-09-10T21:01:20Z",
	"open": "2",
	"high": "3",
	"low": "4",
	"close": "5",
	"volume": "6"
}
  • opened_at - string (RFC 3339)
    The exact time when the candle was opened. It may be used to uniquely identify the candle.

  • open - string (decimal)
    The open price of the candle.

  • high - string (decimal)
    The high price of the candle.

  • low - string (decimal)
    The low price of the candle.

  • close - string (decimal)
    The close price of the candle.

  • volume - string (decimal)
    The transaction volume of the candle.

Public Trade Update #

update@trades.{symbol}

Sends a notification when a specific symbol’s public trade data is updated.

Payload:

{
	"timestamp": "2020-09-10T21:01:20Z",
	"side": "buy",
	"price": "40.1",
	"quantity": "3.45"
}
  • timestamp - string (RFC 3339)
    The exact time when the trade was made.

  • side - string (enum)
    The side of the trade. Possible values:

    • buy
    • sell
  • price - string (decimal)
    The price of the asset.

  • quantity - string (decimal)
    The quantity of the asset.

Ticker Update #

update@tickers.{symbol}

Sends a notification when a specific symbol’s ticker data is updated.

If symbol is not provided (update@tickers) when a subscription is being made, tickers of all symbols should be published. However, when publishing, the topic should still include the symbol (update@tickers.{symbol}).

Payload:

{
	"last": "31211.45",
	"ask": "32211.45",
	"bid": "30211.45",
	"change": "1201.12",
	"percent_change": "7",
	"volume": "31234512.1"
}
  • last - string (decimal)
    The last (most recent) price of the asset.

  • ask - string (decimal)
    The ask price of the asset.

  • bid - string (decimal)
    The bid price of the asset.

  • change - string (decimal)
    The 24-hour price change.

  • percent_change - string (decimal)
    The 24-hour price change percentage.

  • volume - string (decimal)
    The 24-hour transaction volume.

Account Information Update #

update@account

Sends a notification when account information is updated.

Payload:

{
	"cash": {
		"asset": "USD",
		"quantity": "31.0"
	}
}
  • cash - object
    The information about cash resources.
    • asset - string
      The asset that is being used as cash. If the cash resources are not being used, the asset should be returned as an empty string.

    • quantity - string (decimal)
      The available quantity of the cash asset.

Positions Update #

update@positions

Sends a notification when account positions are updated.

Payload:

{
	"BTC": {
		"quantity": "0.31"
	},
	"ETH": {
		"quantity": "1203.12"
	}
}
  • quantity - string (decimal)
    The number of asset units that are owned.

Order Update #

update@orders.{status}.{symbol}

Sends a notification when a specific symbol’s order is updated. Possible status values:

  • open
  • cancelled
  • partially_filled
  • filled
If status and symbol are not provided (update@orders) when a subscription is being made, orders of all statuses and symbols should be published. However, when publishing, the topic should still include the status and symbol (update@orders.{status}.{symbol}).

Payload:

{
	"id": "9bsv0s78ajk0036f3m60",
	"side": "buy",
	"price": "38012.123",
	"total_quantity": "0.0541",
	"filled_quantity": "0.0241"
}
  • id - string
    The ID of the order that is used by the exchange.

  • side - string (enum)
    The side of the order. Possible values:

    • buy
    • sell
  • price - string (decimal)
    The price of the asset.

  • total_quantity - string (decimal)
    The total quantity of the asset.

  • filled_quantity - string (decimal)
    The quantity of the asset that is already filled/traded.