consequunturatque
Version:
A JavaScript / Python / PHP cryptocurrency trading library with support for 130+ exchanges
1,123 lines (1,103 loc) • 84.6 kB
JavaScript
'use strict';
// ---------------------------------------------------------------------------
const Exchange = require ('./base/Exchange');
const { AuthenticationError, ExchangeError, OrderNotFound, ArgumentsRequired, BadSymbol, BadRequest, NullResponse, InvalidOrder, BadResponse, NotSupported, ExchangeNotAvailable, RequestTimeout, RateLimitExceeded, PermissionDenied, InsufficientFunds, InvalidAddress } = require ('./base/errors');
const { TICK_SIZE, TRUNCATE } = require ('./base/functions/number');
const Precise = require ('./base/Precise');
// ---------------------------------------------------------------------------
module.exports = class hbtc extends Exchange {
describe () {
return this.deepExtend (super.describe (), {
'id': 'hbtc',
'name': 'HBTC',
'countries': [ 'CN' ],
'rateLimit': 2000,
'version': 'v1',
'has': {
'cancelOrder': true,
'CORS': false,
'createOrder': true,
'fetchAccounts': true,
'fetchBalance': true,
'fetchBidAsk': true,
'fetchBidsAsks': true,
'fetchClosedOrders': true,
'fetchCurrencies': false,
'fetchDepositAddress': false,
'fetchDeposits': true,
'fetchLedger': true,
'fetchMarkets': true,
'fetchMyTrades': true,
'fetchOHLCV': true,
'fetchOpenOrders': true,
'fetchOrder': true,
'fetchOrderBook': true,
'fetchOrders': false,
'fetchTicker': true,
'fetchTickers': true,
'fetchTime': true,
'fetchTrades': true,
'fetchTradingLimits': true,
'fetchWithdrawals': true,
'withdraw': true,
},
'timeframes': {
'1m': '1m',
'3m': '3m',
'5m': '5m',
'15m': '15m',
'30m': '30m',
'1h': '1h',
'2h': '2h',
'4h': '4h',
'6h': '6h',
'8h': '8h',
'12h': '12h',
'1d': '1d',
'3d': '3d',
'1w': '1w',
'1M': '1M',
},
'urls': {
'logo': 'https://user-images.githubusercontent.com/51840849/80134449-70663300-85a7-11ea-8942-e204cdeaab5d.jpg', // 交易所LOGO
'api': {
'quote': 'https://api.hbtc.com/openapi/quote', // 市场API数据端点
'contract': 'https://api.hbtc.com/openapi/contract', // 合约API数据端点
'option': 'https://api.hbtc.com/openapi/option', // 合约API数据端点
'public': 'https://api.hbtc.com/openapi', // 公共API数据端点
'private': 'https://api.hbtc.com/openapi', // 私有API数据端点
'zendesk': 'https://hbtc.zendesk.com/hc/en-us',
},
'www': 'https://www.hbtc.com', // 公司主页
'referral': 'https://www.hbtc.com/register/O2S8NS', // 邀请链接
'doc': 'https://github.com/bhexopen/BHEX-OpenApi/tree/master/doc', // openapi文档地址
'fees': 'https://hbtc.zendesk.com/hc/zh-cn/articles/360009274694', // 费率介绍
},
'api': {
'public': {
'get': [
'ping',
'time',
'brokerInfo', // 查询当前broker交易规则和symbol信息
'getOptions',
],
},
'quote': {
'get': [
'depth', // 获取深度
'depth/merged',
'trades', // 获取当前最新成交
'klines', // 获取K线数据
'ticker/24hr', // 获取24小时价格变化数据
'ticker/price',
'ticker/bookTicker',
'contract/index', // 获取合约标的指数价格
'contract/depth', // 获取合约深度
'contract/depth/merged',
'contract/trades', // 获取合约最近成交,
'contract/klines', // 获取合约的K线数据
'contract/ticker/24hr',
'option/index',
'option/depth',
'option/depth/merged',
'option/trades',
'option/klines',
'option/ticker/24hr',
],
},
'contract': {
'get': [
// public
'insurance',
'fundingRate', // 获取资金费率信息
// private
'openOrders', // 查询合约当前委托
'historyOrders', // 查询合约历史委托
'getOrder', // 查询合约订单详情
'myTrades', // 查询合约历史成交
'positions', // 查询合约当前持仓
'account', // 查询合约账户信息
],
'post': [
'order', // 创建合约订单
'modifyMargin', // 修改保证金
],
'delete': [
'order/cancel', // 取消合约订单
'order/batchCancel',
],
},
'option': {
'get': [
'openOrders',
'positions',
'historyOrders',
// 'getOrder',
'myTrades',
'settlements',
'account',
],
'post': [
'order',
],
'delete': [
'order/cancel',
],
},
'private': {
'get': [
'order', // 查询订单
'openOrders', // 查询当前委托
'historyOrders', // 查询历史委托
'account', // 获取当前账户信息
'myTrades', // 查询历史成交
'depositOrders',
'withdrawalOrders',
'withdraw/detail',
'balance_flow',
],
'post': [
'order', // 创建新订单
'order/test',
'userDataStream',
'subAccount/query',
'transfer',
'user/transfer',
'withdraw',
],
'put': [
'userDataStream',
],
'delete': [
'order', // 取消订单
'userDataStream',
],
},
},
'precisionMode': TICK_SIZE,
'fees': {
'trading': {
'tierBased': false,
'percentage': true,
'maker': 0.001,
'taker': 0.001,
},
},
'exceptions': {
'exact': {
// general server or network errors
'-1000': ExchangeError, // An unknown error occured while processing the request
'-1001': ExchangeError, // Internal error, unable to process your request. Please try again
'-1002': AuthenticationError, // You are not authorized to execute this request. Request need API Key included in. We suggest that API Key be included in any request
'-1003': RateLimitExceeded, // Too many requests, please use the websocket for live updates
'-1004': BadRequest,
'-1005': PermissionDenied,
'-1006': BadResponse, // An unexpected response was received from the message bus. Execution status unknown. OPEN API server find some exception in execute request.Please report to Customer service
'-1007': RequestTimeout, // Timeout waiting for response from backend server. Send status unknown, execution status unknown
'-1014': InvalidOrder, // Unsupported order combination
'-1015': RateLimitExceeded, // Reach the rate limit.Please slow down your request speed
'-1016': ExchangeNotAvailable, // This service is no longer available
'-1020': NotSupported, // This operation is not supported
'-1021': BadRequest, // Timestamp for this request is outside of the recvWindow
'-1022': AuthenticationError, // Signature for this request is not valid
// request issues
'-1100': BadRequest, // Illegal characters found in a parameter
'-1101': BadRequest, // Too many parameters sent for this endpoint
'-1102': BadRequest, // A mandatory parameter was not sent, was empty/null, or malformed
'-1103': BadRequest, // An unknown parameter was sent
'-1104': BadRequest, // Not all sent parameters were read
'-1105': BadRequest, // A parameter was empty
'-1106': BadRequest, // A parameter was sent when not required
'-1111': BadRequest, // Precision is over the maximum defined for this asset
'-1112': NullResponse, // No orders on book for symbol
'-1114': InvalidOrder, // TimeInForce parameter sent when not required
'-1115': InvalidOrder, // Invalid timeInForce
'-1116': InvalidOrder, // Invalid orderType
'-1117': InvalidOrder, // Invalid side
'-1118': InvalidOrder, // New client order ID was empty
'-1119': InvalidOrder, // Original client order ID was empty
'-1120': BadRequest, // Invalid interval
'-1121': BadSymbol, // Invalid symbol
'-1125': AuthenticationError, // This listenKey does not exist
'-1127': BadRequest, // Lookup interval is too big
'-1128': BadRequest, // Combination of optional parameters invalid
'-1130': BadRequest, // Invalid data sent for a parameter
'-1131': InsufficientFunds,
'-1132': InvalidOrder, // Order price too high
'-1133': InvalidOrder, // Order price lower than the minimum,please check general broker info
'-1134': InvalidOrder, // Order price decimal too long,please check general broker info
'-1135': InvalidOrder, // Order quantity too large
'-1136': InvalidOrder, // Order quantity lower than the minimum
'-1137': InvalidOrder, // Order quantity decimal too long
'-1138': InvalidOrder, // Order price exceeds permissible range
'-1139': InvalidOrder, // Order has been filled
'-1140': InvalidOrder, // Transaction amount lower than the minimum
'-1141': InvalidOrder, // Duplicate clientOrderId
'-1142': InvalidOrder, // Order has been canceled
'-1143': OrderNotFound, // Cannot be found on order book
'-1144': InvalidOrder, // Order has been locked
'-1145': InvalidOrder, // This order type does not support cancellation
'-1146': RequestTimeout, // Order creation timeout
'-1147': RequestTimeout, // Order cancellation timeout
'-1149': InvalidOrder, // Create order failed
'-1187': InvalidAddress, // Withdrawal address not in whitelist
'-2010': InvalidOrder, // NEW_ORDER_REJECTED
'-2011': InvalidOrder, // CANCEL_REJECTED
'-2013': OrderNotFound, // Order does not exist
'-2014': AuthenticationError, // API-key format invalid
'-2015': AuthenticationError, // Invalid API-key, IP, or permissions for action
'-2016': ExchangeError, // No trading window could be found for the symbol. Try ticker/24hrs instead
},
},
// exchange-specific options
'options': {
'fetchTickers': {
'method': 'quoteGetTicker24hr',
},
},
'commonCurrencies': {
'MIS': 'Themis Protocol',
},
});
}
async fetchTime (params = {}) {
const response = await this.publicGetTime (params);
//
// {
// "serverTime": 1527777538000
// }
//
return this.safeInteger (response, 'serverTime');
}
parseMarket (market, type = 'spot') {
const filters = this.safeValue (market, 'filters', []);
const id = this.safeString (market, 'symbol');
let baseId = this.safeString (market, 'baseAsset');
const quoteId = this.safeString (market, 'quoteAsset');
let base = this.safeCurrencyCode (baseId);
const quote = this.safeCurrencyCode (quoteId);
let symbol = base + '/' + quote;
let spot = true;
let future = false;
let option = false;
let inverse = false;
if (type === 'future') {
symbol = id;
spot = false;
future = true;
inverse = this.safeValue (market, 'inverse', false);
baseId = this.safeString (market, 'underlying');
base = this.safeCurrencyCode (baseId);
} else if (type === 'option') {
symbol = id;
spot = false;
option = true;
}
const margin = this.safeValue (market, 'allowMargin', undefined);
const isAggregate = this.safeValue (market, 'isAggregate', undefined);
let active = true;
if (isAggregate === true) {
active = false;
}
let amountMin = undefined;
let amountMax = undefined;
let priceMin = undefined;
let priceMax = undefined;
let costMin = undefined;
for (let j = 0; j < filters.length; j++) {
const filter = filters[j];
const filterType = this.safeString (filter, 'filterType');
if (filterType === 'LOT_SIZE') {
amountMin = this.safeNumber (filter, 'minQty');
amountMax = this.safeNumber (filter, 'maxQty');
}
if (filterType === 'PRICE_FILTER') {
priceMin = this.safeNumber (filter, 'minPrice');
priceMax = this.safeNumber (filter, 'maxPrice');
}
if (filterType === 'MIN_NOTIONAL') {
costMin = this.safeNumber (filter, 'minNotional');
}
}
if ((costMin === undefined) && (amountMin !== undefined) && (priceMin !== undefined)) {
costMin = amountMin * priceMin;
}
const precision = {
'price': this.safeNumber2 (market, 'quotePrecision', 'quoteAssetPrecision'),
'amount': this.safeNumber (market, 'baseAssetPrecision'),
};
const limits = {
'amount': {
'min': amountMin,
'max': amountMax,
},
'price': {
'min': priceMin,
'max': priceMax,
},
'cost': {
'min': costMin,
'max': undefined,
},
};
return {
'id': id,
'symbol': symbol,
'base': base,
'quote': quote,
'baseId': baseId,
'quoteId': quoteId,
'active': active,
'type': type,
'spot': spot,
'future': future,
'option': option,
'margin': margin,
'inverse': inverse,
'precision': precision,
'limits': limits,
'info': market,
};
}
async fetchMarkets (params = {}) {
const response = await this.publicGetBrokerInfo (params);
//
// {
// "timezone":"UTC",
// "serverTime":"1588015885118",
// "brokerFilters":[],
// "symbols":[
// {
// "filters":[
// {"minPrice":"0.01","maxPrice":"100000.00000000","tickSize":"0.01","filterType":"PRICE_FILTER"},
// {"minQty":"0.0005","maxQty":"100000.00000000","stepSize":"0.000001","filterType":"LOT_SIZE"},
// {"minNotional":"0.01","filterType":"MIN_NOTIONAL"}
// ],
// "exchangeId":"301",
// "symbol":"BTCUSDT",
// "symbolName":"BTCUSDT",
// "status":"TRADING",
// "baseAsset":"BTC",
// "baseAssetName":"BTC",
// "baseAssetPrecision":"0.000001",
// "quoteAsset":"USDT",
// "quoteAssetName":"USDT",
// "quotePrecision":"0.01",
// "icebergAllowed":false,
// "isAggregate":false,
// "allowMargin":true
// },
// ],
// "options":[
// {
// "filters":[
// {"minPrice":"0.01","maxPrice":"100000.00000000","tickSize":"0.01","filterType":"PRICE_FILTER"},
// {"minQty":"0.01","maxQty":"100000.00000000","stepSize":"0.001","filterType":"LOT_SIZE"},
// {"minNotional":"1","filterType":"MIN_NOTIONAL"}
// ],
// "exchangeId":"301",
// "symbol":"BTC0501CS8500",
// "symbolName":"BTC0501CS8500",
// "status":"TRADING",
// "baseAsset":"BTC0501CS8500",
// "baseAssetName":"BTC0306CS3800",
// "baseAssetPrecision":"0.001",
// "quoteAsset":"BUSDT",
// "quoteAssetName":"BUSDT",
// "quotePrecision":"0.01",
// "icebergAllowed":false
// "isAggregate":false,
// "allowMargin":false
// },
// ],
// "contracts":[
// {
// "filters":[
// {"minPrice":"0.1","maxPrice":"100000.00000000","tickSize":"0.1","filterType":"PRICE_FILTER"},
// {"minQty":"1","maxQty":"100000.00000000","stepSize":"1","filterType":"LOT_SIZE"},
// {"minNotional":"0.000001","filterType":"MIN_NOTIONAL"}
// ],
// "exchangeId":"301",
// "symbol":"BTC-PERP-REV",
// "symbolName":"BTC-PERP-REV",
// "status":"TRADING",
// "baseAsset":"BTC-PERP-REV",
// "baseAssetPrecision":"1",
// "quoteAsset":"USDT",
// "quoteAssetPrecision":"0.1",
// "icebergAllowed":false,
// "inverse":true,
// "index":"BTCUSDT",
// "marginToken":"TBTC",
// "marginPrecision":"0.00000001",
// "contractMultiplier":"1.0",
// "underlying":"TBTC",
// "riskLimits":[
// {"riskLimitId":"200000001","quantity":"1000000.0","initialMargin":"0.01","maintMargin":"0.005"},
// {"riskLimitId":"200000002","quantity":"2000000.0","initialMargin":"0.02","maintMargin":"0.01"},
// {"riskLimitId":"200000003","quantity":"3000000.0","initialMargin":"0.03","maintMargin":"0.015"},
// {"riskLimitId":"200000004","quantity":"4000000.0","initialMargin":"0.04","maintMargin":"0.02"}
// ]
// },
// {
// "filters":[
// {"minPrice":"0.1","maxPrice":"100000.00000000","tickSize":"0.1","filterType":"PRICE_FILTER"},
// {"minQty":"1","maxQty":"100000.00000000","stepSize":"1","filterType":"LOT_SIZE"},
// {"minNotional":"0.000001","filterType":"MIN_NOTIONAL"}
// ],
// "exchangeId":"301",
// "symbol":"BTC-SWAP",
// "symbolName":"BTC-SWAP",
// "status":"TRADING",
// "baseAsset":"BTC-SWAP",
// "baseAssetPrecision":"1",
// "quoteAsset":"USDT",
// "quoteAssetPrecision":"0.1",
// "icebergAllowed":false,
// "inverse":true,
// "index":"BTCUSDT",
// "marginToken":"BTC",
// "marginPrecision":"0.00000001",
// "contractMultiplier":"1.0",
// "underlying":"BTC",
// "riskLimits":[
// {"riskLimitId":"500000001","quantity":"1000000.0","initialMargin":"0.01","maintMargin":"0.005"},
// {"riskLimitId":"500000002","quantity":"2000000.0","initialMargin":"0.02","maintMargin":"0.01"},
// {"riskLimitId":"500000003","quantity":"3000000.0","initialMargin":"0.03","maintMargin":"0.015"},
// {"riskLimitId":"500000004","quantity":"4000000.0","initialMargin":"0.04","maintMargin":"0.02"}
// ]
// },
// {
// "filters":[
// {"minPrice":"0.1","maxPrice":"100000.00000000","tickSize":"0.1","filterType":"PRICE_FILTER"},
// {"minQty":"1","maxQty":"100000.00000000","stepSize":"1","filterType":"LOT_SIZE"},
// {"minNotional":"0.000000001","filterType":"MIN_NOTIONAL"}
// ],
// "exchangeId":"301",
// "symbol":"BTC-PERP-BUSDT",
// "symbolName":"BTC-PERP-BUSDT",
// "status":"TRADING",
// "baseAsset":"BTC-PERP-BUSDT",
// "baseAssetPrecision":"1",
// "quoteAsset":"BUSDT",
// "quoteAssetPrecision":"0.1",
// "icebergAllowed":false,
// "inverse":false,
// "index":"BTCUSDT",
// "marginToken":"BUSDT",
// "marginPrecision":"0.0001",
// "contractMultiplier":"0.0001",
// "underlying":"TBTC",
// "riskLimits":[
// {"riskLimitId":"600000132","quantity":"1000000.0","initialMargin":"0.01","maintMargin":"0.005"},
// {"riskLimitId":"600000133","quantity":"2000000.0","initialMargin":"0.02","maintMargin":"0.01"},
// {"riskLimitId":"600000134","quantity":"3000000.0","initialMargin":"0.03","maintMargin":"0.015"},
// {"riskLimitId":"600000135","quantity":"4000000.0","initialMargin":"0.04","maintMargin":"0.02"}
// ]
// },
// ]
// }
//
const result = [];
const symbols = this.safeValue (response, 'symbols', []);
for (let i = 0; i < symbols.length; i++) {
const market = this.parseMarket (symbols[i], 'spot');
result.push (market);
}
const options = this.safeValue (response, 'options', []);
for (let i = 0; i < options.length; i++) {
const market = this.parseMarket (options[i], 'option');
result.push (market);
}
const contracts = this.safeValue (response, 'contracts', []);
for (let i = 0; i < contracts.length; i++) {
const market = this.parseMarket (contracts[i], 'future');
result.push (market);
}
return result;
}
async fetchOrderBook (symbol, limit = undefined, params = {}) {
await this.loadMarkets ();
const market = this.market (symbol);
const request = {
'symbol': market['id'],
};
if (limit !== undefined) {
request['limit'] = limit; // default 40, max 40
}
const response = await this.quoteGetDepth (this.extend (request, params));
//
// {
// "time":1588068913453,
// "bids":[
// ["0.025278","0.0202"],
// ["0.025277","16.1132"],
// ["0.025276","7.9056"],
// ]
// "asks":[
// ["0.025302","5.9999"],
// ["0.025303","34.9151"],
// ["0.025304","92.391"],
// ]
// }
//
const timestamp = this.safeInteger (response, 'time');
return this.parseOrderBook (response, symbol, timestamp);
}
async fetchTicker (symbol, params = {}) {
await this.loadMarkets ();
const market = this.market (symbol);
const request = {
'symbol': market['id'],
};
const response = await this.quoteGetTicker24hr (this.extend (request, params));
//
// {
// "time":1588069860794,
// "symbol":"BNB0501PS16",
// "bestBidPrice":"0.2129",
// "bestAskPrice":"0.3163",
// "volume":"33547",
// "quoteVolume":"10801.987",
// "lastPrice":"0.2625",
// "highPrice":"0.3918",
// "lowPrice":"0.2625",
// "openPrice":"0.362",
// }
//
return this.parseTicker (response, market);
}
async fetchBidAsk (symbol, params = {}) {
await this.loadMarkets ();
const market = this.market (symbol);
const request = {
'symbol': market['id'],
};
const response = await this.quoteGetTickerBookTicker (this.extend (request, params));
//
// {
// "symbol": "LTCBTC",
// "bidPrice": "4.00000000",
// "bidQty": "431.00000000",
// "askPrice": "4.00000200",
// "askQty": "9.00000000"
// }
//
return this.parseTicker (response, market);
}
async fetchBidsAsks (symbols = undefined, params = {}) {
await this.loadMarkets ();
const response = await this.quoteGetTickerBookTicker (params);
//
// [
// {
// "symbol": "LTCBTC",
// "bidPrice": "4.00000000",
// "bidQty": "431.00000000",
// "askPrice": "4.00000200",
// "askQty": "9.00000000"
// },
// {
// "symbol": "ETHBTC",
// "bidPrice": "0.07946700",
// "bidQty": "9.00000000",
// "askPrice": "100000.00000000",
// "askQty": "1000.00000000"
// },
// ]
//
return this.parseTickers (response, symbols);
}
async fetchTickers (symbols = undefined, params = {}) {
await this.loadMarkets ();
const options = this.safeValue (this.options, 'fetchTickers', {});
const defaultMethod = this.safeString (options, 'method', 'quoteGetTicker24hr');
const defaultType = this.safeString (options, 'type', 'spot');
const type = this.safeString (params, 'type', defaultType);
const query = this.omit (params, 'type');
let method = defaultMethod;
if (type === 'future') {
method = 'quoteGetContractTicker24hr';
} else if (type === 'option') {
method = 'quoteGetOptionTicker24hr';
}
const response = await this[method] (query);
//
// [
// {
// "time": 1538725500422,
// "symbol": "ETHBTC",
// "lastPrice": "4.00000200",
// "openPrice": "99.00000000",
// "highPrice": "100.00000000",
// "lowPrice": "0.10000000",
// "volume": "8913.30000000"
// },
// ]
//
return this.parseTickers (response, symbols);
}
async fetchBalance (params = {}) {
await this.loadMarkets ();
const options = this.safeValue (this.options, 'fetchBalance', {});
const defaultType = this.safeString (options, 'type', 'spot');
const type = this.safeString (params, 'type', defaultType);
const query = this.omit (params, 'type');
let method = 'privateGetAccount';
if (type === 'future') {
method = 'contractGetAccount';
} else if (type === 'option') {
method = 'optionGetAccount';
}
const response = await this[method] (query);
//
// spot
//
// {
// 'balances': [
// {
// 'asset': 'ALGO',
// 'free': '0',
// 'locked': '0'
// },
// {
// 'asset': 'BHT',
// 'free': '0',
// 'locked': '0'
// }
// ]
// }
//
// contract
//
// {
// "BUSDT":{
// "total":"1000",
// "availableMargin":"1000",
// "positionMargin":"0",
// "orderMargin":"0",
// "tokenId":"BUSDT"
// },
// "TBTC":{
// "total":"0.5",
// "availableMargin":"0.5",
// "positionMargin":"0",
// "orderMargin":"0",
// "tokenId":"TBTC"
// }
// }
//
// option
//
// {
// "optionAsset":"",
// "balances":[
// {
// "tokenName":"USDT",
// "free":"0.0",
// "locked":"0.0",
// "margin":"0.0"
// },
// {
// "tokenName":"BUSDT",
// "free":"0.0",
// "locked":"0.0",
// "margin":"0.0"
// }
// ]
// }
//
const balances = this.safeValue (response, 'balances');
const result = { 'info': response };
if (balances !== undefined) {
for (let i = 0; i < balances.length; i++) {
const balance = balances[i];
const currencyId = this.safeString2 (balance, 'asset', 'tokenName');
const code = this.safeCurrencyCode (currencyId);
const account = this.account ();
account['free'] = this.safeString (balance, 'free');
account['used'] = this.safeString (balance, 'locked');
result[code] = account;
}
} else {
const currencyIds = Object.keys (response);
for (let i = 0; i < currencyIds.length; i++) {
const currencyId = currencyIds[i];
const code = this.safeCurrencyCode (currencyId);
const balance = response[currencyId];
const account = this.account ();
account['free'] = this.safeString (balance, 'availableMargin');
account['total'] = this.safeString (balance, 'total');
result[code] = account;
}
}
return this.parseBalance (result, false);
}
async fetchTrades (symbol, since = undefined, limit = 50, params = {}) {
await this.loadMarkets ();
const market = this.market (symbol);
const request = {
'symbol': market['id'],
};
if (limit !== undefined) {
request['limit'] = limit; // default 500, max 1000
}
const response = await this.quoteGetTrades (this.extend (request, params));
//
// [
// {"price":"0.025344","time":1588084082060,"qty":"1","isBuyerMaker":false},
// {"price":"0.02535","time":1588084086021,"qty":"0.553","isBuyerMaker":true},
// {"price":"0.025348","time":1588084097037,"qty":"1","isBuyerMaker":false},
// ]
//
return this.parseTrades (response, market, since, limit);
}
parseOHLCV (ohlcv, market = undefined) {
//
// [
// 1587906000000, // open time
// "0.1761", // open
// "0.1761", // high
// "0.1761", // low
// "0.1761", // close
// "0", // base volume
// 0, // close time
// "0", // quote volume
// 0, // number of trades
// "0", // taker buy base asset volume
// "0" // taker buy quote asset volume
// ]
//
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),
];
}
async fetchOHLCV (symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
await this.loadMarkets ();
const market = this.market (symbol);
const request = {
'symbol': market['id'],
'interval': this.timeframes[timeframe],
};
if (since !== undefined) {
request['startTime'] = since;
}
if (limit !== undefined) {
request['limit'] = limit; // default 500, max 500
}
const response = await this.quoteGetKlines (this.extend (request, params));
//
// [
// [1587906000000,"0.1761","0.1761","0.1761","0.1761","0",0,"0",0,"0","0"],
// [1587906180000,"0.1761","0.1761","0.1761","0.1761","0",0,"0",0,"0","0"],
// [1587906360000,"0.1761","0.1848","0.1761","0.1848","53",0,"9.7944",1,"0","0"],
// ]
//
return this.parseOHLCVs (response, market, timeframe, since, limit);
}
async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) {
await this.loadMarkets ();
let market = undefined;
const request = {
// if only fromId is set,it will get orders < that fromId in descending order
// if only toId is set, it will get orders > that toId in ascending order
// if fromId is set and toId is set, it will get orders < that fromId and > that toId in descending order
// if fromId is not set and toId it not set, most recent order are returned in descending order
// 'fromId': '43287482374',
// 'toId': '43287482374',
// 'endTime': this.milliseconds (), // optional, spot only
};
const defaultType = this.safeString (this.options, 'type', 'spot');
const options = this.safeValue (this.options, 'fetchMyTrades', {});
const fetchMyTradesType = this.safeString (options, 'type', defaultType);
let type = this.safeString (params, 'type', fetchMyTradesType);
if (symbol !== undefined) {
market = this.market (symbol);
request['symbol'] = market['id'];
type = market['type'];
}
const query = this.omit (params, 'type');
if (limit !== undefined) {
// spot default 500, max 1000
// futures and options default 20, max 1000
request['limit'] = limit;
}
let method = 'privateGetMyTrades';
if (type === 'future') {
method = 'contractGetMyTrades';
} else {
if (type === 'option') {
method = 'optionGetMyTrades';
} else {
if (symbol === undefined) {
throw new ArgumentsRequired (this.id + ' fetchMyTrades() requires a `symbol` argument for ' + type + ' markets');
}
const market = this.market (symbol);
request['symbol'] = market['id'];
// spot only?
if (since !== undefined) {
request['startTime'] = since;
}
}
}
if (since !== undefined) {
request['startTime'] = since;
}
const response = await this[method] (this.extend (request, query));
//
// spot
//
// [
// {
// "id":"616384027512920576",
// "symbol":"TBTCBUSDT",
// "orderId":"616384027202542080",
// "matchOrderId":"605124954767266560",
// "price":"6826.06",
// "qty":"0.1",
// "commission":"0.682606",
// "commissionAsset":"BUSDT",
// "time":"1588214701982",
// "isBuyer":false,
// "isMaker":false,
// "fee":{
// "feeTokenId":"BUSDT",
// "feeTokenName":"BUSDT",
// "fee":"0.682606"
// }
// }
// ]
//
return this.parseTrades (response, market, since, limit);
}
async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
await this.loadMarkets ();
const market = this.market (symbol);
const orderSide = side.toUpperCase ();
const orderType = type.toUpperCase ();
const request = {
'symbol': market['id'],
// BUY or SELL for spot and options
'side': orderSide,
// GTC, FOK, IOC for spot and options
// GTC, FOK, IOC, LIMIT_MAKER for futures
// 'timeInForce': 'GTC',
};
let query = params;
let method = 'privatePostOrder';
if (market['type'] === 'future') {
if ((orderSide !== 'BUY_OPEN') && (orderSide !== 'SELL_OPEN') && (orderSide !== 'BUY_CLOSE') && (orderSide !== 'SELL_CLOSE')) {
throw new NotSupported (this.id + ' createOrder() does not support order side ' + side + ' for ' + market['type'] + ' markets, only BUY_OPEN, SELL_OPEN, BUY_CLOSE and SELL_CLOSE are supported');
}
if ((orderType !== 'LIMIT') && (orderType !== 'STOP')) {
throw new NotSupported (this.id + ' createOrder() does not support order type ' + type + ' for ' + market['type'] + ' markets, only LIMIT and STOP are supported');
}
const clientOrderId = this.safeValue (params, 'clientOrderId');
if (clientOrderId === undefined) {
throw new ArgumentsRequired (this.id + ' createOrder() requires a clientOrderId parameter for ' + market['type'] + ' markets, supply clientOrderId in the params argument');
}
const leverage = this.safeValue (params, 'leverage');
if (leverage === undefined && (orderSide === 'BUY_OPEN' || orderSide === 'SELL_OPEN')) {
throw new NotSupported (this.id + ' createOrder() requires a leverage parameter for ' + market['type'] + ' markets if orderSide is BUY_OPEN or SELL_OPEN');
}
method = 'contractPostOrder';
const priceType = this.safeString (params, 'priceType');
if (priceType === undefined) {
request['price'] = this.priceToPrecision (symbol, price);
} else {
request['priceType'] = priceType;
if (priceType === 'INPUT') {
request['price'] = this.priceToPrecision (symbol, price);
}
}
request['orderType'] = type.toUpperCase (); // LIMIT, STOP
request['quantity'] = this.amountToPrecision (symbol, amount);
// request['leverage'] = 1; // not required for closing orders
request['leverage'] = leverage;
request['clientOrderId'] = clientOrderId;
// optional
// request['priceType'] = 'INPUT', // INPUT, OPPONENT, QUEUE, OVER, MARKET
// request['triggerPrice'] = 123.45;
} else {
if (market['type'] === 'option') {
method = 'optionPostOrder';
}
const newClientOrderId = this.safeValue2 (params, 'clientOrderId', 'newClientOrderId');
if (newClientOrderId !== undefined) {
request['newClientOrderId'] = newClientOrderId;
}
request['type'] = orderType;
if (type === 'limit') {
request['price'] = this.priceToPrecision (symbol, price);
request['quantity'] = this.amountToPrecision (symbol, amount);
} else if (type === 'market') {
// for market buy it requires the amount of quote currency to spend
if (side === 'buy') {
const createMarketBuyOrderRequiresPrice = this.safeValue (this.options, 'createMarketBuyOrderRequiresPrice', true);
if (createMarketBuyOrderRequiresPrice) {
if (price !== undefined) {
amount = amount * price;
} else {
throw new InvalidOrder (this.id + " createOrder() requires the price argument with market buy orders to calculate total order cost (amount to spend), where cost = amount * price. Supply a price argument to createOrder() call if you want the cost to be calculated for you from price and amount, or, alternatively, add .options['createMarketBuyOrderRequiresPrice'] = false and supply the total cost value in the 'amount' argument (the exchange-specific behaviour)");
}
}
const precision = market['precision']['price'];
request['quantity'] = this.decimalToPrecision (amount, TRUNCATE, precision, this.precisionMode);
} else {
request['quantity'] = this.amountToPrecision (symbol, amount);
}
}
}
query = this.omit (query, [ 'clientOrderId', 'newClientOrderId' ]);
const response = await this[method] (this.extend (request, query));
//
// spot
//
// {
// "symbol":"TBTCBUSDT",
// "orderId":"616376654496877056",
// "clientOrderId":"158821382304516955",
// "transactTime":"1588213823080",
// "price":"0",
// "origQty":"1000",
// "executedQty":"0",
// "status":"NEW",
// "timeInForce":"GTC",
// "type":"MARKET",
// "side":"BUY"
// }
//
// contract
//
// {
// 'time': '1570759718825',
// 'updateTime': '0',
// 'orderId': '469961015902208000',
// 'clientOrderId': '6423344174',
// 'symbol': 'BTC-PERP-REV',
// 'price': '8200',
// 'leverage': '12.08',
// 'origQty': '5',
// 'executedQty': '0',
// 'avgPrice': '0',
// 'marginLocked': '0.00005047',
// 'orderType': 'LIMIT',
// 'side': 'BUY_OPEN',
// 'fees': [],
// 'timeInForce': 'GTC',
// 'status': 'NEW',
// 'priceType': 'INPUT'
// }
//
return this.parseOrder (response, market);
}
async cancelOrder (id, symbol = undefined, params = {}) {
await this.loadMarkets ();
const clientOrderId = this.safeValue2 (params, 'origClientOrderId', 'clientOrderId');
const request = {};
const defaultType = this.safeString (this.options, 'type', 'spot');
const options = this.safeValue (this.options, 'cancelOrder', {});
const cancelOrderType = this.safeString (options, 'type', defaultType);
let type = this.safeString (params, 'type', cancelOrderType);
let query = this.omit (params, 'type');
if (clientOrderId !== undefined) {
request['origClientOrderId'] = clientOrderId;
query = this.omit (query, [ 'origClientOrderId', 'clientOrderId' ]);
} else {
request['orderId'] = id;
}
let method = 'privateDeleteOrder';
const orderType = this.safeString (query, 'orderType');
if (orderType !== undefined) {
type = 'future';
}
if (type === 'future') {
method = 'contractDeleteOrderCancel';
if (orderType === undefined) {
throw new ArgumentsRequired (this.id + " cancelOrder() requires an orderType parameter, pass the { 'orderType': 'LIMIT' } or { 'orderType': 'STOP' } in params argument");
}
request['orderType'] = orderType;
} else {
if (type === 'option') {
method = 'optionDeleteOrderCancel';
}
}
const response = await this[method] (this.extend (request, query));
//
// spot
//
// {
// 'exchangeId': '301',
// 'symbol': 'BHTUSDT',
// 'clientOrderId': '0',
// 'orderId': '499890200602846976',
// 'status': 'CANCELED'
// }
//
// futures
//
// {
// "time":"1588353669383",
// "updateTime":"0",
// "orderId":"617549770304599296",
// "clientOrderId":"test-001",
// "symbol":"BTC-PERP-REV",
// "price":"10000",
// "leverage":"1",
// "origQty":"100",
// "executedQty":"0",
// "avgPrice":"0",
// "marginLocked":"0",
// "orderType":"LIMIT",
// "side":"SELL_OPEN",
// "fees":[],
// "timeInForce":"GTC",
// "status":"CANCELED",
// "priceType":"INPUT",
// }
//
return this.parseOrder (response);
}
async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
await this.loadMarkets ();
let market = undefined;
const request = {
// if orderId is set, it will get orders < that orderId otherwise most recent orders are returned
// 'orderId': '43287482374',
};
const defaultType = this.safeString (this.options, 'type', 'spot');
const options = this.safeValue (this.options, 'fetchOpenOrders', {});
const fetchOpenOrdersType = this.safeString (options, 'type', defaultType);
let type = this.safeString (params, 'type', fetchOpenOrdersType);
if (symbol !== undefined) {
market = this.market (symbol);
request['symbol'] = market['id'];
type = market['type'];
}
const query = this.omit (params, 'type');
if (limit !== undefined) {
request['limit'] = limit; // default 500, max 1000
}
let method = 'privateGetOpenOrders';
if (type === 'future') {
method = 'contractGetOpenOrders';
} else if (type === 'option') {
method = 'optionGetOpenOrders';
}
const response = await this[method] (this.extend (request, query));
//
// spot
//
// [
// {
// 'orderId': '499902955766523648',
// 'clientOrderId': '157432907618453',
// 'exchangeId': '301',
// 'symbol': 'BHTUSDT',
// 'price': '0.01',
//