@jalmonter/ccxt
Version:
1,234 lines (1,231 loc) • 148 kB
JavaScript
'use strict';
var bingx$1 = require('./abstract/bingx.js');
var errors = require('./base/errors.js');
var Precise = require('./base/Precise.js');
var sha256 = require('./static_dependencies/noble-hashes/sha256.js');
var number = require('./base/functions/number.js');
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
class bingx extends bingx$1 {
describe() {
return this.deepExtend(super.describe(), {
'id': 'bingx',
'name': 'BingX',
'countries': ['US'],
// cheapest is 60 requests a minute = 1 requests per second on average => ( 1000ms / 1) = 1000 ms between requests on average
'rateLimit': 1000,
'version': 'v1',
'certified': true,
'pro': true,
'has': {
'CORS': undefined,
'spot': true,
'margin': true,
'swap': true,
'future': false,
'option': false,
'cancelAllOrders': true,
'cancelOrder': true,
'cancelOrders': true,
'closeAllPositions': true,
'closePosition': false,
'createMarketBuyOrderWithCost': true,
'createMarketOrderWithCost': true,
'createMarketSellOrderWithCost': true,
'createOrder': true,
'createOrders': true,
'fetchBalance': true,
'fetchClosedOrders': true,
'fetchCurrencies': true,
'fetchDepositAddress': true,
'fetchDeposits': true,
'fetchDepositWithdrawFee': 'emulated',
'fetchDepositWithdrawFees': true,
'fetchFundingRate': true,
'fetchFundingRateHistory': true,
'fetchLeverage': true,
'fetchLiquidations': false,
'fetchMarkets': true,
'fetchMyLiquidations': true,
'fetchOHLCV': true,
'fetchOpenInterest': true,
'fetchOpenOrders': true,
'fetchOrder': true,
'fetchOrderBook': true,
'fetchPositions': true,
'fetchTicker': true,
'fetchTickers': true,
'fetchTime': true,
'fetchTrades': true,
'fetchTransfers': true,
'fetchWithdrawals': true,
'setLeverage': true,
'setMargin': true,
'setMarginMode': true,
'transfer': true,
},
'hostname': 'bingx.com',
'urls': {
'logo': 'https://github-production-user-asset-6210df.s3.amazonaws.com/1294454/253675376-6983b72e-4999-4549-b177-33b374c195e3.jpg',
'api': {
'spot': 'https://open-api.{hostname}/openApi',
'swap': 'https://open-api.{hostname}/openApi',
'contract': 'https://open-api.{hostname}/openApi',
'wallets': 'https://open-api.{hostname}/openApi',
'user': 'https://open-api.{hostname}/openApi',
'subAccount': 'https://open-api.{hostname}/openApi',
'account': 'https://open-api.{hostname}/openApi',
'copyTrading': 'https://open-api.{hostname}/openApi',
},
'www': 'https://bingx.com/',
'doc': 'https://bingx-api.github.io/docs/',
'referral': 'https://bingx.com/invite/OHETOM',
},
'fees': {
'tierBased': true,
'spot': {
'feeSide': 'get',
'maker': this.parseNumber('0.001'),
'taker': this.parseNumber('0.001'),
},
'swap': {
'feeSide': 'quote',
'maker': this.parseNumber('0.0002'),
'taker': this.parseNumber('0.0005'),
},
},
'requiredCredentials': {
'apiKey': true,
'secret': true,
},
'api': {
'spot': {
'v1': {
'public': {
'get': {
'common/symbols': 3,
'market/trades': 3,
'market/depth': 3,
'market/kline': 3,
'ticker/24hr': 1,
},
},
'private': {
'get': {
'trade/query': 3,
'trade/openOrders': 3,
'trade/historyOrders': 3,
'account/balance': 3,
},
'post': {
'trade/order': 3,
'trade/cancel': 3,
'trade/batchOrders': 3,
'trade/cancelOrders': 3,
},
},
},
'v3': {
'private': {
'get': {
'get/asset/transfer': 3,
'asset/transfer': 3,
'capital/deposit/hisrec': 3,
'capital/withdraw/history': 3,
},
'post': {
'post/asset/transfer': 3,
},
},
},
},
'swap': {
'v2': {
'public': {
'get': {
'server/time': 3,
'quote/contracts': 1,
'quote/price': 1,
'quote/depth': 1,
'quote/trades': 1,
'quote/premiumIndex': 1,
'quote/fundingRate': 1,
'quote/klines': 1,
'quote/openInterest': 1,
'quote/ticker': 1,
'quote/bookTicker': 1,
},
},
'private': {
'get': {
'user/balance': 3,
'user/positions': 3,
'user/income': 3,
'trade/openOrders': 3,
'trade/order': 3,
'trade/marginType': 3,
'trade/leverage': 3,
'trade/forceOrders': 3,
'trade/allOrders': 3,
'trade/allFillOrders': 3,
'user/income/export': 3,
'user/commissionRate': 3,
'quote/bookTicker': 3,
},
'post': {
'trade/order': 3,
'trade/batchOrders': 3,
'trade/closeAllPositions': 3,
'trade/marginType': 3,
'trade/leverage': 3,
'trade/positionMargin': 3,
'trade/order/test': 3,
},
'delete': {
'trade/order': 3,
'trade/batchOrders': 3,
'trade/allOpenOrders': 3,
},
},
},
'v3': {
'public': {
'get': {
'quote/klines': 1,
},
},
},
},
'contract': {
'v1': {
'private': {
'get': {
'allPosition': 3,
'allOrders': 3,
'balance': 3,
},
},
},
},
'wallets': {
'v1': {
'private': {
'get': {
'capital/config/getall': 3,
'capital/deposit/address': 1,
'capital/innerTransfer/records': 1,
'capital/subAccount/deposit/address': 1,
'capital/deposit/subHisrec': 1,
'capital/subAccount/innerTransfer/records': 1,
},
'post': {
'capital/withdraw/apply': 3,
'capital/innerTransfer/apply': 3,
'capital/subAccountInnerTransfer/apply': 3,
'capital/deposit/createSubAddress': 1,
},
},
},
},
'subAccount': {
'v1': {
'private': {
'get': {
'list': 3,
'assets': 3,
'apiKey/query': 1,
},
'post': {
'create': 3,
'apiKey/create': 3,
'apiKey/edit': 3,
'apiKey/del': 3,
'updateStatus': 3,
},
},
},
},
'account': {
'v1': {
'private': {
'get': {
'uid': 1,
},
'post': {
'innerTransfer/authorizeSubAccount': 3,
},
},
},
},
'user': {
'auth': {
'private': {
'post': {
'userDataStream': 1,
},
},
},
},
'copyTrading': {
'v1': {
'private': {
'get': {
'swap/trace/currentTrack': 1,
},
'post': {
'swap/trace/closeTrackOrder': 1,
'swap/trace/setTPSL': 1,
},
},
},
},
'api': {
'v3': {
'private': {
'get': {
'asset/transfer': 1,
'capital/deposit/hisrec': 1,
'capital/withdraw/history': 1,
},
'post': {
'post/asset/transfer': 1,
},
},
},
},
},
'timeframes': {
'1m': '1m',
'3m': '3m',
'5m': '5m',
'15m': '15m',
'30m': '30m',
'1h': '1h',
'2h': '2h',
'4h': '4h',
'6h': '6h',
'12h': '12h',
'1d': '1d',
'3d': '3d',
'1w': '1w',
'1M': '1M',
},
'precisionMode': number.DECIMAL_PLACES,
'exceptions': {
'exact': {
'400': errors.BadRequest,
'401': errors.AuthenticationError,
'403': errors.PermissionDenied,
'404': errors.BadRequest,
'429': errors.DDoSProtection,
'418': errors.PermissionDenied,
'500': errors.ExchangeError,
'504': errors.ExchangeError,
'100001': errors.AuthenticationError,
'100412': errors.AuthenticationError,
'100202': errors.InsufficientFunds,
'100204': errors.BadRequest,
'100400': errors.BadRequest,
'100440': errors.ExchangeError,
'100500': errors.ExchangeError,
'100503': errors.ExchangeError,
'80001': errors.BadRequest,
'80012': errors.ExchangeNotAvailable,
'80014': errors.BadRequest,
'80016': errors.OrderNotFound,
'80017': errors.OrderNotFound,
'100437': errors.BadRequest, // {"code":100437,"msg":"The withdrawal amount is lower than the minimum limit, please re-enter.","timestamp":1689258588845}
},
'broad': {},
},
'commonCurrencies': {},
'options': {
'defaultType': 'spot',
'accountsByType': {
'spot': 'FUND',
'swap': 'PFUTURES',
'future': 'SFUTURES',
},
'accountsById': {
'FUND': 'spot',
'PFUTURES': 'swap',
'SFUTURES': 'future',
},
'recvWindow': 5 * 1000,
'broker': 'CCXT',
},
});
}
async fetchTime(params = {}) {
/**
* @method
* @name bingx#fetchTime
* @description fetches the current integer timestamp in milliseconds from the bingx server
* @see https://bingx-api.github.io/docs/#/swapV2/base-info.html#Get%20Server%20Time
* @param {object} [params] extra parameters specific to the exchange API endpoint
* @returns {int} the current integer timestamp in milliseconds from the bingx server
*/
const response = await this.swapV2PublicGetServerTime(params);
//
// {
// "code": 0,
// "msg": "",
// "data": {
// "serverTime": 1675319535362
// }
// }
//
const data = this.safeValue(response, 'data');
return this.safeInteger(data, 'serverTime');
}
async fetchCurrencies(params = {}) {
/**
* @method
* @name bingx#fetchCurrencies
* @description fetches all available currencies on an exchange
* @see https://bingx-api.github.io/docs/#/common/account-api.html#All%20Coins
* @param {object} [params] extra parameters specific to the exchange API endpoint
* @returns {object} an associative dictionary of currencies
*/
if (!this.checkRequiredCredentials(false)) {
return undefined;
}
const response = await this.walletsV1PrivateGetCapitalConfigGetall(params);
//
// {
// "code": 0,
// "timestamp": 1688045966616,
// "data": [
// {
// "coin": "BTC",
// "name": "BTC",
// "networkList": [
// {
// "name": "BTC",
// "network": "BTC",
// "isDefault": true,
// "minConfirm": "2",
// "withdrawEnable": true,
// "withdrawFee": "0.00035",
// "withdrawMax": "1.62842",
// "withdrawMin": "0.0005"
// },
// {
// "name": "BTC",
// "network": "BEP20",
// "isDefault": false,
// "minConfirm": "15",
// "withdrawEnable": true,
// "withdrawFee": "0.00001",
// "withdrawMax": "1.62734",
// "withdrawMin": "0.0001"
// }
// ]
// },
// ...
// ],
// }
//
const data = this.safeValue(response, 'data', []);
const result = {};
for (let i = 0; i < data.length; i++) {
const entry = data[i];
const currencyId = this.safeString(entry, 'coin');
const code = this.safeCurrencyCode(currencyId);
const name = this.safeString(entry, 'name');
const networkList = this.safeValue(entry, 'networkList');
const networks = {};
let fee = undefined;
let active = undefined;
let withdrawEnabled = undefined;
let defaultLimits = {};
for (let j = 0; j < networkList.length; j++) {
const rawNetwork = networkList[j];
const network = this.safeString(rawNetwork, 'network');
const networkCode = this.networkIdToCode(network);
const isDefault = this.safeValue(rawNetwork, 'isDefault');
withdrawEnabled = this.safeValue(rawNetwork, 'withdrawEnable');
const limits = {
'amounts': { 'min': this.safeNumber(rawNetwork, 'withdrawMin'), 'max': this.safeNumber(rawNetwork, 'withdrawMax') },
};
if (isDefault) {
fee = this.safeNumber(rawNetwork, 'withdrawFee');
active = withdrawEnabled;
defaultLimits = limits;
}
networks[networkCode] = {
'info': rawNetwork,
'id': network,
'network': networkCode,
'fee': fee,
'active': active,
'deposit': undefined,
'withdraw': withdrawEnabled,
'precision': undefined,
'limits': limits,
};
}
result[code] = {
'info': entry,
'code': code,
'id': currencyId,
'precision': undefined,
'name': name,
'active': active,
'deposit': undefined,
'withdraw': withdrawEnabled,
'networks': networks,
'fee': fee,
'limits': defaultLimits,
};
}
return result;
}
async fetchSpotMarkets(params) {
const response = await this.spotV1PublicGetCommonSymbols(params);
//
// {
// "code": 0,
// "msg": "",
// "debugMsg": "",
// "data": {
// "symbols": [
// {
// "symbol": "GEAR-USDT",
// "minQty": 735,
// "maxQty": 2941177,
// "minNotional": 5,
// "maxNotional": 20000,
// "status": 1,
// "tickSize": 0.000001,
// "stepSize": 1
// },
// ...
// ]
// }
// }
//
const data = this.safeValue(response, 'data');
const markets = this.safeValue(data, 'symbols', []);
return this.parseMarkets(markets);
}
async fetchSwapMarkets(params) {
const response = await this.swapV2PublicGetQuoteContracts(params);
//
// {
// "code": 0,
// "msg": "",
// "data": [
// {
// "contractId": "100",
// "symbol": "BTC-USDT",
// "size": "0.0001",
// "quantityPrecision": 4,
// "pricePrecision": 1,
// "feeRate": 0.0005,
// "tradeMinLimit": 1,
// "maxLongLeverage": 150,
// "maxShortLeverage": 150,
// "currency": "USDT",
// "asset": "BTC",
// "status": 1
// },
// ...
// ]
// }
//
const markets = this.safeValue(response, 'data', []);
return this.parseMarkets(markets);
}
parseMarket(market) {
const id = this.safeString(market, 'symbol');
const symbolParts = id.split('-');
const baseId = symbolParts[0];
const quoteId = symbolParts[1];
const base = this.safeCurrencyCode(baseId);
const quote = this.safeCurrencyCode(quoteId);
const currency = this.safeString(market, 'currency');
const settle = this.safeCurrencyCode(currency);
let pricePrecision = this.safeInteger(market, 'pricePrecision');
if (pricePrecision === undefined) {
pricePrecision = this.precisionFromString(this.safeString(market, 'tickSize'));
}
let quantityPrecision = this.safeInteger(market, 'quantityPrecision');
if (quantityPrecision === undefined) {
quantityPrecision = this.precisionFromString(this.safeString(market, 'stepSize'));
}
const type = (settle !== undefined) ? 'swap' : 'spot';
const spot = type === 'spot';
const swap = type === 'swap';
let symbol = base + '/' + quote;
if (settle !== undefined) {
symbol += ':' + settle;
}
const fees = this.safeValue(this.fees, type, {});
const contractSize = this.safeNumber(market, 'size');
const isActive = this.safeString(market, 'status') === '1';
const isInverse = (spot) ? undefined : false;
const isLinear = (spot) ? undefined : swap;
return this.safeMarketStructure({
'id': id,
'symbol': symbol,
'base': base,
'quote': quote,
'settle': settle,
'baseId': baseId,
'quoteId': quoteId,
'settleId': currency,
'type': type,
'spot': spot,
'margin': false,
'swap': swap,
'future': false,
'option': false,
'active': isActive,
'contract': swap,
'linear': isLinear,
'inverse': isInverse,
'taker': this.safeNumber(fees, 'taker'),
'maker': this.safeNumber(fees, 'maker'),
'feeSide': this.safeString(fees, 'feeSide'),
'contractSize': contractSize,
'expiry': undefined,
'expiryDatetime': undefined,
'strike': undefined,
'optionType': undefined,
'precision': {
'amount': quantityPrecision,
'price': pricePrecision,
},
'limits': {
'leverage': {
'min': undefined,
'max': this.safeInteger(market, 'maxLongLeverage'),
},
'amount': {
'min': this.safeNumber(market, 'minQty'),
'max': this.safeNumber(market, 'maxQty'),
},
'price': {
'min': undefined,
'max': undefined,
},
'cost': {
'min': this.safeNumber(market, 'minNotional'),
'max': this.safeNumber(market, 'maxNotional'),
},
},
'created': undefined,
'info': market,
});
}
async fetchMarkets(params = {}) {
/**
* @method
* @name bingx#fetchMarkets
* @description retrieves data on all markets for bingx
* @see https://bingx-api.github.io/docs/#/spot/market-api.html#Query%20Symbols
* @see https://bingx-api.github.io/docs/#/swapV2/market-api.html#Contract%20Information
* @param {object} [params] extra parameters specific to the exchange API endpoint
* @returns {object[]} an array of objects representing market data
*/
const requests = [this.fetchSpotMarkets(params), this.fetchSwapMarkets(params)];
const promises = await Promise.all(requests);
const spotMarkets = this.safeValue(promises, 0, []);
const swapMarkets = this.safeValue(promises, 1, []);
return this.arrayConcat(spotMarkets, swapMarkets);
}
async fetchOHLCV(symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
/**
* @method
* @name bingx#fetchOHLCV
* @description fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market
* @see https://bingx-api.github.io/docs/#/swapV2/market-api.html#K-Line%20Data
* @see https://bingx-api.github.io/docs/#/spot/market-api.html#Candlestick%20chart%20data
* @see https://bingx-api.github.io/docs/#/swapV2/market-api.html#%20K-Line%20Data
* @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} [since] timestamp in ms of the earliest candle to fetch
* @param {int} [limit] the maximum amount of candles to fetch
* @param {object} [params] extra parameters specific to the exchange API endpoint
* @param {int} [params.until] timestamp in ms of the latest candle to fetch
* @param {boolean} [params.paginate] default false, when true will automatically paginate by calling this endpoint multiple times. See in the docs all the [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
* @returns {int[][]} A list of candles ordered as timestamp, open, high, low, close, volume
*/
await this.loadMarkets();
let paginate = false;
[paginate, params] = this.handleOptionAndParams(params, 'fetchOHLCV', 'paginate', false);
if (paginate) {
return await this.fetchPaginatedCallDeterministic('fetchOHLCV', symbol, since, limit, timeframe, params, 1440);
}
const market = this.market(symbol);
const request = {
'symbol': market['id'],
};
request['interval'] = this.safeString(this.timeframes, timeframe, timeframe);
if (since !== undefined) {
request['startTime'] = since;
}
if (limit !== undefined) {
request['limit'] = limit;
}
const until = this.safeInteger2(params, 'until', 'endTime');
if (until !== undefined) {
params = this.omit(params, ['until']);
request['endTime'] = until;
}
let response = undefined;
if (market['spot']) {
response = await this.spotV1PublicGetMarketKline(this.extend(request, params));
}
else {
response = await this.swapV3PublicGetQuoteKlines(this.extend(request, params));
}
//
// {
// "code": 0,
// "msg": "",
// "data": [
// {
// "open": "19396.8",
// "close": "19394.4",
// "high": "19397.5",
// "low": "19385.7",
// "volume": "110.05",
// "time": 1666583700000
// },
// ...
// ]
// }
//
let ohlcvs = this.safeValue(response, 'data', []);
if (!Array.isArray(ohlcvs)) {
ohlcvs = [ohlcvs];
}
return this.parseOHLCVs(ohlcvs, market, timeframe, since, limit);
}
parseOHLCV(ohlcv, market = undefined) {
//
// {
// "open": "19394.4",
// "close": "19379.0",
// "high": "19394.4",
// "low": "19368.3",
// "volume": "167.44",
// "time": 1666584000000
// }
// spot
// [
// 1691402580000,
// 29093.61,
// 29093.93,
// 29087.73,
// 29093.24,
// 0.59,
// 1691402639999,
// 17221.07
// ]
//
if (Array.isArray(ohlcv)) {
return [
this.safeInteger(ohlcv, 0),
this.safeNumber(ohlcv, 1),
this.safeNumber(ohlcv, 2),
this.safeNumber(ohlcv, 3),
this.safeNumber(ohlcv, 4),
this.safeNumber(ohlcv, 5),
];
}
return [
this.safeInteger(ohlcv, 'time'),
this.safeNumber(ohlcv, 'open'),
this.safeNumber(ohlcv, 'high'),
this.safeNumber(ohlcv, 'low'),
this.safeNumber(ohlcv, 'close'),
this.safeNumber(ohlcv, 'volume'),
];
}
async fetchTrades(symbol, since = undefined, limit = undefined, params = {}) {
/**
* @method
* @name bingx#fetchTrades
* @description get the list of most recent trades for a particular symbol
* @see https://bingx-api.github.io/docs/#/spot/market-api.html#Query%20transaction%20records
* @see https://bingx-api.github.io/docs/#/swapV2/market-api.html#The%20latest%20Trade%20of%20a%20Trading%20Pair
* @param {string} symbol unified symbol of the market to fetch trades for
* @param {int} [since] timestamp in ms of the earliest trade to fetch
* @param {int} [limit] the maximum amount of trades to fetch
* @param {object} [params] extra parameters specific to the exchange API endpoint
* @returns {object[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=public-trades}
*/
await this.loadMarkets();
const market = this.market(symbol);
const request = {
'symbol': market['id'],
};
if (limit !== undefined) {
request['limit'] = Math.min(limit, 100); // avoid API exception "limit should less than 100"
}
let response = undefined;
let marketType = undefined;
[marketType, params] = this.handleMarketTypeAndParams('fetchTrades', market, params);
if (marketType === 'spot') {
response = await this.spotV1PublicGetMarketTrades(this.extend(request, params));
}
else {
response = await this.swapV2PublicGetQuoteTrades(this.extend(request, params));
}
//
// spot
//
// {
// "code": 0,
// "data": [
// {
// "id": 43148253,
// "price": 25714.71,
// "qty": 1.674571,
// "time": 1655085975589,
// "buyerMaker": false
// }
// ]
// }
//
// swap
//
// {
// "code":0,
// "msg":"",
// "data":[
// {
// "time": 1672025549368,
// "isBuyerMaker": true,
// "price": "16885.0",
// "qty": "3.3002",
// "quoteQty": "55723.87"
// },
// ...
// ]
// }
//
const trades = this.safeValue(response, 'data', []);
return this.parseTrades(trades, market, since, limit);
}
parseTrade(trade, market = undefined) {
//
// spot
// fetchTrades
//
// {
// "id": 43148253,
// "price": 25714.71,
// "qty": 1.674571,
// "time": 1655085975589,
// "buyerMaker": false
// }
//
// swap
// fetchTrades
//
// {
// "time": 1672025549368,
// "isBuyerMaker": true,
// "price": "16885.0",
// "qty": "3.3002",
// "quoteQty": "55723.87"
// }
//
// swap
// fetchMyTrades
//
// {
// "volume": "0.1",
// "price": "106.75",
// "amount": "10.6750",
// "commission": "-0.0053",
// "currency": "USDT",
// "orderId": "1676213270274379776",
// "liquidatedPrice": "0.00",
// "liquidatedMarginRatio": "0.00",
// "filledTime": "2023-07-04T20:56:01.000+0800"
// }
//
//
// ws
//
// spot
//
// {
// "E": 1690214529432,
// "T": 1690214529386,
// "e": "trade",
// "m": true,
// "p": "29110.19",
// "q": "0.1868",
// "s": "BTC-USDT",
// "t": "57903921"
// }
//
// swap
//
// {
// "q": "0.0421",
// "p": "29023.5",
// "T": 1690221401344,
// "m": false,
// "s": "BTC-USDT"
// }
//
let time = this.safeIntegerN(trade, ['time', 'filledTm', 'T']);
const datetimeId = this.safeString(trade, 'filledTm');
if (datetimeId !== undefined) {
time = this.parse8601(datetimeId);
}
if (time === 0) {
time = undefined;
}
const cost = this.safeString(trade, 'quoteQty');
const type = (cost === undefined) ? 'spot' : 'swap';
const currencyId = this.safeString2(trade, 'currency', 'N');
const currencyCode = this.safeCurrencyCode(currencyId);
const m = this.safeValue(trade, 'm', false);
const marketId = this.safeString(trade, 's');
const isBuyerMaker = this.safeValue2(trade, 'buyerMaker', 'isBuyerMaker');
let takeOrMaker = (isBuyerMaker || m) ? 'maker' : 'taker';
let side = this.safeStringLower2(trade, 'side', 'S');
if (side === undefined) {
side = (isBuyerMaker || m) ? 'sell' : 'buy';
takeOrMaker = 'taker';
}
return this.safeTrade({
'id': this.safeStringN(trade, ['id', 't']),
'info': trade,
'timestamp': time,
'datetime': this.iso8601(time),
'symbol': this.safeSymbol(marketId, market, '-', type),
'order': this.safeString2(trade, 'orderId', 'i'),
'type': this.safeStringLower(trade, 'o'),
'side': this.parseOrderSide(side),
'takerOrMaker': takeOrMaker,
'price': this.safeString2(trade, 'price', 'p'),
'amount': this.safeStringN(trade, ['qty', 'amount', 'q']),
'cost': cost,
'fee': {
'cost': this.parseNumber(Precise["default"].stringAbs(this.safeString2(trade, 'commission', 'n'))),
'currency': currencyCode,
'rate': undefined,
},
}, market);
}
async fetchOrderBook(symbol, limit = undefined, params = {}) {
/**
* @method
* @name bingx#fetchOrderBook
* @description fetches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
* @see https://bingx-api.github.io/docs/#/spot/market-api.html#Query%20depth%20information
* @see https://bingx-api.github.io/docs/#/swapV2/market-api.html#Get%20Market%20Depth
* @param {string} symbol unified symbol of the market to fetch the order book for
* @param {int} [limit] the maximum amount of order book entries to return
* @param {object} [params] extra parameters specific to the exchange 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 request = {
'symbol': market['id'],
};
if (limit !== undefined) {
request['limit'] = limit;
}
let response = undefined;
let marketType = undefined;
[marketType, params] = this.handleMarketTypeAndParams('fetchOrderBook', market, params);
if (marketType === 'spot') {
response = await this.spotV1PublicGetMarketDepth(this.extend(request, params));
}
else {
response = await this.swapV2PublicGetQuoteDepth(this.extend(request, params));
}
//
// spot
//
// {
// "code": 0,
// "data": {
// "bids": [
// [
// "26324.73",
// "0.37655"
// ],
// [
// "26324.71",
// "0.31888"
// ],
// ],
// "asks": [
// [
// "26340.30",
// "6.45221"
// ],
// [
// "26340.15",
// "6.73261"
// ],
// ]}
// }
//
// swap
//
// {
// "code": 0,
// "msg": "",
// "data": {
// "T": 1683914263304,
// "bids": [
// [
// "26300.90000000",
// "30408.00000000"
// ],
// [
// "26300.80000000",
// "50906.00000000"
// ],
// ],
// "asks": [
// [
// "26301.00000000",
// "43616.00000000"
// ],
// [
// "26301.10000000",
// "49402.00000000"
// ],
// ]}
// }
//
const orderbook = this.safeValue(response, 'data', {});
const timestamp = this.safeInteger2(orderbook, 'T', 'ts');
return this.parseOrderBook(orderbook, market['symbol'], timestamp, 'bids', 'asks', 0, 1);
}
async fetchFundingRate(symbol, params = {}) {
/**
* @method
* @name bingx#fetchFundingRate
* @description fetch the current funding rate
* @see https://bingx-api.github.io/docs/#/swapV2/market-api.html#Current%20Funding%20Rate
* @param {string} symbol unified market symbol
* @param {object} [params] extra parameters specific to the exchange API endpoint
* @returns {object} a [funding rate structure]{@link https://docs.ccxt.com/#/?id=funding-rate-structure}
*/
await this.loadMarkets();
const market = this.market(symbol);
const request = {
'symbol': market['id'],
};
const response = await this.swapV2PublicGetQuotePremiumIndex(this.extend(request, params));
//
// {
// "code":0,
// "msg":"",
// "data":[
// {
// "symbol": "BTC-USDT",
// "markPrice": "16884.5",
// "indexPrice": "16886.9",
// "lastFundingRate": "0.0001",
// "nextFundingTime": 1672041600000
// },
// ...
// ]
// }
//
const data = this.safeValue(response, 'data', {});
return this.parseFundingRate(data, market);
}
parseFundingRate(contract, market = undefined) {
//
// {
// "symbol": "BTC-USDT",
// "markPrice": "16884.5",
// "indexPrice": "16886.9",
// "lastFundingRate": "0.0001",
// "nextFundingTime": 1672041600000
// }
//
const marketId = this.safeString(contract, 'symbol');
const nextFundingTimestamp = this.safeInteger(contract, 'nextFundingTime');
return {
'info': contract,
'symbol': this.safeSymbol(marketId, market, '-', 'swap'),
'markPrice': this.safeNumber(contract, 'markPrice'),
'indexPrice': this.safeNumber(contract, 'indexPrice'),
'interestRate': undefined,
'estimatedSettlePrice': undefined,
'timestamp': undefined,
'datetime': undefined,
'fundingRate': this.safeNumber(contract, 'lastFundingRate'),
'fundingTimestamp': undefined,
'fundingDatetime': undefined,
'nextFundingRate': undefined,
'nextFundingTimestamp': nextFundingTimestamp,
'nextFundingDatetime': this.iso8601(nextFundingTimestamp),
'previousFundingRate': undefined,
'previousFundingTimestamp': undefined,
'previousFundingDatetime': undefined,
};
}
async fetchFundingRateHistory(symbol = undefined, since = undefined, limit = undefined, params = {}) {
/**
* @method
* @name bingx#fetchFundingRateHistory
* @description fetches historical funding rate prices
* @see https://bingx-api.github.io/docs/#/swapV2/market-api.html#Funding%20Rate%20History
* @param {string} symbol unified symbol of the market to fetch the funding rate history for
* @param {int} [since] timestamp in ms of the earliest funding rate to fetch
* @param {int} [limit] the maximum amount of [funding rate structures]{@link https://docs.ccxt.com/#/?id=funding-rate-history-structure} to fetch
* @param {object} [params] extra parameters specific to the exchange API endpoint
* @param {int} [params.until] timestamp in ms of the latest funding rate to fetch
* @param {boolean} [params.paginate] default false, when true will automatically paginate by calling this endpoint multiple times. See in the docs all the [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
* @returns {object[]} a list of [funding rate structures]{@link https://docs.ccxt.com/#/?id=funding-rate-history-structure}
*/
if (symbol === undefined) {
throw new errors.ArgumentsRequired(this.id + ' fetchFundingRateHistory() requires a symbol argument');
}
await this.loadMarkets();
let paginate = false;
[paginate, params] = this.handleOptionAndParams(params, 'fetchFundingRateHistory', 'paginate');
if (paginate) {
return await this.fetchPaginatedCallDeterministic('fetchFundingRateHistory', symbol, since, limit, '8h', params);
}
const market = this.market(symbol);
const request = {
'symbol': market['id'],
};
if (since !== undefined) {
request['startTime'] = since;
}
if (limit !== undefined) {
request['limit'] = limit;
}
const until = this.safeInteger2(params, 'until', 'startTime');
if (until !== undefined) {
params = this.omit(params, ['until']);
request['startTime'] = until;
}
const response = await this.swapV2PublicGetQuoteFundingRate(this.extend(request, params));
//
// {
// "code":0,
// "msg":"",
// "data":[
// {
// "symbol": "BTC-USDT",
// "fundingRate": "0.0001",
// "fundingTime": 1585684800000
// },
// ...
// ]
// }
//
const data = this.safeValue(response, 'data', []);
const rates = [];
for (let i = 0; i < data.length; i++) {
const entry = data[i];
const marketId = this.safeString(entry, 'symbol');
const symbolInner = this.safeSymbol(marketId, market, '-', 'swap');
const timestamp = this.safeInteger(entry, 'fundingTime');
rates.push({
'info': entry,
'symbol': symbolInner,
'fundingRate': this.safeNumber(entry, 'fundingRate'),
'timestamp': timestamp,
'datetime': this.iso8601(timestamp),
});
}
const sorted = this.sortBy(rates, 'timestamp');
return this.filterBySymbolSinceLimit(sorted, market['symbol'], since, limit);
}
async fetchOpenInterest(symbol, params = {}) {
/**
* @method
* @name bingx#fetchOpenInterest
* @description Retrieves the open interest of a currency
* @see https://bingx-api.github.io/docs/#/swapV2/market-api.html#Get%20Swap%20Open%20Positions
* @param {string} symbol Unified CCXT market symbol
* @param {object} [params] exchange specific parameters
* @returns {object} an open interest structure{@link https://docs.ccxt.com/#/?id=open-interest-structure}
*/
await this.loadMarkets();
const market = this.market(symbol);
const request = {
'symbol': market['id'],
};
const response = await this.swapV2PublicGetQuoteOpenInterest(this.extend(request, params));
//
// {
// "code": 0,
// "msg": "",
// "data": {
// "openInterest": "3289641547.10",
// "symbol": "BTC-USDT",
// "time": 1672026617364
// }
// }
//
const data = this.safeValue(response, 'data', {});
return this.parseOpenInterest(data, market);
}
parseOpenInterest(interest, market = undefined) {
//
// {
// "openInterest": "3289641547.10",
// "symbol": "BTC-USDT",
// "time": 1672026617364
// }
//
const timestamp = this.safeInteger(interest, 'time');
const id = this.safeString(interest, 'symbol');
const symbol = this.safeSymbol(id, market, '-', 'swap');
const openInterest = this.safeNumber(interest, 'openInterest');
return this.safeOpenInterest({
'symbol': symbol,
'baseVolume': undefined,
'quoteVolume': undefined,
'openInterestAmount': undefined,
'openInterestValue': openInterest,
'timestamp': timestamp,
'datetime': this.iso8601(timestamp),
'info': interest,
}, market);
}
async fetchTicker(symbol, params = {}) {
/**
* @method
* @name bingx#fetchTicker
* @description fetches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
* @see https://bingx-api.github.io/docs/#/swapV2/market-api.html#Get%20Ticker
* @see https://bingx-api.github.io/docs/#/spot/market-api.html#24%E5%B0%8F%E6%97%B6%E4%BB%B7%E6%A0%BC%E5%8F%98%E5%8A%A8%E6%83%85%E5%86%B5
* @param {string} symbol unified symbol of the market to fetch the ticker for
* @param {object} [params] extra parameters specific to the exchange 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'],
};
let response = undefined;
if (market['spot']) {
response = await this.spotV1PublicGetTicker24hr(this.extend(request, params));
}
else {
response = await this.swapV2PublicGetQuoteTicker(this.extend(request, params));
}
const data = this.safeValue(response, 'data');
const ticker = this.safeValue(data, 0, data);
return this.parseTicker(ticker, market);
}
async fetchTickers(symbols = undefined, params = {}) {
/**
* @method
* @name bingx#fetchTickers