UNPKG

ccxt

Version:

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

1,086 lines (1,084 loc) • 239 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/phemex.js'; import { ExchangeError, BadSymbol, AuthenticationError, InsufficientFunds, InvalidOrder, ArgumentsRequired, OrderNotFound, BadRequest, PermissionDenied, AccountSuspended, CancelPending, DDoSProtection, DuplicateOrderId, RateLimitExceeded } from './base/errors.js'; import { Precise } from './base/Precise.js'; import { TICK_SIZE } from './base/functions/number.js'; import { sha256 } from './static_dependencies/noble-hashes/sha256.js'; // ---------------------------------------------------------------------------- /** * @class phemex * @augments Exchange */ export default class phemex extends Exchange { describe() { return this.deepExtend(super.describe(), { 'id': 'phemex', 'name': 'Phemex', 'countries': ['CN'], 'rateLimit': 120.5, 'version': 'v1', 'certified': false, 'pro': true, 'hostname': 'api.phemex.com', 'has': { 'CORS': undefined, 'spot': true, 'margin': false, 'swap': true, 'future': false, 'option': false, 'addMargin': false, 'cancelAllOrders': true, 'cancelOrder': true, 'closePosition': false, 'createConvertTrade': true, 'createOrder': true, 'createReduceOnlyOrder': true, 'createStopLimitOrder': true, 'createStopMarketOrder': true, 'createStopOrder': true, 'editOrder': true, 'fetchBalance': true, 'fetchBorrowRateHistories': false, 'fetchBorrowRateHistory': false, 'fetchClosedOrders': true, 'fetchConvertQuote': true, 'fetchConvertTrade': false, 'fetchConvertTradeHistory': true, 'fetchCrossBorrowRate': false, 'fetchCrossBorrowRates': false, 'fetchCurrencies': true, 'fetchDepositAddress': true, 'fetchDepositAddresses': false, 'fetchDepositAddressesByNetwork': false, 'fetchDeposits': true, 'fetchFundingHistory': true, 'fetchFundingRate': true, 'fetchFundingRateHistories': false, 'fetchFundingRateHistory': true, 'fetchFundingRates': false, 'fetchIndexOHLCV': false, 'fetchIsolatedBorrowRate': false, 'fetchIsolatedBorrowRates': false, 'fetchLeverage': false, 'fetchLeverageTiers': true, 'fetchMarketLeverageTiers': 'emulated', 'fetchMarkets': true, 'fetchMarkOHLCV': false, 'fetchMyTrades': true, 'fetchOHLCV': true, 'fetchOpenInterest': true, 'fetchOpenOrders': true, 'fetchOrder': true, 'fetchOrderBook': true, 'fetchOrders': true, 'fetchPositions': true, 'fetchPositionsRisk': false, 'fetchPremiumIndexOHLCV': false, 'fetchTicker': true, 'fetchTickers': true, 'fetchTrades': true, 'fetchTradingFee': false, 'fetchTradingFees': false, 'fetchTransfers': true, 'fetchWithdrawals': true, 'reduceMargin': false, 'sandbox': true, 'setLeverage': true, 'setMargin': true, 'setMarginMode': true, 'setPositionMode': true, 'transfer': true, 'withdraw': true, }, 'urls': { 'logo': 'https://user-images.githubusercontent.com/1294454/85225056-221eb600-b3d7-11ea-930d-564d2690e3f6.jpg', 'test': { 'v1': 'https://testnet-api.phemex.com/v1', 'v2': 'https://testnet-api.phemex.com', 'public': 'https://testnet-api.phemex.com/exchange/public', 'private': 'https://testnet-api.phemex.com', }, 'api': { 'v1': 'https://{hostname}/v1', 'v2': 'https://{hostname}', 'public': 'https://{hostname}/exchange/public', 'private': 'https://{hostname}', }, 'www': 'https://phemex.com', 'doc': 'https://phemex-docs.github.io/#overview', 'fees': 'https://phemex.com/fees-conditions', 'referral': { 'url': 'https://phemex.com/register?referralCode=EDNVJ', 'discount': 0.1, }, }, 'timeframes': { '1m': '60', '3m': '180', '5m': '300', '15m': '900', '30m': '1800', '1h': '3600', '2h': '7200', '3h': '10800', '4h': '14400', '6h': '21600', '12h': '43200', '1d': '86400', '1w': '604800', '1M': '2592000', '3M': '7776000', '1Y': '31104000', }, 'api': { 'public': { 'get': { 'cfg/v2/products': 5, 'cfg/fundingRates': 5, 'products': 5, 'nomics/trades': 5, 'md/kline': 5, 'md/v2/kline/list': 5, 'md/v2/kline': 5, 'md/v2/kline/last': 5, 'md/orderbook': 5, 'md/trade': 5, 'md/spot/ticker/24hr': 5, 'exchange/public/cfg/chain-settings': 5, // ?currency=<currency> }, }, 'v1': { 'get': { 'md/fullbook': 5, 'md/orderbook': 5, 'md/trade': 5, 'md/ticker/24hr': 5, 'md/ticker/24hr/all': 5, 'md/spot/ticker/24hr': 5, 'md/spot/ticker/24hr/all': 5, 'exchange/public/products': 5, 'api-data/public/data/funding-rate-history': 5, }, }, 'v2': { 'get': { 'public/products': 5, 'public/products-plus': 5, 'md/v2/orderbook': 5, 'md/v2/trade': 5, 'md/v2/ticker/24hr': 5, 'md/v2/ticker/24hr/all': 5, 'api-data/public/data/funding-rate-history': 5, }, }, 'private': { 'get': { // spot 'spot/orders/active': 1, // 'spot/orders/active': 5, // ?symbol=<symbol>&clOrDID=<clOrdID> 'spot/orders': 1, 'spot/wallets': 5, 'exchange/spot/order': 5, 'exchange/spot/order/trades': 5, 'exchange/order/v2/orderList': 5, 'exchange/order/v2/tradingList': 5, // swap 'accounts/accountPositions': 1, 'g-accounts/accountPositions': 1, 'accounts/positions': 25, 'api-data/futures/funding-fees': 5, 'api-data/g-futures/funding-fees': 5, 'api-data/futures/orders': 5, 'api-data/g-futures/orders': 5, 'api-data/futures/orders/by-order-id': 5, 'api-data/g-futures/orders/by-order-id': 5, 'api-data/futures/trades': 5, 'api-data/g-futures/trades': 5, 'api-data/futures/trading-fees': 5, 'api-data/g-futures/trading-fees': 5, 'api-data/futures/v2/tradeAccountDetail': 5, 'g-orders/activeList': 1, 'orders/activeList': 1, 'exchange/order/list': 5, 'exchange/order': 5, // 'exchange/order': 5, // ?symbol=<symbol>&clOrdID=<clOrdID5,clOrdID2> 'exchange/order/trade': 5, 'phemex-user/users/children': 5, 'phemex-user/wallets/v2/depositAddress': 5, 'phemex-user/wallets/tradeAccountDetail': 5, 'phemex-deposit/wallets/api/depositAddress': 5, 'phemex-deposit/wallets/api/depositHist': 5, 'phemex-deposit/wallets/api/chainCfg': 5, 'phemex-withdraw/wallets/api/withdrawHist': 5, 'phemex-withdraw/wallets/api/asset/info': 5, 'phemex-user/order/closedPositionList': 5, 'exchange/margins/transfer': 5, 'exchange/wallets/confirm/withdraw': 5, 'exchange/wallets/withdrawList': 5, 'exchange/wallets/depositList': 5, 'exchange/wallets/v2/depositAddress': 5, 'api-data/spots/funds': 5, 'api-data/spots/orders': 5, 'api-data/spots/orders/by-order-id': 5, 'api-data/spots/pnls': 5, 'api-data/spots/trades': 5, 'api-data/spots/trades/by-order-id': 5, 'assets/convert': 5, // transfer 'assets/transfer': 5, 'assets/spots/sub-accounts/transfer': 5, 'assets/futures/sub-accounts/transfer': 5, 'assets/quote': 5, // ?fromCurrency=<currency>&toCurrency=<currency>&amountEv=<amount> // deposit/withdraw }, 'post': { // spot 'spot/orders': 1, // swap 'orders': 1, 'g-orders': 1, 'positions/assign': 5, 'exchange/wallets/transferOut': 5, 'exchange/wallets/transferIn': 5, 'exchange/margins': 5, 'exchange/wallets/createWithdraw': 5, 'exchange/wallets/cancelWithdraw': 5, 'exchange/wallets/createWithdrawAddress': 5, // transfer 'assets/transfer': 5, 'assets/spots/sub-accounts/transfer': 5, 'assets/futures/sub-accounts/transfer': 5, 'assets/universal-transfer': 5, 'assets/convert': 5, // withdraw 'phemex-withdraw/wallets/api/createWithdraw': 5, 'phemex-withdraw/wallets/api/cancelWithdraw': 5, // ?id=<id> }, 'put': { // spot 'spot/orders/create': 1, 'spot/orders': 1, // swap 'orders/replace': 1, 'g-orders/replace': 1, 'positions/leverage': 5, 'g-positions/leverage': 5, 'g-positions/switch-pos-mode-sync': 5, 'positions/riskLimit': 5, // ?symbol=<symbol>&riskLimit=<riskLimit>&riskLimitEv=<riskLimitEv> }, 'delete': { // spot 'spot/orders': 2, 'spot/orders/all': 2, // 'spot/orders': 5, // ?symbol=<symbol>&clOrdID=<clOrdID> // swap 'orders/cancel': 1, 'orders': 1, 'orders/all': 3, 'g-orders/cancel': 1, 'g-orders': 1, 'g-orders/all': 3, // ?symbol=<symbol>&untriggered=<untriggered>&text=<text> }, }, }, 'precisionMode': TICK_SIZE, 'fees': { 'trading': { 'tierBased': false, 'percentage': true, 'taker': this.parseNumber('0.001'), 'maker': this.parseNumber('0.001'), }, }, 'features': { 'default': { 'sandbox': true, 'createOrder': { 'marginMode': false, 'triggerPrice': true, // todo 'triggerPriceType': { 'mark': true, 'last': true, 'index': true, }, 'triggerDirection': false, 'stopLossPrice': false, 'takeProfitPrice': false, 'attachedStopLossTakeProfit': undefined, 'timeInForce': { 'IOC': true, 'FOK': true, 'PO': true, 'GTD': false, }, 'hedged': false, 'leverage': false, 'marketBuyByCost': true, 'marketBuyRequiresPrice': false, 'selfTradePrevention': false, 'trailing': false, 'iceberg': false, }, 'createOrders': undefined, 'fetchMyTrades': { 'marginMode': false, 'limit': 200, 'daysBack': 100000, 'untilDays': 2, 'symbolRequired': false, }, 'fetchOrder': { 'marginMode': false, 'trigger': false, 'trailing': false, 'symbolRequired': true, }, 'fetchOpenOrders': { 'marginMode': false, 'limit': undefined, 'trigger': false, 'trailing': false, 'symbolRequired': true, }, 'fetchOrders': { 'marginMode': false, 'limit': undefined, 'daysBack': undefined, 'untilDays': undefined, 'trigger': false, 'trailing': false, 'symbolRequired': true, }, 'fetchClosedOrders': { 'marginMode': false, 'limit': 200, 'daysBack': 100000, 'daysBackCanceled': 100000, 'untilDays': 2, 'trigger': false, 'trailing': false, 'symbolRequired': false, }, 'fetchOHLCV': { 'limit': 1000, }, }, 'spot': { 'extends': 'default', }, 'forDerivatives': { 'extends': 'default', 'createOrder': { 'triggerDirection': true, 'attachedStopLossTakeProfit': { 'triggerPriceType': { 'mark': true, 'last': true, 'index': true, }, 'price': true, }, 'hedged': true, }, 'fetchOHLCV': { 'limit': 2000, }, }, 'swap': { 'linear': { 'extends': 'forDerivatives', }, 'inverse': { 'extends': 'forDerivatives', }, }, 'future': { 'linear': undefined, 'inverse': undefined, }, }, 'requiredCredentials': { 'apiKey': true, 'secret': true, }, 'exceptions': { 'exact': { // not documented '401': AuthenticationError, '412': BadRequest, '6001': BadRequest, // documented '19999': BadRequest, '10001': DuplicateOrderId, '10002': OrderNotFound, '10003': CancelPending, '10004': CancelPending, '10005': CancelPending, '11001': InsufficientFunds, '11002': InvalidOrder, '11003': InsufficientFunds, '11004': InvalidOrder, '11005': InsufficientFunds, '11006': ExchangeError, '11007': ExchangeError, '11008': ExchangeError, '11009': ExchangeError, '11010': InsufficientFunds, '11011': InvalidOrder, '11012': InvalidOrder, '11013': InvalidOrder, '11014': InvalidOrder, '11015': InvalidOrder, '11016': BadRequest, '11017': ExchangeError, '11018': ExchangeError, '11019': ExchangeError, '11020': ExchangeError, '11021': ExchangeError, '11022': AccountSuspended, '11023': ExchangeError, '11024': ExchangeError, '11025': BadRequest, '11026': ExchangeError, '11027': BadSymbol, '11028': BadSymbol, '11029': ExchangeError, '11030': ExchangeError, '11031': DDoSProtection, '11032': DDoSProtection, '11033': DuplicateOrderId, '11034': InvalidOrder, '11035': InvalidOrder, '11036': InvalidOrder, '11037': InvalidOrder, '11038': InvalidOrder, '11039': InvalidOrder, '11040': InvalidOrder, '11041': InvalidOrder, '11042': InvalidOrder, '11043': InvalidOrder, '11044': InvalidOrder, '11045': InvalidOrder, '11046': InvalidOrder, '11047': InvalidOrder, '11048': InvalidOrder, '11049': InvalidOrder, '11050': InvalidOrder, '11051': InvalidOrder, '11052': InvalidOrder, '11053': InvalidOrder, '11054': InvalidOrder, '11055': InvalidOrder, '11056': InvalidOrder, '11057': InvalidOrder, '11058': InvalidOrder, '11059': InvalidOrder, '11060': InvalidOrder, '11061': CancelPending, '11062': InvalidOrder, '11063': InvalidOrder, '11064': InvalidOrder, '11065': InvalidOrder, '11066': InvalidOrder, '11067': InvalidOrder, '11068': InvalidOrder, '11069': ExchangeError, '11070': BadSymbol, '11071': InvalidOrder, '11072': InvalidOrder, '11073': InvalidOrder, '11074': InvalidOrder, '11075': InvalidOrder, '11076': InvalidOrder, '11077': InvalidOrder, '11078': InvalidOrder, '11079': InvalidOrder, '11080': InvalidOrder, '11081': InvalidOrder, '11082': InsufficientFunds, '11083': InvalidOrder, '11084': InvalidOrder, '11085': DuplicateOrderId, '11086': InvalidOrder, '11087': InvalidOrder, '11088': InvalidOrder, '11089': InvalidOrder, '11090': InvalidOrder, '11091': InvalidOrder, '11092': InvalidOrder, '11093': InvalidOrder, '11094': InvalidOrder, '11095': InvalidOrder, '11096': InvalidOrder, '11097': BadRequest, '11098': BadRequest, '11099': ExchangeError, '11100': InsufficientFunds, '11101': InsufficientFunds, '11102': BadRequest, '11103': BadRequest, '11104': BadRequest, '11105': InsufficientFunds, '11106': InsufficientFunds, '11107': ExchangeError, '11108': InvalidOrder, '11109': InvalidOrder, '11110': InvalidOrder, '11111': InvalidOrder, '11112': InvalidOrder, '11113': BadRequest, '11114': InvalidOrder, '11115': InvalidOrder, '11116': InvalidOrder, '11117': InvalidOrder, '11118': InvalidOrder, '11119': InvalidOrder, '11120': InvalidOrder, '11121': InvalidOrder, '11122': InvalidOrder, '11123': InvalidOrder, '11124': InvalidOrder, '11125': InvalidOrder, '11126': InvalidOrder, '11128': InvalidOrder, '11129': InvalidOrder, '11130': InvalidOrder, '11131': InvalidOrder, '11132': InvalidOrder, '11133': InvalidOrder, '11134': InvalidOrder, // not documented '30000': BadRequest, '30018': BadRequest, '34003': PermissionDenied, '35104': InsufficientFunds, '39995': RateLimitExceeded, '39996': PermissionDenied, '39997': BadSymbol, // {"code":39997,"msg":"Symbol not listed sMOVRUSDT","data":null} }, 'broad': { '401 Insufficient privilege': PermissionDenied, '401 Request IP mismatch': PermissionDenied, 'Failed to find api-key': AuthenticationError, 'Missing required parameter': BadRequest, 'API Signature verification failed': AuthenticationError, 'Api key not found': AuthenticationError, // {"msg":"Api key not found 698dc9e3-6faa-4910-9476-12857e79e198","code":"10500"} }, }, 'options': { 'brokerId': 'CCXT123456', 'x-phemex-request-expiry': 60, 'createOrderByQuoteRequiresPrice': true, 'networks': { 'TRC20': 'TRX', 'ERC20': 'ETH', 'BEP20': 'BNB', }, 'defaultNetworks': { 'USDT': 'ETH', 'MKR': 'ETH', }, 'defaultSubType': 'linear', 'accountsByType': { 'spot': 'spot', 'swap': 'future', }, 'stableCoins': [ 'BUSD', 'FEI', 'TUSD', 'USD', 'USDC', 'USDD', 'USDP', 'USDT', ], 'transfer': { 'fillResponseFromRequest': true, }, 'triggerPriceTypesMap': { 'last': 'ByLastPrice', 'mark': 'ByMarkPrice', 'index': 'ByIndexPrice', 'ask': 'ByAskPrice', 'bid': 'ByBidPrice', }, }, }); } parseSafeNumber(value = undefined) { if (value === undefined) { return value; } let parts = value.split(','); value = parts.join(''); parts = value.split(' '); return this.safeNumber(parts, 0); } parseSwapMarket(market) { // // { // "symbol":"BTCUSD", // // "code":"1", // "type":"Perpetual", // "displaySymbol":"BTC / USD", // "indexSymbol":".BTC", // "markSymbol":".MBTC", // "fundingRateSymbol":".BTCFR", // "fundingRate8hSymbol":".BTCFR8H", // "contractUnderlyingAssets":"USD", // or eg. `1000 SHIB` // "settleCurrency":"BTC", // "quoteCurrency":"USD", // "contractSize":"1 USD", // "lotSize":1, // "tickSize":0.5, // "priceScale":4, // "ratioScale":8, // "pricePrecision":1, // "minPriceEp":5000, // "maxPriceEp":10000000000, // "maxOrderQty":1000000, // "status":"Listed", // "tipOrderQty":1000000, // "listTime":"1574650800000", // "majorSymbol":true, // "steps":"50", // "riskLimits":[ // {"limit":100,"initialMargin":"1.0%","initialMarginEr":1000000,"maintenanceMargin":"0.5%","maintenanceMarginEr":500000}, // {"limit":150,"initialMargin":"1.5%","initialMarginEr":1500000,"maintenanceMargin":"1.0%","maintenanceMarginEr":1000000}, // {"limit":200,"initialMargin":"2.0%","initialMarginEr":2000000,"maintenanceMargin":"1.5%","maintenanceMarginEr":1500000}, // ], // "underlyingSymbol":".BTC", // "baseCurrency":"BTC", // "settlementCurrency":"BTC", // "valueScale":8, // "defaultLeverage":0, // "maxLeverage":100, // "initMarginEr":"1000000", // "maintMarginEr":"500000", // "defaultRiskLimitEv":10000000000, // "deleverage":true, // "makerFeeRateEr":-250000, // "takerFeeRateEr":750000, // "fundingInterval":8, // "marketUrl":"https://phemex.com/trade/BTCUSD", // "description":"BTCUSD is a BTC/USD perpetual contract priced on the .BTC Index. Each contract is worth 1 USD of Bitcoin. Funding is paid and received every 8 hours. At UTC time: 00:00, 08:00, 16:00.", // } // const id = this.safeString(market, 'symbol'); const contractUnderlyingAssets = this.safeString(market, 'contractUnderlyingAssets'); const baseId = this.safeString(market, 'baseCurrency', contractUnderlyingAssets); const quoteId = this.safeString(market, 'quoteCurrency'); const settleId = this.safeString(market, 'settleCurrency'); let base = this.safeCurrencyCode(baseId); base = base.replace(' ', ''); // replace space for junction codes, eg. `1000 SHIB` const quote = this.safeCurrencyCode(quoteId); const settle = this.safeCurrencyCode(settleId); let inverse = false; if (settleId !== quoteId) { inverse = true; // some unhandled cases if (!('baseCurrency' in market) && base === quote) { base = settle; } } const priceScale = this.safeInteger(market, 'priceScale'); const ratioScale = this.safeInteger(market, 'ratioScale'); const valueScale = this.safeInteger(market, 'valueScale'); const minPriceEp = this.safeString(market, 'minPriceEp'); const maxPriceEp = this.safeString(market, 'maxPriceEp'); const makerFeeRateEr = this.safeString(market, 'makerFeeRateEr'); const takerFeeRateEr = this.safeString(market, 'takerFeeRateEr'); const status = this.safeString(market, 'status'); const contractSizeString = this.safeString(market, 'contractSize', ' '); let contractSize = undefined; if (settle === 'USDT') { contractSize = this.parseNumber('1'); } else if (contractSizeString.indexOf(' ')) { // "1 USD" // "0.005 ETH" const parts = contractSizeString.split(' '); contractSize = this.parseNumber(parts[0]); } else { // "1.0" contractSize = this.parseNumber(contractSizeString); } return this.safeMarketStructure({ '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': status === 'Listed', 'contract': true, 'linear': !inverse, 'inverse': inverse, 'taker': this.parseNumber(this.fromEn(takerFeeRateEr, ratioScale)), 'maker': this.parseNumber(this.fromEn(makerFeeRateEr, ratioScale)), 'contractSize': contractSize, 'expiry': undefined, 'expiryDatetime': undefined, 'strike': undefined, 'optionType': undefined, 'priceScale': priceScale, 'valueScale': valueScale, 'ratioScale': ratioScale, 'precision': { 'amount': this.safeNumber2(market, 'lotSize', 'qtyStepSize'), 'price': this.safeNumber(market, 'tickSize'), }, 'limits': { 'leverage': { 'min': this.parseNumber('1'), 'max': this.safeNumber(market, 'maxLeverage'), }, 'amount': { 'min': undefined, 'max': undefined, }, 'price': { 'min': this.parseNumber(this.fromEn(minPriceEp, priceScale)), 'max': this.parseNumber(this.fromEn(maxPriceEp, priceScale)), }, 'cost': { 'min': undefined, 'max': this.parseNumber(this.safeString(market, 'maxOrderQty')), }, }, 'created': undefined, 'info': market, }); } parseSpotMarket(market) { // // { // "symbol":"sBTCUSDT", // "code":1001, // "type":"Spot", // "displaySymbol":"BTC / USDT", // "quoteCurrency":"USDT", // "priceScale":8, // "ratioScale":8, // "pricePrecision":2, // "baseCurrency":"BTC", // "baseTickSize":"0.000001 BTC", // "baseTickSizeEv":100, // "quoteTickSize":"0.01 USDT", // "quoteTickSizeEv":1000000, // "baseQtyPrecision":6, // "quoteQtyPrecision":2, // "minOrderValue":"10 USDT", // "minOrderValueEv":1000000000, // "maxBaseOrderSize":"1000 BTC", // "maxBaseOrderSizeEv":100000000000, // "maxOrderValue":"5,000,000 USDT", // "maxOrderValueEv":500000000000000, // "defaultTakerFee":"0.001", // "defaultTakerFeeEr":100000, // "defaultMakerFee":"0.001", // "defaultMakerFeeEr":100000, // "description":"BTCUSDT is a BTC/USDT spot trading pair. Minimum order value is 1 USDT", // "status":"Listed", // "tipOrderQty":2, // "listTime":1589338800000, // "buyPriceUpperLimitPct":110, // "sellPriceLowerLimitPct":90, // "leverage":5 // }, // const type = this.safeStringLower(market, 'type'); const id = this.safeString(market, 'symbol'); const quoteId = this.safeString(market, 'quoteCurrency'); const baseId = this.safeString(market, 'baseCurrency'); const base = this.safeCurrencyCode(baseId); const quote = this.safeCurrencyCode(quoteId); const status = this.safeString(market, 'status'); const precisionAmount = this.parseSafeNumber(this.safeString(market, 'baseTickSize')); const precisionPrice = this.parseSafeNumber(this.safeString(market, 'quoteTickSize')); return this.safeMarketStructure({ 'id': id, 'symbol': base + '/' + quote, 'base': base, 'quote': quote, 'settle': undefined, 'baseId': baseId, 'quoteId': quoteId, 'settleId': undefined, 'type': type, 'spot': true, 'margin': false, 'swap': false, 'future': false, 'option': false, 'active': status === 'Listed', 'contract': false, 'linear': undefined, 'inverse': undefined, 'taker': this.safeNumber(market, 'defaultTakerFee'), 'maker': this.safeNumber(market, 'defaultMakerFee'), 'contractSize': undefined, 'expiry': undefined, 'expiryDatetime': undefined, 'strike': undefined, 'optionType': undefined, 'priceScale': this.safeInteger(market, 'priceScale'), 'valueScale': this.safeInteger(market, 'valueScale'), 'ratioScale': this.safeInteger(market, 'ratioScale'), 'precision': { 'amount': precisionAmount, 'price': precisionPrice, }, 'limits': { 'leverage': { 'min': undefined, 'max': undefined, }, 'amount': { 'min': precisionAmount, 'max': this.parseSafeNumber(this.safeString(market, 'maxBaseOrderSize')), }, 'price': { 'min': precisionPrice, 'max': undefined, }, 'cost': { 'min': this.parseSafeNumber(this.safeString(market, 'minOrderValue')), 'max': this.parseSafeNumber(this.safeString(market, 'maxOrderValue')), }, }, 'created': this.safeInteger(market, 'listTime'), 'info': market, }); } /** * @method * @name phemex#fetchMarkets * @description retrieves data on all markets for phemex * @see https://phemex-docs.github.io/#query-product-information-3 * @param {object} [params] extra parameters specific to the exchange API endpoint * @returns {object[]} an array of objects representing market data */ async fetchMarkets(params = {}) { const v2ProductsPromise = this.v2GetPublicProducts(params); // // { // "code":0, // "msg":"", // "data":{ // "currencies":[ // {"currency":"BTC","name":"Bitcoin","code":1,"valueScale":8,"minValueEv":1,"maxValueEv":5000000000000000000,"needAddrTag":0,"status":"Listed","displayCurrency":"BTC","inAssetsDisplay":1,"perpetual":0,"stableCoin":0,"assetsPrecision":8}, // {"currency":"USD","name":"USD","code":2,"valueScale":4,"minValueEv":1,"maxValueEv":5000000000000000000,"needAddrTag":0,"status":"Listed","displayCurrency":"USD","inAssetsDisplay":1,"perpetual":0,"stableCoin":0,"assetsPrecision":2}, // {"currency":"USDT","name":"TetherUS","code":3,"valueScale":8,"minValueEv":1,"maxValueEv":5000000000000000000,"needAddrTag":0,"status":"Listed","displayCurrency":"USDT","inAssetsDisplay":1,"perpetual":2,"stableCoin":1,"assetsPrecision":8}, // ], // "products":[ // { // "symbol":"BTCUSD", // "code":1, // "type":"Perpetual" // "displaySymbol":"BTC / USD", // "indexSymbol":".BTC", // "markSymbol":".MBTC", // "fundingRateSymbol":".BTCFR", // "fundingRate8hSymbol":".BTCFR8H", // "contractUnderlyingAssets":"USD", // "settleCurrency":"BTC", // "quoteCurrency":"USD", // "contractSize":1.0, // "lotSize":1, // "tickSize":0.5, // "priceScale":4, // "ratioScale":8, // "pricePrecision":1, // "minPriceEp":5000, // "maxPriceEp":10000000000, // "maxOrderQty":1000000, // "description":"BTC/USD perpetual contracts are priced on the .BTC Index. Each contract is worth 1 USD. Funding fees are paid and received every 8 hours at UTC time: 00:00, 08:00 and 16:00.", // "status":"Listed", // "tipOrderQty":1000000, // "listTime":1574650800000, // "majorSymbol":true, // "defaultLeverage":"-10", // "fundingInterval":28800, // "maxLeverage":100 // }, // { // "symbol":"sBTCUSDT", // "code":1001, // "type":"Spot", // "displaySymbol":"BTC / USDT", // "quoteCurrency":"USDT", // "priceScale":8, // "ratioScale":8, // "pricePrecision":2, // "baseCurrency":"BTC", // "baseTickSize":"0.000001 BTC", // "baseTickSizeEv":100, // "quoteTickSize":"0.01 USDT", // "quoteTickSizeEv":1000000, // "baseQtyPrecision":6, // "quoteQtyPrecision":2, // "minOrderValue":"10 USDT", // "minOrderValueEv":1000000000, // "maxBaseOrderSize":"1000 BTC", // "maxBaseOrderSizeEv":100000000000, // "maxOrderValue":"5,000,000 USDT", // "maxOrderValueEv":500000000000000, // "defaultTakerFee":"0.001", // "defaultTakerFeeEr":100000, // "defaultMakerFee":"0.001", // "defaultMakerFeeEr":100000, // "description":"BTCUSDT is a BTC/USDT spot trading pair. Minimum order value is 1 USDT", // "status":"Listed", // "tipOrderQty":2, // "listTime":1589338800000, // "buyPriceUpperLimitPct":110, // "sellPriceLowerLimitPct":90, // "leverage":5 // }, // ], // "perpProductsV2":[ // { // "symbol":"BTCUSDT", // "code":41541, // "type":"PerpetualV2", // "displaySymbol":"BTC / USDT", // "indexSymbol":".BTCUSDT", // "markSymbol":".MBTCUSDT", // "fundingRateSymbol":".BTCUSDTFR", // "fundingRate8hSymbol":".BTCUSDTFR8H", // "contractUnderlyingAssets":"BTC", // "settleCurrency":"USDT", // "quoteCurrency":"USDT", // "tickSize":"0.1", // "priceScale":0, // "ratioScale":0, // "pricePrecision":1, // "baseCurrency":"BTC", // "description":"BTC/USDT perpetual contracts are priced on the .BTCUSDT Index. Each contract is worth 1 BTC. Funding fees are paid and received every 8 hours at UTC time: 00:00, 08:00 and 16:00.", // "status":"Listed", // "tipOrderQty":0, // "listTime":1668225600000, // "majorSymbol":true, // "defaultLeverage":"-10", // "fundingInterval":28800, // "maxLeverage":100, // "maxOrderQtyRq":"1000", // "maxPriceRp":"2000000000", // "minOrderValueRv":"1", // "minPriceRp":"1000.0", // "qtyPrecision":3, // "qtyStepSize":"0.001", // "tipOrderQtyRq":"200", // "maxOpenPosLeverage":100.0 // }, // ], // "riskLimits":[ // { // "symbol":"BTCUSD", // "steps":"50", // "riskLimits":[ // {"limit":100,"initialMargin":"1.0%","initialMarginEr":1000000,"maintenanceMargin":"0.5%","maintenanceMarginEr":500000}, // {"limit":150,"initialMargin":"1.5%","initialMarginEr":1500000,"maintenanceMargin":"1.0%","maintenanceMarginEr":1000000}, // {"limit":200,"initialMargin":"2.0%","initialMarginEr":2000000,"maintenanceMargin":"1.5%","maintenanceMarginEr":1500000}, // ] // }, // ], // "leverages":[ // {"initialMargin":"1.0%","initialMarginEr":1000000,"options":[1,2,3,5,10,25,50,100]}, // {"initialMargin":"1.5%","initialMarginEr":1500000,"options":[1,2,3,5,10,25,50,66]}, // {"initialMargin":"2.0%","initialMarginEr":2000000,"options":[1,2,3,5,10,25,33,50]}, // ], // "riskLimitsV2":[ // { // "symbol":"BTCUSDT", // "steps":"2000K", // "riskLimits":[ // {"limit":2000000,"initialMarginRr":"0.01","maintenanceMarginRr":"0.005"},, // {"limit":4000000,"initialMarginRr":"0.015","maintenanceMarginRr":"0.0075"}, // {"limit":6000000,"initialMarginRr":"0.02","maintenanceMarginRr":"0.01"}, // ] // }, // ], // "leveragesV2":[ // {"options":[1.0,2.0,3.0,5.0,10.0,25.0,50.0,100.0],"initialMarginRr":"0.01"}, // {"options":[1.0,2.0,3.0,5.0,10.0,25.0,50.0,66.67],"initialMarginRr":"0.015"}, // {"options":[1.0,2.0,3.0,5.0,10.0,25.0,33.0,50.0],"initialMarginRr":"0.02"}, // ], // "ratioScale":8, // "md5Checksum":"5c6604814d3c1bafbe602c3d11a7e8bf", // } // } // const v1ProductsPromise = this.v1GetExchangePublicProducts(params); const [v2Products, v1Products] = await Promise.all([v2ProductsPromise, v1ProductsPromise]); const v1ProductsData = this.safeValue(v1Products, 'data', []); // // { // "code":0, // "msg":"OK", // "data":[ // { // "symbol":"BTCUSD", // "underlyingSymbol":".BTC", // "quoteCurrency":"USD", // "baseCurrency":"BTC", // "settlementCurrency":"BTC", // "maxOrderQty":1000000, // "maxPriceEp":100000000000000, // "lotSize":1, // "tickSize":"0.5", // "contractSize":"1 USD", // "priceScale":4, // "ratioScale":8, // "valueScale":8, // "defaultLeverage":0, // "maxLeverage":100, // "initMarginEr":"1000000", // "maintMarginEr":"500000", // "defaultRiskLimitEv":10000000000, // "deleverage":true, // "makerFeeRateEr":-250000, // "takerFeeRateEr":750000, // "fundingInterval":8, // "marketUrl":"https://phemex.com/trade/BTCUSD", // "description":"BTCUSD is a BTC/USD perpetual contract priced on the .BTC Index. Each contract is worth 1 USD of Bitcoin. Funding is paid and received every 8 hours. At UTC time: 00:00, 08:00, 16:00.", // "type":"Perpetual" // }, // ] // } // const v2ProductsData = this.safeDict(v2Products, 'data', {}); let products = this.safeList(v2ProductsData, 'products', []); const perpetualProductsV2 = this.safeList(v2ProductsData, 'perpProductsV2', []); products = this.arrayConcat(products, perpetualProductsV2); let riskLimits = this.safeList(v2ProductsData, 'riskLimits', []); const riskLimitsV2 = this.safeList(v2ProductsData, 'riskLimitsV2', []); riskLimits = this.arrayConcat(riskLimits, riskLimitsV2); const currencies = this.safeList(v2ProductsData, 'currencies', []); const riskLimitsById = this.indexBy(riskLimits, 'symbol'); const v1ProductsById = this.indexBy(v1ProductsData, 'symbol'); const currenciesByCode = this.indexBy(currencies, 'currency'); const result = []; for (let i = 0; i < products.length; i++) { let market = products[i]; const type = this.safeStringLower(market, 'type'); if ((type === 'perpetual') || (type === 'perpetualv2') || (type === 'perpetualpilot')) { const id = this.safeString(market, 'symbol'); const riskLimitValues = this.safe