ccxt
Version:
767 lines (765 loc) • 281 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 { sha256 } from '@noble/hashes/sha2.js';
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';
// ----------------------------------------------------------------------------
/**
* @class phemex
* @augments Exchange
*/
export default class phemex extends Exchange {
describe() {
return this.deepExtend(super.describe(), {
'id': 'phemex',
'name': 'Phemex',
'countries': ['CN'], // China
'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,
'borrowCrossMargin': false,
'borrowIsolatedMargin': false,
'borrowMargin': false,
'cancelAllOrders': true,
'cancelOrder': true,
'closePosition': false,
'createConvertTrade': true,
'createOrder': true,
'createReduceOnlyOrder': true,
'createStopLimitOrder': true,
'createStopMarketOrder': true,
'createStopOrder': true,
'editOrder': true,
'fetchAllGreeks': false,
'fetchBalance': true,
'fetchBorrowInterest': false,
'fetchBorrowRate': false,
'fetchBorrowRateHistories': false,
'fetchBorrowRateHistory': false,
'fetchBorrowRates': false,
'fetchBorrowRatesPerSymbol': 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,
'fetchGreeks': 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,
'fetchOption': false,
'fetchOptionChain': false,
'fetchOrder': true,
'fetchOrderBook': true,
'fetchOrders': true,
'fetchPositionADLRank': true,
'fetchPositions': true,
'fetchPositionsADLRank': true,
'fetchPositionsRisk': false,
'fetchPremiumIndexOHLCV': false,
'fetchTicker': true,
'fetchTickers': true,
'fetchTrades': true,
'fetchTradingFee': false,
'fetchTradingFees': false,
'fetchTransfers': true,
'fetchVolatilityHistory': false,
'fetchWithdrawals': true,
'reduceMargin': false,
'repayCrossMargin': false,
'repayIsolatedMargin': 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, // spot + contracts
'cfg/fundingRates': 5,
'products': 5, // contracts only
'nomics/trades': 5, // ?market=<symbol>&since=<since>
'md/kline': 5, // ?from=1589811875&resolution=1800&symbol=sBTCUSDT&to=1592457935
'md/v2/kline/list': 5, // perpetual api ?symbol=<symbol>&to=<to>&from=<from>&resolution=<resolution>
'md/v2/kline': 5, // ?symbol=<symbol>&resolution=<resolution>&limit=<limit>
'md/v2/kline/last': 5, // perpetual ?symbol=<symbol>&resolution=<resolution>&limit=<limit>
'md/orderbook': 5, // ?symbol=<symbol>
'md/trade': 5, // ?symbol=<symbol>
'md/spot/ticker/24hr': 5, // ?symbol=<symbol>
'exchange/public/cfg/chain-settings': 5, // ?currency=<currency>
},
},
'v1': {
'get': {
'md/fullbook': 5, // ?symbol=<symbol>
'md/orderbook': 5, // ?symbol=<symbol>
'md/trade': 5, // ?symbol=<symbol>&id=<id>
'md/ticker/24hr': 5, // ?symbol=<symbol>&id=<id>
'md/ticker/24hr/all': 5, // ?id=<id>
'md/spot/ticker/24hr': 5, // ?symbol=<symbol>&id=<id>
'md/spot/ticker/24hr/all': 5, // ?symbol=<symbol>&id=<id>
'exchange/public/products': 5, // contracts only
'api-data/public/data/funding-rate-history': 5,
},
},
'v2': {
'get': {
'public/products': 5,
'public/products-plus': 5,
'md/v2/orderbook': 5, // ?symbol=<symbol>&id=<id>
'md/v2/trade': 5, // ?symbol=<symbol>&id=<id>
'md/v2/ticker/24hr': 5, // ?symbol=<symbol>&id=<id>
'md/v2/ticker/24hr/all': 5, // ?id=<id>
'api-data/public/data/funding-rate-history': 5,
},
},
'private': {
'get': {
// spot
'spot/orders/active': 1, // ?symbol=<symbol>&orderID=<orderID>
// 'spot/orders/active': 5, // ?symbol=<symbol>&clOrDID=<clOrdID>
'spot/orders': 1, // ?symbol=<symbol>
'spot/wallets': 5, // ?currency=<currency>
'exchange/spot/order': 5, // ?symbol=<symbol>&ordStatus=<ordStatus5,orderStatus2>ordType=<ordType5,orderType2>&start=<start>&end=<end>&limit=<limit>&offset=<offset>
'exchange/spot/order/trades': 5, // ?symbol=<symbol>&start=<start>&end=<end>&limit=<limit>&offset=<offset>
'exchange/order/v2/orderList': 5, // ?symbol=<symbol>¤cy=<currency>&ordStatus=<ordStatus>&ordType=<ordType>&start=<start>&end=<end>&offset=<offset>&limit=<limit>&withCount=<withCount></withCount>
'exchange/order/v2/tradingList': 5, // ?symbol=<symbol>¤cy=<currency>&execType=<execType>&offset=<offset>&limit=<limit>&withCount=<withCount>
// swap
'accounts/accountPositions': 1, // ?currency=<currency>
'g-accounts/accountPositions': 1, // ?currency=<currency>
'g-accounts/positions': 25, // ?currency=<currency>
'g-accounts/risk-unit': 1,
'api-data/futures/funding-fees': 5, // ?symbol=<symbol>
'api-data/g-futures/funding-fees': 5, // ?symbol=<symbol>
'api-data/futures/orders': 5, // ?symbol=<symbol>
'api-data/g-futures/orders': 5, // ?symbol=<symbol>
'api-data/futures/orders/by-order-id': 5, // ?symbol=<symbol>
'api-data/g-futures/orders/by-order-id': 5, // ?symbol=<symbol>
'api-data/futures/trades': 5, // ?symbol=<symbol>
'api-data/g-futures/trades': 5, // ?symbol=<symbol>
'api-data/futures/trading-fees': 5, // ?symbol=<symbol>
'api-data/g-futures/trading-fees': 5, // ?symbol=<symbol>
'api-data/futures/v2/tradeAccountDetail': 5, // ?currency=<currency>&type=<type>&limit=<limit>&offset=<offset>&start=<start>&end=<end>&withCount=<withCount>
'api-data/g-futures/closedPosition': 5,
'g-orders/activeList': 1, // ?symbol=<symbol>
'orders/activeList': 1, // ?symbol=<symbol>
'exchange/order/list': 5, // ?symbol=<symbol>&start=<start>&end=<end>&offset=<offset>&limit=<limit>&ordStatus=<ordStatus>&withCount=<withCount>
'exchange/order': 5, // ?symbol=<symbol>&orderID=<orderID5,orderID2>
// 'exchange/order': 5, // ?symbol=<symbol>&clOrdID=<clOrdID5,clOrdID2>
'exchange/order/trade': 5, // ?symbol=<symbol>&start=<start>&end=<end>&limit=<limit>&offset=<offset>&withCount=<withCount>
'phemex-user/users/children': 5, // ?offset=<offset>&limit=<limit>&withCount=<withCount>
'phemex-user/wallets/v2/depositAddress': 5, // ?_t=1592722635531¤cy=USDT
'phemex-user/wallets/tradeAccountDetail': 5, // ?bizCode=¤cy=&end=1642443347321&limit=10&offset=0&side=&start=1&type=4&withCount=true
'phemex-deposit/wallets/api/depositAddress': 5, // ?currency=<currency>&chainName=<chainName>
'phemex-deposit/wallets/api/depositHist': 5, // ?currency=<currency>&offset=<offset>&limit=<limit>&withCount=<withCount>
'phemex-deposit/wallets/api/chainCfg': 5, // ?currency=<currency>
'phemex-withdraw/wallets/api/withdrawHist': 5, // ?currency=<currency>&chainName=<chainNameList>&offset=<offset>&limit=<limit>&withCount=<withCount>
'phemex-withdraw/wallets/api/asset/info': 5, // ?currency=<currency>&amount=<amount>
'phemex-user/order/closedPositionList': 5, // ?currency=USD&limit=10&offset=0&symbol=&withCount=true
'exchange/margins/transfer': 5, // ?start=<start>&end=<end>&offset=<offset>&limit=<limit>&withCount=<withCount>
'exchange/wallets/confirm/withdraw': 5, // ?code=<withdrawConfirmCode>
'exchange/wallets/withdrawList': 5, // ?currency=<currency>&limit=<limit>&offset=<offset>&withCount=<withCount>
'exchange/wallets/depositList': 5, // ?currency=<currency>&offset=<offset>&limit=<limit>
'exchange/wallets/v2/depositAddress': 5, // ?currency=<currency>
'api-data/spots/funds': 5, // ?currency=<currency>&start=<start>&end=<end>&limit=<limit>&offset=<offset>
'api-data/spots/orders': 5, // ?symbol=<symbol>
'api-data/spots/orders/by-order-id': 5, // ?symbol=<symbol>&oderId=<orderID>&clOrdID=<clOrdID>
'api-data/spots/pnls': 5,
'api-data/spots/trades': 5, // ?symbol=<symbol>
'api-data/spots/trades/by-order-id': 5, // ?symbol=<symbol>&oderId=<orderID>&clOrdID=<clOrdID>
'assets/convert': 5, // ?startTime=<startTime>&endTime=<endTime>&limit=<limit>&offset=<offset>
// transfer
'assets/transfer': 5, // ?currency=<currency>&start=<start>&end=<end>&limit=<limit>&offset=<offset>
'assets/spots/sub-accounts/transfer': 5, // ?currency=<currency>&start=<start>&end=<end>&limit=<limit>&offset=<offset>
'assets/futures/sub-accounts/transfer': 5, // ?currency=<currency>&start=<start>&end=<end>&limit=<limit>&offset=<offset>
'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, // ?symbol=<symbol>&posBalance=<posBalance>&posBalanceEv=<posBalanceEv>
'exchange/wallets/transferOut': 5,
'exchange/wallets/transferIn': 5,
'exchange/margins': 5,
'exchange/wallets/createWithdraw': 5, // ?otpCode=<otpCode>
'exchange/wallets/cancelWithdraw': 5,
'exchange/wallets/createWithdrawAddress': 5, // ?otpCode={optCode}
// transfer
'assets/transfer': 5,
'assets/spots/sub-accounts/transfer': 5, // for sub-account only
'assets/futures/sub-accounts/transfer': 5, // for sub-account only
'assets/universal-transfer': 5, // for Main account only
'assets/convert': 5,
// withdraw
'phemex-withdraw/wallets/api/createWithdraw': 5, // ?currency=<currency>&address=<address>&amount=<amount>&addressTag=<addressTag>&chainName=<chainName>
'phemex-withdraw/wallets/api/cancelWithdraw': 5, // ?id=<id>
},
'put': {
// spot
'spot/orders/create': 1, // ?symbol=<symbol>&trigger=<trigger>&clOrdID=<clOrdID>&priceEp=<priceEp>&baseQtyEv=<baseQtyEv>"eQtyEv=<quoteQtyEv>&stopPxEp=<stopPxEp>&text=<text>&side=<side>&qtyType=<qtyType>&ordType=<ordType>&timeInForce=<timeInForce>&execInst=<execInst>
'spot/orders': 1, // ?symbol=<symbol>&orderID=<orderID>&origClOrdID=<origClOrdID>&clOrdID=<clOrdID>&priceEp=<priceEp>&baseQtyEV=<baseQtyEV>"eQtyEv=<quoteQtyEv>&stopPxEp=<stopPxEp>
// swap
'orders/replace': 1, // ?symbol=<symbol>&orderID=<orderID>&origClOrdID=<origClOrdID>&clOrdID=<clOrdID>&price=<price>&priceEp=<priceEp>&orderQty=<orderQty>&stopPx=<stopPx>&stopPxEp=<stopPxEp>&takeProfit=<takeProfit>&takeProfitEp=<takeProfitEp>&stopLoss=<stopLoss>&stopLossEp=<stopLossEp>&pegOffsetValueEp=<pegOffsetValueEp>&pegPriceType=<pegPriceType>
'g-orders/replace': 1, // ?symbol=<symbol>&orderID=<orderID>&origClOrdID=<origClOrdID>&clOrdID=<clOrdID>&price=<price>&priceEp=<priceEp>&orderQty=<orderQty>&stopPx=<stopPx>&stopPxEp=<stopPxEp>&takeProfit=<takeProfit>&takeProfitEp=<takeProfitEp>&stopLoss=<stopLoss>&stopLossEp=<stopLossEp>&pegOffsetValueEp=<pegOffsetValueEp>&pegPriceType=<pegPriceType>
'g-orders/create': 1,
'positions/leverage': 5, // ?symbol=<symbol>&leverage=<leverage>&leverageEr=<leverageEr>
'g-positions/leverage': 5, // ?symbol=<symbol>&leverage=<leverage>&leverageEr=<leverageEr>
'g-positions/switch-pos-mode-sync': 5, // ?symbol=<symbol>&targetPosMode=<targetPosMode>
'positions/riskLimit': 5, // ?symbol=<symbol>&riskLimit=<riskLimit>&riskLimitEv=<riskLimitEv>
},
'delete': {
// spot
'spot/orders': 2, // ?symbol=<symbol>&orderID=<orderID>
'spot/orders/all': 2, // ?symbol=<symbol>&untriggered=<untriggered>
// 'spot/orders': 5, // ?symbol=<symbol>&clOrdID=<clOrdID>
// swap
'orders/cancel': 1, // ?symbol=<symbol>&orderID=<orderID>
'orders': 1, // ?symbol=<symbol>&orderID=<orderID1>,<orderID2>,<orderID3>
'orders/all': 3, // ?symbol=<symbol>&untriggered=<untriggered>&text=<text>
'g-orders/cancel': 1, // ?symbol=<symbol>&orderID=<orderID>
'g-orders': 1, // ?symbol=<symbol>&orderID=<orderID1>,<orderID2>,<orderID3>
'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, // todo
'takeProfitPrice': false, // todo
'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, // todo implement
'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, // {"code":"401","msg":"401 Failed to load API KEY."}
'412': BadRequest, // {"code":412,"msg":"Missing parameter - resolution","data":null}
'6001': BadRequest, // {"error":{"code":6001,"message":"invalid argument"},"id":null,"result":null}
// documented
'19999': BadRequest, // REQUEST_IS_DUPLICATED Duplicated request ID
'10001': DuplicateOrderId, // OM_DUPLICATE_ORDERID Duplicated order ID
'10002': OrderNotFound, // OM_ORDER_NOT_FOUND Cannot find order ID
'10003': CancelPending, // OM_ORDER_PENDING_CANCEL Cannot cancel while order is already in pending cancel status
'10004': CancelPending, // OM_ORDER_PENDING_REPLACE Cannot cancel while order is already in pending cancel status
'10005': CancelPending, // OM_ORDER_PENDING Cannot cancel while order is already in pending cancel status
'11001': InsufficientFunds, // TE_NO_ENOUGH_AVAILABLE_BALANCE Insufficient available balance
'11002': InvalidOrder, // TE_INVALID_RISK_LIMIT Invalid risk limit value
'11003': InsufficientFunds, // TE_NO_ENOUGH_BALANCE_FOR_NEW_RISK_LIMIT Insufficient available balance
'11004': InvalidOrder, // TE_INVALID_LEVERAGE invalid input or new leverage is over maximum allowed leverage
'11005': InsufficientFunds, // TE_NO_ENOUGH_BALANCE_FOR_NEW_LEVERAGE Insufficient available balance
'11006': ExchangeError, // TE_CANNOT_CHANGE_POSITION_MARGIN_WITHOUT_POSITION Position size is zero. Cannot change margin
'11007': ExchangeError, // TE_CANNOT_CHANGE_POSITION_MARGIN_FOR_CROSS_MARGIN Cannot change margin under CrossMargin
'11008': ExchangeError, // TE_CANNOT_REMOVE_POSITION_MARGIN_MORE_THAN_ADDED exceeds the maximum removable Margin
'11009': ExchangeError, // TE_CANNOT_REMOVE_POSITION_MARGIN_DUE_TO_UNREALIZED_PNL exceeds the maximum removable Margin
'11010': InsufficientFunds, // TE_CANNOT_ADD_POSITION_MARGIN_DUE_TO_NO_ENOUGH_AVAILABLE_BALANCE Insufficient available balance
'11011': InvalidOrder, // TE_REDUCE_ONLY_ABORT Cannot accept reduce only order
'11012': InvalidOrder, // TE_REPLACE_TO_INVALID_QTY Order quantity Error
'11013': InvalidOrder, // TE_CONDITIONAL_NO_POSITION Position size is zero. Cannot determine conditional order's quantity
'11014': InvalidOrder, // TE_CONDITIONAL_CLOSE_POSITION_WRONG_SIDE Close position conditional order has the same side
'11015': InvalidOrder, // TE_CONDITIONAL_TRIGGERED_OR_CANCELED
'11016': BadRequest, // TE_ADL_NOT_TRADING_REQUESTED_ACCOUNT Request is routed to the wrong trading engine
'11017': ExchangeError, // TE_ADL_CANNOT_FIND_POSITION Cannot find requested position on current account
'11018': ExchangeError, // TE_NO_NEED_TO_SETTLE_FUNDING The current account does not need to pay a funding fee
'11019': ExchangeError, // TE_FUNDING_ALREADY_SETTLED The current account already pays the funding fee
'11020': ExchangeError, // TE_CANNOT_TRANSFER_OUT_DUE_TO_BONUS Withdraw to wallet needs to remove all remaining bonus. However if bonus is used by position or order cost, withdraw fails.
'11021': ExchangeError, // TE_INVALID_BONOUS_AMOUNT // Grpc command cannot be negative number Invalid bonus amount
'11022': AccountSuspended, // TE_REJECT_DUE_TO_BANNED Account is banned
'11023': ExchangeError, // TE_REJECT_DUE_TO_IN_PROCESS_OF_LIQ Account is in the process of liquidation
'11024': ExchangeError, // TE_REJECT_DUE_TO_IN_PROCESS_OF_ADL Account is in the process of auto-deleverage
'11025': BadRequest, // TE_ROUTE_ERROR Request is routed to the wrong trading engine
'11026': ExchangeError, // TE_UID_ACCOUNT_MISMATCH
'11027': BadSymbol, // TE_SYMBOL_INVALID Invalid number ID or name
'11028': BadSymbol, // TE_CURRENCY_INVALID Invalid currency ID or name
'11029': ExchangeError, // TE_ACTION_INVALID Unrecognized request type
'11030': ExchangeError, // TE_ACTION_BY_INVALID
'11031': DDoSProtection, // TE_SO_NUM_EXCEEDS Number of total conditional orders exceeds the max limit
'11032': DDoSProtection, // TE_AO_NUM_EXCEEDS Number of total active orders exceeds the max limit
'11033': DuplicateOrderId, // TE_ORDER_ID_DUPLICATE Duplicated order ID
'11034': InvalidOrder, // TE_SIDE_INVALID Invalid side
'11035': InvalidOrder, // TE_ORD_TYPE_INVALID Invalid OrderType
'11036': InvalidOrder, // TE_TIME_IN_FORCE_INVALID Invalid TimeInForce
'11037': InvalidOrder, // TE_EXEC_INST_INVALID Invalid ExecType
'11038': InvalidOrder, // TE_TRIGGER_INVALID Invalid trigger type
'11039': InvalidOrder, // TE_STOP_DIRECTION_INVALID Invalid stop direction type
'11040': InvalidOrder, // TE_NO_MARK_PRICE Cannot get valid mark price to create conditional order
'11041': InvalidOrder, // TE_NO_INDEX_PRICE Cannot get valid index price to create conditional order
'11042': InvalidOrder, // TE_NO_LAST_PRICE Cannot get valid last market price to create conditional order
'11043': InvalidOrder, // TE_RISING_TRIGGER_DIRECTLY Conditional order would be triggered immediately
'11044': InvalidOrder, // TE_FALLING_TRIGGER_DIRECTLY Conditional order would be triggered immediately
'11045': InvalidOrder, // TE_TRIGGER_PRICE_TOO_LARGE Conditional order trigger price is too high
'11046': InvalidOrder, // TE_TRIGGER_PRICE_TOO_SMALL Conditional order trigger price is too low
'11047': InvalidOrder, // TE_BUY_TP_SHOULD_GT_BASE TakeProfile BUY conditional order trigger price needs to be greater than reference price
'11048': InvalidOrder, // TE_BUY_SL_SHOULD_LT_BASE StopLoss BUY condition order price needs to be less than the reference price
'11049': InvalidOrder, // TE_BUY_SL_SHOULD_GT_LIQ StopLoss BUY condition order price needs to be greater than liquidation price or it will not trigger
'11050': InvalidOrder, // TE_SELL_TP_SHOULD_LT_BASE TakeProfile SELL conditional order trigger price needs to be less than reference price
'11051': InvalidOrder, // TE_SELL_SL_SHOULD_LT_LIQ StopLoss SELL condition order price needs to be less than liquidation price or it will not trigger
'11052': InvalidOrder, // TE_SELL_SL_SHOULD_GT_BASE StopLoss SELL condition order price needs to be greater than the reference price
'11053': InvalidOrder, // TE_PRICE_TOO_LARGE
'11054': InvalidOrder, // TE_PRICE_WORSE_THAN_BANKRUPT Order price cannot be more aggressive than bankrupt price if this order has instruction to close a position
'11055': InvalidOrder, // TE_PRICE_TOO_SMALL Order price is too low
'11056': InvalidOrder, // TE_QTY_TOO_LARGE Order quantity is too large
'11057': InvalidOrder, // TE_QTY_NOT_MATCH_REDUCE_ONLY Does not allow ReduceOnly order without position
'11058': InvalidOrder, // TE_QTY_TOO_SMALL Order quantity is too small
'11059': InvalidOrder, // TE_TP_SL_QTY_NOT_MATCH_POS Position size is zero. Cannot accept any TakeProfit or StopLoss order
'11060': InvalidOrder, // TE_SIDE_NOT_CLOSE_POS TakeProfit or StopLoss order has wrong side. Cannot close position
'11061': CancelPending, // TE_ORD_ALREADY_PENDING_CANCEL Repeated cancel request
'11062': InvalidOrder, // TE_ORD_ALREADY_CANCELED Order is already canceled
'11063': InvalidOrder, // TE_ORD_STATUS_CANNOT_CANCEL Order is not able to be canceled under current status
'11064': InvalidOrder, // TE_ORD_ALREADY_PENDING_REPLACE Replace request is rejected because order is already in pending replace status
'11065': InvalidOrder, // TE_ORD_REPLACE_NOT_MODIFIED Replace request does not modify any parameters of the order
'11066': InvalidOrder, // TE_ORD_STATUS_CANNOT_REPLACE Order is not able to be replaced under current status
'11067': InvalidOrder, // TE_CANNOT_REPLACE_PRICE Market conditional order cannot change price
'11068': InvalidOrder, // TE_CANNOT_REPLACE_QTY Condtional order for closing position cannot change order quantity, since the order quantity is determined by position size already
'11069': ExchangeError, // TE_ACCOUNT_NOT_IN_RANGE The account ID in the request is not valid or is not in the range of the current process
'11070': BadSymbol, // TE_SYMBOL_NOT_IN_RANGE The symbol is invalid
'11071': InvalidOrder, // TE_ORD_STATUS_CANNOT_TRIGGER
'11072': InvalidOrder, // TE_TKFR_NOT_IN_RANGE The fee value is not valid
'11073': InvalidOrder, // TE_MKFR_NOT_IN_RANGE The fee value is not valid
'11074': InvalidOrder, // TE_CANNOT_ATTACH_TP_SL Order request cannot contain TP/SL parameters when the account already has positions
'11075': InvalidOrder, // TE_TP_TOO_LARGE TakeProfit price is too large
'11076': InvalidOrder, // TE_TP_TOO_SMALL TakeProfit price is too small
'11077': InvalidOrder, // TE_TP_TRIGGER_INVALID Invalid trigger type
'11078': InvalidOrder, // TE_SL_TOO_LARGE StopLoss price is too large
'11079': InvalidOrder, // TE_SL_TOO_SMALL StopLoss price is too small
'11080': InvalidOrder, // TE_SL_TRIGGER_INVALID Invalid trigger type
'11081': InvalidOrder, // TE_RISK_LIMIT_EXCEEDS Total potential position breaches current risk limit
'11082': InsufficientFunds, // TE_CANNOT_COVER_ESTIMATE_ORDER_LOSS The remaining balance cannot cover the potential unrealized PnL for this new order
'11083': InvalidOrder, // TE_TAKE_PROFIT_ORDER_DUPLICATED TakeProfit order already exists
'11084': InvalidOrder, // TE_STOP_LOSS_ORDER_DUPLICATED StopLoss order already exists
'11085': DuplicateOrderId, // TE_CL_ORD_ID_DUPLICATE ClOrdId is duplicated
'11086': InvalidOrder, // TE_PEG_PRICE_TYPE_INVALID PegPriceType is invalid
'11087': InvalidOrder, // TE_BUY_TS_SHOULD_LT_BASE The trailing order's StopPrice should be less than the current last price
'11088': InvalidOrder, // TE_BUY_TS_SHOULD_GT_LIQ The traling order's StopPrice should be greater than the current liquidation price
'11089': InvalidOrder, // TE_SELL_TS_SHOULD_LT_LIQ The traling order's StopPrice should be greater than the current last price
'11090': InvalidOrder, // TE_SELL_TS_SHOULD_GT_BASE The traling order's StopPrice should be less than the current liquidation price
'11091': InvalidOrder, // TE_BUY_REVERT_VALUE_SHOULD_LT_ZERO The PegOffset should be less than zero
'11092': InvalidOrder, // TE_SELL_REVERT_VALUE_SHOULD_GT_ZERO The PegOffset should be greater than zero
'11093': InvalidOrder, // TE_BUY_TTP_SHOULD_ACTIVATE_ABOVE_BASE The activation price should be greater than the current last price
'11094': InvalidOrder, // TE_SELL_TTP_SHOULD_ACTIVATE_BELOW_BASE The activation price should be less than the current last price
'11095': InvalidOrder, // TE_TRAILING_ORDER_DUPLICATED A trailing order exists already
'11096': InvalidOrder, // TE_CLOSE_ORDER_CANNOT_ATTACH_TP_SL An order to close position cannot have trailing instruction
'11097': BadRequest, // TE_CANNOT_FIND_WALLET_OF_THIS_CURRENCY This crypto is not supported
'11098': BadRequest, // TE_WALLET_INVALID_ACTION Invalid action on wallet
'11099': ExchangeError, // TE_WALLET_VID_UNMATCHED Wallet operation request has a wrong wallet vid
'11100': InsufficientFunds, // TE_WALLET_INSUFFICIENT_BALANCE Wallet has insufficient balance
'11101': InsufficientFunds, // TE_WALLET_INSUFFICIENT_LOCKED_BALANCE Locked balance in wallet is not enough for unlock/withdraw request
'11102': BadRequest, // TE_WALLET_INVALID_DEPOSIT_AMOUNT Deposit amount must be greater than zero
'11103': BadRequest, // TE_WALLET_INVALID_WITHDRAW_AMOUNT Withdraw amount must be less than zero
'11104': BadRequest, // TE_WALLET_REACHED_MAX_AMOUNT Deposit makes wallet exceed max amount allowed
'11105': InsufficientFunds, // TE_PLACE_ORDER_INSUFFICIENT_BASE_BALANCE Insufficient funds in base wallet
'11106': InsufficientFunds, // TE_PLACE_ORDER_INSUFFICIENT_QUOTE_BALANCE Insufficient funds in quote wallet
'11107': ExchangeError, // TE_CANNOT_CONNECT_TO_REQUEST_SEQ TradingEngine failed to connect with CrossEngine
'11108': InvalidOrder, // TE_CANNOT_REPLACE_OR_CANCEL_MARKET_ORDER Cannot replace/amend market order
'11109': InvalidOrder, // TE_CANNOT_REPLACE_OR_CANCEL_IOC_ORDER Cannot replace/amend ImmediateOrCancel order
'11110': InvalidOrder, // TE_CANNOT_REPLACE_OR_CANCEL_FOK_ORDER Cannot replace/amend FillOrKill order
'11111': InvalidOrder, // TE_MISSING_ORDER_ID OrderId is missing
'11112': InvalidOrder, // TE_QTY_TYPE_INVALID QtyType is invalid
'11113': BadRequest, // TE_USER_ID_INVALID UserId is invalid
'11114': InvalidOrder, // TE_ORDER_VALUE_TOO_LARGE Order value is too large
'11115': InvalidOrder, // TE_ORDER_VALUE_TOO_SMALL Order value is too small
'11116': InvalidOrder, // TE_BO_NUM_EXCEEDS Details: the total count of brakcet orders should equal or less than 5
'11117': InvalidOrder, // TE_BO_CANNOT_HAVE_BO_WITH_DIFF_SIDE Details: all bracket orders should have the same Side.
'11118': InvalidOrder, // TE_BO_TP_PRICE_INVALID Details: bracker order take profit price is invalid
'11119': InvalidOrder, // TE_BO_SL_PRICE_INVALID Details: bracker order stop loss price is invalid
'11120': InvalidOrder, // TE_BO_SL_TRIGGER_PRICE_INVALID Details: bracker order stop loss trigger price is invalid
'11121': InvalidOrder, // TE_BO_CANNOT_REPLACE Details: cannot replace bracket order.
'11122': InvalidOrder, // TE_BO_BOTP_STATUS_INVALID Details: bracket take profit order status is invalid
'11123': InvalidOrder, // TE_BO_CANNOT_PLACE_BOTP_OR_BOSL_ORDER Details: cannot place bracket take profit order
'11124': InvalidOrder, // TE_BO_CANNOT_REPLACE_BOTP_OR_BOSL_ORDER Details: cannot place bracket stop loss order
'11125': InvalidOrder, // TE_BO_CANNOT_CANCEL_BOTP_OR_BOSL_ORDER Details: cannot cancel bracket sl/tp order
'11126': InvalidOrder, // TE_BO_DONOT_SUPPORT_API Details: doesn't support bracket order via API
'11128': InvalidOrder, // TE_BO_INVALID_EXECINST Details: ExecInst value is invalid
'11129': InvalidOrder, // TE_BO_MUST_BE_SAME_SIDE_AS_POS Details: bracket order should have the same side as position's side
'11130': InvalidOrder, // TE_BO_WRONG_SL_TRIGGER_TYPE Details: bracket stop loss order trigger type is invalid
'11131': InvalidOrder, // TE_BO_WRONG_TP_TRIGGER_TYPE Details: bracket take profit order trigger type is invalid
'11132': InvalidOrder, // TE_BO_ABORT_BOSL_DUE_BOTP_CREATE_FAILED Details: cancel bracket stop loss order due failed to create take profit order.
'11133': InvalidOrder, // TE_BO_ABORT_BOSL_DUE_BOPO_CANCELED Details: cancel bracket stop loss order due main order canceled.
'11134': InvalidOrder, // TE_BO_ABORT_BOTP_DUE_BOPO_CANCELED Details: cancel bracket take profit order due main order canceled.
// not documented
'30000': BadRequest, // {"code":30000,"msg":"Please double check input arguments","data":null}
'30018': BadRequest, // {"code":30018,"msg":"phemex.data.size.uplimt","data":null}
'34003': PermissionDenied, // {"code":34003,"msg":"Access forbidden","data":null}
'35104': InsufficientFunds, // {"code":35104,"msg":"phemex.spot.wallet.balance.notenough","data":null}
'39995': RateLimitExceeded, // {"code": "39995","msg": "Too many requests."}
'39996': PermissionDenied, // {"code": "39996","msg": "Access denied."}
'39997': BadSymbol, // {"code":39997,"msg":"Symbol not listed sMOVRUSDT","data":null}
},
'broad': {
'401 Insufficient privilege': PermissionDenied, // {"code": "401","msg": "401 Insufficient privilege."}
'401 Request IP mismatch': PermissionDenied, // {"code": "401","msg": "401 Request IP mismatch."}
'Failed to find api-key': AuthenticationError, // {"msg":"Failed to find api-key 1c5ec63fd-660d-43ea-847a-0d3ba69e106e","code":10500}
'Missing required parameter': BadRequest, // {"msg":"Missing required parameter","code":10500}
'API Signature verification failed': AuthenticationError, // {"msg":"API Signature verification failed.","code":10500}
'Api key not found': AuthenticationError, // {"msg":"Api key not found 698dc9e3-6faa-4910-9476-12857e79e198","code":"10500"}
},
},
'options': {
'brokerId': 'CCXT123456', // updated from CCXT to CCXT123456
'x-phemex-request-expiry': 60, // in seconds
'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);
}
const isLinear = !inverse;
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': isLinear,
'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':