@proton/ccxt
Version:
A JavaScript / TypeScript / Python / C# / PHP cryptocurrency trading library with support for 130+ exchanges
1,216 lines (1,213 loc) • 80.3 kB
JavaScript
// ----------------------------------------------------------------------------
// PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
// https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
// EDIT THE CORRESPONDENT .ts FILE INSTEAD
// ---------------------------------------------------------------------------
import Exchange from './abstract/bkex.js';
import { ExchangeError, BadRequest, ArgumentsRequired, InsufficientFunds, InvalidOrder } from './base/errors.js';
import { TICK_SIZE } from './base/functions/number.js';
import { sha256 } from './static_dependencies/noble-hashes/sha256.js';
// ---------------------------------------------------------------------------
export default class bkex extends Exchange {
describe() {
return this.deepExtend(super.describe(), {
'id': 'bkex',
'name': 'BKEX',
'countries': ['BVI'],
'rateLimit': 100,
'version': 'v2',
'certified': false,
'has': {
'CORS': undefined,
'spot': true,
'margin': undefined,
'swap': true,
'future': undefined,
'option': undefined,
'addMargin': undefined,
'cancelAllOrders': undefined,
'cancelOrder': true,
'cancelOrders': true,
'createDepositAddress': undefined,
'createLimitOrder': undefined,
'createMarketOrder': undefined,
'createOrder': true,
'editOrder': undefined,
'fetchAccounts': undefined,
'fetchBalance': true,
'fetchBidsAsks': undefined,
'fetchBorrowRate': undefined,
'fetchBorrowRateHistory': undefined,
'fetchBorrowRates': undefined,
'fetchBorrowRatesPerSymbol': undefined,
'fetchCanceledOrders': undefined,
'fetchClosedOrder': undefined,
'fetchClosedOrders': true,
'fetchCurrencies': true,
'fetchDeposit': false,
'fetchDepositAddress': true,
'fetchDepositAddresses': undefined,
'fetchDepositAddressesByNetwork': undefined,
'fetchDeposits': true,
'fetchDepositWithdrawFee': 'emulated',
'fetchDepositWithdrawFees': true,
'fetchFundingHistory': undefined,
'fetchFundingRate': undefined,
'fetchFundingRateHistory': true,
'fetchFundingRates': undefined,
'fetchIndexOHLCV': undefined,
'fetchL2OrderBook': undefined,
'fetchLedger': undefined,
'fetchLedgerEntry': undefined,
'fetchLeverageTiers': undefined,
'fetchMarginMode': false,
'fetchMarketLeverageTiers': true,
'fetchMarkets': true,
'fetchMarkOHLCV': undefined,
'fetchMyTrades': undefined,
'fetchOHLCV': true,
'fetchOpenOrder': true,
'fetchOpenOrders': true,
'fetchOrder': false,
'fetchOrderBook': true,
'fetchOrderBooks': undefined,
'fetchOrders': undefined,
'fetchOrderTrades': undefined,
'fetchPosition': undefined,
'fetchPositionMode': false,
'fetchPositions': undefined,
'fetchPositionsRisk': undefined,
'fetchPremiumIndexOHLCV': undefined,
'fetchStatus': true,
'fetchTicker': true,
'fetchTickers': true,
'fetchTime': true,
'fetchTrades': true,
'fetchTradingFee': false,
'fetchTradingFees': false,
'fetchTradingLimits': undefined,
'fetchTransactionFee': 'emulated',
'fetchTransactionFees': true,
'fetchTransactions': undefined,
'fetchTransfer': false,
'fetchTransfers': false,
'fetchWithdrawal': false,
'fetchWithdrawals': true,
'reduceMargin': undefined,
'setLeverage': undefined,
'setMarginMode': undefined,
'setPositionMode': undefined,
'signIn': undefined,
'transfer': false,
'withdraw': false,
},
'timeframes': {
'1m': '1m',
'5m': '5m',
'15m': '15m',
'30m': '30m',
'1h': '1h',
'4h': '4h',
'6h': '6h',
'12h': '12h',
'1d': '1d',
'1w': '1w',
},
'urls': {
'logo': 'https://user-images.githubusercontent.com/1294454/158043180-bb079a65-69e8-45a2-b393-f094d334e610.jpg',
'api': {
'spot': 'https://api.bkex.com',
'swap': 'https://fapi.bkex.com',
},
'www': 'https://www.bkex.com/',
'doc': [
'https://bkexapi.github.io/docs/api_en.htm',
],
'fees': [
'https://www.bkex.com/help/instruction/33',
],
},
'api': {
'public': {
'spot': {
'get': {
'/common/symbols': 1,
'/common/currencys': 1,
'/common/timestamp': 1,
'/q/kline': 1,
'/q/tickers': 1,
'/q/ticker/price': 1,
'/q/depth': 1,
'/q/deals': 1,
},
},
'swap': {
'get': {
'/market/candle': 1,
'/market/deals': 1,
'/market/depth': 1,
'/market/fundingRate': 1,
'/market/index': 1,
'/market/riskLimit': 1,
'/market/symbols': 1,
'/market/ticker/price': 1,
'/market/tickers': 1,
'/server/ping': 1,
},
},
},
'private': {
'spot': {
'get': {
'/u/api/info': 1,
'/u/account/balance': 1,
'/u/wallet/address': 1,
'/u/wallet/depositRecord': 1,
'/u/wallet/withdrawRecord': 1,
'/u/order/openOrders': 1,
'/u/order/openOrder/detail': 1,
'/u/order/historyOrders': 1,
},
'post': {
'/u/account/transfer': 1,
'/u/wallet/withdraw': 1,
'/u/order/create': 1,
'/u/order/cancel': 1,
'/u/order/batchCreate': 1,
'/u/order/batchCancel': 1,
},
},
'swap': {
'get': {
'/account/balance': 1,
'/account/balanceRecord': 1,
'/account/order': 1,
'/account/orderForced': 1,
'/account/position': 1,
'/entrust/finished': 1,
'/entrust/unFinish': 1,
'/order/finished': 1,
'/order/finishedInfo': 1,
'/order/unFinish': 1,
'/position/info': 1,
},
'post': {
'/account/setLeverage': 1,
'/entrust/add': 1,
'/entrust/cancel': 1,
'/order/batchCancel': 1,
'/order/batchOpen': 1,
'/order/cancel': 1,
'/order/close': 1,
'/order/closeAll': 1,
'/order/open': 1,
'/position/setSpSl': 1,
'/position/update': 1,
},
},
},
},
'fees': {
'trading': {
'tierBased': false,
'percentage': true,
'maker': this.parseNumber('0.0015'),
'taker': this.parseNumber('0.002'),
},
},
'options': {
'timeframes': {
'spot': {
'1m': '1m',
'5m': '5m',
'15m': '15m',
'30m': '30m',
'1h': '1h',
'4h': '4h',
'6h': '6h',
'12h': '12h',
'1d': '1d',
'1w': '1w',
},
'swap': {
'1m': 'M1',
'5m': 'M5',
'15m': 'M15',
'30m': 'M30',
'1h': 'H1',
'4h': 'H4',
'6h': 'H6',
'1d': 'D1',
},
},
'defaultType': 'spot',
'networks': {
'TRX': 'TRC-20',
'TRC20': 'TRC-20',
'ETH': 'ERC-20',
'ERC20': 'ERC-20',
'BEP20': 'BEP-20(BSC)',
},
},
'commonCurrencies': {
'SHINJA': 'SHINJA(1M)',
},
'precisionMode': TICK_SIZE,
'exceptions': {
'exact': {
'1005': InsufficientFunds,
},
'broad': {
'Not Enough balance': InsufficientFunds,
'Order does not exist': InvalidOrder,
'System busy, please try again later': BadRequest, // in my tests, this was thrown mostly when request was bad, not the problem of exchange. It is easily reproduced in 'cancelOrders'
},
},
});
}
async fetchMarkets(params = {}) {
/**
* @method
* @name bkex#fetchMarkets
* @description retrieves data on all markets for bkex
* @see https://bkexapi.github.io/docs/api_en.htm?shell#basicInformation-1
* @see https://bkexapi.github.io/docs/api_en.htm?shell#contract-market-symbols
* @param {object} params extra parameters specific to the exchange api endpoint
* @returns {[object]} an array of objects representing market data
*/
let promises = [
this.publicSpotGetCommonSymbols(params),
this.publicSwapGetMarketSymbols(params),
];
promises = await Promise.all(promises);
const spotMarkets = promises[0];
//
// {
// "code": "0",
// "data": [
// {
// "minimumOrderSize": "0",
// "minimumTradeVolume": "0E-18",
// "pricePrecision": "11",
// "supportTrade": true,
// "symbol": "COMT_USDT",
// "volumePrecision": 0
// },
// ],
// "msg": "success",
// "status": 0
// }
//
const swapMarkets = promises[1];
//
// {
// "code": 0,
// "msg": "success",
// "data": [
// {
// "symbol": "luna_usdt",
// "supportTrade": false,
// "volumePrecision": 0,
// "pricePrecision": 3,
// "marketMiniAmount": "1",
// "limitMiniAmount": "1"
// },
// ]
// }
//
const spotData = this.safeValue(spotMarkets, 'data', []);
const swapData = this.safeValue(swapMarkets, 'data', []);
const data = this.arrayConcat(spotData, swapData);
const result = [];
for (let i = 0; i < data.length; i++) {
const market = data[i];
const marketId = this.safeString(market, 'symbol');
const id = this.safeStringUpper(market, 'symbol');
const [baseId, quoteId] = id.split('_');
const base = this.safeCurrencyCode(baseId);
const quote = this.safeCurrencyCode(quoteId);
const minimumOrderSize = this.safeString(market, 'minimumOrderSize');
const type = (minimumOrderSize !== undefined) ? 'spot' : 'swap';
const swap = (type === 'swap');
let symbol = base + '/' + quote;
let settleId = undefined;
let settle = undefined;
if (swap) {
settleId = quoteId;
settle = quote;
symbol = base + '/' + quote + ':' + settle;
}
const linear = swap ? true : undefined;
result.push({
'id': marketId,
'symbol': symbol,
'base': base,
'quote': quote,
'settle': settle,
'baseId': baseId,
'quoteId': quoteId,
'settleId': settleId,
'type': type,
'spot': (type === 'spot'),
'margin': false,
'future': false,
'swap': swap,
'option': false,
'active': this.safeValue(market, 'supportTrade'),
'contract': swap,
'linear': linear,
'inverse': undefined,
'contractSize': undefined,
'expiry': undefined,
'expiryDatetime': undefined,
'strike': undefined,
'optionType': undefined,
'precision': {
'amount': this.parseNumber(this.parsePrecision(this.safeString(market, 'volumePrecision'))),
'price': this.parseNumber(this.parsePrecision(this.safeString(market, 'pricePrecision'))),
},
'limits': {
'leverage': {
'min': undefined,
'max': undefined,
},
'amount': {
'min': this.safeNumberN(market, ['minimumOrderSize', 'marketMiniAmount', 'limitMiniAmount']),
'max': undefined,
},
'price': {
'min': undefined,
'max': undefined,
},
'cost': {
'min': this.safeNumber(market, 'minimumTradeVolume'),
'max': undefined,
},
},
'info': market,
});
}
return result;
}
async fetchCurrencies(params = {}) {
/**
* @method
* @name bkex#fetchCurrencies
* @description fetches all available currencies on an exchange
* @param {object} params extra parameters specific to the bkex api endpoint
* @returns {object} an associative dictionary of currencies
*/
const response = await this.publicSpotGetCommonCurrencys(params);
//
// {
// "code": "0",
// "data": [
// {
// "currency": "ETH",
// "maxWithdrawOneDay": "100.000000000000000000",
// "maxWithdrawSingle": "50.000000000000000000",
// "minWithdrawSingle": "0.005000000000000000",
// "supportDeposit": true,
// "supportTrade": true,
// "supportWithdraw": true,
// "withdrawFee": 0.01
// },
// ],
// "msg": "success",
// "status": 0
// }
//
const data = this.safeValue(response, 'data', []);
const result = {};
for (let i = 0; i < data.length; i++) {
const currency = data[i];
const id = this.safeString(currency, 'currency');
const code = this.safeCurrencyCode(id);
const name = this.safeString(currency, 'name');
const withdrawEnabled = this.safeValue(currency, 'supportWithdraw');
const depositEnabled = this.safeValue(currency, 'supportDeposit');
const tradeEnabled = this.safeValue(currency, 'supportTrade');
const active = withdrawEnabled && depositEnabled && tradeEnabled;
result[code] = {
'id': id,
'code': code,
'name': name,
'deposit': depositEnabled,
'withdraw': withdrawEnabled,
'active': active,
'fee': this.safeNumber(currency, 'withdrawFee'),
'precision': undefined,
'limits': {
'amount': { 'min': undefined, 'max': undefined },
'price': { 'min': undefined, 'max': undefined },
'cost': { 'min': undefined, 'max': undefined },
'withdraw': { 'min': this.safeNumber(currency, 'minWithdrawSingle'), 'max': this.safeNumber(currency, 'maxWithdrawSingle') },
},
'info': currency,
};
}
return result;
}
async fetchTime(params = {}) {
/**
* @method
* @name bkex#fetchTime
* @description fetches the current integer timestamp in milliseconds from the exchange server
* @param {object} params extra parameters specific to the bkex api endpoint
* @returns {int} the current integer timestamp in milliseconds from the exchange server
*/
const response = await this.publicSpotGetCommonTimestamp(params);
//
// {
// "code": '0',
// "data": 1573542445411,
// "msg": "success",
// "status": 0
// }
//
return this.safeInteger(response, 'data');
}
async fetchStatus(params = {}) {
/**
* @method
* @name bkex#fetchStatus
* @description the latest known information on the availability of the exchange API
* @param {object} params extra parameters specific to the bkex api endpoint
* @returns {object} a [status structure]{@link https://docs.ccxt.com/#/?id=exchange-status-structure}
*/
const response = await this.publicSpotGetCommonTimestamp(params);
//
// {
// "code": '0',
// "data": 1573542445411,
// "msg": "success",
// "status": 0
// }
//
const statusRaw = this.safeInteger(response, 'status');
const codeRaw = this.safeInteger(response, 'code');
const updated = this.safeInteger(response, 'data');
return {
'status': (statusRaw === 0 && codeRaw === 0) ? 'ok' : statusRaw,
'updated': updated,
'eta': undefined,
'url': undefined,
'info': response,
};
}
async fetchOHLCV(symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
/**
* @method
* @name bkex#fetchOHLCV
* @description fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market
* @see https://bkexapi.github.io/docs/api_en.htm?shell#quotationData-1
* @see https://bkexapi.github.io/docs/api_en.htm?shell#contract-kline
* @param {string} symbol unified symbol of the market to fetch OHLCV data for
* @param {string} timeframe the length of time each candle represents
* @param {int|undefined} since timestamp in ms of the earliest candle to fetch
* @param {int|undefined} limit the maximum amount of candles to fetch
* @param {object} params extra parameters specific to the bkex api endpoint
* @returns {[[int]]} A list of candles ordered as timestamp, open, high, low, close, volume
*/
await this.loadMarkets();
const market = this.market(symbol);
const swap = market['swap'];
const request = {
'symbol': market['id'],
};
let method = 'publicSpotGetQKline';
const timeframes = this.safeValue(this.options, 'timeframes');
if (swap) {
const swapTimeframes = this.safeValue(timeframes, 'swap');
method = 'publicSwapGetMarketCandle';
request['period'] = this.safeString(swapTimeframes, timeframe, timeframe);
if (limit !== undefined) {
request['count'] = limit;
}
}
else {
const spotTimeframes = this.safeValue(timeframes, 'spot');
request['symbol'] = market['id'];
request['period'] = this.safeString(spotTimeframes, timeframe, timeframe);
}
if (limit !== undefined) {
const limitRequest = swap ? 'count' : 'size';
request[limitRequest] = limit;
}
// their docs says that 'from/to' arguments are mandatory, however that's not true in reality
if (since !== undefined) {
const sinceRequest = swap ? 'start' : 'from';
request[sinceRequest] = since;
// when 'since' [from] argument is set, then exchange also requires 'to' value to be set. So we have to set 'to' argument depending 'limit' amount (if limit was not provided, then exchange-default 500).
if (limit === undefined) {
limit = 500;
}
const duration = this.parseTimeframe(timeframe);
const timerange = limit * duration * 1000;
const toRequest = swap ? 'end' : 'to';
request[toRequest] = this.sum(request[sinceRequest], timerange);
}
const response = await this[method](request);
//
// spot
//
// {
// "code": "0",
// "data": [
// {
// "close": "43414.68",
// "high": "43446.47",
// "low": "43403.05",
// "open": "43406.05",
// "quoteVolume": "61500.40099",
// "symbol": "BTC_USDT",
// "ts": "1646152440000",
// "volume": 1.41627
// },
// ],
// "msg": "success",
// "status": 0
// }
//
// swap
//
// {
// "code": 0,
// "msg": "success",
// "data": [
// {
// "symbol": "btc_usdt",
// "amount": "10.26",
// "volume": "172540.9433",
// "open": "16817.29",
// "close": "1670476440000",
// "high": "16816.45",
// "low": "16817.29",
// "ts": 1670476440000
// },
// ]
// }
//
const data = this.safeValue(response, 'data', []);
return this.parseOHLCVs(data, market, timeframe, since, limit);
}
parseOHLCV(ohlcv, market = undefined) {
const baseCurrencyVolume = market['swap'] ? 'amount' : 'volume';
return [
this.safeInteger(ohlcv, 'ts'),
this.safeFloat(ohlcv, 'open'),
this.safeFloat(ohlcv, 'high'),
this.safeFloat(ohlcv, 'low'),
this.safeFloat(ohlcv, 'close'),
this.safeFloat(ohlcv, baseCurrencyVolume),
];
}
async fetchTicker(symbol, params = {}) {
/**
* @method
* @name bkex#fetchTicker
* @description fetches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
* @see https://bkexapi.github.io/docs/api_en.htm?shell#quotationData-2
* @see https://bkexapi.github.io/docs/api_en.htm?shell#contract-ticker-data
* @param {string} symbol unified symbol of the market to fetch the ticker for
* @param {object} params extra parameters specific to the bkex api endpoint
* @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure}
*/
await this.loadMarkets();
const market = this.market(symbol);
const request = {
'symbol': market['id'],
};
const [marketType, query] = this.handleMarketTypeAndParams('fetchTicker', market, params);
const method = (marketType === 'swap') ? 'publicSwapGetMarketTickers' : 'publicSpotGetQTickers';
const response = await this[method](this.extend(request, query));
//
// spot
//
// {
// "code": "0",
// "data": [
// {
// "change": "6.52",
// "close": "43573.470000",
// "high": "44940.540000",
// "low": "40799.840000",
// "open": "40905.780000",
// "quoteVolume": "225621691.5991",
// "symbol": "BTC_USDT",
// "ts": "1646156490781",
// "volume": 5210.349
// }
// ],
// "msg": "success",
// "status": 0
// }
//
// swap
//
// {
// "code": 0,
// "msg": "success",
// "data": [
// {
// "symbol": "btc_usdt",
// "amount": "171035.45",
// "volume": "2934757466.3859",
// "open": "17111.43",
// "close": "17135.74",
// "high": "17225.99",
// "low": "17105.77",
// "lastPrice": "17135.74",
// "lastAmount": "1.05",
// "lastTime": 1670709364912,
// "change": "0.14"
// }
// ]
// }
//
const tickers = this.safeValue(response, 'data', []);
const ticker = this.safeValue(tickers, 0);
return this.parseTicker(ticker, market);
}
async fetchTickers(symbols = undefined, params = {}) {
/**
* @method
* @name bkex#fetchTickers
* @description fetches price tickers for multiple markets, statistical calculations with the information calculated over the past 24 hours each market
* @see https://bkexapi.github.io/docs/api_en.htm?shell#quotationData-2
* @see https://bkexapi.github.io/docs/api_en.htm?shell#contract-ticker-data
* @param {[string]|undefined} symbols unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned
* @param {object} params extra parameters specific to the bkex api endpoint
* @returns {object} a dictionary of [ticker structures]{@link https://docs.ccxt.com/#/?id=ticker-structure}
*/
await this.loadMarkets();
const request = {};
if (symbols !== undefined) {
if (!Array.isArray(symbols)) {
throw new BadRequest(this.id + ' fetchTickers() symbols argument should be an array');
}
}
let market = undefined;
if (symbols !== undefined) {
const marketIds = this.marketIds(symbols);
const symbol = this.safeString(symbols, 0);
market = this.market(symbol);
if (market['swap']) {
if (Array.isArray(symbols)) {
const symbolsLength = symbols.length;
if (symbolsLength > 1) {
throw new BadRequest(this.id + ' fetchTickers() symbols argument cannot contain more than 1 symbol for swap markets');
}
}
request['symbol'] = market['id'];
}
else {
request['symbol'] = marketIds.join(',');
}
}
const [marketType, query] = this.handleMarketTypeAndParams('fetchTickers', market, params);
const method = (marketType === 'swap') ? 'publicSwapGetMarketTickers' : 'publicSpotGetQTickers';
const response = await this[method](this.extend(request, query));
//
// spot
//
// {
// "code": "0",
// "data": [
// {
// "change": "6.52",
// "close": "43573.470000",
// "high": "44940.540000",
// "low": "40799.840000",
// "open": "40905.780000",
// "quoteVolume": "225621691.5991",
// "symbol": "BTC_USDT",
// "ts": "1646156490781",
// "volume": 5210.349
// }
// ],
// "msg": "success",
// "status": 0
// }
//
// swap
//
// {
// "code": 0,
// "msg": "success",
// "data": [
// {
// "symbol": "btc_usdt",
// "amount": "171035.45",
// "volume": "2934757466.3859",
// "open": "17111.43",
// "close": "17135.74",
// "high": "17225.99",
// "low": "17105.77",
// "lastPrice": "17135.74",
// "lastAmount": "1.05",
// "lastTime": 1670709364912,
// "change": "0.14"
// }
// ]
// }
//
const tickers = this.safeValue(response, 'data', []);
return this.parseTickers(tickers, symbols, query);
}
parseTicker(ticker, market = undefined) {
//
// spot
//
// {
// "change":-0.46,
// "close":29664.46,
// "high":30784.99,
// "low":29455.36,
// "open":29803.38,
// "quoteVolume":714653752.6991,
// "symbol":"BTC_USDT",
// "ts":1652812048118,
// "volume":23684.9416
// }
//
// swap
//
// {
// "symbol": "btc_usdt",
// "amount": "171035.45",
// "volume": "2934757466.3859",
// "open": "17111.43",
// "close": "17135.74",
// "high": "17225.99",
// "low": "17105.77",
// "lastPrice": "17135.74",
// "lastAmount": "1.05",
// "lastTime": 1670709364912,
// "change": "0.14"
// }
//
const marketId = this.safeString(ticker, 'symbol');
market = this.safeMarket(marketId, market);
const symbol = this.safeSymbol(marketId, market);
const timestamp = this.safeInteger2(ticker, 'ts', 'lastTime');
const baseCurrencyVolume = market['swap'] ? 'amount' : 'volume';
const quoteCurrencyVolume = market['swap'] ? 'volume' : 'quoteVolume';
const lastPrice = market['swap'] ? 'lastPrice' : 'close';
return this.safeTicker({
'symbol': symbol,
'timestamp': timestamp,
'datetime': this.iso8601(timestamp),
'high': this.safeString(ticker, 'high'),
'low': this.safeString(ticker, 'low'),
'bid': undefined,
'bidVolume': undefined,
'ask': undefined,
'askVolume': undefined,
'vwap': undefined,
'open': this.safeString(ticker, 'open'),
'close': this.safeString(ticker, 'close'),
'last': this.safeString(ticker, lastPrice),
'previousClose': undefined,
'change': undefined,
'percentage': this.safeString(ticker, 'change'),
'average': undefined,
'baseVolume': this.safeString(ticker, baseCurrencyVolume),
'quoteVolume': this.safeString(ticker, quoteCurrencyVolume),
'info': ticker,
}, market);
}
async fetchOrderBook(symbol, limit = undefined, params = {}) {
/**
* @method
* @name bkex#fetchOrderBook
* @description fetches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
* @see https://bkexapi.github.io/docs/api_en.htm?shell#quotationData-4
* @see https://bkexapi.github.io/docs/api_en.htm?shell#contract-deep-data
* @param {string} symbol unified symbol of the market to fetch the order book for
* @param {int|undefined} limit the maximum amount of order book entries to return
* @param {object} params extra parameters specific to the bkex api endpoint
* @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/#/?id=order-book-structure} indexed by market symbols
*/
await this.loadMarkets();
const market = this.market(symbol);
const swap = market['swap'];
const request = {
'symbol': market['id'],
};
let method = 'publicSpotGetQDepth';
if (swap) {
method = 'publicSwapGetMarketDepth';
}
else {
if (limit !== undefined) {
request['depth'] = Math.min(limit, 50);
}
}
const response = await this[method](this.extend(request, params));
//
// spot
//
// {
// "code": "0",
// "data": {
// "ask": [
// ["43820.07","0.86947"],
// ["43820.25","0.07503"],
// ],
// "bid": [
// ["43815.94","0.43743"],
// ["43815.72","0.08901"],
// ],
// "symbol": "BTC_USDT",
// "timestamp": 1646161595841
// },
// "msg": "success",
// "status": 0
// }
//
// swap
//
// {
// "code": 0,
// "msg": "success",
// "data": {
// "bid": [
// ["16803.170000","4.96"],
// ["16803.140000","11.07"],
// ],
// "ask": [
// ["16803.690000","9.2"],
// ["16804.180000","9.43"],
// ]
// }
// }
//
const data = this.safeValue(response, 'data');
const timestamp = this.safeInteger(data, 'timestamp');
return this.parseOrderBook(data, market['symbol'], timestamp, 'bid', 'ask');
}
async fetchTrades(symbol, since = undefined, limit = undefined, params = {}) {
/**
* @method
* @name bkex#fetchTrades
* @description get the list of most recent trades for a particular symbol
* @see https://bkexapi.github.io/docs/api_en.htm?shell#quotationData-5
* @see https://bkexapi.github.io/docs/api_en.htm?shell#contract-trades-history
* @param {string} symbol unified symbol of the market to fetch trades for
* @param {int|undefined} since timestamp in ms of the earliest trade to fetch
* @param {int|undefined} limit the maximum amount of trades to fetch
* @param {object} params extra parameters specific to the bkex api endpoint
* @returns {[object]} a list of [trade structures]{@link https://docs.ccxt.com/en/latest/manual.html?#public-trades}
*/
await this.loadMarkets();
const market = this.market(symbol);
const swap = market['swap'];
const request = {
'symbol': market['id'],
};
let method = 'publicSpotGetQDeals';
if (swap) {
method = 'publicSwapGetMarketDeals';
}
else {
if (limit !== undefined) {
request['size'] = Math.min(limit, 50);
}
}
const response = await this[method](this.extend(request, params));
//
// spot
//
// {
// "code": "0",
// "data": [
// {
// "direction": "S",
// "price": "43930.63",
// "symbol": "BTC_USDT",
// "ts": "1646224171992",
// "volume": 0.030653
// }, // first item is most recent
// ],
// "msg": "success",
// "status": 0
// }
//
// swap
//
// {
// "code": 0,
// "msg": "success",
// "data": [
// {
// "symbol": "btc_usdt",
// "amount": "0.06",
// "price": "17134.66",
// "side": "sell",
// "time": 1670651851646
// },
// ]
// }
//
const trades = this.safeValue(response, 'data');
return this.parseTrades(trades, market, since, limit);
}
parseTrade(trade, market = undefined) {
const timestamp = this.safeInteger2(trade, 'ts', 'time');
const marketId = this.safeString(trade, 'symbol');
market = this.safeMarket(marketId, market);
const side = this.parseTradeSide(this.safeString2(trade, 'direction', 'side'));
const amount = this.safeNumber2(trade, 'volume', 'amount');
const price = this.safeNumber(trade, 'price');
const type = undefined;
let id = this.safeString(trade, 'tid');
if (id === undefined) {
id = this.syntheticTradeId(market, timestamp, side, amount, price, type);
}
return this.safeTrade({
'id': id,
'timestamp': timestamp,
'datetime': this.iso8601(timestamp),
'symbol': market['symbol'],
'order': undefined,
'type': type,
'side': side,
'takerOrMaker': undefined,
'price': price,
'amount': amount,
'cost': undefined,
'fee': undefined,
'info': trade,
}, market);
}
parseTradeSide(side) {
const sides = {
'B': 'buy',
'S': 'sell',
'buy': 'buy',
'sell': 'sell',
};
return this.safeString(sides, side, side);
}
syntheticTradeId(market = undefined, timestamp = undefined, side = undefined, amount = undefined, price = undefined, orderType = undefined, takerOrMaker = undefined) {
// TODO: can be unified method? this approach is being used by multiple exchanges (mexc, woo-coinsbit, dydx, ...)
let id = '';
if (timestamp !== undefined) {
id = this.numberToString(timestamp) + '-' + this.safeString(market, 'id', '_');
if (side !== undefined) {
id += '-' + side;
}
if (orderType !== undefined) {
id += '-' + orderType;
}
if (takerOrMaker !== undefined) {
id += '-' + takerOrMaker;
}
if (amount !== undefined) {
id += '-' + this.numberToString(amount);
}
if (price !== undefined) {
id += '-' + this.numberToString(price);
}
}
return id;
}
async fetchBalance(params = {}) {
/**
* @method
* @name bkex#fetchBalance
* @description query for balance and get the amount of funds available for trading or funds locked in orders
* @param {object} params extra parameters specific to the bkex api endpoint
* @returns {object} a [balance structure]{@link https://docs.ccxt.com/en/latest/manual.html?#balance-structure}
*/
await this.loadMarkets();
const query = this.omit(params, 'type');
const response = await this.privateSpotGetUAccountBalance(query);
//
// {
// "code": "0",
// "data": {
// "WALLET": [
// {
// "available": "0.221212121000000000",
// "currency": "PHX",
// "frozen": "0E-18",
// "total": 0.221212121
// },
// {
// "available": "44.959577229600000000",
// "currency": "USDT",
// "frozen": "0E-18",
// "total": 44.9595772296
// }
// ]
// },
// "msg": "success",
// "status": 0
// }
//
const balances = this.safeValue(response, 'data');
const wallets = this.safeValue(balances, 'WALLET', []);
const result = { 'info': wallets };
for (let i = 0; i < wallets.length; i++) {
const wallet = wallets[i];
const currencyId = wallet['currency'];
const code = this.safeCurrencyCode(currencyId);
const account = this.account();
account['free'] = this.safeNumber(wallet, 'available');
account['used'] = this.safeNumber(wallet, 'frozen');
account['total'] = this.safeNumber(wallet, 'total');
result[code] = account;
}
return this.safeBalance(result);
}
async fetchDepositAddress(code, params = {}) {
/**
* @method
* @name bkex#fetchDepositAddress
* @description fetch the deposit address for a currency associated with this account
* @param {string} code unified currency code
* @param {object} params extra parameters specific to the bkex api endpoint
* @returns {object} an [address structure]{@link https://docs.ccxt.com/#/?id=address-structure}
*/
await this.loadMarkets();
const currency = this.currency(code);
const request = {
'currency': currency['id'],
};
const response = await this.privateSpotGetUWalletAddress(this.extend(request, params));
// NOTE: You can only retrieve addresses of already generated wallets - so should already have generated that COIN deposit address in UI. Otherwise, it seems from API you can't create/obtain addresses for those coins.
//
// {
// "code": "0",
// "data": [
// {
// "currency": "BTC",
// "address": "1m4k2yUKTSrX6SM9FGgvwMyxQbYtRVi2N",
// "memo": ""
// }
// ],
// "msg": "success",
// "status": 0
// }
//
const data = this.safeValue(response, 'data', {});
return this.parseDepositAddress(data, currency);
}
parseDepositAddress(data, currency = undefined) {
const depositObject = this.safeValue(data, 0);
const address = this.safeString(depositObject, 'address');
const tag = this.safeString(depositObject, 'memo');
const currencyId = this.safeString(depositObject, 'currency');
currency = this.safeCurrency(currencyId, currency);
return {
'currency': currency['code'],
'address': address,
'tag': tag,
'network': undefined,
'info': data,
};
}
async fetchDeposits(code = undefined, since = undefined, limit = undefined, params = {}) {
/**
* @method
* @name bkex#fetchDeposits
* @description fetch all deposits made to an account
* @param {string} code unified currency code
* @param {int|undefined} since the earliest time in ms to fetch deposits for
* @param {int|undefined} limit the maximum number of deposits structures to retrieve
* @param {object} params extra parameters specific to the bkex api endpoint
* @returns {[object]} a list of [transaction structures]{@link https://docs.ccxt.com/#/?id=transaction-structure}
*/
if (code === undefined) {
throw new ArgumentsRequired(this.id + ' fetchDeposits() requires code argument');
}
await this.loadMarkets();
const currency = this.currency(code);
const request = {
'currency': currency['id'],
};
if (since !== undefined) {
request['startTime'] = since;
const endTime = this.milliseconds();
request['endTime'] = endTime;
}
if (limit !== undefined) {
request['Size'] = limit; // Todo: id api-docs, 'size' is incorrectly required to be in Uppercase
}
const response = await this.privateSpotGetUWalletDepositRecord(this.extend(request, params));
//
// {
// "code": "0",
// "data": {
// "data": [
// {
// "createTime": "1622274255000",
// "currency": "BNB",
// "fromAddress": "bnb10af52w77pkehgxhnwgeca50q2t2354q4xexa5y",
// "hash": "97B982F497782C2777C0F6AD16CEAAC65A93A364B684A23A71CFBB8C010DEEA6",
// "id": "2021052923441510234383337",
// "status": "0",
// "toAddress": "bnb13w64gkc42c0l45m2p5me4qn35z0a3ej9ldks3j_82784659",
// "volume": 0.073
// }
// ],
// "total": 1
// },
// "msg": "success",
// "status": 0
// }
//
const data = this.safeValue(response, 'data', {});
const dataInner = this.safeValue(data, 'data', []);
for (let i = 0; i < dataInner.length; i++) {
dataInner[i]['transactType'] = 'deposit';
}
return this.parseTransactions(dataInner, currency, since, limit, params);
}
async fetchWithdrawals(code = undefined, since = undefined, limit = undefined, params = {}) {
/**
* @method
* @name bkex#fetchWithdrawals
* @description fetch all withdrawals made from an account
* @param {string} code unified currency code
* @param {int|undefined} since the earliest time in ms to fetch withdrawals for
* @param {int|undefined} limit the maximum number of withdrawals structures to retrieve
* @param {object} params extra parameters specific to the bkex api endpoint
* @returns {[object]} a list of [transaction structures]{@link https://docs.ccxt.com/#/?id=transaction-structure}
*/
if (code === undefined) {
throw new ArgumentsRequired(this.id + ' fetchWithdrawals() requires code argument');
}
await this.loadMarkets();
const currency = this.currency(code);
const request = {
'currency': currency['id'],
};
if (since !== undefined) {
request['startTime'] = since;
const endTime = this.milliseconds();
request['endTime'] = endTime;
}
if (limit !== undefined) {
request['Size'] = limit; // Todo: id api-docs, 'size' is incorrectly required to be in Uppercase
}
const response = await this.privateSpotGetUWalletWithdrawRecord(this.extend(request, params));
//
// {
// "code": "0",
// "data": {
// "data": [
// {
// ...
// }
// ],
// "total": 1
// },
// "msg": "success",
// "status": 0
// }
//
const data = this.safeValue(response, 'data', {});
const dataInner = this.safeValue(data, 'data', []);