# -*- coding: utf-8 -*-

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

from ccxt_zagrava.base.exchange import Exchange
from ccxt_zagrava.abstract.krakenfutures import ImplicitAPI
import hashlib
from ccxt_zagrava.base.types import Balances, Currency, Int, Leverage, Leverages, LeverageTier, LeverageTiers, Market, Num, Order, OrderBook, OrderRequest, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade, TransferEntry
from typing import List
from ccxt_zagrava.base.errors import ExchangeError
from ccxt_zagrava.base.errors import AuthenticationError
from ccxt_zagrava.base.errors import ArgumentsRequired
from ccxt_zagrava.base.errors import BadRequest
from ccxt_zagrava.base.errors import InsufficientFunds
from ccxt_zagrava.base.errors import InvalidOrder
from ccxt_zagrava.base.errors import OrderNotFound
from ccxt_zagrava.base.errors import OrderImmediatelyFillable
from ccxt_zagrava.base.errors import OrderNotFillable
from ccxt_zagrava.base.errors import DuplicateOrderId
from ccxt_zagrava.base.errors import ContractUnavailable
from ccxt_zagrava.base.errors import DDoSProtection
from ccxt_zagrava.base.errors import RateLimitExceeded
from ccxt_zagrava.base.errors import ExchangeNotAvailable
from ccxt_zagrava.base.errors import InvalidNonce
from ccxt_zagrava.base.decimal_to_precision import TICK_SIZE
from ccxt_zagrava.base.precise import Precise


