sfccxt
Version:
A JavaScript / Python / PHP cryptocurrency trading library with support for 130+ exchanges
1,173 lines (1,157 loc) • 153 kB
JavaScript
'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