UNPKG

sfccxt

Version:

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

1,173 lines (1,157 loc) 153 kB
'use strict'; // --------------------------------------------------------------------------- const Exchange = require ('./base/Exchange'); const { AccountNotEnabled, InvalidAddress, ExchangeError, BadRequest, AuthenticationError, RateLimitExceeded, BadSymbol, InvalidOrder, InsufficientFunds, ArgumentsRequired, OrderNotFound, PermissionDenied, NotSupported } = require ('./base/errors'); const { TICK_SIZE } = require ('./base/functions/number'); const Precise = require ('./base/Precise'); // --------------------------------------------------------------------------- module.exports = class mexc extends Exchange { describe () { return this.deepExtend (super.describe (), { 'id': 'mexc', 'name': 'MEXC Global', 'countries': [ 'SC' ], // Seychelles 'rateLimit': 50, // default rate limit is 20 times per second 'version': 'v2', 'certified': true, 'pro': true, 'has': { 'CORS': undefined, 'spot': true, 'margin': undefined, // has but unimplemented 'swap': true, 'future': false, 'option': false, 'addMargin': true, 'cancelAllOrders': true, 'cancelOrder': true, 'createMarketOrder': false, 'createOrder': true, 'createReduceOnlyOrder': false, 'createStopLimitOrder': true, 'createStopMarketOrder': false, 'createStopOrder': true, 'fetchBalance': true, 'fetchCanceledOrders': true, 'fetchClosedOrders': true, 'fetchCurrencies': true, 'fetchDepositAddress': true, 'fetchDepositAddressesByNetwork': true, 'fetchDeposits': true, 'fetchFundingHistory': true, 'fetchFundingRate': true, 'fetchFundingRateHistory': true, 'fetchFundingRates': false, 'fetchIndexOHLCV': true, 'fetchLeverage': undefined, 'fetchLeverageTiers': true, 'fetchMarginMode': false, 'fetchMarketLeverageTiers': 'emulated', 'fetchMarkets': true, 'fetchMarkOHLCV': true, 'fetchMyTrades': true, 'fetchOHLCV': true, 'fetchOpenInterestHistory': false, 'fetchOpenOrders': true, 'fetchOrder': true, 'fetchOrderBook': true, 'fetchOrderTrades': true, 'fetchPosition': true, 'fetchPositionMode': true, 'fetchPositions': true, 'fetchPositionsRisk': false, 'fetchPremiumIndexOHLCV': true, 'fetchStatus': true, 'fetchTicker': true, 'fetchTickers': true, 'fetchTime': true, 'fetchTrades': true, 'fetchTradingFee': false, 'fetchTradingFees': true, 'fetchTransfer': true, 'fetchTransfers': true, 'fetchWithdrawals': true, 'reduceMargin': true, 'setLeverage': true, 'setMarginMode': false, 'setPositionMode': true, 'transfer': true, 'withdraw': true, }, 'timeframes': { '1m': '1m', '5m': '5m', '15m': '15m', '30m': '30m', '1h': '1h', '1d': '1d', '1w': '1w', '1M': '1M', }, 'urls': { 'logo': 'https://user-images.githubusercontent.com/1294454/137283979-8b2a818d-8633-461b-bfca-de89e8c446b2.jpg', 'api': { 'spot': { 'public': 'https://www.mexc.com/open/api/v2', 'private': 'https://www.mexc.com/open/api/v2', }, 'contract': { 'public': 'https://contract.mexc.com/api/v1/contract', 'private': 'https://contract.mexc.com/api/v1/private', }, }, 'www': 'https://www.mexc.com/', 'doc': [ 'https://mxcdevelop.github.io/APIDoc/', ], 'fees': [ 'https://www.mexc.com/fee', ], 'referral': 'https://m.mexc.com/auth/signup?inviteCode=1FQ1G', }, 'api': { 'contract': { 'public': { 'get': { 'ping': 2, 'detail': 2, 'support_currencies': 2, 'depth/{symbol}': 2, 'depth_commits/{symbol}/{limit}': 2, 'index_price/{symbol}': 2, 'fair_price/{symbol}': 2, 'funding_rate/{symbol}': 2, 'kline/{symbol}': 2, 'kline/index_price/{symbol}': 2, 'kline/fair_price/{symbol}': 2, 'deals/{symbol}': 2, 'ticker': 2, 'risk_reverse': 2, 'risk_reverse/history': 2, 'funding_rate/history': 2, }, }, 'private': { 'get': { 'account/assets': 2, 'account/asset/{currency}': 2, 'account/transfer_record': 2, 'position/list/history_positions': 2, 'position/open_positions': 2, 'position/funding_records': 2, 'position/position_mode': 2, 'order/list/open_orders/{symbol}': 2, 'order/list/history_orders': 2, 'order/external/{symbol}/{external_oid}': 2, 'order/get/{order_id}': 2, 'order/batch_query': 8, 'order/deal_details/{order_id}': 2, 'order/list/order_deals': 2, 'planorder/list/orders': 2, 'stoporder/list/orders': 2, 'stoporder/order_details/{stop_order_id}': 2, 'account/risk_limit': 2, 'account/tiered_fee_rate': 2, }, 'post': { 'position/change_margin': 2, 'position/change_leverage': 2, 'position/change_position_mode': 2, 'order/submit': 2, 'order/submit_batch': 40, 'order/cancel': 2, 'order/cancel_with_external': 2, 'order/cancel_all': 2, 'account/change_risk_level': 2, 'planorder/place': 2, 'planorder/cancel': 2, 'planorder/cancel_all': 2, 'stoporder/cancel': 2, 'stoporder/cancel_all': 2, 'stoporder/change_price': 2, 'stoporder/change_plan_price': 2, }, }, }, 'spot': { 'public': { 'get': { 'market/symbols': 1, 'market/coin/list': 2, 'common/timestamp': 1, 'common/ping': 1, 'market/ticker': 1, 'market/depth': 1, 'market/deals': 1, 'market/kline': 1, 'market/api_default_symbols': 2, }, }, 'private': { 'get': { 'account/info': 1, 'order/open_orders': 1, 'order/list': 1, 'order/query': 1, 'order/deals': 1, 'order/deal_detail': 1, 'asset/deposit/address/list': 2, 'asset/deposit/list': 2, 'asset/address/list': 2, 'asset/withdraw/list': 2, 'asset/internal/transfer/record': 10, 'account/balance': 10, 'asset/internal/transfer/info': 10, 'market/api_symbols': 2, }, 'post': { 'order/place': 1, 'order/place_batch': 1, 'asset/withdraw': 2, 'asset/internal/transfer': 10, }, 'delete': { 'order/cancel': 1, 'order/cancel_by_symbol': 1, 'asset/withdraw': 2, }, }, }, }, 'precisionMode': TICK_SIZE, 'fees': { 'trading': { 'tierBased': false, 'percentage': true, 'maker': this.parseNumber ('0.002'), // maker / taker 'taker': this.parseNumber ('0.002'), }, }, 'options': { 'timeframes': { 'spot': { '1m': '1m', '5m': '5m', '15m': '15m', '30m': '30m', '1h': '1h', '1d': '1d', '1M': '1M', }, 'contract': { '1m': 'Min1', '5m': 'Min5', '15m': 'Min15', '30m': 'Min30', '1h': 'Min60', '4h': 'Hour4', '8h': 'Hour8', '1d': 'Day1', '1w': 'Week1', '1M': 'Month1', }, }, 'defaultType': 'spot', // spot, swap 'networks': { 'TRX': 'TRC20', 'ETH': 'ERC20', 'BEP20': 'BEP20(BSC)', 'BSC': 'BEP20(BSC)', }, 'accountsByType': { 'spot': 'MAIN', 'swap': 'CONTRACT', }, 'transfer': { 'accountsById': { 'MAIN': 'spot', 'CONTRACT': 'swap', }, 'status': { 'SUCCESS': 'ok', 'FAILED': 'failed', 'WAIT': 'pending', }, }, 'fetchOrdersByState': { 'method': 'spotPrivateGetOrderList', // contractPrivateGetPlanorderListOrders }, 'cancelOrder': { 'method': 'spotPrivateDeleteOrderCancel', // contractPrivatePostOrderCancel contractPrivatePostPlanorderCancel }, 'broker': 'CCXT', }, 'commonCurrencies': { 'BEYONDPROTOCOL': 'BEYOND', 'BIFI': 'BIFIF', 'BYN': 'BeyondFi', 'COFI': 'COFIX', // conflict with CoinFi 'DFI': 'DfiStarter', 'DFT': 'dFuture', 'DRK': 'DRK', 'EGC': 'Egoras Credit', 'FLUX1': 'FLUX', // switched places 'FLUX': 'FLUX1', // switched places 'FREE': 'FreeRossDAO', // conflict with FREE Coin 'GMT': 'GMT Token', 'HERO': 'Step Hero', // conflict with Metahero 'MIMO': 'Mimosa', 'PROS': 'Pros.Finance', // conflict with Prosper 'SIN': 'Sin City Token', 'SOUL': 'Soul Swap', 'STEPN': 'GMT', }, 'exceptions': { 'exact': { '400': BadRequest, // Invalid parameter '401': AuthenticationError, // Invalid signature, fail to pass the validation '402': AuthenticationError, // {"success":false,"code":402,"message":"API key expired!"} '403': PermissionDenied, // {"msg":"no permission to access the endpoint","code":403} '429': RateLimitExceeded, // too many requests, rate limit rule is violated '703': PermissionDenied, // Require trade read permission! '1000': AccountNotEnabled, // {"success":false,"code":1000,"message":"Please open contract account first!"} '1002': InvalidOrder, // {"success":false,"code":1002,"message":"Contract not allow place order!"} '10072': AuthenticationError, // Invalid access key '10073': AuthenticationError, // Invalid request time '10075': PermissionDenied, // {"msg":"IP [xxx.xxx.xxx.xxx] not in the ip white list","code":10075} '10101': InsufficientFunds, // {"code":10101,"msg":"Insufficient balance"} '10216': InvalidAddress, // {"code":10216,"msg":"No available deposit address"} '10232': BadSymbol, // {"code":10232,"msg":"The currency not exist"} '30000': BadSymbol, // Trading is suspended for the requested symbol '30001': InvalidOrder, // Current trading type (bid or ask) is not allowed '30002': InvalidOrder, // Invalid trading amount, smaller than the symbol minimum trading amount '30003': InvalidOrder, // Invalid trading amount, greater than the symbol maximum trading amount '30004': InsufficientFunds, // Insufficient balance '30005': InvalidOrder, // Oversell error '30010': InvalidOrder, // Price out of allowed range '30014': BadSymbol, // {"msg":"invalid symbol","code":30014} '30016': BadSymbol, // Market is closed '30019': InvalidOrder, // Orders count over limit for batch processing '30020': BadSymbol, // Restricted symbol, API access is not allowed for the time being '30021': BadSymbol, // Invalid symbol '33333': BadSymbol, // {"code":33333,"msg":"currency can not be null"} }, 'broad': { 'price and quantity must be positive': InvalidOrder, // {"msg":"price and quantity must be positive","code":400} }, }, }); } async fetchTime (params = {}) { /** * @method * @name mexc#fetchTime * @description fetches the current integer timestamp in milliseconds from the exchange server * @param {object} params extra parameters specific to the mexc api endpoint * @returns {int} the current integer timestamp in milliseconds from the exchange server */ const [ marketType, query ] = this.handleMarketTypeAndParams ('fetchTime', undefined, params); const method = this.getSupportedMapping (marketType, { 'spot': 'spotPublicGetCommonTimestamp', 'swap': 'contractPublicGetPing', }); const response = await this[method] (this.extend (query)); // // spot // // { // "code":200, // "data":1633375641837 // } // // contract // // { // "success":true, // "code":0, // "data":1634095541710 // } // return this.safeInteger (response, 'data'); } async fetchStatus (params = {}) { /** * @method * @name mexc#fetchStatus * @description the latest known information on the availability of the exchange API * @param {object} params extra parameters specific to the mexc api endpoint * @returns {object} a [status structure]{@link https://docs.ccxt.com/en/latest/manual.html#exchange-status-structure} */ const response = await this.spotPublicGetCommonPing (params); // // { "code":200 } // const code = this.safeInteger (response, 'code'); const status = (code === 200) ? 'ok' : 'maintenance'; return { 'status': status, 'updated': undefined, 'eta': undefined, 'url': undefined, 'info': response, }; } async fetchCurrencies (params = {}) { /** * @method * @name mexc#fetchCurrencies * @description fetches all available currencies on an exchange * @param {object} params extra parameters specific to the mexc api endpoint * @returns {object} an associative dictionary of currencies */ const response = await this.spotPublicGetMarketCoinList (params); // // { // "code":200, // "data":[ // { // "currency":"AGLD", // "coins":[ // { // "chain":"ERC20", // "precision":18, // "fee":8.09, // "is_withdraw_enabled":true, // "is_deposit_enabled":true, // "deposit_min_confirm":16, // "withdraw_limit_max":500000.0, // "withdraw_limit_min":14.0 // } // ], // "full_name":"Adventure Gold" // }, // ] // } // const data = this.safeValue (response, 'data', []); const result = {}; for (let i = 0; i < data.length; i++) { const currency = data[i]; const id = this.safeString (currency, 'currency'); const code = this.safeCurrencyCode (id); const name = this.safeString (currency, 'full_name'); let currencyActive = false; let minPrecision = undefined; let currencyFee = undefined; let currencyWithdrawMin = undefined; let currencyWithdrawMax = undefined; const networks = {}; const chains = this.safeValue (currency, 'coins', []); let depositEnabled = false; let withdrawEnabled = false; for (let j = 0; j < chains.length; j++) { const chain = chains[j]; const networkId = this.safeString (chain, 'chain'); const network = this.safeNetwork (networkId); const isDepositEnabled = this.safeValue (chain, 'is_deposit_enabled', false); const isWithdrawEnabled = this.safeValue (chain, 'is_withdraw_enabled', false); const active = (isDepositEnabled && isWithdrawEnabled); currencyActive = active || currencyActive; const withdrawMin = this.safeString (chain, 'withdraw_limit_min'); const withdrawMax = this.safeString (chain, 'withdraw_limit_max'); currencyWithdrawMin = (currencyWithdrawMin === undefined) ? withdrawMin : currencyWithdrawMin; currencyWithdrawMax = (currencyWithdrawMax === undefined) ? withdrawMax : currencyWithdrawMax; if (Precise.stringGt (currencyWithdrawMin, withdrawMin)) { currencyWithdrawMin = withdrawMin; } if (Precise.stringLt (currencyWithdrawMax, withdrawMax)) { currencyWithdrawMax = withdrawMax; } if (isDepositEnabled) { depositEnabled = true; } if (isWithdrawEnabled) { withdrawEnabled = true; } const precision = this.parsePrecision (this.safeString (chain, 'precision')); if (precision !== undefined) { minPrecision = (minPrecision === undefined) ? precision : Precise.stringMin (precision, minPrecision); } networks[network] = { 'info': chain, 'id': networkId, 'network': network, 'active': active, 'deposit': isDepositEnabled, 'withdraw': isWithdrawEnabled, 'fee': this.safeNumber (chain, 'fee'), 'precision': this.parseNumber (minPrecision), 'limits': { 'withdraw': { 'min': withdrawMin, 'max': withdrawMax, }, }, }; } const networkKeys = Object.keys (networks); const networkKeysLength = networkKeys.length; if ((networkKeysLength === 1) || ('NONE' in networks)) { const defaultNetwork = this.safeValue2 (networks, 'NONE', networkKeysLength - 1); if (defaultNetwork !== undefined) { currencyFee = defaultNetwork['fee']; } } result[code] = { 'id': id, 'code': code, 'info': currency, 'name': name, 'active': currencyActive, 'deposit': depositEnabled, 'withdraw': withdrawEnabled, 'fee': currencyFee, 'precision': this.parseNumber (minPrecision), 'limits': { 'amount': { 'min': undefined, 'max': undefined, }, 'withdraw': { 'min': currencyWithdrawMin, 'max': currencyWithdrawMax, }, }, 'networks': networks, }; } return result; } async fetchMarkets (params = {}) { /** * @method * @name mexc#fetchMarkets * @description retrieves data on all markets for mexc * @param {object} params extra parameters specific to the exchange api endpoint * @returns {[object]} an array of objects representing market data */ const defaultType = this.safeString2 (this.options, 'fetchMarkets', 'defaultType', 'spot'); const type = this.safeString (params, 'type', defaultType); const query = this.omit (params, 'type'); const spot = (type === 'spot'); const swap = (type === 'swap'); if (!spot && !swap) { throw new ExchangeError (this.id + " does not support '" + type + "' type, set exchange.options['defaultType'] to 'spot' or 'swap''"); // eslint-disable-line quotes } if (spot) { return await this.fetchSpotMarkets (query); } else if (swap) { return await this.fetchContractMarkets (query); } } async fetchContractMarkets (params = {}) { const response = await this.contractPublicGetDetail (params); // // { // "success":true, // "code":0, // "data":[ // { // "symbol":"BTC_USDT", // "displayName":"BTC_USDT永续", // "displayNameEn":"BTC_USDT SWAP", // "positionOpenType":3, // "baseCoin":"BTC", // "quoteCoin":"USDT", // "settleCoin":"USDT", // "contractSize":0.0001, // "minLeverage":1, // "maxLeverage":125, // "priceScale":2, // "volScale":0, // "amountScale":4, // "priceUnit":0.5, // "volUnit":1, // "minVol":1, // "maxVol":1000000, // "bidLimitPriceRate":0.1, // "askLimitPriceRate":0.1, // "takerFeeRate":0.0006, // "makerFeeRate":0.0002, // "maintenanceMarginRate":0.004, // "initialMarginRate":0.008, // "riskBaseVol":10000, // "riskIncrVol":200000, // "riskIncrMmr":0.004, // "riskIncrImr":0.004, // "riskLevelLimit":5, // "priceCoefficientVariation":0.1, // "indexOrigin":["BINANCE","GATEIO","HUOBI","MXC"], // "state":0, // 0 enabled, 1 delivery, 2 completed, 3 offline, 4 pause // "isNew":false, // "isHot":true, // "isHidden":false // }, // ] // } // const data = this.safeValue (response, 'data', []); const result = []; for (let i = 0; i < data.length; i++) { const market = data[i]; const id = this.safeString (market, 'symbol'); const baseId = this.safeString (market, 'baseCoin'); const quoteId = this.safeString (market, 'quoteCoin'); const settleId = this.safeString (market, 'settleCoin'); const base = this.safeCurrencyCode (baseId); const quote = this.safeCurrencyCode (quoteId); const settle = this.safeCurrencyCode (settleId); const state = this.safeString (market, 'state'); result.push ({ 'id': id, 'symbol': base + '/' + quote + ':' + settle, 'base': base, 'quote': quote, 'settle': settle, 'baseId': baseId, 'quoteId': quoteId, 'settleId': settleId, 'type': 'swap', 'spot': false, 'margin': false, 'swap': true, 'future': false, 'option': false, 'active': (state === '0'), 'contract': true, 'linear': true, 'inverse': false, 'taker': this.safeNumber (market, 'takerFeeRate'), 'maker': this.safeNumber (market, 'makerFeeRate'), 'contractSize': this.safeNumber (market, 'contractSize'), 'expiry': undefined, 'expiryDatetime': undefined, 'strike': undefined, 'optionType': undefined, 'precision': { 'amount': this.safeNumber (market, 'volUnit'), 'price': this.safeNumber (market, 'priceUnit'), }, 'limits': { 'leverage': { 'min': this.safeNumber (market, 'minLeverage'), 'max': this.safeNumber (market, 'maxLeverage'), }, 'amount': { 'min': this.safeNumber (market, 'minVol'), 'max': this.safeNumber (market, 'maxVol'), }, 'price': { 'min': undefined, 'max': undefined, }, 'cost': { 'min': undefined, 'max': undefined, }, }, 'info': market, }); } return result; } async fetchSpotMarkets (params = {}) { const response = await this.spotPublicGetMarketSymbols (params); // // { // "code":200, // "data":[ // { // "symbol":"DFD_USDT", // "state":"ENABLED", // "countDownMark":1, // "vcoinName":"DFD", // "vcoinStatus":1, // "price_scale":4, // "quantity_scale":2, // "min_amount":"5", // not an amount = cost // "max_amount":"5000000", // "maker_fee_rate":"0.002", // "taker_fee_rate":"0.002", // "limited":true, // "etf_mark":0, // "symbol_partition":"ASSESS" // }, // ] // } // const data = this.safeValue (response, 'data', []); const response2 = await this.spotPublicGetMarketApiDefaultSymbols (params); // // { // "code":200, // "data":{ // "symbol":[ // "ALEPH_USDT","OGN_USDT","HC_USDT", // ] // } // } // const data2 = this.safeValue (response2, 'data', {}); const symbols = this.safeValue (data2, 'symbol', []); const result = []; for (let i = 0; i < data.length; i++) { const market = data[i]; const id = this.safeString (market, 'symbol'); const [ baseId, quoteId ] = id.split ('_'); const base = this.safeCurrencyCode (baseId); const quote = this.safeCurrencyCode (quoteId); const state = this.safeString (market, 'state'); let active = false; for (let j = 0; j < symbols.length; j++) { if (symbols[j] === id) { if (state === 'ENABLED') { active = true; } break; } } result.push ({ 'id': id, 'symbol': base + '/' + quote, 'base': base, 'quote': quote, 'settle': undefined, 'baseId': baseId, 'quoteId': quoteId, 'settleId': undefined, 'type': 'spot', 'spot': true, 'margin': false, 'swap': false, 'future': false, 'option': false, 'active': active, 'contract': false, 'linear': undefined, 'inverse': undefined, 'taker': this.safeNumber (market, 'taker_fee_rate'), 'maker': this.safeNumber (market, 'maker_fee_rate'), 'contractSize': undefined, 'expiry': undefined, 'expiryDatetime': undefined, 'strike': undefined, 'optionType': undefined, 'precision': { 'amount': this.parseNumber (this.parsePrecision (this.safeString (market, 'quantity_scale'))), 'price': this.parseNumber (this.parsePrecision (this.safeString (market, 'price_scale'))), }, 'limits': { 'leverage': { 'min': undefined, 'max': undefined, }, 'amount': { 'min': undefined, 'max': undefined, }, 'price': { 'min': undefined, 'max': undefined, }, 'cost': { 'min': this.safeNumber (market, 'min_amount'), 'max': this.safeNumber (market, 'max_amount'), }, }, 'info': market, }); } return result; } async fetchTickers (symbols = undefined, params = {}) { /** * @method * @name mexc#fetchTickers * @description fetches price tickers for multiple markets, statistical calculations with the information calculated over the past 24 hours each market * @param {[string]|undefined} symbols unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned * @param {object} params extra parameters specific to the mexc api endpoint * @returns {object} an array of [ticker structures]{@link https://docs.ccxt.com/en/latest/manual.html#ticker-structure} */ await this.loadMarkets (); symbols = this.marketSymbols (symbols); const first = this.safeString (symbols, 0); let market = undefined; if (first !== undefined) { market = this.market (first); } const [ marketType, query ] = this.handleMarketTypeAndParams ('fetchTickers', market, params); const method = this.getSupportedMapping (marketType, { 'spot': 'spotPublicGetMarketTicker', 'swap': 'contractPublicGetTicker', }); const response = await this[method] (this.extend (query)); // // { // "success":true, // "code":0, // "data":[ // { // "symbol":"NKN_USDT", // "lastPrice":0.36199, // "bid1":0.35908, // "ask1":0.36277, // "volume24":657754, // "amount24":239024.53998, // "holdVol":149969, // "lower24Price":0.34957, // "high24Price":0.37689, // "riseFallRate":0.0117, // "riseFallValue":0.00419, // "indexPrice":0.36043, // "fairPrice":0.36108, // "fundingRate":0.000535, // "maxBidPrice":0.43251, // "minAskPrice":0.28834, // "timestamp":1634163352075 // }, // ] // } // const data = this.safeValue (response, 'data', []); return this.parseTickers (data, symbols); } async fetchTicker (symbol, params = {}) { /** * @method * @name mexc#fetchTicker * @description fetches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market * @param {string} symbol unified symbol of the market to fetch the ticker for * @param {object} params extra parameters specific to the mexc api endpoint * @returns {object} a [ticker structure]{@link https://docs.ccxt.com/en/latest/manual.html#ticker-structure} */ await this.loadMarkets (); const market = this.market (symbol); const request = { 'symbol': market['id'], }; let method = undefined; if (market['spot']) { method = 'spotPublicGetMarketTicker'; } else if (market['swap']) { method = 'contractPublicGetTicker'; } const response = await this[method] (this.extend (request, params)); // // spot // // { // "code":200, // "data":[ // { // "symbol":"BTC_USDT", // "volume":"880.821523", // "high":"49496.95", // highest price over the past 24 hours // "low":"46918.4", // lowest // "bid":"49297.64", // current buying price == the best price you can sell for // "ask":"49297.75", // current selling price == the best price you can buy for // "open":"48764.9", // open price 24h ago // "last":"49297.73", // last = close // "time":1633378200000, // timestamp // "change_rate":"0.0109265" // (last / open) - 1 // } // ] // } // // swap / contract // // { // "success":true, // "code":0, // "data":{ // "symbol":"ETH_USDT", // "lastPrice":3581.3, // "bid1":3581.25, // "ask1":3581.5, // "volume24":4045530, // "amount24":141331823.5755, // "holdVol":5832946, // "lower24Price":3413.4, // "high24Price":3588.7, // "riseFallRate":0.0275, // "riseFallValue":95.95, // "indexPrice":3580.7852, // "fairPrice":3581.08, // "fundingRate":0.000063, // "maxBidPrice":3938.85, // "minAskPrice":3222.7, // "timestamp":1634162885016 // } // } // if (market['spot']) { const data = this.safeValue (response, 'data', []); const ticker = this.safeValue (data, 0); return this.parseTicker (ticker, market); } else if (market['swap']) { const data = this.safeValue (response, 'data', {}); return this.parseTicker (data, market); } } parseTicker (ticker, market = undefined) { // // spot // // { // "symbol":"BTC_USDT", // "volume":"880.821523", // "high":"49496.95", // "low":"46918.4", // "bid":"49297.64", // "ask":"49297.75", // "open":"48764.9", // "last":"49297.73", // "time":1633378200000, // "change_rate":"0.0109265" // } // // contract // // { // "symbol":"ETH_USDT", // "lastPrice":3581.3, // "bid1":3581.25, // "ask1":3581.5, // "volume24":4045530, // "amount24":141331823.5755, // "holdVol":5832946, // "lower24Price":3413.4, // "high24Price":3588.7, // "riseFallRate":0.0275, // "riseFallValue":95.95, // "indexPrice":3580.7852, // "fairPrice":3581.08, // "fundingRate":0.000063, // "maxBidPrice":3938.85, // "minAskPrice":3222.7, // "timestamp":1634162885016 // } // const timestamp = this.safeInteger2 (ticker, 'time', 'timestamp'); const marketId = this.safeString (ticker, 'symbol'); const symbol = this.safeSymbol (marketId, market, '_'); const baseVolume = this.safeString2 (ticker, 'volume', 'volume24'); const quoteVolume = this.safeString (ticker, 'amount24'); const open = this.safeString (ticker, 'open'); const last = this.safeString2 (ticker, 'last', 'lastPrice'); const change = this.safeString (ticker, 'riseFallValue'); const riseFallRate = this.safeString (ticker, 'riseFallRate'); const percentage = Precise.stringAdd (riseFallRate, '1'); return this.safeTicker ({ 'symbol': symbol, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), 'high': this.safeString2 (ticker, 'high', 'high24Price'), 'low': this.safeString2 (ticker, 'low', 'lower24Price'), 'bid': this.safeString2 (ticker, 'bid', 'bid1'), 'bidVolume': undefined, 'ask': this.safeString2 (ticker, 'ask', 'ask1'), 'askVolume': undefined, 'vwap': undefined, 'open': open, 'close': last, 'last': last, 'previousClose': undefined, 'change': change, 'percentage': percentage, 'average': undefined, 'baseVolume': baseVolume, 'quoteVolume': quoteVolume, 'info': ticker, }, market); } async fetchOrderBook (symbol, limit = undefined, params = {}) { /** * @method * @name mexc#fetchOrderBook * @description fetches information on open orders with bid (buy) and ask (sell) prices, volumes and other data * @param {string} symbol unified symbol of the market to fetch the order book for * @param {int|undefined} limit the maximum amount of order book entries to return * @param {object} params extra parameters specific to the mexc api endpoint * @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/en/latest/manual.html#order-book-structure} indexed by market symbols */ await this.loadMarkets (); const market = this.market (symbol); const request = { 'symbol': market['id'], }; let method = undefined; if (market['spot']) { method = 'spotPublicGetMarketDepth'; if (limit === undefined) { limit = 100; // the spot api requires a limit } request['depth'] = limit; } else if (market['swap']) { method = 'contractPublicGetDepthSymbol'; if (limit !== undefined) { request['limit'] = limit; } } const response = await this[method] (this.extend (request, params)); // // spot // // { // "code":200, // "data":{ // "asks":[ // {"price":"49060.56","quantity":"0.099842"}, // {"price":"49060.58","quantity":"0.016003"}, // {"price":"49060.6","quantity":"0.023677"} // ], // "bids":[ // {"price":"49060.45","quantity":"1.693009"}, // {"price":"49060.44","quantity":"0.000843"}, // {"price":"49059.98","quantity":"0.735"}, // ], // "version":"202454074", // } // } // // swap / contract // // { // "success":true, // "code":0, // "data":{ // "asks":[ // [3445.7,48379,1], // [3445.75,34994,1], // [3445.8,68634,2], // ], // "bids":[ // [3445.55,44081,1], // [3445.5,24857,1], // [3445.45,50272,1], // ], // "version":2827730444, // "timestamp":1634117846232 // } // } // const data = this.safeValue (response, 'data', {}); const priceKey = market['spot'] ? 'price' : 0; const amountKey = market['spot'] ? 'quantity' : 1; const timestamp = this.safeInteger (data, 'timestamp'); const orderbook = this.parseOrderBook (data, symbol, timestamp, 'bids', 'asks', priceKey, amountKey); orderbook['nonce'] = this.safeInteger (data, 'version'); return orderbook; } async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) { /** * @method * @name mexc#fetchTrades * @description get the list of most recent trades for a particular symbol * @param {string} symbol unified symbol of the market to fetch trades for * @param {int|undefined} since timestamp in ms of the earliest trade to fetch * @param {int|undefined} limit the maximum amount of trades to fetch * @param {object} params extra parameters specific to the mexc api endpoint * @returns {[object]} a list of [trade structures]{@link https://docs.ccxt.com/en/latest/manual.html?#public-trades} */ await this.loadMarkets (); const market = this.market (symbol); const request = { 'symbol': market['id'], }; if (limit !== undefined) { request['limit'] = limit; // default 100, max 100 } let method = undefined; if (market['spot']) { method = 'spotPublicGetMarketDeals'; } else if (market['swap']) { method = 'contractPublicGetDealsSymbol'; } const response = await this[method] (this.extend (request, params)); // // spot // // { // "code":200, // "data":[ // {"trade_time":1633381766725,"trade_price":"0.068981","trade_quantity":"0.005","trade_type":"BID"}, // {"trade_time":1633381732705,"trade_price":"0.068979","trade_quantity":"0.006","trade_type":"BID"}, // {"trade_time":1633381694604,"trade_price":"0.068975","trade_quantity":"0.011","trade_type":"ASK"}, // ] // } // // swap / contract // // { // "success":true, // "code":0, // "data":[ // {"p":3598.85,"v":52,"T":1,"O":2,"M":2,"t":1634169038038}, // {"p":3599.2,"v":15,"T":2,"O":3,"M":1,"t":1634169035603}, // {"p":3600.15,"v":229,"T":2,"O":1,"M":2,"t":1634169026354}, // ] // } // const data = this.safeValue (response, 'data', []); return this.parseTrades (data, market, since, limit); } parseTrade (trade, market = undefined) { // // public fetchTrades // // spot // // { // "trade_time":1633381766725, // "trade_price":"0.068981", // "trade_quantity":"0.005", // "trade_type":"BID" // } // // swap / contract // // { // "p":3598.85, // "v":52, // "T":1, // 1 buy, 2 sell // "O":2, // 1 opens a position, 2 does not open a position // "M":2, // self-trading, 1 yes, 2 no // "t":1634169038038 // } // // private fetchMyTrades, fetchOrderTrades // // { // "id":"b160b8f072d9403e96289139d5544809", // "symbol":"USDC_USDT", // "quantity":"150", // "price":"0.9997", // "amount":"149.955", // "fee":"0.29991", // "trade_type":"ASK", // "order_id":"d798765285374222990bbd14decb86cd", // "is_taker":true, // "fee_currency":"USDT", // "create_time":1633984904000 // } // let timestamp = this.safeInteger2 (trade, 'create_time', 'trade_time'); timestamp = this.safeInteger (trade, 't', timestamp); const marketId = this.safeString (trade, 'symbol'); market = this.safeMarket (marketId, market, '_'); const symbol = market['symbol']; let priceString = this.safeString2 (trade, 'price', 'trade_price'); priceString = this.safeString (trade, 'p', priceString); let amountString = this.safeString2 (trade, 'quantity', 'trade_quantity'); amountString = this.safeString (trade, 'v', amountString); const costString = this.safeString (trade, 'amount'); let side = this.safeString2 (trade, 'trade_type', 'T'); if ((side === 'BID') || (side === '1')) { side = 'buy'; } else if ((side === 'ASK') || (side === '2')) { side = 'sell'; } let id = this.safeString2 (trade, 'id', 'trade_time'); if (id === undefined) { id = this.safeString (trade, 't', id); if (id !== undefined) { id += '-' + market['id'] + '-' + amountString; } } const