UNPKG

astro-perp-ccxt-dev

Version:

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

5,328 lines 245 kB
'use strict';

var phemex$1 = require('./abstract/phemex.js');
var errors = require('./base/errors.js');
var Precise = require('./base/Precise.js');
var number = require('./base/functions/number.js');
var sha256 = require('./static_dependencies/noble-hashes/sha256.js');

// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
/**
 * @class phemex
 * @augments Exchange
 */
class phemex extends phemex$1 {
    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': number.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': errors.AuthenticationError,
                    '412': errors.BadRequest,
                    '6001': errors.BadRequest,
                    // documented
                    '19999': errors.BadRequest,
                    '10001': errors.DuplicateOrderId,
                    '10002': errors.OrderNotFound,
                    '10003': errors.CancelPending,
                    '10004': errors.CancelPending,
                    '10005': errors.CancelPending,
                    '11001': errors.InsufficientFunds,
                    '11002': errors.InvalidOrder,
                    '11003': errors.InsufficientFunds,
                    '11004': errors.InvalidOrder,
                    '11005': errors.InsufficientFunds,
                    '11006': errors.ExchangeError,
                    '11007': errors.ExchangeError,
                    '11008': errors.ExchangeError,
                    '11009': errors.ExchangeError,
                    '11010': errors.InsufficientFunds,
                    '11011': errors.InvalidOrder,
                    '11012': errors.InvalidOrder,
                    '11013': errors.InvalidOrder,
                    '11014': errors.InvalidOrder,
                    '11015': errors.InvalidOrder,
                    '11016': errors.BadRequest,
                    '11017': errors.ExchangeError,
                    '11018': errors.ExchangeError,
                    '11019': errors.ExchangeError,
                    '11020': errors.ExchangeError,
                    '11021': errors.ExchangeError,
                    '11022': errors.AccountSuspended,
                    '11023': errors.ExchangeError,
                    '11024': errors.ExchangeError,
                    '11025': errors.BadRequest,
                    '11026': errors.ExchangeError,
                    '11027': errors.BadSymbol,
                    '11028': errors.BadSymbol,
                    '11029': errors.ExchangeError,
                    '11030': errors.ExchangeError,
                    '11031': errors.DDoSProtection,
                    '11032': errors.DDoSProtection,
                    '11033': errors.DuplicateOrderId,
                    '11034': errors.InvalidOrder,
                    '11035': errors.InvalidOrder,
                    '11036': errors.InvalidOrder,
                    '11037': errors.InvalidOrder,
                    '11038': errors.InvalidOrder,
                    '11039': errors.InvalidOrder,
                    '11040': errors.InvalidOrder,
                    '11041': errors.InvalidOrder,
                    '11042': errors.InvalidOrder,
                    '11043': errors.InvalidOrder,
                    '11044': errors.InvalidOrder,
                    '11045': errors.InvalidOrder,
                    '11046': errors.InvalidOrder,
                    '11047': errors.InvalidOrder,
                    '11048': errors.InvalidOrder,
                    '11049': errors.InvalidOrder,
                    '11050': errors.InvalidOrder,
                    '11051': errors.InvalidOrder,
                    '11052': errors.InvalidOrder,
                    '11053': errors.InvalidOrder,
                    '11054': errors.InvalidOrder,
                    '11055': errors.InvalidOrder,
                    '11056': errors.InvalidOrder,
                    '11057': errors.InvalidOrder,
                    '11058': errors.InvalidOrder,
                    '11059': errors.InvalidOrder,
                    '11060': errors.InvalidOrder,
                    '11061': errors.CancelPending,
                    '11062': errors.InvalidOrder,
                    '11063': errors.InvalidOrder,
                    '11064': errors.InvalidOrder,
                    '11065': errors.InvalidOrder,
                    '11066': errors.InvalidOrder,
                    '11067': errors.InvalidOrder,
                    '11068': errors.InvalidOrder,
                    '11069': errors.ExchangeError,
                    '11070': errors.BadSymbol,
                    '11071': errors.InvalidOrder,
                    '11072': errors.InvalidOrder,
                    '11073': errors.InvalidOrder,
                    '11074': errors.InvalidOrder,
                    '11075': errors.InvalidOrder,
                    '11076': errors.InvalidOrder,
                    '11077': errors.InvalidOrder,
                    '11078': errors.InvalidOrder,
                    '11079': errors.InvalidOrder,
                    '11080': errors.InvalidOrder,
                    '11081': errors.InvalidOrder,
                    '11082': errors.InsufficientFunds,
                    '11083': errors.InvalidOrder,
                    '11084': errors.InvalidOrder,
                    '11085': errors.DuplicateOrderId,
                    '11086': errors.InvalidOrder,
                    '11087': errors.InvalidOrder,
                    '11088': errors.InvalidOrder,
                    '11089': errors.InvalidOrder,
                    '11090': errors.InvalidOrder,
                    '11091': errors.InvalidOrder,
                    '11092': errors.InvalidOrder,
                    '11093': errors.InvalidOrder,
                    '11094': errors.InvalidOrder,
                    '11095': errors.InvalidOrder,
                    '11096': errors.InvalidOrder,
                    '11097': errors.BadRequest,
                    '11098': errors.BadRequest,
                    '11099': errors.ExchangeError,
                    '11100': errors.InsufficientFunds,
                    '11101': errors.InsufficientFunds,
                    '11102': errors.BadRequest,
                    '11103': errors.BadRequest,
                    '11104': errors.BadRequest,
                    '11105': errors.InsufficientFunds,
                    '11106': errors.InsufficientFunds,
                    '11107': errors.ExchangeError,
                    '11108': errors.InvalidOrder,
                    '11109': errors.InvalidOrder,
                    '11110': errors.InvalidOrder,
                    '11111': errors.InvalidOrder,
                    '11112': errors.InvalidOrder,
                    '11113': errors.BadRequest,
                    '11114': errors.InvalidOrder,
                    '11115': errors.InvalidOrder,
                    '11116': errors.InvalidOrder,
                    '11117': errors.InvalidOrder,
                    '11118': errors.InvalidOrder,
                    '11119': errors.InvalidOrder,
                    '11120': errors.InvalidOrder,
                    '11121': errors.InvalidOrder,
                    '11122': errors.InvalidOrder,
                    '11123': errors.InvalidOrder,
                    '11124': errors.InvalidOrder,
                    '11125': errors.InvalidOrder,
                    '11126': errors.InvalidOrder,
                    '11128': errors.InvalidOrder,
                    '11129': errors.InvalidOrder,
                    '11130': errors.InvalidOrder,
                    '11131': errors.InvalidOrder,
                    '11132': errors.InvalidOrder,
                    '11133': errors.InvalidOrder,
                    '11134': errors.InvalidOrder,
                    // not documented
                    '30000': errors.BadRequest,
                    '30018': errors.BadRequest,
                    '34003': errors.PermissionDenied,
                    '35104': errors.InsufficientFunds,
                    '39995': errors.RateLimitExceeded,
                    '39996': errors.PermissionDenied,
                    '39997': errors.BadSymbol, // {"code":39997,"msg":"Symbol not listed sMOVRUSDT","data":null}
                },
                'broad': {
                    '401 Insufficient privilege': errors.PermissionDenied,
                    '401 Request IP mismatch': errors.PermissionDenied,
                    'Failed to find api-key': errors.AuthenticationError,
                    'Missing required parameter': errors.BadRequest,
                    'API Signature verification failed': errors.AuthenticationError,
                    'Api key not found': errors.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.safeDict(riskLimitsById, id, {});
                market = this.extend(market, riskLimitValues);
                const v1ProductsValues = this.safeDict(v1ProductsById, id, {});
                market = this.extend(market, v1ProductsValues);
                market = this.parseSwapMarket(market);
            }
            else {
                const baseCurrency = this.safeString(market, 'baseCurrency');
                const currencyValues = this.safeDict(currenciesByCode, baseCurrency, {});
                const valueScale = this.safeString(currencyValues, 'valueScale', '8');
                market = this.extend(market, { 'valueScale': valueScale });
                market = this.parseSpotMarket(market);
            }
            result.push(market);
        }
        return result;
    }
    /**
     * @method
     * @name phemex#fetchCurrencies
     * @description fetches all available currencies on an exchange
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @returns {object} an associative dictionary of currencies
     */
    async fetchCurrencies(params = {}) {
        const response = await this.v2GetPublicProducts(params);
        //
        //     {
        //         "code":0,
        //         "msg":"OK",
        //         "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},
        //             ],
        //             ...
        //         }
        //     }
        const data = this.safeValue(response, 'data', {});
        const currencies = this.safeValue(data, 'currencies', []);
        const result = {};
        for (let i = 0; i < currencies.length; i++) {
            const currency = currencies[i];
            const id = this.safeString(currency, 'currency');
            const code = this.safeCurrencyCode(id);
            const valueScaleString = this.safeString(currency, 'valueScale');
            const valueScale = parseInt(valueScaleString);
            const minValueEv = this.safeString(currency, 'minValueEv');
            const maxValueEv = this.safeString(currency, 'maxValueEv');
            let minAmount = undefined;
            let maxAmount = undefined;
            let precision = undefined;
            if (valueScale !== undefined) {
                const precisionString = this.parsePrecision(valueScaleString);
                precision = this.parseNumber(precisionString);
                minAmount = this.parseNumber(Precise["default"].stringMul(minValueEv, precisionString));
                maxAmount = this.parseNumber(Precise["default"].stringMul(maxValueEv, precisionString));
            }
            result[code] = this.safeCurrencyStructure({
                'id': id,
                'info': currency,
                'code': code,
                'name': this.safeString(currency, 'name'),
                'active': this.safeString(currency, 'status') === 'Listed',
                'deposit': undefined,
                'withdraw': undefined,
                'fee': undefined,
                'precision': precision,
                'limits': {
                    'amount': {
                        'min': minAmount,
                        'max': maxAmount,
                    },
                    'withdraw': {
                        'min': undefined,
                        'max': undefined,
                    },
                },
                'valueScale': valueScale,
                'networks': undefined,
                'type': 'crypto',
            });
        }
        return result;
    }
    customParseBidAsk(bidask, priceKey = 0, amountKey = 1, market = undefined) {
        if (market === undefined) {
            throw new errors.ArgumentsRequired(this.id + ' customParseBidAsk() requires a market argument');
        }
        let amount = this.safeString(bidask, amountKey);
        if (market['spot']) {
            amount = this.fromEv(amount, market);
        }
        return [
            this.parseNumber(this.fromEp(this.safeString(bidask, priceKey), market)),
            this.parseNumber(amount),
        ];
    }
    customParseOrderBook(orderbook, symbol, timestamp = undefined, bidsKey = 'bids', asksKey = 'asks', priceKey = 0, amountKey = 1, market = undefined) {
        const result = {
            'symbol': symbol,
            'timestamp': timestamp,
            'datetime': this.iso8601(timestamp),
            'nonce': undefined,
        };
        const sides = [bidsKey, asksKey];
        for (let i = 0; i < sides.length; i++) {
            const side = sides[i];
            const orders = [];
            const bidasks = this.safeValue(orderbook, side);
            for (let k = 0; k < bidasks.length; k++) {
                orders.push(this.customParseBidAsk(bidasks[k], priceKey, amountKey, market));
            }
            result[side] = orders;
        }
        result[bidsKey] = this.sortBy(result[bidsKey], 0, true);
        result[asksKey] = this.sortBy(result[asksKey], 0);
        return result;
    }
    /**
     * @method
     * @name phemex#fetchOrderBook
     * @description fetches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
     * @see https://github.com/phemex/phemex-api-docs/blob/master/Public-Hedged-Perpetual-API.md#queryorderbook
     * @param {string} symbol unified symbol of the market to fetch the order book for
     * @param {int} [limit] the maximum amount of order book entries to return
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/#/?id=order-book-structure} indexed by market symbols
     */
    async fetchOrderBook(symbol, limit = undefined, params = {}) {
        await this.loadMarkets();
        const market = this.market(symbol);
        const request = {
            'symbol': market['id'],
            // 'id': 123456789, // optional request id
        };
        let response = undefined;
        if (market['linear'] && market['settle'] === 'USDT') {
            response = await this.v2GetMdV2Orderbook(this.extend(request, params));
        }
        else {
            if ((limit !== undefined) && (limit <= 30)) {
                response = await this.v1GetMdOrderbook(this.extend(request, params));
            }
            else {
                response = await this.v1GetMdFullbook(this.extend(request, params));
            }
        }
        //
        //     {
        //         "error": null,
        //         "id": 0,
        //         "result": {
        //             "book": {
        //                 "asks": [
        //                     [ 23415000000, 105262000 ],
        //                     [ 23416000000, 147914000 ],
        //                     [ 23419000000, 160914000 ],
        //                 ],
        //                 "bids": [
        //                     [ 23360000000, 32995000 ],
        //                     [ 23359000000, 221887000 ],
        //                     [ 23356000000, 284599000 ],
        //                 ],
        //             },
        //             "depth": 30,
        //             "sequence": 1592059928,
        //             "symbol": "sETHUSDT",
        //             "timestamp": 1592387340020000955,
        //             "type": "snapshot"
        //         }
        //     }
        //
        const result = this.safeValue(response, 'result', {});
        const book = this.safeValue2(result, 'book', 'orderbook_p', {});
        const timestamp = this.safeIntegerProduct(result, 'timestamp', 0.000001);
        const orderbook = this.customParseOrderBook(book, symbol, timestamp, 'bids', 'asks', 0, 1, market);
        orderbook['nonce'] = this.safeInteger(result, 'sequence');
        return orderbook;
    }
    toEn(n, scale) {
        const stringN = this.numberToString(n);
        const precise = new Precise["default"](stringN);
        precise.decimals = precise.decimals - scale;
        precise.reduce();
        const preciseString = precise.toString();
        return this.parseToNumeric(preciseString);
    }
    toEv(amount, market = undefined) {
        if ((amount === undefined) || (market === undefined)) {
            return amount;
        }
        return this.toEn(amount, market['valueScale']);
    }
    toEp(price, market = undefined) {
        if ((price === undefined) || (market === undefined)) {
            return price;
        }
        return this.toEn(price, market['priceScale']);
    }
    fromEn(en, scale) {
        if (en === undefined || scale === undefined) {
            return undefined;
        }
        const precise = new Precise["default"](en);
        precise.decimals = this.sum(precise.decimals, scale);
        precise.reduce();
        return precise.toString();
    }
    fromEp(ep, market = undefined) {
        if ((ep === undefined) || (market === undefined)) {
            return ep;
        }
        return this.fromEn(ep, this.safeInteger(market, 'priceScale'));
    }
    fromEv(ev, market = undefined) {
        if ((ev === undefined) || (market === undefined)) {
            return ev;
        }
        return this.fromEn(ev, this.safeInteger(market, 'valueScale'));
    }
    fromEr(er, market = undefined) {
        if ((er === undefined) || (market === undefined)) {
            return er;
        }
        return this.fromEn(er, this.safeInteger(market, 'ratioScale'));
    }
    parseOHLCV(ohlcv, market = undefined) {
        //
        //     [
        //         1592467200, // timestamp
        //         300, // interval
        //         23376000000, // last
        //         23322000000, // open
        //         23381000000, // high
        //         23315000000, // low
        //         23367000000, // close
        //         208671000, // base volume
        //         48759063370, // quote volume
        //     ]
        //
        let baseVolume;
        if ((market !== undefined) && market['spot']) {
            baseVolume = this.parseNumber(this.fromEv(this.safeString(ohlcv, 7), market));
        }
        else {
            baseVolume = this.safeNumber(ohlcv, 7);
        }
        return [
            this.safeTimestamp(ohlcv, 0),
            this.parseNumber(this.fromEp(this.safeString(ohlcv, 3), market)),
            this.parseNumber(this.fromEp(this.safeString(ohlcv, 4), market)),
            this.parseNumber(this.fromEp(this.safeString(ohlcv, 5), market)),
            this.parseNumber(this.fromEp(this.safeString(ohlcv, 6), market)),
            baseVolume,
        ];
    }
    /**
     * @method
     * @name phemex#fetchOHLCV
     * @description fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market
     * @see https://github.com/phemex/phemex-api-docs/blob/master/Public-Hedged-Perpetual-API.md#querykline
     * @see https://github.com/phemex/phemex-api-docs/blob/master/Public-Contract-API-en.md#query-kline
     * @param {string} symbol unified symbol of the market to fetch OHLCV data for
     * @param {string} timeframe the length of time each candle represents
     * @param {int} [since] *only used for USDT settled contracts, otherwise is emulated and not supported by the exchange* timestamp in ms of the earliest candle to fetch
     * @param {int} [limit] the maximum amount of candles to fetch
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @param {int} [params.until] *USDT settled/ linear swaps only* end time in ms
     * @returns {int[][]} A list of candles ordered as timestamp, open, high, low, close, volume
     */
    async fetchOHLCV(symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
        await this.loadMarkets();
        const market = this.market(symbol);
        const userLimit = limit;
        const request = {
            'symbol': market['id'],
            'resolution': this.safeString(this.timeframes, timeframe, timeframe),
        };
        const until = this.safeInteger2(params, 'until', 'to');
        params = this.omit(params, ['until']);
        const usesSpecialFromToEndpoint = ((market['linear'] || market['settle'] === 'USDT')) && ((since !== undefined) || (until !== undefined));
        let maxLimit = 1000;
        if (usesSpecialFromToEndpoint) {
            maxLimit = 2000;
        }
        if (limit === undefined) {
            limit = maxLimit;
        }
        request['limit'] = Math.min(limit, maxLimit);
        let response = undefined;
        if (market['linear'] || market['settle'] === 'USDT') {
            if ((until !== undefined) || (since !== undefined)) {
                const candleDuration = this.parseTimeframe(timeframe);
                if (since !== undefined) {
                    since = Math.round(since / 1000);
                    request['from'] = since;
                }
                else {
                    // when 'to' is defined since is mandatory
                    since = (until / 100) - (maxLimit * candleDuration);
                }
                if (until !== undefined) {
                    request['to'] = Math.round(until / 1000);
                }
                else {
                    // when since is defined 'to' is mandatory
                    let to = since + (maxLimit * candleDuration);
                    const now = this.seconds();
                    if (to > now) {
                        to = now;
                    }
                    request['to'] = to;
                }
                response = await this.publicGetMdV2KlineList(this.extend(request, params));
            }
            else {
                response = await this.publicGetMdV2KlineLast(this.extend(request, params));
            }
        }
        else {
            if (since !== undefined) {
                // phemex also provides kline query with from/to, however, this interface is NOT recommended and does not work properly.
                // we do not send since param to the exchange, instead we calculate appropriate limit param
                const duration = this.parseTimeframe(timeframe) * 1000;
                const timeDelta = this.milliseconds() - since;
                limit = this.parseToInt(timeDelta / duration); // setting limit to the number of candles after since
            }
            response = await this.publicGetMdV2Kline(this.extend(request, params));
        }
        //
        //     {
        //         "code":0,
        //         "msg":"OK",
        //         "data":{
        //             "total":-1,
        //             "rows":[
        //                 [1592467200,300,23376000000,23322000000,23381000000,23315000000,23367000000,208671000,48759063370],
        //                 [1592467500,300,23367000000,23314000000,23390000000,23311000000,23331000000,234820000,54848948710],
        //                 [1592467800,300,23331000000,23385000000,23391000000,23326000000,23387000000,152931000,35747882250],
        //             ]
        //         }
        //     }
        //
        const data = this.safeValue(response, 'data', {});
        const rows = this.safeList(data, 'rows', []);
        return this.parseOHLCVs(rows, market, timeframe, since, userLimit);
    }
    parseTicker(ticker, market = undefined) {
        //
        // spot
        //
        //     {
        //         "askEp": 943836000000,
        //         "bidEp": 943601000000,
        //         "highEp": 955946000000,
        //         "lastEp": 943803000000,
        //         "lowEp": 924973000000,
        //         "openEp": 948693000000,
        //         "symbol": "sBTCUSDT",
        //         "timestamp": 1592471203505728630,
        //         "turnoverEv": 111822826123103,
        //         "volumeEv": 11880532281
        //     }
        //
        // swap
        //
        //     {
        //         "askEp": 2332500,
        //         "bidEp": 2331000,
        //         "fundingRateEr": 10000,
        //         "highEp": 2380000,
        //         "indexEp": 2329057,
        //         "lastEp": 2331500,
        //         "lowEp": 2274000,
        //         "markEp": 2329232,
        //         "openEp": 2337500,
        //         "openInterest": 1298050,
        //         "predFundingRateEr": 19921,
        //         "symbol": "ETHUSD",
        //         "timestamp": 1592474241582701416,
        //         "turnoverEv": 47228362330,
        //         "volume": 4053863
        //     }
        // linear swap v2
        //
        //     {
        //         "closeRp":"16820.5",
        //         "fundingRateRr":"0.0001",
        //         "highRp":"16962.1",
        //         "indexPriceRp":"16830.15651565",
        //         "lowRp":"16785",
        //         "markPriceRp":"16830.97534951",
        //         "openInterestRv":"1323.596",
        //         "openRp":"16851.7",
        //         "predFundingRateRr":"0.0001",
        //         "symbol":"BTCUSDT",
        //         "timestamp":"1672142789065593096",
        //         "turnoverRv":"124835296.0538",
        //         "volumeRq":"7406.95"
        //     }
        //
        const marketId = this.safeString(ticker, 'symbol');
        market = this.safeMarket(marketId, market);
        const symbol = market['symbol'];
        const timestamp = this.safeIntegerProduct(ticker, 'timestamp', 0.000001);
        const last = this.fromEp(this.safeString2(ticker, 'lastEp', 'closeRp'), market);
        const quoteVolume = this.fromEr(this.safeString2(ticker, 'turnoverEv', 'turnoverRv'), market);
        let baseVolume = this.safeString(ticker, 'volume');
        if (baseVolume === undefined) {
            baseVolume = this.fromEv(this.safeString2(ticker, 'volumeEv', 'volumeRq'), market);
        }
        const open = this.fromEp(this.safeString(ticker, 'openEp'), market);
        return this.safeTicker({
            'symbol': symbol,
            'timestamp': timestamp,
            'datetime': this.iso8601(timestamp),
            'high': this.fromEp(this.safeString2(ticker, 'highEp', 'highRp'), market),
            'low': this.fromEp(this.safeString2(ticker, 'lowEp', 'lowRp'), market),
            'bid': this.fromEp(this.safeString(ticker, 'bidEp'), market),
            'bidVolume': undefined,
            'ask': this.fromEp(this.safeString(ticker, 'askEp'), market),
            'askVolume': undefined,
            'vwap': undefined,
            'open': open,
            'close': last,
            'last': last,
            'previousClose': undefined,
            'change': undefined,
            'percentage': undefined,
            'average': undefined,
            'baseVolume': baseVolume,
            'quoteVolume': quoteVolume,
            'info': ticker,
        }, market);
    }
    /**
     * @method
     * @name phemex#fetchTicker
     * @description fetches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
     * @see https://github.com/phemex/phemex-api-docs/blob/master/Public-Hedged-Perpetual-API.md#query24hrsticker
     * @param {string} symbol unified symbol of the market to fetch the ticker for
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure}
     */
    async fetchTicker(symbol, params = {}) {
        await this.loadMarkets();
        const market = this.market(symbol);
        const request = {
            'symbol': market['id'],
            // 'id': 123456789, // optional request id
        };
        let response = undefined;
        if (market['swap']) {
            if (market['inverse'] || market['settle'] === 'USD') {
                response = await this.v1GetMdTicker24hr(this.extend(request, params));
            }
            else {
                response = await this.v2GetMdV2Ticker24hr(this.extend(request, params));
            }
        }
        else {
            response = await this.v1GetMdSpotTicker24hr(this.extend(request, params));
        }
        //
        // spot
        //
        //     {
        //         "error": null,
        //         "id": 0,
        //         "result": {
        //             "askEp": 943836000000,
        //             "bidEp": 943601000000,
        //             "highEp": 955946000000,
        //             "lastEp": 943803000000,
        //             "lowEp": 924973000000,
        //             "openEp": 948693000000,
        //             "symbol": "sBTCUSDT",
        //             "timestamp": 1592471203505728630,
        //             "turnoverEv": 111822826123103,
        //             "volumeEv": 11880532281
        //         }
        //     }
        //
        // swap
        //
        //     {
        //         "error": null,
        //         "id": 0,
        //         "result": {
        //             "askEp": 2332500,
        //             "bidEp": 2331000,
        //             "fundingRateEr": 10000,
        //             "highEp": 2380000,
        //             "indexEp": 2329057,
        //             "lastEp": 2331500,
        //             "lowEp": 2274000,
        //             "markEp": 2329232,
        //             "openEp": 2337500,
        //             "openInterest": 1298050,
        //             "predFundingRateEr": 19921,
        //             "symbol": "ETHUSD",
        //             "timestamp": 1592474241582701416,
        //             "turnoverEv": 47228362330,
        //             "volume": 4053863
        //         }
        //     }
        //
        const result = this.safeDict(response, 'result', {});
        return this.parseTicker(result, market);
    }
    /**
     * @method
     * @name phemex#fetchTickers
     * @description fetches price tickers for multiple markets, statistical information calculated over the past 24 hours for each market
     * @see https://phemex-docs.github.io/#query-24-hours-ticker-for-all-symbols-2     // spot
     * @see https://phemex-docs.github.io/#query-24-ticker-for-all-symbols             // linear
     * @see https://phemex-docs.github.io/#query-24-hours-ticker-for-all-symbols       // inverse
     * @param {string[]|undefined} symbols unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @returns {object} a dictionary of [ticker structures]{@link https://docs.ccxt.com/#/?id=ticker-structure}
     */
    async fetchTickers(symbols = undefined, params = {}) {
        await this.loadMarkets();
        let market = undefined;
        if (symbols !== undefined) {
            const first = this.safeValue(symbols, 0);
            market = this.market(first);
        }
        let type = undefined;
        [type, params] = this.handleMarketTypeAndParams('fetchTickers', market, params);
        let subType = undefined;
        [subType, params] = this.handleSubTypeAndParams('fetchTickers', market, params);
        const query = this.omit(params, 'type');
        let response = undefined;
        if (type === 'spot') {
            response = await this.v1GetMdSpotTicker24hrAll(query);
        }
        else if (subType === 'inverse' || this.safeString(market, 'settle') === 'USD') {
            response = await this.v1GetMdTicker24hrAll(query);
        }
        else {
            response = await this.v2GetMdV2Ticker24hrAll(query);
        }
        const result = this.safeList(response, 'result', []);
        return this.parseTickers(result, symbols);
    }
    /**
     * @method
     * @name phemex#fetchTrades
     * @description get the list of most recent trades for a particular symbol
     * @see https://github.com/phemex/phemex-api-docs/blob/master/Public-Hedged-Perpetual-API.md#querytrades
     * @param {string} symbol unified symbol of the market to fetch trades for
     * @param {int} [since] timestamp in ms of the earliest trade to fetch
     * @param {int} [limit] the maximum amount of trades to fetch
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @returns {Trade[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=public-trades}
     */
    async fetchTrades(symbol, since = undefined, limit = undefined, params = {}) {
        await this.loadMarkets();
        const market = this.market(symbol);
        const request = {
            'symbol': market['id'],
            // 'id': 123456789, // optional request id
        };
        let response = undefined;
        if (market['linear'] && market['settle'] === 'USDT') {
            response = await this.v2GetMdV2Trade(this.extend(request, params));
        }
        else {
            response = await this.v1GetMdTrade(this.extend(request, params));
        }
        //
        //     {
        //         "error": null,
        //         "id": 0,
        //         "result": {
        //             "sequence": 1315644947,
        //             "symbol": "BTCUSD",
        //             "trades": [
        //                 [ 1592541746712239749, 13156448570000, "Buy", 93070000, 40173 ],
        //                 [ 1592541740434625085, 13156447110000, "Sell", 93065000, 5000 ],
        //                 [ 1592541732958241616, 13156441390000, "Buy", 93070000, 3460 ],
        //             ],
        //             "type": "snapshot"
        //         }
        //     }
        //
        const result = this.safeValue(response, 'result', {});
        const trades = this.safeValue2(result, 'trades', 'trades_p', []);
        return this.parseTrades(trades, market, since, limit);
    }
    parseTrade(trade, market = undefined) {
        //
        // fetchTrades (public) spot & contract
        //
        //     [
        //         1592541746712239749,
        //         13156448570000,
        //         "Buy",
        //         93070000,
        //         40173
        //     ]
        //
        // fetchTrades (public) perp
        //
        //     [
        //         1675690986063435800,
        //         "Sell",
        //         "22857.4",
        //         "0.269"
        //     ]
        //
        // fetchMyTrades (private)
        //
        // spot
        //
        //     {
        //         "qtyType": "ByQuote",
        //         "transactTimeNs": 1589450974800550100,
        //         "clOrdID": "8ba59d40-df25-d4b0-14cf-0703f44e9690",
        //         "orderID": "b2b7018d-f02f-4c59-b4cf-051b9c2d2e83",
        //         "symbol": "sBTCUSDT",
        //         "side": "Buy",
        //         "priceEP": 970056000000,
        //         "baseQtyEv": 0,
        //         "quoteQtyEv": 1000000000,
        //         "action": "New",
        //         "execStatus": "MakerFill",
        //         "ordStatus": "Filled",
        //         "ordType": "Limit",
        //         "execInst": "None",
        //         "timeInForce": "GoodTillCancel",
        //         "stopDirection": "UNSPECIFIED",
        //         "tradeType": "Trade",
        //         "stopPxEp": 0,
        //         "execId": "c6bd8979-07ba-5946-b07e-f8b65135dbb1",
        //         "execPriceEp": 970056000000,
        //         "execBaseQtyEv": 103000,
        //         "execQuoteQtyEv": 999157680,
        //         "leavesBaseQtyEv": 0,
        //         "leavesQuoteQtyEv": 0,
        //         "execFeeEv": 0,
        //         "feeRateEr": 0
        //         "baseCurrency": "BTC",
        //         "quoteCurrency": "USDT",
        //         "feeCurrency": "BTC"
        //     }
        //
        // swap
        //
        //     {
        //         "transactTimeNs": 1578026629824704800,
        //         "symbol": "BTCUSD",
        //         "currency": "BTC",
        //         "action": "Replace",
        //         "side": "Sell",
        //         "tradeType": "Trade",
        //         "execQty": 700,
        //         "execPriceEp": 71500000,
        //         "orderQty": 700,
        //         "priceEp": 71500000,
        //         "execValueEv": 9790209,
        //         "feeRateEr": -25000,
        //         "execFeeEv": -2447,
        //         "ordType": "Limit",
        //         "execID": "b01671a1-5ddc-5def-b80a-5311522fd4bf",
        //         "orderID": "b63bc982-be3a-45e0-8974-43d6375fb626",
        //         "clOrdID": "uuid-1577463487504",
        //         "execStatus": "MakerFill"
        //     }
        // perpetual
        //     {
        //         "accountID": 9328670003,
        //         "action": "New",
        //         "actionBy": "ByUser",
        //         "actionTimeNs": 1666858780876924611,
        //         "addedSeq": 77751555,
        //         "apRp": "0",
        //         "bonusChangedAmountRv": "0",
        //         "bpRp": "0",
        //         "clOrdID": "c0327a7d-9064-62a9-28f6-2db9aaaa04e0",
        //         "closedPnlRv": "0",
        //         "closedSize": "0",
        //         "code": 0,
        //         "cumFeeRv": "0",
        //         "cumQty": "0",
        //         "cumValueRv": "0",
        //         "curAccBalanceRv": "1508.489893982237",
        //         "curAssignedPosBalanceRv": "24.62786650928",
        //         "curBonusBalanceRv": "0",
        //         "curLeverageRr": "-10",
        //         "curPosSide": "Buy",
        //         "curPosSize": "0.043",
        //         "curPosTerm": 1,
        //         "curPosValueRv": "894.0689",
        //         "curRiskLimitRv": "1000000",
        //         "currency": "USDT",
        //         "cxlRejReason": 0,
        //         "displayQty": "0.003",
        //         "execFeeRv": "0",
        //         "execID": "00000000-0000-0000-0000-000000000000",
        //         "execPriceRp": "20723.7",
        //         "execQty": "0",
        //         "execSeq": 77751555,
        //         "execStatus": "New",
        //         "execValueRv": "0",
        //         "feeRateRr": "0",
        //         "leavesQty": "0.003",
        //         "leavesValueRv": "63.4503",
        //         "message": "No error",
        //         "ordStatus": "New",
        //         "ordType": "Market",
        //         "orderID": "fa64c6f2-47a4-4929-aab4-b7fa9bbc4323",
        //         "orderQty": "0.003",
        //         "pegOffsetValueRp": "0",
        //         "posSide": "Long",
        //         "priceRp": "21150.1",
        //         "relatedPosTerm": 1,
        //         "relatedReqNum": 11,
        //         "side": "Buy",
        //         "slTrigger": "ByMarkPrice",
        //         "stopLossRp": "0",
        //         "stopPxRp": "0",
        //         "symbol": "BTCUSDT",
        //         "takeProfitRp": "0",
        //         "timeInForce": "ImmediateOrCancel",
        //         "tpTrigger": "ByLastPrice",
        //         "tradeType": "Amend",
        //         "transactTimeNs": 1666858780881545305,
        //         "userID": 932867
        //     }
        //
        // swap - USDT
        //
        //     {
        //         "createdAt": 1666226932259,
        //         "symbol": "ETHUSDT",
        //         "currency": "USDT",
        //         "action": 1,
        //         "tradeType": 1,
        //         "execQtyRq": "0.01",
        //         "execPriceRp": "1271.9",
        //         "side": 1,
        //         "orderQtyRq": "0.78",
        //         "priceRp": "1271.9",
        //         "execValueRv": "12.719",
        //         "feeRateRr": "0.0001",
        //         "execFeeRv": "0.0012719",
        //         "ordType": 2,
        //         "execId": "8718cae",
        //         "execStatus": 6
        //     }
        // spot with fees paid using PT token
        //     "createdAt": "1714990724076",
        //     "symbol": "BTCUSDT",
        //     "currency": "USDT",
        //     "action": "1",
        //     "tradeType": "1",
        //     "execQtyRq": "0.003",
        //     "execPriceRp": "64935",
        //     "side": "2",
        //     "orderQtyRq": "0.003",
        //     "priceRp": "51600",
        //     "execValueRv": "194.805",
        //     "feeRateRr": "0.000495",
        //     "execFeeRv": "0",
        //     "ordType": "3",
        //     "execId": "XXXXXX",
        //     "execStatus": "7",
        //     "posSide": "1",
        //     "ptFeeRv": "0.110012249248",
        //     "ptPriceRp": "0.876524893"
        //
        let priceString;
        let amountString;
        let timestamp;
        let id = undefined;
        let side = undefined;
        let costString = undefined;
        let type = undefined;
        let fee = undefined;
        let feeCostString = undefined;
        let feeRateString = undefined;
        let feeCurrencyCode = undefined;
        const marketId = this.safeString(trade, 'symbol');
        market = this.safeMarket(marketId, market);
        const symbol = market['symbol'];
        let orderId = undefined;
        let takerOrMaker = undefined;
        if (Array.isArray(trade)) {
            const tradeLength = trade.length;
            timestamp = this.safeIntegerProduct(trade, 0, 0.000001);
            if (tradeLength > 4) {
                id = this.safeString(trade, tradeLength - 4);
            }
            side = this.safeStringLower(trade, tradeLength - 3);
            priceString = this.safeString(trade, tradeLength - 2);
            amountString = this.safeString(trade, tradeLength - 1);
            if (typeof trade[tradeLength - 2] === 'number') {
                priceString = this.fromEp(priceString, market);
                amountString = this.fromEv(amountString, market);
            }
        }
        else {
            timestamp = this.safeIntegerProduct(trade, 'transactTimeNs', 0.000001);
            if (timestamp === undefined) {
                timestamp = this.safeInteger(trade, 'createdAt');
            }
            id = this.safeString2(trade, 'execId', 'execID');
            orderId = this.safeString(trade, 'orderID');
            if (market['settle'] === 'USDT') {
                const sideId = this.safeStringLower(trade, 'side');
                if ((sideId === 'buy') || (sideId === 'sell')) {
                    side = sideId;
                }
                else if (sideId !== undefined) {
                    side = (sideId === '1') ? 'buy' : 'sell';
                }
                const ordType = this.safeString(trade, 'ordType');
                if (ordType === '1') {
                    type = 'market';
                }
                else if (ordType === '2') {
                    type = 'limit';
                }
                priceString = this.safeString(trade, 'execPriceRp');
                amountString = this.safeString(trade, 'execQtyRq');
                costString = this.safeString(trade, 'execValueRv');
                feeCostString = this.omitZero(this.safeString(trade, 'execFeeRv'));
                feeRateString = this.safeString(trade, 'feeRateRr');
                if (feeCostString !== undefined) {
                    const currencyId = this.safeString(trade, 'currency');
                    feeCurrencyCode = this.safeCurrencyCode(currencyId);
                }
                else {
                    const ptFeeRv = this.omitZero(this.safeString(trade, 'ptFeeRv'));
                    if (ptFeeRv !== undefined) {
                        feeCostString = ptFeeRv;
                        feeCurrencyCode = 'PT';
                    }
                }
            }
            else {
                side = this.safeStringLower(trade, 'side');
                type = this.parseOrderType(this.safeString(trade, 'ordType'));
                const execStatus = this.safeString(trade, 'execStatus');
                if (execStatus === 'MakerFill') {
                    takerOrMaker = 'maker';
                }
                priceString = this.fromEp(this.safeString(trade, 'execPriceEp'), market);
                amountString = this.fromEv(this.safeString(trade, 'execBaseQtyEv'), market);
                amountString = this.safeString(trade, 'execQty', amountString);
                costString = this.fromEr(this.safeString2(trade, 'execQuoteQtyEv', 'execValueEv'), market);
                feeCostString = this.fromEr(this.omitZero(this.safeString(trade, 'execFeeEv')), market);
                if (feeCostString !== undefined) {
                    feeRateString = this.fromEr(this.safeString(trade, 'feeRateEr'), market);
                    if (market['spot']) {
                        feeCurrencyCode = this.safeCurrencyCode(this.safeString(trade, 'feeCurrency'));
                    }
                    else {
                        const info = this.safeValue(market, 'info');
                        if (info !== undefined) {
                            const settlementCurrencyId = this.safeString(info, 'settlementCurrency');
                            feeCurrencyCode = this.safeCurrencyCode(settlementCurrencyId);
                        }
                    }
                }
                else {
                    feeCostString = this.safeString(trade, 'ptFeeRv');
                    if (feeCostString !== undefined) {
                        feeCurrencyCode = 'PT';
                    }
                }
            }
            fee = {
                'cost': feeCostString,
                'rate': feeRateString,
                'currency': feeCurrencyCode,
            };
        }
        return this.safeTrade({
            'info': trade,
            'id': id,
            'symbol': symbol,
            'timestamp': timestamp,
            'datetime': this.iso8601(timestamp),
            'order': orderId,
            'type': type,
            'side': side,
            'takerOrMaker': takerOrMaker,
            'price': priceString,
            'amount': amountString,
            'cost': costString,
            'fee': fee,
        }, market);
    }
    parseSpotBalance(response) {
        //
        //     {
        //         "code":0,
        //         "msg":"",
        //         "data":[
        //             {
        //                 "currency":"USDT",
        //                 "balanceEv":0,
        //                 "lockedTradingBalanceEv":0,
        //                 "lockedWithdrawEv":0,
        //                 "lastUpdateTimeNs":1592065834511322514,
        //                 "walletVid":0
        //             },
        //             {
        //                 "currency":"ETH",
        //                 "balanceEv":0,
        //                 "lockedTradingBalanceEv":0,
        //                 "lockedWithdrawEv":0,
        //                 "lastUpdateTimeNs":1592065834511322514,
        //                 "walletVid":0
        //             }
        //         ]
        //     }
        //
        let timestamp = undefined;
        const result = { 'info': response };
        const data = this.safeValue(response, 'data', []);
        for (let i = 0; i < data.length; i++) {
            const balance = data[i];
            const currencyId = this.safeString(balance, 'currency');
            const code = this.safeCurrencyCode(currencyId);
            const currency = this.safeValue(this.currencies, code, {});
            const scale = this.safeInteger(currency, 'valueScale', 8);
            const account = this.account();
            const balanceEv = this.safeString(balance, 'balanceEv');
            const lockedTradingBalanceEv = this.safeString(balance, 'lockedTradingBalanceEv');
            const lockedWithdrawEv = this.safeString(balance, 'lockedWithdrawEv');
            const total = this.fromEn(balanceEv, scale);
            const lockedTradingBalance = this.fromEn(lockedTradingBalanceEv, scale);
            const lockedWithdraw = this.fromEn(lockedWithdrawEv, scale);
            const used = Precise["default"].stringAdd(lockedTradingBalance, lockedWithdraw);
            const lastUpdateTimeNs = this.safeIntegerProduct(balance, 'lastUpdateTimeNs', 0.000001);
            timestamp = (timestamp === undefined) ? lastUpdateTimeNs : Math.max(timestamp, lastUpdateTimeNs);
            account['total'] = total;
            account['used'] = used;
            result[code] = account;
        }
        result['timestamp'] = timestamp;
        result['datetime'] = this.iso8601(timestamp);
        return this.safeBalance(result);
    }
    parseSwapBalance(response) {
        // usdt
        //   {
        //       "info": {
        //         "code": "0",
        //         "msg": '',
        //         "data": {
        //           "account": {
        //             "userID": "940666",
        //             "accountId": "9406660003",
        //             "currency": "USDT",
        //             "accountBalanceRv": "99.93143972",
        //             "totalUsedBalanceRv": "0.40456",
        //             "bonusBalanceRv": "0"
        //           },
        //   }
        //
        //     {
        //         "code":0,
        //         "msg":"",
        //         "data":{
        //             "account":{
        //                 "accountId":6192120001,
        //                 "currency":"BTC",
        //                 "accountBalanceEv":1254744,
        //                 "totalUsedBalanceEv":0,
        //                 "bonusBalanceEv":1254744
        //             }
        //         }
        //     }
        //
        const result = { 'info': response };
        const data = this.safeValue(response, 'data', {});
        const balance = this.safeValue(data, 'account', {});
        const currencyId = this.safeString(balance, 'currency');
        const code = this.safeCurrencyCode(currencyId);
        const currency = this.currency(code);
        const valueScale = this.safeInteger(currency, 'valueScale', 8);
        const account = this.account();
        const accountBalanceEv = this.safeString2(balance, 'accountBalanceEv', 'accountBalanceRv');
        const totalUsedBalanceEv = this.safeString2(balance, 'totalUsedBalanceEv', 'totalUsedBalanceRv');
        const needsConversion = (code !== 'USDT');
        account['total'] = needsConversion ? this.fromEn(accountBalanceEv, valueScale) : accountBalanceEv;
        account['used'] = needsConversion ? this.fromEn(totalUsedBalanceEv, valueScale) : totalUsedBalanceEv;
        result[code] = account;
        return this.safeBalance(result);
    }
    /**
     * @method
     * @name phemex#fetchBalance
     * @description query for balance and get the amount of funds available for trading or funds locked in orders
     * @see https://phemex-docs.github.io/#query-wallets
     * @see https://github.com/phemex/phemex-api-docs/blob/master/Public-Hedged-Perpetual-API.md#query-account-positions
     * @see https://phemex-docs.github.io/#query-trading-account-and-positions
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @param {string} [params.type] spot or swap
     * @param {string} [params.code] *swap only* currency code of the balance to query (USD, USDT, etc), default is USDT
     * @returns {object} a [balance structure]{@link https://docs.ccxt.com/#/?id=balance-structure}
     */
    async fetchBalance(params = {}) {
        await this.loadMarkets();
        let type = undefined;
        [type, params] = this.handleMarketTypeAndParams('fetchBalance', undefined, params);
        const code = this.safeString(params, 'code');
        params = this.omit(params, ['code']);
        let response = undefined;
        const request = {};
        if ((type !== 'spot') && (type !== 'swap')) {
            throw new errors.BadRequest(this.id + ' does not support ' + type + ' markets, only spot and swap');
        }
        if (type === 'swap') {
            let settle = undefined;
            [settle, params] = this.handleOptionAndParams(params, 'fetchBalance', 'settle', 'USDT');
            if (code !== undefined || settle !== undefined) {
                let coin = undefined;
                if (code !== undefined) {
                    coin = code;
                }
                else {
                    coin = settle;
                }
                const currency = this.currency(coin);
                request['currency'] = currency['id'];
                if (currency['id'] === 'USDT') {
                    response = await this.privateGetGAccountsAccountPositions(this.extend(request, params));
                }
                else {
                    response = await this.privateGetAccountsAccountPositions(this.extend(request, params));
                }
            }
            else {
                const currency = this.safeString(params, 'currency');
                if (currency === undefined) {
                    throw new errors.ArgumentsRequired(this.id + ' fetchBalance() requires a code parameter or a currency or settle parameter for ' + type + ' type');
                }
                response = await this.privateGetSpotWallets(this.extend(request, params));
            }
        }
        else {
            response = await this.privateGetSpotWallets(this.extend(request, params));
        }
        //
        // usdt
        //   {
        //       "info": {
        //         "code": "0",
        //         "msg": '',
        //         "data": {
        //           "account": {
        //             "userID": "940666",
        //             "accountId": "9406660003",
        //             "currency": "USDT",
        //             "accountBalanceRv": "99.93143972",
        //             "totalUsedBalanceRv": "0.40456",
        //             "bonusBalanceRv": "0"
        //           },
        //   }
        //
        // spot
        //
        //     {
        //         "code":0,
        //         "msg":"",
        //         "data":[
        //             {
        //                 "currency":"USDT",
        //                 "balanceEv":0,
        //                 "lockedTradingBalanceEv":0,
        //                 "lockedWithdrawEv":0,
        //                 "lastUpdateTimeNs":1592065834511322514,
        //                 "walletVid":0
        //             },
        //             {
        //                 "currency":"ETH",
        //                 "balanceEv":0,
        //                 "lockedTradingBalanceEv":0,
        //                 "lockedWithdrawEv":0,
        //                 "lastUpdateTimeNs":1592065834511322514,
        //                 "walletVid":0
        //             }
        //         ]
        //     }
        //
        // swap
        //
        //     {
        //         "code":0,
        //         "msg":"",
        //         "data":{
        //             "account":{
        //                 "accountId":6192120001,
        //                 "currency":"BTC",
        //                 "accountBalanceEv":1254744,
        //                 "totalUsedBalanceEv":0,
        //                 "bonusBalanceEv":1254744
        //             },
        //             "positions":[
        //                 {
        //                     "accountID":6192120001,
        //                     "symbol":"BTCUSD",
        //                     "currency":"BTC",
        //                     "side":"None",
        //                     "positionStatus":"Normal",
        //                     "crossMargin":false,
        //                     "leverageEr":0,
        //                     "leverage":0E-8,
        //                     "initMarginReqEr":1000000,
        //                     "initMarginReq":0.01000000,
        //                     "maintMarginReqEr":500000,
        //                     "maintMarginReq":0.00500000,
        //                     "riskLimitEv":10000000000,
        //                     "riskLimit":100.00000000,
        //                     "size":0,
        //                     "value":0E-8,
        //                     "valueEv":0,
        //                     "avgEntryPriceEp":0,
        //                     "avgEntryPrice":0E-8,
        //                     "posCostEv":0,
        //                     "posCost":0E-8,
        //                     "assignedPosBalanceEv":0,
        //                     "assignedPosBalance":0E-8,
        //                     "bankruptCommEv":0,
        //                     "bankruptComm":0E-8,
        //                     "bankruptPriceEp":0,
        //                     "bankruptPrice":0E-8,
        //                     "positionMarginEv":0,
        //                     "positionMargin":0E-8,
        //                     "liquidationPriceEp":0,
        //                     "liquidationPrice":0E-8,
        //                     "deleveragePercentileEr":0,
        //                     "deleveragePercentile":0E-8,
        //                     "buyValueToCostEr":1150750,
        //                     "buyValueToCost":0.01150750,
        //                     "sellValueToCostEr":1149250,
        //                     "sellValueToCost":0.01149250,
        //                     "markPriceEp":96359083,
        //                     "markPrice":9635.90830000,
        //                     "markValueEv":0,
        //                     "markValue":null,
        //                     "unRealisedPosLossEv":0,
        //                     "unRealisedPosLoss":null,
        //                     "estimatedOrdLossEv":0,
        //                     "estimatedOrdLoss":0E-8,
        //                     "usedBalanceEv":0,
        //                     "usedBalance":0E-8,
        //                     "takeProfitEp":0,
        //                     "takeProfit":null,
        //                     "stopLossEp":0,
        //                     "stopLoss":null,
        //                     "realisedPnlEv":0,
        //                     "realisedPnl":null,
        //                     "cumRealisedPnlEv":0,
        //                     "cumRealisedPnl":null
        //                 }
        //             ]
        //         }
        //     }
        //
        if (type === 'swap') {
            return this.parseSwapBalance(response);
        }
        return this.parseSpotBalance(response);
    }
    parseOrderStatus(status) {
        const statuses = {
            'Created': 'open',
            'Untriggered': 'open',
            'Deactivated': 'closed',
            'Triggered': 'open',
            'Rejected': 'rejected',
            'New': 'open',
            'PartiallyFilled': 'open',
            'Filled': 'closed',
            'Canceled': 'canceled',
            'Suspended': 'canceled',
            '1': 'open',
            '2': 'canceled',
            '3': 'closed',
            '4': 'canceled',
            '5': 'open',
            '6': 'open',
            '7': 'closed',
            '8': 'canceled',
        };
        return this.safeString(statuses, status, status);
    }
    parseOrderType(type) {
        const types = {
            '1': 'market',
            '2': 'limit',
            '3': 'stop',
            '4': 'stopLimit',
            '5': 'market',
            '6': 'limit',
            '7': 'market',
            '8': 'market',
            '9': 'stopLimit',
            '10': 'market',
            'Limit': 'limit',
            'Market': 'market',
        };
        return this.safeString(types, type, type);
    }
    parseTimeInForce(timeInForce) {
        const timeInForces = {
            'GoodTillCancel': 'GTC',
            'PostOnly': 'PO',
            'ImmediateOrCancel': 'IOC',
            'FillOrKill': 'FOK',
        };
        return this.safeString(timeInForces, timeInForce, timeInForce);
    }
    parseSpotOrder(order, market = undefined) {
        //
        // spot
        //
        //     {
        //         "orderID": "d1d09454-cabc-4a23-89a7-59d43363f16d",
        //         "clOrdID": "309bcd5c-9f6e-4a68-b775-4494542eb5cb",
        //         "priceEp": 0,
        //         "action": "New",
        //         "trigger": "UNSPECIFIED",
        //         "pegPriceType": "UNSPECIFIED",
        //         "stopDirection": "UNSPECIFIED",
        //         "bizError": 0,
        //         "symbol": "sBTCUSDT",
        //         "side": "Buy",
        //         "baseQtyEv": 0,
        //         "ordType": "Limit",
        //         "timeInForce": "GoodTillCancel",
        //         "ordStatus": "Created",
        //         "cumFeeEv": 0,
        //         "cumBaseQtyEv": 0,
        //         "cumQuoteQtyEv": 0,
        //         "leavesBaseQtyEv": 0,
        //         "leavesQuoteQtyEv": 0,
        //         "avgPriceEp": 0,
        //         "cumBaseAmountEv": 0,
        //         "cumQuoteAmountEv": 0,
        //         "quoteQtyEv": 0,
        //         "qtyType": "ByBase",
        //         "stopPxEp": 0,
        //         "pegOffsetValueEp": 0
        //     }
        //
        //     {
        //         "orderID":"99232c3e-3d6a-455f-98cc-2061cdfe91bc",
        //         "stopPxEp":0,
        //         "avgPriceEp":0,
        //         "qtyType":"ByBase",
        //         "leavesBaseQtyEv":0,
        //         "leavesQuoteQtyEv":0,
        //         "baseQtyEv":"1000000000",
        //         "feeCurrency":"4",
        //         "stopDirection":"UNSPECIFIED",
        //         "symbol":"sETHUSDT",
        //         "side":"Buy",
        //         "quoteQtyEv":250000000000,
        //         "priceEp":25000000000,
        //         "ordType":"Limit",
        //         "timeInForce":"GoodTillCancel",
        //         "ordStatus":"Rejected",
        //         "execStatus":"NewRejected",
        //         "createTimeNs":1592675305266037130,
        //         "cumFeeEv":0,
        //         "cumBaseValueEv":0,
        //         "cumQuoteValueEv":0
        //     }
        //
        const id = this.safeString(order, 'orderID');
        let clientOrderId = this.safeString(order, 'clOrdID');
        if ((clientOrderId !== undefined) && (clientOrderId.length < 1)) {
            clientOrderId = undefined;
        }
        const marketId = this.safeString(order, 'symbol');
        market = this.safeMarket(marketId, market);
        const symbol = market['symbol'];
        const price = this.fromEp(this.safeString(order, 'priceEp'), market);
        const amount = this.fromEv(this.safeString(order, 'baseQtyEv'), market);
        const remaining = this.omitZero(this.fromEv(this.safeString(order, 'leavesBaseQtyEv'), market));
        const filled = this.fromEv(this.safeString2(order, 'cumBaseQtyEv', 'cumBaseValueEv'), market);
        const cost = this.fromEr(this.safeString2(order, 'cumQuoteValueEv', 'quoteQtyEv'), market);
        const average = this.fromEp(this.safeString(order, 'avgPriceEp'), market);
        const status = this.parseOrderStatus(this.safeString(order, 'ordStatus'));
        const side = this.safeStringLower(order, 'side');
        const type = this.parseOrderType(this.safeString(order, 'ordType'));
        const timestamp = this.safeIntegerProduct2(order, 'actionTimeNs', 'createTimeNs', 0.000001);
        let fee = undefined;
        const feeCost = this.fromEv(this.safeString(order, 'cumFeeEv'), market);
        if (feeCost !== undefined) {
            fee = {
                'cost': feeCost,
                'currency': this.safeCurrencyCode(this.safeString(order, 'feeCurrency')),
            };
        }
        const timeInForce = this.parseTimeInForce(this.safeString(order, 'timeInForce'));
        const triggerPrice = this.parseNumber(this.omitZero(this.fromEp(this.safeString(order, 'stopPxEp'))));
        const postOnly = (timeInForce === 'PO');
        return this.safeOrder({
            'info': order,
            'id': id,
            'clientOrderId': clientOrderId,
            'timestamp': timestamp,
            'datetime': this.iso8601(timestamp),
            'lastTradeTimestamp': undefined,
            'symbol': symbol,
            'type': type,
            'timeInForce': timeInForce,
            'postOnly': postOnly,
            'side': side,
            'price': price,
            'triggerPrice': triggerPrice,
            'amount': amount,
            'cost': cost,
            'average': average,
            'filled': filled,
            'remaining': remaining,
            'status': status,
            'fee': fee,
            'trades': undefined,
        }, market);
    }
    parseOrderSide(side) {
        const sides = {
            '1': 'buy',
            '2': 'sell',
        };
        return this.safeString(sides, side, side);
    }
    parseSwapOrder(order, market = undefined) {
        //
        //     {
        //         "bizError":0,
        //         "orderID":"7a1ad384-44a3-4e54-a102-de4195a29e32",
        //         "clOrdID":"",
        //         "symbol":"ETHUSD",
        //         "side":"Buy",
        //         "actionTimeNs":1592668973945065381,
        //         "transactTimeNs":0,
        //         "orderType":"Market",
        //         "priceEp":2267500,
        //         "price":226.75000000,
        //         "orderQty":1,
        //         "displayQty":0,
        //         "timeInForce":"ImmediateOrCancel",
        //         "reduceOnly":false,
        //         "closedPnlEv":0,
        //         "closedPnl":0E-8,
        //         "closedSize":0,
        //         "cumQty":0,
        //         "cumValueEv":0,
        //         "cumValue":0E-8,
        //         "leavesQty":1,
        //         "leavesValueEv":11337,
        //         "leavesValue":1.13370000,
        //         "stopDirection":"UNSPECIFIED",
        //         "stopPxEp":0,
        //         "stopPx":0E-8,
        //         "trigger":"UNSPECIFIED",
        //         "pegOffsetValueEp":0,
        //         "execStatus":"PendingNew",
        //         "pegPriceType":"UNSPECIFIED",
        //         "ordStatus":"Created",
        //         "execInst": "ReduceOnly"
        //     }
        //
        // usdt
        // {
        //        "bizError":"0",
        //        "orderID":"bd720dff-5647-4596-aa4e-656bac87aaad",
        //        "clOrdID":"ccxt2022843dffac9477b497",
        //        "symbol":"LTCUSDT",
        //        "side":"Buy",
        //        "actionTimeNs":"1677667878751724052",
        //        "transactTimeNs":"1677667878754017434",
        //        "orderType":"Limit",
        //        "priceRp":"40",
        //        "orderQtyRq":"0.1",
        //        "displayQtyRq":"0.1",
        //        "timeInForce":"GoodTillCancel",
        //        "reduceOnly":false,
        //        "closedPnlRv":"0",
        //        "closedSizeRq":"0",
        //        "cumQtyRq":"0",
        //        "cumValueRv":"0",
        //        "leavesQtyRq":"0.1",
        //        "leavesValueRv":"4",
        //        "stopDirection":"UNSPECIFIED",
        //        "stopPxRp":"0",
        //        "trigger":"UNSPECIFIED",
        //        "pegOffsetValueRp":"0",
        //        "pegOffsetProportionRr":"0",
        //        "execStatus":"New",
        //        "pegPriceType":"UNSPECIFIED",
        //        "ordStatus":"New",
        //        "execInst":"None",
        //        "takeProfitRp":"0",
        //        "stopLossRp":"0"
        //     }
        //
        // v2 orderList
        //    {
        //        "createdAt":"1677686231301",
        //        "symbol":"LTCUSDT",
        //        "orderQtyRq":"0.2",
        //        "side":"1",
        //        "posSide":"3",
        //        "priceRp":"50",
        //        "execQtyRq":"0",
        //        "leavesQtyRq":"0.2",
        //        "execPriceRp":"0",
        //        "orderValueRv":"10",
        //        "leavesValueRv":"10",
        //        "cumValueRv":"0",
        //        "stopDirection":"0",
        //        "stopPxRp":"0",
        //        "trigger":"0",
        //        "actionBy":"1",
        //        "execFeeRv":"0",
        //        "ordType":"2",
        //        "ordStatus":"5",
        //        "clOrdId":"4b3b188",
        //        "orderId":"4b3b1884-87cf-4897-b596-6693b7ed84d1",
        //        "execStatus":"5",
        //        "bizError":"0",
        //        "totalPnlRv":null,
        //        "avgTransactPriceRp":null,
        //        "orderDetailsVos":null,
        //        "tradeType":"0"
        //    }
        //
        const id = this.safeString2(order, 'orderID', 'orderId');
        let clientOrderId = this.safeString2(order, 'clOrdID', 'clOrdId');
        if ((clientOrderId !== undefined) && (clientOrderId.length < 1)) {
            clientOrderId = undefined;
        }
        const marketId = this.safeString(order, 'symbol');
        const symbol = this.safeSymbol(marketId, market);
        market = this.safeMarket(marketId, market);
        const status = this.parseOrderStatus(this.safeString(order, 'ordStatus'));
        const side = this.parseOrderSide(this.safeStringLower(order, 'side'));
        const type = this.parseOrderType(this.safeString(order, 'orderType'));
        let price = this.safeString(order, 'priceRp');
        if (price === undefined) {
            price = this.fromEp(this.safeString(order, 'priceEp'), market);
        }
        const amount = this.safeNumber2(order, 'orderQty', 'orderQtyRq');
        const filled = this.safeNumber2(order, 'cumQty', 'cumQtyRq');
        const remaining = this.safeNumber2(order, 'leavesQty', 'leavesQtyRq');
        let timestamp = this.safeIntegerProduct(order, 'actionTimeNs', 0.000001);
        if (timestamp === undefined) {
            timestamp = this.safeInteger(order, 'createdAt');
        }
        const cost = this.safeNumber2(order, 'cumValue', 'cumValueRv');
        let lastTradeTimestamp = this.safeIntegerProduct(order, 'transactTimeNs', 0.000001);
        if (lastTradeTimestamp === 0) {
            lastTradeTimestamp = undefined;
        }
        const timeInForce = this.parseTimeInForce(this.safeString(order, 'timeInForce'));
        const triggerPrice = this.omitZero(this.safeString2(order, 'stopPx', 'stopPxRp'));
        const postOnly = (timeInForce === 'PO');
        let reduceOnly = this.safeValue(order, 'reduceOnly');
        const execInst = this.safeString(order, 'execInst');
        if (execInst === 'ReduceOnly') {
            reduceOnly = true;
        }
        const takeProfit = this.safeString(order, 'takeProfitRp');
        const stopLoss = this.safeString(order, 'stopLossRp');
        const feeValue = this.omitZero(this.safeString(order, 'execFeeRv'));
        const ptFeeRv = this.omitZero(this.safeString(order, 'ptFeeRv'));
        let fee = undefined;
        if (feeValue !== undefined) {
            fee = {
                'cost': feeValue,
                'currency': market['quote'],
            };
        }
        else if (ptFeeRv !== undefined) {
            fee = {
                'cost': ptFeeRv,
                'currency': 'PT',
            };
        }
        return this.safeOrder({
            'info': order,
            'id': id,
            'clientOrderId': clientOrderId,
            'datetime': this.iso8601(timestamp),
            'timestamp': timestamp,
            'lastTradeTimestamp': lastTradeTimestamp,
            'symbol': symbol,
            'type': type,
            'timeInForce': timeInForce,
            'postOnly': postOnly,
            'reduceOnly': reduceOnly,
            'side': side,
            'price': price,
            'triggerPrice': triggerPrice,
            'takeProfitPrice': takeProfit,
            'stopLossPrice': stopLoss,
            'amount': amount,
            'filled': filled,
            'remaining': remaining,
            'cost': cost,
            'average': undefined,
            'status': status,
            'fee': fee,
            'trades': undefined,
        });
    }
    parseOrder(order, market = undefined) {
        const isSwap = this.safeBool(market, 'swap', false);
        const hasPnl = ('closedPnl' in order) || ('closedPnlRv' in order) || ('totalPnlRv' in order);
        if (isSwap || hasPnl) {
            return this.parseSwapOrder(order, market);
        }
        return this.parseSpotOrder(order, market);
    }
    /**
     * @method
     * @name phemex#createOrder
     * @description create a trade order
     * @see https://github.com/phemex/phemex-api-docs/blob/master/Public-Hedged-Perpetual-API.md#place-order
     * @see https://phemex-docs.github.io/#place-order-http-put-prefered-3
     * @param {string} symbol unified symbol of the market to create an order in
     * @param {string} type 'market' or 'limit'
     * @param {string} side 'buy' or 'sell'
     * @param {float} amount how much of currency you want to trade in units of base currency
     * @param {float} [price] the price at which the order is to be fulfilled, in units of the quote currency, ignored in market orders
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @param {float} [params.trigger] trigger price for conditional orders
     * @param {object} [params.takeProfit] *swap only* *takeProfit object in params* containing the triggerPrice at which the attached take profit order will be triggered (perpetual swap markets only)
     * @param {float} [params.takeProfit.triggerPrice] take profit trigger price
     * @param {object} [params.stopLoss] *swap only* *stopLoss object in params* containing the triggerPrice at which the attached stop loss order will be triggered (perpetual swap markets only)
     * @param {float} [params.stopLoss.triggerPrice] stop loss trigger price
     * @param {string} [params.posSide] *swap only* "Merged" for one way mode, "Long" for buy side of hedged mode, "Short" for sell side of hedged mode
     * @param {bool} [params.hedged] *swap only* true for hedged mode, false for one way mode, default is false
     * @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
     */
    async createOrder(symbol, type, side, amount, price = undefined, params = {}) {
        await this.loadMarkets();
        const market = this.market(symbol);
        const requestSide = this.capitalize(side);
        type = this.capitalize(type);
        const request = {
            // common
            'symbol': market['id'],
            'side': requestSide,
            'ordType': type, // Market, Limit, Stop, StopLimit, MarketIfTouched, LimitIfTouched (additionally for contract-markets: MarketAsLimit, StopAsLimit, MarketIfTouchedAsLimit)
            // 'stopPxEp': this.toEp (stopPx, market), // for conditional orders
            // 'priceEp': this.toEp (price, market), // required for limit orders
            // 'timeInForce': 'GoodTillCancel', // GoodTillCancel, PostOnly, ImmediateOrCancel, FillOrKill
            // ----------------------------------------------------------------
            // spot
            // 'qtyType': 'ByBase', // ByBase, ByQuote
            // 'quoteQtyEv': this.toEp (cost, market),
            // 'baseQtyEv': this.toEv (amount, market),
            // 'trigger': 'ByLastPrice', // required for conditional orders
            // ----------------------------------------------------------------
            // swap
            // 'clOrdID': this.uuid (), // max length 40
            // 'orderQty': this.amountToPrecision (amount, symbol),
            // 'reduceOnly': false,
            // 'closeOnTrigger': false, // implicit reduceOnly and cancel other orders in the same direction
            // 'takeProfitEp': this.toEp (takeProfit, market),
            // 'stopLossEp': this.toEp (stopLossEp, market),
            // 'triggerType': 'ByMarkPrice', // ByMarkPrice, ByLastPrice
            // 'pegOffsetValueEp': integer, // Trailing offset from current price. Negative value when position is long, positive when position is short
            // 'pegPriceType': 'TrailingStopPeg', // TrailingTakeProfitPeg
            // 'text': 'comment',
            // 'posSide': Position direction - "Merged" for oneway mode , "Long" / "Short" for hedge mode
        };
        const clientOrderId = this.safeString2(params, 'clOrdID', 'clientOrderId');
        const stopLoss = this.safeValue(params, 'stopLoss');
        const stopLossDefined = (stopLoss !== undefined);
        const takeProfit = this.safeValue(params, 'takeProfit');
        const takeProfitDefined = (takeProfit !== undefined);
        if (clientOrderId === undefined) {
            const brokerId = this.safeString(this.options, 'brokerId', 'CCXT123456');
            if (brokerId !== undefined) {
                request['clOrdID'] = brokerId + this.uuid16();
            }
        }
        else {
            request['clOrdID'] = clientOrderId;
            params = this.omit(params, ['clOrdID', 'clientOrderId']);
        }
        const triggerPrice = this.safeStringN(params, ['stopPx', 'stopPrice', 'triggerPrice']);
        if (triggerPrice !== undefined) {
            if (market['settle'] === 'USDT') {
                request['stopPxRp'] = this.priceToPrecision(symbol, triggerPrice);
            }
            else {
                request['stopPxEp'] = this.toEp(triggerPrice, market);
            }
        }
        params = this.omit(params, ['stopPx', 'stopPrice', 'stopLoss', 'takeProfit', 'triggerPrice']);
        if (market['spot']) {
            let qtyType = this.safeValue(params, 'qtyType', 'ByBase');
            if ((type === 'Market') || (type === 'Stop') || (type === 'MarketIfTouched')) {
                if (price !== undefined) {
                    qtyType = 'ByQuote';
                }
            }
            if (triggerPrice !== undefined) {
                if (type === 'Limit') {
                    request['ordType'] = 'StopLimit';
                }
                else if (type === 'Market') {
                    request['ordType'] = 'Stop';
                }
                request['trigger'] = 'ByLastPrice';
            }
            request['qtyType'] = qtyType;
            if (qtyType === 'ByQuote') {
                let cost = this.safeNumber(params, 'cost');
                params = this.omit(params, 'cost');
                if (this.options['createOrderByQuoteRequiresPrice']) {
                    if (price !== undefined) {
                        const amountString = this.numberToString(amount);
                        const priceString = this.numberToString(price);
                        const quoteAmount = Precise["default"].stringMul(amountString, priceString);
                        cost = this.parseNumber(quoteAmount);
                    }
                    else if (cost === undefined) {
                        throw new errors.ArgumentsRequired(this.id + ' createOrder() ' + qtyType + ' requires a price argument or a cost parameter');
                    }
                }
                cost = (cost === undefined) ? amount : cost;
                const costString = this.numberToString(cost);
                request['quoteQtyEv'] = this.toEv(costString, market);
            }
            else {
                const amountString = this.numberToString(amount);
                request['baseQtyEv'] = this.toEv(amountString, market);
            }
        }
        else if (market['swap']) {
            const hedged = this.safeBool(params, 'hedged', false);
            params = this.omit(params, 'hedged');
            let posSide = this.safeStringLower(params, 'posSide');
            if (posSide === undefined) {
                if (hedged) {
                    const reduceOnly = this.safeBool(params, 'reduceOnly');
                    if (reduceOnly) {
                        side = (side === 'buy') ? 'sell' : 'buy';
                        params = this.omit(params, 'reduceOnly');
                    }
                    posSide = (side === 'buy') ? 'Long' : 'Short';
                }
                else {
                    posSide = 'Merged';
                }
            }
            posSide = this.capitalize(posSide);
            request['posSide'] = posSide;
            if (market['settle'] === 'USDT') {
                request['orderQtyRq'] = amount;
            }
            else {
                request['orderQty'] = this.parseToInt(amount);
            }
            if (triggerPrice !== undefined) {
                const triggerType = this.safeString(params, 'triggerType', 'ByMarkPrice');
                request['triggerType'] = triggerType;
                // set direction & exchange specific order type
                let triggerDirection = undefined;
                [triggerDirection, params] = this.handleParamString(params, 'triggerDirection');
                if (triggerDirection === undefined) {
                    throw new errors.ArgumentsRequired(this.id + " createOrder() also requires a 'triggerDirection' parameter with either 'up' or 'down' value");
                }
                // the flow defined per https://phemex-docs.github.io/#more-order-type-examples
                if (triggerDirection === 'up') {
                    if (side === 'sell') {
                        request['ordType'] = (type === 'Market') ? 'MarketIfTouched' : 'LimitIfTouched';
                    }
                    else if (side === 'buy') {
                        request['ordType'] = (type === 'Market') ? 'Stop' : 'StopLimit';
                    }
                }
                else if (triggerDirection === 'down') {
                    if (side === 'sell') {
                        request['ordType'] = (type === 'Market') ? 'Stop' : 'StopLimit';
                    }
                    else if (side === 'buy') {
                        request['ordType'] = (type === 'Market') ? 'MarketIfTouched' : 'LimitIfTouched';
                    }
                }
            }
            if (stopLossDefined || takeProfitDefined) {
                if (stopLossDefined) {
                    const stopLossTriggerPrice = this.safeValue2(stopLoss, 'triggerPrice', 'stopPrice');
                    if (stopLossTriggerPrice === undefined) {
                        throw new errors.InvalidOrder(this.id + ' createOrder() requires a trigger price in params["stopLoss"]["triggerPrice"] for a stop loss order');
                    }
                    if (market['settle'] === 'USDT') {
                        request['stopLossRp'] = this.priceToPrecision(symbol, stopLossTriggerPrice);
                    }
                    else {
                        request['stopLossEp'] = this.toEp(stopLossTriggerPrice, market);
                    }
                    const stopLossTriggerPriceType = this.safeString2(stopLoss, 'triggerPriceType', 'slTrigger');
                    if (stopLossTriggerPriceType !== undefined) {
                        request['slTrigger'] = this.safeString(this.options['triggerPriceTypesMap'], stopLossTriggerPriceType, stopLossTriggerPriceType);
                    }
                    const slLimitPrice = this.safeString(stopLoss, 'price');
                    if (slLimitPrice !== undefined) {
                        request['slPxRp'] = this.priceToPrecision(symbol, slLimitPrice);
                    }
                }
                if (takeProfitDefined) {
                    const takeProfitTriggerPrice = this.safeValue2(takeProfit, 'triggerPrice', 'stopPrice');
                    if (takeProfitTriggerPrice === undefined) {
                        throw new errors.InvalidOrder(this.id + ' createOrder() requires a trigger price in params["takeProfit"]["triggerPrice"] for a take profit order');
                    }
                    if (market['settle'] === 'USDT') {
                        request['takeProfitRp'] = this.priceToPrecision(symbol, takeProfitTriggerPrice);
                    }
                    else {
                        request['takeProfitEp'] = this.toEp(takeProfitTriggerPrice, market);
                    }
                    const takeProfitTriggerPriceType = this.safeString2(takeProfit, 'triggerPriceType', 'tpTrigger');
                    if (takeProfitTriggerPriceType !== undefined) {
                        request['tpTrigger'] = this.safeString(this.options['triggerPriceTypesMap'], takeProfitTriggerPriceType, takeProfitTriggerPriceType);
                    }
                    const tpLimitPrice = this.safeString(takeProfit, 'price');
                    if (tpLimitPrice !== undefined) {
                        request['tpPxRp'] = this.priceToPrecision(symbol, tpLimitPrice);
                    }
                }
            }
        }
        if ((type === 'Limit') || (type === 'StopLimit') || (type === 'LimitIfTouched')) {
            if (market['settle'] === 'USDT') {
                request['priceRp'] = this.priceToPrecision(symbol, price);
            }
            else {
                const priceString = this.numberToString(price);
                request['priceEp'] = this.toEp(priceString, market);
            }
        }
        const takeProfitPrice = this.safeString(params, 'takeProfitPrice');
        if (takeProfitPrice !== undefined) {
            if (market['settle'] === 'USDT') {
                request['takeProfitRp'] = this.priceToPrecision(symbol, takeProfitPrice);
            }
            else {
                request['takeProfitEp'] = this.toEp(takeProfitPrice, market);
            }
            params = this.omit(params, 'takeProfitPrice');
        }
        const stopLossPrice = this.safeString(params, 'stopLossPrice');
        if (stopLossPrice !== undefined) {
            if (market['settle'] === 'USDT') {
                request['stopLossRp'] = this.priceToPrecision(symbol, stopLossPrice);
            }
            else {
                request['stopLossEp'] = this.toEp(stopLossPrice, market);
            }
            params = this.omit(params, 'stopLossPrice');
        }
        let response = undefined;
        if (market['settle'] === 'USDT') {
            response = await this.privatePostGOrders(this.extend(request, params));
        }
        else if (market['contract']) {
            response = await this.privatePostOrders(this.extend(request, params));
        }
        else {
            response = await this.privatePostSpotOrders(this.extend(request, params));
        }
        //
        // spot
        //
        //     {
        //         "code": 0,
        //         "msg": "",
        //         "data": {
        //             "orderID": "d1d09454-cabc-4a23-89a7-59d43363f16d",
        //             "clOrdID": "309bcd5c-9f6e-4a68-b775-4494542eb5cb",
        //             "priceEp": 0,
        //             "action": "New",
        //             "trigger": "UNSPECIFIED",
        //             "pegPriceType": "UNSPECIFIED",
        //             "stopDirection": "UNSPECIFIED",
        //             "bizError": 0,
        //             "symbol": "sBTCUSDT",
        //             "side": "Buy",
        //             "baseQtyEv": 0,
        //             "ordType": "Limit",
        //             "timeInForce": "GoodTillCancel",
        //             "ordStatus": "Created",
        //             "cumFeeEv": 0,
        //             "cumBaseQtyEv": 0,
        //             "cumQuoteQtyEv": 0,
        //             "leavesBaseQtyEv": 0,
        //             "leavesQuoteQtyEv": 0,
        //             "avgPriceEp": 0,
        //             "cumBaseAmountEv": 0,
        //             "cumQuoteAmountEv": 0,
        //             "quoteQtyEv": 0,
        //             "qtyType": "ByBase",
        //             "stopPxEp": 0,
        //             "pegOffsetValueEp": 0
        //         }
        //     }
        //
        // swap
        //
        //     {
        //         "code":0,
        //         "msg":"",
        //         "data":{
        //             "bizError":0,
        //             "orderID":"7a1ad384-44a3-4e54-a102-de4195a29e32",
        //             "clOrdID":"",
        //             "symbol":"ETHUSD",
        //             "side":"Buy",
        //             "actionTimeNs":1592668973945065381,
        //             "transactTimeNs":0,
        //             "orderType":"Market",
        //             "priceEp":2267500,
        //             "price":226.75000000,
        //             "orderQty":1,
        //             "displayQty":0,
        //             "timeInForce":"ImmediateOrCancel",
        //             "reduceOnly":false,
        //             "closedPnlEv":0,
        //             "closedPnl":0E-8,
        //             "closedSize":0,
        //             "cumQty":0,
        //             "cumValueEv":0,
        //             "cumValue":0E-8,
        //             "leavesQty":1,
        //             "leavesValueEv":11337,
        //             "leavesValue":1.13370000,
        //             "stopDirection":"UNSPECIFIED",
        //             "stopPxEp":0,
        //             "stopPx":0E-8,
        //             "trigger":"UNSPECIFIED",
        //             "pegOffsetValueEp":0,
        //             "execStatus":"PendingNew",
        //             "pegPriceType":"UNSPECIFIED",
        //             "ordStatus":"Created"
        //         }
        //     }
        //
        const data = this.safeDict(response, 'data', {});
        return this.parseOrder(data, market);
    }
    /**
     * @method
     * @name phemex#editOrder
     * @description edit a trade order
     * @see https://github.com/phemex/phemex-api-docs/blob/master/Public-Hedged-Perpetual-API.md#amend-order-by-orderid
     * @param {string} id cancel order id
     * @param {string} symbol unified symbol of the market to create an order in
     * @param {string} type 'market' or 'limit'
     * @param {string} side 'buy' or 'sell'
     * @param {float} amount how much of currency you want to trade in units of base currency
     * @param {float} [price] the price at which the order is to be fulfilled, in units of the quote currency, ignored in market orders
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @param {string} [params.posSide] either 'Merged' or 'Long' or 'Short'
     * @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
     */
    async editOrder(id, symbol, type, side, amount = undefined, price = undefined, params = {}) {
        await this.loadMarkets();
        const market = this.market(symbol);
        const request = {
            'symbol': market['id'],
        };
        const clientOrderId = this.safeString2(params, 'clientOrderId', 'clOrdID');
        params = this.omit(params, ['clientOrderId', 'clOrdID']);
        const isUSDTSettled = (market['settle'] === 'USDT');
        if (clientOrderId !== undefined) {
            request['clOrdID'] = clientOrderId;
        }
        else {
            request['orderID'] = id;
        }
        if (price !== undefined) {
            if (isUSDTSettled) {
                request['priceRp'] = this.priceToPrecision(market['symbol'], price);
            }
            else {
                request['priceEp'] = this.toEp(price, market);
            }
        }
        // Note the uppercase 'V' in 'baseQtyEV' request. that is exchange's requirement at this moment. However, to avoid mistakes from user side, let's support lowercased 'baseQtyEv' too
        const finalQty = this.safeString(params, 'baseQtyEv');
        params = this.omit(params, ['baseQtyEv']);
        if (finalQty !== undefined) {
            request['baseQtyEV'] = finalQty;
        }
        else if (amount !== undefined) {
            if (isUSDTSettled) {
                request['orderQtyRq'] = this.amountToPrecision(market['symbol'], amount);
            }
            else {
                request['baseQtyEV'] = this.toEv(amount, market);
            }
        }
        const triggerPrice = this.safeStringN(params, ['triggerPrice', 'stopPx', 'stopPrice']);
        if (triggerPrice !== undefined) {
            if (isUSDTSettled) {
                request['stopPxRp'] = this.priceToPrecision(symbol, triggerPrice);
            }
            else {
                request['stopPxEp'] = this.toEp(triggerPrice, market);
            }
        }
        params = this.omit(params, ['triggerPrice', 'stopPx', 'stopPrice']);
        let response = undefined;
        if (isUSDTSettled) {
            const posSide = this.safeString(params, 'posSide');
            if (posSide === undefined) {
                request['posSide'] = 'Merged';
            }
            response = await this.privatePutGOrdersReplace(this.extend(request, params));
        }
        else if (market['swap']) {
            response = await this.privatePutOrdersReplace(this.extend(request, params));
        }
        else {
            response = await this.privatePutSpotOrders(this.extend(request, params));
        }
        const data = this.safeDict(response, 'data', {});
        return this.parseOrder(data, market);
    }
    /**
     * @method
     * @name phemex#cancelOrder
     * @description cancels an open order
     * @see https://github.com/phemex/phemex-api-docs/blob/master/Public-Hedged-Perpetual-API.md#cancel-single-order-by-orderid
     * @param {string} id order id
     * @param {string} symbol unified symbol of the market the order was made in
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @param {string} [params.posSide] either 'Merged' or 'Long' or 'Short'
     * @returns {object} An [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
     */
    async cancelOrder(id, symbol = undefined, params = {}) {
        if (symbol === undefined) {
            throw new errors.ArgumentsRequired(this.id + ' cancelOrder() requires a symbol argument');
        }
        await this.loadMarkets();
        const market = this.market(symbol);
        const request = {
            'symbol': market['id'],
        };
        const clientOrderId = this.safeString2(params, 'clientOrderId', 'clOrdID');
        params = this.omit(params, ['clientOrderId', 'clOrdID']);
        if (clientOrderId !== undefined) {
            request['clOrdID'] = clientOrderId;
        }
        else {
            request['orderID'] = id;
        }
        let response = undefined;
        if (market['settle'] === 'USDT') {
            const posSide = this.safeString(params, 'posSide');
            if (posSide === undefined) {
                request['posSide'] = 'Merged';
            }
            response = await this.privateDeleteGOrdersCancel(this.extend(request, params));
        }
        else if (market['swap']) {
            response = await this.privateDeleteOrdersCancel(this.extend(request, params));
        }
        else {
            response = await this.privateDeleteSpotOrders(this.extend(request, params));
        }
        const data = this.safeDict(response, 'data', {});
        return this.parseOrder(data, market);
    }
    /**
     * @method
     * @name phemex#cancelAllOrders
     * @description cancel all open orders in a market
     * @see https://github.com/phemex/phemex-api-docs/blob/master/Public-Hedged-Perpetual-API.md#cancelall
     * @param {string} symbol unified market symbol of the market to cancel orders in
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @returns {object[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
     */
    async cancelAllOrders(symbol = undefined, params = {}) {
        if (symbol === undefined) {
            throw new errors.ArgumentsRequired(this.id + ' cancelAllOrders() requires a symbol argument');
        }
        await this.loadMarkets();
        const market = this.market(symbol);
        const trigger = this.safeValue2(params, 'stop', 'trigger', false);
        params = this.omit(params, ['stop', 'trigger']);
        const request = {
            'symbol': market['id'],
            // 'untriggerred': false, // false to cancel non-conditional orders, true to cancel conditional orders
            // 'text': 'up to 40 characters max',
        };
        if (trigger) {
            request['untriggerred'] = trigger;
        }
        let response = undefined;
        if (market['settle'] === 'USDT') {
            response = await this.privateDeleteGOrdersAll(this.extend(request, params));
            //
            //    {
            //        code: '0',
            //        msg: '',
            //        data: '1'
            //    }
            //
        }
        else if (market['swap']) {
            response = await this.privateDeleteOrdersAll(this.extend(request, params));
            //
            //    {
            //        code: '0',
            //        msg: '',
            //        data: '1'
            //    }
            //
        }
        else {
            response = await this.privateDeleteSpotOrdersAll(this.extend(request, params));
            //
            //    {
            //        code: '0',
            //        msg: '',
            //        data: {
            //            total: '1'
            //        }
            //    }
            //
        }
        return [
            this.safeOrder({
                'info': response,
            }),
        ];
    }
    /**
     * @method
     * @name phemex#fetchOrder
     * @see https://phemex-docs.github.io/#query-orders-by-ids
     * @description fetches information on an order made by the user
     * @param {string} id the order id
     * @param {string} symbol unified symbol of the market the order was made in
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @returns {object} An [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
     */
    async fetchOrder(id, symbol = undefined, params = {}) {
        if (symbol === undefined) {
            throw new errors.ArgumentsRequired(this.id + ' fetchOrder() requires a symbol argument');
        }
        await this.loadMarkets();
        const market = this.market(symbol);
        const request = {
            'symbol': market['id'],
        };
        const clientOrderId = this.safeString2(params, 'clientOrderId', 'clOrdID');
        params = this.omit(params, ['clientOrderId', 'clOrdID']);
        if (clientOrderId !== undefined) {
            request['clOrdID'] = clientOrderId;
        }
        else {
            request['orderID'] = id;
        }
        let response = undefined;
        if (market['settle'] === 'USDT') {
            response = await this.privateGetApiDataGFuturesOrdersByOrderId(this.extend(request, params));
        }
        else if (market['spot']) {
            response = await this.privateGetApiDataSpotsOrdersByOrderId(this.extend(request, params));
        }
        else {
            response = await this.privateGetExchangeOrder(this.extend(request, params));
        }
        const data = this.safeValue(response, 'data', {});
        let order = data;
        if (Array.isArray(data)) {
            const numOrders = data.length;
            if (numOrders < 1) {
                if (clientOrderId !== undefined) {
                    throw new errors.OrderNotFound(this.id + ' fetchOrder() ' + symbol + ' order with clientOrderId ' + clientOrderId + ' not found');
                }
                else {
                    throw new errors.OrderNotFound(this.id + ' fetchOrder() ' + symbol + ' order with id ' + id + ' not found');
                }
            }
            order = this.safeDict(data, 0, {});
        }
        else if (market['spot']) {
            const rows = this.safeList(data, 'rows', []);
            order = this.safeDict(rows, 0, {});
        }
        return this.parseOrder(order, market);
    }
    /**
     * @method
     * @name phemex#fetchOrders
     * @description fetches information on multiple orders made by the user
     * @see https://github.com/phemex/phemex-api-docs/blob/master/Public-Hedged-Perpetual-API.md#queryorder
     * @param {string} symbol unified market symbol of the market orders were made in
     * @param {int} [since] the earliest time in ms to fetch orders for
     * @param {int} [limit] the maximum number of order structures to retrieve
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @returns {Order[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
     */
    async fetchOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
        if (symbol === undefined) {
            throw new errors.ArgumentsRequired(this.id + ' fetchOrders() requires a symbol argument');
        }
        await this.loadMarkets();
        const market = this.market(symbol);
        const request = {
            'symbol': market['id'],
        };
        if (since !== undefined) {
            request['start'] = since;
        }
        if (limit !== undefined) {
            request['limit'] = limit;
        }
        let response = undefined;
        if (market['settle'] === 'USDT') {
            request['currency'] = market['settle'];
            response = await this.privateGetExchangeOrderV2OrderList(this.extend(request, params));
        }
        else if (market['swap']) {
            response = await this.privateGetExchangeOrderList(this.extend(request, params));
        }
        else {
            response = await this.privateGetApiDataSpotsOrders(this.extend(request, params));
        }
        const data = this.safeValue(response, 'data', {});
        const rows = this.safeList(data, 'rows', data);
        return this.parseOrders(rows, market, since, limit);
    }
    /**
     * @method
     * @name phemex#fetchOpenOrders
     * @description fetch all unfilled currently open orders
     * @see https://github.com/phemex/phemex-api-docs/blob/master/Public-Hedged-Perpetual-API.md#queryopenorder
     * @see https://github.com/phemex/phemex-api-docs/blob/master/Public-Contract-API-en.md
     * @see https://github.com/phemex/phemex-api-docs/blob/master/Public-Spot-API-en.md#spotListAllOpenOrder
     * @param {string} symbol unified market symbol
     * @param {int} [since] the earliest time in ms to fetch open orders for
     * @param {int} [limit] the maximum number of open order structures to retrieve
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @returns {Order[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
     */
    async fetchOpenOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
        await this.loadMarkets();
        if (symbol === undefined) {
            throw new errors.ArgumentsRequired(this.id + ' fetchOpenOrders() requires a symbol argument');
        }
        await this.loadMarkets();
        const market = this.market(symbol);
        const request = {
            'symbol': market['id'],
        };
        let response = undefined;
        try {
            if (market['settle'] === 'USDT') {
                response = await this.privateGetGOrdersActiveList(this.extend(request, params));
            }
            else if (market['swap']) {
                response = await this.privateGetOrdersActiveList(this.extend(request, params));
            }
            else {
                response = await this.privateGetSpotOrders(this.extend(request, params));
            }
        }
        catch (e) {
            if (e instanceof errors.OrderNotFound) {
                return [];
            }
            throw e;
        }
        const data = this.safeValue(response, 'data', {});
        if (Array.isArray(data)) {
            return this.parseOrders(data, market, since, limit);
        }
        else {
            const rows = this.safeList(data, 'rows', []);
            return this.parseOrders(rows, market, since, limit);
        }
    }
    /**
     * @method
     * @name phemex#fetchClosedOrders
     * @description fetches information on multiple closed orders made by the user
     * @see https://github.com/phemex/phemex-api-docs/blob/master/Public-Hedged-Perpetual-API.md#queryorder
     * @see https://github.com/phemex/phemex-api-docs/blob/master/Public-Contract-API-en.md#queryorder
     * @see https://github.com/phemex/phemex-api-docs/blob/master/Public-Hedgedd-Perpetual-API.md#query-closed-orders-by-symbol
     * @see https://github.com/phemex/phemex-api-docs/blob/master/Public-Spot-API-en.md#spotDataOrdersByIds
     * @param {string} symbol unified market symbol of the market orders were made in
     * @param {int} [since] the earliest time in ms to fetch orders for
     * @param {int} [limit] the maximum number of order structures to retrieve
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @param {string} [params.settle] the settlement currency to fetch orders for
     * @returns {Order[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
     */
    async fetchClosedOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
        await this.loadMarkets();
        let market = undefined;
        if (symbol !== undefined) {
            market = this.market(symbol);
        }
        const request = {};
        if (market !== undefined) {
            request['symbol'] = market['id'];
        }
        if (since !== undefined) {
            request['start'] = since;
        }
        if (limit !== undefined) {
            request['limit'] = limit;
        }
        let response = undefined;
        if ((symbol === undefined) || (this.safeString(market, 'settle') === 'USDT')) {
            request['currency'] = this.safeString(params, 'settle', 'USDT');
            response = await this.privateGetExchangeOrderV2OrderList(this.extend(request, params));
        }
        else if (market['swap']) {
            response = await this.privateGetExchangeOrderList(this.extend(request, params));
        }
        else {
            response = await this.privateGetExchangeSpotOrder(this.extend(request, params));
        }
        //
        // spot
        //
        //     {
        //         "code":0,
        //         "msg":"OK",
        //         "data":{
        //             "total":8,
        //             "rows":[
        //                 {
        //                     "orderID":"99232c3e-3d6a-455f-98cc-2061cdfe91bc",
        //                     "stopPxEp":0,
        //                     "avgPriceEp":0,
        //                     "qtyType":"ByBase",
        //                     "leavesBaseQtyEv":0,
        //                     "leavesQuoteQtyEv":0,
        //                     "baseQtyEv":"1000000000",
        //                     "feeCurrency":"4",
        //                     "stopDirection":"UNSPECIFIED",
        //                     "symbol":"sETHUSDT",
        //                     "side":"Buy",
        //                     "quoteQtyEv":250000000000,
        //                     "priceEp":25000000000,
        //                     "ordType":"Limit",
        //                     "timeInForce":"GoodTillCancel",
        //                     "ordStatus":"Rejected",
        //                     "execStatus":"NewRejected",
        //                     "createTimeNs":1592675305266037130,
        //                     "cumFeeEv":0,
        //                     "cumBaseValueEv":0,
        //                     "cumQuoteValueEv":0
        //                 },
        //             ]
        //         }
        //     }
        //
        const data = this.safeValue(response, 'data', {});
        if (Array.isArray(data)) {
            return this.parseOrders(data, market, since, limit);
        }
        else {
            const rows = this.safeList(data, 'rows', []);
            return this.parseOrders(rows, market, since, limit);
        }
    }
    /**
     * @method
     * @name phemex#fetchMyTrades
     * @description fetch all trades made by the user
     * @see https://github.com/phemex/phemex-api-docs/blob/master/Public-Contract-API-en.md#query-user-trade
     * @see https://github.com/phemex/phemex-api-docs/blob/master/Public-Hedged-Perpetual-API.md#query-user-trade
     * @see https://github.com/phemex/phemex-api-docs/blob/master/Public-Spot-API-en.md#spotDataTradesHist
     * @param {string} symbol unified market symbol
     * @param {int} [since] the earliest time in ms to fetch trades for
     * @param {int} [limit] the maximum number of trades structures to retrieve
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @returns {Trade[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=trade-structure}
     */
    async fetchMyTrades(symbol = undefined, since = undefined, limit = undefined, params = {}) {
        await this.loadMarkets();
        let market = undefined;
        if (symbol !== undefined) {
            market = this.market(symbol);
        }
        const request = {};
        if (limit !== undefined) {
            limit = Math.min(200, limit);
            request['limit'] = limit;
        }
        const isUSDTSettled = (symbol === undefined) || (this.safeString(market, 'settle') === 'USDT');
        if (isUSDTSettled) {
            request['currency'] = 'USDT';
            request['offset'] = 0;
            if (limit === undefined) {
                request['limit'] = 200;
            }
        }
        else {
            request['symbol'] = market['id'];
        }
        if (since !== undefined) {
            request['start'] = since;
        }
        let response = undefined;
        if (isUSDTSettled) {
            response = await this.privateGetExchangeOrderV2TradingList(this.extend(request, params));
        }
        else if (market['swap']) {
            response = await this.privateGetExchangeOrderTrade(this.extend(request, params));
        }
        else {
            response = await this.privateGetExchangeSpotOrderTrades(this.extend(request, params));
        }
        //
        // spot
        //
        //     {
        //         "code": 0,
        //         "msg": "OK",
        //         "data": {
        //             "total": 1,
        //             "rows": [
        //                 {
        //                     "qtyType": "ByQuote",
        //                     "transactTimeNs": 1589450974800550100,
        //                     "clOrdID": "8ba59d40-df25-d4b0-14cf-0703f44e9690",
        //                     "orderID": "b2b7018d-f02f-4c59-b4cf-051b9c2d2e83",
        //                     "symbol": "sBTCUSDT",
        //                     "side": "Buy",
        //                     "priceEP": 970056000000,
        //                     "baseQtyEv": 0,
        //                     "quoteQtyEv": 1000000000,
        //                     "action": "New",
        //                     "execStatus": "MakerFill",
        //                     "ordStatus": "Filled",
        //                     "ordType": "Limit",
        //                     "execInst": "None",
        //                     "timeInForce": "GoodTillCancel",
        //                     "stopDirection": "UNSPECIFIED",
        //                     "tradeType": "Trade",
        //                     "stopPxEp": 0,
        //                     "execId": "c6bd8979-07ba-5946-b07e-f8b65135dbb1",
        //                     "execPriceEp": 970056000000,
        //                     "execBaseQtyEv": 103000,
        //                     "execQuoteQtyEv": 999157680,
        //                     "leavesBaseQtyEv": 0,
        //                     "leavesQuoteQtyEv": 0,
        //                     "execFeeEv": 0,
        //                     "feeRateEr": 0
        //                 }
        //             ]
        //         }
        //     }
        //
        //
        // swap
        //
        //     {
        //         "code": 0,
        //         "msg": "OK",
        //         "data": {
        //             "total": 79,
        //             "rows": [
        //                 {
        //                     "transactTimeNs": 1606054879331565300,
        //                     "symbol": "BTCUSD",
        //                     "currency": "BTC",
        //                     "action": "New",
        //                     "side": "Buy",
        //                     "tradeType": "Trade",
        //                     "execQty": 5,
        //                     "execPriceEp": 182990000,
        //                     "orderQty": 5,
        //                     "priceEp": 183870000,
        //                     "execValueEv": 27323,
        //                     "feeRateEr": 75000,
        //                     "execFeeEv": 21,
        //                     "ordType": "Market",
        //                     "execID": "5eee56a4-04a9-5677-8eb0-c2fe22ae3645",
        //                     "orderID": "ee0acb82-f712-4543-a11d-d23efca73197",
        //                     "clOrdID": "",
        //                     "execStatus": "TakerFill"
        //                 },
        //             ]
        //         }
        //     }
        //
        // swap - usdt
        //
        // {
        //     "code": 0,
        //     "msg": "OK",
        //     "data": {
        //         "total": 4,
        //         "rows": [
        //             {
        //                 "createdAt": 1666226932259,
        //                 "symbol": "ETHUSDT",
        //                 "currency": "USDT",
        //                 "action": 1,
        //                 "tradeType": 1,
        //                 "execQtyRq": "0.01",
        //                 "execPriceRp": "1271.9",
        //                 "side": 1,
        //                 "orderQtyRq": "0.78",
        //                 "priceRp": "1271.9",
        //                 "execValueRv": "12.719",
        //                 "feeRateRr": "0.0001",
        //                 "execFeeRv": "0.0012719",
        //                 "ordType": 2,
        //                 "execId": "8718cae",
        //                 "execStatus": 6
        //             },
        //         ]
        //     }
        // }
        //
        let data = undefined;
        if (isUSDTSettled) {
            data = this.safeValue(response, 'data', []);
        }
        else {
            data = this.safeValue(response, 'data', {});
            data = this.safeValue(data, 'rows', []);
        }
        return this.parseTrades(data, market, since, limit);
    }
    /**
     * @method
     * @name phemex#fetchDepositAddress
     * @description fetch the deposit address for a currency associated with this account
     * @param {string} code unified currency code
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @param {string} [params.network] the chain name to fetch the deposit address e.g. ETH, TRX, EOS, SOL, etc.
     * @returns {object} an [address structure]{@link https://docs.ccxt.com/#/?id=address-structure}
     */
    async fetchDepositAddress(code, params = {}) {
        await this.loadMarkets();
        const currency = this.currency(code);
        const request = {
            'currency': currency['id'],
        };
        const defaultNetworks = this.safeDict(this.options, 'defaultNetworks');
        const defaultNetwork = this.safeStringUpper(defaultNetworks, code);
        const networks = this.safeDict(this.options, 'networks', {});
        let network = this.safeStringUpper2(params, 'network', 'chainName', defaultNetwork);
        network = this.safeString(networks, network, network);
        if (network === undefined) {
            throw new errors.ArgumentsRequired(this.id + ' fetchDepositAddress() requires a network parameter');
        }
        else {
            request['chainName'] = network;
            params = this.omit(params, 'network');
        }
        const response = await this.privateGetExchangeWalletsV2DepositAddress(this.extend(request, params));
        //
        //     {
        //         "code": 0,
        //         "msg": "OK",
        //         "data": {
        //             "address": "tb1qxel5wq5gumt",
        //             "tag": "",
        //             "notice": false,
        //             "accountType": 1,
        //             "contractName": null,
        //             "chainTokenUrl": null,
        //             "sign": null
        //         }
        //     }
        //
        const data = this.safeValue(response, 'data', {});
        const address = this.safeString(data, 'address');
        const tag = this.safeString(data, 'tag');
        this.checkAddress(address);
        return {
            'info': response,
            'currency': code,
            'network': undefined,
            'address': address,
            'tag': tag,
        };
    }
    /**
     * @method
     * @name phemex#fetchDeposits
     * @description fetch all deposits made to an account
     * @param {string} code unified currency code
     * @param {int} [since] the earliest time in ms to fetch deposits for
     * @param {int} [limit] the maximum number of deposits structures to retrieve
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @returns {object[]} a list of [transaction structures]{@link https://docs.ccxt.com/#/?id=transaction-structure}
     */
    async fetchDeposits(code = undefined, since = undefined, limit = undefined, params = {}) {
        await this.loadMarkets();
        let currency = undefined;
        if (code !== undefined) {
            currency = this.currency(code);
        }
        const response = await this.privateGetExchangeWalletsDepositList(params);
        //
        //     {
        //         "code":0,
        //         "msg":"OK",
        //         "data":[
        //             {
        //                 "id":29200,
        //                 "currency":"USDT",
        //                 "currencyCode":3,
        //                 "txHash":"0x0bdbdc47807769a03b158d5753f54dfc58b92993d2f5e818db21863e01238e5d",
        //                 "address":"0x5bfbf60e0fa7f63598e6cfd8a7fd3ffac4ccc6ad",
        //                 "amountEv":3000000000,
        //                 "confirmations":13,
        //                 "type":"Deposit",
        //                 "status":"Success",
        //                 "createdAt":1592722565000
        //             }
        //         ]
        //     }
        //
        const data = this.safeList(response, 'data', []);
        return this.parseTransactions(data, currency, since, limit);
    }
    /**
     * @method
     * @name phemex#fetchWithdrawals
     * @description fetch all withdrawals made from an account
     * @param {string} code unified currency code
     * @param {int} [since] the earliest time in ms to fetch withdrawals for
     * @param {int} [limit] the maximum number of withdrawals structures to retrieve
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @returns {object[]} a list of [transaction structures]{@link https://docs.ccxt.com/#/?id=transaction-structure}
     */
    async fetchWithdrawals(code = undefined, since = undefined, limit = undefined, params = {}) {
        await this.loadMarkets();
        let currency = undefined;
        if (code !== undefined) {
            currency = this.currency(code);
        }
        const response = await this.privateGetExchangeWalletsWithdrawList(params);
        //
        //     {
        //         "code":0,
        //         "msg":"OK",
        //         "data":[
        //             {
        //                 "address": "1Lxxxxxxxxxxx"
        //                 "amountEv": 200000
        //                 "currency": "BTC"
        //                 "currencyCode": 1
        //                 "expiredTime": 0
        //                 "feeEv": 50000
        //                 "rejectReason": null
        //                 "status": "Succeed"
        //                 "txHash": "44exxxxxxxxxxxxxxxxxxxxxx"
        //                 "withdrawStatus: ""
        //             }
        //         ]
        //     }
        //
        const data = this.safeList(response, 'data', []);
        return this.parseTransactions(data, currency, since, limit);
    }
    parseTransactionStatus(status) {
        const statuses = {
            'Success': 'ok',
            'Succeed': 'ok',
            'Rejected': 'failed',
            'Security check failed': 'failed',
            'SecurityCheckFailed': 'failed',
            'Expired': 'failed',
            'Address Risk': 'failed',
            'Security Checking': 'pending',
            'SecurityChecking': 'pending',
            'Pending Review': 'pending',
            'Pending Transfer': 'pending',
            'AmlCsApporve': 'pending',
            'New': 'pending',
            'Confirmed': 'pending',
            'Cancelled': 'canceled',
        };
        return this.safeString(statuses, status, status);
    }
    parseTransaction(transaction, currency = undefined) {
        //
        // withdraw
        //
        //     {
        //         "id": "10000001",
        //         "freezeId": null,
        //         "address": "44exxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
        //         "amountRv": "100",
        //         "chainCode": "11",
        //         "chainName": "TRX",
        //         "currency": "USDT",
        //         "currencyCode": 3,
        //         "email": "abc@gmail.com",
        //         "expiredTime": "0",
        //         "feeRv": "1",
        //         "nickName": null,
        //         "phone": null,
        //         "rejectReason": "",
        //         "submitedAt": "1670000000000",
        //         "submittedAt": "1670000000000",
        //         "txHash": null,
        //         "userId": "10000001",
        //         "status": "Success"
        //
        // fetchDeposits
        //
        //     {
        //         "id": "29200",
        //         "currency": "USDT",
        //         "currencyCode": "3",
        //         "chainName": "ETH",
        //         "chainCode": "4",
        //         "txHash": "0x0bdbdc47807769a03b158d5753f54dfc58b92993d2f5e818db21863e01238e5d",
        //         "address": "0x5bfbf60e0fa7f63598e6cfd8a7fd3ffac4ccc6ad",
        //         "amountEv": "3000000000",
        //         "confirmations": "13",
        //         "type": "Deposit",
        //         "status": "Success",
        //         "createdAt": "1592722565000",
        //     }
        //
        // fetchWithdrawals
        //
        //     {
        //         "id": "10000001",
        //         "userId": "10000001",
        //         "freezeId": "10000002",
        //         "phone": null,
        //         "email": "abc@gmail.com",
        //         "nickName": null,
        //         "currency": "USDT",
        //         "currencyCode": "3",
        //         "status": "Succeed",
        //         "withdrawStatus": "Succeed",
        //         "amountEv": "8800000000",
        //         "feeEv": "1200000000",
        //         "address": "0x5xxxad",
        //         "txHash: "0x0xxxx5d",
        //         "submitedAt": "1702571922000",
        //         "submittedAt": "1702571922000",
        //         "expiredTime": "0",
        //         "rejectReason": null,
        //         "chainName": "ETH",
        //         "chainCode": "4",
        //         "proxyAddress": null
        //     }
        //
        const id = this.safeString(transaction, 'id');
        const address = this.safeString(transaction, 'address');
        const tag = undefined;
        const txid = this.safeString(transaction, 'txHash');
        const currencyId = this.safeString(transaction, 'currency');
        currency = this.safeCurrency(currencyId, currency);
        const code = currency['code'];
        const networkId = this.safeString(transaction, 'chainName');
        const timestamp = this.safeIntegerN(transaction, ['createdAt', 'submitedAt', 'submittedAt']);
        let type = this.safeStringLower(transaction, 'type');
        let feeCost = this.parseNumber(this.fromEn(this.safeString(transaction, 'feeEv'), currency['valueScale']));
        if (feeCost === undefined) {
            feeCost = this.safeNumber(transaction, 'feeRv');
        }
        let fee = undefined;
        if (feeCost !== undefined) {
            type = 'withdrawal';
            fee = {
                'cost': feeCost,
                'currency': code,
            };
        }
        const status = this.parseTransactionStatus(this.safeString(transaction, 'status'));
        let amount = this.parseNumber(this.fromEn(this.safeString(transaction, 'amountEv'), currency['valueScale']));
        if (amount === undefined) {
            amount = this.safeNumber(transaction, 'amountRv');
        }
        return {
            'info': transaction,
            'id': id,
            'txid': txid,
            'timestamp': timestamp,
            'datetime': this.iso8601(timestamp),
            'network': this.networkIdToCode(networkId),
            'address': address,
            'addressTo': address,
            'addressFrom': undefined,
            'tag': tag,
            'tagTo': tag,
            'tagFrom': undefined,
            'type': type,
            'amount': amount,
            'currency': code,
            'status': status,
            'updated': undefined,
            'comment': undefined,
            'internal': undefined,
            'fee': fee,
        };
    }
    /**
     * @method
     * @name phemex#fetchPositions
     * @description fetch all open positions
     * @see https://github.com/phemex/phemex-api-docs/blob/master/Public-Contract-API-en.md#query-trading-account-and-positions
     * @see https://github.com/phemex/phemex-api-docs/blob/master/Public-Hedged-Perpetual-API.md#query-account-positions
     * @see https://phemex-docs.github.io/#query-account-positions-with-unrealized-pnl
     * @param {string[]} [symbols] list of unified market symbols
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @param {string} [params.code] the currency code to fetch positions for, USD, BTC or USDT, USDT is the default
     * @param {string} [params.method] *USDT contracts only* 'privateGetGAccountsAccountPositions' or 'privateGetAccountsPositions' default is 'privateGetGAccountsAccountPositions'
     * @returns {object[]} a list of [position structure]{@link https://docs.ccxt.com/#/?id=position-structure}
     */
    async fetchPositions(symbols = undefined, params = {}) {
        await this.loadMarkets();
        symbols = this.marketSymbols(symbols);
        let subType = undefined;
        let code = this.safeString2(params, 'currency', 'code', 'USDT');
        params = this.omit(params, ['currency', 'code']);
        let settle = undefined;
        let market = undefined;
        const firstSymbol = this.safeString(symbols, 0);
        if (firstSymbol !== undefined) {
            market = this.market(firstSymbol);
            settle = market['settle'];
            code = market['settle'];
        }
        else {
            [settle, params] = this.handleOptionAndParams(params, 'fetchPositions', 'settle', code);
        }
        [subType, params] = this.handleSubTypeAndParams('fetchPositions', market, params);
        const isUSDTSettled = settle === 'USDT';
        if (isUSDTSettled) {
            code = 'USDT';
        }
        else if (settle === 'BTC') {
            code = 'BTC';
        }
        else if (code === undefined) {
            code = (subType === 'linear') ? 'USD' : 'BTC';
        }
        const currency = this.currency(code);
        const request = {
            'currency': currency['id'],
        };
        let response = undefined;
        if (isUSDTSettled) {
            let method = undefined;
            [method, params] = this.handleOptionAndParams(params, 'fetchPositions', 'method', 'privateGetGAccountsAccountPositions');
            if (method === 'privateGetGAccountsAccountPositions') {
                response = await this.privateGetGAccountsAccountPositions(this.extend(request, params));
            }
            else {
                response = await this.privateGetAccountsPositions(this.extend(request, params));
            }
        }
        else {
            response = await this.privateGetAccountsAccountPositions(this.extend(request, params));
        }
        //
        //     {
        //         "code":0,"msg":"",
        //         "data":{
        //             "account":{
        //                 "accountId":6192120001,
        //                 "currency":"BTC",
        //                 "accountBalanceEv":1254744,
        //                 "totalUsedBalanceEv":0,
        //                 "bonusBalanceEv":1254744
        //             },
        //             "positions":[
        //                 {
        //                     "accountID":6192120001,
        //                     "symbol":"BTCUSD",
        //                     "currency":"BTC",
        //                     "side":"None",
        //                     "positionStatus":"Normal",
        //                     "crossMargin":false,
        //                     "leverageEr":100000000,
        //                     "leverage":1.00000000,
        //                     "initMarginReqEr":100000000,
        //                     "initMarginReq":1.00000000,
        //                     "maintMarginReqEr":500000,
        //                     "maintMarginReq":0.00500000,
        //                     "riskLimitEv":10000000000,
        //                     "riskLimit":100.00000000,
        //                     "size":0,
        //                     "value":0E-8,
        //                     "valueEv":0,
        //                     "avgEntryPriceEp":0,
        //                     "avgEntryPrice":0E-8,
        //                     "posCostEv":0,
        //                     "posCost":0E-8,
        //                     "assignedPosBalanceEv":0,
        //                     "assignedPosBalance":0E-8,
        //                     "bankruptCommEv":0,
        //                     "bankruptComm":0E-8,
        //                     "bankruptPriceEp":0,
        //                     "bankruptPrice":0E-8,
        //                     "positionMarginEv":0,
        //                     "positionMargin":0E-8,
        //                     "liquidationPriceEp":0,
        //                     "liquidationPrice":0E-8,
        //                     "deleveragePercentileEr":0,
        //                     "deleveragePercentile":0E-8,
        //                     "buyValueToCostEr":100225000,
        //                     "buyValueToCost":1.00225000,
        //                     "sellValueToCostEr":100075000,
        //                     "sellValueToCost":1.00075000,
        //                     "markPriceEp":135736070,
        //                     "markPrice":13573.60700000,
        //                     "markValueEv":0,
        //                     "markValue":null,
        //                     "unRealisedPosLossEv":0,
        //                     "unRealisedPosLoss":null,
        //                     "estimatedOrdLossEv":0,
        //                     "estimatedOrdLoss":0E-8,
        //                     "usedBalanceEv":0,
        //                     "usedBalance":0E-8,
        //                     "takeProfitEp":0,
        //                     "takeProfit":null,
        //                     "stopLossEp":0,
        //                     "stopLoss":null,
        //                     "cumClosedPnlEv":0,
        //                     "cumFundingFeeEv":0,
        //                     "cumTransactFeeEv":0,
        //                     "realisedPnlEv":0,
        //                     "realisedPnl":null,
        //                     "cumRealisedPnlEv":0,
        //                     "cumRealisedPnl":null
        //                 }
        //             ]
        //         }
        //     }
        //
        const data = this.safeValue(response, 'data', {});
        const positions = this.safeValue(data, 'positions', []);
        const result = [];
        for (let i = 0; i < positions.length; i++) {
            const position = positions[i];
            result.push(this.parsePosition(position));
        }
        return this.filterByArrayPositions(result, 'symbol', symbols, false);
    }
    parsePosition(position, market = undefined) {
        //
        //    {
        //        "userID": "811370",
        //        "accountID": "8113700002",
        //        "symbol": "ETHUSD",
        //        "currency": "USD",
        //        "side": "Buy",
        //        "positionStatus": "Normal",
        //        "crossMargin": false,
        //        "leverageEr": "200000000",
        //        "leverage": "2.00000000",
        //        "initMarginReqEr": "50000000",
        //        "initMarginReq": "0.50000000",
        //        "maintMarginReqEr": "1000000",
        //        "maintMarginReq": "0.01000000",
        //        "riskLimitEv": "5000000000",
        //        "riskLimit": "500000.00000000",
        //        "size": "1",
        //        "value": "22.22370000",
        //        "valueEv": "222237",
        //        "avgEntryPriceEp": "44447400",
        //        "avgEntryPrice": "4444.74000000",
        //        "posCostEv": "111202",
        //        "posCost": "11.12020000",
        //        "assignedPosBalanceEv": "111202",
        //        "assignedPosBalance": "11.12020000",
        //        "bankruptCommEv": "84",
        //        "bankruptComm": "0.00840000",
        //        "bankruptPriceEp": "22224000",
        //        "bankruptPrice": "2222.40000000",
        //        "positionMarginEv": "111118",
        //        "positionMargin": "11.11180000",
        //        "liquidationPriceEp": "22669000",
        //        "liquidationPrice": "2266.90000000",
        //        "deleveragePercentileEr": "0",
        //        "deleveragePercentile": "0E-8",
        //        "buyValueToCostEr": "50112500",
        //        "buyValueToCost": "0.50112500",
        //        "sellValueToCostEr": "50187500",
        //        "sellValueToCost": "0.50187500",
        //        "markPriceEp": "31332499",
        //        "markPrice": "3133.24990000",
        //        "markValueEv": "0",
        //        "markValue": null,
        //        "unRealisedPosLossEv": "0",
        //        "unRealisedPosLoss": null,
        //        "estimatedOrdLossEv": "0",
        //        "estimatedOrdLoss": "0E-8",
        //        "usedBalanceEv": "111202",
        //        "usedBalance": "11.12020000",
        //        "takeProfitEp": "0",
        //        "takeProfit": null,
        //        "stopLossEp": "0",
        //        "stopLoss": null,
        //        "cumClosedPnlEv": "-1546",
        //        "cumFundingFeeEv": "1605",
        //        "cumTransactFeeEv": "8438",
        //        "realisedPnlEv": "0",
        //        "realisedPnl": null,
        //        "cumRealisedPnlEv": "0",
        //        "cumRealisedPnl": null,
        //        "transactTimeNs": "1641571200001885324",
        //        "takerFeeRateEr": "0",
        //        "makerFeeRateEr": "0",
        //        "term": "6",
        //        "lastTermEndTimeNs": "1607711882505745356",
        //        "lastFundingTimeNs": "1641571200000000000",
        //        "curTermRealisedPnlEv": "-1567",
        //        "execSeq": "12112761561"
        //    }
        //
        const marketId = this.safeString(position, 'symbol');
        market = this.safeMarket(marketId, market);
        const symbol = market['symbol'];
        const collateral = this.safeString2(position, 'positionMargin', 'positionMarginRv');
        const notionalString = this.safeString2(position, 'value', 'valueRv');
        const maintenanceMarginPercentageString = this.safeString2(position, 'maintMarginReq', 'maintMarginReqRr');
        const maintenanceMarginString = Precise["default"].stringMul(notionalString, maintenanceMarginPercentageString);
        const initialMarginString = this.safeString2(position, 'assignedPosBalance', 'assignedPosBalanceRv');
        const initialMarginPercentageString = Precise["default"].stringDiv(initialMarginString, notionalString);
        const liquidationPrice = this.safeNumber2(position, 'liquidationPrice', 'liquidationPriceRp');
        const markPriceString = this.safeString2(position, 'markPrice', 'markPriceRp');
        const contracts = this.safeString(position, 'size');
        const contractSize = this.safeValue(market, 'contractSize');
        const contractSizeString = this.numberToString(contractSize);
        const leverage = this.parseNumber(Precise["default"].stringAbs((this.safeString2(position, 'leverage', 'leverageRr'))));
        const entryPriceString = this.safeString2(position, 'avgEntryPrice', 'avgEntryPriceRp');
        const rawSide = this.safeString(position, 'side');
        let side = undefined;
        if (rawSide !== undefined) {
            side = (rawSide === 'Buy') ? 'long' : 'short';
        }
        let priceDiff = undefined;
        const currency = this.safeString(position, 'currency');
        if (currency === 'USD') {
            if (side === 'long') {
                priceDiff = Precise["default"].stringSub(markPriceString, entryPriceString);
            }
            else {
                priceDiff = Precise["default"].stringSub(entryPriceString, markPriceString);
            }
        }
        else {
            // inverse
            if (side === 'long') {
                priceDiff = Precise["default"].stringSub(Precise["default"].stringDiv('1', entryPriceString), Precise["default"].stringDiv('1', markPriceString));
            }
            else {
                priceDiff = Precise["default"].stringSub(Precise["default"].stringDiv('1', markPriceString), Precise["default"].stringDiv('1', entryPriceString));
            }
        }
        const unrealizedPnl = Precise["default"].stringMul(Precise["default"].stringMul(priceDiff, contracts), contractSizeString);
        const marginRatio = Precise["default"].stringDiv(maintenanceMarginString, collateral);
        const isCross = this.safeValue(position, 'crossMargin');
        return this.safePosition({
            'info': position,
            'id': undefined,
            'symbol': symbol,
            'contracts': this.parseNumber(contracts),
            'contractSize': contractSize,
            'unrealizedPnl': this.parseNumber(unrealizedPnl),
            'leverage': leverage,
            'liquidationPrice': liquidationPrice,
            'collateral': this.parseNumber(collateral),
            'notional': this.parseNumber(notionalString),
            'markPrice': this.parseNumber(markPriceString),
            'lastPrice': undefined,
            'entryPrice': this.parseNumber(entryPriceString),
            'timestamp': undefined,
            'lastUpdateTimestamp': undefined,
            'initialMargin': this.parseNumber(initialMarginString),
            'initialMarginPercentage': this.parseNumber(initialMarginPercentageString),
            'maintenanceMargin': this.parseNumber(maintenanceMarginString),
            'maintenanceMarginPercentage': this.parseNumber(maintenanceMarginPercentageString),
            'marginRatio': this.parseNumber(marginRatio),
            'datetime': undefined,
            'marginMode': isCross ? 'cross' : 'isolated',
            'side': side,
            'hedged': false,
            'percentage': undefined,
            'stopLossPrice': undefined,
            'takeProfitPrice': undefined,
        });
    }
    /**
     * @method
     * @name phemex#fetchFundingHistory
     * @description fetch the history of funding payments paid and received on this account
     * @see https://github.com/phemex/phemex-api-docs/blob/master/Public-Hedged-Perpetual-API.md#futureDataFundingFeesHist
     * @param {string} symbol unified market symbol
     * @param {int} [since] the earliest time in ms to fetch funding history for
     * @param {int} [limit] the maximum number of funding history structures to retrieve
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @returns {object} a [funding history structure]{@link https://docs.ccxt.com/#/?id=funding-history-structure}
     */
    async fetchFundingHistory(symbol = undefined, since = undefined, limit = undefined, params = {}) {
        if (symbol === undefined) {
            throw new errors.ArgumentsRequired(this.id + ' fetchFundingHistory() requires a symbol argument');
        }
        await this.loadMarkets();
        const market = this.market(symbol);
        const request = {
            'symbol': market['id'],
            // 'limit': 20, // Page size default 20, max 200
            // 'offset': 0, // Page start default 0
        };
        if (limit !== undefined) {
            if (limit > 200) {
                throw new errors.BadRequest(this.id + ' fetchFundingHistory() limit argument cannot exceed 200');
            }
            request['limit'] = limit;
        }
        let response = undefined;
        const isUsdt = market['settle'] === 'USDT';
        if (isUsdt) {
            response = await this.privateGetApiDataGFuturesFundingFees(this.extend(request, params));
        }
        else {
            response = await this.privateGetApiDataFuturesFundingFees(this.extend(request, params));
        }
        //
        //     {
        //         "code": 0,
        //         "msg": "OK",
        //         "data": {
        //             "rows": [
        //                 {
        //                     "symbol": "BTCUSD",
        //                     "currency": "BTC",
        //                     "execQty": 18, // "execQty" regular, but "execQtyRq" in hedge
        //                     "side": "Buy",
        //                     "execPriceEp": 360086455, // "execPriceEp" regular, but "execPriceRp" in hedge
        //                     "execValueEv": 49987, // "execValueEv" regular, but "execValueRv" in hedge
        //                     "fundingRateEr": 10000, // "fundingRateEr" regular, but "fundingRateRr" in hedge
        //                     "feeRateEr": 10000, // "feeRateEr" regular, but "feeRateRr" in hedge
        //                     "execFeeEv": 5, // "execFeeEv" regular, but "execFeeRv" in hedge
        //                     "createTime": 1651881600000
        //                 }
        //             ]
        //         }
        //     }
        //
        const data = this.safeValue(response, 'data', {});
        const rows = this.safeValue(data, 'rows', []);
        const result = [];
        for (let i = 0; i < rows.length; i++) {
            const entry = rows[i];
            const timestamp = this.safeInteger(entry, 'createTime');
            const execFee = this.safeString2(entry, 'execFeeEv', 'execFeeRv');
            const currencyCode = this.safeCurrencyCode(this.safeString(entry, 'currency'));
            result.push({
                'info': entry,
                'symbol': this.safeString(entry, 'symbol'),
                'code': currencyCode,
                'timestamp': timestamp,
                'datetime': this.iso8601(timestamp),
                'id': undefined,
                'amount': this.parseFundingFeeToPrecision(execFee, market, currencyCode),
            });
        }
        return result;
    }
    parseFundingFeeToPrecision(value, market = undefined, currencyCode = undefined) {
        if (value === undefined || currencyCode === undefined) {
            return value;
        }
        // it was confirmed by phemex support, that USDT contracts use direct amounts in funding fees, while USD & INVERSE needs 'valueScale'
        const isUsdt = market['settle'] === 'USDT';
        if (!isUsdt) {
            const currency = this.safeCurrency(currencyCode);
            const scale = this.safeString(currency['info'], 'valueScale');
            const tickPrecision = this.parsePrecision(scale);
            value = Precise["default"].stringMul(value, tickPrecision);
        }
        return value;
    }
    /**
     * @method
     * @name phemex#fetchFundingRate
     * @description fetch the current funding rate
     * @param {string} symbol unified market symbol
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @returns {object} a [funding rate structure]{@link https://docs.ccxt.com/#/?id=funding-rate-structure}
     */
    async fetchFundingRate(symbol, params = {}) {
        await this.loadMarkets();
        const market = this.market(symbol);
        if (!market['swap']) {
            throw new errors.BadSymbol(this.id + ' fetchFundingRate() supports swap contracts only');
        }
        const request = {
            'symbol': market['id'],
        };
        let response = {};
        if (!market['linear']) {
            response = await this.v1GetMdTicker24hr(this.extend(request, params));
        }
        else {
            response = await this.v2GetMdV2Ticker24hr(this.extend(request, params));
        }
        //
        //     {
        //         "error": null,
        //         "id": 0,
        //         "result": {
        //             "askEp": 2332500,
        //             "bidEp": 2331000,
        //             "fundingRateEr": 10000,
        //             "highEp": 2380000,
        //             "indexEp": 2329057,
        //             "lastEp": 2331500,
        //             "lowEp": 2274000,
        //             "markEp": 2329232,
        //             "openEp": 2337500,
        //             "openInterest": 1298050,
        //             "predFundingRateEr": 19921,
        //             "symbol": "ETHUSD",
        //             "timestamp": 1592474241582701416,
        //             "turnoverEv": 47228362330,
        //             "volume": 4053863
        //         }
        //     }
        //
        const result = this.safeValue(response, 'result', {});
        return this.parseFundingRate(result, market);
    }
    parseFundingRate(contract, market = undefined) {
        //
        //     {
        //         "askEp": 2332500,
        //         "bidEp": 2331000,
        //         "fundingRateEr": 10000,
        //         "highEp": 2380000,
        //         "indexEp": 2329057,
        //         "lastEp": 2331500,
        //         "lowEp": 2274000,
        //         "markEp": 2329232,
        //         "openEp": 2337500,
        //         "openInterest": 1298050,
        //         "predFundingRateEr": 19921,
        //         "symbol": "ETHUSD",
        //         "timestamp": 1592474241582701416,
        //         "turnoverEv": 47228362330,
        //         "volume": 4053863
        //     }
        //
        // linear swap v2
        //
        //     {
        //         "closeRp":"16820.5",
        //         "fundingRateRr":"0.0001",
        //         "highRp":"16962.1",
        //         "indexPriceRp":"16830.15651565",
        //         "lowRp":"16785",
        //         "markPriceRp":"16830.97534951",
        //         "openInterestRv":"1323.596",
        //         "openRp":"16851.7",
        //         "predFundingRateRr":"0.0001",
        //         "symbol":"BTCUSDT",
        //         "timestamp":"1672142789065593096",
        //         "turnoverRv":"124835296.0538",
        //         "volumeRq":"7406.95"
        //     }
        //
        const marketId = this.safeString(contract, 'symbol');
        const symbol = this.safeSymbol(marketId, market);
        const timestamp = this.safeIntegerProduct(contract, 'timestamp', 0.000001);
        const markEp = this.fromEp(this.safeString(contract, 'markEp'), market);
        const indexEp = this.fromEp(this.safeString(contract, 'indexEp'), market);
        const fundingRateEr = this.fromEr(this.safeString(contract, 'fundingRateEr'), market);
        const nextFundingRateEr = this.fromEr(this.safeString(contract, 'predFundingRateEr'), market);
        return {
            'info': contract,
            'symbol': symbol,
            'markPrice': this.safeNumber(contract, 'markPriceRp', markEp),
            'indexPrice': this.safeNumber(contract, 'indexPriceRp', indexEp),
            'interestRate': undefined,
            'estimatedSettlePrice': undefined,
            'timestamp': timestamp,
            'datetime': this.iso8601(timestamp),
            'fundingRate': this.safeNumber(contract, 'fundingRateRr', fundingRateEr),
            'fundingTimestamp': undefined,
            'fundingDatetime': undefined,
            'nextFundingRate': this.safeNumber(contract, 'predFundingRateRr', nextFundingRateEr),
            'nextFundingTimestamp': undefined,
            'nextFundingDatetime': undefined,
            'previousFundingRate': undefined,
            'previousFundingTimestamp': undefined,
            'previousFundingDatetime': undefined,
            'interval': undefined,
        };
    }
    /**
     * @method
     * @name phemex#setMargin
     * @description Either adds or reduces margin in an isolated position in order to set the margin to a specific value
     * @see https://github.com/phemex/phemex-api-docs/blob/master/Public-Contract-API-en.md#assign-position-balance-in-isolated-marign-mode
     * @param {string} symbol unified market symbol of the market to set margin in
     * @param {float} amount the amount to set the margin to
     * @param {object} [params] parameters specific to the exchange API endpoint
     * @returns {object} A [margin structure]{@link https://docs.ccxt.com/#/?id=add-margin-structure}
     */
    async setMargin(symbol, amount, params = {}) {
        await this.loadMarkets();
        const market = this.market(symbol);
        const request = {
            'symbol': market['id'],
            'posBalanceEv': this.toEv(amount, market),
        };
        const response = await this.privatePostPositionsAssign(this.extend(request, params));
        //
        //     {
        //         "code": 0,
        //         "msg": "",
        //         "data": "OK"
        //     }
        //
        return this.extend(this.parseMarginModification(response, market), {
            'amount': amount,
        });
    }
    parseMarginStatus(status) {
        const statuses = {
            '0': 'ok',
        };
        return this.safeString(statuses, status, status);
    }
    parseMarginModification(data, market = undefined) {
        //
        //     {
        //         "code": 0,
        //         "msg": "",
        //         "data": "OK"
        //     }
        //
        market = this.safeMarket(undefined, market);
        const inverse = this.safeValue(market, 'inverse');
        const codeCurrency = inverse ? 'base' : 'quote';
        return {
            'info': data,
            'symbol': this.safeSymbol(undefined, market),
            'type': 'set',
            'marginMode': 'isolated',
            'amount': undefined,
            'total': undefined,
            'code': market[codeCurrency],
            'status': this.parseMarginStatus(this.safeString(data, 'code')),
            'timestamp': undefined,
            'datetime': undefined,
        };
    }
    /**
     * @method
     * @name phemex#setMarginMode
     * @description set margin mode to 'cross' or 'isolated'
     * @see https://phemex-docs.github.io/#set-leverage
     * @param {string} marginMode 'cross' or 'isolated'
     * @param {string} symbol unified market symbol
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @returns {object} response from the exchange
     */
    async setMarginMode(marginMode, symbol = undefined, params = {}) {
        if (symbol === undefined) {
            throw new errors.ArgumentsRequired(this.id + ' setMarginMode() requires a symbol argument');
        }
        await this.loadMarkets();
        const market = this.market(symbol);
        if (!market['swap'] || market['settle'] === 'USDT') {
            throw new errors.BadSymbol(this.id + ' setMarginMode() supports swap (non USDT based) contracts only');
        }
        marginMode = marginMode.toLowerCase();
        if (marginMode !== 'isolated' && marginMode !== 'cross') {
            throw new errors.BadRequest(this.id + ' setMarginMode() marginMode argument should be isolated or cross');
        }
        let leverage = this.safeInteger(params, 'leverage');
        if (marginMode === 'cross') {
            leverage = 0;
        }
        if (leverage === undefined) {
            throw new errors.ArgumentsRequired(this.id + ' setMarginMode() requires a leverage parameter');
        }
        const request = {
            'symbol': market['id'],
            'leverage': leverage,
        };
        return await this.privatePutPositionsLeverage(this.extend(request, params));
    }
    /**
     * @method
     * @name phemex#setPositionMode
     * @description set hedged to true or false for a market
     * @see https://github.com/phemex/phemex-api-docs/blob/master/Public-Hedged-Perpetual-API.md#switch-position-mode-synchronously
     * @param {bool} hedged set to true to use dualSidePosition
     * @param {string} symbol not used by binance setPositionMode ()
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @returns {object} response from the exchange
     */
    async setPositionMode(hedged, symbol = undefined, params = {}) {
        this.checkRequiredArgument('setPositionMode', symbol, 'symbol');
        await this.loadMarkets();
        const market = this.market(symbol);
        if (market['settle'] !== 'USDT') {
            throw new errors.BadSymbol(this.id + ' setPositionMode() supports USDT settled markets only');
        }
        const request = {
            'symbol': market['id'],
        };
        if (hedged) {
            request['targetPosMode'] = 'Hedged';
        }
        else {
            request['targetPosMode'] = 'OneWay';
        }
        return await this.privatePutGPositionsSwitchPosModeSync(this.extend(request, params));
    }
    /**
     * @method
     * @name phemex#fetchLeverageTiers
     * @description retrieve information on the maximum leverage, and maintenance margin for trades of varying trade sizes
     * @param {string[]|undefined} symbols list of unified market symbols
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @returns {object} a dictionary of [leverage tiers structures]{@link https://docs.ccxt.com/#/?id=leverage-tiers-structure}, indexed by market symbols
     */
    async fetchLeverageTiers(symbols = undefined, params = {}) {
        await this.loadMarkets();
        if (symbols !== undefined) {
            const first = this.safeValue(symbols, 0);
            const market = this.market(first);
            if (market['settle'] !== 'USD') {
                throw new errors.BadSymbol(this.id + ' fetchLeverageTiers() supports USD settled markets only');
            }
        }
        const response = await this.publicGetCfgV2Products(params);
        //
        //     {
        //         "code":0,
        //         "msg":"OK",
        //         "data":{
        //             "ratioScale":8,
        //             "currencies":[
        //                 {"currency":"BTC","valueScale":8,"minValueEv":1,"maxValueEv":5000000000000000000,"name":"Bitcoin"},
        //                 {"currency":"USD","valueScale":4,"minValueEv":1,"maxValueEv":500000000000000,"name":"USD"},
        //                 {"currency":"USDT","valueScale":8,"minValueEv":1,"maxValueEv":5000000000000000000,"name":"TetherUS"},
        //             ],
        //             "products":[
        //                 {
        //                     "symbol":"BTCUSD",
        //                     "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,
        //                     "type":"Perpetual"
        //                 },
        //                 {
        //                     "symbol":"sBTCUSDT",
        //                     "displaySymbol":"BTC / USDT",
        //                     "quoteCurrency":"USDT",
        //                     "pricePrecision":2,
        //                     "type":"Spot",
        //                     "baseCurrency":"BTC",
        //                     "baseTickSize":"0.000001 BTC",
        //                     "baseTickSizeEv":100,
        //                     "quoteTickSize":"0.01 USDT",
        //                     "quoteTickSizeEv":1000000,
        //                     "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,
        //                     "baseQtyPrecision":6,
        //                     "quoteQtyPrecision":2
        //                 },
        //             ],
        //             "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]},
        //             ]
        //         }
        //     }
        //
        //
        const data = this.safeValue(response, 'data', {});
        const riskLimits = this.safeList(data, 'riskLimits');
        return this.parseLeverageTiers(riskLimits, symbols, 'symbol');
    }
    parseMarketLeverageTiers(info, market = undefined) {
        /**
         * @param {object} info Exchange market response for 1 market
         * @param {object} market CCXT market
         */
        //
        //     {
        //         "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},
        //         ]
        //     },
        //
        const marketId = this.safeString(info, 'symbol');
        market = this.safeMarket(marketId, market);
        const riskLimits = (market['info']['riskLimits']);
        const tiers = [];
        let minNotional = 0;
        for (let i = 0; i < riskLimits.length; i++) {
            const tier = riskLimits[i];
            const maxNotional = this.safeInteger(tier, 'limit');
            tiers.push({
                'tier': this.sum(i, 1),
                'symbol': this.safeSymbol(marketId, market),
                'currency': market['settle'],
                'minNotional': minNotional,
                'maxNotional': maxNotional,
                'maintenanceMarginRate': this.safeString(tier, 'maintenanceMargin'),
                'maxLeverage': undefined,
                'info': tier,
            });
            minNotional = maxNotional;
        }
        return tiers;
    }
    sign(path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
        const query = this.omit(params, this.extractParams(path));
        const requestPath = '/' + this.implodeParams(path, params);
        let url = requestPath;
        let queryString = '';
        if ((method === 'GET') || (method === 'DELETE') || (method === 'PUT') || (url === '/positions/assign')) {
            if (Object.keys(query).length) {
                queryString = this.urlencodeWithArrayRepeat(query);
                url += '?' + queryString;
            }
        }
        if (api === 'private') {
            this.checkRequiredCredentials();
            const timestamp = this.seconds();
            const xPhemexRequestExpiry = this.safeInteger(this.options, 'x-phemex-request-expiry', 60);
            const expiry = this.sum(timestamp, xPhemexRequestExpiry);
            const expiryString = expiry.toString();
            headers = {
                'x-phemex-access-token': this.apiKey,
                'x-phemex-request-expiry': expiryString,
            };
            let payload = '';
            if (method === 'POST') {
                const isOrderPlacement = (path === 'g-orders') || (path === 'spot/orders') || (path === 'orders');
                if (isOrderPlacement) {
                    if (this.safeString(params, 'clOrdID') === undefined) {
                        const id = this.safeString(this.options, 'brokerId', 'CCXT123456');
                        params['clOrdID'] = id + this.uuid16();
                    }
                }
                payload = this.json(params);
                body = payload;
                headers['Content-Type'] = 'application/json';
            }
            const auth = requestPath + queryString + expiryString + payload;
            headers['x-phemex-request-signature'] = this.hmac(this.encode(auth), this.encode(this.secret), sha256.sha256);
        }
        url = this.implodeHostname(this.urls['api'][api]) + url;
        return { 'url': url, 'method': method, 'body': body, 'headers': headers };
    }
    /**
     * @method
     * @name phemex#setLeverage
     * @description set the level of leverage for a market
     * @see https://github.com/phemex/phemex-api-docs/blob/master/Public-Hedged-Perpetual-API.md#set-leverage
     * @param {float} leverage the rate of leverage, 100 > leverage > -100 excluding numbers between -1 to 1
     * @param {string} symbol unified market symbol
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @param {bool} [params.hedged] set to true if hedged position mode is enabled (by default long and short leverage are set to the same value)
     * @param {float} [params.longLeverageRr] *hedged mode only* set the leverage for long positions
     * @param {float} [params.shortLeverageRr] *hedged mode only* set the leverage for short positions
     * @returns {object} response from the exchange
     */
    async setLeverage(leverage, symbol = undefined, params = {}) {
        // WARNING: THIS WILL INCREASE LIQUIDATION PRICE FOR OPEN ISOLATED LONG POSITIONS
        // AND DECREASE LIQUIDATION PRICE FOR OPEN ISOLATED SHORT POSITIONS
        if (symbol === undefined) {
            throw new errors.ArgumentsRequired(this.id + ' setLeverage() requires a symbol argument');
        }
        if ((leverage < -100) || (leverage > 100)) {
            throw new errors.BadRequest(this.id + ' setLeverage() leverage should be between -100 and 100');
        }
        await this.loadMarkets();
        const isHedged = this.safeBool(params, 'hedged', false);
        const longLeverageRr = this.safeInteger(params, 'longLeverageRr');
        const shortLeverageRr = this.safeInteger(params, 'shortLeverageRr');
        const market = this.market(symbol);
        const request = {
            'symbol': market['id'],
        };
        let response = undefined;
        if (market['settle'] === 'USDT') {
            if (!isHedged && longLeverageRr === undefined && shortLeverageRr === undefined) {
                request['leverageRr'] = leverage;
            }
            else {
                const longVar = (longLeverageRr !== undefined) ? longLeverageRr : leverage;
                const shortVar = (shortLeverageRr !== undefined) ? shortLeverageRr : leverage;
                request['longLeverageRr'] = longVar;
                request['shortLeverageRr'] = shortVar;
            }
            response = await this.privatePutGPositionsLeverage(this.extend(request, params));
        }
        else {
            request['leverage'] = leverage;
            response = await this.privatePutPositionsLeverage(this.extend(request, params));
        }
        return response;
    }
    /**
     * @method
     * @name phemex#transfer
     * @description transfer currency internally between wallets on the same account
     * @see https://phemex-docs.github.io/#transfer-between-spot-and-futures
     * @see https://phemex-docs.github.io/#universal-transfer-main-account-only-transfer-between-sub-to-main-main-to-sub-or-sub-to-sub
     * @param {string} code unified currency code
     * @param {float} amount amount to transfer
     * @param {string} fromAccount account to transfer from
     * @param {string} toAccount account to transfer to
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @param {string} [params.bizType] for transferring between main and sub-acounts either 'SPOT' or 'PERPETUAL' default is 'SPOT'
     * @returns {object} a [transfer structure]{@link https://docs.ccxt.com/#/?id=transfer-structure}
     */
    async transfer(code, amount, fromAccount, toAccount, params = {}) {
        await this.loadMarkets();
        const currency = this.currency(code);
        const accountsByType = this.safeValue(this.options, 'accountsByType', {});
        const fromId = this.safeString(accountsByType, fromAccount, fromAccount);
        const toId = this.safeString(accountsByType, toAccount, toAccount);
        const scaledAmmount = this.toEv(amount, currency);
        let direction = undefined;
        let transfer = undefined;
        if (fromId === 'spot' && toId === 'future') {
            direction = 2;
        }
        else if (fromId === 'future' && toId === 'spot') {
            direction = 1;
        }
        if (direction !== undefined) {
            const request = {
                'currency': currency['id'],
                'moveOp': direction,
                'amountEv': scaledAmmount,
            };
            const response = await this.privatePostAssetsTransfer(this.extend(request, params));
            //
            //     {
            //         "code": "0",
            //         "msg": "OK",
            //         "data": {
            //             "linkKey": "8564eba4-c9ec-49d6-9b8c-2ec5001a0fb9",
            //             "userId": "4018340",
            //             "currency": "USD",
            //             "amountEv": "10",
            //             "side": "2",
            //             "status": "10"
            //         }
            //     }
            //
            const data = this.safeValue(response, 'data', {});
            transfer = this.parseTransfer(data, currency);
        }
        else { // sub account transfer
            const request = {
                'fromUserId': fromId,
                'toUserId': toId,
                'amountEv': scaledAmmount,
                'currency': currency['id'],
                'bizType': this.safeString(params, 'bizType', 'SPOT'),
            };
            const response = await this.privatePostAssetsUniversalTransfer(this.extend(request, params));
            //
            //     {
            //         "code": "0",
            //         "msg": "OK",
            //         "data": "API-923db826-aaaa-aaaa-aaaa-4d98c3a7c9fd"
            //     }
            //
            transfer = this.parseTransfer(response);
        }
        const transferOptions = this.safeValue(this.options, 'transfer', {});
        const fillResponseFromRequest = this.safeBool(transferOptions, 'fillResponseFromRequest', true);
        if (fillResponseFromRequest) {
            if (transfer['fromAccount'] === undefined) {
                transfer['fromAccount'] = fromAccount;
            }
            if (transfer['toAccount'] === undefined) {
                transfer['toAccount'] = toAccount;
            }
            if (transfer['amount'] === undefined) {
                transfer['amount'] = amount;
            }
            if (transfer['currency'] === undefined) {
                transfer['currency'] = code;
            }
        }
        return transfer;
    }
    /**
     * @method
     * @name phemex#fetchTransfers
     * @description fetch a history of internal transfers made on an account
     * @see https://phemex-docs.github.io/#query-transfer-history
     * @param {string} code unified currency code of the currency transferred
     * @param {int} [since] the earliest time in ms to fetch transfers for
     * @param {int} [limit] the maximum number of  transfers structures to retrieve
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @returns {object[]} a list of [transfer structures]{@link https://docs.ccxt.com/#/?id=transfer-structure}
     */
    async fetchTransfers(code = undefined, since = undefined, limit = undefined, params = {}) {
        await this.loadMarkets();
        if (code === undefined) {
            throw new errors.ArgumentsRequired(this.id + ' fetchTransfers() requires a code argument');
        }
        const currency = this.currency(code);
        const request = {
            'currency': currency['id'],
        };
        if (since !== undefined) {
            request['start'] = since;
        }
        if (limit !== undefined) {
            request['limit'] = limit;
        }
        const response = await this.privateGetAssetsTransfer(this.extend(request, params));
        //
        //     {
        //         "code": 0,
        //         "msg": "OK",
        //         "data": {
        //             "rows": [
        //                 {
        //                     "linkKey": "87c071a3-8628-4ac2-aca1-6ce0d1fad66c",
        //                     "userId": 4148428,
        //                     "currency": "BTC",
        //                     "amountEv": 67932,
        //                     "side": 2,
        //                     "status": 10,
        //                     "createTime": 1652832467000,
        //                     "bizType": 10
        //                 }
        //             ]
        //         }
        //     }
        //
        const data = this.safeValue(response, 'data', {});
        const transfers = this.safeList(data, 'rows', []);
        return this.parseTransfers(transfers, currency, since, limit);
    }
    parseTransfer(transfer, currency = undefined) {
        //
        // transfer
        //
        //     {
        //         "linkKey": "8564eba4-c9ec-49d6-9b8c-2ec5001a0fb9",
        //         "userId": "4018340",
        //         "currency": "USD",
        //         "amountEv": "10",
        //         "side": "2",
        //         "status": "10"
        //     }
        //
        // fetchTransfers
        //
        //     {
        //         "linkKey": "87c071a3-8628-4ac2-aca1-6ce0d1fad66c",
        //         "userId": 4148428,
        //         "currency": "BTC",
        //         "amountEv": 67932,
        //         "side": 2,
        //         "status": 10,
        //         "createTime": 1652832467000,
        //         "bizType": 10
        //     }
        //
        const id = this.safeString(transfer, 'linkKey');
        const status = this.safeString(transfer, 'status');
        const amountEv = this.safeString(transfer, 'amountEv');
        const amountTransfered = this.fromEv(amountEv);
        const currencyId = this.safeString(transfer, 'currency');
        const code = this.safeCurrencyCode(currencyId, currency);
        const side = this.safeInteger(transfer, 'side');
        let fromId = undefined;
        let toId = undefined;
        if (side === 1) {
            fromId = 'swap';
            toId = 'spot';
        }
        else if (side === 2) {
            fromId = 'spot';
            toId = 'swap';
        }
        const timestamp = this.safeInteger(transfer, 'createTime');
        return {
            'info': transfer,
            'id': id,
            'timestamp': timestamp,
            'datetime': this.iso8601(timestamp),
            'currency': code,
            'amount': amountTransfered,
            'fromAccount': fromId,
            'toAccount': toId,
            'status': this.parseTransferStatus(status),
        };
    }
    parseTransferStatus(status) {
        const statuses = {
            '3': 'rejected',
            '6': 'canceled',
            '10': 'ok',
            '11': 'failed', // 'Failed',
        };
        return this.safeString(statuses, status, status);
    }
    /**
     * @method
     * @name phemex#fetchFundingRateHistory
     * @description fetches historical funding rate prices
     * @see https://phemex-docs.github.io/#query-funding-rate-history-2
     * @param {string} symbol unified symbol of the market to fetch the funding rate history for
     * @param {int} [since] timestamp in ms of the earliest funding rate to fetch
     * @param {int} [limit] the maximum amount of [funding rate structures]{@link https://docs.ccxt.com/#/?id=funding-rate-history-structure} to fetch
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @param {boolean} [params.paginate] default false, when true will automatically paginate by calling this endpoint multiple times. See in the docs all the [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
     * @param {int} [params.until] timestamp in ms of the latest funding rate
     * @returns {object[]} a list of [funding rate structures]{@link https://docs.ccxt.com/#/?id=funding-rate-history-structure}
     */
    async fetchFundingRateHistory(symbol = undefined, since = undefined, limit = undefined, params = {}) {
        if (symbol === undefined) {
            throw new errors.ArgumentsRequired(this.id + ' fetchFundingRateHistory() requires a symbol argument');
        }
        await this.loadMarkets();
        const market = this.market(symbol);
        const isUsdtSettled = market['settle'] === 'USDT';
        if (!market['swap']) {
            throw new errors.BadRequest(this.id + ' fetchFundingRateHistory() supports swap contracts only');
        }
        let paginate = false;
        [paginate, params] = this.handleOptionAndParams(params, 'fetchFundingRateHistory', 'paginate');
        if (paginate) {
            return await this.fetchPaginatedCallDeterministic('fetchFundingRateHistory', symbol, since, limit, '8h', params, 100);
        }
        let customSymbol = undefined;
        if (isUsdtSettled) {
            customSymbol = '.' + market['id'] + 'FR8H'; // phemex requires a custom symbol for funding rate history
        }
        else {
            customSymbol = '.' + market['baseId'] + 'FR8H';
        }
        let request = {
            'symbol': customSymbol,
        };
        if (since !== undefined) {
            request['start'] = since;
        }
        if (limit !== undefined) {
            request['limit'] = limit;
        }
        [request, params] = this.handleUntilOption('end', request, params);
        let response = undefined;
        if (isUsdtSettled) {
            response = await this.v2GetApiDataPublicDataFundingRateHistory(this.extend(request, params));
        }
        else {
            response = await this.v1GetApiDataPublicDataFundingRateHistory(this.extend(request, params));
        }
        //
        //    {
        //        "code":"0",
        //        "msg":"OK",
        //        "data":{
        //           "rows":[
        //              {
        //                 "symbol":".BTCUSDTFR8H",
        //                 "fundingRate":"0.0001",
        //                 "fundingTime":"1682064000000",
        //                 "intervalSeconds":"28800"
        //              }
        //           ]
        //        }
        //    }
        //
        const data = this.safeValue(response, 'data', {});
        const rates = this.safeValue(data, 'rows');
        const result = [];
        for (let i = 0; i < rates.length; i++) {
            const item = rates[i];
            const timestamp = this.safeInteger(item, 'fundingTime');
            result.push({
                'info': item,
                'symbol': symbol,
                'fundingRate': this.safeNumber(item, 'fundingRate'),
                'timestamp': timestamp,
                'datetime': this.iso8601(timestamp),
            });
        }
        const sorted = this.sortBy(result, 'timestamp');
        return this.filterBySymbolSinceLimit(sorted, symbol, since, limit);
    }
    /**
     * @method
     * @name phemex#withdraw
     * @description make a withdrawal
     * @see https://phemex-docs.github.io/#create-withdraw-request
     * @param {string} code unified currency code
     * @param {float} amount the amount to withdraw
     * @param {string} address the address to withdraw to
     * @param {string} tag
     * @param {object} [params] extra parameters specific to the phemex api endpoint
     * @param {string} [params.network] unified network code
     * @returns {object} a [transaction structure]{@link https://github.com/ccxt/ccxt/wiki/Manual#transaction-structure}
     */
    async withdraw(code, amount, address, tag = undefined, params = {}) {
        [tag, params] = this.handleWithdrawTagAndParams(tag, params);
        await this.loadMarkets();
        this.checkAddress(address);
        const currency = this.currency(code);
        let networkCode = undefined;
        [networkCode, params] = this.handleNetworkCodeAndParams(params);
        let networkId = undefined;
        if (networkCode !== undefined) {
            networkId = this.networkCodeToId(networkCode);
        }
        const stableCoins = this.safeValue(this.options, 'stableCoins');
        if (networkId === undefined) {
            if (!(this.inArray(code, stableCoins))) {
                networkId = currency['id'];
            }
            else {
                throw new errors.ArgumentsRequired(this.id + ' withdraw () requires an extra argument params["network"]');
            }
        }
        const request = {
            'currency': currency['id'],
            'address': address,
            'amount': amount,
            'chainName': networkId.toUpperCase(),
        };
        if (tag !== undefined) {
            request['addressTag'] = tag;
        }
        const response = await this.privatePostPhemexWithdrawWalletsApiCreateWithdraw(this.extend(request, params));
        //
        //     {
        //         "code": 0,
        //         "msg": "OK",
        //         "data": {
        //             "id": "10000001",
        //             "freezeId": null,
        //             "address": "44exxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
        //             "amountRv": "100",
        //             "chainCode": "11",
        //             "chainName": "TRX",
        //             "currency": "USDT",
        //             "currencyCode": 3,
        //             "email": "abc@gmail.com",
        //             "expiredTime": "0",
        //             "feeRv": "1",
        //             "nickName": null,
        //             "phone": null,
        //             "rejectReason": "",
        //             "submitedAt": "1670000000000",
        //             "submittedAt": "1670000000000",
        //             "txHash": null,
        //             "userId": "10000001",
        //             "status": "Success"
        //         }
        //     }
        //
        const data = this.safeDict(response, 'data', {});
        return this.parseTransaction(data, currency);
    }
    /**
     * @method
     * @name phemex#fetchOpenInterest
     * @description retrieves the open interest of a trading pair
     * @see https://phemex-docs.github.io/#query-24-hours-ticker
     * @param {string} symbol unified CCXT market symbol
     * @param {object} [params] exchange specific parameters
     * @returns {object} an open interest structure{@link https://docs.ccxt.com/#/?id=open-interest-structure}
     */
    async fetchOpenInterest(symbol, params = {}) {
        await this.loadMarkets();
        const market = this.market(symbol);
        if (!market['contract']) {
            throw new errors.BadRequest(this.id + ' fetchOpenInterest is only supported for contract markets.');
        }
        const request = {
            'symbol': market['id'],
        };
        const response = await this.v2GetMdV2Ticker24hr(this.extend(request, params));
        //
        //    {
        //        error: null,
        //        id: '0',
        //        result: {
        //          closeRp: '67550.1',
        //          fundingRateRr: '0.0001',
        //          highRp: '68400',
        //          indexPriceRp: '67567.15389794',
        //          lowRp: '66096.4',
        //          markPriceRp: '67550.1',
        //          openInterestRv: '1848.1144186',
        //          openRp: '66330',
        //          predFundingRateRr: '0.0001',
        //          symbol: 'BTCUSDT',
        //          timestamp: '1729114315443343001',
        //          turnoverRv: '228863389.3237532',
        //          volumeRq: '3388.5600312'
        //        }
        //    }
        //
        const result = this.safeDict(response, 'result');
        return this.parseOpenInterest(result, market);
    }
    parseOpenInterest(interest, market = undefined) {
        //
        //    {
        //        closeRp: '67550.1',
        //        fundingRateRr: '0.0001',
        //        highRp: '68400',
        //        indexPriceRp: '67567.15389794',
        //        lowRp: '66096.4',
        //        markPriceRp: '67550.1',
        //        openInterestRv: '1848.1144186',
        //        openRp: '66330',
        //        predFundingRateRr: '0.0001',
        //        symbol: 'BTCUSDT',
        //        timestamp: '1729114315443343001',
        //        turnoverRv: '228863389.3237532',
        //        volumeRq: '3388.5600312'
        //    }
        //
        const timestamp = this.safeInteger(interest, 'timestamp') / 1000000;
        const id = this.safeString(interest, 'symbol');
        return this.safeOpenInterest({
            'info': interest,
            'symbol': this.safeSymbol(id, market),
            'baseVolume': this.safeString(interest, 'volumeRq'),
            'quoteVolume': undefined,
            'openInterestAmount': this.safeString(interest, 'openInterestRv'),
            'openInterestValue': undefined,
            'timestamp': timestamp,
            'datetime': this.iso8601(timestamp),
        }, market);
    }
    /**
     * @method
     * @name phemex#fetchConvertQuote
     * @description fetch a quote for converting from one currency to another
     * @see https://phemex-docs.github.io/#rfq-quote
     * @param {string} fromCode the currency that you want to sell and convert from
     * @param {string} toCode the currency that you want to buy and convert into
     * @param {float} amount how much you want to trade in units of the from currency
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @returns {object} a [conversion structure]{@link https://docs.ccxt.com/#/?id=conversion-structure}
     */
    async fetchConvertQuote(fromCode, toCode, amount = undefined, params = {}) {
        await this.loadMarkets();
        const fromCurrency = this.currency(fromCode);
        const toCurrency = this.currency(toCode);
        const valueScale = this.safeInteger(fromCurrency, 'valueScale');
        const request = {
            'fromCurrency': fromCode,
            'toCurrency': toCode,
            'fromAmountEv': this.toEn(amount, valueScale),
        };
        const response = await this.privateGetAssetsQuote(this.extend(request, params));
        //
        //     {
        //         "code": 0,
        //         "msg": "OK",
        //         "data": {
        //             "code": "GIF...AAA",
        //             "quoteArgs": {
        //                 "origin": 10,
        //                 "price": "0.00000939",
        //                 "proceeds": "0.00000000",
        //                 "ttlMs": 7000,
        //                 "expireAt": 1739875826009,
        //                 "requestAt": 1739875818009,
        //                 "quoteAt": 1739875816594
        //             }
        //         }
        //     }
        //
        const data = this.safeDict(response, 'data', {});
        return this.parseConversion(data, fromCurrency, toCurrency);
    }
    /**
     * @method
     * @name phemex#createConvertTrade
     * @description convert from one currency to another
     * @see https://phemex-docs.github.io/#convert
     * @param {string} id the id of the trade that you want to make
     * @param {string} fromCode the currency that you want to sell and convert from
     * @param {string} toCode the currency that you want to buy and convert into
     * @param {float} [amount] how much you want to trade in units of the from currency
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @returns {object} a [conversion structure]{@link https://docs.ccxt.com/#/?id=conversion-structure}
     */
    async createConvertTrade(id, fromCode, toCode, amount = undefined, params = {}) {
        await this.loadMarkets();
        const fromCurrency = this.currency(fromCode);
        const toCurrency = this.currency(toCode);
        const valueScale = this.safeInteger(fromCurrency, 'valueScale');
        const request = {
            'code': id,
            'fromCurrency': fromCode,
            'toCurrency': toCode,
        };
        if (amount !== undefined) {
            request['fromAmountEv'] = this.toEn(amount, valueScale);
        }
        const response = await this.privatePostAssetsConvert(this.extend(request, params));
        //
        //     {
        //         "code": 0,
        //         "msg": "OK",
        //         "data": {
        //             "moveOp": 0,
        //             "fromCurrency": "USDT",
        //             "toCurrency": "BTC",
        //             "fromAmountEv": 4000000000,
        //             "toAmountEv": 41511,
        //             "linkKey": "45c8ed8e-d3f4-472d-8262-e464e8c46247",
        //             "status": 10
        //         }
        //     }
        //
        const data = this.safeDict(response, 'data', {});
        const fromCurrencyId = this.safeString(data, 'fromCurrency');
        const fromResult = this.safeCurrency(fromCurrencyId, fromCurrency);
        const toCurrencyId = this.safeString(data, 'toCurrency');
        const to = this.safeCurrency(toCurrencyId, toCurrency);
        return this.parseConversion(data, fromResult, to);
    }
    /**
     * @method
     * @name phemex#fetchConvertTradeHistory
     * @description fetch the users history of conversion trades
     * @see https://phemex-docs.github.io/#query-convert-history
     * @param {string} [code] the unified currency code
     * @param {int} [since] the earliest time in ms to fetch conversions for
     * @param {int} [limit] the maximum number of conversion structures to retrieve, default 20, max 200
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @param {string} [params.until] the end time in ms
     * @param {string} [params.fromCurrency] the currency that you sold and converted from
     * @param {string} [params.toCurrency] the currency that you bought and converted into
     * @returns {object[]} a list of [conversion structures]{@link https://docs.ccxt.com/#/?id=conversion-structure}
     */
    async fetchConvertTradeHistory(code = undefined, since = undefined, limit = undefined, params = {}) {
        await this.loadMarkets();
        let request = {};
        if (code !== undefined) {
            request['fromCurrency'] = code;
        }
        if (since !== undefined) {
            request['startTime'] = since;
        }
        if (limit !== undefined) {
            request['limit'] = limit;
        }
        [request, params] = this.handleUntilOption('endTime', request, params);
        const response = await this.privateGetAssetsConvert(this.extend(request, params));
        //
        //     {
        //         "code": 0,
        //         "msg": "OK",
        //         "data": {
        //             "total": 2,
        //             "rows": [
        //                 {
        //                     "linkKey": "45c8ed8e-d3f4-472d-8262-e464e8c46247",
        //                     "createTime": 1739882294000,
        //                     "fromCurrency": "USDT",
        //                     "toCurrency": "BTC",
        //                     "fromAmountEv": 4000000000,
        //                     "toAmountEv": 41511,
        //                     "status": 10,
        //                     "conversionRate": 1037,
        //                     "errorCode": 0
        //                 },
        //             ]
        //         }
        //     }
        //
        const data = this.safeDict(response, 'data', {});
        const rows = this.safeList(data, 'rows', []);
        return this.parseConversions(rows, code, 'fromCurrency', 'toCurrency', since, limit);
    }
    parseConversion(conversion, fromCurrency = undefined, toCurrency = undefined) {
        //
        // fetchConvertQuote
        //
        //     {
        //         "code": "GIF...AAA",
        //         "quoteArgs": {
        //             "origin": 10,
        //             "price": "0.00000939",
        //             "proceeds": "0.00000000",
        //             "ttlMs": 7000,
        //             "expireAt": 1739875826009,
        //             "requestAt": 1739875818009,
        //             "quoteAt": 1739875816594
        //         }
        //     }
        //
        // createConvertTrade
        //
        //     {
        //         "moveOp": 0,
        //         "fromCurrency": "USDT",
        //         "toCurrency": "BTC",
        //         "fromAmountEv": 4000000000,
        //         "toAmountEv": 41511,
        //         "linkKey": "45c8ed8e-d3f4-472d-8262-e464e8c46247",
        //         "status": 10
        //     }
        //
        // fetchConvertTradeHistory
        //
        //     {
        //         "linkKey": "45c8ed8e-d3f4-472d-8262-e464e8c46247",
        //         "createTime": 1739882294000,
        //         "fromCurrency": "USDT",
        //         "toCurrency": "BTC",
        //         "fromAmountEv": 4000000000,
        //         "toAmountEv": 41511,
        //         "status": 10,
        //         "conversionRate": 1037,
        //         "errorCode": 0
        //     }
        //
        const quoteArgs = this.safeDict(conversion, 'quoteArgs', {});
        const requestTime = this.safeInteger(quoteArgs, 'requestAt');
        const timestamp = this.safeInteger(conversion, 'createTime', requestTime);
        const fromCoin = this.safeString(conversion, 'fromCurrency', this.safeString(fromCurrency, 'code'));
        const fromCode = this.safeCurrencyCode(fromCoin, fromCurrency);
        const toCoin = this.safeString(conversion, 'toCurrency', this.safeString(toCurrency, 'code'));
        const toCode = this.safeCurrencyCode(toCoin, toCurrency);
        const fromValueScale = this.safeInteger(fromCurrency, 'valueScale');
        const toValueScale = this.safeInteger(toCurrency, 'valueScale');
        let fromAmount = this.fromEn(this.safeString(conversion, 'fromAmountEv'), fromValueScale);
        if (fromAmount === undefined && quoteArgs !== undefined) {
            fromAmount = this.fromEn(this.safeString(quoteArgs, 'origin'), fromValueScale);
        }
        let toAmount = this.fromEn(this.safeString(conversion, 'toAmountEv'), toValueScale);
        if (toAmount === undefined && quoteArgs !== undefined) {
            toAmount = this.fromEn(this.safeString(quoteArgs, 'proceeds'), toValueScale);
        }
        return {
            'info': conversion,
            'timestamp': timestamp,
            'datetime': this.iso8601(timestamp),
            'id': this.safeString(conversion, 'code'),
            'fromCurrency': fromCode,
            'fromAmount': this.parseNumber(fromAmount),
            'toCurrency': toCode,
            'toAmount': this.parseNumber(toAmount),
            'price': this.safeNumber(quoteArgs, 'price'),
            'fee': undefined,
        };
    }
    handleErrors(httpCode, reason, url, method, headers, body, response, requestHeaders, requestBody) {
        if (response === undefined) {
            return undefined; // fallback to default error handler
        }
        //
        //     {"code":30018,"msg":"phemex.data.size.uplimt","data":null}
        //     {"code":412,"msg":"Missing parameter - resolution","data":null}
        //     {"code":412,"msg":"Missing parameter - to","data":null}
        //     {"error":{"code":6001,"message":"invalid argument"},"id":null,"result":null}
        //
        const error = this.safeValue(response, 'error', response);
        const errorCode = this.safeString(error, 'code');
        const message = this.safeString(error, 'msg');
        if ((errorCode !== undefined) && (errorCode !== '0')) {
            const feedback = this.id + ' ' + body;
            this.throwExactlyMatchedException(this.exceptions['exact'], errorCode, feedback);
            this.throwBroadlyMatchedException(this.exceptions['broad'], message, feedback);
            throw new errors.ExchangeError(feedback); // unknown message
        }
        return undefined;
    }
}

module.exports = phemex;