@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
JavaScript
// ----------------------------------------------------------------------------
// 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