UNPKG

consequunturatque

Version:

A JavaScript / Python / PHP cryptocurrency trading library with support for 130+ exchanges

1,123 lines (1,103 loc) 84.6 kB
'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', //