class krakenfutures(Exchange, ImplicitAPI):

    def describe(self):
        return self.deep_extend(super(krakenfutures, self).describe(), {
            'id': 'krakenfutures',
            'name': 'Kraken Futures',
            'countries': ['US'],
            'version': 'v3',
            'userAgent': None,
            'rateLimit': 600,
            'pro': True,
            'has': {
                'CORS': None,
                'spot': False,
                'margin': False,
                'swap': True,
                'future': True,
                'option': False,
                'cancelAllOrders': True,
                'cancelAllOrdersAfter': True,
                'cancelOrder': True,
                'cancelOrders': True,
                'createMarketOrder': False,
                'createOrder': True,
                'editOrder': True,
                'fetchBalance': True,
                'fetchBorrowRateHistories': False,
                'fetchBorrowRateHistory': False,
                'fetchCanceledOrders': True,
                'fetchClosedOrders': True,  # https://support.kraken.com/hc/en-us/articles/360058243651-Historical-orders
                'fetchCrossBorrowRate': False,
                'fetchCrossBorrowRates': False,
                'fetchDepositAddress': False,
                'fetchDepositAddresses': False,
                'fetchDepositAddressesByNetwork': False,
                'fetchFundingHistory': None,
                'fetchFundingRate': 'emulated',
                'fetchFundingRateHistory': True,
                'fetchFundingRates': True,
                'fetchIndexOHLCV': False,
                'fetchIsolatedBorrowRate': False,
                'fetchIsolatedBorrowRates': False,
                'fetchIsolatedPositions': False,
                'fetchLeverage': True,
                'fetchLeverages': True,
                'fetchLeverageTiers': True,
                'fetchMarketLeverageTiers': 'emulated',
                'fetchMarkets': True,
                'fetchMarkOHLCV': True,
                'fetchMyTrades': True,
                'fetchOHLCV': True,
                'fetchOpenOrders': True,
                'fetchOrder': False,
                'fetchOrderBook': True,
                'fetchOrders': False,
                'fetchPositions': True,
                'fetchPremiumIndexOHLCV': False,
                'fetchTickers': True,
                'fetchTrades': True,
                'sandbox': True,
                'setLeverage': True,
                'setMarginMode': False,
                'transfer': True,
            },
            'urls': {
                'test': {
                    'public': 'https://demo-futures.kraken.com/derivatives/api/',
                    'private': 'https://demo-futures.kraken.com/derivatives/api/',
                    'charts': 'https://demo-futures.kraken.com/api/charts/',
                    'history': 'https://demo-futures.kraken.com/api/history/',
                    'www': 'https://demo-futures.kraken.com',
                },
                'logo': 'https://user-images.githubusercontent.com/24300605/81436764-b22fd580-9172-11ea-9703-742783e6376d.jpg',
                'api': {
                    'charts': 'https://futures.kraken.com/api/charts/',
                    'history': 'https://futures.kraken.com/api/history/',
                    'feeschedules': 'https://futures.kraken.com/api/feeschedules/',
                    'public': 'https://futures.kraken.com/derivatives/api/',
                    'private': 'https://futures.kraken.com/derivatives/api/',
                },
                'www': 'https://futures.kraken.com/',
                'doc': [
                    'https://docs.futures.kraken.com/#introduction',
                ],
                'fees': 'https://support.kraken.com/hc/en-us/articles/360022835771-Transaction-fees-and-rebates-for-Kraken-Futures',
                'referral': None,
            },
            'api': {
                'public': {
                    'get': [
                        'feeschedules',
                        'instruments',
                        'orderbook',
                        'tickers',
                        'history',
                        'historicalfundingrates',
                    ],
                },
                'private': {
                    'get': [
                        'feeschedules/volumes',
                        'openpositions',
                        'notifications',
                        'accounts',
                        'openorders',
                        'recentorders',
                        'fills',
                        'transfers',
                        'leveragepreferences',
                        'pnlpreferences',
                        'assignmentprogram/current',
                        'assignmentprogram/history',
                    ],
                    'post': [
                        'sendorder',
                        'editorder',
                        'cancelorder',
                        'transfer',
                        'batchorder',
                        'cancelallorders',
                        'cancelallordersafter',
                        'withdrawal',                              # for futures wallet -> kraken spot wallet
                        'assignmentprogram/add',
                        'assignmentprogram/delete',
                    ],
                    'put': [
                        'leveragepreferences',
                        'pnlpreferences',
                    ],
                },
                'charts': {
                    'get': [
                        '{price_type}/{symbol}/{interval}',
                    ],
                },
                'history': {
                    'get': [
                        'orders',
                        'executions',
                        'triggers',
                        'accountlogcsv',
                        'account-log',
                        'market/{symbol}/orders',
                        'market/{symbol}/executions',
                    ],
                },
            },
            'fees': {
                'trading': {
                    'tierBased': True,
                    'percentage': True,
                    'taker': self.parse_number('0.0005'),
                    'maker': self.parse_number('0.0002'),
                    'tiers': {
                        'taker': [
                            [self.parse_number('0'), self.parse_number('0.0005')],
                            [self.parse_number('100000'), self.parse_number('0.0004')],
                            [self.parse_number('1000000'), self.parse_number('0.0003')],
                            [self.parse_number('5000000'), self.parse_number('0.00025')],
                            [self.parse_number('10000000'), self.parse_number('0.0002')],
                            [self.parse_number('20000000'), self.parse_number('0.00015')],
                            [self.parse_number('50000000'), self.parse_number('0.000125')],
                            [self.parse_number('100000000'), self.parse_number('0.0001')],
                        ],
                        'maker': [
                            [self.parse_number('0'), self.parse_number('0.0002')],
                            [self.parse_number('100000'), self.parse_number('0.0015')],
                            [self.parse_number('1000000'), self.parse_number('0.000125')],
                            [self.parse_number('5000000'), self.parse_number('0.0001')],
                            [self.parse_number('10000000'), self.parse_number('0.000075')],
                            [self.parse_number('20000000'), self.parse_number('0.00005')],
                            [self.parse_number('50000000'), self.parse_number('0.000025')],
                            [self.parse_number('100000000'), self.parse_number('0')],
                        ],
                    },
                },
            },
            'exceptions': {
                'exact': {
                    'apiLimitExceeded': RateLimitExceeded,
                    'marketUnavailable': ContractUnavailable,
                    'requiredArgumentMissing': BadRequest,
                    'unavailable': ExchangeNotAvailable,
                    'authenticationError': AuthenticationError,
                    'accountInactive': ExchangeError,              # When account has no trade history / no order history. Should self error be ignored in some cases?
                    'invalidAccount': BadRequest,                  # the fromAccount or the toAccount are invalid
                    'invalidAmount': BadRequest,
                    'insufficientFunds': InsufficientFunds,
                    'Bad Request': BadRequest,                     # The URL contains invalid characters.(Please encode the json URL parameter)
                    'Unavailable': InsufficientFunds,              # Insufficient funds in Futures account [withdraw]
                    'invalidUnit': BadRequest,
                    'Json Parse Error': ExchangeError,
                    'nonceBelowThreshold': InvalidNonce,
                    'nonceDuplicate': InvalidNonce,
                    'notFound': BadRequest,
                    'Server Error': ExchangeError,
                    'unknownError': ExchangeError,
                },
                'broad': {
                    'invalidArgument': BadRequest,
                    'nonceBelowThreshold': InvalidNonce,
                    'nonceDuplicate': InvalidNonce,
                },
            },
            'precisionMode': TICK_SIZE,
            'options': {
                'access': {
                    'history': {
                        'GET': {
                            'orders': 'private',
                            'executions': 'private',
                            'triggers': 'private',
                            'accountlogcsv': 'private',
                        },
                    },
                },
                'settlementCurrencies': {
                    'flex': ['USDT', 'BTC', 'USD', 'GBP', 'EUR', 'USDC'],
                },
                'symbol': {
                    'quoteIds': ['USD', 'XBT'],
                    'reversed': False,
                },
                'versions': {
                    'public': {
                        'GET': {
                            'historicalfundingrates': 'v4',
                        },
                    },
                    'charts': {
                        'GET': {
                            '{price_type}/{symbol}/{interval}': 'v1',
                        },
                    },
                    'history': {
                        'GET': {
                            'orders': 'v2',
                            'executions': 'v2',
                            'triggers': 'v2',
                            'accountlogcsv': 'v2',
                        },
                    },
                },
                'fetchTrades': {
                    'method': 'historyGetMarketSymbolExecutions',  # historyGetMarketSymbolExecutions, publicGetHistory
                },
            },
            'timeframes': {
                '1m': '1m',
                '5m': '5m',
                '15m': '15m',
                '30m': '30m',
                '1h': '1h',
                '4h': '4h',
                '12h': '12h',
                '1d': '1d',
                '1w': '1w',
            },
        })

    def fetch_markets(self, params={}) -> List[Market]:
        """
        Fetches the available trading markets from the exchange, Multi-collateral markets are returned markets, but can be settled in multiple currencies
        :see: https://docs.futures.kraken.com/#http-api-trading-v3-api-instrument-details-get-instruments
        :param dict [params]: exchange specific params
        :returns: An array of market structures
        """
        response = self.publicGetInstruments(params)
        #
        #    {
        #        "result": "success",
        #        "instruments": [
        #            {
        #                "symbol": "fi_ethusd_180928",
        #                "type": "futures_inverse",  # futures_vanilla  # spot index
        #                "underlying": "rr_ethusd",
        #                "lastTradingTime": "2018-09-28T15:00:00.000Z",
        #                "tickSize": 0.1,
        #                "contractSize": 1,
        #                "tradeable": True,
        #                "marginLevels": [
        #                    {
        #                        "contracts":0,
        #                        "initialMargin":0.02,
        #                        "maintenanceMargin":0.01
        #                    },
        #                    {
        #                        "contracts":250000,
        #                        "initialMargin":0.04,
        #                        "maintenanceMargin":0.02
        #                    },
        #                    ...
        #                ],
        #                "isin": "GB00JVMLMP88",
        #                "retailMarginLevels": [
        #                    {
        #                        "contracts": 0,
        #                        "initialMargin": 0.5,
        #                        "maintenanceMargin": 0.25
        #                    }
        #                ],
        #                "tags": [],
        #            },
        #            {
        #                "symbol": "in_xbtusd",
        #                "type": "spot index",
        #                "tradeable":false
        #            }
        #        ]
        #        "serverTime": "2018-07-19T11:32:39.433Z"
        #    }
        #
        instruments = self.safe_value(response, 'instruments', [])
        result = []
        for i in range(0, len(instruments)):
            market = instruments[i]
            id = self.safe_string(market, 'symbol')
            marketType = self.safe_string(market, 'type')
            type = None
            index = (marketType.find(' index') >= 0)
            linear = None
            inverse = None
            expiry = None
            if not index:
                linear = (marketType.find('_vanilla') >= 0)
                inverse = not linear
                settleTime = self.safe_string(market, 'lastTradingTime')
                type = 'swap' if (settleTime is None) else 'future'
                expiry = self.parse8601(settleTime)
            else:
                type = 'index'
            swap = (type == 'swap')
            future = (type == 'future')
            symbol = id
            split = id.split('_')
            splitMarket = self.safe_string(split, 1)
            baseId = splitMarket[0:len(splitMarket) - 3]
            quoteId = 'usd'  # always USD
            base = self.safe_currency_code(baseId)
            quote = self.safe_currency_code(quoteId)
            # swap == perpetual
            settle = None
            settleId = None
            cvtp = self.safe_string(market, 'contractValueTradePrecision')
            amountPrecision = self.parse_number(self.integer_precision_to_amount(cvtp))
            pricePrecision = self.safe_number(market, 'tickSize')
            contract = (swap or future or index)
            swapOrFutures = (swap or future)
            if swapOrFutures:
                exchangeType = self.safe_string(market, 'type')
                if exchangeType == 'futures_inverse':
                    settle = base
                    settleId = baseId
                    inverse = True
                else:
                    settle = quote
                    settleId = quoteId
                    inverse = False
                linear = not inverse
                symbol = base + '/' + quote + ':' + settle
                if future:
                    symbol = symbol + '-' + self.yymmdd(expiry)
            result.append({
                'id': id,
                'symbol': symbol,
                'base': base,
                'quote': quote,
                'settle': settle,
                'baseId': baseId,
                'quoteId': quoteId,
                'settleId': settleId,
                'type': type,
                'spot': False,
                'margin': False,
                'swap': swap,
                'future': future,
                'option': False,
                'index': index,
                'active': None,
                'contract': contract,
                'linear': linear,
                'inverse': inverse,
                'contractSize': self.safe_number(market, 'contractSize'),
                'maintenanceMarginRate': None,
                'expiry': expiry,
                'expiryDatetime': self.iso8601(expiry),
                'strike': None,
                'optionType': None,
                'precision': {
                    'amount': amountPrecision,
                    'price': pricePrecision,
                },
                'limits': {
                    'leverage': {
                        'min': None,
                        'max': None,
                    },
                    'amount': {
                        'min': None,
                        'max': None,
                    },
                    'price': {
                        'min': None,
                        'max': None,
                    },
                    'cost': {
                        'min': None,
                        'max': None,
                    },
                },
                'created': self.parse8601(self.safe_string(market, 'openingDate')),
                'info': market,
            })
        settlementCurrencies = self.options['settlementCurrencies']['flex']
        currencies = []
        for i in range(0, len(settlementCurrencies)):
            code = settlementCurrencies[i]
            currencies.append({
                'id': code.lower(),
                'numericId': None,
                'code': code,
                'precision': None,
            })
        self.currencies = self.deep_extend(currencies, self.currencies)
        return result

    def fetch_order_book(self, symbol: str, limit: Int = None, params={}) -> OrderBook:
        """
        :see: https://docs.futures.kraken.com/#http-api-trading-v3-api-market-data-get-orderbook
        Fetches a list of open orders in a market
        :param str symbol: Unified market symbol
        :param int [limit]: Not used by krakenfutures
        :param dict [params]: exchange specific params
        :returns: An `order book structure <https://docs.ccxt_zagrava.com/#/?id=order-book-structure>`
        """
        self.load_markets()
        market = self.market(symbol)
        request: dict = {
            'symbol': market['id'],
        }
        response = self.publicGetOrderbook(self.extend(request, params))
        #
        #    {
        #       "result": "success",
        #       "serverTime": "2016-02-25T09:45:53.818Z",
        #       "orderBook": {
        #          "bids": [
        #                [
        #                    4213,
        #                    2000,
        #                ],
        #                [
        #                    4210,
        #                    4000,
        #                ],
        #                ...
        #            ],
        #            "asks": [
        #                [
        #                    4218,
        #                    4000,
        #                ],
        #                [
        #                    4220,
        #                    5000,
        #                ],
        #                ...
        #            ],
        #        },
        #    }
        #
        timestamp = self.parse8601(response['serverTime'])
        return self.parse_order_book(response['orderBook'], symbol, timestamp)

    def fetch_tickers(self, symbols: Strings = None, params={}) -> Tickers:
        """
        fetches price tickers for multiple markets, statistical information calculated over the past 24 hours for each market
        :see: https://docs.futures.kraken.com/#http-api-trading-v3-api-market-data-get-tickers
        :param str[] symbols: unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict: an array of `ticker structures <https://docs.ccxt_zagrava.com/#/?id=ticker-structure>`
        """
        self.load_markets()
        response = self.publicGetTickers(params)
        #
        #    {
        #        "result": "success",
        #        "tickers": [
        #            {
        #                "tag": 'semiannual',  # 'month', 'quarter', "perpetual", "semiannual",
        #                "pair": "ETH:USD",
        #                "symbol": "fi_ethusd_220624",
        #                "markPrice": "2925.72",
        #                "bid": "2923.8",
        #                "bidSize": "16804",
        #                "ask": "2928.65",
        #                "askSize": "1339",
        #                "vol24h": "860493",
        #                "openInterest": "3023363.00000000",
        #                "open24h": "3021.25",
        #                "indexPrice": "2893.71",
        #                "last": "2942.25",
        #                "lastTime": "2022-02-18T14:08:15.578Z",
        #                "lastSize": "151",
        #                "suspended": False
        #            },
        #            {
        #                "symbol": "in_xbtusd",  # "rr_xbtusd",
        #                "last": "40411",
        #                "lastTime": "2022-02-18T14:16:28.000Z"
        #            },
        #            ...
        #        ],
        #        "serverTime": "2022-02-18T14:16:29.440Z"
        #    }
        #
        tickers = self.safe_list(response, 'tickers')
        return self.parse_tickers(tickers, symbols)

    def parse_ticker(self, ticker: dict, market: Market = None) -> Ticker:
        #
        #    {
        #        "tag": 'semiannual',  # 'month', 'quarter', "perpetual", "semiannual",
        #        "pair": "ETH:USD",
        #        "symbol": "fi_ethusd_220624",
        #        "markPrice": "2925.72",
        #        "bid": "2923.8",
        #        "bidSize": "16804",
        #        "ask": "2928.65",
        #        "askSize": "1339",
        #        "vol24h": "860493",
        #        "openInterest": "3023363.00000000",
        #        "open24h": "3021.25",
        #        "indexPrice": "2893.71",
        #        "last": "2942.25",
        #        "lastTime": "2022-02-18T14:08:15.578Z",
        #        "lastSize": "151",
        #        "suspended": False
        #    }
        #
        #    {
        #        "symbol": "in_xbtusd",  # "rr_xbtusd",
        #        "last": "40411",
        #        "lastTime": "2022-02-18T14:16:28.000Z"
        #    }
        #
        marketId = self.safe_string(ticker, 'symbol')
        market = self.safe_market(marketId, market)
        symbol = market['symbol']
        timestamp = self.parse8601(self.safe_string(ticker, 'lastTime'))
        open = self.safe_string(ticker, 'open24h')
        last = self.safe_string(ticker, 'last')
        change = Precise.string_sub(last, open)
        percentage = Precise.string_mul(Precise.string_div(change, open), '100')
        average = Precise.string_div(Precise.string_add(open, last), '2')
        volume = self.safe_string(ticker, 'vol24h')
        baseVolume = None
        quoteVolume = None
        isIndex = self.safe_bool(market, 'index', False)
        if not isIndex:
            if market['linear']:
                baseVolume = volume
            elif market['inverse']:
                quoteVolume = volume
        return self.safe_ticker({
            'symbol': symbol,
            'timestamp': timestamp,
            'datetime': self.iso8601(timestamp),
            'high': None,
            'low': None,
            'bid': self.safe_string(ticker, 'bid'),
            'bidVolume': self.safe_string(ticker, 'bidSize'),
            'ask': self.safe_string(ticker, 'ask'),
            'askVolume': self.safe_string(ticker, 'askSize'),
            'vwap': None,
            'open': open,
            'close': last,
            'last': last,
            'previousClose': None,
            'change': change,
            'percentage': percentage,
            'average': average,
            'baseVolume': baseVolume,
            'quoteVolume': quoteVolume,
            'info': ticker,
        })

    def fetch_ohlcv(self, symbol: str, timeframe='1m', since: Int = None, limit: Int = None, params={}) -> List[list]:
        """
        :see: https://docs.futures.kraken.com/#http-api-charts-candles
        fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market
        :param str symbol: unified symbol of the market to fetch OHLCV data for
        :param str 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 dict [params]: extra parameters specific to the exchange API endpoint
        :param boolean [params.paginate]: default False, when True will automatically paginate by calling self endpoint multiple times. See in the docs all the [availble parameters](https://github.com/ccxt_zagrava/ccxt_zagrava/wiki/Manual#pagination-params)
        :returns int[][]: A list of candles ordered, open, high, low, close, volume
        """
        self.load_markets()
        market = self.market(symbol)
        paginate = False
        paginate, params = self.handle_option_and_params(params, 'fetchOHLCV', 'paginate')
        if paginate:
            return self.fetch_paginated_call_deterministic('fetchOHLCV', symbol, since, limit, timeframe, params, 5000)
        request: dict = {
            'symbol': market['id'],
            'price_type': self.safe_string(params, 'price', 'trade'),
            'interval': self.timeframes[timeframe],
        }
        params = self.omit(params, 'price')
        if since is not None:
            duration = self.parse_timeframe(timeframe)
            request['from'] = self.parse_to_int(since / 1000)
            if limit is None:
                limit = 5000
            limit = min(limit, 5000)
            toTimestamp = self.sum(request['from'], limit * duration - 1)
            currentTimestamp = self.seconds()
            request['to'] = min(toTimestamp, currentTimestamp)
        elif limit is not None:
            limit = min(limit, 5000)
            duration = self.parse_timeframe(timeframe)
            request['to'] = self.seconds()
            request['from'] = self.parse_to_int(request['to'] - (duration * limit))
        response = self.chartsGetPriceTypeSymbolInterval(self.extend(request, params))
        #
        #    {
        #        "candles": [
        #            {
        #                "time": 1645198500000,
        #                "open": "309.15000000000",
        #                "high": "309.15000000000",
        #                "low": "308.70000000000",
        #                "close": "308.85000000000",
        #                "volume": 0
        #            }
        #        ],
        #        "more_candles": True
        #    }
        #
        candles = self.safe_list(response, 'candles')
        return self.parse_ohlcvs(candles, market, timeframe, since, limit)

    def parse_ohlcv(self, ohlcv, market: Market = None) -> list:
        #
        #    {
        #        "time": 1645198500000,
        #        "open": "309.15000000000",
        #        "high": "309.15000000000",
        #        "low": "308.70000000000",
        #        "close": "308.85000000000",
        #        "volume": 0
        #    }
        #
        return [
            self.safe_integer(ohlcv, 'time'),       # unix timestamp in milliseconds
            self.safe_number(ohlcv, 'open'),        # open price
            self.safe_number(ohlcv, 'high'),        # highest price
            self.safe_number(ohlcv, 'low'),         # lowest price
            self.safe_number(ohlcv, 'close'),       # close price
            self.safe_number(ohlcv, 'volume'),      # trading volume, None for mark or index price
        ]

    def fetch_trades(self, symbol: str, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
        """
        :see: https://docs.futures.kraken.com/#http-api-trading-v3-api-market-data-get-trade-history
        :see: https://docs.futures.kraken.com/#http-api-history-market-history-get-public-execution-events
        Fetch a history of filled trades that self account has made
        :param str symbol: Unified ccxt_zagrava market symbol
        :param int [since]: Timestamp in ms of earliest trade. Not used by krakenfutures except in combination with params.until
        :param int [limit]: Total number of trades, cannot exceed 100
        :param dict [params]: Exchange specific params
        :param int [params.until]: Timestamp in ms of latest trade
        :param boolean [params.paginate]: default False, when True will automatically paginate by calling self endpoint multiple times. See in the docs all the [availble parameters](https://github.com/ccxt_zagrava/ccxt_zagrava/wiki/Manual#pagination-params)
        :param str [params.method]: The method to use to fetch trades. Can be 'historyGetMarketSymbolExecutions' or 'publicGetHistory' default is 'historyGetMarketSymbolExecutions'
        :returns: An array of `trade structures <https://docs.ccxt_zagrava.com/#/?id=trade-structure>`
        """
        self.load_markets()
        paginate = False
        paginate, params = self.handle_option_and_params(params, 'fetchTrades', 'paginate')
        if paginate:
            return self.fetch_paginated_call_dynamic('fetchTrades', symbol, since, limit, params)
        market = self.market(symbol)
        request: dict = {
            'symbol': market['id'],
        }
        method = None
        method, params = self.handle_option_and_params(params, 'fetchTrades', 'method', 'historyGetMarketSymbolExecutions')
        rawTrades = None
        isFullHistoryEndpoint = (method == 'historyGetMarketSymbolExecutions')
        if isFullHistoryEndpoint:
            request, params = self.handle_until_option('before', request, params)
            if since is not None:
                request['since'] = since
                request['sort'] = 'asc'
            if limit is not None:
                request['count'] = limit
            response = self.historyGetMarketSymbolExecutions(self.extend(request, params))
            #
            #    {
            #        "elements": [
            #            {
            #                "uid": "a5105030-f054-44cc-98ab-30d5cae96bef",
            #                "timestamp": "1710150778607",
            #                "event": {
            #                    "Execution": {
            #                        "execution": {
            #                            "uid": "2d485b71-cd28-4a1e-9364-371a127550d2",
            #                            "makerOrder": {
            #                                "uid": "0a25f66b-1109-49ec-93a3-d17bf9e9137e",
            #                                "tradeable": "PF_XBTUSD",
            #                                "direction": "Buy",
            #                                "quantity": "0.26500",
            #                                "timestamp": "1710150778570",
            #                                "limitPrice": "71907",
            #                                "orderType": "Post",
            #                                "reduceOnly": False,
            #                                "lastUpdateTimestamp": "1710150778570"
            #                            },
            #                            "takerOrder": {
            #                                "uid": "04de3ee0-9125-4960-bf8f-f63b577b6790",
            #                                "tradeable": "PF_XBTUSD",
            #                                "direction": "Sell",
            #                                "quantity": "0.0002",
            #                                "timestamp": "1710150778607",
            #                                "limitPrice": "71187.00",
            #                                "orderType": "Market",
            #                                "reduceOnly": False,
            #                                "lastUpdateTimestamp": "1710150778607"
            #                            },
            #                            "timestamp": "1710150778607",
            #                            "quantity": "0.0002",
            #                            "price": "71907",
            #                            "markPrice": "71903.32715463147",
            #                            "limitFilled": False,
            #                            "usdValue": "14.38"
            #                        },
            #                        "takerReducedQuantity": ""
            #                    }
            #                }
            #            },
            #            ... followed by older items
            #        ],
            #        "len": "1000",
            #        "continuationToken": "QTexMDE0OTe33NTcyXy8xNDIzAjc1NjY5MwI="
            #    }
            #
            elements = self.safe_list(response, 'elements', [])
            # we need to reverse the list to fix chronology
            rawTrades = []
            length = len(elements)
            for i in range(0, length):
                index = length - 1 - i
                element = elements[index]
                event = self.safe_dict(element, 'event', {})
                executionContainer = self.safe_dict(event, 'Execution', {})
                rawTrade = self.safe_dict(executionContainer, 'execution', {})
                rawTrades.append(rawTrade)
        else:
            request, params = self.handle_until_option('lastTime', request, params)
            response = self.publicGetHistory(self.extend(request, params))
            #
            #    {
            #        "result": "success",
            #        "history": [
            #            {
            #                "time": "2022-03-18T04:55:37.692Z",
            #                "trade_id": 100,
            #                "price": 0.7921,
            #                "size": 1068,
            #                "side": "sell",
            #                "type": "fill",
            #                "uid": "6c5da0b0-f1a8-483f-921f-466eb0388265"
            #            },
            #            ...
            #        ],
            #        "serverTime": "2022-03-18T06:39:18.056Z"
            #    }
            #
            rawTrades = self.safe_list(response, 'history', [])
        return self.parse_trades(rawTrades, market, since, limit)

    def parse_trade(self, trade: dict, market: Market = None) -> Trade:
        #
        # fetchTrades(recent trades)
        #
        #    {
        #        "time": "2019-02-14T09:25:33.920Z",
        #        "trade_id": 100,
        #        "price": 3574,
        #        "size": 100,
        #        "side": "buy",
        #        "type": "fill"  # fill, liquidation, assignment, termination
        #        "uid": "11c3d82c-9e70-4fe9-8115-f643f1b162d4"
        #    }
        #
        # fetchTrades(executions history)
        #
        #    {
        #        "timestamp": "1710152516830",
        #        "price": "71927.0",
        #        "quantity": "0.0695",
        #        "markPrice": "71936.38701675525",
        #        "limitFilled": True,
        #        "usdValue": "4998.93",
        #        "uid": "116ae634-253f-470b-bd20-fa9d429fb8b1",
        #        "makerOrder": {"uid": "17bfe4de-c01e-4938-926c-617d2a2d0597", "tradeable": "PF_XBTUSD", "direction": "Buy", "quantity": "0.0695", "timestamp": "1710152515836", "limitPrice": "71927.0", "orderType": "Post", "reduceOnly": False, "lastUpdateTimestamp": "1710152515836"},
        #        "takerOrder": {"uid": "d3e437b4-aa70-4108-b5cf-b1eecb9845b5", "tradeable": "PF_XBTUSD", "direction": "Sell", "quantity": "0.940100", "timestamp": "1710152516830", "limitPrice": "71915", "orderType": "IoC", "reduceOnly": False, "lastUpdateTimestamp": "1710152516830"}
        #    }
        #
        # fetchMyTrades(private)
        #
        #    {
        #        "fillTime": "2016-02-25T09:47:01.000Z",
        #        "order_id": "c18f0c17-9971-40e6-8e5b-10df05d422f0",
        #        "fill_id": "522d4e08-96e7-4b44-9694-bfaea8fe215e",
        #        "cliOrdId": "d427f920-ec55-4c18-ba95-5fe241513b30",     # OPTIONAL
        #        "symbol": "fi_xbtusd_180615",
        #        "side": "buy",
        #        "size": 2000,
        #        "price": 4255,
        #        "fillType": "maker"                                     # taker, takerAfterEdit, maker, liquidation, assignee
        #    }
        #
        # execution report(createOrder, editOrder)
        #
        #    {
        #        "executionId": "e1ec9f63-2338-4c44-b40a-43486c6732d7",
        #        "price": 7244.5,
        #        "amount": 10,
        #        "orderPriorEdit": null,
        #        "orderPriorExecution": {
        #            "orderId": "61ca5732-3478-42fe-8362-abbfd9465294",
        #            "cliOrdId": null,
        #            "type": "lmt",
        #            "symbol": "pi_xbtusd",
        #            "side": "buy",
        #            "quantity": 10,
        #            "filled": 0,
        #            "limitPrice": 7500,
        #            "reduceOnly": False,
        #            "timestamp": "2019-12-11T17:17:33.888Z",
        #            "lastUpdateTimestamp": "2019-12-11T17:17:33.888Z"
        #        },
        #        "takerReducedQuantity": null,
        #        "type": "EXECUTION"
        #    }
        #
        timestamp = self.parse8601(self.safe_string_2(trade, 'time', 'fillTime'))
        price = self.safe_string(trade, 'price')
        amount = self.safe_string_n(trade, ['size', 'amount', 'quantity'], '0.0')
        id = self.safe_string_2(trade, 'uid', 'fill_id')
        if id is None:
            id = self.safe_string(trade, 'executionId')
        order = self.safe_string(trade, 'order_id')
        marketId = self.safe_string(trade, 'symbol')
        side = self.safe_string(trade, 'side')
        type = None
        priorEdit = self.safe_value(trade, 'orderPriorEdit')
        priorExecution = self.safe_value(trade, 'orderPriorExecution')
        if priorExecution is not None:
            order = self.safe_string(priorExecution, 'orderId')
            marketId = self.safe_string(priorExecution, 'symbol')
            side = self.safe_string(priorExecution, 'side')
            type = self.safe_string(priorExecution, 'type')
        elif priorEdit is not None:
            order = self.safe_string(priorEdit, 'orderId')
            marketId = self.safe_string(priorEdit, 'symbol')
            side = self.safe_string(priorEdit, 'type')
            type = self.safe_string(priorEdit, 'type')
        if type is not None:
            type = self.parse_order_type(type)
        market = self.safe_market(marketId, market)
        cost = None
        linear = self.safe_bool(market, 'linear')
        if (amount is not None) and (price is not None) and (market is not None):
            if linear:
                cost = Precise.string_mul(amount, price)  # in quote
            else:
                cost = Precise.string_div(amount, price)  # in base
            contractSize = self.safe_string(market, 'contractSize')
            cost = Precise.string_mul(cost, contractSize)
        takerOrMaker = None
        fillType = self.safe_string(trade, 'fillType')
        if fillType is not None:
            if fillType.find('taker') >= 0:
                takerOrMaker = 'taker'
            elif fillType.find('maker') >= 0:
                takerOrMaker = 'maker'
        isHistoricalExecution = ('takerOrder' in trade)
        if isHistoricalExecution:
            timestamp = self.safe_integer(trade, 'timestamp')
            taker = self.safe_dict(trade, 'takerOrder', {})
            if taker is not None:
                side = self.safe_string_lower(taker, 'direction')
                takerOrMaker = 'taker'
        return self.safe_trade({
            'info': trade,
            'id': id,
            'symbol': self.safe_string(market, 'symbol'),
            'timestamp': timestamp,
            'datetime': self.iso8601(timestamp),
            'order': order,
            'type': type,
            'side': side,
            'takerOrMaker': takerOrMaker,
            'price': price,
            'amount': amount if linear else None,
            'cost': cost,
            'fee': None,
        })

    def create_order_request(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}):
        market = self.market(symbol)
        symbol = market['symbol']
        type = self.safe_string(params, 'orderType', type)
        timeInForce = self.safe_string(params, 'timeInForce')
        postOnly = False
        postOnly, params = self.handle_post_only(type == 'market', type == 'post', params)
        if postOnly:
            type = 'post'
        elif timeInForce == 'ioc':
            type = 'ioc'
        elif type == 'limit':
            type = 'lmt'
        elif type == 'market':
            type = 'mkt'
        request: dict = {
            'symbol': market['id'],
            'side': side,
            'size': self.amount_to_precision(symbol, amount),
        }
        clientOrderId = self.safe_string_2(params, 'clientOrderId', 'cliOrdId')
        if clientOrderId is not None:
            request['cliOrdId'] = clientOrderId
        triggerPrice = self.safe_string_2(params, 'triggerPrice', 'stopPrice')
        isTriggerOrder = triggerPrice is not None
        stopLossTriggerPrice = self.safe_string(params, 'stopLossPrice')
        takeProfitTriggerPrice = self.safe_string(params, 'takeProfitPrice')
        isStopLossTriggerOrder = stopLossTriggerPrice is not None
        isTakeProfitTriggerOrder = takeProfitTriggerPrice is not None
        isStopLossOrTakeProfitTrigger = isStopLossTriggerOrder or isTakeProfitTriggerOrder
        triggerSignal = self.safe_string(params, 'triggerSignal', 'last')
        reduceOnly = self.safe_value(params, 'reduceOnly')
        if isStopLossOrTakeProfitTrigger or isTriggerOrder:
            request['triggerSignal'] = triggerSignal
        if isTriggerOrder:
            type = 'stp'
            request['stopPrice'] = self.price_to_precision(symbol, triggerPrice)
        elif isStopLossOrTakeProfitTrigger:
            reduceOnly = True
            if isStopLossTriggerOrder:
                type = 'stp'
                request['stopPrice'] = self.price_to_precision(symbol, stopLossTriggerPrice)
            elif isTakeProfitTriggerOrder:
                type = 'take_profit'
                request['stopPrice'] = self.price_to_precision(symbol, takeProfitTriggerPrice)
        if reduceOnly:
            request['reduceOnly'] = True
        request['orderType'] = type
        if price is not None:
            request['limitPrice'] = self.price_to_precision(symbol, price)
        params = self.omit(params, ['clientOrderId', 'timeInForce', 'triggerPrice', 'stopLossPrice', 'takeProfitPrice'])
        return self.extend(request, params)

    def create_order(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}):
        """
        Create an order on the exchange
        :see: https://docs.futures.kraken.com/#http-api-trading-v3-api-order-management-send-order
        :param str symbol: unified market symbol
        :param str type: 'limit' or 'market'
        :param str side: 'buy' or 'sell'
        :param float amount: number of contracts
        :param float [price]: limit order price
        :param bool [params.reduceOnly]: set if you wish the order to only reduce an existing position, any order which increases an existing position will be rejected, default is False
        :param bool [params.postOnly]: set if you wish to make a postOnly order, default is False
        :param str [params.clientOrderId]: UUID The order identity that is specified from the user, It must be globally unique
        :param float [params.triggerPrice]: the price that a stop order is triggered at
        :param float [params.stopLossPrice]: the price that a stop loss order is triggered at
        :param float [params.takeProfitPrice]: the price that a take profit order is triggered at
        :param str [params.triggerSignal]: for triggerPrice, stopLossPrice and takeProfitPrice orders, the trigger price type, 'last', 'mark' or 'index', default is 'last'
        """
        self.load_markets()
        market = self.market(symbol)
        orderRequest = self.create_order_request(symbol, type, side, amount, price, params)
        response = self.privatePostSendorder(orderRequest)
        #
        #    {
        #        "result": "success",
        #        "sendStatus": {
        #            "order_id": "salf320-e337-47ac-b345-30sdfsalj",
        #            "status": "placed",
        #            "receivedTime": "2022-02-28T19:32:17.122Z",
        #            "orderEvents": [
        #                {
        #                    "order": {
        #                        "orderId": "salf320-e337-47ac-b345-30sdfsalj",
        #                        "cliOrdId": null,
        #                        "type": "lmt",
        #                        "symbol": "pi_xrpusd",
        #                        "side": "buy",
        #                        "quantity": 1,
        #                        "filled": 0,
        #                        "limitPrice": 0.7,
        #                        "reduceOnly": False,
        #                        "timestamp": "2022-02-28T19:32:17.122Z",
        #                        "lastUpdateTimestamp": "2022-02-28T19:32:17.122Z"
        #                    },
        #                    "reducedQuantity": null,
        #                    "type": "PLACE"
        #                }
        #            ]
        #        },
        #        "serverTime": "2022-02-28T19:32:17.122Z"
        #    }
        #
        sendStatus = self.safe_value(response, 'sendStatus')
        status = self.safe_string(sendStatus, 'status')
        self.verify_order_action_success(status, 'createOrder', ['filled'])
        return self.parse_order(sendStatus, market)

    def create_orders(self, orders: List[OrderRequest], params={}):
        """
        create a list of trade orders
        :see: https://docs.futures.kraken.com/#http-api-trading-v3-api-order-management-batch-order-management
        :param Array orders: list of orders to create, each object should contain the parameters required by createOrder, namely symbol, type, side, amount, price and params
        :returns dict: an `order structure <https://docs.ccxt_zagrava.com/#/?id=order-structure>`
        """
        self.load_markets()
        ordersRequests = []
        for i in range(0, len(orders)):
            rawOrder = orders[i]
            marketId = self.safe_string(rawOrder, 'symbol')
            type = self.safe_string(rawOrder, 'type')
            side = self.safe_string(rawOrder, 'side')
            amount = self.safe_value(rawOrder, 'amount')
            price = self.safe_value(rawOrder, 'price')
            orderParams = self.safe_value(rawOrder, 'params', {})
            extendedParams = self.extend(orderParams, params)  # the request does not accept extra params since it's a list, so we're extending each order with the common params
            if not ('order_tag' in extendedParams):
                # order tag is mandatory so we will generate one if not provided
                extendedParams['order_tag'] = self.sum(i, str(1))  # sequential counter
            extendedParams['order'] = 'send'
            orderRequest = self.create_order_request(marketId, type, side, amount, price, extendedParams)
            ordersRequests.append(orderRequest)
        request: dict = {
            'batchOrder': ordersRequests,
        }
        response = self.privatePostBatchorder(self.extend(request, params))
        #
        # {
        #     "result": "success",
        #     "serverTime": "2023-10-24T08:40:57.339Z",
        #     "batchStatus": [
        #        {
        #           "status": "requiredArgumentMissing",
        #           "orderEvents": []
        #        },
        #        {
        #           "status": "requiredArgumentMissing",
        #           "orderEvents": []
        #        }
        #     ]
        # }
        #
        data = self.safe_list(response, 'batchStatus', [])
        return self.parse_orders(data)

    def edit_order(self, id: str, symbol: str, type: OrderType, side: OrderSide, amount: Num = None, price: Num = None, params={}):
        """
        :see: https://docs.futures.kraken.com/#http-api-trading-v3-api-order-management-edit-order
        Edit an open order on the exchange
        :param str id: order id
        :param str symbol: Not used by Krakenfutures
        :param str type: Not used by Krakenfutures
        :param str side: Not used by Krakenfutures
        :param float amount: Order size
        :param float [price]: Price to fill order at
        :param dict [params]: Exchange specific params
        :returns: An `order structure <https://docs.ccxt_zagrava.com/#/?id=order-structure>`
        """
        self.load_markets()
        request: dict = {
            'orderId': id,
        }
        if amount is not None:
            request['size'] = amount
        if price is not None:
            request['limitPrice'] = price
        response = self.privatePostEditorder(self.extend(request, params))
        status = self.safe_string(response['editStatus'], 'status')
        self.verify_order_action_success(status, 'editOrder', ['filled'])
        order = self.parse_order(response['editStatus'])
        order['info'] = response
        return order

    def cancel_order(self, id: str, symbol: Str = None, params={}):
        """
        :see: https://docs.futures.kraken.com/#http-api-trading-v3-api-order-management-cancel-order
        Cancel an open order on the exchange
        :param str id: Order id
        :param str symbol: Not used by Krakenfutures
        :param dict [params]: Exchange specific params
        :returns: An `order structure <https://docs.ccxt_zagrava.com/#/?id=order-structure>`
        """
        self.load_markets()
        response = self.privatePostCancelorder(self.extend({'order_id': id}, params))
        status = self.safe_string(self.safe_value(response, 'cancelStatus', {}), 'status')
        self.verify_order_action_success(status, 'cancelOrder')
        order: dict = {}
        if 'cancelStatus' in response:
            order = self.parse_order(response['cancelStatus'])
        return self.extend({'info': response}, order)

    def cancel_orders(self, ids: List[str], symbol: Str = None, params={}):
        """
        cancel multiple orders
        :see: https://docs.futures.kraken.com/#http-api-trading-v3-api-order-management-batch-order-management
        :param str[] ids: order ids
        :param str [symbol]: unified market symbol
        :param dict [params]: extra parameters specific to the exchange API endpoint
         *
         * EXCHANGE SPECIFIC PARAMETERS
        :param str[] [params.clientOrderIds]: max length 10 e.g. ["my_id_1","my_id_2"]
        :returns dict: an list of `order structures <https://docs.ccxt_zagrava.com/#/?id=order-structure>`
        """
        self.load_markets()
        orders = []
        clientOrderIds = self.safe_value(params, 'clientOrderIds', [])
        clientOrderIdsLength = len(clientOrderIds)
        if clientOrderIdsLength > 0:
            for i in range(0, len(clientOrderIds)):
                orders.append({'order': 'cancel', 'cliOrdId': clientOrderIds[i]})
        else:
            for i in range(0, len(ids)):
                orders.append({'order': 'cancel', 'order_id': ids[i]})
        request: dict = {
            'batchOrder': orders,
        }
        response = self.privatePostBatchorder(self.extend(request, params))
        # {
        #     "result": "success",
        #     "serverTime": "2023-10-23T16:36:51.327Z",
        #     "batchStatus": [
        #       {
        #         "status": "cancelled",
        #         "order_id": "101c2327-f12e-45f2-8445-7502b87afc0b",
        #         "orderEvents": [
        #           {
        #             "uid": "101c2327-f12e-45f2-8445-7502b87afc0b",
        #             "order": {
        #               "orderId": "101c2327-f12e-45f2-8445-7502b87afc0b",
        #               "cliOrdId": null,
        #               "type": "lmt",
        #               "symbol": "PF_LTCUSD",
        #               "side": "buy",
        #               "quantity": "0.10000000000",
        #               "filled": "0E-11",
        #               "limitPrice": "50.00000000000",
        #               "reduceOnly": False,
        #               "timestamp": "2023-10-20T10:29:13.005Z",
        #               "lastUpdateTimestamp": "2023-10-20T10:29:13.005Z"
        #             },
        #             "type": "CANCEL"
        #           }
        #         ]
        #       }
        #     ]
        # }
        batchStatus = self.safe_list(response, 'batchStatus', [])
        return self.parse_orders(batchStatus)

    def cancel_all_orders(self, symbol: Str = None, params={}):
        """
        :see: https://docs.futures.kraken.com/#http-api-trading-v3-api-order-management-cancel-all-orders
        Cancels all orders on the exchange, including trigger orders
        :param str symbol: Unified market symbol
        :param dict [params]: Exchange specific params
        :returns: Response from exchange api
        """
        request: dict = {}
        if symbol is not None:
            request['symbol'] = self.market_id(symbol)
        response = self.privatePostCancelallorders(self.extend(request, params))
        #
        #    {
        #        result: 'success',
        #        cancelStatus: {
        #          receivedTime: '2024-06-06T01:12:44.814Z',
        #          cancelOnly: 'PF_XRPUSD',
        #          status: 'cancelled',
        #          cancelledOrders: [{order_id: '272fd0ac-45c0-4003-b84d-d39b9e86bd36'}],
        #          orderEvents: [
        #            {
        #              uid: '272fd0ac-45c0-4003-b84d-d39b9e86bd36',
        #              order: {
        #                orderId: '272fd0ac-45c0-4003-b84d-d39b9e86bd36',
        #                cliOrdId: null,
        #                type: 'lmt',
        #                symbol: 'PF_XRPUSD',
        #                side: 'buy',
        #                quantity: '10',
        #                filled: '0',
        #                limitPrice: '0.4',
        #                reduceOnly: False,
        #                timestamp: '2024-06-06T01:11:16.045Z',
        #                lastUpdateTimestamp: '2024-06-06T01:11:16.045Z'
        #              },
        #              type: 'CANCEL'
        #            }
        #          ]
        #        },
        #        serverTime: '2024-06-06T01:12:44.814Z'
        #    }
        #
        cancelStatus = self.safe_dict(response, 'cancelStatus')
        orderEvents = self.safe_list(cancelStatus, 'orderEvents', [])
        orders = []
        for i in range(0, len(orderEvents)):
            orderEvent = self.safe_dict(orderEvents, 0)
            order = self.safe_dict(orderEvent, 'order', {})
            orders.append(order)
        return self.parse_orders(orders)

    def cancel_all_orders_after(self, timeout: Int, params={}):
        """
        dead man's switch, cancel all orders after the given timeout
        :see: https://docs.futures.kraken.com/#http-api-trading-v3-api-order-management-dead-man-39-s-switch
        :param number timeout: time in milliseconds, 0 represents cancel the timer
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict: the api result
        """
        self.load_markets()
        request: dict = {
            'timeout': (self.parse_to_int(timeout / 1000)) if (timeout > 0) else 0,
        }
        response = self.privatePostCancelallordersafter(self.extend(request, params))
        #
        #     {
        #         "result": "success",
        #         "serverTime": "2018-06-19T16:51:23.839Z",
        #         "status": {
        #             "currentTime": "2018-06-19T16:51:23.839Z",
        #             "triggerTime": "0"
        #         }
        #     }
        #
        return response

    def fetch_open_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
        """
        :see: https://docs.futures.kraken.com/#http-api-trading-v3-api-order-management-get-open-orders
        Gets all open orders, including trigger orders, for an account from the exchange api
        :param str symbol: Unified market symbol
        :param int [since]: Timestamp(ms) of earliest order.(Not used by kraken api but filtered internally by ccxt_zagrava)
        :param int [limit]: How many orders to return.(Not used by kraken api but filtered internally by ccxt_zagrava)
        :param dict [params]: Exchange specific parameters
        :returns: An array of `order structures <https://docs.ccxt_zagrava.com/#/?id=order-structure>`
        """
        self.load_markets()
        market = None
        if symbol is not None:
            market = self.market(symbol)
        response = self.privateGetOpenorders(params)
        orders = self.safe_list(response, 'openOrders', [])
        return self.parse_orders(orders, market, since, limit)

    def fetch_closed_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
        """
        :see: https://docs.futures.kraken.com/#http-api-history-account-history-get-order-events
        Gets all closed orders, including trigger orders, for an account from the exchange api
        :param str symbol: Unified market symbol
        :param int [since]: Timestamp(ms) of earliest order.
        :param int [limit]: How many orders to return.
        :param dict [params]: Exchange specific parameters
        :returns: An array of `order structures <https://docs.ccxt_zagrava.com/#/?id=order-structure>`
        """
        self.load_markets()
        market = None
        if symbol is not None:
            market = self.market(symbol)
        request: dict = {}
        if limit is not None:
            request['count'] = limit
        if since is not None:
            request['from'] = since
        response = self.historyGetOrders(self.extend(request, params))
        allOrders = self.safe_list(response, 'elements', [])
        closedOrders = []
        for i in range(0, len(allOrders)):
            order = allOrders[i]
            event = self.safe_dict(order, 'event', {})
            orderPlaced = self.safe_dict(event, 'OrderPlaced')
            if orderPlaced is not None:
                innerOrder = self.safe_dict(orderPlaced, 'order', {})
                filled = self.safe_string(innerOrder, 'filled')
                if filled != '0':
                    innerOrder['status'] = 'closed'  # status not available in the response
                    closedOrders.append(innerOrder)
        return self.parse_orders(closedOrders, market, since, limit)

    def fetch_canceled_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
        """
        :see: https://docs.futures.kraken.com/#http-api-history-account-history-get-order-events
        Gets all canceled orders, including trigger orders, for an account from the exchange api
        :param str symbol: Unified market symbol
        :param int [since]: Timestamp(ms) of earliest order.
        :param int [limit]: How many orders to return.
        :param dict [params]: Exchange specific parameters
        :returns: An array of `order structures <https://docs.ccxt_zagrava.com/#/?id=order-structure>`
        """
        self.load_markets()
        market = None
        if symbol is not None:
            market = self.market(symbol)
        request: dict = {}
        if limit is not None:
            request['count'] = limit
        if since is not None:
            request['from'] = since
        response = self.historyGetOrders(self.extend(request, params))
        allOrders = self.safe_list(response, 'elements', [])
        canceledAndRejected = []
        for i in range(0, len(allOrders)):
            order = allOrders[i]
            event = self.safe_dict(order, 'event', {})
            orderPlaced = self.safe_dict(event, 'OrderPlaced')
            if orderPlaced is not None:
                innerOrder = self.safe_dict(orderPlaced, 'order', {})
                filled = self.safe_string(innerOrder, 'filled')
                if filled == '0':
                    innerOrder['status'] = 'canceled'  # status not available in the response
                    canceledAndRejected.append(innerOrder)
            orderCanceled = self.safe_dict(event, 'OrderCancelled')
            if orderCanceled is not None:
                innerOrder = self.safe_dict(orderCanceled, 'order', {})
                innerOrder['status'] = 'canceled'  # status not available in the response
                canceledAndRejected.append(innerOrder)
            orderRejected = self.safe_dict(event, 'OrderRejected')
            if orderRejected is not None:
                innerOrder = self.safe_dict(orderRejected, 'order', {})
                innerOrder['status'] = 'rejected'  # status not available in the response
                canceledAndRejected.append(innerOrder)
        return self.parse_orders(canceledAndRejected, market, since, limit)

    def parse_order_type(self, orderType):
        map: dict = {
            'lmt': 'limit',
            'mkt': 'market',
            'post': 'limit',
            'ioc': 'market',
        }
        return self.safe_string(map, orderType, orderType)

    def verify_order_action_success(self, status, method, omit=[]):
        errors: dict = {
            'invalidOrderType': InvalidOrder,
            'invalidSide': InvalidOrder,
            'invalidSize': InvalidOrder,
            'invalidPrice': InvalidOrder,
            'insufficientAvailableFunds': InsufficientFunds,
            'selfFill': ExchangeError,
            'tooManySmallOrders': ExchangeError,
            'maxPositionViolation': BadRequest,
            'marketSuspended': ExchangeNotAvailable,
            'marketInactive': ExchangeNotAvailable,
            'clientOrderIdAlreadyExist': DuplicateOrderId,
            'clientOrderIdTooLong': BadRequest,
            'outsidePriceCollar': InvalidOrder,
            'postWouldExecute': OrderImmediatelyFillable,  # the unplaced order could actually be parsed(with status = "rejected"), but there is self specific error for self
            'iocWouldNotExecute': OrderNotFillable,  # -||-
            'wouldNotReducePosition': ExchangeError,
            'orderForEditNotFound': OrderNotFound,
            'orderForEditNotAStop': InvalidOrder,
            'filled': OrderNotFound,
            'notFound': OrderNotFound,
        }
        if (status in errors) and not self.in_array(status, omit):
            raise errors[status](self.id + ': ' + method + ' failed due to ' + status)

    def parse_order_status(self, status: Str):
        statuses: dict = {
            'placed': 'open',  # the order was placed successfully
            'cancelled': 'canceled',  # the order was cancelled successfully
            'invalidOrderType': 'rejected',  # the order was not placed because orderType is invalid
            'invalidSide': 'rejected',  # the order was not placed because side is invalid
            'invalidSize': 'rejected',  # the order was not placed because size is invalid
            'invalidPrice': 'rejected',  # the order was not placed because limitPrice and/or stopPrice are invalid
            'insufficientAvailableFunds': 'rejected',  # the order was not placed because available funds are insufficient
            'selfFill': 'rejected',  # the order was not placed because it would be filled against an existing order belonging to the same account
            'tooManySmallOrders': 'rejected',  # the order was not placed because the number of small open orders would exceed the permissible limit
            'maxPositionViolation': 'rejected',  # Order would cause you to exceed your maximum hasattr(self, position) contract.
            'marketSuspended': 'rejected',  # the order was not placed because the market is suspended
            'marketInactive': 'rejected',  # the order was not placed because the market is inactive
            'clientOrderIdAlreadyExist': 'rejected',  # the specified client id already exist
            'clientOrderIdTooLong': 'rejected',  # the client id is longer than the permissible limit
            'outsidePriceCollar': 'rejected',  # the limit order crosses the spread but is an order of magnitude away from the mark price - fat finger control
            # Should the next two be 'expired' ?
            'postWouldExecute': 'rejected',  # the post-only order would be filled upon placement, thus is cancelled
            'iocWouldNotExecute': 'rejected',  # the immediate-or-cancel order would not execute.
            'wouldNotReducePosition': 'rejected',  # the reduce only order would not reduce position.
            'edited': 'open',  # the order was edited successfully
            'orderForEditNotFound': 'rejected',  # the requested order for edit has not been found
            'orderForEditNotAStop': 'rejected',  # the supplied stopPrice cannot be applied because order is not a stop order
            'filled': 'closed',  # the order was found completely filled and could not be cancelled
            'notFound': 'rejected',  # the order was not found, either because it had already been cancelled or it never existed
            'untouched': 'open',  # the entire size of the order is unfilled
            'partiallyFilled': 'open',  # the size of the order is partially but not entirely filled
        }
        return self.safe_string(statuses, status, status)

    def parse_order(self, order: dict, market: Market = None) -> Order:
        #
        # LIMIT
        #
        #    {
        #        "order_id": "179f9af8-e45e-469d-b3e9-2fd4675cb7d0",
        #        "status": "placed",
        #        "receivedTime": "2019-09-05T16:33:50.734Z",
        #        "orderEvents": [
        #            {
        #                "uid": "614a5298-0071-450f-83c6-0617ce8c6bc4",
        #                "order": {
        #                    "orderId": "179f9af8-e45e-469d-b3e9-2fd4675cb7d0",
        #                    "cliOrdId": null,
        #                    "type": "lmt",
        #                    "symbol": "pi_xbtusd",
        #                    "side": "buy",
        #                    "quantity": 10000,
        #                    "filled": 0,
        #                    "limitPrice": 9400,
        #                    "reduceOnly": False,
        #                    "timestamp": "2019-09-05T16:33:50.734Z",
        #                    "lastUpdateTimestamp": "2019-09-05T16:33:50.734Z"
        #                },
        #                "reducedQuantity": null,
        #                "reason": "WOULD_NOT_REDUCE_POSITION",  # REJECTED
        #                "type": "PLACE"
        #            }
        #        ]
        #    }
        #
        # CONDITIONAL
        #
        #    {
        #        "order_id": "1abfd3c6-af93-4b30-91cc-e4a93797f3f5",
        #        "status": "placed",
        #        "receivedTime": "2019-12-05T10:20:50.701Z",
        #        "orderEvents": [
        #            {
        #                "orderTrigger": {
        #                    "uid": "1abfd3c6-af93-4b30-91cc-e4a93797f3f5",
        #                    "clientId":null,
        #                    "type": "lmt",                                # "ioc" if stop market
        #                    "symbol": "pi_xbtusd",
        #                    "side": "buy",
        #                    "quantity":10,
        #                    "limitPrice":15000,
        #                    "triggerPrice":9500,
        #                    "triggerSide": "trigger_below",
        #                    "triggerSignal": "mark_price",
        #                    "reduceOnly":false,
        #                    "timestamp": "2019-12-05T10:20:50.701Z",
        #                    "lastUpdateTimestamp": "2019-12-05T10:20:50.701Z"
        #                },
        #                "type": "PLACE"
        #            }
        #        ]
        #    }
        #
        # EXECUTION
        #
        #    {
        #        "order_id": "61ca5732-3478-42fe-8362-abbfd9465294",
        #        "status": "placed",
        #        "receivedTime": "2019-12-11T17:17:33.888Z",
        #        "orderEvents": [
        #            {
        #                "executionId": "e1ec9f63-2338-4c44-b40a-43486c6732d7",
        #                "price": 7244.5,
        #                "amount": 10,
        #                "orderPriorEdit": null,
        #                "orderPriorExecution": {
        #                    "orderId": "61ca5732-3478-42fe-8362-abbfd9465294",
        #                    "cliOrdId": null,
        #                    "type": "lmt",
        #                    "symbol": "pi_xbtusd",
        #                    "side": "buy",
        #                    "quantity": 10,
        #                    "filled": 0,
        #                    "limitPrice": 7500,
        #                    "reduceOnly": False,
        #                    "timestamp": "2019-12-11T17:17:33.888Z",
        #                    "lastUpdateTimestamp": "2019-12-11T17:17:33.888Z"
        #                },
        #                "takerReducedQuantity": null,
        #                "type": "EXECUTION"
        #            }
        #        ]
        #    }
        #
        # EDIT ORDER
        #
        #    {
        #        "status": "edited",
        #        "orderId": "022774bc-2c4a-4f26-9317-436c8d85746d",
        #        "receivedTime": "2019-09-05T16:47:47.521Z",
        #        "orderEvents": [
        #            {
        #                "old": {
        #                    "orderId": "022774bc-2c4a-4f26-9317-436c8d85746d",
        #                    "cliOrdId":null,
        #                    "type": "lmt",
        #                    "symbol": "pi_xbtusd",
        #                    "side": "buy",
        #                    "quantity":1000,
        #                    "filled":0,
        #                    "limitPrice":9400.0,
        #                    "reduceOnly":false,
        #                    "timestamp": "2019-09-05T16:41:35.173Z",
        #                    "lastUpdateTimestamp": "2019-09-05T16:41:35.173Z"
        #                },
        #                "new": {
        #                    "orderId": "022774bc-2c4a-4f26-9317-436c8d85746d",
        #                    "cliOrdId": null,
        #                    "type": "lmt",
        #                    "symbol": "pi_xbtusd",
        #                    "side": "buy",
        #                    "quantity": 1501,
        #                    "filled": 0,
        #                    "limitPrice": 7200,
        #                    "reduceOnly": False,
        #                    "timestamp": "2019-09-05T16:41:35.173Z",
        #                    "lastUpdateTimestamp": "2019-09-05T16:47:47.519Z"
        #                },
        #                "reducedQuantity": null,
        #                "type": "EDIT"
        #            }
        #        ]
        #    }
        #
        # CANCEL ORDER
        #
        #    {
        #        "status": "cancelled",
        #        "orderEvents": [
        #            {
        #                "uid": "85c40002-3f20-4e87-9302-262626c3531b",
        #                "order": {
        #                    "orderId": "85c40002-3f20-4e87-9302-262626c3531b",
        #                    "cliOrdId": null,
        #                    "type": "lmt",
        #                    "symbol": "pi_xbtusd",
        #                    "side": "buy",
        #                    "quantity": 1000,
        #                    "filled": 0,
        #                    "limitPrice": 10144,
        #                    "stopPrice": null,
        #                    "reduceOnly": False,
        #                    "timestamp": "2019-08-01T15:26:27.790Z"
        #                },
        #                "type": "CANCEL"
        #            }
        #        ]
        #    }
        #
        # cancelAllOrders
        #
        #    {
        #        "orderId": "85c40002-3f20-4e87-9302-262626c3531b",
        #        "cliOrdId": null,
        #        "type": "lmt",
        #        "symbol": "pi_xbtusd",
        #        "side": "buy",
        #        "quantity": 1000,
        #        "filled": 0,
        #        "limitPrice": 10144,
        #        "stopPrice": null,
        #        "reduceOnly": False,
        #        "timestamp": "2019-08-01T15:26:27.790Z"
        #    }
        #
        # FETCH OPEN ORDERS
        #
        #    {
        #        "order_id": "59302619-41d2-4f0b-941f-7e7914760ad3",
        #        "symbol": "pi_xbtusd",
        #        "side": "sell",
        #        "orderType": "lmt",
        #        "limitPrice": 10640,
        #        "unfilledSize": 304,
        #        "receivedTime": "2019-09-05T17:01:17.410Z",
        #        "status": "untouched",
        #        "filledSize": 0,
        #        "reduceOnly": True,
        #        "lastUpdateTime": "2019-09-05T17:01:17.410Z"
        #    }
        #
        # createOrders error
        #    {
        #       "status": "requiredArgumentMissing",
        #       "orderEvents": []
        #    }
        # closed orders
        #    {
        #        uid: '2f00cd63-e61d-44f8-8569-adabde885941',
        #        timestamp: '1707258274849',
        #        event: {
        #          OrderPlaced: {
        #            order: {
        #              uid: '85805e01-9eed-4395-8360-ed1a228237c9',
        #              accountUid: '406142dd-7c5c-4a8b-acbc-5f16eca30009',
        #              tradeable: 'PF_LTCUSD',
        #              direction: 'Buy',
        #              quantity: '0',
        #              filled: '0.1',
        #              timestamp: '1707258274849',
        #              limitPrice: '69.2200000000',
        #              orderType: 'IoC',
        #              clientId: '',
        #              reduceOnly: False,
        #              lastUpdateTimestamp: '1707258274849'
        #            },
        #            reason: 'new_user_order',
        #            reducedQuantity: '',
        #            algoId: ''
        #          }
        #        }
        #    }
        #
        orderEvents = self.safe_value(order, 'orderEvents', [])
        errorStatus = self.safe_string(order, 'status')
        orderEventsLength = len(orderEvents)
        if ('orderEvents' in order) and (errorStatus is not None) and (orderEventsLength == 0):
            # creteOrders error response
            return self.safe_order({'info': order, 'status': 'rejected'})
        details = None
        isPrior = False
        fixed = False
        statusId = None
        price = None
        trades = []
        if orderEventsLength:
            executions = []
            for i in range(0, len(orderEvents)):
                item = orderEvents[i]
                if self.safe_string(item, 'type') == 'EXECUTION':
                    executions.append(item)
                # Final order(after placement / editing / execution / canceling)
                orderTrigger = self.safe_value(item, 'orderTrigger')
                details = self.safe_value_2(item, 'new', 'order', orderTrigger)
                if details is not None:
                    isPrior = False
                    fixed = True
                elif not fixed:
                    orderPriorExecution = self.safe_value(item, 'orderPriorExecution')
                    details = self.safe_value_2(item, 'orderPriorExecution', 'orderPriorEdit')
                    price = self.safe_string(orderPriorExecution, 'limitPrice')
                    if details is not None:
                        isPrior = True
            trades = self.parse_trades(executions)
            statusId = self.safe_string(order, 'status')
        if details is None:
            details = order
        if statusId is None:
            statusId = self.safe_string(details, 'status')
        # This may be incorrectly marked as "open" if only execution report is given,
        # but will be fixed below
        status = self.parse_order_status(statusId)
        isClosed = self.in_array(status, ['canceled', 'rejected', 'closed'])
        marketId = self.safe_string(details, 'symbol')
        market = self.safe_market(marketId, market)
        timestamp = self.parse8601(self.safe_string_2(details, 'timestamp', 'receivedTime'))
        lastUpdateTimestamp = self.parse8601(self.safe_string(details, 'lastUpdateTime'))
        if price is None:
            price = self.safe_string(details, 'limitPrice')
        amount = self.safe_string(details, 'quantity')
        filled = self.safe_string_2(details, 'filledSize', 'filled', '0.0')
        remaining = self.safe_string(details, 'unfilledSize')
        average = None
        filled2 = '0.0'
        tradesLength = len(trades)
        if tradesLength > 0:
            vwapSum = '0.0'
            for i in range(0, len(trades)):
                trade = trades[i]
                tradeAmount = self.safe_string(trade, 'amount')
                tradePrice = self.safe_string(trade, 'price')
                filled2 = Precise.string_add(filled2, tradeAmount)
                vwapSum = Precise.string_add(vwapSum, Precise.string_mul(tradeAmount, tradePrice))
            average = Precise.string_div(vwapSum, filled2)
            if (amount is not None) and (not isClosed) and isPrior and Precise.string_ge(filled2, amount):
                status = 'closed'
                isClosed = True
            if isPrior:
                filled = Precise.string_add(filled, filled2)
            else:
                filled = Precise.string_max(filled, filled2)
        if remaining is None:
            if isPrior:
                if amount is not None:
                    # remaining amount before execution minus executed amount
                    remaining = Precise.string_sub(amount, filled2)
            else:
                remaining = amount
        # if fetchOpenOrders are parsed
        if (amount is None) and (not isPrior) and (remaining is not None):
            amount = Precise.string_add(filled, remaining)
        cost = None
        if (filled is not None) and (market is not None):
            whichPrice = average if (average is not None) else price
            if whichPrice is not None:
                if market['linear']:
                    cost = Precise.string_mul(filled, whichPrice)  # in quote
                else:
                    cost = Precise.string_div(filled, whichPrice)  # in base
        id = self.safe_string_2(order, 'order_id', 'orderId')
        if id is None:
            id = self.safe_string_2(details, 'orderId', 'uid')
        type = self.safe_string_lower_2(details, 'type', 'orderType')
        timeInForce = 'gtc'
        if type == 'ioc' or self.parse_order_type(type) == 'market':
            timeInForce = 'ioc'
        return self.safe_order({
            'info': order,
            'id': id,
            'clientOrderId': self.safe_string_n(details, ['clientOrderId', 'clientId', 'cliOrdId']),
            'timestamp': timestamp,
            'datetime': self.iso8601(timestamp),
            'lastTradeTimestamp': None,
            'lastUpdateTimestamp': lastUpdateTimestamp,
            'symbol': self.safe_string(market, 'symbol'),
            'type': self.parse_order_type(type),
            'timeInForce': timeInForce,
            'postOnly': type == 'post',
            'reduceOnly': self.safe_bool_2(details, 'reduceOnly', 'reduce_only'),
            'side': self.safe_string(details, 'side'),
            'price': price,
            'stopPrice': self.safe_string(details, 'triggerPrice'),
            'triggerPrice': self.safe_string(details, 'triggerPrice'),
            'amount': amount,
            'cost': cost,
            'average': average,
            'filled': filled,
            'remaining': remaining,
            'status': status,
            'fee': None,
            'fees': None,
            'trades': trades,
        })

    def fetch_my_trades(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
        """
        fetch all trades made by the user
        :see: https://docs.futures.kraken.com/#http-api-trading-v3-api-historical-data-get-your-fills
        :param str symbol: unified market symbol
        :param int [since]: *not used by the  api* the earliest time in ms to fetch trades for
        :param int [limit]: the maximum number of trades structures to retrieve
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :param int [params.until]: the latest time in ms to fetch entries for
        :returns Trade[]: a list of `trade structures <https://docs.ccxt_zagrava.com/#/?id=trade-structure>`
        """
        self.load_markets()
        market = None
        if symbol is not None:
            market = self.market(symbol)
        response = self.privateGetFills(params)
        #
        #    {
        #        "result": "success",
        #        "serverTime": "2016-02-25T09:45:53.818Z",
        #        "fills": [
        #            {
        #                "fillTime": "2016-02-25T09:47:01.000Z",
        #                "order_id": "c18f0c17-9971-40e6-8e5b-10df05d422f0",
        #                "fill_id": "522d4e08-96e7-4b44-9694-bfaea8fe215e",
        #                "cliOrdId": "d427f920-ec55-4c18-ba95-5fe241513b30",  # EXTRA
        #                "symbol": "fi_xbtusd_180615",
        #                "side": "buy",
        #                "size": 2000,
        #                "price": 4255,
        #                "fillType": "maker"
        #            },
        #            ...
        #        ]
        #    }
        #
        return self.parse_trades(response['fills'], market, since, limit)

    def fetch_balance(self, params={}) -> Balances:
        """
        :see: https://docs.futures.kraken.com/#http-api-trading-v3-api-account-information-get-wallets
        Fetch the balance for a sub-account, all sub-account balances are inside 'info' in the response
        :param dict [params]: Exchange specific parameters
        :param str [params.type]: The sub-account type to query the balance of, possible values include 'flex', 'cash'/'main'/'funding', or a market symbol * defaults to 'flex' *
        :param str [params.symbol]: A unified market symbol, when assigned the balance for a trading market that matches the symbol is returned
        :returns: A `balance structure <https://docs.ccxt_zagrava.com/#/?id=balance-structure>`
        """
        self.load_markets()
        type = self.safe_string_2(params, 'type', 'account')
        symbol = self.safe_string(params, 'symbol')
        params = self.omit(params, ['type', 'account', 'symbol'])
        response = self.privateGetAccounts(params)
        #
        #    {
        #        "result": "success",
        #        "accounts": {
        #            "fi_xbtusd": {
        #                "auxiliary": {usd: "0", pv: '0.0', pnl: '0.0', af: '0.0', funding: "0.0"},
        #                "marginRequirements": {im: '0.0', mm: '0.0', lt: '0.0', tt: "0.0"},
        #                "triggerEstimates": {im: '0', mm: '0', lt: "0", tt: "0"},
        #                "balances": {xbt: "0.0"},
        #                "currency": "xbt",
        #                "type": "marginAccount"
        #            },
        #            "cash": {
        #                "balances": {
        #                    "eur": "0.0",
        #                    "gbp": "0.0",
        #                    "bch": "0.0",
        #                    "xrp": "2.20188538338",
        #                    "usd": "0.0",
        #                    "eth": "0.0",
        #                    "usdt": "0.0",
        #                    "ltc": "0.0",
        #                    "usdc": "0.0",
        #                    "xbt": "0.0"
        #                },
        #                "type": "cashAccount"
        #            },
        #            "fv_xrpxbt": {
        #                "auxiliary": {usd: "0", pv: '0.0', pnl: '0.0', af: '0.0', funding: "0.0"},
        #                "marginRequirements": {im: '0.0', mm: '0.0', lt: '0.0', tt: "0.0"},
        #                "triggerEstimates": {im: '0', mm: '0', lt: "0", tt: "0"},
        #                "balances": {xbt: "0.0"},
        #                "currency": "xbt",
        #                "type": "marginAccount"
        #            },
        #            "fi_xrpusd": {
        #                "auxiliary": {usd: "0", pv: '11.0', pnl: '0.0', af: '11.0', funding: "0.0"},
        #                "marginRequirements": {im: '0.0', mm: '0.0', lt: '0.0', tt: "0.0"},
        #                "triggerEstimates": {im: '0', mm: '0', lt: "0", tt: "0"},
        #                "balances": {xrp: "11.0"},
        #                "currency": "xrp",
        #                "type": "marginAccount"
        #            },
        #            "fi_ethusd": {
        #                "auxiliary": {usd: "0", pv: '0.0', pnl: '0.0', af: '0.0', funding: "0.0"},
        #                "marginRequirements": {im: '0.0', mm: '0.0', lt: '0.0', tt: "0.0"},
        #                "triggerEstimates": {im: '0', mm: '0', lt: "0", tt: "0"},
        #                "balances": {eth: "0.0"},
        #                "currency": "eth",
        #                "type": "marginAccount"
        #            },
        #            "fi_ltcusd": {
        #                "auxiliary": {usd: "0", pv: '0.0', pnl: '0.0', af: '0.0', funding: "0.0"},
        #                "marginRequirements": {im: '0.0', mm: '0.0', lt: '0.0', tt: "0.0"},
        #                "triggerEstimates": {im: '0', mm: '0', lt: "0", tt: "0"},
        #                "balances": {ltc: "0.0"},
        #                "currency": "ltc",
        #                "type": "marginAccount"
        #            },
        #            "fi_bchusd": {
        #                "auxiliary": {usd: "0", pv: '0.0', pnl: '0.0', af: '0.0', funding: "0.0"},
        #                "marginRequirements": {im: '0.0', mm: '0.0', lt: '0.0', tt: "0.0"},
        #                "triggerEstimates": {im: '0', mm: '0', lt: "0", tt: "0"},
        #                "balances": {bch: "0.0"},
        #                "currency": "bch",
        #                "type": "marginAccount"
        #            },
        #            "flex": {
        #                "currencies": {},
        #                "initialMargin": "0.0",
        #                "initialMarginWithOrders": "0.0",
        #                "maintenanceMargin": "0.0",
        #                "balanceValue": "0.0",
        #                "portfolioValue": "0.0",
        #                "collateralValue": "0.0",
        #                "pnl": "0.0",
        #                "unrealizedFunding": "0.0",
        #                "totalUnrealized": "0.0",
        #                "totalUnrealizedAsMargin": "0.0",
        #                "availableMargin": "0.0",
        #                "marginEquity": "0.0",
        #                "type": "multiCollateralMarginAccount"
        #            }
        #        },
        #        "serverTime": "2022-04-12T07:48:07.475Z"
        #    }
        #
        datetime = self.safe_string(response, 'serverTime')
        if type == 'marginAccount' or type == 'margin':
            if symbol is None:
                raise ArgumentsRequired(self.id + ' fetchBalance requires symbol argument for margin accounts')
            type = symbol
        if type is None:
            type = 'flex' if (symbol is None) else symbol
        accountName = self.parse_account(type)
        accounts = self.safe_value(response, 'accounts')
        account = self.safe_value(accounts, accountName)
        if account is None:
            type = '' if (type is None) else type
            symbol = '' if (symbol is None) else symbol
            raise BadRequest(self.id + ' fetchBalance has no account for ' + type)
        balance = self.parse_balance(account)
        balance['info'] = response
        balance['timestamp'] = self.parse8601(datetime)
        balance['datetime'] = datetime
        return balance

    def parse_balance(self, response) -> Balances:
        #
        # cashAccount
        #
        #    {
        #        "balances": {
        #            "eur": "0.0",
        #            "gbp": "0.0",
        #            "bch": "0.0",
        #            "xrp": "2.20188538338",
        #            "usd": "0.0",
        #            "eth": "0.0",
        #            "usdt": "0.0",
        #            "ltc": "0.0",
        #            "usdc": "0.0",
        #            "xbt": "0.0"
        #        },
        #        "type": "cashAccount"
        #    }
        #
        # marginAccount e,g, fi_xrpusd
        #
        #    {
        #        "auxiliary": {
        #            "usd": "0",
        #            "pv": "11.0",
        #            "pnl": "0.0",
        #            "af": "11.0",
        #            "funding": "0.0"
        #        },
        #        "marginRequirements": {im: '0.0', mm: '0.0', lt: '0.0', tt: "0.0"},
        #        "triggerEstimates": {im: '0', mm: '0', lt: "0", tt: "0"},
        #        "balances": {xrp: "11.0"},
        #        "currency": "xrp",
        #        "type": "marginAccount"
        #    }
        #
        # flex/multiCollateralMarginAccount
        #
        #    {
        #       "currencies": {
        #            "USDT": {
        #                "quantity": "1",
        #                "value": "1.0001",
        #                "collateral": "0.9477197625",
        #                "available": "1.0"
        #             }
        #       },
        #       "initialMargin": "0.0",
        #       "initialMarginWithOrders": "0.0",
        #       "maintenanceMargin": "0.0",
        #       "balanceValue": "1.0",
        #       "portfolioValue": "1.0",
        #       "collateralValue": "0.95",
        #       "pnl": "0.0",
        #       "unrealizedFunding": "0.0",
        #       "totalUnrealized": "0.0",
        #       "totalUnrealizedAsMargin": "0.0",
        #       "availableMargin": "0.95",
        #       "marginEquity": "0.95",
        #       "type": "multiCollateralMarginAccount"
        #    }
        #
        accountType = self.safe_string_2(response, 'accountType', 'type')
        isFlex = (accountType == 'multiCollateralMarginAccount')
        isCash = (accountType == 'cashAccount')
        balances = self.safe_value_2(response, 'balances', 'currencies', {})
        result: dict = {}
        currencyIds = list(balances.keys())
        for i in range(0, len(currencyIds)):
            currencyId = currencyIds[i]
            balance = balances[currencyId]
            code = self.safe_currency_code(currencyId)
            splitCode = code.split('_')
            codeLength = len(splitCode)
            if codeLength > 1:
                continue   # Removes contract codes like PI_XRPUSD
            account = self.account()
            if isFlex:
                account['total'] = self.safe_string(balance, 'quantity')
                account['free'] = self.safe_string(balance, 'available')
            elif isCash:
                account['used'] = '0.0'
                account['total'] = balance
            else:
                auxiliary = self.safe_value(response, 'auxiliary')
                account['free'] = self.safe_string(auxiliary, 'af')
                account['total'] = self.safe_string(auxiliary, 'pv')
            result[code] = account
        return self.safe_balance(result)

    def fetch_funding_rates(self, symbols: Strings = None, params={}):
        """
        :see: https://docs.futures.kraken.com/#http-api-trading-v3-api-market-data-get-tickers
        fetch the current funding rates
        :param str[] symbols: unified market symbols
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns Order[]: an array of `funding rate structures <https://docs.ccxt_zagrava.com/#/?id=funding-rate-structure>`
        """
        self.load_markets()
        marketIds = self.market_ids(symbols)
        response = self.publicGetTickers(params)
        tickers = self.safe_value(response, 'tickers')
        fundingRates = []
        for i in range(0, len(tickers)):
            entry = tickers[i]
            entry_symbol = self.safe_value(entry, 'symbol')
            if marketIds is not None:
                if not self.in_array(entry_symbol, marketIds):
                    continue
            market = self.safe_market(entry_symbol)
            parsed = self.parse_funding_rate(entry, market)
            fundingRates.append(parsed)
        return self.index_by(fundingRates, 'symbol')

    def parse_funding_rate(self, ticker, market: Market = None):
        #
        # {"ask": 26.283,
        #  "askSize": 4.6,
        #  "bid": 26.201,
        #  "bidSize": 190,
        #  "fundingRate": -0.000944642727438883,
        #  "fundingRatePrediction": -0.000872671532340275,
        #  "indexPrice": 26.253,
        #  "last": 26.3,
        #  "lastSize": 0.1,
        #  "lastTime": "2023-06-11T18:55:28.958Z",
        #  "markPrice": 26.239,
        #  "open24h": 26.3,
        #  "openInterest": 641.1,
        #  "pair": "COMP:USD",
        #  "postOnly": False,
        #  "suspended": False,
        #  "symbol": "pf_compusd",
        #  "tag": "perpetual",
        #  "vol24h": 0.1,
        #  "volumeQuote": 2.63}
        #
        fundingRateMultiplier = '8'  # https://support.kraken.com/hc/en-us/articles/9618146737172-Perpetual-Contracts-Funding-Rate-Method-Prior-to-September-29-2022
        marketId = self.safe_string(ticker, 'symbol')
        symbol = self.symbol(marketId)
        timestamp = self.parse8601(self.safe_string(ticker, 'lastTime'))
        indexPrice = self.safe_number(ticker, 'indexPrice')
        markPriceString = self.safe_string(ticker, 'markPrice')
        markPrice = self.parse_number(markPriceString)
        fundingRateString = self.safe_string(ticker, 'fundingRate')
        fundingRateResult = Precise.string_div(Precise.string_mul(fundingRateString, fundingRateMultiplier), markPriceString)
        fundingRate = self.parse_number(fundingRateResult)
        nextFundingRateString = self.safe_string(ticker, 'fundingRatePrediction')
        nextFundingRateResult = Precise.string_div(Precise.string_mul(nextFundingRateString, fundingRateMultiplier), markPriceString)
        nextFundingRate = self.parse_number(nextFundingRateResult)
        return {
            'info': ticker,
            'symbol': symbol,
            'markPrice': markPrice,
            'indexPrice': indexPrice,
            'interestRate': None,
            'estimatedSettlePrice': None,
            'timestamp': timestamp,
            'datetime': self.iso8601(timestamp),
            'fundingRate': fundingRate,
            'fundingTimestamp': None,
            'fundingDatetime': None,
            'nextFundingRate': nextFundingRate,
            'nextFundingTimestamp': None,
            'nextFundingDatetime': None,
            'previousFundingRate': None,
            'previousFundingTimestamp': None,
            'previousFundingDatetime': None,
        }

    def fetch_funding_rate_history(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
        """
        fetches historical funding rate prices
        :see: https://docs.futures.kraken.com/#http-api-trading-v3-api-historical-funding-rates-historical-funding-rates
        :param str symbol: unified symbol of the market to fetch the funding rate history for
        :param int [since]: timestamp in ms of the earliest funding rate to fetch
        :param int [limit]: the maximum amount of `funding rate structures <https://docs.ccxt_zagrava.com/#/?id=funding-rate-history-structure>` to fetch
        :param dict [params]: extra parameters specific to the api endpoint
        :returns dict[]: a list of `funding rate structures <https://docs.ccxt_zagrava.com/#/?id=funding-rate-history-structure>`
        """
        if symbol is None:
            raise ArgumentsRequired(self.id + ' fetchFundingRateHistory() requires a symbol argument')
        self.load_markets()
        market = self.market(symbol)
        if not market['swap']:
            raise BadRequest(self.id + ' fetchFundingRateHistory() supports swap contracts only')
        request: dict = {
            'symbol': market['id'].upper(),
        }
        response = self.publicGetHistoricalfundingrates(self.extend(request, params))
        #
        #    {
        #        "rates": [
        #          {
        #            "timestamp": '2018-08-31T16:00:00.000Z',
        #            "fundingRate": '2.18900669884E-7',
        #            "relativeFundingRate": '0.000060779960000000'
        #          },
        #          ...
        #        ]
        #    }
        #
        rates = self.safe_value(response, 'rates')
        result = []
        for i in range(0, len(rates)):
            item = rates[i]
            datetime = self.safe_string(item, 'timestamp')
            result.append({
                'info': item,
                'symbol': symbol,
                'fundingRate': self.safe_number(item, 'relativeFundingRate'),
                'timestamp': self.parse8601(datetime),
                'datetime': datetime,
            })
        sorted = self.sort_by(result, 'timestamp')
        return self.filter_by_symbol_since_limit(sorted, symbol, since, limit)

    def fetch_positions(self, symbols: Strings = None, params={}):
        """
        :see: https://docs.futures.kraken.com/#http-api-trading-v3-api-account-information-get-open-positions
        Fetches current contract trading positions
        :param str[] symbols: List of unified symbols
        :param dict [params]: Not used by krakenfutures
        :returns: Parsed exchange response for positions
        """
        self.load_markets()
        request: dict = {}
        response = self.privateGetOpenpositions(request)
        #
        #    {
        #        "result": "success",
        #        "openPositions": [
        #            {
        #                "side": "long",
        #                "symbol": "pi_xrpusd",
        #                "price": "0.7533",
        #                "fillTime": "2022-03-03T22:51:16.566Z",
        #                "size": "230",
        #                "unrealizedFunding": "-0.001878596918214635"
        #            }
        #        ],
        #        "serverTime": "2022-03-03T22:51:16.566Z"
        #    }
        #
        result = self.parse_positions(response)
        return self.filter_by_array_positions(result, 'symbol', symbols, False)

    def parse_positions(self, response, symbols: Strings = None, params={}):
        result = []
        positions = self.safe_value(response, 'openPositions')
        for i in range(0, len(positions)):
            position = self.parse_position(positions[i])
            result.append(position)
        return result

    def parse_position(self, position: dict, market: Market = None):
        # cross
        #    {
        #        "side": "long",
        #        "symbol": "pi_xrpusd",
        #        "price": "0.7533",
        #        "fillTime": "2022-03-03T22:51:16.566Z",
        #        "size": "230",
        #        "unrealizedFunding": "-0.001878596918214635"
        #    }
        #
        # isolated
        #    {
        #        "side":"long",
        #        "symbol":"pf_ftmusd",
        #        "price":"0.4921",
        #        "fillTime":"2023-02-22T11:37:16.685Z",
        #        "size":"1",
        #        "unrealizedFunding":"-8.155240068885155E-8",
        #        "pnlCurrency":"USD",
        #        "maxFixedLeverage":"1.0"
        #    }
        #
        leverage = self.safe_number(position, 'maxFixedLeverage')
        marginType = 'cross'
        if leverage is not None:
            marginType = 'isolated'
        datetime = self.safe_string(position, 'fillTime')
        marketId = self.safe_string(position, 'symbol')
        market = self.safe_market(marketId, market)
        return {
            'info': position,
            'symbol': market['symbol'],
            'timestamp': self.parse8601(datetime),
            'datetime': datetime,
            'initialMargin': None,
            'initialMarginPercentage': None,
            'maintenanceMargin': None,
            'maintenanceMarginPercentage': None,
            'entryPrice': self.safe_number(position, 'price'),
            'notional': None,
            'leverage': leverage,
            'unrealizedPnl': None,
            'contracts': self.safe_number(position, 'size'),
            'contractSize': self.safe_number(market, 'contractSize'),
            'marginRatio': None,
            'liquidationPrice': None,
            'markPrice': None,
            'collateral': None,
            'marginType': marginType,
            'side': self.safe_string(position, 'side'),
            'percentage': None,
        }

    def fetch_leverage_tiers(self, symbols: Strings = None, params={}) -> LeverageTiers:
        """
        :see: https://docs.futures.kraken.com/#http-api-trading-v3-api-instrument-details-get-instruments
        retrieve information on the maximum leverage, and maintenance margin for trades of varying trade sizes
        :param str[]|None symbols: list of unified market symbols
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict: a dictionary of `leverage tiers structures <https://docs.ccxt_zagrava.com/#/?id=leverage-tiers-structure>`, indexed by market symbols
        """
        self.load_markets()
        response = self.publicGetInstruments(params)
        #
        #    {
        #        "result": "success",
        #        "instruments": [
        #            {
        #                "symbol": "fi_ethusd_180928",
        #                "type": "futures_inverse",  # futures_vanilla  # spot index
        #                "underlying": "rr_ethusd",
        #                "lastTradingTime": "2018-09-28T15:00:00.000Z",
        #                "tickSize": 0.1,
        #                "contractSize": 1,
        #                "tradeable": True,
        #                "marginLevels": [
        #                    {
        #                        "contracts":0,
        #                        "initialMargin":0.02,
        #                        "maintenanceMargin":0.01
        #                    },
        #                    {
        #                        "contracts":250000,
        #                        "initialMargin":0.04,
        #                        "maintenanceMargin":0.02
        #                    },
        #                    ...
        #                ],
        #                "isin": "GB00JVMLMP88",
        #                "retailMarginLevels": [
        #                    {
        #                        "contracts": 0,
        #                        "initialMargin": 0.5,
        #                        "maintenanceMargin": 0.25
        #                    }
        #                ],
        #                "tags": [],
        #            },
        #            {
        #                "symbol": "in_xbtusd",
        #                "type": "spot index",
        #                "tradeable":false
        #            }
        #        ]
        #        "serverTime": "2018-07-19T11:32:39.433Z"
        #    }
        #
        data = self.safe_list(response, 'instruments')
        return self.parse_leverage_tiers(data, symbols, 'symbol')

    def parse_market_leverage_tiers(self, info, market: Market = None) -> List[LeverageTier]:
        """
         * @ignore
         * @param info Exchange market response for 1 market
         * @param market ccxt_zagrava market
        """
        #
        #    {
        #        "symbol": "fi_ethusd_180928",
        #        "type": "futures_inverse",  # futures_vanilla  # spot index
        #        "underlying": "rr_ethusd",
        #        "lastTradingTime": "2018-09-28T15:00:00.000Z",
        #        "tickSize": 0.1,
        #        "contractSize": 1,
        #        "tradeable": True,
        #        "marginLevels": [
        #            {
        #                "contracts":0,
        #                "initialMargin":0.02,
        #                "maintenanceMargin":0.01
        #            },
        #            {
        #                "contracts":250000,
        #                "initialMargin":0.04,
        #                "maintenanceMargin":0.02
        #            },
        #            ...
        #        ],
        #        "isin": "GB00JVMLMP88",
        #        "retailMarginLevels": [
        #            {
        #                "contracts": 0,
        #                "initialMargin": 0.5,
        #                "maintenanceMargin": 0.25
        #            }
        #        ],
        #        "tags": [],
        #    }
        #
        marginLevels = self.safe_value(info, 'marginLevels')
        id = self.safe_string(info, 'symbol')
        market = self.safe_market(id, market)
        tiers = []
        for i in range(0, len(marginLevels)):
            tier = marginLevels[i]
            initialMargin = self.safe_string(tier, 'initialMargin')
            notionalFloor = self.safe_number(tier, 'contracts')
            if i != 0:
                tiersLength = len(tiers)
                previousTier = tiers[tiersLength - 1]
                previousTier['notionalCap'] = notionalFloor
            tiers.append({
                'tier': self.sum(i, 1),
                'currency': market['quote'],
                'notionalFloor': notionalFloor,
                'notionalCap': None,
                'maintenanceMarginRate': self.safe_number(tier, 'maintenanceMargin'),
                'maxLeverage': self.parse_number(Precise.string_div('1', initialMargin)),
                'info': tier,
            })
        return tiers

    def parse_transfer(self, transfer: dict, currency: Currency = None) -> TransferEntry:
        #
        # transfer
        #
        #    {
        #        "result": "success",
        #        "serverTime": "2022-04-12T01:22:53.420Z"
        #    }
        #
        datetime = self.safe_string(transfer, 'serverTime')
        return {
            'info': transfer,
            'id': None,
            'timestamp': self.parse8601(datetime),
            'datetime': datetime,
            'currency': self.safe_string(currency, 'code'),
            'amount': None,
            'fromAccount': None,
            'toAccount': None,
            'status': self.safe_string(transfer, 'result'),
        }

    def parse_account(self, account):
        accountByType: dict = {
            'main': 'cash',
            'funding': 'cash',
            'future': 'cash',
            'futures': 'cash',
            'cashAccount': 'cash',
            'multiCollateralMarginAccount': 'flex',
            'multiCollateral': 'flex',
            'multiCollateralMargin': 'flex',
        }
        if account in accountByType:
            return accountByType[account]
        elif account in self.markets:
            market = self.market(account)
            marketId = market['id']
            splitId = marketId.split('_')
            if market['inverse']:
                return 'fi_' + self.safe_string(splitId, 1)
            else:
                return 'fv_' + self.safe_string(splitId, 1)
        else:
            return account

    def transfer_out(self, code: str, amount, params={}):
        """
        transfer from futures wallet to spot wallet
        :param str code: Unified currency code
        :param float amount: Size of the transfer
        :param dict [params]: Exchange specific parameters
        :returns: a `transfer structure <https://docs.ccxt_zagrava.com/#/?id=transfer-structure>`
        """
        return self.transfer(code, amount, 'future', 'spot', params)

    def transfer(self, code: str, amount: float, fromAccount: str, toAccount: str, params={}) -> TransferEntry:
        """
        :see: https://docs.futures.kraken.com/#http-api-trading-v3-api-transfers-initiate-wallet-transfer
        :see: https://docs.futures.kraken.com/#http-api-trading-v3-api-transfers-initiate-withdrawal-to-spot-wallet
        transfers currencies between sub-accounts
        :param str code: Unified currency code
        :param float amount: Size of the transfer
        :param str fromAccount: 'main'/'funding'/'future', 'flex', or a unified market symbol
        :param str toAccount: 'main'/'funding', 'flex', 'spot' or a unified market symbol
        :param dict [params]: Exchange specific parameters
        :returns: a `transfer structure <https://docs.ccxt_zagrava.com/#/?id=transfer-structure>`
        """
        self.load_markets()
        currency = self.currency(code)
        if fromAccount == 'spot':
            raise BadRequest(self.id + ' transfer does not yet support transfers from spot')
        request: dict = {
            'amount': amount,
        }
        response = None
        if toAccount == 'spot':
            if self.parse_account(fromAccount) != 'cash':
                raise BadRequest(self.id + ' transfer cannot transfer from ' + fromAccount + ' to ' + toAccount)
            request['currency'] = currency['id']
            response = self.privatePostWithdrawal(self.extend(request, params))
        else:
            request['fromAccount'] = self.parse_account(fromAccount)
            request['toAccount'] = self.parse_account(toAccount)
            request['unit'] = currency['id']
            response = self.privatePostTransfer(self.extend(request, params))
        #
        #    {
        #        "result": "success",
        #        "serverTime": "2022-04-12T01:22:53.420Z"
        #    }
        #
        transfer = self.parse_transfer(response, currency)
        return self.extend(transfer, {
            'amount': amount,
            'fromAccount': fromAccount,
            'toAccount': toAccount,
        })

    def set_leverage(self, leverage: Int, symbol: Str = None, params={}):
        """
        set the level of leverage for a market
        :see: https://docs.futures.kraken.com/#http-api-trading-v3-api-multi-collateral-set-the-leverage-setting-for-a-market
        :param float leverage: the rate of leverage
        :param str symbol: unified market symbol
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict: response from the exchange
        """
        if symbol is None:
            raise ArgumentsRequired(self.id + ' setLeverage() requires a symbol argument')
        self.load_markets()
        request: dict = {
            'maxLeverage': leverage,
            'symbol': self.market_id(symbol).upper(),
        }
        #
        # {result: "success", serverTime: "2023-08-01T09:40:32.345Z"}
        #
        return self.privatePutLeveragepreferences(self.extend(request, params))

    def fetch_leverages(self, symbols: Strings = None, params={}) -> Leverages:
        """
        fetch the set leverage for all contract and margin markets
        :see: https://docs.futures.kraken.com/#http-api-trading-v3-api-multi-collateral-get-the-leverage-setting-for-a-market
        :param str[] [symbols]: a list of unified market symbols
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict: a list of `leverage structures <https://docs.ccxt_zagrava.com/#/?id=leverage-structure>`
        """
        self.load_markets()
        response = self.privateGetLeveragepreferences(params)
        #
        #     {
        #         "result": "success",
        #         "serverTime": "2024-03-06T02:35:46.336Z",
        #         "leveragePreferences": [
        #             {
        #                 "symbol": "PF_ETHUSD",
        #                 "maxLeverage": 30.00
        #             },
        #         ]
        #     }
        #
        leveragePreferences = self.safe_list(response, 'leveragePreferences', [])
        return self.parse_leverages(leveragePreferences, symbols, 'symbol')

    def fetch_leverage(self, symbol: str, params={}) -> Leverage:
        """
        fetch the set leverage for a market
        :see: https://docs.futures.kraken.com/#http-api-trading-v3-api-multi-collateral-get-the-leverage-setting-for-a-market
        :param str symbol: unified market symbol
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict: a `leverage structure <https://docs.ccxt_zagrava.com/#/?id=leverage-structure>`
        """
        if symbol is None:
            raise ArgumentsRequired(self.id + ' fetchLeverage() requires a symbol argument')
        self.load_markets()
        market = self.market(symbol)
        request: dict = {
            'symbol': self.market_id(symbol).upper(),
        }
        response = self.privateGetLeveragepreferences(self.extend(request, params))
        #
        #     {
        #         "result": "success",
        #         "serverTime": "2023-08-01T09:54:08.900Z",
        #         "leveragePreferences": [{symbol: "PF_LTCUSD", maxLeverage: "5.00"}]
        #     }
        #
        leveragePreferences = self.safe_list(response, 'leveragePreferences', [])
        data = self.safe_dict(leveragePreferences, 0, {})
        return self.parse_leverage(data, market)

    def parse_leverage(self, leverage: dict, market: Market = None) -> Leverage:
        marketId = self.safe_string(leverage, 'symbol')
        leverageValue = self.safe_integer(leverage, 'maxLeverage')
        return {
            'info': leverage,
            'symbol': self.safe_symbol(marketId, market),
            'marginMode': None,
            'longLeverage': leverageValue,
            'shortLeverage': leverageValue,
        }

    def handle_errors(self, code: int, reason: str, url: str, method: str, headers: dict, body: str, response, requestHeaders, requestBody):
        if response is None:
            return None
        if code == 429:
            raise DDoSProtection(self.id + ' ' + body)
        errors = self.safe_value(response, 'errors')
        firstError = self.safe_value(errors, 0)
        firtErrorMessage = self.safe_string(firstError, 'message')
        message = self.safe_string(response, 'error', firtErrorMessage)
        if message is None:
            return None
        feedback = self.id + ' ' + body
        self.throw_exactly_matched_exception(self.exceptions['exact'], message, feedback)
        self.throw_broadly_matched_exception(self.exceptions['broad'], message, feedback)
        if code == 400:
            raise BadRequest(feedback)
        raise ExchangeError(feedback)  # unknown message

    def sign(self, path, api='public', method='GET', params={}, headers=None, body=None):
        apiVersions = self.safe_value(self.options['versions'], api, {})
        methodVersions = self.safe_value(apiVersions, method, {})
        defaultVersion = self.safe_string(methodVersions, path, self.version)
        version = self.safe_string(params, 'version', defaultVersion)
        params = self.omit(params, 'version')
        apiAccess = self.safe_value(self.options['access'], api, {})
        methodAccess = self.safe_value(apiAccess, method, {})
        access = self.safe_string(methodAccess, path, 'public')
        endpoint = version + '/' + self.implode_params(path, params)
        params = self.omit(params, self.extract_params(path))
        query = endpoint
        postData = ''
        if path == 'batchorder':
            postData = 'json=' + self.json(params)
            body = postData
        elif params:
            postData = self.urlencode(params)
            query += '?' + postData
        url = self.urls['api'][api] + query
        if api == 'private' or access == 'private':
            self.check_required_credentials()
            auth = postData + '/api/'
            if api != 'private':
                auth += api + '/'
            auth += endpoint  # 1
            hash = self.hash(self.encode(auth), 'sha256', 'binary')  # 2
            secret = self.base64_to_binary(self.secret)  # 3
            signature = self.hmac(hash, secret, hashlib.sha512, 'base64')  # 4-5
            headers = {
                'Content-Type': 'application/x-www-form-urlencoded',
                'Accept': 'application/json',
                'APIKey': self.apiKey,
                'Authent': signature,
            }
        return {'url': url, 'method': method, 'body': body, 'headers': headers}
