UNPKG

consequunturatque

Version:

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

1,073 lines (1,057 loc) 101 kB
'use strict'; // --------------------------------------------------------------------------- const Exchange = require ('./base/Exchange'); const { AuthenticationError, ExchangeNotAvailable, AccountSuspended, PermissionDenied, RateLimitExceeded, InvalidNonce, InvalidAddress, ArgumentsRequired, ExchangeError, InvalidOrder, InsufficientFunds, BadRequest, OrderNotFound, BadSymbol, NotSupported } = require ('./base/errors'); const { ROUND, TICK_SIZE, TRUNCATE } = require ('./base/functions/number'); // --------------------------------------------------------------------------- module.exports = class bitmart extends Exchange { describe () { return this.deepExtend (super.describe (), { 'id': 'bitmart', 'name': 'BitMart', 'countries': [ 'US', 'CN', 'HK', 'KR' ], 'rateLimit': 1000, 'version': 'v1', 'has': { 'cancelAllOrders': true, 'cancelOrder': true, 'cancelOrders': true, 'createOrder': true, 'fetchBalance': true, 'fetchCanceledOrders': true, 'fetchClosedOrders': true, 'fetchCurrencies': true, 'fetchDepositAddress': true, 'fetchDeposits': true, 'fetchMarkets': true, 'fetchMyTrades': true, 'fetchOHLCV': true, 'fetchOpenOrders': true, 'fetchOrder': true, 'fetchOrderBook': true, 'fetchOrders': true, 'fetchOrderTrades': true, 'fetchTicker': true, 'fetchTickers': true, 'fetchTime': true, 'fetchStatus': true, 'fetchTrades': true, 'fetchWithdrawals': true, 'withdraw': true, }, 'hostname': 'bitmart.com', // bitmart.info for Hong Kong users 'urls': { 'logo': 'https://user-images.githubusercontent.com/1294454/61835713-a2662f80-ae85-11e9-9d00-6442919701fd.jpg', 'api': 'https://api-cloud.{hostname}', // bitmart.info for Hong Kong users 'www': 'https://www.bitmart.com/', 'doc': 'https://developer-pro.bitmart.com/', 'referral': 'http://www.bitmart.com/?r=rQCFLh', 'fees': 'https://www.bitmart.com/fee/en', }, 'requiredCredentials': { 'apiKey': true, 'secret': true, 'uid': true, }, 'api': { 'public': { 'system': { 'get': [ 'time', // https://api-cloud.bitmart.com/system/time 'service', // https://api-cloud.bitmart.com/system/service ], }, 'account': { 'get': [ 'currencies', // https://api-cloud.bitmart.com/account/v1/currencies ], }, 'spot': { 'get': [ 'currencies', 'symbols', 'symbols/details', 'ticker', // ?symbol=BTC_USDT 'steps', // ?symbol=BMX_ETH 'symbols/kline', // ?symbol=BMX_ETH&step=15&from=1525760116&to=1525769116 'symbols/book', // ?symbol=BMX_ETH&precision=6 'symbols/trades', // ?symbol=BMX_ETH ], }, 'contract': { 'get': [ 'contracts', // https://api-cloud.bitmart.com/contract/v1/ifcontract/contracts 'pnls', 'indexes', 'tickers', 'quote', 'indexquote', 'trades', 'depth', 'fundingrate', ], }, }, 'private': { 'account': { 'get': [ 'wallet', // ?account_type=1 'deposit/address', // ?currency=USDT-TRC20 'withdraw/charge', // ?currency=BTC 'deposit-withdraw/history', // ?limit=10&offset=1&operationType=withdraw 'deposit-withdraw/detail', // ?id=1679952 ], 'post': [ 'withdraw/apply', ], }, 'spot': { 'get': [ 'wallet', 'order_detail', 'orders', 'trades', ], 'post': [ 'submit_order', // https://api-cloud.bitmart.com/spot/v1/submit_order 'cancel_order', // https://api-cloud.bitmart.com/spot/v2/cancel_order 'cancel_orders', ], }, 'contract': { 'get': [ 'userOrders', 'userOrderInfo', 'userTrades', 'orderTrades', 'accounts', 'userPositions', 'userLiqRecords', 'positionFee', ], 'post': [ 'batchOrders', 'submitOrder', 'cancelOrders', 'marginOper', ], }, }, }, 'timeframes': { '1m': 1, '3m': 3, '5m': 5, '15m': 15, '30m': 30, '45m': 45, '1h': 60, '2h': 120, '3h': 180, '4h': 240, '1d': 1440, '1w': 10080, '1M': 43200, }, 'fees': { 'trading': { 'tierBased': true, 'percentage': true, 'taker': 0.0025, 'maker': 0.0025, 'tiers': { 'taker': [ [0, 0.20 / 100], [10, 0.18 / 100], [50, 0.16 / 100], [250, 0.14 / 100], [1000, 0.12 / 100], [5000, 0.10 / 100], [25000, 0.08 / 100], [50000, 0.06 / 100], ], 'maker': [ [0, 0.1 / 100], [10, 0.09 / 100], [50, 0.08 / 100], [250, 0.07 / 100], [1000, 0.06 / 100], [5000, 0.05 / 100], [25000, 0.04 / 100], [50000, 0.03 / 100], ], }, }, }, 'precisionMode': TICK_SIZE, 'exceptions': { 'exact': { // general errors '30000': ExchangeError, // 404, Not found '30001': AuthenticationError, // 401, Header X-BM-KEY is empty '30002': AuthenticationError, // 401, Header X-BM-KEY not found '30003': AccountSuspended, // 401, Header X-BM-KEY has frozen '30004': AuthenticationError, // 401, Header X-BM-SIGN is empty '30005': AuthenticationError, // 401, Header X-BM-SIGN is wrong '30006': AuthenticationError, // 401, Header X-BM-TIMESTAMP is empty '30007': AuthenticationError, // 401, Header X-BM-TIMESTAMP range. Within a minute '30008': AuthenticationError, // 401, Header X-BM-TIMESTAMP invalid format '30010': PermissionDenied, // 403, IP is forbidden. We recommend enabling IP whitelist for API trading. After that reauth your account '30011': AuthenticationError, // 403, Header X-BM-KEY over expire time '30012': AuthenticationError, // 403, Header X-BM-KEY is forbidden to request it '30013': RateLimitExceeded, // 429, Request too many requests '30014': ExchangeNotAvailable, // 503, Service unavailable // funding account errors '60000': BadRequest, // 400, Invalid request (maybe the body is empty, or the int parameter passes string data) '60001': BadRequest, // 400, Asset account type does not exist '60002': BadRequest, // 400, currency does not exist '60003': ExchangeError, // 400, Currency has been closed recharge channel, if there is any problem, please consult customer service '60004': ExchangeError, // 400, Currency has been closed withdraw channel, if there is any problem, please consult customer service '60005': ExchangeError, // 400, Minimum amount is %s '60006': ExchangeError, // 400, Maximum withdraw precision is %d '60007': InvalidAddress, // 400, Only withdrawals from added addresses are allowed '60008': InsufficientFunds, // 400, Balance not enough '60009': ExchangeError, // 400, Beyond the limit '60010': ExchangeError, // 400, Withdraw id or deposit id not found '60011': InvalidAddress, // 400, Address is not valid '60012': ExchangeError, // 400, This action is not supported in this currency(If IOTA, HLX recharge and withdraw calls are prohibited) '60020': PermissionDenied, // 403, Your account is not allowed to recharge '60021': PermissionDenied, // 403, Your account is not allowed to withdraw '60022': PermissionDenied, // 403, No withdrawals for 24 hours '60030': BadRequest, // 405, Method Not Allowed '60031': BadRequest, // 415, Unsupported Media Type '60050': ExchangeError, // 500, User account not found '60051': ExchangeError, // 500, Internal Server Error // spot errors '50000': BadRequest, // 400, Bad Request '50001': BadSymbol, // 400, Symbol not found '50002': BadRequest, // 400, From Or To format error '50003': BadRequest, // 400, Step format error '50004': BadRequest, // 400, Kline size over 500 '50005': OrderNotFound, // 400, Order Id not found '50006': InvalidOrder, // 400, Minimum size is %s '50007': InvalidOrder, // 400, Maximum size is %s '50008': InvalidOrder, // 400, Minimum price is %s '50009': InvalidOrder, // 400, Minimum count*price is %s '50010': InvalidOrder, // 400, RequestParam size is required '50011': InvalidOrder, // 400, RequestParam price is required '50012': InvalidOrder, // 400, RequestParam notional is required '50013': InvalidOrder, // 400, Maximum limit*offset is %d '50014': BadRequest, // 400, RequestParam limit is required '50015': BadRequest, // 400, Minimum limit is 1 '50016': BadRequest, // 400, Maximum limit is %d '50017': BadRequest, // 400, RequestParam offset is required '50018': BadRequest, // 400, Minimum offset is 1 '50019': BadRequest, // 400, Maximum price is %s // '50019': ExchangeError, // 400, Invalid status. validate status is [1=Failed, 2=Success, 3=Frozen Failed, 4=Frozen Success, 5=Partially Filled, 6=Fully Fulled, 7=Canceling, 8=Canceled '50020': InsufficientFunds, // 400, Balance not enough '50021': BadRequest, // 400, Invalid %s '50022': ExchangeNotAvailable, // 400, Service unavailable '50023': BadSymbol, // 400, This Symbol can't place order by api '53000': AccountSuspended, // 403, Your account is frozen due to security policies. Please contact customer service '57001': BadRequest, // 405, Method Not Allowed '58001': BadRequest, // 415, Unsupported Media Type '59001': ExchangeError, // 500, User account not found '59002': ExchangeError, // 500, Internal Server Error // contract errors '40001': ExchangeError, // 400, Cloud account not found '40002': ExchangeError, // 400, out_trade_no not found '40003': ExchangeError, // 400, out_trade_no already existed '40004': ExchangeError, // 400, Cloud account count limit '40005': ExchangeError, // 400, Transfer vol precision error '40006': PermissionDenied, // 400, Invalid ip error '40007': BadRequest, // 400, Parse parameter error '40008': InvalidNonce, // 400, Check nonce error '40009': BadRequest, // 400, Check ver error '40010': BadRequest, // 400, Not found func error '40011': BadRequest, // 400, Invalid request '40012': ExchangeError, // 500, System error '40013': ExchangeError, // 400, Access too often" CLIENT_TIME_INVALID, "Please check your system time. '40014': BadSymbol, // 400, This contract is offline '40015': BadSymbol, // 400, This contract's exchange has been paused '40016': InvalidOrder, // 400, This order would trigger user position liquidate '40017': InvalidOrder, // 400, It is not possible to open and close simultaneously in the same position '40018': InvalidOrder, // 400, Your position is closed '40019': ExchangeError, // 400, Your position is in liquidation delegating '40020': InvalidOrder, // 400, Your position volume is not enough '40021': ExchangeError, // 400, The position is not exsit '40022': ExchangeError, // 400, The position is not isolated '40023': ExchangeError, // 400, The position would liquidate when sub margin '40024': ExchangeError, // 400, The position would be warnning of liquidation when sub margin '40025': ExchangeError, // 400, The position’s margin shouldn’t be lower than the base limit '40026': ExchangeError, // 400, You cross margin position is in liquidation delegating '40027': InsufficientFunds, // 400, You contract account available balance not enough '40028': PermissionDenied, // 400, Your plan order's count is more than system maximum limit. '40029': InvalidOrder, // 400, The order's leverage is too large. '40030': InvalidOrder, // 400, The order's leverage is too small. '40031': InvalidOrder, // 400, The deviation between current price and trigger price is too large. '40032': InvalidOrder, // 400, The plan order's life cycle is too long. '40033': InvalidOrder, // 400, The plan order's life cycle is too short. '40034': BadSymbol, // 400, This contract is not found }, 'broad': {}, }, 'commonCurrencies': { 'COT': 'Community Coin', 'CPC': 'CPCoin', 'ONE': 'Menlo One', 'PLA': 'Plair', }, 'options': { 'defaultType': 'spot', // 'spot', 'swap' 'fetchBalance': { 'type': 'spot', // 'spot', 'swap', 'contract', 'account' }, 'createMarketBuyOrderRequiresPrice': true, }, }); } async fetchTime (params = {}) { const response = await this.publicSystemGetTime (params); // // { // "message":"OK", // "code":1000, // "trace":"c4e5e5b7-fe9f-4191-89f7-53f6c5bf9030", // "data":{ // "server_time":1599843709578 // } // } // const data = this.safeValue (response, 'data', {}); return this.safeInteger (data, 'server_time'); } async fetchStatus (params = {}) { const options = this.safeValue (this.options, 'fetchBalance', {}); const defaultType = this.safeString (this.options, 'defaultType'); let type = this.safeString (options, 'type', defaultType); type = this.safeString (params, 'type', type); params = this.omit (params, 'type'); const response = await this.publicSystemGetService (params); // // { // "code": 1000, // "trace":"886fb6ae-456b-4654-b4e0-d681ac05cea1", // "message": "OK", // "data": { // "serivce":[ // { // "title": "Spot API Stop", // "service_type": "spot", // "status": "2", // "start_time": 1527777538000, // "end_time": 1527777538000 // }, // { // "title": "Contract API Stop", // "service_type": "contract", // "status": "2", // "start_time": 1527777538000, // "end_time": 1527777538000 // } // ] // } // } // const data = this.safeValue (response, 'data', {}); const services = this.safeValue (data, 'service', []); const servicesByType = this.indexBy (services, 'service_type'); if ((type === 'swap') || (type === 'future')) { type = 'contract'; } const service = this.safeValue (servicesByType, type); let status = undefined; let eta = undefined; if (service !== undefined) { const statusCode = this.safeInteger (service, 'status'); if (statusCode === 2) { status = 'ok'; } else { status = 'maintenance'; eta = this.safeInteger (service, 'end_time'); } } this.status = this.extend (this.status, { 'status': status, 'updated': this.milliseconds (), 'eta': eta, }); return this.status; } async fetchSpotMarkets (params = {}) { const response = await this.publicSpotGetSymbolsDetails (params); // // { // "message":"OK", // "code":1000, // "trace":"a67c9146-086d-4d3f-9897-5636a9bb26e1", // "data":{ // "symbols":[ // { // "symbol":"PRQ_BTC", // "symbol_id":1232, // "base_currency":"PRQ", // "quote_currency":"BTC", // "quote_increment":"1.0000000000", // "base_min_size":"1.0000000000", // "base_max_size":"10000000.0000000000", // "price_min_precision":8, // "price_max_precision":10, // "expiration":"NA", // "min_buy_amount":"0.0001000000", // "min_sell_amount":"0.0001000000" // }, // ] // } // } // const data = this.safeValue (response, 'data', {}); const symbols = this.safeValue (data, 'symbols', []); const result = []; for (let i = 0; i < symbols.length; i++) { const market = symbols[i]; const id = this.safeString (market, 'symbol'); const numericId = this.safeInteger (market, 'symbol_id'); const baseId = this.safeString (market, 'base_currency'); const quoteId = this.safeString (market, 'quote_currency'); const base = this.safeCurrencyCode (baseId); const quote = this.safeCurrencyCode (quoteId); const symbol = base + '/' + quote; // // https://github.com/bitmartexchange/bitmart-official-api-docs/blob/master/rest/public/symbols_details.md#response-details // from the above API doc: // quote_increment Minimum order price as well as the price increment // price_min_precision Minimum price precision (digit) used to query price and kline // price_max_precision Maximum price precision (digit) used to query price and kline // // the docs are wrong: https://github.com/ccxt/ccxt/issues/5612 // const pricePrecision = this.safeInteger (market, 'price_max_precision'); const precision = { 'amount': this.safeNumber (market, 'base_min_size'), 'price': parseFloat (this.decimalToPrecision (Math.pow (10, -pricePrecision), ROUND, 10)), }; const minBuyCost = this.safeNumber (market, 'min_buy_amount'); const minSellCost = this.safeNumber (market, 'min_sell_amount'); const minCost = Math.max (minBuyCost, minSellCost); const limits = { 'amount': { 'min': this.safeNumber (market, 'base_min_size'), 'max': this.safeNumber (market, 'base_max_size'), }, 'price': { 'min': undefined, 'max': undefined, }, 'cost': { 'min': minCost, 'max': undefined, }, }; result.push ({ 'id': id, 'numericId': numericId, 'symbol': symbol, 'base': base, 'quote': quote, 'baseId': baseId, 'quoteId': quoteId, 'type': 'spot', 'spot': true, 'future': false, 'swap': false, 'precision': precision, 'limits': limits, 'info': market, 'active': undefined, }); } return result; } async fetchContractMarkets (params = {}) { const response = await this.publicContractGetContracts (params); // // { // "errno":"OK", // "message":"OK", // "code":1000, // "trace":"7fcedfb5-a660-4780-8a7a-b36a9e2159f7", // "data":{ // "contracts":[ // { // "contract":{ // "contract_id":1, // "index_id":1, // "name":"BTCUSDT", // "display_name":"BTCUSDT永续合约", // "display_name_en":"BTCUSDT_SWAP", // "contract_type":1, // "base_coin":"BTC", // "quote_coin":"USDT", // "price_coin":"BTC", // "exchange":"*", // "contract_size":"0.0001", // "begin_at":"2018-08-17T04:00:00Z", // "delive_at":"2020-08-15T12:00:00Z", // "delivery_cycle":28800, // "min_leverage":"1", // "max_leverage":"100", // "price_unit":"0.1", // "vol_unit":"1", // "value_unit":"0.0001", // "min_vol":"1", // "max_vol":"300000", // "liquidation_warn_ratio":"0.85", // "fast_liquidation_ratio":"0.8", // "settgle_type":1, // "open_type":3, // "compensate_type":1, // "status":3, // "block":1, // "rank":1, // "created_at":"2018-07-12T19:16:57Z", // "depth_bord":"1.001", // "base_coin_zh":"比特币", // "base_coin_en":"Bitcoin", // "max_rate":"0.00375", // "min_rate":"-0.00375" // }, // "risk_limit":{"contract_id":1,"base_limit":"1000000","step":"500000","maintenance_margin":"0.005","initial_margin":"0.01"}, // "fee_config":{"contract_id":1,"maker_fee":"-0.0003","taker_fee":"0.001","settlement_fee":"0","created_at":"2018-07-12T20:47:22Z"}, // "plan_order_config":{"contract_id":0,"min_scope":"0.001","max_scope":"2","max_count":10,"min_life_cycle":24,"max_life_cycle":168} // }, // ] // } // } // const data = this.safeValue (response, 'data', {}); const contracts = this.safeValue (data, 'contracts', []); const result = []; for (let i = 0; i < contracts.length; i++) { const market = contracts[i]; const contract = this.safeValue (market, 'contract', {}); const id = this.safeString (contract, 'contract_id'); const numericId = this.safeInteger (contract, 'contract_id'); const baseId = this.safeString (contract, 'base_coin'); const quoteId = this.safeString (contract, 'quote_coin'); const base = this.safeCurrencyCode (baseId); const quote = this.safeCurrencyCode (quoteId); const symbol = this.safeString (contract, 'name'); // // https://github.com/bitmartexchange/bitmart-official-api-docs/blob/master/rest/public/symbols_details.md#response-details // from the above API doc: // quote_increment Minimum order price as well as the price increment // price_min_precision Minimum price precision (digit) used to query price and kline // price_max_precision Maximum price precision (digit) used to query price and kline // // the docs are wrong: https://github.com/ccxt/ccxt/issues/5612 // const amountPrecision = this.safeNumber (contract, 'vol_unit'); const pricePrecision = this.safeNumber (contract, 'price_unit'); const precision = { 'amount': amountPrecision, 'price': pricePrecision, }; const limits = { 'amount': { 'min': this.safeNumber (contract, 'min_vol'), 'max': this.safeNumber (contract, 'max_vol'), }, 'price': { 'min': undefined, 'max': undefined, }, 'cost': { 'min': undefined, 'max': undefined, }, }; const contractType = this.safeValue (contract, 'contract_type'); let future = false; let swap = false; let type = 'contract'; if (contractType === 1) { type = 'swap'; swap = true; } else if (contractType === 2) { type = 'future'; future = true; } const feeConfig = this.safeValue (market, 'fee_config', {}); const maker = this.safeNumber (feeConfig, 'maker_fee'); const taker = this.safeNumber (feeConfig, 'taker_fee'); result.push ({ 'id': id, 'numericId': numericId, 'symbol': symbol, 'base': base, 'quote': quote, 'baseId': baseId, 'quoteId': quoteId, 'maker': maker, 'taker': taker, 'type': type, 'spot': false, 'future': future, 'swap': swap, 'precision': precision, 'limits': limits, 'info': market, 'active': undefined, }); } return result; } async fetchMarkets (params = {}) { const spotMarkets = await this.fetchSpotMarkets (); const contractMarkets = await this.fetchContractMarkets (); const allMarkets = this.arrayConcat (spotMarkets, contractMarkets); return allMarkets; } parseTicker (ticker, market = undefined) { // // spot // // { // "symbol":"ETH_BTC", // "last_price":"0.036037", // "quote_volume_24h":"4380.6660000000", // "base_volume_24h":"159.3582006712", // "high_24h":"0.036972", // "low_24h":"0.035524", // "open_24h":"0.036561", // "close_24h":"0.036037", // "best_ask":"0.036077", // "best_ask_size":"9.9500", // "best_bid":"0.035983", // "best_bid_size":"4.2792", // "fluctuation":"-0.0143", // "url":"https://www.bitmart.com/trade?symbol=ETH_BTC" // } // // contract // // { // "last_price":"422.2", // "open":"430.5", // "close":"422.2", // "low":"421.9", // "high":"436.9", // "avg_price":"430.8569900089815372072", // "volume":"2720", // "total_volume":"18912248", // "timestamp":1597631495, // "rise_fall_rate":"-0.0192799070847851336", // "rise_fall_value":"-8.3", // "contract_id":2, // "position_size":"3067404", // "volume_day":"9557384", // "amount24":"80995537.0919999999999974153", // "base_coin_volume":"189122.48", // "quote_coin_volume":"81484742.475833810590837937856", // "pps":"1274350547", // "index_price":"422.135", // "fair_price":"422.147253318507", // "depth_price":{"bid_price":"421.9","ask_price":"422","mid_price":"421.95"}, // "fair_basis":"0.000029027013", // "fair_value":"0.012253318507", // "rate":{"quote_rate":"0.0006","base_rate":"0.0003","interest_rate":"0.000099999999"}, // "premium_index":"0.000045851604", // "funding_rate":"0.000158", // "next_funding_rate":"0.000099999999", // "next_funding_at":"2020-08-17T04:00:00Z" // } // const timestamp = this.safeTimestamp (ticker, 'timestamp', this.milliseconds ()); const marketId = this.safeString2 (ticker, 'symbol', 'contract_id'); const symbol = this.safeSymbol (marketId, market, '_'); const last = this.safeNumber2 (ticker, 'close_24h', 'last_price'); let percentage = this.safeNumber (ticker, 'fluctuation', 'rise_fall_rate'); if (percentage !== undefined) { percentage *= 100; } const baseVolume = this.safeNumber2 (ticker, 'base_volume_24h', 'base_coin_volume'); const quoteVolume = this.safeNumber2 (ticker, 'quote_volume_24h', 'quote_coin_volume'); const vwap = this.vwap (baseVolume, quoteVolume); const open = this.safeNumber2 (ticker, 'open_24h', 'open'); let average = undefined; if ((last !== undefined) && (open !== undefined)) { average = this.sum (last, open) / 2; } average = this.safeNumber (ticker, 'avg_price', average); const price = this.safeValue (ticker, 'depth_price', ticker); return { 'symbol': symbol, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'high': this.safeNumber2 (ticker, 'high', 'high_24h'), 'low': this.safeNumber2 (ticker, 'low', 'low_24h'), 'bid': this.safeNumber (price, 'best_bid', 'bid_price'), 'bidVolume': this.safeNumber (ticker, 'best_bid_size'), 'ask': this.safeNumber (price, 'best_ask', 'ask_price'), 'askVolume': this.safeNumber (ticker, 'best_ask_size'), 'vwap': vwap, 'open': this.safeNumber (ticker, 'open_24h'), 'close': last, 'last': last, 'previousClose': undefined, 'change': undefined, 'percentage': percentage, 'average': average, 'baseVolume': baseVolume, 'quoteVolume': quoteVolume, 'info': ticker, }; } async fetchTicker (symbol, params = {}) { await this.loadMarkets (); const market = this.market (symbol); const request = {}; let method = undefined; if (market['swap'] || market['future']) { method = 'publicContractGetTickers'; request['contractID'] = market['id']; } else if (market['spot']) { method = 'publicSpotGetTicker'; request['symbol'] = market['id']; } const response = await this[method] (this.extend (request, params)); // // spot // // { // "message":"OK", // "code":1000, // "trace":"6aa5b923-2f57-46e3-876d-feca190e0b82", // "data":{ // "tickers":[ // { // "symbol":"ETH_BTC", // "last_price":"0.036037", // "quote_volume_24h":"4380.6660000000", // "base_volume_24h":"159.3582006712", // "high_24h":"0.036972", // "low_24h":"0.035524", // "open_24h":"0.036561", // "close_24h":"0.036037", // "best_ask":"0.036077", // "best_ask_size":"9.9500", // "best_bid":"0.035983", // "best_bid_size":"4.2792", // "fluctuation":"-0.0143", // "url":"https://www.bitmart.com/trade?symbol=ETH_BTC" // } // ] // } // } // // contract // // { // "errno":"OK", // "message":"OK", // "code":1000, // "trace":"d09b57c4-d99b-4a13-91a8-2df98f889909", // "data":{ // "tickers":[ // { // "last_price":"422.2", // "open":"430.5", // "close":"422.2", // "low":"421.9", // "high":"436.9", // "avg_price":"430.8569900089815372072", // "volume":"2720", // "total_volume":"18912248", // "timestamp":1597631495, // "rise_fall_rate":"-0.0192799070847851336", // "rise_fall_value":"-8.3", // "contract_id":2, // "position_size":"3067404", // "volume_day":"9557384", // "amount24":"80995537.0919999999999974153", // "base_coin_volume":"189122.48", // "quote_coin_volume":"81484742.475833810590837937856", // "pps":"1274350547", // "index_price":"422.135", // "fair_price":"422.147253318507", // "depth_price":{"bid_price":"421.9","ask_price":"422","mid_price":"421.95"}, // "fair_basis":"0.000029027013", // "fair_value":"0.012253318507", // "rate":{"quote_rate":"0.0006","base_rate":"0.0003","interest_rate":"0.000099999999"}, // "premium_index":"0.000045851604", // "funding_rate":"0.000158", // "next_funding_rate":"0.000099999999", // "next_funding_at":"2020-08-17T04:00:00Z" // } // ] // } // } // const data = this.safeValue (response, 'data', {}); const tickers = this.safeValue (data, 'tickers', []); const tickersById = this.indexBy (tickers, 'symbol'); const ticker = this.safeValue (tickersById, market['id']); return this.parseTicker (ticker, market); } async fetchTickers (symbols = undefined, params = {}) { await this.loadMarkets (); const defaultType = this.safeString (this.options, 'defaultType', 'spot'); const type = this.safeString (params, 'type', defaultType); params = this.omit (params, 'type'); let method = undefined; if ((type === 'swap') || (type === 'future')) { method = 'publicContractGetTickers'; } else if (type === 'spot') { method = 'publicSpotGetTicker'; } const response = await this[method] (params); const data = this.safeValue (response, 'data', {}); const tickers = this.safeValue (data, 'tickers', []); const result = {}; for (let i = 0; i < tickers.length; i++) { const ticker = this.parseTicker (tickers[i]); const symbol = ticker['symbol']; result[symbol] = ticker; } return this.filterByArray (result, 'symbol', symbols); } async fetchCurrencies (params = {}) { const response = await this.publicAccountGetCurrencies (params); // // { // "message":"OK", // "code":1000, // "trace":"8c768b3c-025f-413f-bec5-6d6411d46883", // "data":{ // "currencies":[ // {"currency":"MATIC","name":"Matic Network","withdraw_enabled":true,"deposit_enabled":true}, // {"currency":"KTN","name":"Kasoutuuka News","withdraw_enabled":true,"deposit_enabled":false}, // {"currency":"BRT","name":"Berith","withdraw_enabled":true,"deposit_enabled":true}, // ] // } // } // const data = this.safeValue (response, 'data', {}); const currencies = this.safeValue (data, 'currencies', []); const result = {}; for (let i = 0; i < currencies.length; i++) { const currency = currencies[i]; const id = this.safeString (currency, 'currency'); const code = this.safeCurrencyCode (id); const name = this.safeString (currency, 'name'); const withdrawEnabled = this.safeValue (currency, 'withdraw_enabled'); const depositEnabled = this.safeValue (currency, 'deposit_enabled'); const active = withdrawEnabled && depositEnabled; result[code] = { 'id': id, 'code': code, 'name': name, 'info': currency, // the original payload 'active': active, 'fee': undefined, 'precision': undefined, 'limits': { 'amount': { 'min': undefined, 'max': undefined }, 'withdraw': { 'min': undefined, 'max': undefined }, }, }; } return result; } async fetchOrderBook (symbol, limit = undefined, params = {}) { await this.loadMarkets (); const market = this.market (symbol); const request = {}; let method = undefined; if (market['spot']) { method = 'publicSpotGetSymbolsBook'; request['symbol'] = market['id']; // request['precision'] = 4; // optional price precision / depth level whose range is defined in symbol details } else if (market['swap'] || market['future']) { method = 'publicContractGetDepth'; request['contractID'] = market['id']; if (limit !== undefined) { request['count'] = limit; // returns all records if size is omitted } } const response = await this[method] (this.extend (request, params)); // // spot // // { // "message":"OK", // "code":1000, // "trace":"8254f8fc-431d-404f-ad9a-e716339f66c7", // "data":{ // "buys":[ // {"amount":"4.7091","total":"4.71","price":"0.034047","count":"1"}, // {"amount":"5.7439","total":"10.45","price":"0.034039","count":"1"}, // {"amount":"2.5249","total":"12.98","price":"0.032937","count":"1"}, // ], // "sells":[ // {"amount":"41.4365","total":"41.44","price":"0.034174","count":"1"}, // {"amount":"4.2317","total":"45.67","price":"0.034183","count":"1"}, // {"amount":"0.3000","total":"45.97","price":"0.034240","count":"1"}, // ] // } // } // // contract // // { // "errno":"OK", // "message":"OK", // "code":1000, // "trace":"c330dfca-ca5b-4f15-b350-9fef3f049b4f", // "data":{ // "sells":[ // {"price":"347.6","vol":"6678"}, // {"price":"347.7","vol":"3452"}, // {"price":"347.8","vol":"6331"}, // ], // "buys":[ // {"price":"347.5","vol":"6222"}, // {"price":"347.4","vol":"20979"}, // {"price":"347.3","vol":"15179"}, // ] // } // } // const data = this.safeValue (response, 'data', {}); if (market['spot']) { return this.parseOrderBook (data, symbol, undefined, 'buys', 'sells', 'price', 'amount'); } else if (market['swap'] || market['future']) { return this.parseOrderBook (data, symbol, undefined, 'buys', 'sells', 'price', 'vol'); } } parseTrade (trade, market = undefined) { // // public fetchTrades spot // // { // "amount":"0.005703", // "order_time":1599652045394, // "price":"0.034029", // "count":"0.1676", // "type":"sell" // } // // public fetchTrades contract, private fetchMyTrades contract // // { // "order_id":109159616160, // "trade_id":109159616197, // "contract_id":2, // "deal_price":"347.6", // "deal_vol":"5623", // "make_fee":"-5.8636644", // "take_fee":"9.772774", // "created_at":"2020-09-09T11:49:50.749170536Z", // "way":1, // "fluctuation":"0" // } // // private fetchMyTrades spot // // { // "detail_id":256348632, // "order_id":2147484350, // "symbol":"BTC_USDT", // "create_time":1590462303000, // "side":"buy", // "fees":"0.00001350", // "fee_coin_name":"BTC", // "notional":"88.00000000", // "price_avg":"8800.00", // "size":"0.01000", // "exec_type":"M" // } // const id = this.safeString2 (trade, 'trade_id', 'detail_id'); let timestamp = this.safeInteger2 (trade, 'order_time', 'create_time'); if (timestamp === undefined) { timestamp = this.parse8601 (this.safeString (trade, 'created_at')); } const type = undefined; const way = this.safeInteger (trade, 'way'); let side = this.safeStringLower2 (trade, 'type', 'side'); if ((side === undefined) && (way !== undefined)) { if (way < 5) { side = 'buy'; } else { side = 'sell'; } } let takerOrMaker = undefined; const execType = this.safeString (trade, 'exec_type'); if (execType !== undefined) { takerOrMaker = (execType === 'M') ? 'maker' : 'taker'; } let price = this.safeNumber2 (trade, 'price', 'deal_price'); price = this.safeNumber (trade, 'price_avg', price); let amount = this.safeNumber2 (trade, 'amount', 'deal_vol'); amount = this.safeNumber (trade, 'size', amount); let cost = this.safeNumber2 (trade, 'count', 'notional'); if ((cost === undefined) && (price !== undefined) && (amount !== undefined)) { cost = amount * price; } const orderId = this.safeInteger (trade, 'order_id'); const marketId = this.safeString2 (trade, 'contract_id', 'symbol'); const symbol = this.safeSymbol (marketId, market, '_'); const feeCost = this.safeNumber (trade, 'fees'); let fee = undefined; if (feeCost !== undefined) { const feeCurrencyId = this.safeString (trade, 'fee_coin_name'); let feeCurrencyCode = this.safeCurrencyCode (feeCurrencyId); if ((feeCurrencyCode === undefined) && (market !== undefined)) { feeCurrencyCode = (side === 'buy') ? market['base'] : market['quote']; } fee = { 'cost': feeCost, 'currency': feeCurrencyCode, }; } return { 'info': trade, 'id': id, 'order': orderId, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'symbol': symbol, 'type': type, 'side': side, 'price': price, 'amount': amount, 'cost': cost, 'takerOrMaker': takerOrMaker, 'fee': fee, }; } async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) { await this.loadMarkets (); const market = this.market (symbol); const request = { 'symbol': market['id'], }; let method = undefined; if (market['spot']) { request['symbol'] = market['id']; method = 'publicSpotGetSymbolsTrades'; } else if (market['swap'] || market['future']) { method = 'publicContractGetTrades'; request['contractID'] = market['id']; } const response = await this[method] (this.extend (request, params)); // // spot // // { // "message":"OK", // "code":1000, // "trace":"222d74c0-8f6d-49d9-8e1b-98118c50eeba", // "data":{ // "trades":[ // { // "amount":"0.005703", // "order_time":15