UNPKG

@proton/ccxt

Version:

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

1,142 lines (1,140 loc) 222 kB
// ---------------------------------------------------------------------------- // PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN: // https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code // EDIT THE CORRESPONDENT .ts FILE INSTEAD // --------------------------------------------------------------------------- import Exchange from './abstract/mexc.js'; import { BadRequest, InvalidNonce, BadSymbol, InvalidOrder, InvalidAddress, ExchangeError, ArgumentsRequired, NotSupported, InsufficientFunds, PermissionDenied, AuthenticationError, AccountSuspended } from './base/errors.js'; import { TICK_SIZE } from './base/functions/number.js'; import { Precise } from './base/Precise.js'; import { sha256 } from './static_dependencies/noble-hashes/sha256.js'; // --------------------------------------------------------------------------- export default class mexc extends Exchange { describe() { return this.deepExtend(super.describe(), { 'id': 'mexc', 'name': 'MEXC Global', 'countries': ['SC'], 'rateLimit': 50, 'version': 'v3', 'certified': true, 'pro': true, 'has': { 'CORS': undefined, 'spot': true, 'margin': true, 'swap': true, 'future': true, 'option': undefined, 'addMargin': true, 'borrowMargin': true, 'cancelAllOrders': true, 'cancelOrder': true, 'cancelOrders': undefined, 'createDepositAddress': true, 'createOrder': true, 'createReduceOnlyOrder': true, 'deposit': undefined, 'editOrder': undefined, 'fetchAccounts': true, 'fetchBalance': true, 'fetchBidsAsks': true, 'fetchBorrowRate': undefined, 'fetchBorrowRateHistory': undefined, 'fetchBorrowRates': undefined, 'fetchBorrowRatesPerSymbol': undefined, 'fetchCanceledOrders': true, 'fetchClosedOrder': undefined, 'fetchClosedOrders': true, 'fetchCurrencies': true, 'fetchDeposit': undefined, 'fetchDepositAddress': true, 'fetchDepositAddresses': undefined, 'fetchDepositAddressesByNetwork': true, 'fetchDeposits': true, 'fetchDepositWithdrawFee': 'emulated', 'fetchDepositWithdrawFees': true, 'fetchFundingHistory': true, 'fetchFundingRate': true, 'fetchFundingRateHistory': true, 'fetchFundingRates': undefined, 'fetchIndexOHLCV': true, 'fetchL2OrderBook': true, 'fetchLedger': undefined, 'fetchLedgerEntry': undefined, 'fetchLeverageTiers': true, 'fetchMarginMode': false, 'fetchMarketLeverageTiers': undefined, 'fetchMarkets': true, 'fetchMarkOHLCV': true, 'fetchMyTrades': true, 'fetchOHLCV': true, 'fetchOpenOrder': undefined, 'fetchOpenOrders': true, 'fetchOrder': true, 'fetchOrderBook': true, 'fetchOrderBooks': undefined, 'fetchOrders': true, 'fetchOrderTrades': true, 'fetchPosition': true, 'fetchPositionMode': true, 'fetchPositions': true, 'fetchPositionsRisk': undefined, 'fetchPremiumIndexOHLCV': false, 'fetchStatus': true, 'fetchTicker': true, 'fetchTickers': true, 'fetchTime': true, 'fetchTrades': true, 'fetchTradingFee': undefined, 'fetchTradingFees': true, 'fetchTradingLimits': undefined, 'fetchTransactionFee': 'emulated', 'fetchTransactionFees': true, 'fetchTransactions': undefined, 'fetchTransfer': true, 'fetchTransfers': true, 'fetchWithdrawal': undefined, 'fetchWithdrawals': true, 'reduceMargin': true, 'repayMargin': true, 'setLeverage': true, 'setMarginMode': undefined, 'setPositionMode': true, 'signIn': undefined, 'transfer': undefined, 'withdraw': true, }, 'urls': { 'logo': 'https://user-images.githubusercontent.com/1294454/137283979-8b2a818d-8633-461b-bfca-de89e8c446b2.jpg', 'api': { 'spot': { 'public': 'https://api.mexc.com', 'private': 'https://api.mexc.com', }, 'spot2': { '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', }, 'broker': { 'private': 'https://api.mexc.com/api/v3/broker', }, }, 'www': 'https://www.mexc.com/', 'doc': [ 'https://mxcdevelop.github.io/apidocs/spot_v3_en/', 'https://mxcdevelop.github.io/APIDoc/', // v1 & v2 : soon to be deprecated ], 'fees': [ 'https://www.mexc.com/fee', ], 'referral': 'https://m.mexc.com/auth/signup?inviteCode=1FQ1G', }, 'api': { 'spot': { 'public': { 'get': { 'ping': 1, 'time': 1, 'exchangeInfo': 1, 'depth': 1, 'trades': 1, 'historicalTrades': 1, 'aggTrades': 1, 'klines': 1, 'avgPrice': 1, 'ticker/24hr': 1, 'ticker/price': 1, 'ticker/bookTicker': 1, 'etf/info': 1, }, }, 'private': { 'get': { 'order': 1, 'openOrders': 1, 'allOrders': 1, 'account': 1, 'myTrades': 1, 'sub-account/list': 1, 'sub-account/apiKey': 1, 'capital/config/getall': 1, 'capital/deposit/hisrec': 1, 'capital/withdraw/history': 1, 'capital/deposit/address': 1, 'capital/transfer': 1, 'capital/transfer/tranId': 1, 'capital/sub-account/universalTransfer': 1, 'capital/convert': 1, 'capital/convert/list': 1, 'margin/loan': 1, 'margin/allOrders': 1, 'margin/myTrades': 1, 'margin/openOrders': 1, 'margin/maxTransferable': 1, 'margin/priceIndex': 1, 'margin/order': 1, 'margin/isolated/account': 1, 'margin/maxBorrowable': 1, 'margin/repay': 1, 'margin/isolated/pair': 1, 'margin/forceLiquidationRec': 1, 'margin/isolatedMarginData': 1, 'margin/isolatedMarginTier': 1, 'rebate/taxQuery': 1, 'rebate/detail': 1, 'rebate/detail/kickback': 1, 'rebate/referCode': 1, 'mxDeduct/enable': 1, 'userDataStream': 1, }, 'post': { 'order': 1, 'order/test': 1, 'sub-account/virtualSubAccount': 1, 'sub-account/apiKey': 1, 'sub-account/futures': 1, 'sub-account/margin': 1, 'batchOrders': 1, 'capital/withdraw/apply': 1, 'capital/transfer': 1, 'capital/deposit/address': 1, 'capital/sub-account/universalTransfer': 1, 'capital/convert': 1, 'margin/tradeMode': 1, 'margin/order': 1, 'margin/loan': 1, 'margin/repay': 1, 'mxDeduct/enable': 1, 'userDataStream': 1, }, 'put': { 'userDataStream': 1, }, 'delete': { 'order': 1, 'openOrders': 1, 'sub-account/apiKey': 1, 'margin/order': 1, 'margin/openOrders': 1, 'userDataStream': 1, }, }, }, '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, 'position/leverage': 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, }, }, }, 'spot2': { '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, 'order/advanced/place_batch': 1, 'asset/withdraw': 2, 'asset/internal/transfer': 10, }, 'delete': { 'order/cancel': 1, 'order/cancel_by_symbol': 1, 'asset/withdraw': 2, }, }, }, 'broker': { 'private': { 'get': { 'sub-account/universalTransfer': 1, 'sub-account/list': 1, 'sub-account/apiKey': 1, 'capital/deposit/subAddress': 1, 'capital/deposit/subHisrec': 1, 'capital/deposit/subHisrec/getall': 1, }, 'post': { 'sub-account/virtualSubAccount': 1, 'sub-account/apiKey': 1, 'capital/deposit/subAddress': 1, 'capital/withdraw/apply': 1, 'sub-account/universalTransfer': 1, 'sub-account/futures': 1, }, 'delete': { 'sub-account/apiKey': 1, }, }, }, }, 'precisionMode': TICK_SIZE, 'timeframes': { '1m': '1m', '5m': '5m', '15m': '15m', '30m': '30m', '1h': '1h', '4h': '4h', '8h': '8h', '1d': '1d', '1w': '1w', '1M': '1M', // spot, swap }, 'fees': { 'trading': { 'tierBased': false, 'percentage': true, 'maker': this.parseNumber('0.002'), 'taker': this.parseNumber('0.002'), }, }, 'options': { 'createMarketBuyOrderRequiresPrice': true, 'unavailableContracts': { 'BTC/USDT:USDT': true, 'LTC/USDT:USDT': true, 'ETH/USDT:USDT': true, }, 'fetchMarkets': { 'types': { 'spot': true, 'future': { 'linear': false, 'inverse': false, }, 'swap': { 'linear': true, 'inverse': false, }, }, }, 'timeframes': { 'spot': { '1m': '1m', '5m': '5m', '15m': '15m', '30m': '30m', '1h': '60m', '4h': '4h', '1d': '1d', '1M': '1M', }, 'swap': { '1m': 'Min1', '5m': 'Min5', '15m': 'Min15', '30m': 'Min30', '1h': 'Min60', '4h': 'Hour4', '8h': 'Hour8', '1d': 'Day1', '1w': 'Week1', '1M': 'Month1', }, }, 'defaultType': 'spot', 'networks': { 'TRX': 'TRC20', 'ETH': 'ERC20', 'BEP20': 'BEP20(BSC)', 'BSC': 'BEP20(BSC)', }, 'networksById': { 'BEP20(BSC)': 'BSC', }, 'networkAliases': { 'BSC(BEP20)': 'BSC', }, 'recvWindow': 5 * 1000, 'maxTimeTillEnd': 90 * 86400 * 1000 - 1, 'broker': 'CCXT', }, 'commonCurrencies': { 'BEYONDPROTOCOL': 'BEYOND', 'BIFI': 'BIFIF', 'BYN': 'BeyondFi', 'COFI': 'COFIX', 'DFI': 'DfiStarter', 'DFT': 'dFuture', 'DRK': 'DRK', 'EGC': 'Egoras Credit', 'FLUX1': 'FLUX', 'FLUX': 'FLUX1', 'FREE': 'FreeRossDAO', 'GAS': 'GASDAO', 'GASNEO': 'GAS', 'GMT': 'GMT Token', 'STEPN': 'GMT', 'HERO': 'Step Hero', 'MIMO': 'Mimosa', 'PROS': 'Pros.Finance', 'SIN': 'Sin City Token', 'SOUL': 'Soul Swap', }, 'exceptions': { 'exact': { // until mexc migrates fully to v3, it might be worth to note the version & market aside errors, not easily remove obsolete version's exceptions in future '-1128': BadRequest, '-2011': BadRequest, '-1121': BadSymbol, '10101': InsufficientFunds, '2009': InvalidOrder, '2011': BadRequest, '30004': InsufficientFunds, '33333': BadRequest, '44444': BadRequest, '1002': InvalidOrder, '30019': BadRequest, '30005': InvalidOrder, '2003': InvalidOrder, '2005': InsufficientFunds, '400': BadRequest, '600': BadRequest, '70011': PermissionDenied, '88004': InsufficientFunds, '88009': ExchangeError, '88013': InvalidOrder, '88015': InsufficientFunds, '700003': InvalidNonce, '26': ExchangeError, '602': AuthenticationError, '10001': AuthenticationError, '10007': BadSymbol, '10015': BadRequest, '10072': BadRequest, '10073': BadRequest, '10095': InvalidOrder, '10096': InvalidOrder, '10097': InvalidOrder, '10098': InvalidOrder, '10099': BadRequest, '10100': BadRequest, '10102': InvalidOrder, '10103': ExchangeError, '10200': BadRequest, '10201': BadRequest, '10202': BadRequest, '10206': BadRequest, '10211': BadRequest, '10212': BadRequest, '10216': ExchangeError, '10219': ExchangeError, '10222': BadRequest, '10232': BadRequest, '10259': ExchangeError, '10265': ExchangeError, '10268': BadRequest, '20001': ExchangeError, '20002': ExchangeError, '22222': BadRequest, '30000': ExchangeError, '30001': InvalidOrder, '30002': InvalidOrder, '30003': InvalidOrder, '30010': InvalidOrder, '30014': InvalidOrder, '30016': InvalidOrder, '30018': AccountSuspended, '30020': AuthenticationError, '30021': BadRequest, '30025': InvalidOrder, '30026': BadRequest, '30027': InvalidOrder, '30028': InvalidOrder, '30029': InvalidOrder, '30032': InvalidOrder, '30041': InvalidOrder, '60005': ExchangeError, '700001': BadRequest, '700002': AuthenticationError, '700004': BadRequest, '700005': InvalidNonce, '700006': BadRequest, '700007': AuthenticationError, '700008': BadRequest, '730001': BadRequest, '730002': BadRequest, '730000': ExchangeError, '730003': ExchangeError, '730100': ExchangeError, '730600': BadRequest, '730601': BadRequest, '730602': BadRequest, '730700': BadRequest, '730701': BadRequest, '730702': BadRequest, '730703': BadRequest, '730704': BadRequest, '730705': BadRequest, '730706': BadRequest, '730707': BadRequest, '730101': BadRequest, '140001': BadRequest, '140002': AuthenticationError, // sub account is forbidden }, 'broad': { 'Order quantity error, please try to modify.': BadRequest, 'Combination of optional parameters invalid': BadRequest, 'api market order is disabled': BadRequest, 'Contract not allow place order!': InvalidOrder, 'Oversold': InvalidOrder, 'Insufficient position': InsufficientFunds, 'Insufficient balance!': InsufficientFunds, 'Bid price is great than max allow price': InvalidOrder, 'Invalid symbol.': BadSymbol, 'Param error!': BadRequest, // code:600 }, }, }); } async fetchStatus(params = {}) { /** * @method * @name mexc3#fetchStatus * @description the latest known information on the availability of the exchange API * @param {object} params extra parameters specific to the mexc3 api endpoint * @returns {object} a [status structure]{@link https://docs.ccxt.com/#/?id=exchange-status-structure} */ const [marketType, query] = this.handleMarketTypeAndParams('fetchStatus', undefined, params); let response = undefined; let status = undefined; let updated = undefined; if (marketType === 'spot') { response = await this.spotPublicGetPing(query); // // {} // status = Object.keys(response).length ? this.json(response) : 'ok'; } else if (marketType === 'swap') { response = await this.contractPublicGetPing(query); // // {"success":true,"code":"0","data":"1648124374985"} // status = this.safeValue(response, 'success') ? 'ok' : this.json(response); updated = this.safeInteger(response, 'data'); } return { 'status': status, 'updated': updated, 'url': undefined, 'eta': undefined, 'info': response, }; } async fetchTime(params = {}) { /** * @method * @name mexc3#fetchTime * @description fetches the current integer timestamp in milliseconds from the exchange server * @param {object} params extra parameters specific to the mexc3 api endpoint * @returns {int} the current integer timestamp in milliseconds from the exchange server */ const [marketType, query] = this.handleMarketTypeAndParams('fetchTime', undefined, params); let response = undefined; if (marketType === 'spot') { response = await this.spotPublicGetTime(query); // // {"serverTime": "1647519277579"} // return this.safeInteger(response, 'serverTime'); } else if (marketType === 'swap') { response = await this.contractPublicGetPing(query); // // {"success":true,"code":"0","data":"1648124374985"} // return this.safeInteger(response, 'data'); } return undefined; } async fetchCurrencies(params = {}) { /** * @method * @name mexc3#fetchCurrencies * @description fetches all available currencies on an exchange * @see https://mxcdevelop.github.io/apidocs/spot_v3_en/#query-the-currency-information * @param {object} params extra parameters specific to the mexc3 api endpoint * @returns {object} an associative dictionary of currencies */ // this endpoint requires authentication // while fetchCurrencies is a public API method by design // therefore we check the keys here // and fallback to generating the currencies from the markets if (!this.checkRequiredCredentials(false)) { return undefined; } const response = await this.spotPrivateGetCapitalConfigGetall(params); // // { // coin: 'QANX', // name: 'QANplatform', // networkList: [ // { // coin: 'QANX', // depositDesc: null, // depositEnable: true, // minConfirm: '0', // name: 'QANplatform', // network: 'BEP20(BSC)', // withdrawEnable: false, // withdrawFee: '42.000000000000000000', // withdrawIntegerMultiple: null, // withdrawMax: '24000000.000000000000000000', // withdrawMin: '20.000000000000000000', // sameAddress: false, // contract: '0xAAA7A10a8ee237ea61E8AC46C50A8Db8bCC1baaa' // }, // { // coin: 'QANX', // depositDesc: null, // depositEnable: true, // minConfirm: '0', // name: 'QANplatform', // network: 'ERC20', // withdrawEnable: true, // withdrawFee: '2732.000000000000000000', // withdrawIntegerMultiple: null, // withdrawMax: '24000000.000000000000000000', // withdrawMin: '240.000000000000000000', // sameAddress: false, // contract: '0xAAA7A10a8ee237ea61E8AC46C50A8Db8bCC1baaa' // } // ] // } // const result = {}; for (let i = 0; i < response.length; i++) { const currency = response[i]; const id = this.safeString(currency, 'coin'); const code = this.safeCurrencyCode(id); const name = this.safeString(currency, 'name'); let currencyActive = false; let currencyFee = undefined; let currencyWithdrawMin = undefined; let currencyWithdrawMax = undefined; let depositEnabled = false; let withdrawEnabled = false; const networks = {}; const chains = this.safeValue(currency, 'networkList', []); for (let j = 0; j < chains.length; j++) { const chain = chains[j]; const networkId = this.safeString(chain, 'network'); const network = this.safeNetwork(networkId); const isDepositEnabled = this.safeValue(chain, 'depositEnable', false); const isWithdrawEnabled = this.safeValue(chain, 'withdrawEnable', false); const active = (isDepositEnabled && isWithdrawEnabled); currencyActive = active || currencyActive; const withdrawMin = this.safeString(chain, 'withdrawMin'); const withdrawMax = this.safeString(chain, 'withdrawMax'); currencyWithdrawMin = (currencyWithdrawMin === undefined) ? withdrawMin : currencyWithdrawMin; currencyWithdrawMax = (currencyWithdrawMax === undefined) ? withdrawMax : currencyWithdrawMax; const fee = this.safeNumber(chain, 'withdrawFee'); currencyFee = (currencyFee === undefined) ? fee : currencyFee; if (Precise.stringGt(currencyWithdrawMin, withdrawMin)) { currencyWithdrawMin = withdrawMin; } if (Precise.stringLt(currencyWithdrawMax, withdrawMax)) { currencyWithdrawMax = withdrawMax; } if (isDepositEnabled) { depositEnabled = true; } if (isWithdrawEnabled) { withdrawEnabled = true; } networks[network] = { 'info': chain, 'id': networkId, 'network': network, 'active': active, 'deposit': isDepositEnabled, 'withdraw': isWithdrawEnabled, 'fee': fee, 'precision': undefined, '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] = { 'info': currency, 'id': id, 'code': code, 'name': name, 'active': currencyActive, 'deposit': depositEnabled, 'withdraw': withdrawEnabled, 'fee': currencyFee, 'precision': undefined, 'limits': { 'amount': { 'min': undefined, 'max': undefined, }, 'withdraw': { 'min': currencyWithdrawMin, 'max': currencyWithdrawMax, }, }, 'networks': networks, }; } return result; } safeNetwork(networkId) { if (networkId.indexOf('BSC') >= 0) { return 'BEP20'; } const parts = networkId.split(' '); networkId = parts.join(''); networkId = networkId.replace('-20', '20'); const networksById = { 'ETH': 'ETH', 'ERC20': 'ERC20', 'BEP20(BSC)': 'BEP20', 'TRX': 'TRC20', }; return this.safeString(networksById, networkId, networkId); } async fetchMarkets(params = {}) { /** * @method * @name mexc3#fetchMarkets * @description retrieves data on all markets for mexc3 * @param {object} params extra parameters specific to the exchange api endpoint * @returns {[object]} an array of objects representing market data */ const spotMarket = await this.fetchSpotMarkets(params); const swapMarket = await this.fetchSwapMarkets(params); return this.arrayConcat(spotMarket, swapMarket); } async fetchSpotMarkets(params = {}) { const response = await this.spotPublicGetExchangeInfo(params); // // { // "timezone": "CST", // "serverTime": 1647521860402, // "rateLimits": [], // "exchangeFilters": [], // "symbols": [ // { // "symbol": "OGNUSDT", // "status": "ENABLED", // "baseAsset": "OGN", // "baseAssetPrecision": "2", // "quoteAsset": "USDT", // "quoteAssetPrecision": "4", // "orderTypes": [ // "LIMIT", // "LIMIT_MAKER" // ], // "baseCommissionPrecision": "2", // "quoteCommissionPrecision": "4", // "quoteOrderQtyMarketAllowed": false, // "isSpotTradingAllowed": true, // "isMarginTradingAllowed": true, // "permissions": [ // "SPOT", // "MARGIN" // ], // "filters": [], // "baseSizePrecision": "0.01", // this turned out to be a minimum base amount for order // "maxQuoteAmount": "5000000", // "makerCommission": "0.002", // "takerCommission": "0.002" // "quoteAmountPrecision": "5", // this turned out to be a minimum cost amount for order // "quotePrecision": "4", // deprecated in favor of 'quoteAssetPrecision' ( https://dev.binance.vision/t/what-is-the-difference-between-quoteprecision-and-quoteassetprecision/4333 ) // // note, "icebergAllowed" & "ocoAllowed" fields were recently removed // }, // ] // } // // Notes: // - 'quoteAssetPrecision' & 'baseAssetPrecision' are not currency's real blockchain precision (to view currency's actual individual precision, refer to fetchCurrencies() method). // const data = this.safeValue(response, 'symbols', []); 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, 'baseAsset'); const quoteId = this.safeString(market, 'quoteAsset'); const base = this.safeCurrencyCode(baseId); const quote = this.safeCurrencyCode(quoteId); const status = this.safeString(market, 'status'); const isSpotTradingAllowed = this.safeValue(market, 'isSpotTradingAllowed'); let active = false; if ((status === 'ENABLED') && (isSpotTradingAllowed)) { active = true; } const isMarginTradingAllowed = this.safeValue(market, 'isMarginTradingAllowed'); const makerCommission = this.safeNumber(market, 'makerCommission'); const takerCommission = this.safeNumber(market, 'takerCommission'); const maxQuoteAmount = this.safeNumber(market, 'maxQuoteAmount'); result.push({ 'id': id, 'symbol': base + '/' + quote, 'base': base, 'quote': quote, 'settle': undefined, 'baseId': baseId, 'quoteId': quoteId, 'settleId': undefined, 'type': 'spot', 'spot': true, 'margin': isMarginTradingAllowed, 'swap': false, 'future': false, 'option': false, 'active': active, 'contract': false, 'linear': undefined, 'inverse': undefined, 'taker': takerCommission, 'maker': makerCommission, 'contractSize': undefined, 'expiry': undefined, 'expiryDatetime': undefined, 'strike': undefined, 'optionType': undefined, 'precision': { 'amount': this.parseNumber(this.parsePrecision(this.safeString(market, 'baseAssetPrecision'))), 'price': this.parseNumber(this.parsePrecision(this.safeString(market, 'quoteAssetPrecision'))), }, 'limits': { 'leverage': { 'min': undefined, 'max': undefined, }, 'amount': { 'min': this.safeNumber(market, 'baseSizePrecision'), 'max': undefined, }, 'price': { 'min': undefined, 'max': undefined, }, 'cost': { 'min': this.safeNumber(market, 'quoteAmountPrecision'), 'max': maxQuoteAmount, }, }, 'info': market, }); } return result; } async fetchSwapMarkets(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, // seems useless atm, as it's just how UI shows the price, i.e. 29583.50 for BTC/USDT:USDT, while price ticksize is 0.5 // "volScale":0, // probably: contract amount precision // "amountScale":4, // probably: quote currency precision // "priceUnit":0.5, // price tick size // "volUnit":1, // probably: contract tick size // "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 fetchOrderBook(symbol, limit = undefined, params = {}) { /** * @method * @name mexc3#fetchOrderBook * @see https://mxcdevelop.github.io/apidocs/spot_v3_en/#order-book * @see https://mxcdevelop.github.io/apidocs/contract_v1_en/#get-the-contract-s-depth-information * @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 mexc3 api endpoint * @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/#/?id=order-book-structure} indexed by market symbols */ await this.loadMarkets(); const market = this.market(symbol); const request = { 'symbol': market['id'], }; if (limit !== undefined) { request['limit'] = limit; } let orderbook = undefined; if (market['spot']) { const response = await this.spotPublicGetDepth(this.extend(request, params)); // // { // "lastUpdateId": "744267132", // "bids": [ // ["40838.50","0.387864"], // ["40837.95","0.008400"], // ], // "asks": [ // ["40838.61","6.544908"], // ["40838.88","0.498000"], // ] // } // orderbook = this.parseOrderBook(response, symbol); orderbook['nonce'] = this.safeInteger(response, 'lastUpdateId'); } else if (market['swap']) { const response = await this.contractPublicGetDepthSymbol(this.extend(request, params)); // // { // "success":true, // "code":0, // "data":{ // "asks":[ // [3445.72,48379,1], // [3445.75,34994,1], // ], // "bids":[ // [3445.55,44081,1], // [3445.51,24857,1], // ], // "version":2827730444, // "timestamp":1634117846232 // } // } // const data = this.safeValue(response, 'data'); const timestamp = this.safeInteger(data, 'timestamp'); orderbook = this.parseOrderBook(data, symbol, timestamp); orderbook['nonce'] = this.safeInteger(data, 'version'); } return orderbook; } parseBidAsk(bidask, priceKey = 0, amountKey = 1, countKey = 2) { const price = this.safeNumber(bidask, priceKey); const amount = this.safeNumber(bidask, amountKey); const count = this.safeNumber(bidask, countKey); if (count !== undefined) { return [price, amount, count]; } return [price, amount]; } async fetchTrades(symbol, since = undefined, limit = undefined, params = {}) { /** * @method * @name mexc3#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 mexc3 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; } // if (since !== undefined) { // request['startTime'] = since; bug in api, waiting for fix // } let trades = undefined; if (market['spot']) { let method = this.safeString(this.optio