UNPKG

astro-perp-ccxt-dev

Version:

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

3,682 lines 162 kB
// ----------------------------------------------------------------------------

// PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
// https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
// EDIT THE CORRESPONDENT .ts FILE INSTEAD

//  ---------------------------------------------------------------------------
import Exchange from './abstract/poloniex.js';
import { ArgumentsRequired, ExchangeError, ExchangeNotAvailable, NotSupported, RequestTimeout, AuthenticationError, PermissionDenied, InsufficientFunds, OrderNotFound, InvalidOrder, AccountSuspended, OnMaintenance, BadSymbol, BadRequest } from './base/errors.js';
import { Precise } from './base/Precise.js';
import { TICK_SIZE } from './base/functions/number.js';
import { sha256 } from './static_dependencies/noble-hashes/sha256.js';
//  ---------------------------------------------------------------------------
/**
 * @class poloniex
 * @augments Exchange
 */
export default class poloniex extends Exchange {
    describe() {
        return this.deepExtend(super.describe(), {
            'id': 'poloniex',
            'name': 'Poloniex',
            'countries': ['US'],
            // 200 requests per second for some unauthenticated market endpoints => 1000ms / 200 = 5ms between requests
            'rateLimit': 5,
            'certified': false,
            'pro': true,
            'has': {
                'CORS': undefined,
                'spot': true,
                'margin': undefined,
                'swap': true,
                'future': true,
                'option': false,
                'addMargin': true,
                'cancelAllOrders': true,
                'cancelOrder': true,
                'cancelOrders': undefined,
                'createDepositAddress': true,
                'createMarketBuyOrderWithCost': true,
                'createMarketOrderWithCost': false,
                'createMarketSellOrderWithCost': false,
                'createOrder': true,
                'createOrders': undefined,
                'createStopOrder': true,
                'createTriggerOrder': true,
                'editOrder': true,
                'fetchBalance': true,
                'fetchClosedOrder': false,
                'fetchClosedOrders': true,
                'fetchCurrencies': true,
                'fetchDepositAddress': true,
                'fetchDepositAddresses': false,
                'fetchDepositAddressesByNetwork': false,
                'fetchDeposits': true,
                'fetchDepositsWithdrawals': true,
                'fetchDepositWithdrawFee': 'emulated',
                'fetchDepositWithdrawFees': true,
                'fetchFundingHistory': false,
                'fetchFundingInterval': false,
                'fetchFundingIntervals': false,
                'fetchFundingRate': false,
                'fetchFundingRateHistory': false,
                'fetchFundingRates': undefined,
                'fetchLedger': undefined,
                'fetchLeverage': true,
                'fetchLiquidations': undefined,
                'fetchMarginMode': false,
                'fetchMarkets': true,
                'fetchMyTrades': true,
                'fetchOHLCV': true,
                'fetchOpenInterestHistory': false,
                'fetchOpenOrder': false,
                'fetchOpenOrders': true,
                'fetchOrder': true,
                'fetchOrderBook': true,
                'fetchOrderBooks': false,
                'fetchOrderTrades': true,
                'fetchPosition': false,
                'fetchPositionMode': true,
                'fetchPositions': true,
                'fetchTicker': true,
                'fetchTickers': true,
                'fetchTime': true,
                'fetchTrades': true,
                'fetchTradingFee': false,
                'fetchTradingFees': true,
                'fetchTransactions': 'emulated',
                'fetchTransfer': false,
                'fetchTransfers': false,
                'fetchWithdrawals': true,
                'reduceMargin': true,
                'sandbox': true,
                'setLeverage': true,
                'setPositionMode': true,
                'transfer': true,
                'withdraw': true,
            },
            'timeframes': {
                '1m': 'MINUTE_1',
                '5m': 'MINUTE_5',
                '10m': 'MINUTE_10',
                '15m': 'MINUTE_15',
                '30m': 'MINUTE_30',
                '1h': 'HOUR_1',
                '2h': 'HOUR_2',
                '4h': 'HOUR_4',
                '6h': 'HOUR_6',
                '12h': 'HOUR_12',
                '1d': 'DAY_1',
                '3d': 'DAY_3',
                '1w': 'WEEK_1',
                '1M': 'MONTH_1', // not in swap
            },
            'urls': {
                'logo': 'https://user-images.githubusercontent.com/1294454/27766817-e9456312-5ee6-11e7-9b3c-b628ca5626a5.jpg',
                'api': {
                    'spot': 'https://api.poloniex.com',
                    'swap': 'https://api.poloniex.com',
                },
                'test': {
                    'spot': 'https://sand-spot-api-gateway.poloniex.com',
                },
                'www': 'https://www.poloniex.com',
                'doc': 'https://api-docs.poloniex.com/spot/',
                'fees': 'https://poloniex.com/fees',
                'referral': 'https://poloniex.com/signup?c=UBFZJRPJ',
            },
            'api': {
                'public': {
                    'get': {
                        'markets': 20,
                        'markets/{symbol}': 1,
                        'currencies': 20,
                        'currencies/{currency}': 20,
                        'v2/currencies': 20,
                        'v2/currencies/{currency}': 20,
                        'timestamp': 1,
                        'markets/price': 1,
                        'markets/{symbol}/price': 1,
                        'markets/markPrice': 1,
                        'markets/{symbol}/markPrice': 1,
                        'markets/{symbol}/markPriceComponents': 1,
                        'markets/{symbol}/orderBook': 1,
                        'markets/{symbol}/candles': 1,
                        'markets/{symbol}/trades': 20,
                        'markets/ticker24h': 20,
                        'markets/{symbol}/ticker24h': 20,
                        'markets/collateralInfo': 1,
                        'markets/{currency}/collateralInfo': 1,
                        'markets/borrowRatesInfo': 1,
                    },
                },
                'private': {
                    'get': {
                        'accounts': 4,
                        'accounts/balances': 4,
                        'accounts/{id}/balances': 4,
                        'accounts/activity': 20,
                        'accounts/transfer': 20,
                        'accounts/transfer/{id}': 4,
                        'feeinfo': 20,
                        'accounts/interest/history': 1,
                        'subaccounts': 4,
                        'subaccounts/balances': 20,
                        'subaccounts/{id}/balances': 4,
                        'subaccounts/transfer': 20,
                        'subaccounts/transfer/{id}': 4,
                        'wallets/addresses': 20,
                        'wallets/addresses/{currency}': 20,
                        'wallets/activity': 20,
                        'margin/accountMargin': 4,
                        'margin/borrowStatus': 4,
                        'margin/maxSize': 4,
                        'orders': 20,
                        'orders/{id}': 4,
                        'orders/killSwitchStatus': 4,
                        'smartorders': 20,
                        'smartorders/{id}': 4,
                        'orders/history': 20,
                        'smartorders/history': 20,
                        'trades': 20,
                        'orders/{id}/trades': 4,
                    },
                    'post': {
                        'accounts/transfer': 4,
                        'subaccounts/transfer': 20,
                        'wallets/address': 20,
                        'wallets/withdraw': 20,
                        'v2/wallets/withdraw': 20,
                        'orders': 4,
                        'orders/batch': 20,
                        'orders/killSwitch': 4,
                        'smartorders': 4,
                    },
                    'delete': {
                        'orders/{id}': 4,
                        'orders/cancelByIds': 20,
                        'orders': 20,
                        'smartorders/{id}': 4,
                        'smartorders/cancelByIds': 20,
                        'smartorders': 20,
                    },
                    'put': {
                        'orders/{id}': 20,
                        'smartorders/{id}': 20,
                    },
                },
                'swapPublic': {
                    'get': {
                        // 300 calls / second
                        'v3/market/allInstruments': 2 / 3,
                        'v3/market/instruments': 2 / 3,
                        'v3/market/orderBook': 2 / 3,
                        'v3/market/candles': 10,
                        'v3/market/indexPriceCandlesticks': 10,
                        'v3/market/premiumIndexCandlesticks': 10,
                        'v3/market/markPriceCandlesticks': 10,
                        'v3/market/trades': 2 / 3,
                        'v3/market/liquidationOrder': 2 / 3,
                        'v3/market/tickers': 2 / 3,
                        'v3/market/markPrice': 2 / 3,
                        'v3/market/indexPrice': 2 / 3,
                        'v3/market/indexPriceComponents': 2 / 3,
                        'v3/market/fundingRate': 2 / 3,
                        'v3/market/openInterest': 2 / 3,
                        'v3/market/insurance': 2 / 3,
                        'v3/market/riskLimit': 2 / 3,
                    },
                },
                'swapPrivate': {
                    'get': {
                        'v3/account/balance': 4,
                        'v3/account/bills': 20,
                        'v3/trade/order/opens': 20,
                        'v3/trade/order/trades': 20,
                        'v3/trade/order/history': 20,
                        'v3/trade/position/opens': 20,
                        'v3/trade/position/history': 20,
                        'v3/position/leverages': 20,
                        'v3/position/mode': 20,
                    },
                    'post': {
                        'v3/trade/order': 4,
                        'v3/trade/orders': 40,
                        'v3/trade/position': 20,
                        'v3/trade/positionAll': 100,
                        'v3/position/leverage': 20,
                        'v3/position/mode': 20,
                        'v3/trade/position/margin': 20,
                    },
                    'delete': {
                        'v3/trade/order': 2,
                        'v3/trade/batchOrders': 20,
                        'v3/trade/allOrders': 20,
                    },
                },
            },
            'fees': {
                'trading': {
                    'feeSide': 'get',
                    // starting from Jan 8 2020
                    'maker': this.parseNumber('0.0009'),
                    'taker': this.parseNumber('0.0009'),
                },
                'funding': {},
            },
            'commonCurrencies': {
                'AIR': 'AirCoin',
                'APH': 'AphroditeCoin',
                'BCC': 'BTCtalkcoin',
                'BCHABC': 'BCHABC',
                'BDG': 'Badgercoin',
                'BTM': 'Bitmark',
                'CON': 'Coino',
                'ETHTRON': 'ETH',
                'GOLD': 'GoldEagles',
                'GPUC': 'GPU',
                'HOT': 'Hotcoin',
                'ITC': 'Information Coin',
                'KEY': 'KEYCoin',
                'MASK': 'NFTX Hashmasks Index',
                'MEME': 'Degenerator Meme',
                'PLX': 'ParallaxCoin',
                'REPV2': 'REP',
                'STR': 'XLM',
                'SOC': 'SOCC',
                'TRADE': 'Unitrade',
                'TRXETH': 'TRX',
                'XAP': 'API Coin',
                // this is not documented in the API docs for Poloniex
                // https://github.com/ccxt/ccxt/issues/7084
                // when the user calls withdraw ('USDT', amount, address, tag, params)
                // with params = { 'currencyToWithdrawAs': 'USDTTRON' }
                // or params = { 'currencyToWithdrawAs': 'USDTETH' }
                // fetchWithdrawals ('USDT') returns the corresponding withdrawals
                // with a USDTTRON or a USDTETH currency id, respectfully
                // therefore we have map them back to the original code USDT
                // otherwise the returned withdrawals are filtered out
                'USDTBSC': 'USDT',
                'USDTTRON': 'USDT',
                'USDTETH': 'USDT',
                'UST': 'USTC',
            },
            'options': {
                'defaultType': 'spot',
                'createMarketBuyOrderRequiresPrice': true,
                'networks': {
                    'BEP20': 'BSC',
                    'ERC20': 'ETH',
                    'TRC20': 'TRON',
                    'TRX': 'TRON',
                },
                'networksById': {
                    'TRX': 'TRC20',
                    'TRON': 'TRC20',
                },
                'limits': {
                    'cost': {
                        'min': {
                            'BTC': 0.0001,
                            'ETH': 0.0001,
                            'USDT': 1.0,
                            'TRX': 100,
                            'BNB': 0.06,
                            'USDC': 1.0,
                            'USDJ': 1.0,
                            'TUSD': 0.0001,
                            'DAI': 1.0,
                            'PAX': 1.0,
                            'BUSD': 1.0,
                        },
                    },
                },
                'accountsByType': {
                    'spot': 'spot',
                    'future': 'futures',
                },
                'accountsById': {
                    'exchange': 'spot',
                    'futures': 'future',
                },
            },
            'features': {
                'default': {
                    'sandbox': true,
                    'createOrder': {
                        'marginMode': true,
                        'triggerPrice': true,
                        'triggerPriceType': undefined,
                        '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': true,
                        'trailing': false,
                        'iceberg': false,
                    },
                    'createOrders': {
                        'max': 20,
                    },
                    'fetchMyTrades': {
                        'marginMode': false,
                        'limit': 1000,
                        'daysBack': 100000,
                        'untilDays': 100000,
                        'symbolRequired': false,
                    },
                    'fetchOrder': {
                        'marginMode': false,
                        'trigger': false,
                        'trailing': false,
                        'symbolRequired': false,
                    },
                    'fetchOpenOrders': {
                        'marginMode': false,
                        'limit': 2000,
                        'trigger': false,
                        'trailing': false,
                        'symbolRequired': false,
                    },
                    'fetchOrders': undefined,
                    'fetchClosedOrders': undefined,
                    'fetchOHLCV': {
                        'limit': 500,
                    },
                },
                'spot': {
                    'extends': 'default',
                },
                'forContracts': {
                    'extends': 'default',
                    'createOrder': {
                        'marginMode': true,
                        'triggerPrice': false,
                        'hedged': true,
                        'stpMode': true,
                        'marketBuyByCost': false,
                    },
                    'createOrders': {
                        'max': 10,
                    },
                    'fetchOpenOrders': {
                        'limit': 100,
                    },
                    'fetchClosedOrders': {
                        'marginMode': false,
                        'limit': 100,
                        'daysBack': undefined,
                        'daysBackCanceled': 1 / 6,
                        'untilDays': undefined,
                        'trigger': false,
                        'trailing': false,
                        'symbolRequired': false,
                    },
                    'fetchMyTrades': {
                        'limit': 100,
                        'untilDays': 90,
                    },
                },
                'swap': {
                    'linear': {
                        'extends': 'forContracts',
                    },
                    'inverse': {
                        'extends': 'forContracts',
                    },
                },
                'future': {
                    'linear': {
                        'extends': 'forContracts',
                    },
                    'inverse': {
                        'extends': 'forContracts',
                    },
                },
            },
            'precisionMode': TICK_SIZE,
            'exceptions': {
                'exact': {
                    // General
                    '500': ExchangeNotAvailable,
                    '603': RequestTimeout,
                    '601': BadRequest,
                    '415': ExchangeError,
                    '602': ArgumentsRequired,
                    // Accounts
                    '21604': BadRequest,
                    '21600': AuthenticationError,
                    '21605': AuthenticationError,
                    '21102': ExchangeError,
                    '21100': AuthenticationError,
                    '21704': AuthenticationError,
                    '21700': BadRequest,
                    '21705': BadRequest,
                    '21707': ExchangeError,
                    '21708': BadRequest,
                    '21601': AccountSuspended,
                    '21711': ExchangeError,
                    '21709': InsufficientFunds,
                    '250000': ExchangeError,
                    '250001': BadRequest,
                    '250002': BadRequest,
                    '250003': BadRequest,
                    '250004': BadRequest,
                    '250005': InsufficientFunds,
                    '250008': BadRequest,
                    '250012': ExchangeError,
                    // Trading
                    '21110': BadRequest,
                    '10040': BadSymbol,
                    '10060': ExchangeError,
                    '10020': BadSymbol,
                    '10041': BadSymbol,
                    '21340': OnMaintenance,
                    '21341': InvalidOrder,
                    '21342': InvalidOrder,
                    '21343': InvalidOrder,
                    '21351': AccountSuspended,
                    '21352': BadSymbol,
                    '21353': PermissionDenied,
                    '21354': PermissionDenied,
                    '21359': OrderNotFound,
                    '21360': InvalidOrder,
                    '24106': BadRequest,
                    '24201': ExchangeNotAvailable,
                    // Orders
                    '21301': OrderNotFound,
                    '21302': ExchangeError,
                    '21304': ExchangeError,
                    '21305': OrderNotFound,
                    '21307': ExchangeError,
                    '21309': InvalidOrder,
                    '21310': InvalidOrder,
                    '21311': InvalidOrder,
                    '21312': InvalidOrder,
                    '21314': InvalidOrder,
                    '21315': InvalidOrder,
                    '21317': InvalidOrder,
                    '21319': InvalidOrder,
                    '21320': InvalidOrder,
                    '21321': InvalidOrder,
                    '21322': InvalidOrder,
                    '21324': BadRequest,
                    '21327': InvalidOrder,
                    '21328': InvalidOrder,
                    '21330': InvalidOrder,
                    '21335': InvalidOrder,
                    '21336': InvalidOrder,
                    '21337': InvalidOrder,
                    '21344': InvalidOrder,
                    '21345': InvalidOrder,
                    '21346': InvalidOrder,
                    '21348': InvalidOrder,
                    '21347': InvalidOrder,
                    '21349': InvalidOrder,
                    '21350': InvalidOrder,
                    '21355': ExchangeError,
                    '21356': BadRequest,
                    '21721': InsufficientFunds,
                    '24101': BadSymbol,
                    '24102': InvalidOrder,
                    '24103': InvalidOrder,
                    '24104': InvalidOrder,
                    '24105': InvalidOrder,
                    '25020': InvalidOrder,
                    // Smartorders
                    '25000': InvalidOrder,
                    '25001': InvalidOrder,
                    '25002': InvalidOrder,
                    '25003': ExchangeError,
                    '25004': InvalidOrder,
                    '25005': ExchangeError,
                    '25006': InvalidOrder,
                    '25007': InvalidOrder,
                    '25008': InvalidOrder,
                    '25009': ExchangeError,
                    '25010': PermissionDenied,
                    '25011': InvalidOrder,
                    '25012': ExchangeError,
                    '25013': OrderNotFound,
                    '25014': OrderNotFound,
                    '25015': OrderNotFound,
                    '25016': ExchangeError,
                    '25017': ExchangeError,
                    '25018': BadRequest,
                    '25019': BadSymbol, // Invalid symbol
                },
                'broad': {},
            },
        });
    }
    parseOHLCV(ohlcv, market = undefined) {
        //
        // spot:
        //
        //     [
        //         [
        //             "22814.01",
        //             "22937.42",
        //             "22832.57",
        //             "22937.42",
        //             "3916.58764051",
        //             "0.171199",
        //             "2982.64647063",
        //             "0.130295",
        //             33,
        //             0,
        //             "22877.449915304470460711",
        //             "MINUTE_5",
        //             1659664800000,
        //             1659665099999
        //         ]
        //     ]
        //
        // contract:
        //
        //           [
        //             "84207.02",
        //             "84320.85",
        //             "84207.02",
        //             "84253.83",
        //             "3707.5395",
        //             "44",
        //             "14",
        //             "1740770040000",
        //             "1740770099999",
        //           ],
        //
        const ohlcvLength = ohlcv.length;
        const isContract = ohlcvLength === 9;
        if (isContract) {
            return [
                this.safeInteger(ohlcv, 7),
                this.safeNumber(ohlcv, 2),
                this.safeNumber(ohlcv, 1),
                this.safeNumber(ohlcv, 0),
                this.safeNumber(ohlcv, 3),
                this.safeNumber(ohlcv, 5),
            ];
        }
        return [
            this.safeInteger(ohlcv, 12),
            this.safeNumber(ohlcv, 2),
            this.safeNumber(ohlcv, 1),
            this.safeNumber(ohlcv, 0),
            this.safeNumber(ohlcv, 3),
            this.safeNumber(ohlcv, 5),
        ];
    }
    /**
     * @method
     * @name poloniex#fetchOHLCV
     * @description fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market
     * @see https://api-docs.poloniex.com/spot/api/public/market-data#candles
     * @see https://api-docs.poloniex.com/v3/futures/api/market/get-kline-data
     * @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] 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] timestamp in ms
     * @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)
     * @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();
        let paginate = false;
        [paginate, params] = this.handleOptionAndParams(params, 'fetchOHLCV', 'paginate', false);
        if (paginate) {
            return await this.fetchPaginatedCallDeterministic('fetchOHLCV', symbol, since, limit, timeframe, params, 500);
        }
        const market = this.market(symbol);
        let request = {
            'symbol': market['id'],
            'interval': this.safeString(this.timeframes, timeframe, timeframe),
        };
        const keyStart = market['spot'] ? 'startTime' : 'sTime';
        const keyEnd = market['spot'] ? 'endTime' : 'eTime';
        if (since !== undefined) {
            request[keyStart] = since;
        }
        if (limit !== undefined) {
            // limit should in between 100 and 500
            request['limit'] = limit;
        }
        [request, params] = this.handleUntilOption(keyEnd, request, params);
        if (market['contract']) {
            if (this.inArray(timeframe, ['10m', '1M'])) {
                throw new NotSupported(this.id + ' ' + timeframe + ' ' + market['type'] + ' fetchOHLCV is not supported');
            }
            const responseRaw = await this.swapPublicGetV3MarketCandles(this.extend(request, params));
            //
            //     {
            //         code: "200",
            //         msg: "Success",
            //         data: [
            //           [
            //             "84207.02",
            //             "84320.85",
            //             "84207.02",
            //             "84253.83",
            //             "3707.5395",
            //             "44",
            //             "14",
            //             "1740770040000",
            //             "1740770099999",
            //           ],
            //
            const data = this.safeList(responseRaw, 'data');
            return this.parseOHLCVs(data, market, timeframe, since, limit);
        }
        const response = await this.publicGetMarketsSymbolCandles(this.extend(request, params));
        //
        //     [
        //         [
        //             "22814.01",
        //             "22937.42",
        //             "22832.57",
        //             "22937.42",
        //             "3916.58764051",
        //             "0.171199",
        //             "2982.64647063",
        //             "0.130295",
        //             33,
        //             0,
        //             "22877.449915304470460711",
        //             "MINUTE_5",
        //             1659664800000,
        //             1659665099999
        //         ]
        //     ]
        //
        return this.parseOHLCVs(response, market, timeframe, since, limit);
    }
    async loadMarkets(reload = false, params = {}) {
        const markets = await super.loadMarkets(reload, params);
        const currenciesByNumericId = this.safeValue(this.options, 'currenciesByNumericId');
        if ((currenciesByNumericId === undefined) || reload) {
            this.options['currenciesByNumericId'] = this.indexBy(this.currencies, 'numericId');
        }
        return markets;
    }
    /**
     * @method
     * @name poloniex#fetchMarkets
     * @description retrieves data on all markets for poloniex
     * @see https://api-docs.poloniex.com/spot/api/public/reference-data#symbol-information
     * @see https://api-docs.poloniex.com/v3/futures/api/market/get-all-product-info
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @returns {object[]} an array of objects representing market data
     */
    async fetchMarkets(params = {}) {
        const promises = [this.fetchSpotMarkets(params), this.fetchSwapMarkets(params)];
        const results = await Promise.all(promises);
        return this.arrayConcat(results[0], results[1]);
    }
    async fetchSpotMarkets(params = {}) {
        const markets = await this.publicGetMarkets(params);
        //
        //     [
        //         {
        //             "symbol" : "BTS_BTC",
        //             "baseCurrencyName" : "BTS",
        //             "quoteCurrencyName" : "BTC",
        //             "displayName" : "BTS/BTC",
        //             "state" : "NORMAL",
        //             "visibleStartTime" : 1659018816626,
        //             "tradableStartTime" : 1659018816626,
        //             "symbolTradeLimit" : {
        //                 "symbol" : "BTS_BTC",
        //                 "priceScale" : 10,
        //                 "quantityScale" : 0,
        //                 "amountScale" : 8,
        //                 "minQuantity" : "100",
        //                 "minAmount" : "0.00001",
        //                 "highestBid" : "0",
        //                 "lowestAsk" : "0"
        //             }
        //         }
        //     ]
        //
        return this.parseMarkets(markets);
    }
    async fetchSwapMarkets(params = {}) {
        // do similar as spot per https://api-docs.poloniex.com/v3/futures/api/market/get-product-info
        const response = await this.swapPublicGetV3MarketAllInstruments(params);
        //
        //    {
        //        "code": "200",
        //        "msg": "Success",
        //        "data": [
        //            {
        //                "symbol": "BNB_USDT_PERP",
        //                "bAsset": ".PBNBUSDT",
        //                "bCcy": "BNB",
        //                "qCcy": "USDT",
        //                "visibleStartTime": "1620390600000",
        //                "tradableStartTime": "1620390600000",
        //                "sCcy": "USDT",
        //                "tSz": "0.001",
        //                "pxScale": "0.001,0.01,0.1,1,10",
        //                "lotSz": "1",
        //                "minSz": "1",
        //                "ctVal": "0.1",
        //                "status": "OPEN",
        //                "oDate": "1620287590000",
        //                "maxPx": "1000000",
        //                "minPx": "0.001",
        //                "maxQty": "1000000",
        //                "minQty": "1",
        //                "maxLever": "50",
        //                "lever": "10",
        //                "ctType": "LINEAR",
        //                "alias": "",
        //                "iM": "0.02",
        //                "mM": "0.0115",
        //                "mR": "2000",
        //                "buyLmt": "",
        //                "sellLmt": "",
        //                "ordPxRange": "0.05",
        //                "marketMaxQty": "2800",
        //                "limitMaxQty": "1000000"
        //            },
        //
        const markets = this.safeList(response, 'data');
        return this.parseMarkets(markets);
    }
    parseMarket(market) {
        if ('ctType' in market) {
            return this.parseSwapMarket(market);
        }
        else {
            return this.parseSpotMarket(market);
        }
    }
    parseSpotMarket(market) {
        const id = this.safeString(market, 'symbol');
        const baseId = this.safeString(market, 'baseCurrencyName');
        const quoteId = this.safeString(market, 'quoteCurrencyName');
        const base = this.safeCurrencyCode(baseId);
        const quote = this.safeCurrencyCode(quoteId);
        const state = this.safeString(market, 'state');
        const active = state === 'NORMAL';
        const symbolTradeLimit = this.safeValue(market, 'symbolTradeLimit');
        // these are known defaults
        return {
            'id': id,
            'symbol': base + '/' + quote,
            'base': base,
            'quote': quote,
            'settle': undefined,
            'baseId': baseId,
            'quoteId': quoteId,
            'settleId': undefined,
            'type': 'spot',
            'spot': true,
            'margin': false,
            'swap': false,
            'future': false,
            'option': false,
            'active': active,
            'contract': false,
            'linear': undefined,
            'inverse': undefined,
            'contractSize': undefined,
            'expiry': undefined,
            'expiryDatetime': undefined,
            'strike': undefined,
            'optionType': undefined,
            'precision': {
                'amount': this.parseNumber(this.parsePrecision(this.safeString(symbolTradeLimit, 'quantityScale'))),
                'price': this.parseNumber(this.parsePrecision(this.safeString(symbolTradeLimit, 'priceScale'))),
            },
            'limits': {
                'amount': {
                    'min': this.safeNumber(symbolTradeLimit, 'minQuantity'),
                    'max': undefined,
                },
                'price': {
                    'min': undefined,
                    'max': undefined,
                },
                'cost': {
                    'min': this.safeNumber(symbolTradeLimit, 'minAmount'),
                    'max': undefined,
                },
            },
            'created': this.safeInteger(market, 'tradableStartTime'),
            'info': market,
        };
    }
    parseSwapMarket(market) {
        //
        //            {
        //                "symbol": "BNB_USDT_PERP",
        //                "bAsset": ".PBNBUSDT",
        //                "bCcy": "BNB",
        //                "qCcy": "USDT",
        //                "visibleStartTime": "1620390600000",
        //                "tradableStartTime": "1620390600000",
        //                "sCcy": "USDT",
        //                "tSz": "0.001",
        //                "pxScale": "0.001,0.01,0.1,1,10",
        //                "lotSz": "1",
        //                "minSz": "1",
        //                "ctVal": "0.1",
        //                "status": "OPEN",
        //                "oDate": "1620287590000",
        //                "maxPx": "1000000",
        //                "minPx": "0.001",
        //                "maxQty": "1000000",
        //                "minQty": "1",
        //                "maxLever": "50",
        //                "lever": "10",
        //                "ctType": "LINEAR",
        //                "alias": "",
        //                "iM": "0.02",
        //                "mM": "0.0115",
        //                "mR": "2000",
        //                "buyLmt": "",
        //                "sellLmt": "",
        //                "ordPxRange": "0.05",
        //                "marketMaxQty": "2800",
        //                "limitMaxQty": "1000000"
        //            },
        //
        const id = this.safeString(market, 'symbol');
        const baseId = this.safeString(market, 'bCcy');
        const quoteId = this.safeString(market, 'qCcy');
        const settleId = this.safeString(market, 'sCcy');
        const base = this.safeCurrencyCode(baseId);
        const quote = this.safeCurrencyCode(quoteId);
        const settle = this.safeCurrencyCode(settleId);
        const status = this.safeString(market, 'status');
        const active = status === 'OPEN';
        const linear = market['ctType'] === 'LINEAR';
        let symbol = base + '/' + quote;
        if (linear) {
            symbol += ':' + settle;
        }
        else {
            // actually, exchange does not have any inverse future now
            symbol += ':' + base;
        }
        const alias = this.safeString(market, 'alias');
        let type = 'swap';
        if (alias !== undefined) {
            type = 'future';
        }
        return {
            'id': id,
            'symbol': symbol,
            'base': base,
            'quote': quote,
            'settle': settle,
            'baseId': baseId,
            'quoteId': quoteId,
            'settleId': settleId,
            'type': (type === 'future') ? 'future' : 'swap',
            'spot': false,
            'margin': false,
            'swap': type === 'swap',
            'future': type === 'future',
            'option': false,
            'active': active,
            'contract': true,
            'linear': linear,
            'inverse': !linear,
            'contractSize': this.safeNumber(market, 'ctVal'),
            'expiry': undefined,
            'expiryDatetime': undefined,
            'strike': undefined,
            'optionType': undefined,
            'taker': this.safeNumber(market, 'tFee'),
            'maker': this.safeNumber(market, 'mFee'),
            'precision': {
                'amount': this.safeNumber(market, 'lotSz'),
                'price': this.safeNumber(market, 'tSz'),
            },
            'limits': {
                'amount': {
                    'min': this.safeNumber(market, 'minSz'),
                    'max': this.safeNumber(market, 'limitMaxQty'),
                },
                'price': {
                    'min': this.safeNumber(market, 'minPx'),
                    'max': this.safeNumber(market, 'maxPx'),
                },
                'cost': {
                    'min': undefined,
                    'max': undefined,
                },
                'leverage': {
                    'max': this.safeNumber(market, 'maxLever'),
                    'min': undefined,
                },
            },
            'created': this.safeInteger(market, 'oDate'),
            'info': market,
        };
    }
    /**
     * @method
     * @name poloniex#fetchTime
     * @description fetches the current integer timestamp in milliseconds from the exchange server
     * @see https://api-docs.poloniex.com/spot/api/public/reference-data#system-timestamp
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @returns {int} the current integer timestamp in milliseconds from the exchange server
     */
    async fetchTime(params = {}) {
        const response = await this.publicGetTimestamp(params);
        return this.safeInteger(response, 'serverTime');
    }
    parseTicker(ticker, market = undefined) {
        //
        //  spot:
        //
        //     {
        //         "symbol" : "BTC_USDT",
        //         "open" : "26053.33",
        //         "low" : "26053.33",
        //         "high" : "26798.02",
        //         "close" : "26447.58",
        //         "quantity" : "6116.210188",
        //         "amount" : "161082122.88450926",
        //         "tradeCount" : "134709",
        //         "startTime" : "1692784440000",
        //         "closeTime" : "1692870839630",
        //         "displayName" : "BTC/USDT",
        //         "dailyChange" : "0.0151",
        //         "bid" : "26447.57",
        //         "bidQuantity" : "0.016313",
        //         "ask" : "26447.58",
        //         "askQuantity" : "0.068307",
        //         "ts" : "1692870845446",
        //         "markPrice" : "26444.11"
        //     }
        //
        //  swap:
        //
        //            {
        //                "s": "XRP_USDT_PERP",
        //                "o": "2.0503",
        //                "l": "2.0066",
        //                "h": "2.216",
        //                "c": "2.1798",
        //                "qty": "21090",
        //                "amt": "451339.65",
        //                "tC": "3267",
        //                "sT": "1740736380000",
        //                "cT": "1740822777559",
        //                "dN": "XRP/USDT/PERP",
        //                "dC": "0.0632",
        //                "bPx": "2.175",
        //                "bSz": "3",
        //                "aPx": "2.1831",
        //                "aSz": "111",
        //                "mPx": "2.1798",
        //                "iPx": "2.1834"
        //            },
        //
        const timestamp = this.safeInteger2(ticker, 'ts', 'cT');
        const marketId = this.safeString2(ticker, 'symbol', 's');
        market = this.safeMarket(marketId);
        const relativeChange = this.safeString2(ticker, 'dailyChange', 'dc');
        const percentage = Precise.stringMul(relativeChange, '100');
        return this.safeTicker({
            'id': marketId,
            'symbol': market['symbol'],
            'timestamp': timestamp,
            'datetime': this.iso8601(timestamp),
            'high': this.safeString2(ticker, 'high', 'h'),
            'low': this.safeString2(ticker, 'low', 'l'),
            'bid': this.safeString2(ticker, 'bid', 'bPx'),
            'bidVolume': this.safeString2(ticker, 'bidQuantity', 'bSz'),
            'ask': this.safeString2(ticker, 'ask', 'aPx'),
            'askVolume': this.safeString2(ticker, 'askQuantity', 'aSz'),
            'vwap': undefined,
            'open': this.safeString2(ticker, 'open', 'o'),
            'close': this.safeString2(ticker, 'close', 'c'),
            'previousClose': undefined,
            'change': undefined,
            'percentage': percentage,
            'average': undefined,
            'baseVolume': this.safeString2(ticker, 'quantity', 'qty'),
            'quoteVolume': this.safeString2(ticker, 'amount', 'amt'),
            'markPrice': this.safeString2(ticker, 'markPrice', 'mPx'),
            'indexPrice': this.safeString(ticker, 'iPx'),
            'info': ticker,
        }, market);
    }
    /**
     * @method
     * @name poloniex#fetchTickers
     * @description fetches price tickers for multiple markets, statistical information calculated over the past 24 hours for each market
     * @see https://api-docs.poloniex.com/spot/api/public/market-data#ticker
     * @see https://api-docs.poloniex.com/v3/futures/api/market/get-market-info
     * @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;
        const request = {};
        if (symbols !== undefined) {
            symbols = this.marketSymbols(symbols, undefined, true, true, false);
            const symbolsLength = symbols.length;
            if (symbolsLength > 0) {
                market = this.market(symbols[0]);
                if (symbolsLength === 1) {
                    request['symbol'] = market['id'];
                }
            }
        }
        let marketType = undefined;
        [marketType, params] = this.handleMarketTypeAndParams('fetchTickers', market, params);
        if (marketType === 'swap') {
            const responseRaw = await this.swapPublicGetV3MarketTickers(this.extend(request, params));
            //
            //    {
            //        "code": "200",
            //        "msg": "Success",
            //        "data": [
            //            {
            //                "s": "XRP_USDT_PERP",
            //                "o": "2.0503",
            //                "l": "2.0066",
            //                "h": "2.216",
            //                "c": "2.1798",
            //                "qty": "21090",
            //                "amt": "451339.65",
            //                "tC": "3267",
            //                "sT": "1740736380000",
            //                "cT": "1740822777559",
            //                "dN": "XRP/USDT/PERP",
            //                "dC": "0.0632",
            //                "bPx": "2.175",
            //                "bSz": "3",
            //                "aPx": "2.1831",
            //                "aSz": "111",
            //                "mPx": "2.1798",
            //                "iPx": "2.1834"
            //            },
            //
            const data = this.safeList(responseRaw, 'data');
            return this.parseTickers(data, symbols);
        }
        const response = await this.publicGetMarketsTicker24h(params);
        //
        //     [
        //         {
        //              "symbol" : "BTC_USDT",
        //              "open" : "26053.33",
        //              "low" : "26053.33",
        //              "high" : "26798.02",
        //              "close" : "26447.58",
        //              "quantity" : "6116.210188",
        //              "amount" : "161082122.88450926",
        //              "tradeCount" : "134709",
        //              "startTime" : "1692784440000",
        //              "closeTime" : "1692870839630",
        //              "displayName" : "BTC/USDT",
        //              "dailyChange" : "0.0151",
        //              "bid" : "26447.57",
        //              "bidQuantity" : "0.016313",
        //              "ask" : "26447.58",
        //              "askQuantity" : "0.068307",
        //              "ts" : "1692870845446",
        //              "markPrice" : "26444.11"
        //         }
        //     ]
        //
        return this.parseTickers(response, symbols);
    }
    /**
     * @method
     * @name poloniex#fetchCurrencies
     * @description fetches all available currencies on an exchange
     * @see https://api-docs.poloniex.com/spot/api/public/reference-data#currency-information
     * @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.publicGetCurrencies(this.extend(params, { 'includeMultiChainCurrencies': true }));
        //
        //     [
        //      {
        //        "USDT": {
        //           "id": 214,
        //           "name": "Tether USD",
        //           "description": "Sweep to Main Account",
        //           "type": "address",
        //           "withdrawalFee": "0.00000000",
        //           "minConf": 2,
        //           "depositAddress": null,
        //           "blockchain": "OMNI",
        //           "delisted": false,
        //           "tradingState": "NORMAL",
        //           "walletState": "DISABLED",
        //           "walletDepositState": "DISABLED",
        //           "walletWithdrawalState": "DISABLED",
        //           "supportCollateral": true,
        //           "supportBorrow": true,
        //           "parentChain": null,
        //           "isMultiChain": true,
        //           "isChildChain": false,
        //           "childChains": [
        //             "USDTBSC",
        //             "USDTETH",
        //             "USDTSOL",
        //             "USDTTRON"
        //           ]
        //        }
        //      },
        //      ...
        //      {
        //        "USDTBSC": {
        //              "id": 582,
        //              "name": "Binance-Peg BSC-USD",
        //              "description": "Sweep to Main Account",
        //              "type": "address",
        //              "withdrawalFee": "0.00000000",
        //              "minConf": 15,
        //              "depositAddress": null,
        //              "blockchain": "BSC",
        //              "delisted": false,
        //              "tradingState": "OFFLINE",
        //              "walletState": "ENABLED",
        //              "walletDepositState": "ENABLED",
        //              "walletWithdrawalState": "DISABLED",
        //              "supportCollateral": false,
        //              "supportBorrow": false,
        //              "parentChain": "USDT",
        //              "isMultiChain": true,
        //              "isChildChain": true,
        //              "childChains": []
        //        }
        //      },
        //      ...
        //     ]
        //
        const result = {};
        // poloniex has a complicated structure of currencies, so we handle them differently
        // at first, turn the response into a normal dictionary
        const currenciesDict = {};
        for (let i = 0; i < response.length; i++) {
            const item = this.safeDict(response, i);
            const ids = Object.keys(item);
            const id = this.safeString(ids, 0);
            currenciesDict[id] = item[id];
        }
        const keys = Object.keys(currenciesDict);
        for (let i = 0; i < keys.length; i++) {
            const id = keys[i];
            const entry = currenciesDict[id];
            const code = this.safeCurrencyCode(id);
            // skip childChains, as they are collected in parentChain loop
            if (this.safeBool(entry, 'isChildChain')) {
                continue;
            }
            const allChainEntries = [];
            const childChains = this.safeList(entry, 'childChains', []);
            if (childChains !== undefined) {
                for (let j = 0; j < childChains.length; j++) {
                    const childChainId = childChains[j];
                    const childNetworkEntry = this.safeDict(currenciesDict, childChainId);
                    allChainEntries.push(childNetworkEntry);
                }
            }
            allChainEntries.push(entry);
            const networks = {};
            for (let j = 0; j < allChainEntries.length; j++) {
                const chainEntry = allChainEntries[j];
                const networkName = this.safeString(chainEntry, 'blockchain');
                const networkCode = this.networkIdToCode(networkName, code);
                const specialNetworkId = this.safeString(childChains, j, id); // in case it's primary chain, defeault to ID
                networks[networkCode] = {
                    'info': chainEntry,
                    'id': specialNetworkId,
                    'numericId': this.safeInteger(chainEntry, 'id'),
                    'network': networkCode,
                    'active': this.safeBool(chainEntry, 'walletState'),
                    'deposit': this.safeString(chainEntry, 'walletDepositState') === 'ENABLED',
                    'withdraw': this.safeString(chainEntry, 'walletWithdrawalState') === 'ENABLED',
                    'fee': this.safeNumber(chainEntry, 'withdrawalFee'),
                    'precision': undefined,
                    'limits': {
                        'withdraw': {
                            'min': undefined,
                            'max': undefined,
                        },
                        'deposit': {
                            'min': undefined,
                            'max': undefined,
                        },
                    },
                };
            }
            result[code] = this.safeCurrencyStructure({
                'info': entry,
                'code': code,
                'id': id,
                'numericId': this.safeInteger(entry, 'id'),
                'type': 'crypto',
                'name': this.safeString(entry, 'name'),
                'active': undefined,
                'deposit': undefined,
                'withdraw': undefined,
                'fee': undefined,
                'precision': undefined,
                'limits': {
                    'amount': {
                        'min': undefined,
                        'max': undefined,
                    },
                    'withdraw': {
                        'min': undefined,
                        'max': undefined,
                    },
                    'deposit': {
                        'min': undefined,
                        'max': undefined,
                    },
                },
                'networks': networks,
            });
        }
        return result;
    }
    /**
     * @method
     * @name poloniex#fetchTicker
     * @description fetches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
     * @see https://api-docs.poloniex.com/spot/api/public/market-data#ticker
     * @see https://api-docs.poloniex.com/v3/futures/api/market/get-market-info
     * @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'],
        };
        if (market['contract']) {
            const tickers = await this.fetchTickers([market['symbol']], params);
            return this.safeDict(tickers, symbol);
        }
        const response = await this.publicGetMarketsSymbolTicker24h(this.extend(request, params));
        //
        //     {
        //         "symbol" : "BTC_USDT",
        //         "open" : "26053.33",
        //         "low" : "26053.33",
        //         "high" : "26798.02",
        //         "close" : "26447.58",
        //         "quantity" : "6116.210188",
        //         "amount" : "161082122.88450926",
        //         "tradeCount" : "134709",
        //         "startTime" : "1692784440000",
        //         "closeTime" : "1692870839630",
        //         "displayName" : "BTC/USDT",
        //         "dailyChange" : "0.0151",
        //         "bid" : "26447.57",
        //         "bidQuantity" : "0.016313",
        //         "ask" : "26447.58",
        //         "askQuantity" : "0.068307",
        //         "ts" : "1692870845446",
        //         "markPrice" : "26444.11"
        //     }
        //
        return this.parseTicker(response, market);
    }
    parseTrade(trade, market = undefined) {
        //
        // fetchTrades
        //
        //  spot:
        //
        //     {
        //         "id" : "60014521",
        //         "price" : "23162.94",
        //         "quantity" : "0.00009",
        //         "amount" : "2.0846646",
        //         "takerSide" : "SELL",
        //         "ts" : 1659684602042,
        //         "createTime" : 1659684602036
        //     }
        //
        //   swap:
        //
        //     {
        //         "id": "105807376",
        //         "side": "buy",
        //         "px": "84410.57",
        //         "qty": "1",
        //         "amt": "84.41057",
        //         "cT": "1740777563557",
        //     }
        //
        // fetchMyTrades
        //
        //  spot:
        //
        //     {
        //         "id": "32164924331503616",
        //         "symbol": "LINK_USDT",
        //         "accountType": "SPOT",
        //         "orderId": "32164923987566592",
        //         "side": "SELL",
        //         "type": "MARKET",
        //         "matchRole": "TAKER",
        //         "createTime": 1648635115525,
        //         "price": "11",
        //         "quantity": "0.5",
        //         "amount": "5.5",
        //         "feeCurrency": "USDT",
        //         "feeAmount": "0.007975",
        //         "pageId": "32164924331503616",
        //         "clientOrderId": "myOwnId-321"
        //     }
        //
        //  swap:
        //
        //     {
        //         "symbol": "BTC_USDT_PERP",
        //         "trdId": "105813553",
        //         "side": "SELL",
        //         "type": "TRADE",
        //         "mgnMode": "CROSS",
        //         "ordType": "MARKET",
        //         "clOrdId": "polo418912106147315112",
        //         "role": "TAKER",
        //         "px": "84704.9",
        //         "qty": "1",
        //         "cTime": "1740842829430",
        //         "uTime": "1740842829450",
        //         "feeCcy": "USDT",
        //         "feeAmt": "0.04235245",
        //         "deductCcy": "",
        //         "deductAmt": "0",
        //         "feeRate": "0.0005",
        //         "id": "418912106342654592",
        //         "posSide": "BOTH",
        //         "ordId": "418912106147315112",
        //         "qCcy": "USDT",
        //         "value": "84.7049",
        //         "actType": "TRADING"
        //     },
        //
        // fetchOrderTrades (taker trades)
        //
        //     {
        //         "id": "30341456333942784",
        //         "symbol": "LINK_USDT",
        //         "accountType": "SPOT",
        //         "orderId": "30249408733945856",
        //         "side": "BUY",
        //         "type": "LIMIT",
        //         "matchRole": "MAKER",
        //         "createTime": 1648200366864,
        //         "price": "3.1",
        //         "quantity": "1",
        //         "amount": "3.1",
        //         "feeCurrency": "LINK",
        //         "feeAmount": "0.00145",
        //         "pageId": "30341456333942784",
        //         "clientOrderId": ""
        //     }
        //
        const id = this.safeStringN(trade, ['id', 'tradeID', 'trdId']);
        const orderId = this.safeString2(trade, 'orderId', 'ordId');
        const timestamp = this.safeIntegerN(trade, ['ts', 'createTime', 'cT', 'cTime']);
        const marketId = this.safeString(trade, 'symbol');
        market = this.safeMarket(marketId, market, '_');
        const symbol = market['symbol'];
        const side = this.safeStringLower2(trade, 'side', 'takerSide');
        let fee = undefined;
        const priceString = this.safeString2(trade, 'price', 'px');
        const amountString = this.safeString2(trade, 'quantity', 'qty');
        const costString = this.safeString2(trade, 'amount', 'amt');
        const feeCurrencyId = this.safeString2(trade, 'feeCurrency', 'feeCcy');
        const feeCostString = this.safeString2(trade, 'feeAmount', 'feeAmt');
        if (feeCostString !== undefined) {
            const feeCurrencyCode = this.safeCurrencyCode(feeCurrencyId);
            fee = {
                'cost': feeCostString,
                'currency': feeCurrencyCode,
            };
        }
        return this.safeTrade({
            'id': id,
            'info': trade,
            'timestamp': timestamp,
            'datetime': this.iso8601(timestamp),
            'symbol': symbol,
            'order': orderId,
            'type': this.safeStringLower2(trade, 'ordType', 'type'),
            'side': side,
            'takerOrMaker': this.safeStringLower2(trade, 'matchRole', 'role'),
            'price': priceString,
            'amount': amountString,
            'cost': costString,
            'fee': fee,
        }, market);
    }
    /**
     * @method
     * @name poloniex#fetchTrades
     * @description get the list of most recent trades for a particular symbol
     * @see https://api-docs.poloniex.com/spot/api/public/market-data#trades
     * @see https://api-docs.poloniex.com/v3/futures/api/market/get-execution-info
     * @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'],
        };
        if (limit !== undefined) {
            request['limit'] = limit; // max 1000, for spot & swap
        }
        if (market['contract']) {
            const response = await this.swapPublicGetV3MarketTrades(this.extend(request, params));
            //
            //     {
            //         code: "200",
            //         msg: "Success",
            //         data: [
            //         {
            //             id: "105807320", // descending order
            //             side: "sell",
            //             px: "84383.93",
            //             qty: "1",
            //             amt: "84.38393",
            //             cT: "1740777074704",
            //         },
            //
            const tradesList = this.safeList(response, 'data');
            return this.parseTrades(tradesList, market, since, limit);
        }
        const trades = await this.publicGetMarketsSymbolTrades(this.extend(request, params));
        //
        //     [
        //         {
        //             "id" : "60014521",
        //             "price" : "23162.94",
        //             "quantity" : "0.00009",
        //             "amount" : "2.0846646",
        //             "takerSide" : "SELL",
        //             "ts" : 1659684602042,
        //             "createTime" : 1659684602036
        //         }
        //     ]
        //
        return this.parseTrades(trades, market, since, limit);
    }
    /**
     * @method
     * @name poloniex#fetchMyTrades
     * @description fetch all trades made by the user
     * @see https://api-docs.poloniex.com/spot/api/private/trade#trade-history
     * @see https://api-docs.poloniex.com/v3/futures/api/trade/get-execution-details
     * @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
     * @param {int} [params.until] the latest time in ms to fetch entries for
     * @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)
     * @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 paginate = false;
        [paginate, params] = this.handleOptionAndParams(params, 'fetchMyTrades', 'paginate');
        if (paginate) {
            return await this.fetchPaginatedCallDynamic('fetchMyTrades', symbol, since, limit, params);
        }
        let market = undefined;
        if (symbol !== undefined) {
            market = this.market(symbol);
        }
        let marketType = undefined;
        [marketType, params] = this.handleMarketTypeAndParams('fetchMyTrades', market, params);
        const isContract = this.inArray(marketType, ['swap', 'future']);
        let request = {
        // 'from': 12345678, // A 'trade Id'. The query begins at ‘from'.
        // 'direction': 'PRE', // PRE, NEXT The direction before or after ‘from'.
        };
        const startKey = isContract ? 'sTime' : 'startTime';
        const endKey = isContract ? 'eTime' : 'endTime';
        if (since !== undefined) {
            request[startKey] = since;
        }
        if (limit !== undefined) {
            request['limit'] = limit;
        }
        if (isContract && symbol !== undefined) {
            request['symbol'] = market['id'];
        }
        [request, params] = this.handleUntilOption(endKey, request, params);
        if (isContract) {
            const raw = await this.swapPrivateGetV3TradeOrderTrades(this.extend(request, params));
            //
            //    {
            //        "code": "200",
            //        "msg": "",
            //        "data": [
            //            {
            //                "symbol": "BTC_USDT_PERP",
            //                "trdId": "105813553",
            //                "side": "SELL",
            //                "type": "TRADE",
            //                "mgnMode": "CROSS",
            //                "ordType": "MARKET",
            //                "clOrdId": "polo418912106147315112",
            //                "role": "TAKER",
            //                "px": "84704.9",
            //                "qty": "1",
            //                "cTime": "1740842829430",
            //                "uTime": "1740842829450",
            //                "feeCcy": "USDT",
            //                "feeAmt": "0.04235245",
            //                "deductCcy": "",
            //                "deductAmt": "0",
            //                "feeRate": "0.0005",
            //                "id": "418912106342654592",
            //                "posSide": "BOTH",
            //                "ordId": "418912106147315112",
            //                "qCcy": "USDT",
            //                "value": "84.7049",
            //                "actType": "TRADING"
            //            },
            //
            const data = this.safeList(raw, 'data');
            return this.parseTrades(data, market, since, limit);
        }
        const response = await this.privateGetTrades(this.extend(request, params));
        //
        //     [
        //         {
        //             "id": "32164924331503616",
        //             "symbol": "LINK_USDT",
        //             "accountType": "SPOT",
        //             "orderId": "32164923987566592",
        //             "side": "SELL",
        //             "type": "MARKET",
        //             "matchRole": "TAKER",
        //             "createTime": 1648635115525,
        //             "price": "11",
        //             "quantity": "0.5",
        //             "amount": "5.5",
        //             "feeCurrency": "USDT",
        //             "feeAmount": "0.007975",
        //             "pageId": "32164924331503616",
        //             "clientOrderId": "myOwnId-321"
        //         }
        //     ]
        //
        const result = this.parseTrades(response, market, since, limit);
        return result;
    }
    parseOrderStatus(status) {
        const statuses = {
            'NEW': 'open',
            'PARTIALLY_FILLED': 'open',
            'FILLED': 'closed',
            'PENDING_CANCEL': 'canceled',
            'PARTIALLY_CANCELED': 'canceled',
            'CANCELED': 'canceled',
            'FAILED': 'canceled',
        };
        return this.safeString(statuses, status, status);
    }
    parseOrder(order, market = undefined) {
        //
        // fetchOpenOrder
        //
        //     {
        //         "id" : "7xxxxxxxxxxxxxxx6",
        //         "clientOrderId" : "",
        //         "symbol" : "ETH_USDT",
        //         "state" : "NEW",
        //         "accountType" : "SPOT",
        //         "side" : "BUY",
        //         "type" : "LIMIT",
        //         "timeInForce" : "GTC",
        //         "quantity" : "0.001",
        //         "price" : "1600",
        //         "avgPrice" : "0",
        //         "amount" : "0",
        //         "filledQuantity" : "0",
        //         "filledAmount" : "0",
        //         "createTime" : 16xxxxxxxxx26,
        //         "updateTime" : 16xxxxxxxxx36
        //     }
        //
        // fetchOpenOrders (and fetchClosedOrders same for contracts)
        //
        //  spot:
        //
        //     {
        //         "id": "24993088082542592",
        //         "clientOrderId": "",
        //         "symbol": "ELON_USDC",
        //         "state": "NEW",
        //         "accountType": "SPOT",
        //         "side": "SELL",
        //         "type": "MARKET",
        //         "timeInForce": "GTC",
        //         "quantity": "1.00",
        //         "price": "0.00",
        //         "avgPrice": "0.00",
        //         "amount": "0.00",
        //         "filledQuantity": "0.00",
        //         "filledAmount": "0.00",
        //         "createTime": 1646925216548,
        //         "updateTime": 1646925216548
        //     }
        //
        //  contract:
        //
        //     {
        //         "symbol": "BTC_USDT_PERP",
        //         "side": "BUY",
        //         "type": "LIMIT",
        //         "ordId": "418890767248232148",
        //         "clOrdId": "polo418890767248232148",
        //         "mgnMode": "CROSS",
        //         "px": "81130.13",
        //         "reduceOnly": false,
        //         "lever": "20",
        //         "state": "NEW",
        //         "source": "WEB",
        //         "timeInForce": "GTC",
        //         "tpTrgPx": "",
        //         "tpPx": "",
        //         "tpTrgPxType": "",
        //         "slTrgPx": "",
        //         "slPx": "",
        //         "slTrgPxType": "",
        //         "avgPx": "0",
        //         "execQty": "0",
        //         "execAmt": "0",
        //         "feeCcy": "",
        //         "feeAmt": "0",
        //         "deductCcy": "0",
        //         "deductAmt": "0",
        //         "stpMode": "NONE", // todo: selfTradePrevention
        //         "cTime": "1740837741523",
        //         "uTime": "1740840846882",
        //         "sz": "1",
        //         "posSide": "BOTH",
        //         "qCcy": "USDT"
        //         "cancelReason": "", // this field can only be in closed orders
        //     },
        //
        // createOrder, editOrder
        //
        //  spot:
        //
        //     {
        //         "id": "29772698821328896",
        //         "clientOrderId": "1234Abc"
        //     }
        //
        //  contract:
        //
        //    {
        //        "ordId":"418876147745775616",
        //        "clOrdId":"polo418876147745775616"
        //    }
        //
        let timestamp = this.safeIntegerN(order, ['timestamp', 'createTime', 'cTime']);
        if (timestamp === undefined) {
            timestamp = this.parse8601(this.safeString(order, 'date'));
        }
        const marketId = this.safeString(order, 'symbol');
        market = this.safeMarket(marketId, market, '_');
        const symbol = market['symbol'];
        let resultingTrades = this.safeValue(order, 'resultingTrades');
        if (resultingTrades !== undefined) {
            if (!Array.isArray(resultingTrades)) {
                resultingTrades = this.safeValue(resultingTrades, this.safeString(market, 'id', marketId));
            }
        }
        const price = this.safeStringN(order, ['price', 'rate', 'px']);
        const amount = this.safeString2(order, 'quantity', 'sz');
        const filled = this.safeString2(order, 'filledQuantity', 'execQty');
        const status = this.parseOrderStatus(this.safeString(order, 'state'));
        const side = this.safeStringLower(order, 'side');
        const rawType = this.safeString(order, 'type');
        const type = this.parseOrderType(rawType);
        const id = this.safeStringN(order, ['orderNumber', 'id', 'orderId', 'ordId']);
        let fee = undefined;
        const feeCurrency = this.safeString2(order, 'tokenFeeCurrency', 'feeCcy');
        let feeCost = undefined;
        let feeCurrencyCode = undefined;
        const rate = this.safeString(order, 'fee');
        if (feeCurrency === undefined) {
            feeCurrencyCode = (side === 'buy') ? market['base'] : market['quote'];
        }
        else {
            // poloniex accepts a 30% discount to pay fees in TRX
            feeCurrencyCode = this.safeCurrencyCode(feeCurrency);
            feeCost = this.safeString2(order, 'tokenFee', 'feeAmt');
        }
        if (feeCost !== undefined) {
            fee = {
                'rate': rate,
                'cost': feeCost,
                'currency': feeCurrencyCode,
            };
        }
        const clientOrderId = this.safeString2(order, 'clientOrderId', 'clOrdId');
        const marginMode = this.safeStringLower(order, 'mgnMode');
        const reduceOnly = this.safeBool(order, 'reduceOnly');
        const leverage = this.safeInteger(order, 'lever');
        const hedged = this.safeString(order, 'posSide') !== 'BOTH';
        return this.safeOrder({
            'info': order,
            'id': id,
            'clientOrderId': clientOrderId,
            'timestamp': timestamp,
            'datetime': this.iso8601(timestamp),
            'lastTradeTimestamp': this.safeInteger(order, 'updateTime'),
            'status': status,
            'symbol': symbol,
            'type': type,
            'timeInForce': this.safeString(order, 'timeInForce'),
            'postOnly': rawType === 'LIMIT_MAKER',
            'side': side,
            'price': price,
            'triggerPrice': this.safeString2(order, 'triggerPrice', 'stopPrice'),
            'cost': this.safeString(order, 'execAmt'),
            'average': this.safeString2(order, 'avgPrice', 'avgPx'),
            'amount': amount,
            'filled': filled,
            'remaining': undefined,
            'trades': resultingTrades,
            'fee': fee,
            'marginMode': marginMode,
            'reduceOnly': reduceOnly,
            'leverage': leverage,
            'hedged': hedged,
        }, market);
    }
    parseOrderType(status) {
        const statuses = {
            'MARKET': 'market',
            'LIMIT': 'limit',
            'LIMIT_MAKER': 'limit',
            'STOP-LIMIT': 'limit',
            'STOP-MARKET': 'market',
        };
        return this.safeString(statuses, status, status);
    }
    parseOpenOrders(orders, market, result) {
        for (let i = 0; i < orders.length; i++) {
            const order = orders[i];
            const extended = this.extend(order, {
                'status': 'open',
                'type': 'limit',
                'side': order['type'],
                'price': order['rate'],
            });
            result.push(this.parseOrder(extended, market));
        }
        return result;
    }
    /**
     * @method
     * @name poloniex#fetchOpenOrders
     * @description fetch all unfilled currently open orders
     * @see https://api-docs.poloniex.com/spot/api/private/order#open-orders
     * @see https://api-docs.poloniex.com/spot/api/private/smart-order#open-orders  // trigger orders
     * @see https://api-docs.poloniex.com/v3/futures/api/trade/get-current-orders
     * @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 orders structures to retrieve
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @param {boolean} [params.trigger] set true to fetch trigger orders instead of regular orders
     * @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();
        let market = undefined;
        const request = {};
        if (symbol !== undefined) {
            market = this.market(symbol);
            request['symbol'] = market['id'];
        }
        let marketType = undefined;
        [marketType, params] = this.handleMarketTypeAndParams('fetchOpenOrders', market, params);
        if (limit !== undefined) {
            const max = (marketType === 'spot') ? 2000 : 100;
            request['limit'] = Math.max(limit, max);
        }
        const isTrigger = this.safeValue2(params, 'trigger', 'stop');
        params = this.omit(params, ['trigger', 'stop']);
        let response = undefined;
        if (marketType !== 'spot') {
            const raw = await this.swapPrivateGetV3TradeOrderOpens(this.extend(request, params));
            //
            //    {
            //        "code": "200",
            //        "msg": "",
            //        "data": [
            //            {
            //                "symbol": "BTC_USDT_PERP",
            //                "side": "BUY",
            //                "type": "LIMIT",
            //                "ordId": "418890767248232148",
            //                "clOrdId": "polo418890767248232148",
            //                "mgnMode": "CROSS",
            //                "px": "81130.13",
            //                "reduceOnly": false,
            //                "lever": "20",
            //                "state": "NEW",
            //                "source": "WEB",
            //                "timeInForce": "GTC",
            //                "tpTrgPx": "",
            //                "tpPx": "",
            //                "tpTrgPxType": "",
            //                "slTrgPx": "",
            //                "slPx": "",
            //                "slTrgPxType": "",
            //                "avgPx": "0",
            //                "execQty": "0",
            //                "execAmt": "0",
            //                "feeCcy": "",
            //                "feeAmt": "0",
            //                "deductCcy": "0",
            //                "deductAmt": "0",
            //                "stpMode": "NONE",
            //                "cTime": "1740837741523",
            //                "uTime": "1740840846882",
            //                "sz": "1",
            //                "posSide": "BOTH",
            //                "qCcy": "USDT"
            //            },
            //
            response = this.safeList(raw, 'data');
        }
        else if (isTrigger) {
            response = await this.privateGetSmartorders(this.extend(request, params));
        }
        else {
            response = await this.privateGetOrders(this.extend(request, params));
        }
        //
        //     [
        //         {
        //             "id" : "7xxxxxxxxxxxxxxx6",
        //             "clientOrderId" : "",
        //             "symbol" : "ETH_USDT",
        //             "state" : "NEW",
        //             "accountType" : "SPOT",
        //             "side" : "BUY",
        //             "type" : "LIMIT",
        //             "timeInForce" : "GTC",
        //             "quantity" : "0.001",
        //             "price" : "1600",
        //             "avgPrice" : "0",
        //             "amount" : "0",
        //             "filledQuantity" : "0",
        //             "filledAmount" : "0",
        //             "stopPrice": "3750.00",              // for trigger orders
        //             "createTime" : 16xxxxxxxxx26,
        //             "updateTime" : 16xxxxxxxxx36
        //         }
        //     ]
        //
        const extension = { 'status': 'open' };
        return this.parseOrders(response, market, since, limit, extension);
    }
    /**
     * @method
     * @name poloniex#fetchClosedOrders
     * @see https://api-docs.poloniex.com/v3/futures/api/trade/get-order-history
     * @description fetches information on multiple closed orders made by the user
     * @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 {int} [params.until] timestamp in ms of the latest entry
     * @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;
        let request = {};
        if (symbol !== undefined) {
            market = this.market(symbol);
            request['symbol'] = market['id'];
        }
        let marketType = undefined;
        [marketType, params] = this.handleMarketTypeAndParams('fetchClosedOrders', market, params, 'swap');
        if (marketType === 'spot') {
            throw new NotSupported(this.id + ' fetchClosedOrders() is not supported for spot markets yet');
        }
        if (limit !== undefined) {
            request['limit'] = Math.min(200, limit);
        }
        if (since !== undefined) {
            request['sTime'] = since;
        }
        [request, params] = this.handleUntilOption('eTime', request, params);
        const response = await this.swapPrivateGetV3TradeOrderHistory(this.extend(request, params));
        //
        //    {
        //        "code": "200",
        //        "msg": "",
        //        "data": [
        //            {
        //                "symbol": "BTC_USDT_PERP",
        //                "side": "SELL",
        //                "type": "MARKET",
        //                "ordId": "418912106147315712",
        //                "clOrdId": "polo418912106147315712",
        //                "mgnMode": "CROSS",
        //                "px": "0",
        //                "sz": "2",
        //                "lever": "20",
        //                "state": "FILLED",
        //                "cancelReason": "",
        //                "source": "WEB",
        //                "reduceOnly": "true",
        //                "timeInForce": "GTC",
        //                "tpTrgPx": "",
        //                "tpPx": "",
        //                "tpTrgPxType": "",
        //                "slTrgPx": "",
        //                "slPx": "",
        //                "slTrgPxType": "",
        //                "avgPx": "84705.56",
        //                "execQty": "2",
        //                "execAmt": "169.41112",
        //                "feeCcy": "USDT",
        //                "feeAmt": "0.08470556",
        //                "deductCcy": "0",
        //                "deductAmt": "0",
        //                "stpMode": "NONE",
        //                "cTime": "1740842829116",
        //                "uTime": "1740842829130",
        //                "posSide": "BOTH",
        //                "qCcy": "USDT"
        //            },
        //
        const data = this.safeList(response, 'data', []);
        return this.parseOrders(data, market, since, limit);
    }
    /**
     * @method
     * @name poloniex#createOrder
     * @description create a trade order
     * @see https://api-docs.poloniex.com/spot/api/private/order#create-order
     * @see https://api-docs.poloniex.com/spot/api/private/smart-order#create-order  // trigger orders
     * @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.triggerPrice] the price at which a trigger order is triggered at
     * @param {float} [params.cost] *spot market buy only* the quote quantity that can be used as an alternative for the amount
     * @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);
        let request = {
            'symbol': market['id'],
            'side': side.toUpperCase(), // uppercase, both for spot & swap
            // 'timeInForce': timeInForce, // matches unified values
            // 'accountType': 'SPOT',
            // 'amount': amount,
        };
        const triggerPrice = this.safeNumber2(params, 'stopPrice', 'triggerPrice');
        [request, params] = this.orderRequest(symbol, type, side, amount, request, price, params);
        let response = undefined;
        if (market['swap'] || market['future']) {
            const responseInitial = await this.swapPrivatePostV3TradeOrder(this.extend(request, params));
            //
            // {"code":200,"msg":"Success","data":{"ordId":"418876147745775616","clOrdId":"polo418876147745775616"}}
            //
            response = this.safeDict(responseInitial, 'data');
        }
        else if (triggerPrice !== undefined) {
            response = await this.privatePostSmartorders(this.extend(request, params));
        }
        else {
            response = await this.privatePostOrders(this.extend(request, params));
        }
        //
        //     {
        //         "id" : "78923648051920896",
        //         "clientOrderId" : ""
        //     }
        //
        return this.parseOrder(response, market);
    }
    orderRequest(symbol, type, side, amount, request, price = undefined, params = {}) {
        const triggerPrice = this.safeNumber2(params, 'stopPrice', 'triggerPrice');
        const market = this.market(symbol);
        if (market['contract']) {
            let marginMode = undefined;
            [marginMode, params] = this.handleParamString(params, 'marginMode');
            if (marginMode !== undefined) {
                this.checkRequiredArgument('createOrder', marginMode, 'marginMode', ['cross', 'isolated']);
                request['mgnMode'] = marginMode.toUpperCase();
            }
            let hedged = undefined;
            [hedged, params] = this.handleParamString(params, 'hedged');
            if (hedged) {
                if (marginMode === undefined) {
                    throw new ArgumentsRequired(this.id + ' createOrder() requires a marginMode parameter "cross" or "isolated" for hedged orders');
                }
                if (!('posSide' in params)) {
                    throw new ArgumentsRequired(this.id + ' createOrder() requires a posSide parameter "LONG" or "SHORT" for hedged orders');
                }
            }
        }
        let upperCaseType = type.toUpperCase();
        const isMarket = upperCaseType === 'MARKET';
        const isPostOnly = this.isPostOnly(isMarket, upperCaseType === 'LIMIT_MAKER', params);
        params = this.omit(params, ['postOnly', 'triggerPrice', 'stopPrice']);
        if (triggerPrice !== undefined) {
            if (!market['spot']) {
                throw new InvalidOrder(this.id + ' createOrder() does not support trigger orders for ' + market['type'] + ' markets');
            }
            upperCaseType = (price === undefined) ? 'STOP' : 'STOP_LIMIT';
            request['stopPrice'] = triggerPrice;
        }
        else if (isPostOnly) {
            upperCaseType = 'LIMIT_MAKER';
        }
        request['type'] = upperCaseType;
        if (isMarket) {
            if (side === 'buy') {
                let quoteAmount = undefined;
                let createMarketBuyOrderRequiresPrice = true;
                [createMarketBuyOrderRequiresPrice, params] = this.handleOptionAndParams(params, 'createOrder', 'createMarketBuyOrderRequiresPrice', true);
                const cost = this.safeNumber(params, 'cost');
                params = this.omit(params, 'cost');
                if (cost !== undefined) {
                    quoteAmount = this.costToPrecision(symbol, cost);
                }
                else if (createMarketBuyOrderRequiresPrice && market['spot']) {
                    if (price === undefined) {
                        throw new InvalidOrder(this.id + ' createOrder() requires the price argument for market buy orders to calculate the total cost to spend (amount * price), alternatively set the createMarketBuyOrderRequiresPrice option or param to false and pass the cost to spend (quote quantity) in the amount argument');
                    }
                    else {
                        const amountString = this.numberToString(amount);
                        const priceString = this.numberToString(price);
                        const costRequest = Precise.stringMul(amountString, priceString);
                        quoteAmount = this.costToPrecision(symbol, costRequest);
                    }
                }
                else {
                    quoteAmount = this.costToPrecision(symbol, amount);
                }
                const amountKey = market['spot'] ? 'amount' : 'sz';
                request[amountKey] = quoteAmount;
            }
            else {
                const amountKey = market['spot'] ? 'quantity' : 'sz';
                request[amountKey] = this.amountToPrecision(symbol, amount);
            }
        }
        else {
            const amountKey = market['spot'] ? 'quantity' : 'sz';
            request[amountKey] = this.amountToPrecision(symbol, amount);
            const priceKey = market['spot'] ? 'price' : 'px';
            request[priceKey] = this.priceToPrecision(symbol, price);
        }
        const clientOrderId = this.safeString(params, 'clientOrderId');
        if (clientOrderId !== undefined) {
            request['clientOrderId'] = clientOrderId;
            params = this.omit(params, 'clientOrderId');
        }
        // remember the timestamp before issuing the request
        return [request, params];
    }
    /**
     * @method
     * @name poloniex#editOrder
     * @description edit a trade order
     * @see https://api-docs.poloniex.com/spot/api/private/order#cancel-replace-order
     * @see https://api-docs.poloniex.com/spot/api/private/smart-order#cancel-replace-order
     * @param {string} id 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 the currency you want to trade in units of the 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.triggerPrice] The price at which a trigger order is triggered at
     * @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);
        if (!market['spot']) {
            throw new NotSupported(this.id + ' editOrder() does not support ' + market['type'] + ' orders, only spot orders are accepted');
        }
        let request = {
            'id': id,
            // 'timeInForce': timeInForce,
        };
        const triggerPrice = this.safeNumber2(params, 'stopPrice', 'triggerPrice');
        [request, params] = this.orderRequest(symbol, type, side, amount, request, price, params);
        let response = undefined;
        if (triggerPrice !== undefined) {
            response = await this.privatePutSmartordersId(this.extend(request, params));
        }
        else {
            response = await this.privatePutOrdersId(this.extend(request, params));
        }
        //
        //     {
        //         "id" : "78923648051920896",
        //         "clientOrderId" : ""
        //     }
        //
        response = this.extend(response, {
            'side': side,
            'type': type,
        });
        return this.parseOrder(response, market);
    }
    async cancelOrder(id, symbol = undefined, params = {}) {
        //
        // @method
        // @name poloniex#cancelOrder
        // @description cancels an open order
        // @see https://api-docs.poloniex.com/spot/api/private/order#cancel-order-by-id
        // @see https://api-docs.poloniex.com/spot/api/private/smart-order#cancel-order-by-id  // trigger orders
        // @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 {boolean} [params.trigger] true if canceling a trigger order
        // @returns {object} An [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
        //
        await this.loadMarkets();
        if (symbol === undefined) {
            throw new ArgumentsRequired(this.id + ' cancelOrder() requires a symbol argument');
        }
        const market = this.market(symbol);
        const request = {};
        if (!market['spot']) {
            request['symbol'] = market['id'];
            request['ordId'] = id;
            const raw = await this.swapPrivateDeleteV3TradeOrder(this.extend(request, params));
            //
            //    {
            //        "code": "200",
            //        "msg": "Success",
            //        "data": {
            //            "ordId": "418886099910612040",
            //            "clOrdId": "polo418886099910612040"
            //        }
            //    }
            //
            return this.parseOrder(this.safeDict(raw, 'data'));
        }
        const clientOrderId = this.safeValue(params, 'clientOrderId');
        if (clientOrderId !== undefined) {
            id = clientOrderId;
        }
        request['id'] = id;
        const isTrigger = this.safeValue2(params, 'trigger', 'stop');
        params = this.omit(params, ['clientOrderId', 'trigger', 'stop']);
        let response = undefined;
        if (isTrigger) {
            response = await this.privateDeleteSmartordersId(this.extend(request, params));
        }
        else {
            response = await this.privateDeleteOrdersId(this.extend(request, params));
        }
        //
        //   {
        //       "orderId":"210832697138888704",
        //       "clientOrderId":"",
        //       "state":"PENDING_CANCEL",
        //       "code":200,
        //       "message":""
        //   }
        //
        return this.parseOrder(response);
    }
    /**
     * @method
     * @name poloniex#cancelAllOrders
     * @description cancel all open orders
     * @see https://api-docs.poloniex.com/spot/api/private/order#cancel-all-orders
     * @see https://api-docs.poloniex.com/spot/api/private/smart-order#cancel-all-orders  // trigger orders
     * @see https://api-docs.poloniex.com/v3/futures/api/trade/cancel-all-orders - contract markets
     * @param {string} symbol unified market symbol, only orders in the market of this symbol are cancelled when symbol is not undefined
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @param {boolean} [params.trigger] true if canceling trigger orders
     * @returns {object[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
     */
    async cancelAllOrders(symbol = undefined, params = {}) {
        await this.loadMarkets();
        const request = {
            // 'accountTypes': 'SPOT',
            'symbols': [],
        };
        let market = undefined;
        if (symbol !== undefined) {
            market = this.market(symbol);
            request['symbols'] = [
                market['id'],
            ];
        }
        let response = undefined;
        let marketType = undefined;
        [marketType, params] = this.handleMarketTypeAndParams('cancelAllOrders', market, params);
        if (marketType === 'swap' || marketType === 'future') {
            const raw = await this.swapPrivateDeleteV3TradeAllOrders(this.extend(request, params));
            //
            //    {
            //        "code": "200",
            //        "msg": "Success",
            //        "data": [
            //            {
            //                "code": "200",
            //                "msg": "Success",
            //                "ordId": "418885787866388511",
            //                "clOrdId": "polo418885787866388511"
            //            }
            //        ]
            //    }
            //
            response = this.safeList(raw, 'data');
            return this.parseOrders(response, market);
        }
        const isTrigger = this.safeValue2(params, 'trigger', 'stop');
        params = this.omit(params, ['trigger', 'stop']);
        if (isTrigger) {
            response = await this.privateDeleteSmartorders(this.extend(request, params));
        }
        else {
            response = await this.privateDeleteOrders(this.extend(request, params));
        }
        //
        //     [
        //         {
        //             "orderId" : "78xxxxxxxx80",
        //             "clientOrderId" : "",
        //             "state" : "NEW",
        //             "code" : 200,
        //             "message" : ""
        //         }, {
        //             "orderId" : "78xxxxxxxxx80",
        //             "clientOrderId" : "",
        //             "state" : "NEW",
        //             "code" : 200,
        //             "message" : ""
        //         }
        //     ]
        //
        return this.parseOrders(response, market);
    }
    /**
     * @method
     * @name poloniex#fetchOrder
     * @description fetch an order by it's id
     * @see https://api-docs.poloniex.com/spot/api/private/order#order-details
     * @see https://api-docs.poloniex.com/spot/api/private/smart-order#open-orders  // trigger orders
     * @param {string} id order id
     * @param {string} symbol unified market symbol, default is undefined
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @param {boolean} [params.trigger] true if fetching a trigger order
     * @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
     */
    async fetchOrder(id, symbol = undefined, params = {}) {
        await this.loadMarkets();
        id = id.toString();
        const request = {
            'id': id,
        };
        let market = undefined;
        if (symbol !== undefined) {
            market = this.market(symbol);
            request['symbol'] = market['id'];
        }
        let marketType = undefined;
        [marketType, params] = this.handleMarketTypeAndParams('fetchOrder', market, params);
        if (marketType !== 'spot') {
            throw new NotSupported(this.id + ' fetchOrder() is not supported for ' + marketType + ' markets yet');
        }
        const isTrigger = this.safeValue2(params, 'trigger', 'stop');
        params = this.omit(params, ['trigger', 'stop']);
        let response = undefined;
        if (isTrigger) {
            response = await this.privateGetSmartordersId(this.extend(request, params));
            response = this.safeValue(response, 0);
        }
        else {
            response = await this.privateGetOrdersId(this.extend(request, params));
        }
        //
        //     {
        //         "id": "21934611974062080",
        //         "clientOrderId": "123",
        //         "symbol": "TRX_USDC",
        //         "state": "NEW",
        //         "accountType": "SPOT",
        //         "side": "SELL",
        //         "type": "LIMIT",
        //         "timeInForce": "GTC",
        //         "quantity": "1.00",
        //         "price": "10.00",
        //         "avgPrice": "0.00",
        //         "amount": "0.00",
        //         "filledQuantity": "0.00",
        //         "filledAmount": "0.00",
        //         "stopPrice": "3750.00",              // for trigger orders
        //         "createTime": 1646196019020,
        //         "updateTime": 1646196019020
        //     }
        //
        const order = this.parseOrder(response);
        order['id'] = id;
        return order;
    }
    async fetchOrderStatus(id, symbol = undefined, params = {}) {
        await this.loadMarkets();
        const orders = await this.fetchOpenOrders(symbol, undefined, undefined, params);
        const indexed = this.indexBy(orders, 'id');
        return (id in indexed) ? 'open' : 'closed';
    }
    /**
     * @method
     * @name poloniex#fetchOrderTrades
     * @description fetch all the trades made from a single order
     * @see https://api-docs.poloniex.com/spot/api/private/trade#trades-by-order-id
     * @param {string} id order id
     * @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 to retrieve
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @returns {object[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=trade-structure}
     */
    async fetchOrderTrades(id, symbol = undefined, since = undefined, limit = undefined, params = {}) {
        await this.loadMarkets();
        const request = {
            'id': id,
        };
        const trades = await this.privateGetOrdersIdTrades(this.extend(request, params));
        //
        //     [
        //         {
        //             "id": "30341456333942784",
        //             "symbol": "LINK_USDT",
        //             "accountType": "SPOT",
        //             "orderId": "30249408733945856",
        //             "side": "BUY",
        //             "type": "LIMIT",
        //             "matchRole": "MAKER",
        //             "createTime": 1648200366864,
        //             "price": "3.1",
        //             "quantity": "1",
        //             "amount": "3.1",
        //             "feeCurrency": "LINK",
        //             "feeAmount": "0.00145",
        //             "pageId": "30341456333942784",
        //             "clientOrderId": ""
        //         }
        //     ]
        //
        return this.parseTrades(trades);
    }
    parseBalance(response) {
        const result = {
            'info': response,
            'timestamp': undefined,
            'datetime': undefined,
        };
        // for swap
        if (!Array.isArray(response)) {
            const ts = this.safeInteger(response, 'uTime');
            result['timestamp'] = ts;
            result['datetime'] = this.iso8601(ts);
            const details = this.safeList(response, 'details', []);
            for (let i = 0; i < details.length; i++) {
                const balance = details[i];
                const currencyId = this.safeString(balance, 'ccy');
                const code = this.safeCurrencyCode(currencyId);
                const account = this.account();
                account['total'] = this.safeString(balance, 'avail');
                account['used'] = this.safeString(balance, 'im');
                result[code] = account;
            }
            return this.safeBalance(result);
        }
        // for spot
        for (let i = 0; i < response.length; i++) {
            const account = this.safeValue(response, i, {});
            const balances = this.safeValue(account, 'balances');
            for (let j = 0; j < balances.length; j++) {
                const balance = this.safeValue(balances, j);
                const currencyId = this.safeString(balance, 'currency');
                const code = this.safeCurrencyCode(currencyId);
                const newAccount = this.account();
                newAccount['free'] = this.safeString(balance, 'available');
                newAccount['used'] = this.safeString(balance, 'hold');
                result[code] = newAccount;
            }
        }
        return this.safeBalance(result);
    }
    /**
     * @method
     * @name poloniex#fetchBalance
     * @description query for balance and get the amount of funds available for trading or funds locked in orders
     * @see https://api-docs.poloniex.com/spot/api/private/account#all-account-balances
     * @see https://api-docs.poloniex.com/v3/futures/api/account/balance
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @returns {object} a [balance structure]{@link https://docs.ccxt.com/#/?id=balance-structure}
     */
    async fetchBalance(params = {}) {
        await this.loadMarkets();
        let marketType = undefined;
        [marketType, params] = this.handleMarketTypeAndParams('fetchBalance', undefined, params);
        if (marketType !== 'spot') {
            const responseRaw = await this.swapPrivateGetV3AccountBalance(params);
            //
            //    {
            //        "code": "200",
            //        "msg": "",
            //        "data": {
            //            "state": "NORMAL",
            //            "eq": "9.98571622",
            //            "isoEq": "0",
            //            "im": "0",
            //            "mm": "0",
            //            "mmr": "0",
            //            "upl": "0",
            //            "availMgn": "9.98571622",
            //            "cTime": "1738093601775",
            //            "uTime": "1740829116236",
            //            "details": [
            //                {
            //                    "ccy": "USDT",
            //                    "eq": "9.98571622",
            //                    "isoEq": "0",
            //                    "avail": "9.98571622",
            //                    "trdHold": "0",
            //                    "upl": "0",
            //                    "isoAvail": "0",
            //                    "isoHold": "0",
            //                    "isoUpl": "0",
            //                    "im": "0",
            //                    "mm": "0",
            //                    "mmr": "0",
            //                    "imr": "0",
            //                    "cTime": "1740829116236",
            //                    "uTime": "1740829116236"
            //                }
            //            ]
            //        }
            //    }
            //
            const data = this.safeDict(responseRaw, 'data', {});
            return this.parseBalance(data);
        }
        const request = {
            'accountType': 'SPOT',
        };
        const response = await this.privateGetAccountsBalances(this.extend(request, params));
        //
        //     [
        //         {
        //             "accountId" : "7xxxxxxxxxx8",
        //             "accountType" : "SPOT",
        //             "balances" : [
        //                 {
        //                     "currencyId" : "214",
        //                     "currency" : "USDT",
        //                     "available" : "2.00",
        //                     "hold" : "0.00"
        //                 }
        //             ]
        //         }
        //     ]
        //
        return this.parseBalance(response);
    }
    /**
     * @method
     * @name poloniex#fetchTradingFees
     * @description fetch the trading fees for multiple markets
     * @see https://api-docs.poloniex.com/spot/api/private/account#fee-info
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @returns {object} a dictionary of [fee structures]{@link https://docs.ccxt.com/#/?id=fee-structure} indexed by market symbols
     */
    async fetchTradingFees(params = {}) {
        await this.loadMarkets();
        const response = await this.privateGetFeeinfo(params);
        //
        //     {
        //         "trxDiscount" : false,
        //         "makerRate" : "0.00145",
        //         "takerRate" : "0.00155",
        //         "volume30D" : "0.00"
        //     }
        //
        const result = {};
        for (let i = 0; i < this.symbols.length; i++) {
            const symbol = this.symbols[i];
            result[symbol] = {
                'info': response,
                'symbol': symbol,
                'maker': this.safeNumber(response, 'makerRate'),
                'taker': this.safeNumber(response, 'takerRate'),
                'percentage': true,
                'tierBased': true,
            };
        }
        return result;
    }
    /**
     * @method
     * @name poloniex#fetchOrderBook
     * @description fetches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
     * @see https://api-docs.poloniex.com/spot/api/public/market-data#order-book
     * @see https://api-docs.poloniex.com/v3/futures/api/market/get-order-book
     * @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'],
        };
        if (limit !== undefined) {
            request['limit'] = limit; // The default value of limit is 10. Valid limit values are: 5, 10, 20, 50, 100, 150.
            if (market['contract']) {
                request['limit'] = this.findNearestCeiling([5, 10, 20, 100, 150], limit);
            }
        }
        if (market['contract']) {
            const responseRaw = await this.swapPublicGetV3MarketOrderBook(this.extend(request, params));
            //
            //    {
            //       "code": 200,
            //       "data": {
            //         "asks": [ ["58700", "9934"], ..],
            //         "bids": [ ["58600", "9952"], ..],
            //         "s": "100",
            //         "ts": 1719974138333
            //       },
            //       "msg": "Success"
            //    }
            //
            const data = this.safeDict(responseRaw, 'data', {});
            const ts = this.safeInteger(data, 'ts');
            return this.parseOrderBook(data, symbol, ts);
        }
        const response = await this.publicGetMarketsSymbolOrderBook(this.extend(request, params));
        //
        //     {
        //         "time" : 1659695219507,
        //         "scale" : "-1",
        //         "asks" : [ "23139.82", "0.317981", "23140", "0.191091", "23170.06", "0.01", "23200", "0.107758", "23230.55", "0.01", "23247.2", "0.154", "23254", "0.005121", "23263", "0.038", "23285.4", "0.308", "23300", "0.108896" ],
        //         "bids" : [ "23139.74", "0.432092", "23139.73", "0.198592", "23123.21", "0.000886", "23123.2", "0.308", "23121.4", "0.154", "23105", "0.000789", "23100", "0.078175", "23069.1", "0.026276", "23068.83", "0.001329", "23051", "0.000048" ],
        //         "ts" : 1659695219513
        //     }
        //
        const timestamp = this.safeInteger(response, 'time');
        const asks = this.safeValue(response, 'asks');
        const bids = this.safeValue(response, 'bids');
        const asksResult = [];
        const bidsResult = [];
        for (let i = 0; i < asks.length; i++) {
            if ((i % 2) < 1) {
                const price = this.safeNumber(asks, i);
                const amount = this.safeNumber(asks, this.sum(i, 1));
                asksResult.push([price, amount]);
            }
        }
        for (let i = 0; i < bids.length; i++) {
            if ((i % 2) < 1) {
                const price = this.safeNumber(bids, i);
                const amount = this.safeNumber(bids, this.sum(i, 1));
                bidsResult.push([price, amount]);
            }
        }
        return {
            'symbol': market['symbol'],
            'bids': this.sortBy(bidsResult, 0, true),
            'asks': this.sortBy(asksResult, 0),
            'timestamp': timestamp,
            'datetime': this.iso8601(timestamp),
            'nonce': undefined,
        };
    }
    /**
     * @method
     * @name poloniex#createDepositAddress
     * @description create a currency deposit address
     * @see https://api-docs.poloniex.com/spot/api/private/wallet#deposit-addresses
     * @param {string} code unified currency code of the currency for the deposit address
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @returns {object} an [address structure]{@link https://docs.ccxt.com/#/?id=address-structure}
     */
    async createDepositAddress(code, params = {}) {
        await this.loadMarkets();
        const [request, extraParams, currency, networkEntry] = this.prepareRequestForDepositAddress(code, params);
        params = extraParams;
        const response = await this.privatePostWalletsAddress(this.extend(request, params));
        //
        //     {
        //         "address" : "0xfxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxf"
        //     }
        //
        return this.parseDepositAddressSpecial(response, currency, networkEntry);
    }
    /**
     * @method
     * @name poloniex#fetchDepositAddress
     * @description fetch the deposit address for a currency associated with this account
     * @see https://api-docs.poloniex.com/spot/api/private/wallet#deposit-addresses
     * @param {string} code unified currency code
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @returns {object} an [address structure]{@link https://docs.ccxt.com/#/?id=address-structure}
     */
    async fetchDepositAddress(code, params = {}) {
        await this.loadMarkets();
        const [request, extraParams, currency, networkEntry] = this.prepareRequestForDepositAddress(code, params);
        params = extraParams;
        const response = await this.privateGetWalletsAddresses(this.extend(request, params));
        //
        //     {
        //         "USDTTRON" : "Txxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxp"
        //     }
        //
        const keys = Object.keys(response);
        const length = keys.length;
        if (length < 1) {
            throw new ExchangeError(this.id + ' fetchDepositAddress() returned an empty response, you might need to try "createDepositAddress" at first and then use "fetchDepositAddress"');
        }
        return this.parseDepositAddressSpecial(response, currency, networkEntry);
    }
    prepareRequestForDepositAddress(code, params = {}) {
        if (!(code in this.currencies)) {
            throw new BadSymbol(this.id + ' fetchDepositAddress(): can not recognize ' + code + ' currency, you might try using unified currency-code and add provide specific "network" parameter, like: fetchDepositAddress("USDT", { "network": "TRC20" })');
        }
        const currency = this.currency(code);
        let networkCode = undefined;
        [networkCode, params] = this.handleNetworkCodeAndParams(params);
        if (networkCode === undefined) {
            // we need to know the network to find out the currency-junction
            throw new ArgumentsRequired(this.id + ' fetchDepositAddress requires a network parameter for ' + code + '.');
        }
        let exchangeNetworkId = undefined;
        networkCode = this.networkIdToCode(networkCode, code);
        const networkEntry = this.safeDict(currency['networks'], networkCode);
        if (networkEntry !== undefined) {
            exchangeNetworkId = networkEntry['id'];
        }
        else {
            exchangeNetworkId = networkCode;
        }
        const request = {
            'currency': exchangeNetworkId,
        };
        return [request, params, currency, networkEntry];
    }
    parseDepositAddressSpecial(response, currency, networkEntry) {
        let address = this.safeString(response, 'address');
        if (address === undefined) {
            address = this.safeString(response, networkEntry['id']);
        }
        let tag = undefined;
        this.checkAddress(address);
        if (networkEntry !== undefined) {
            const depositAddress = this.safeString(networkEntry['info'], 'depositAddress');
            if (depositAddress !== undefined) {
                tag = address;
                address = depositAddress;
            }
        }
        return {
            'info': response,
            'currency': currency['code'],
            'network': this.safeString(networkEntry, 'network'),
            'address': address,
            'tag': tag,
        };
    }
    /**
     * @method
     * @name poloniex#transfer
     * @description transfer currency internally between wallets on the same account
     * @see https://api-docs.poloniex.com/spot/api/private/account#accounts-transfer
     * @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
     * @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, fromAccount);
        const request = {
            'amount': this.currencyToPrecision(code, amount),
            'currency': currency['id'],
            'fromAccount': fromId,
            'toAccount': toId,
        };
        const response = await this.privatePostAccountsTransfer(this.extend(request, params));
        //
        //    {
        //        "transferId" : "168041074"
        //    }
        //
        return this.parseTransfer(response, currency);
    }
    parseTransfer(transfer, currency = undefined) {
        //
        //    {
        //        "transferId" : "168041074"
        //    }
        //
        return {
            'info': transfer,
            'id': this.safeString(transfer, 'transferId'),
            'timestamp': undefined,
            'datetime': undefined,
            'currency': this.safeString(currency, 'id'),
            'amount': undefined,
            'fromAccount': undefined,
            'toAccount': undefined,
            'status': undefined,
        };
    }
    /**
     * @method
     * @name poloniex#withdraw
     * @description make a withdrawal
     * @see https://api-docs.poloniex.com/spot/api/private/wallet#withdraw-currency
     * @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 exchange API endpoint
     * @returns {object} a [transaction structure]{@link https://docs.ccxt.com/#/?id=transaction-structure}
     */
    async withdraw(code, amount, address, tag = undefined, params = {}) {
        [tag, params] = this.handleWithdrawTagAndParams(tag, params);
        this.checkAddress(address);
        const [request, extraParams, currency, networkEntry] = this.prepareRequestForDepositAddress(code, params);
        params = extraParams;
        request['amount'] = this.currencyToPrecision(code, amount);
        request['address'] = address;
        if (tag !== undefined) {
            request['paymentId'] = tag;
        }
        const response = await this.privatePostWalletsWithdraw(this.extend(request, params));
        //
        //     {
        //         "response": "Withdrew 1.00000000 USDT.",
        //         "email2FA": false,
        //         "withdrawalNumber": 13449869
        //     }
        //
        const withdrawResponse = {
            'response': response,
            'withdrawNetworkEntry': networkEntry,
        };
        return this.parseTransaction(withdrawResponse, currency);
    }
    async fetchTransactionsHelper(code = undefined, since = undefined, limit = undefined, params = {}) {
        await this.loadMarkets();
        const year = 31104000; // 60 * 60 * 24 * 30 * 12 = one year of history, why not
        const now = this.seconds();
        const start = (since !== undefined) ? this.parseToInt(since / 1000) : now - 10 * year;
        const request = {
            'start': start,
            'end': now, // UNIX timestamp, required
        };
        const response = await this.privateGetWalletsActivity(this.extend(request, params));
        //
        //     {
        //         "adjustments":[],
        //         "deposits":[
        //             {
        //                 "currency": "BTC",
        //                 "address": "1MEtiqJWru53FhhHrfJPPvd2tC3TPDVcmW",
        //                 "amount": "0.01063000",
        //                 "confirmations":  1,
        //                 "txid": "952b0e1888d6d491591facc0d37b5ebec540ac1efb241fdbc22bcc20d1822fb6",
        //                 "timestamp":  1507916888,
        //                 "status": "COMPLETE"
        //             },
        //             {
        //                 "currency": "ETH",
        //                 "address": "0x20108ba20b65c04d82909e91df06618107460197",
        //                 "amount": "4.00000000",
        //                 "confirmations": 38,
        //                 "txid": "0x4be260073491fe63935e9e0da42bd71138fdeb803732f41501015a2d46eb479d",
        //                 "timestamp": 1525060430,
        //                 "status": "COMPLETE"
        //             }
        //         ],
        //         "withdrawals":[
        //             {
        //                 "withdrawalNumber":13449869,
        //                 "currency":"USDTTRON", // not documented in API docs, see commonCurrencies in describe()
        //                 "address":"TXGaqPW23JdRWhsVwS2mRsGsegbdnAd3Rw",
        //                 "amount":"1.00000000",
        //                 "fee":"0.00000000",
        //                 "timestamp":1591573420,
        //                 "status":"COMPLETE: dadf427224b3d44b38a2c13caa4395e4666152556ca0b2f67dbd86a95655150f",
        //                 "ipAddress":"x.x.x.x",
        //                 "canCancel":0,
        //                 "canResendEmail":0,
        //                 "paymentID":null,
        //                 "scope":"crypto"
        //             },
        //             {
        //                 "withdrawalNumber": 8224394,
        //                 "currency": "EMC2",
        //                 "address": "EYEKyCrqTNmVCpdDV8w49XvSKRP9N3EUyF",
        //                 "amount": "63.10796020",
        //                 "fee": "0.01000000",
        //                 "timestamp": 1510819838,
        //                 "status": "COMPLETE: d37354f9d02cb24d98c8c4fc17aa42f475530b5727effdf668ee5a43ce667fd6",
        //                 "ipAddress": "x.x.x.x"
        //             },
        //             {
        //                 "withdrawalNumber": 9290444,
        //                 "currency": "ETH",
        //                 "address": "0x191015ff2e75261d50433fbd05bd57e942336149",
        //                 "amount": "0.15500000",
        //                 "fee": "0.00500000",
        //                 "timestamp": 1514099289,
        //                 "status": "COMPLETE: 0x12d444493b4bca668992021fd9e54b5292b8e71d9927af1f076f554e4bea5b2d",
        //                 "ipAddress": "x.x.x.x"
        //             },
        //             {
        //                 "withdrawalNumber": 11518260,
        //                 "currency": "BTC",
        //                 "address": "8JoDXAmE1GY2LRK8jD1gmAmgRPq54kXJ4t",
        //                 "amount": "0.20000000",
        //                 "fee": "0.00050000",
        //                 "timestamp": 1527918155,
        //                 "status": "COMPLETE: 1864f4ebb277d90b0b1ff53259b36b97fa1990edc7ad2be47c5e0ab41916b5ff",
        //                 "ipAddress": "x.x.x.x"
        //             }
        //         ]
        //     }
        //
        return response;
    }
    /**
     * @method
     * @name poloniex#fetchDepositsWithdrawals
     * @description fetch history of deposits and withdrawals
     * @see https://api-docs.poloniex.com/spot/api/private/wallet#wallets-activity-records
     * @param {string} [code] unified currency code for the currency of the deposit/withdrawals, default is undefined
     * @param {int} [since] timestamp in ms of the earliest deposit/withdrawal, default is undefined
     * @param {int} [limit] max number of deposit/withdrawals to return, default is undefined
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @returns {object} a list of [transaction structure]{@link https://docs.ccxt.com/#/?id=transaction-structure}
     */
    async fetchDepositsWithdrawals(code = undefined, since = undefined, limit = undefined, params = {}) {
        await this.loadMarkets();
        const response = await this.fetchTransactionsHelper(code, since, limit, params);
        let currency = undefined;
        if (code !== undefined) {
            currency = this.currency(code);
        }
        const withdrawals = this.safeValue(response, 'withdrawals', []);
        const deposits = this.safeValue(response, 'deposits', []);
        const withdrawalTransactions = this.parseTransactions(withdrawals, currency, since, limit);
        const depositTransactions = this.parseTransactions(deposits, currency, since, limit);
        const transactions = this.arrayConcat(depositTransactions, withdrawalTransactions);
        return this.filterByCurrencySinceLimit(this.sortBy(transactions, 'timestamp'), code, since, limit);
    }
    /**
     * @method
     * @name poloniex#fetchWithdrawals
     * @description fetch all withdrawals made from an account
     * @see https://api-docs.poloniex.com/spot/api/private/wallet#wallets-activity-records
     * @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 = {}) {
        const response = await this.fetchTransactionsHelper(code, since, limit, params);
        let currency = undefined;
        if (code !== undefined) {
            currency = this.currency(code);
        }
        const withdrawals = this.safeValue(response, 'withdrawals', []);
        const transactions = this.parseTransactions(withdrawals, currency, since, limit);
        return this.filterByCurrencySinceLimit(transactions, code, since, limit);
    }
    /**
     * @method
     * @name poloniex#fetchDepositWithdrawFees
     * @description fetch deposit and withdraw fees
     * @see https://api-docs.poloniex.com/spot/api/public/reference-data#currency-information
     * @param {string[]|undefined} codes list of unified currency codes
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @returns {object[]} a list of [fees structures]{@link https://docs.ccxt.com/#/?id=fee-structure}
     */
    async fetchDepositWithdrawFees(codes = undefined, params = {}) {
        await this.loadMarkets();
        const response = await this.publicGetCurrencies(this.extend(params, { 'includeMultiChainCurrencies': true }));
        //
        //     [
        //         {
        //             "1CR": {
        //                 "id": 1,
        //                 "name": "1CRedit",
        //                 "description": "BTC Clone",
        //                 "type": "address",
        //                 "withdrawalFee": "0.01000000",
        //                 "minConf": 10000,
        //                 "depositAddress": null,
        //                 "blockchain": "1CR",
        //                 "delisted": false,
        //                 "tradingState": "NORMAL",
        //                 "walletState": "DISABLED",
        //                 "parentChain": null,
        //                 "isMultiChain": false,
        //                 "isChildChain": false,
        //                 "childChains": []
        //             }
        //         }
        //     ]
        //
        const data = {};
        for (let i = 0; i < response.length; i++) {
            const entry = response[i];
            const currencies = Object.keys(entry);
            const currencyId = this.safeString(currencies, 0);
            data[currencyId] = entry[currencyId];
        }
        return this.parseDepositWithdrawFees(data, codes);
    }
    parseDepositWithdrawFees(response, codes = undefined, currencyIdKey = undefined) {
        //
        //         {
        //             "1CR": {
        //                 "id": 1,
        //                 "name": "1CRedit",
        //                 "description": "BTC Clone",
        //                 "type": "address",
        //                 "withdrawalFee": "0.01000000",
        //                 "minConf": 10000,
        //                 "depositAddress": null,
        //                 "blockchain": "1CR",
        //                 "delisted": false,
        //                 "tradingState": "NORMAL",
        //                 "walletState": "DISABLED",
        //                 "parentChain": null,
        //                 "isMultiChain": false,
        //                 "isChildChain": false,
        //                 "childChains": []
        //             },
        //         }
        //
        const depositWithdrawFees = {};
        codes = this.marketCodes(codes);
        const responseKeys = Object.keys(response);
        for (let i = 0; i < responseKeys.length; i++) {
            const currencyId = responseKeys[i];
            const code = this.safeCurrencyCode(currencyId);
            const feeInfo = response[currencyId];
            if ((codes === undefined) || (this.inArray(code, codes))) {
                const currency = this.currency(code);
                depositWithdrawFees[code] = this.parseDepositWithdrawFee(feeInfo, currency);
                const childChains = this.safeValue(feeInfo, 'childChains');
                const chainsLength = childChains.length;
                if (chainsLength > 0) {
                    for (let j = 0; j < childChains.length; j++) {
                        let networkId = childChains[j];
                        networkId = networkId.replace(code, '');
                        const networkCode = this.networkIdToCode(networkId);
                        const networkInfo = this.safeValue(response, networkId);
                        const networkObject = {};
                        const withdrawFee = this.safeNumber(networkInfo, 'withdrawalFee');
                        networkObject[networkCode] = {
                            'withdraw': {
                                'fee': withdrawFee,
                                'percentage': (withdrawFee !== undefined) ? false : undefined,
                            },
                            'deposit': {
                                'fee': undefined,
                                'percentage': undefined,
                            },
                        };
                        depositWithdrawFees[code]['networks'] = this.extend(depositWithdrawFees[code]['networks'], networkObject);
                    }
                }
            }
        }
        return depositWithdrawFees;
    }
    parseDepositWithdrawFee(fee, currency = undefined) {
        const depositWithdrawFee = this.depositWithdrawFee({});
        depositWithdrawFee['info'][currency['code']] = fee;
        const networkId = this.safeString(fee, 'blockchain');
        const withdrawFee = this.safeNumber(fee, 'withdrawalFee');
        const withdrawResult = {
            'fee': withdrawFee,
            'percentage': (withdrawFee !== undefined) ? false : undefined,
        };
        const depositResult = {
            'fee': undefined,
            'percentage': undefined,
        };
        depositWithdrawFee['withdraw'] = withdrawResult;
        depositWithdrawFee['deposit'] = depositResult;
        const networkCode = this.networkIdToCode(networkId);
        depositWithdrawFee['networks'][networkCode] = {
            'withdraw': withdrawResult,
            'deposit': depositResult,
        };
        return depositWithdrawFee;
    }
    /**
     * @method
     * @name poloniex#fetchDeposits
     * @description fetch all deposits made to an account
     * @see https://api-docs.poloniex.com/spot/api/private/wallet#wallets-activity-records
     * @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 = {}) {
        const response = await this.fetchTransactionsHelper(code, since, limit, params);
        let currency = undefined;
        if (code !== undefined) {
            currency = this.currency(code);
        }
        const deposits = this.safeValue(response, 'deposits', []);
        const transactions = this.parseTransactions(deposits, currency, since, limit);
        return this.filterByCurrencySinceLimit(transactions, code, since, limit);
    }
    parseTransactionStatus(status) {
        const statuses = {
            'COMPLETE': 'ok',
            'COMPLETED': 'ok',
            'AWAITING APPROVAL': 'pending',
            'AWAITING_APPROVAL': 'pending',
            'PENDING': 'pending',
            'PROCESSING': 'pending',
            'COMPLETE ERROR': 'failed',
            'COMPLETE_ERROR': 'failed',
        };
        return this.safeString(statuses, status, status);
    }
    parseTransaction(transaction, currency = undefined) {
        //
        // deposits
        //
        //     {
        //         "txid": "f49d489616911db44b740612d19464521179c76ebe9021af85b6de1e2f8d68cd",
        //         "amount": "49798.01987021",
        //         "status": "COMPLETE",
        //         "address": "DJVJZ58tJC8UeUv9Tqcdtn6uhWobouxFLT",
        //         "currency": "DOGE",
        //         "timestamp": 1524321838,
        //         "confirmations": 3371,
        //         "depositNumber": 134587098
        //     }
        //
        // withdrawals
        //
        //     {
        //         "withdrawalRequestsId": 7397527,
        //         "currency": "ETC",
        //         "address": "0x26419a62055af459d2cd69bb7392f5100b75e304",
        //         "amount": "13.19951600",
        //         "fee": "0.01000000",
        //         "timestamp": 1506010932,
        //         "status": "COMPLETED",
        //         "txid": "343346392f82ac16e8c2604f2a604b7b2382d0e9d8030f673821f8de4b5f5bk",
        //         "ipAddress": "1.2.3.4",
        //         "paymentID": null
        //     }
        //
        // withdraw
        //
        //     {
        //         "withdrawalRequestsId": 33485231
        //     }
        //
        // if it's being parsed from "withdraw()" method, get the original response
        if ('withdrawNetworkEntry' in transaction) {
            transaction = transaction['response'];
        }
        const timestamp = this.safeTimestamp(transaction, 'timestamp');
        const currencyId = this.safeString(transaction, 'currency');
        const code = this.safeCurrencyCode(currencyId);
        let status = this.safeString(transaction, 'status', 'pending');
        status = this.parseTransactionStatus(status);
        const txid = this.safeString(transaction, 'txid');
        const type = ('withdrawalRequestsId' in transaction) ? 'withdrawal' : 'deposit';
        const id = this.safeString2(transaction, 'withdrawalRequestsId', 'depositNumber');
        const address = this.safeString(transaction, 'address');
        const tag = this.safeString(transaction, 'paymentID');
        let amountString = this.safeString(transaction, 'amount');
        const feeCostString = this.safeString(transaction, 'fee');
        if (type === 'withdrawal') {
            amountString = Precise.stringSub(amountString, feeCostString);
        }
        return {
            'info': transaction,
            'id': id,
            'currency': code,
            'amount': this.parseNumber(amountString),
            'network': undefined,
            'address': address,
            'addressTo': undefined,
            'addressFrom': undefined,
            'tag': tag,
            'tagTo': undefined,
            'tagFrom': undefined,
            'status': status,
            'type': type,
            'updated': undefined,
            'txid': txid,
            'timestamp': timestamp,
            'datetime': this.iso8601(timestamp),
            'comment': undefined,
            'internal': undefined,
            'fee': {
                'currency': code,
                'cost': this.parseNumber(feeCostString),
                'rate': undefined,
            },
        };
    }
    /**
     * @method
     * @name poloniex#setLeverage
     * @description set the level of leverage for a market
     * @see https://api-docs.poloniex.com/v3/futures/api/positions/set-leverage
     * @param {int} leverage the rate of leverage
     * @param {string} symbol unified market symbol
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @param {string} [params.marginMode] 'cross' or 'isolated'
     * @returns {object} response from the exchange
     */
    async setLeverage(leverage, symbol = undefined, params = {}) {
        if (symbol === undefined) {
            throw new ArgumentsRequired(this.id + ' setLeverage() requires a symbol argument');
        }
        await this.loadMarkets();
        const market = this.market(symbol);
        let marginMode = undefined;
        [marginMode, params] = this.handleMarginModeAndParams('setLeverage', params);
        if (marginMode === undefined) {
            throw new ArgumentsRequired(this.id + ' setLeverage() requires a marginMode parameter "cross" or "isolated"');
        }
        let hedged = undefined;
        [hedged, params] = this.handleParamBool(params, 'hedged', false);
        if (hedged) {
            if (!('posSide' in params)) {
                throw new ArgumentsRequired(this.id + ' setLeverage() requires a posSide parameter for hedged mode: "LONG" or "SHORT"');
            }
        }
        const request = {
            'lever': leverage,
            'mgnMode': marginMode.toUpperCase(),
            'symbol': market['id'],
        };
        const response = await this.swapPrivatePostV3PositionLeverage(this.extend(request, params));
        return response;
    }
    /**
     * @method
     * @name poloniex#fetchLeverage
     * @description fetch the set leverage for a market
     * @see https://api-docs.poloniex.com/v3/futures/api/positions/get-leverages
     * @param {string} symbol unified market symbol
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @returns {object} a [leverage structure]{@link https://docs.ccxt.com/#/?id=leverage-structure}
     */
    async fetchLeverage(symbol, params = {}) {
        await this.loadMarkets();
        const market = this.market(symbol);
        const request = {
            'symbol': market['id'],
        };
        let marginMode = undefined;
        [marginMode, params] = this.handleMarginModeAndParams('fetchLeverage', params);
        if (marginMode === undefined) {
            throw new ArgumentsRequired(this.id + ' fetchLeverage() requires a marginMode parameter "cross" or "isolated"');
        }
        request['mgnMode'] = marginMode.toUpperCase();
        const response = await this.swapPrivateGetV3PositionLeverages(this.extend(request, params));
        //
        //  for one-way mode:
        //
        //    {
        //        "code": "200",
        //        "msg": "",
        //        "data": [
        //            {
        //                "symbol": "BTC_USDT_PERP",
        //                "lever": "10",
        //                "mgnMode": "CROSS",
        //                "posSide": "BOTH"
        //            }
        //        ]
        //    }
        //
        //  for hedge:
        //
        //    {
        //        "code": "200",
        //        "msg": "",
        //        "data": [
        //            {
        //                "symbol": "BTC_USDT_PERP",
        //                "lever": "20",
        //                "mgnMode": "CROSS",
        //                "posSide": "SHORT"
        //            },
        //            {
        //                "symbol": "BTC_USDT_PERP",
        //                "lever": "20",
        //                "mgnMode": "CROSS",
        //                "posSide": "LONG"
        //            }
        //        ]
        //    }
        //
        return this.parseLeverage(response, market);
    }
    parseLeverage(leverage, market = undefined) {
        let shortLeverage = undefined;
        let longLeverage = undefined;
        let marketId = undefined;
        let marginMode = undefined;
        const data = this.safeList(leverage, 'data');
        for (let i = 0; i < data.length; i++) {
            const entry = data[i];
            marketId = this.safeString(entry, 'symbol');
            marginMode = this.safeString(entry, 'mgnMode');
            const lever = this.safeInteger(entry, 'lever');
            const posSide = this.safeString(entry, 'posSide');
            if (posSide === 'LONG') {
                longLeverage = lever;
            }
            else if (posSide === 'SHORT') {
                shortLeverage = lever;
            }
            else {
                longLeverage = lever;
                shortLeverage = lever;
            }
        }
        return {
            'info': leverage,
            'symbol': this.safeSymbol(marketId, market),
            'marginMode': marginMode,
            'longLeverage': longLeverage,
            'shortLeverage': shortLeverage,
        };
    }
    /**
     * @method
     * @name poloniex#fetchPositionMode
     * @description fetchs the position mode, hedged or one way, hedged for binance is set identically for all linear markets or all inverse markets
     * @see https://api-docs.poloniex.com/v3/futures/api/positions/position-mode-switch
     * @param {string} symbol unified symbol of the market to fetch the order book for
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @returns {object} an object detailing whether the market is in hedged or one-way mode
     */
    async fetchPositionMode(symbol = undefined, params = {}) {
        const response = await this.swapPrivateGetV3PositionMode(params);
        //
        //    {
        //        "code": "200",
        //        "msg": "Success",
        //        "data": {
        //            "posMode": "ONE_WAY"
        //        }
        //    }
        //
        const data = this.safeDict(response, 'data', {});
        const posMode = this.safeString(data, 'posMode');
        const hedged = posMode === 'HEDGE';
        return {
            'info': response,
            'hedged': hedged,
        };
    }
    /**
     * @method
     * @name poloniex#setPositionMode
     * @description set hedged to true or false for a market
     * @see https://api-docs.poloniex.com/v3/futures/api/positions/position-mode-switch
     * @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 = {}) {
        const mode = hedged ? 'HEDGE' : 'ONE_WAY';
        const request = {
            'posMode': mode,
        };
        const response = await this.swapPrivatePostV3PositionMode(this.extend(request, params));
        //
        //    {
        //        "code": "200",
        //        "msg": "Success",
        //        "data": {}
        //    }
        //
        return response;
    }
    /**
     * @method
     * @name poloniex#fetchPositions
     * @description fetch all open positions
     * @see https://api-docs.poloniex.com/v3/futures/api/positions/get-current-position
     * @param {string[]|undefined} symbols list of unified market symbols
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @param {boolean} [params.standard] whether to fetch standard contract positions
     * @returns {object[]} a list of [position structures]{@link https://docs.ccxt.com/#/?id=position-structure}
     */
    async fetchPositions(symbols = undefined, params = {}) {
        await this.loadMarkets();
        symbols = this.marketSymbols(symbols);
        const response = await this.swapPrivateGetV3TradePositionOpens(params);
        //
        //    {
        //        "code": "200",
        //        "msg": "",
        //        "data": [
        //            {
        //                "symbol": "BTC_USDT_PERP",
        //                "posSide": "LONG",
        //                "side": "BUY",
        //                "mgnMode": "CROSS",
        //                "openAvgPx": "94193.42",
        //                "qty": "1",
        //                "availQty": "1",
        //                "lever": "20",
        //                "adl": "0.3007",
        //                "liqPx": "84918.201844064386317906",
        //                "im": "4.7047795",
        //                "mm": "0.56457354",
        //                "upl": "-0.09783",
        //                "uplRatio": "-0.0207",
        //                "pnl": "0",
        //                "markPx": "94095.59",
        //                "mgnRatio": "0.0582",
        //                "state": "NORMAL",
        //                "cTime": "1740950344401",
        //                "uTime": "1740950344401",
        //                "mgn": "4.7047795",
        //                "actType": "TRADING",
        //                "maxWAmt": "0",
        //                "tpTrgPx": "",
        //                "slTrgPx": ""
        //            }
        //        ]
        //    }
        //
        const positions = this.safeList(response, 'data', []);
        return this.parsePositions(positions, symbols);
    }
    parsePosition(position, market = undefined) {
        //
        //            {
        //                "symbol": "BTC_USDT_PERP",
        //                "posSide": "LONG",
        //                "side": "BUY",
        //                "mgnMode": "CROSS",
        //                "openAvgPx": "94193.42",
        //                "qty": "1",
        //                "availQty": "1",
        //                "lever": "20",
        //                "adl": "0.3007",
        //                "liqPx": "84918.201844064386317906",
        //                "im": "4.7047795",
        //                "mm": "0.56457354",
        //                "upl": "-0.09783",
        //                "uplRatio": "-0.0207",
        //                "pnl": "0",
        //                "markPx": "94095.59",
        //                "mgnRatio": "0.0582",
        //                "state": "NORMAL",
        //                "cTime": "1740950344401",
        //                "uTime": "1740950344401",
        //                "mgn": "4.7047795",
        //                "actType": "TRADING",
        //                "maxWAmt": "0",
        //                "tpTrgPx": "",
        //                "slTrgPx": ""
        //            }
        //
        const marketId = this.safeString(position, 'symbol');
        market = this.safeMarket(marketId, market);
        const timestamp = this.safeInteger(position, 'cTime');
        const marginMode = this.safeStringLower(position, 'mgnMode');
        const leverage = this.safeString(position, 'lever');
        const initialMargin = this.safeString(position, 'im');
        const notional = Precise.stringMul(leverage, initialMargin);
        const qty = this.safeString(position, 'qty');
        const avgPrice = this.safeString(position, 'openAvgPx');
        const collateral = Precise.stringMul(qty, avgPrice);
        // todo: some more fields
        return this.safePosition({
            'info': position,
            'id': undefined,
            'symbol': market['symbol'],
            'notional': notional,
            'marginMode': marginMode,
            'liquidationPrice': this.safeNumber(position, 'liqPx'),
            'entryPrice': this.safeNumber(position, 'openAvgPx'),
            'unrealizedPnl': this.safeNumber(position, 'upl'),
            'percentage': undefined,
            'contracts': this.safeNumber(position, 'qty'),
            'contractSize': undefined,
            'markPrice': this.safeNumber(position, 'markPx'),
            'lastPrice': undefined,
            'side': this.safeStringLower(position, 'posSide'),
            'hedged': undefined,
            'timestamp': timestamp,
            'datetime': this.iso8601(timestamp),
            'lastUpdateTimestamp': undefined,
            'maintenanceMargin': this.safeNumber(position, 'mm'),
            'maintenanceMarginPercentage': undefined,
            'collateral': collateral,
            'initialMargin': initialMargin,
            'initialMarginPercentage': undefined,
            'leverage': parseInt(leverage),
            'marginRatio': this.safeNumber(position, 'mgnRatio'),
            'stopLossPrice': this.safeNumber(position, 'slTrgPx'),
            'takeProfitPrice': this.safeNumber(position, 'tpTrgPx'),
        });
    }
    async modifyMarginHelper(symbol, amount, type, params = {}) {
        await this.loadMarkets();
        const market = this.market(symbol);
        amount = this.amountToPrecision(symbol, amount);
        const request = {
            'symbol': market['id'],
            'amt': Precise.stringAbs(amount),
            'type': type.toUpperCase(), // 'ADD' or 'REDUCE'
        };
        // todo: hedged handling, tricky
        if (!('posMode' in params)) {
            request['posMode'] = 'BOTH';
        }
        const response = await this.swapPrivatePostV3TradePositionMargin(this.extend(request, params));
        //
        // {
        //     "code": 200,
        //     "data": {
        //       "amt": "50",
        //       "lever": "20",
        //       "symbol": "DOT_USDT_PERP",
        //       "posSide": "BOTH",
        //       "type": "ADD"
        //     },
        //     "msg": "Success"
        // }
        //
        if (type === 'reduce') {
            amount = Precise.stringAbs(amount);
        }
        const data = this.safeDict(response, 'data');
        return this.parseMarginModification(data, market);
    }
    parseMarginModification(data, market = undefined) {
        const marketId = this.safeString(data, 'symbol');
        market = this.safeMarket(marketId, market);
        const rawType = this.safeString(data, 'type');
        const type = (rawType === 'ADD') ? 'add' : 'reduce';
        return {
            'info': data,
            'symbol': market['symbol'],
            'type': type,
            'marginMode': undefined,
            'amount': this.safeNumber(data, 'amt'),
            'total': undefined,
            'code': undefined,
            'status': 'ok',
            'timestamp': undefined,
            'datetime': undefined,
        };
    }
    /**
     * @method
     * @name poloniex#reduceMargin
     * @description remove margin from a position
     * @param {string} symbol unified market symbol
     * @param {float} amount the amount of margin to remove
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @returns {object} a [margin structure]{@link https://docs.ccxt.com/#/?id=reduce-margin-structure}
     */
    async reduceMargin(symbol, amount, params = {}) {
        return await this.modifyMarginHelper(symbol, -amount, 'reduce', params);
    }
    /**
     * @method
     * @name poloniex#addMargin
     * @description add margin
     * @param {string} symbol unified market symbol
     * @param {float} amount amount of margin to add
     * @param {object} [params] extra parameters specific to the exchange API endpoint
     * @returns {object} a [margin structure]{@link https://docs.ccxt.com/#/?id=add-margin-structure}
     */
    async addMargin(symbol, amount, params = {}) {
        return await this.modifyMarginHelper(symbol, amount, 'add', params);
    }
    nonce() {
        return this.milliseconds();
    }
    sign(path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
        let url = this.urls['api']['spot'];
        if (this.inArray(api, ['swapPublic', 'swapPrivate'])) {
            url = this.urls['api']['swap'];
        }
        const query = this.omit(params, this.extractParams(path));
        const implodedPath = this.implodeParams(path, params);
        if (api === 'public' || api === 'swapPublic') {
            url += '/' + implodedPath;
            if (Object.keys(query).length) {
                url += '?' + this.urlencode(query);
            }
        }
        else {
            this.checkRequiredCredentials();
            const timestamp = this.nonce().toString();
            let auth = method + "\n"; // eslint-disable-line quotes
            url += '/' + implodedPath;
            auth += '/' + implodedPath;
            if ((method === 'POST') || (method === 'PUT') || (method === 'DELETE')) {
                auth += "\n"; // eslint-disable-line quotes
                if (Object.keys(query).length) {
                    body = this.json(query);
                    auth += 'requestBody=' + body + '&';
                }
                auth += 'signTimestamp=' + timestamp;
            }
            else {
                let sortedQuery = this.extend({ 'signTimestamp': timestamp }, query);
                sortedQuery = this.keysort(sortedQuery);
                auth += "\n" + this.urlencode(sortedQuery); // eslint-disable-line quotes
                if (Object.keys(query).length) {
                    url += '?' + this.urlencode(query);
                }
            }
            const signature = this.hmac(this.encode(auth), this.encode(this.secret), sha256, 'base64');
            headers = {
                'Content-Type': 'application/json',
                'key': this.apiKey,
                'signTimestamp': timestamp,
                'signature': signature,
            };
        }
        return { 'url': url, 'method': method, 'body': body, 'headers': headers };
    }
    handleErrors(code, reason, url, method, headers, body, response, requestHeaders, requestBody) {
        if (response === undefined) {
            return undefined;
        }
        //
        //     {
        //         "code" : 21709,
        //         "message" : "Low available balance"
        //     }
        //
        const responseCode = this.safeString(response, 'code');
        if ((responseCode !== undefined) && (responseCode !== '200')) {
            const codeInner = response['code'];
            const message = this.safeString(response, 'message');
            const feedback = this.id + ' ' + body;
            this.throwExactlyMatchedException(this.exceptions['exact'], codeInner, feedback);
            this.throwBroadlyMatchedException(this.exceptions['broad'], message, feedback);
            throw new ExchangeError(feedback); // unknown message
        }
        return undefined;
    }
}