ccxt
Version:
1,086 lines (1,084 loc) • 239 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/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