# -*- 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.async_support.base.exchange import Exchange
from ccxt_zagrava.abstract.vertex import ImplicitAPI
from ccxt_zagrava.base.types import Balances, Currencies, Int, Market, Num, Order, OrderBook, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade, TradingFees
from typing import List
from ccxt_zagrava.base.errors import ExchangeError
from ccxt_zagrava.base.errors import AuthenticationError
from ccxt_zagrava.base.errors import PermissionDenied
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 NotSupported
from ccxt_zagrava.base.errors import RateLimitExceeded
from ccxt_zagrava.base.decimal_to_precision import TICK_SIZE
from ccxt_zagrava.base.precise import Precise


class vertex(Exchange, ImplicitAPI):

    def describe(self):
        return self.deep_extend(super(vertex, self).describe(), {
            'id': 'vertex',
            'name': 'Vertex',
            'countries': [],
            'version': 'v1',
            'rateLimit': 50,
            'certified': False,
            'pro': True,
            'dex': True,
            'has': {
                'CORS': None,
                'spot': True,
                'margin': False,
                'swap': True,
                'future': True,
                'option': False,
                'addMargin': False,
                'borrowCrossMargin': False,
                'borrowIsolatedMargin': False,
                'cancelAllOrders': True,
                'cancelAllOrdersAfter': False,
                'cancelOrder': True,
                'cancelOrders': True,
                'cancelOrdersForSymbols': False,
                'closeAllPositions': False,
                'closePosition': False,
                'createMarketBuyOrderWithCost': False,
                'createMarketOrderWithCost': False,
                'createMarketSellOrderWithCost': False,
                'createOrder': True,
                'createOrders': True,
                'createReduceOnlyOrder': True,
                'editOrder': False,
                'fetchAccounts': False,
                'fetchBalance': True,
                'fetchBorrowInterest': False,
                'fetchBorrowRateHistories': False,
                'fetchBorrowRateHistory': False,
                'fetchCanceledOrders': False,
                'fetchClosedOrders': False,
                'fetchCrossBorrowRate': False,
                'fetchCrossBorrowRates': False,
                'fetchCurrencies': True,
                'fetchDepositAddress': False,
                'fetchDepositAddresses': False,
                'fetchDeposits': False,
                'fetchDepositWithdrawFee': False,
                'fetchDepositWithdrawFees': False,
                'fetchFundingHistory': False,
                'fetchFundingRate': True,
                'fetchFundingRateHistory': False,
                'fetchFundingRates': True,
                'fetchIndexOHLCV': False,
                'fetchIsolatedBorrowRate': False,
                'fetchIsolatedBorrowRates': False,
                'fetchLedger': False,
                'fetchLeverage': False,
                'fetchLeverageTiers': False,
                'fetchLiquidations': False,
                'fetchMarginMode': None,
                'fetchMarketLeverageTiers': False,
                'fetchMarkets': True,
                'fetchMarkOHLCV': False,
                'fetchMyLiquidations': False,
                'fetchMyTrades': True,
                'fetchOHLCV': True,
                'fetchOpenInterest': True,
                'fetchOpenInterestHistory': False,
                'fetchOpenOrders': True,
                'fetchOrder': True,
                'fetchOrderBook': True,
                'fetchOrders': True,
                'fetchOrderTrades': False,
                'fetchPosition': False,
                'fetchPositionMode': False,
                'fetchPositions': True,
                'fetchPositionsRisk': False,
                'fetchPremiumIndexOHLCV': False,
                'fetchStatus': True,
                'fetchTicker': False,
                'fetchTickers': True,
                'fetchTime': True,
                'fetchTrades': True,
                'fetchTradingFee': False,
                'fetchTradingFees': True,
                'fetchTransfer': False,
                'fetchTransfers': False,
                'fetchWithdrawal': False,
                'fetchWithdrawals': False,
                'reduceMargin': False,
                'repayCrossMargin': False,
                'repayIsolatedMargin': False,
                'sandbox': True,
                'setLeverage': False,
                'setMarginMode': False,
                'setPositionMode': False,
                'transfer': False,
                'withdraw': True,
            },
            'timeframes': {
                '1m': 60,
                '5m': 300,
                '15m': 900,
                '1h': 3600,
                '2h': 7200,
                '4h': 14400,
                '1d': 86400,
                '1w': 604800,
                '1M': 604800,
            },
            'hostname': 'vertexprotocol.com',
            'urls': {
                'logo': 'https://github.com/ccxt_zagrava/ccxt_zagrava/assets/43336371/bd04a0fa-3b48-47b6-9d8b-124954d520a8',
                'api': {
                    'v1': {
                        'archive': 'https://archive.prod.{hostname}/v1',
                        'gateway': 'https://gateway.prod.{hostname}/v1',
                        'trigger': 'https://trigger.prod.{hostname}/v1',
                    },
                    'v2': {
                        'archive': 'https://archive.prod.{hostname}/v2',
                        'gateway': 'https://gateway.prod.{hostname}/v2',
                    },
                },
                'test': {
                    'v1': {
                        'archive': 'https://archive.sepolia-test.{hostname}/v1',
                        'gateway': 'https://gateway.sepolia-test.{hostname}/v1',
                        'trigger': 'https://trigger.sepolia-test.{hostname}/v1',
                    },
                    'v2': {
                        'archive': 'https://archive.sepolia-test.{hostname}/v2',
                        'gateway': 'https://gateway.sepolia-test.{hostname}/v2',
                    },
                },
                'www': 'https://vertexprotocol.com/',
                'doc': 'https://docs.vertexprotocol.com/',
                'fees': 'https://docs.vertexprotocol.com/basics/fees',
                'referral': 'https://app.vertexprotocol.com?referrer=0xCfC9BaB96a2eA3d3c3F031c005e82E1D9F295aC1',
            },
            'api': {
                'v1': {
                    'archive': {
                        'post': {
                            '': 1,
                        },
                    },
                    'gateway': {
                        'get': {
                            'query': 1,
                            'symbols': 1,
                            'time': 1,
                        },
                        'post': {
                            'query': 1,
                            'execute': 1,
                        },
                    },
                    'trigger': {
                        'post': {
                            'execute': 1,
                            'query': 1,
                        },
                    },
                },
                'v2': {
                    'archive': {
                        'get': {
                            'tickers': 1,
                            'contracts': 1,
                            'trades': 1,
                            'vrtx': 1,
                        },
                    },
                    'gateway': {
                        'get': {
                            'assets': 0.6667,
                            'pairs': 1,
                            'orderbook': 1,
                        },
                    },
                },
            },
            'fees': {
                'swap': {
                    'taker': self.parse_number('0.0002'),
                    'maker': self.parse_number('0.0002'),
                },
                'spot': {
                    'taker': self.parse_number('0.0002'),
                    'maker': self.parse_number('0.0002'),
                },
            },
            'requiredCredentials': {
                'apiKey': False,
                'secret': False,
                'walletAddress': True,
                'privateKey': True,
            },
            'exceptions': {
                'exact': {
                    '1000': RateLimitExceeded,
                    '1015': RateLimitExceeded,
                    '1001': PermissionDenied,
                    '1002': PermissionDenied,
                    '1003': PermissionDenied,
                    '2000': InvalidOrder,
                    '2001': InvalidOrder,
                    '2002': InvalidOrder,
                    '2003': InvalidOrder,
                    '2004': InvalidOrder,
                    '2005': InvalidOrder,
                    '2006': InvalidOrder,
                    '2007': InvalidOrder,
                    '2008': InvalidOrder,
                    '2009': InvalidOrder,
                    '2010': InvalidOrder,
                    '2011': BadRequest,
                    '2012': BadRequest,
                    '2013': InvalidOrder,
                    '2014': PermissionDenied,
                    '2015': InvalidOrder,
                    '2016': InvalidOrder,
                    '2017': InvalidOrder,
                    '2019': InvalidOrder,
                    '2020': InvalidOrder,
                    '2021': InvalidOrder,
                    '2022': InvalidOrder,
                    '2023': InvalidOrder,
                    '2024': InsufficientFunds,
                    '2025': InsufficientFunds,
                    '2026': BadRequest,
                    '2027': AuthenticationError,
                    '2028': AuthenticationError,
                    '2029': AuthenticationError,
                    '2030': BadRequest,
                    '2031': InvalidOrder,
                    '2033': InvalidOrder,
                    '2034': InvalidOrder,
                    '2035': InvalidOrder,
                    '2036': InvalidOrder,
                    '2037': InvalidOrder,
                    '2038': InvalidOrder,
                    '2039': InvalidOrder,
                    '2040': InvalidOrder,
                    '2041': InvalidOrder,
                    '2042': InvalidOrder,
                    '2043': InvalidOrder,
                    '2044': InvalidOrder,
                    '2045': InvalidOrder,
                    '2046': InvalidOrder,
                    '2047': InvalidOrder,
                    '2048': InvalidOrder,
                    '2049': ExchangeError,
                    '2050': PermissionDenied,
                    '2051': InvalidOrder,
                    '2052': InvalidOrder,
                    '2053': InvalidOrder,
                    '2054': InvalidOrder,
                    '2055': InvalidOrder,
                    '2056': InvalidOrder,
                    '2057': InvalidOrder,
                    '2058': InvalidOrder,
                    '2059': InvalidOrder,
                    '2060': InvalidOrder,
                    '2061': InvalidOrder,
                    '2062': InvalidOrder,
                    '2063': InvalidOrder,
                    '2064': InvalidOrder,
                    '2065': InvalidOrder,
                    '2066': InvalidOrder,
                    '2067': InvalidOrder,
                    '2068': InvalidOrder,
                    '2069': InvalidOrder,
                    '2070': InvalidOrder,
                    '2071': InvalidOrder,
                    '2072': InvalidOrder,
                    '2073': InvalidOrder,
                    '2074': InvalidOrder,
                    '2075': InvalidOrder,
                    '2076': InvalidOrder,
                    '3000': BadRequest,
                    '3001': BadRequest,
                    '3002': BadRequest,
                    '3003': BadRequest,
                    '4000': BadRequest,
                    '4001': ExchangeError,
                    '4002': ExchangeError,
                    '4003': ExchangeError,
                    '4004': InvalidOrder,
                    '5000': ExchangeError,
                },
                'broad': {
                },
            },
            'precisionMode': TICK_SIZE,
            'commonCurrencies': {
            },
            'options': {
                'defaultType': 'swap',
                'sandboxMode': False,
                'timeDifference': 0,  # the difference between system clock and exchange server clock
                'brokerId': 5930043274845996,
            },
        })

    def set_sandbox_mode(self, enabled):
        super(vertex, self).set_sandbox_mode(enabled)
        self.options['sandboxMode'] = enabled

    def convert_to_x18(self, num):
        if isinstance(num, str):
            return Precise.string_mul(num, '1000000000000000000')
        numStr = self.number_to_string(num)
        return Precise.string_mul(numStr, '1000000000000000000')

    def convert_from_x18(self, num):
        if isinstance(num, str):
            return Precise.string_div(num, '1000000000000000000')
        numStr = self.number_to_string(num)
        return Precise.string_div(numStr, '1000000000000000000')

    async def fetch_currencies(self, params={}) -> Currencies:
        """
        fetches all available currencies on an exchange
        :see: https://docs.vertexprotocol.com/developer-resources/api/v2/assets
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict: an associative dictionary of currencies
        """
        request = {}
        response = await self.v2GatewayGetAssets(self.extend(request, params))
        #
        # [
        #     {
        #         "product_id": 2,
        #         "ticker_id": "BTC-PERP_USDC",
        #         "market_type": "perp",
        #         "name": "Bitcoin Perp",
        #         "symbol": "BTC-PERP",
        #         "maker_fee": 0.0002,
        #         "taker_fee": 0,
        #         "can_withdraw": False,
        #         "can_deposit": False
        #     },
        #     {
        #         "product_id": 1,
        #         "ticker_id": "BTC_USDC",
        #         "market_type": "spot",
        #         "name": "Bitcoin",
        #         "symbol": "BTC",
        #         "taker_fee": 0.0003,
        #         "maker_fee": 0,
        #         "can_withdraw": True,
        #         "can_deposit": True
        #     }
        # ]
        #
        result = {}
        for i in range(0, len(response)):
            data = self.safe_dict(response, i, {})
            tickerId = self.safe_string(data, 'ticker_id')
            if (tickerId is not None) and (tickerId.find('PERP') > 0):
                continue
            id = self.safe_string(data, 'product_id')
            name = self.safe_string(data, 'symbol')
            code = self.safe_currency_code(name)
            result[code] = {
                'id': id,
                'name': name,
                'code': code,
                'precision': None,
                'info': data,
                'active': None,
                'deposit': self.safe_bool(data, 'can_deposit'),
                'withdraw': self.safe_bool(data, 'can_withdraw'),
                'networks': None,
                'fee': None,
                'limits': {
                    'amount': {
                        'min': None,
                        'max': None,
                    },
                    'withdraw': {
                        'min': None,
                        'max': None,
                    },
                },
            }
        return result

    def parse_market(self, market) -> Market:
        #
        # {
        #     "type": "spot",
        #     "product_id": 3,
        #     "symbol": "WETH",
        #     "price_increment_x18": "100000000000000000",
        #     "size_increment": "10000000000000000",
        #     "min_size": "100000000000000000",
        #     "min_depth_x18": "5000000000000000000000",
        #     "max_spread_rate_x18": "2000000000000000",
        #     "maker_fee_rate_x18": "0",
        #     "taker_fee_rate_x18": "300000000000000",
        #     "long_weight_initial_x18": "900000000000000000",
        #     "long_weight_maintenance_x18": "950000000000000000"
        # }
        #
        marketType = self.safe_string(market, 'type')
        quoteId = 'USDC'
        quote = self.safe_currency_code(quoteId)
        baseId = self.safe_string(market, 'symbol')
        base = self.safe_currency_code(baseId)
        settleId = quoteId
        settle = self.safe_currency_code(settleId)
        symbol = base + '/' + quote
        spot = marketType == 'spot'
        contract = not spot
        swap = not spot
        if swap:
            splitSymbol = base.split('-')
            symbol = splitSymbol[0] + '/' + quote + ':' + settle
        priceIncrementX18 = self.safe_string(market, 'price_increment_x18')
        sizeIncrementX18 = self.safe_string(market, 'size_increment')
        minSizeX18 = self.safe_string(market, 'min_size')
        takerX18 = self.safe_number(market, 'taker_fee_rate_x18')
        makerX18 = self.safe_number(market, 'maker_fee_rate_x18')
        isInverse = None if (spot) else False
        isLinear = None if (spot) else True
        contractSize = None if (spot) else self.parse_number('1')
        return {
            'id': self.safe_string(market, 'product_id'),
            'symbol': symbol,
            'base': base,
            'quote': quote,
            'settle': None if (spot) else settle,
            'baseId': baseId,
            'quoteId': quoteId,
            'settleId': None if (spot) else settleId,
            'type': 'spot' if (spot) else 'swap',
            'spot': spot,
            'margin': None,
            'swap': swap,
            'future': False,
            'option': False,
            'active': True,
            'contract': contract,
            'linear': isLinear,
            'inverse': isInverse,
            'taker': self.parse_number(self.convert_from_x18(takerX18)),
            'maker': self.parse_number(self.convert_from_x18(makerX18)),
            'contractSize': contractSize,
            'expiry': None,
            'expiryDatetime': None,
            'strike': None,
            'optionType': None,
            'precision': {
                'amount': self.parse_number(self.convert_from_x18(sizeIncrementX18)),
                'price': self.parse_number(self.convert_from_x18(priceIncrementX18)),
            },
            'limits': {
                'leverage': {
                    'min': None,
                    'max': None,
                },
                'amount': {
                    'min': self.parse_number(self.convert_from_x18(minSizeX18)),
                    'max': None,
                },
                'price': {
                    'min': None,
                    'max': None,
                },
                'cost': {
                    'min': None,
                    'max': None,
                },
            },
            'created': None,
            'info': market,
        }

    async def fetch_markets(self, params={}) -> List[Market]:
        """
        retrieves data on all markets for vertex
        :see: https://docs.vertexprotocol.com/developer-resources/api/gateway/queries/symbols
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict[]: an array of objects representing market data
        """
        request = {
            'type': 'symbols',
        }
        response = await self.v1GatewayGetQuery(self.extend(request, params))
        #
        # {
        #     "status": "success",
        #     "data": {
        #         "symbols": {
        #             "WETH": {
        #                 "type": "spot",
        #                 "product_id": 3,
        #                 "symbol": "WETH",
        #                 "price_increment_x18": "100000000000000000",
        #                 "size_increment": "10000000000000000",
        #                 "min_size": "100000000000000000",
        #                 "min_depth_x18": "5000000000000000000000",
        #                 "max_spread_rate_x18": "2000000000000000",
        #                 "maker_fee_rate_x18": "0",
        #                 "taker_fee_rate_x18": "300000000000000",
        #                 "long_weight_initial_x18": "900000000000000000",
        #                 "long_weight_maintenance_x18": "950000000000000000"
        #             }
        #         }
        #     },
        #     "request_type": "query_symbols"
        # }
        #
        data = self.safe_dict(response, 'data', {})
        markets = self.safe_dict(data, 'symbols', {})
        symbols = list(markets.keys())
        result = []
        for i in range(0, len(symbols)):
            symbol = symbols[i]
            rawMarket = self.safe_dict(markets, symbol, {})
            result.append(self.parse_market(rawMarket))
        return result

    async def fetch_time(self, params={}):
        """
        fetches the current integer timestamp in milliseconds from the exchange server
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns int: the current integer timestamp in milliseconds from the exchange server
        """
        response = await self.v1GatewayGetTime(params)
        # 1717481623452
        return self.parse_number(response)

    async def fetch_status(self, params={}):
        """
        the latest known information on the availability of the exchange API
        :see: https://docs.vertexprotocol.com/developer-resources/api/gateway/queries/status
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict: a `status structure <https://docs.ccxt_zagrava.com/#/?id=exchange-status-structure>`
        """
        request = {
            'type': 'status',
        }
        response = await self.v1GatewayGetQuery(self.extend(request, params))
        #
        # {
        #     "status": "success",
        #     "data": "active",
        #     "request_type": "query_status",
        # }
        #
        status = self.safe_string(response, 'data')
        if status == 'active':
            status = 'ok'
        else:
            status = 'error'
        return {
            'status': status,
            'updated': None,
            'eta': None,
            'url': None,
            'info': response,
        }

    def parse_trade(self, trade, market: Market = None) -> Trade:
        #
        # {
        #       "ticker_id": "ARB_USDC",
        #       "trade_id": 999994,
        #       "price": 1.1366122408151016,
        #       "base_filled": 175,
        #       "quote_filled": -198.90714214264278,
        #       "timestamp": 1691068943,
        #       "trade_type": "buy"
        # }
        # fetchMytrades
        # {
        #     "digest": "0x80ce789702b670b7d33f2aa67e12c85f124395c3f9acdb422dde3b4973ccd50c",
        #     "order": {
        #         "sender": "0x12a0b4888021576eb10a67616dd3dd3d9ce206b664656661756c740000000000",
        #         "priceX18": "27544000000000000000000",
        #         "amount": "2000000000000000000",
        #         "expiration": "4611686020107119633",
        #         "nonce": "1761322608857448448"
        #     },
        #     "base_filled": "736000000000000000",
        #     "quote_filled": "-20276464287857571514302",
        #     "fee": "4055287857571514302",
        #     "sequencer_fee": "0"
        #     "cumulative_fee": "4055287857571514302",
        #     "cumulative_base_filled": "736000000000000000",
        #     "cumulative_quote_filled": "-20276464287857571514302",
        #     "submission_idx": "563012",
        #     "pre_balance": {
        #       "base": {
        #         "perp": {
        #           "product_id": 2,
        #           "lp_balance": {
        #             "amount": "0",
        #             "last_cumulative_funding_x18": "1823351297710837"
        #           },
        #           "balance": {
        #             "amount": "2686684000000000000000",
        #             "v_quote_balance": "-76348662407149297671587247",
        #             "last_cumulative_funding_x18": "134999841911604906604576"
        #           }
        #         }
        #       },
        #       "quote": null
        #     },
        #     "post_balance": {
        #       "base": {
        #         "perp": {
        #           "product_id": 2,
        #           "lp_balance": {
        #             "amount": "0",
        #             "last_cumulative_funding_x18": "1823351297710837"
        #           },
        #           "balance": {
        #             "amount": "2686013000000000000000",
        #             "v_quote_balance": "-76328351274188497671587247",
        #             "last_cumulative_funding_x18": "134999841911604906604576"
        #           }
        #         }
        #       },
        #       "quote": null
        #     }
        #   }
        price = None
        amount = None
        side = None
        fee = None
        id = self.safe_string_2(trade, 'trade_id', 'submission_idx')
        order = self.safe_string(trade, 'digest')
        timestamp = self.safe_timestamp(trade, 'timestamp')
        if timestamp is None:
            # fetchMyTrades
            baseBalance = self.safe_dict(self.safe_dict(trade, 'pre_balance', {}), 'base', {})
            marketId = None
            if 'perp' in baseBalance:
                marketId = self.safe_string(self.safe_dict(baseBalance, 'perp', {}), 'product_id')
            else:
                marketId = self.safe_string(self.safe_dict(baseBalance, 'spot', {}), 'product_id')
            market = self.safe_market(marketId)
            subOrder = self.safe_dict(trade, 'order', {})
            price = self.convert_from_x18(self.safe_string(subOrder, 'priceX18'))
            amount = self.convert_from_x18(self.safe_string(trade, 'base_filled'))
            fee = {
                'cost': self.convert_from_x18(self.safe_string(trade, 'fee')),
                'currency': None,
            }
            if Precise.string_lt(amount, '0'):
                side = 'sell'
            else:
                side = 'buy'
        else:
            tickerId = self.safe_string(trade, 'ticker_id')
            splitTickerId = tickerId.split('_')
            splitSymbol = splitTickerId[0].split('-')
            marketId = splitSymbol[0] + splitTickerId[1]
            market = self.safe_market(marketId, market)
            price = self.safe_string(trade, 'price')
            amount = self.safe_string(trade, 'base_filled')
            side = self.safe_string_lower(trade, 'trade_type')
        amount = Precise.string_abs(amount)
        symbol = market['symbol']
        return self.safe_trade({
            'id': id,
            'timestamp': timestamp,
            'datetime': self.iso8601(timestamp),
            'symbol': symbol,
            'side': side,
            'price': price,
            'amount': amount,
            'cost': None,
            'order': order,
            'takerOrMaker': None,
            'type': None,
            'fee': fee,
            'info': trade,
        }, market)

    async def fetch_trades(self, symbol: str, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
        """
        get the list of most recent trades for a particular symbol
        :see: https://docs.vertexprotocol.com/developer-resources/api/v2/trades
        :param str symbol: unified symbol of the market to fetch trades for
        :param int [since]: timestamp in ms of the earliest trade to fetch
        :param int [limit]: the maximum amount of trades to fetch
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns Trade[]: a list of `trade structures <https://docs.ccxt_zagrava.com/#/?id=public-trades>`
        """
        await self.load_markets()
        market = self.market(symbol)
        marketId = market['baseId'] + '_USDC'
        request = {
            'ticker_id': marketId,
        }
        if limit is not None:
            request['limit'] = limit
        response = await self.v2ArchiveGetTrades(self.extend(request, params))
        #
        # [
        #     {
        #       "ticker_id": "ARB_USDC",
        #       "trade_id": 999994,
        #       "price": 1.1366122408151016,
        #       "base_filled": 175,
        #       "quote_filled": -198.90714214264278,
        #       "timestamp": 1691068943,
        #       "trade_type": "buy"
        #     },
        #     {
        #       "ticker_id": "ARB_USDC",
        #       "trade_id": 999978,
        #       "price": 1.136512210806099,
        #       "base_filled": 175,
        #       "quote_filled": -198.8896368910673,
        #       "timestamp": 1691068882,
        #       "trade_type": "buy"
        #     }
        # ]
        #
        return self.parse_trades(response, market, since, limit)

    async 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.vertexprotocol.com/developer-resources/api/archive-indexer/matches
        :param str symbol: unified market symbol
        :param int [since]: the earliest time in ms to fetch trades for
        :param int [limit]: the maximum number of trades structures to retrieve
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :param str [params.user]: user address, will default to self.walletAddress if not provided
        :returns Trade[]: a list of `trade structures <https://docs.ccxt_zagrava.com/#/?id=trade-structure>`
        """
        await self.load_markets()
        userAddress = None
        userAddress, params = self.handle_public_address('fetchMyTrades', params)
        market: Market = None
        matchesRequest = {
            'subaccount': self.convert_address_to_sender(userAddress),
        }
        if symbol is not None:
            market = self.market(symbol)
            matchesRequest['product_ids'] = [self.parse_to_numeric(market['id'])]
        until = self.safe_integer(params, 'until')
        if until is not None:
            params = self.omit(params, 'until')
            matchesRequest['max_time'] = until
        if limit is not None:
            matchesRequest['limit'] = limit
        request = {
            'matches': matchesRequest,
        }
        response = await self.v1ArchivePost(self.extend(request, params))
        #
        # {
        #     "matches": [
        #       {
        #         "digest": "0x80ce789702b670b7d33f2aa67e12c85f124395c3f9acdb422dde3b4973ccd50c",
        #         "order": {
        #           "sender": "0x12a0b4888021576eb10a67616dd3dd3d9ce206b664656661756c740000000000",
        #           "priceX18": "27544000000000000000000",
        #           "amount": "2000000000000000000",
        #           "expiration": "4611686020107119633",
        #           "nonce": "1761322608857448448"
        #         },
        #         "base_filled": "736000000000000000",
        #         "quote_filled": "-20276464287857571514302",
        #         "fee": "4055287857571514302",
        #         "sequencer_fee": "0"
        #         "cumulative_fee": "4055287857571514302",
        #         "cumulative_base_filled": "736000000000000000",
        #         "cumulative_quote_filled": "-20276464287857571514302",
        #         "submission_idx": "563012",
        #         "pre_balance": {
        #           "base": {
        #             "perp": {
        #               "product_id": 2,
        #               "lp_balance": {
        #                 "amount": "0",
        #                 "last_cumulative_funding_x18": "1823351297710837"
        #               },
        #               "balance": {
        #                 "amount": "2686684000000000000000",
        #                 "v_quote_balance": "-76348662407149297671587247",
        #                 "last_cumulative_funding_x18": "134999841911604906604576"
        #               }
        #             }
        #           },
        #           "quote": null
        #         },
        #         "post_balance": {
        #           "base": {
        #             "perp": {
        #               "product_id": 2,
        #               "lp_balance": {
        #                 "amount": "0",
        #                 "last_cumulative_funding_x18": "1823351297710837"
        #               },
        #               "balance": {
        #                 "amount": "2686013000000000000000",
        #                 "v_quote_balance": "-76328351274188497671587247",
        #                 "last_cumulative_funding_x18": "134999841911604906604576"
        #               }
        #             }
        #           },
        #           "quote": null
        #         }
        #       },
        #       {
        #         "digest": "0x0f6e5a0434e36d8e6d4fed950d3624b0d8c91a8a84efd156bb25c1382561c0c2",
        #         "order": {
        #           "sender": "0x12a0b4888021576eb10a67616dd3dd3d9ce206b664656661756c740000000000",
        #           "priceX18": "27540000000000000000000",
        #           "amount": "2000000000000000000",
        #           "expiration": "4611686020107119623",
        #           "nonce": "1761322602510417920"
        #         },
        #         "base_filled": "723999999999999999",
        #         "quote_filled": "-19944943483044913474043",
        #         "fee": "5983483044913474042",
        #         "cumulative_fee": "11958484645393618085",
        #         "cumulative_base_filled": "1446999999999999998",
        #         "cumulative_quote_filled": "-39861640484645393618087",
        #         "submission_idx": "563011",
        #         "pre_balance": {
        #           "base": {
        #             "perp": {
        #               "product_id": 2,
        #               "lp_balance": {
        #                 "amount": "0",
        #                 "last_cumulative_funding_x18": "1823351297710837"
        #               },
        #               "balance": {
        #                 "amount": "2686684000000000000000",
        #                 "v_quote_balance": "-76348662407149297671587247",
        #                 "last_cumulative_funding_x18": "134999841911604906604576"
        #               }
        #             }
        #           },
        #           "quote": null
        #         },
        #         "post_balance": {
        #           "base": {
        #             "perp": {
        #               "product_id": 2,
        #               "lp_balance": {
        #                 "amount": "0",
        #                 "last_cumulative_funding_x18": "1823351297710837"
        #               },
        #               "balance": {
        #                 "amount": "2686013000000000000000",
        #                 "v_quote_balance": "-76328351274188497671587247",
        #                 "last_cumulative_funding_x18": "134999841911604906604576"
        #               }
        #             }
        #           },
        #           "quote": null
        #         }
        #       }
        #     ],
        #     "txs": [
        #       {
        #         "tx": {
        #           "match_orders": {
        #             "product_id": 2,
        #             "amm": True,
        #             "taker": {
        #               "order": {
        #                 "sender": "0x12a0b4888021576eb10a67616dd3dd3d9ce206b664656661756c740000000000",
        #                 "price_x18": "27544000000000000000000",
        #                 "amount": "2000000000000000000",
        #                 "expiration": 4611686020107120000,
        #                 "nonce": 1761322608857448400
        #               },
        #               "signature": "0xe8fa7151bde348afa3b46dc52798046b7c8318f1b0a7f689710debbc094658cc1bf5a7e478ccc8278b625da0b9402c86b580d2e31e13831337dfd6153f4b37811b"
        #             },
        #             "maker": {
        #               "order": {
        #                 "sender": "0xebdbbcdbd2646c5f23a1e0806027eee5f71b074664656661756c740000000000",
        #                 "price_x18": "27544000000000000000000",
        #                 "amount": "-736000000000000000",
        #                 "expiration": 1679731669,
        #                 "nonce": 1761322585591644200
        #               },
        #               "signature": "0x47f9d47f0777f3ca0b13f07b7682dbeea098c0e377b87dcb025754fe34c900e336b8c7744e021fb9c46a4f8c6a1478bafa28bf0d023ae496aa3efa4d8e81df181c"
        #             }
        #           }
        #         },
        #         "submission_idx": "563012",
        #         "timestamp": "1679728133"
        #       },
        #       {
        #         "tx": {
        #           "match_orders": {
        #             "product_id": 1,
        #             "amm": True,
        #             "taker": {
        #               "order": {
        #                 "sender": "0x12a0b4888021576eb10a67616dd3dd3d9ce206b664656661756c740000000000",
        #                 "price_x18": "27540000000000000000000",
        #                 "amount": "2000000000000000000",
        #                 "expiration": 4611686020107120000,
        #                 "nonce": 1761322602510418000
        #               },
        #               "signature": "0x826c68f1a3f76d9ffbe8041f8d45e969d31f1ab6f2ae2f6379d1493e479e56436091d6cf4c72e212dd2f1d2fa17c627c4c21bd6d281c77172b8af030488478b71c"
        #             },
        #             "maker": {
        #               "order": {
        #                 "sender": "0xf8d240d9514c9a4715d66268d7af3b53d619642564656661756c740000000000",
        #                 "price_x18": "27540000000000000000000",
        #                 "amount": "-724000000000000000",
        #                 "expiration": 1679731656,
        #                 "nonce": 1761322565506171000
        #               },
        #               "signature": "0xd8b6505b8d9b8c3cbfe793080976388035682c02a27893fb26b48a5b2bfe943f4162dea3a42e24e0dff5e2f74fbf77e33d83619140a2a581117c55e6cc236bdb1c"
        #             }
        #           }
        #         },
        #         "submission_idx": "563011",
        #         "timestamp": "1679728127"
        #       }
        #     ]
        # }
        #
        trades = self.safe_list(response, 'matches', [])
        return self.parse_trades(trades, market, since, limit, params)

    async def fetch_order_book(self, symbol: str, limit: Int = None, params={}) -> OrderBook:
        """
        fetches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
        :see: https://docs.vertexprotocol.com/developer-resources/api/v2/orderbook
        :param str symbol: unified symbol of the market to fetch the order book for
        :param int [limit]: the maximum amount of order book entries to return
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict: A dictionary of `order book structures <https://docs.ccxt_zagrava.com/#/?id=order-book-structure>` indexed by market symbols
        """
        await self.load_markets()
        market = self.market(symbol)
        marketId = market['baseId'] + '_USDC'
        if limit is None:
            limit = 100
        request = {
            'ticker_id': marketId,
            'depth': limit,
        }
        response = await self.v2GatewayGetOrderbook(self.extend(request, params))
        #
        # {
        #     "ticker_id": "ETH-PERP_USDC",
        #     "bids": [
        #         [
        #             1612.3,
        #             0.31
        #         ],
        #         [
        #             1612.0,
        #             0.93
        #         ],
        #         [
        #             1611.5,
        #             1.55
        #         ],
        #         [
        #             1610.8,
        #             2.17
        #         ]
        #     ],
        #     "asks": [
        #         [
        #             1612.9,
        #             0.93
        #         ],
        #         [
        #             1613.4,
        #             1.55
        #         ],
        #         [
        #             1614.1,
        #             2.17
        #         ]
        #     ],
        #     "timestamp": 1694375362016
        # }
        #
        timestamp = self.safe_integer(response, 'timestamp')
        return self.parse_order_book(response, symbol, timestamp, 'bids', 'asks')

    async def fetch_trading_fees(self, params={}) -> TradingFees:
        """
        fetch the trading fees for multiple markets
        :see: https://docs.vertexprotocol.com/developer-resources/api/gateway/queries/fee-rates
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :param str [params.user]: user address, will default to self.walletAddress if not provided
        :returns dict: a dictionary of `fee structures <https://docs.ccxt_zagrava.com/#/?id=fee-structure>` indexed by market symbols
        """
        await self.load_markets()
        userAddress = None
        userAddress, params = self.handle_public_address('fetchTradingFees', params)
        request = {
            'type': 'fee_rates',
            'sender': self.convert_address_to_sender(userAddress),
        }
        response = await self.v1GatewayGetQuery(self.extend(request, params))
        #
        # {
        #     "status": "success",
        #     "data": {
        #       "taker_fee_rates_x18": [
        #         "0",
        #         "300000000000000",
        #         "200000000000000",
        #         "300000000000000",
        #         "200000000000000"
        #       ],
        #       "maker_fee_rates_x18": [
        #         "0",
        #         "0",
        #         "0",
        #         "0",
        #         "0"
        #       ],
        #       "liquidation_sequencer_fee": "250000000000000000",
        #       "health_check_sequencer_fee": "100000000000000000",
        #       "taker_sequencer_fee": "25000000000000000",
        #       "withdraw_sequencer_fees": [
        #         "10000000000000000",
        #         "40000000000000",
        #         "0",
        #         "600000000000000",
        #         "0"
        #       ]
        #     },
        #     "request_type": "query_fee_rates",
        # }
        #
        data = self.safe_dict(response, 'data', {})
        maker = self.safe_list(data, 'maker_fee_rates_x18', [])
        taker = self.safe_list(data, 'taker_fee_rates_x18', [])
        result = {}
        for i in range(0, len(taker)):
            market = self.safe_market(self.number_to_string(i))
            if market['id'] is None:
                continue
            symbol = market['symbol']
            result[symbol] = {
                'info': response,
                'symbol': symbol,
                'maker': self.parse_number(self.convert_from_x18(maker[i])),
                'taker': self.parse_number(self.convert_from_x18(taker[i])),
                'percentage': True,
                'tierBased': False,
            }
        return result

    def parse_ohlcv(self, ohlcv, market: Market = None) -> list:
        # example response in fetchOHLCV
        return [
            self.safe_timestamp(ohlcv, 'timestamp'),
            self.parse_number(self.convert_from_x18(self.safe_string(ohlcv, 'open_x18'))),
            self.parse_number(self.convert_from_x18(self.safe_string(ohlcv, 'high_x18'))),
            self.parse_number(self.convert_from_x18(self.safe_string(ohlcv, 'low_x18'))),
            self.parse_number(self.convert_from_x18(self.safe_string(ohlcv, 'close_x18'))),
            self.parse_number(self.convert_from_x18(self.safe_string(ohlcv, 'volume'))),
        ]

    async def fetch_ohlcv(self, symbol: str, timeframe='1m', since: Int = None, limit: Int = None, params={}) -> List[list]:
        """
        :see: https://docs.vertexprotocol.com/developer-resources/api/archive-indexer/candlesticks
        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]: max=1000, max=100 when since is defined and is less than(now - (999 * (timeframe in ms)))
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns int[][]: A list of candles ordered, open, high, low, close, volume
        """
        await self.load_markets()
        market = self.market(symbol)
        ohlcvRequest = {
            'product_id': self.parse_to_int(market['id']),
            'granularity': self.safe_integer(self.timeframes, timeframe),
        }
        until = self.safe_integer(params, 'until')
        if until is not None:
            params = self.omit(params, 'until')
            ohlcvRequest['max_time'] = until
        if limit is not None:
            ohlcvRequest['limit'] = min(limit, 1000)
        request = {
            'candlesticks': ohlcvRequest,
        }
        response = await self.v1ArchivePost(self.extend(request, params))
        #
        # {
        #     "candlesticks": [
        #       {
        #         "product_id": 1,
        #         "granularity": 60,
        #         "submission_idx": "627709",
        #         "timestamp": "1680118140",
        #         "open_x18": "27235000000000000000000",
        #         "high_x18": "27298000000000000000000",
        #         "low_x18": "27235000000000000000000",
        #         "close_x18": "27298000000000000000000",
        #         "volume": "1999999999999999998"
        #       },
        #       {
        #         "product_id": 1,
        #         "granularity": 60,
        #         "submission_idx": "627699",
        #         "timestamp": "1680118080",
        #         "open_x18": "27218000000000000000000",
        #         "high_x18": "27245000000000000000000",
        #         "low_x18": "27218000000000000000000",
        #         "close_x18": "27245000000000000000000",
        #         "volume": "11852999999999999995"
        #       }
        #     ]
        # }
        #
        rows = self.safe_list(response, 'candlesticks', [])
        return self.parse_ohlcvs(rows, market, timeframe, since, limit)

    def parse_funding_rate(self, ticker, market: Market = None):
        #
        # {
        #     "product_id": 4,
        #     "funding_rate_x18": "2447900598160952",
        #     "update_time": "1680116326"
        # }
        #
        # {
        #     "ETH-PERP_USDC": {
        #         "ticker_id": "ETH-PERP_USDC",
        #         "base_currency": "ETH-PERP",
        #         "quote_currency": "USDC",
        #         "last_price": 1620.3,
        #         "base_volume": 1309.2,
        #         "quote_volume": 2117828.093867611,
        #         "product_type": "perpetual",
        #         "contract_price": 1620.372642114429,
        #         "contract_price_currency": "USD",
        #         "open_interest": 1635.2,
        #         "open_interest_usd": 2649633.3443855145,
        #         "index_price": 1623.293496279935,
        #         "mark_price": 1623.398589416731,
        #         "funding_rate": 0.000068613217104332,
        #         "next_funding_rate_timestamp": 1694379600,
        #         "price_change_percent_24h": -0.6348599635253989
        #     }
        # }
        #
        fundingRate = self.safe_number(ticker, 'funding_rate')
        if fundingRate is None:
            fundingRateX18 = self.safe_string(ticker, 'funding_rate_x18')
            fundingRate = self.parse_number(self.convert_from_x18(fundingRateX18))
        fundingTimestamp = self.safe_timestamp_2(ticker, 'update_time', 'next_funding_rate_timestamp')
        markPrice = self.safe_number(ticker, 'mark_price')
        indexPrice = self.safe_number(ticker, 'index_price')
        return {
            'info': ticker,
            'symbol': market['symbol'],
            'markPrice': markPrice,
            'indexPrice': indexPrice,
            'interestRate': None,
            'estimatedSettlePrice': None,
            'timestamp': None,
            'datetime': None,
            'fundingRate': fundingRate,
            'fundingTimestamp': fundingTimestamp,
            'fundingDatetime': self.iso8601(fundingTimestamp),
            'nextFundingRate': None,
            'nextFundingTimestamp': None,
            'nextFundingDatetime': None,
            'previousFundingRate': None,
            'previousFundingTimestamp': None,
            'previousFundingDatetime': None,
        }

    async def fetch_funding_rate(self, symbol: str, params={}):
        """
        fetch the current funding rate
        :see: https://docs.vertexprotocol.com/developer-resources/api/archive-indexer/funding-rate
        :param str symbol: unified market symbol
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict: a `funding rate structure <https://docs.ccxt_zagrava.com/#/?id=funding-rate-structure>`
        """
        await self.load_markets()
        market = self.market(symbol)
        request = {
            'funding_rate': {
                'product_id': self.parse_to_int(market['id']),
            },
        }
        response = await self.v1ArchivePost(self.extend(request, params))
        #
        # {
        #     "product_id": 4,
        #     "funding_rate_x18": "2447900598160952",
        #     "update_time": "1680116326"
        # }
        #
        return self.parse_funding_rate(response, market)

    async def fetch_funding_rates(self, symbols: Strings = None, params={}):
        """
        fetches funding rates for multiple markets
        :see: https://docs.vertexprotocol.com/developer-resources/api/v2/contracts
        :param str[] symbols: unified symbols of the markets to fetch the funding rates for, all market funding rates are returned if not assigned
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict: an array of `funding rate structures <https://docs.ccxt_zagrava.com/#/?id=funding-rate-structure>`
        """
        await self.load_markets()
        request = {}
        if symbols is not None:
            symbols = self.market_symbols(symbols)
        response = await self.v2ArchiveGetContracts(self.extend(request, params))
        #
        # {
        #     "ETH-PERP_USDC": {
        #         "ticker_id": "ETH-PERP_USDC",
        #         "base_currency": "ETH-PERP",
        #         "quote_currency": "USDC",
        #         "last_price": 1620.3,
        #         "base_volume": 1309.2,
        #         "quote_volume": 2117828.093867611,
        #         "product_type": "perpetual",
        #         "contract_price": 1620.372642114429,
        #         "contract_price_currency": "USD",
        #         "open_interest": 1635.2,
        #         "open_interest_usd": 2649633.3443855145,
        #         "index_price": 1623.293496279935,
        #         "mark_price": 1623.398589416731,
        #         "funding_rate": 0.000068613217104332,
        #         "next_funding_rate_timestamp": 1694379600,
        #         "price_change_percent_24h": -0.6348599635253989
        #     }
        # }
        #
        keys = list(response.keys())
        fundingRates = {}
        for i in range(0, len(keys)):
            tickerId = keys[i]
            parsedTickerId = tickerId.split('-')
            data = response[tickerId]
            marketId = parsedTickerId[0] + '/USDC:USDC'
            market = self.market(marketId)
            ticker = self.parse_funding_rate(data, market)
            symbol = ticker['symbol']
            fundingRates[symbol] = ticker
        return self.filter_by_array(fundingRates, 'symbol', symbols)

    def parse_open_interest(self, interest, market: Market = None):
        #
        # {
        #     "ETH-PERP_USDC": {
        #         "ticker_id": "ETH-PERP_USDC",
        #         "base_currency": "ETH-PERP",
        #         "quote_currency": "USDC",
        #         "last_price": 1620.3,
        #         "base_volume": 1309.2,
        #         "quote_volume": 2117828.093867611,
        #         "product_type": "perpetual",
        #         "contract_price": 1620.372642114429,
        #         "contract_price_currency": "USD",
        #         "open_interest": 1635.2,
        #         "open_interest_usd": 2649633.3443855145,
        #         "index_price": 1623.293496279935,
        #         "mark_price": 1623.398589416731,
        #         "funding_rate": 0.000068613217104332,
        #         "next_funding_rate_timestamp": 1694379600,
        #         "price_change_percent_24h": -0.6348599635253989
        #     }
        # }
        #
        value = self.safe_number(interest, 'open_interest_usd')
        return self.safe_open_interest({
            'symbol': market['symbol'],
            'openInterestAmount': None,
            'openInterestValue': value,
            'timestamp': None,
            'datetime': None,
            'info': interest,
        }, market)

    async def fetch_open_interest(self, symbol: str, params={}):
        """
        Retrieves the open interest of a derivative trading pair
        :see: https://docs.vertexprotocol.com/developer-resources/api/v2/contracts
        :param str symbol: Unified ccxt_zagrava market symbol
        :param dict [params]: exchange specific parameters
        :returns dict} an open interest structure{@link https://docs.ccxt_zagrava.com/#/?id=open-interest-structure:
        """
        await self.load_markets()
        market = self.market(symbol)
        if not market['contract']:
            raise BadRequest(self.id + ' fetchOpenInterest() supports contract markets only')
        request = {}
        response = await self.v2ArchiveGetContracts(self.extend(request, params))
        #
        # {
        #     "ETH-PERP_USDC": {
        #         "ticker_id": "ETH-PERP_USDC",
        #         "base_currency": "ETH-PERP",
        #         "quote_currency": "USDC",
        #         "last_price": 1620.3,
        #         "base_volume": 1309.2,
        #         "quote_volume": 2117828.093867611,
        #         "product_type": "perpetual",
        #         "contract_price": 1620.372642114429,
        #         "contract_price_currency": "USD",
        #         "open_interest": 1635.2,
        #         "open_interest_usd": 2649633.3443855145,
        #         "index_price": 1623.293496279935,
        #         "mark_price": 1623.398589416731,
        #         "funding_rate": 0.000068613217104332,
        #         "next_funding_rate_timestamp": 1694379600,
        #         "price_change_percent_24h": -0.6348599635253989
        #     }
        # }
        #
        tickerId = market['base'] + '_USDC'
        openInterest = self.safe_dict(response, tickerId, {})
        return self.parse_open_interest(openInterest, market)

    def parse_ticker(self, ticker: dict, market: Market = None) -> Ticker:
        #
        #     {
        #         "ticker_id": "BTC_USDC",
        #         "base_currency": "BTC",
        #         "quote_currency": "USDC",
        #         "last_price": 25728.0,
        #         "base_volume": 552.048,
        #         "quote_volume": 14238632.207250029,
        #         "price_change_percent_24h": -0.6348599635253989
        #     }
        #
        base = self.safe_string(ticker, 'base_currency')
        quote = self.safe_string(ticker, 'quote_currency')
        marketId = base + '/' + quote
        if base.find('PERP') > 0:
            marketId = marketId.replace('-PERP', '') + ':USDC'
        market = self.market(marketId)
        last = self.safe_string(ticker, 'last_price')
        return self.safe_ticker({
            'symbol': market['symbol'],
            'timestamp': None,
            'datetime': None,
            'high': None,
            'low': None,
            'bid': None,
            'bidVolume': None,
            'ask': None,
            'askVolume': None,
            'vwap': None,
            'open': None,
            'close': last,
            'last': last,
            'previousClose': None,
            'change': None,
            'percentage': self.safe_string(ticker, 'price_change_percent_24h'),
            'average': None,
            'baseVolume': self.safe_string(ticker, 'base_volume'),
            'quoteVolume': self.safe_string(ticker, 'quote_volume'),
            'info': ticker,
        }, market)

    async 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.vertexprotocol.com/developer-resources/api/v2/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: a dictionary of `ticker structures <https://docs.ccxt_zagrava.com/#/?id=ticker-structure>`
        """
        await self.load_markets()
        symbols = self.market_symbols(symbols, None, True, True, True)
        request = {}
        response = await self.v2ArchiveGetTickers(self.extend(request, params))
        #
        # {
        #     "ETH_USDC": {
        #         "ticker_id": "ETH_USDC",
        #         "base_currency": "ETH",
        #         "quote_currency": "USDC",
        #         "last_price": 1619.1,
        #         "base_volume": 1428.32,
        #         "quote_volume": 2310648.316391866,
        #         "price_change_percent_24h": -1.0509394462969588
        #     },
        #     "BTC_USDC": {
        #         "ticker_id": "BTC_USDC",
        #         "base_currency": "BTC",
        #         "quote_currency": "USDC",
        #         "last_price": 25728.0,
        #         "base_volume": 552.048,
        #         "quote_volume": 14238632.207250029,
        #         "price_change_percent_24h": -0.6348599635253989
        #     }
        # }
        #
        tickers = list(response.values())
        return self.parse_tickers(tickers, symbols)

    async def query_contracts(self, params={}) -> Currencies:
        # query contract addresses for sending order
        cachedContracts = self.safe_dict(self.options, 'v1contracts')
        if cachedContracts is not None:
            return cachedContracts
        request = {
            'type': 'contracts',
        }
        response = await self.v1GatewayGetQuery(self.extend(request, params))
        data = self.safe_dict(response, 'data', {})
        self.options['v1contracts'] = data
        return data

    def nonce(self):
        return self.milliseconds() - self.options['timeDifference']

    def hash_message(self, message):
        return '0x' + self.hash(message, 'keccak', 'hex')

    def sign_hash(self, hash, privateKey):
        signature = self.ecdsa(hash[-64:], privateKey[-64:], 'secp256k1', None)
        r = signature['r']
        s = signature['s']
        v = self.int_to_base16(self.sum(27, signature['v']))
        return '0x' + r.rjust(64, '0') + s.rjust(64, '0') + v

    def sign_message(self, message, privateKey):
        return self.sign_hash(self.hash_message(message), privateKey[-64:])

    def build_sig(self, chainId, messageTypes, message, verifyingContractAddress=''):
        domain = {
            'chainId': chainId,
            'name': 'Vertex',
            'verifyingContract': verifyingContractAddress,
            'version': '0.0.1',
        }
        msg = self.eth_encode_structured_data(domain, messageTypes, message)
        signature = self.sign_message(msg, self.privateKey)
        return signature

    def build_create_order_sig(self, message, chainId, verifyingContractAddress):
        messageTypes = {
            'Order': [
                {'name': 'sender', 'type': 'bytes32'},
                {'name': 'priceX18', 'type': 'int128'},
                {'name': 'amount', 'type': 'int128'},
                {'name': 'expiration', 'type': 'uint64'},
                {'name': 'nonce', 'type': 'uint64'},
            ],
        }
        return self.build_sig(chainId, messageTypes, message, verifyingContractAddress)

    def build_list_trigger_tx_sig(self, message, chainId, verifyingContractAddress):
        messageTypes = {
            'ListTriggerOrders': [
                {'name': 'sender', 'type': 'bytes32'},
                {'name': 'recvTime', 'type': 'uint64'},
            ],
        }
        return self.build_sig(chainId, messageTypes, message, verifyingContractAddress)

    def build_cancel_all_orders_sig(self, message, chainId, verifyingContractAddress):
        messageTypes = {
            'CancellationProducts': [
                {'name': 'sender', 'type': 'bytes32'},
                {'name': 'productIds', 'type': 'uint32[]'},
                {'name': 'nonce', 'type': 'uint64'},
            ],
        }
        return self.build_sig(chainId, messageTypes, message, verifyingContractAddress)

    def build_cancel_orders_sig(self, message, chainId, verifyingContractAddress):
        messageTypes = {
            'Cancellation': [
                {'name': 'sender', 'type': 'bytes32'},
                {'name': 'productIds', 'type': 'uint32[]'},
                {'name': 'digests', 'type': 'bytes32[]'},
                {'name': 'nonce', 'type': 'uint64'},
            ],
        }
        return self.build_sig(chainId, messageTypes, message, verifyingContractAddress)

    def build_withdraw_sig(self, message, chainId, verifyingContractAddress):
        messageTypes = {
            'WithdrawCollateral': [
                {'name': 'sender', 'type': 'bytes32'},
                {'name': 'productId', 'type': 'uint32'},
                {'name': 'amount', 'type': 'uint128'},
                {'name': 'nonce', 'type': 'uint64'},
            ],
        }
        return self.build_sig(chainId, messageTypes, message, verifyingContractAddress)

    def convert_address_to_sender(self, address: str):
        sender = address + '64656661756c74'
        return sender.ljust(66, '0')

    def get_nonce(self, now, expiration):
        if now is None:
            now = self.nonce()
        # nonce = ((now + expiration) << 20) + 1000
        # 1 << 20 = 1048576
        return Precise.string_add(Precise.string_mul(Precise.string_add(self.number_to_string(now), self.number_to_string(expiration)), '1048576'), '1000')

    def get_expiration(self, now, timeInForce, postOnly, reduceOnly):
        expiration = Precise.string_add(self.number_to_string(now), '86400')
        if timeInForce == 'ioc':
            # 1 << 62 = 4611686018427387904
            expiration = Precise.string_or(expiration, '4611686018427387904')
        elif timeInForce == 'fok':
            # 2 << 62 = 9223372036854775808
            expiration = Precise.string_or(expiration, '9223372036854775808')
        elif postOnly:
            # 3 << 62 = 13835058055282163712
            expiration = Precise.string_or(expiration, '13835058055282163712')
        if reduceOnly:
            # 1 << 61 = 2305843009213693952
            expiration = Precise.string_or(expiration, '2305843009213693952')
        return expiration

    def get_amount(self, amount, side):
        amountString = self.number_to_string(amount)
        if side == 'sell':
            if amount > 0:
                # amount *= -1
                amountString = Precise.string_mul(amountString, '-1')
        else:
            if amount < 0:
                # amount *= -1
                amountString = Precise.string_mul(amountString, '-1')
        return amountString

    async def create_order(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}):
        """
        create a trade order
        :see: https://docs.vertexprotocol.com/developer-resources/api/gateway/executes/place-order
        :see: https://docs.vertexprotocol.com/developer-resources/api/trigger/executes/place-order
        :param str symbol: unified symbol of the market to create an order in
        :param str type: 'market' or 'limit'
        :param str side: 'buy' or 'sell'
        :param float amount: how much of currency you want to trade in units of base currency
        :param float [price]: the price at which the order is to be fulfilled, in units of the quote currency, ignored in market orders
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :param str [params.timeInForce]: ioc, fok
        :param bool [params.postOnly]: True or False whether the order is post-only
        :param bool [params.reduceOnly]: True or False whether the order is reduce-only, only works for ioc and fok order
        :param float [params.triggerPrice]: The price at which a trigger order is triggered at
        :returns dict: an `order structure <https://docs.ccxt_zagrava.com/#/?id=order-structure>`
        """
        self.check_required_credentials()
        marketType = type.lower()
        isMarketOrder = marketType == 'market'
        if isMarketOrder and price is None:
            raise ArgumentsRequired(self.id + ' createOrder() requires a price argument for market order')
        await self.load_markets()
        market = self.market(symbol)
        marketId = self.parse_to_int(market['id'])
        contracts = await self.query_contracts()
        chainId = self.safe_string(contracts, 'chain_id')
        bookAddresses = self.safe_list(contracts, 'book_addrs', [])
        verifyingContractAddress = self.safe_string(bookAddresses, marketId)
        defaultTimeInForce = 'fok' if (isMarketOrder) else None
        timeInForce = self.safe_string_lower(params, 'timeInForce', defaultTimeInForce)
        postOnly = self.safe_bool(params, 'postOnly', False)
        reduceOnly = self.safe_bool(params, 'reduceOnly', False)
        triggerPrice = self.safe_string_2(params, 'triggerPrice', 'stopPrice')
        stopLossPrice = self.safe_string(params, 'stopLossPrice', triggerPrice)
        takeProfitPrice = self.safe_string(params, 'takeProfitPrice')
        isTrigger = (stopLossPrice or takeProfitPrice)
        now = self.nonce()
        nonce = self.get_nonce(now, 90000)
        if postOnly and reduceOnly:
            raise NotSupported(self.id + ' reduceOnly not supported when postOnly is enabled')
        expiration = self.get_expiration(now, timeInForce, postOnly, reduceOnly)
        if isTrigger:
            # 1 << 63 = 9223372036854775808
            nonce = Precise.string_or(nonce, '9223372036854775808')
        amountString = self.get_amount(amount, side)
        order = {
            'sender': self.convert_address_to_sender(self.walletAddress),
            'priceX18': self.convert_to_x18(self.price_to_precision(symbol, price)),
            'amount': self.convert_to_x18(self.amount_to_precision(symbol, amountString)),
            'expiration': expiration,
            'nonce': nonce,
        }
        request = {
            'place_order': {
                'product_id': marketId,
                'order': {
                    'sender': order['sender'],
                    'priceX18': order['priceX18'],
                    'amount': order['amount'],
                    'expiration': self.number_to_string(order['expiration']),
                    'nonce': order['nonce'],
                },
                'signature': self.build_create_order_sig(order, chainId, verifyingContractAddress),
                'id': self.safe_integer(self.options, 'brokerId', 5930043274845996),
            },
        }
        params = self.omit(params, ['timeInForce', 'reduceOnly', 'postOnly', 'triggerPrice', 'stopPrice', 'stopLossPrice', 'takeProfitPrice'])
        response = None
        if isTrigger:
            trigger = {}
            if stopLossPrice is not None:
                trigger['last_price_below'] = self.convert_to_x18(stopLossPrice)
            elif takeProfitPrice is not None:
                trigger['last_price_above'] = self.convert_to_x18(takeProfitPrice)
            request['place_order']['trigger'] = trigger
            response = await self.v1TriggerPostExecute(self.extend(request, params))
        else:
            response = await self.v1GatewayPostExecute(self.extend(request, params))
        #
        # {
        #     "status": "success",
        #     "signature": {signature},
        #     "data": {
        #       "digest": {order digest}
        #     },
        #     "request_type": "execute_place_order"
        #     "id": 100
        # }
        #
        data = self.safe_dict(response, 'data', {})
        return self.safe_order({
            'id': self.safe_string(data, 'digest'),
        })

    async def edit_order(self, id: str, symbol: str, type: OrderType, side: OrderSide, amount: Num = None, price: Num = None, params={}):
        """
        edit a trade order
        :see: https://docs.vertexprotocol.com/developer-resources/api/gateway/executes/cancel-and-place
        :param str id: cancel order id
        :param str symbol: unified symbol of the market to create an order in
        :param str type: 'market' or 'limit'
        :param str side: 'buy' or 'sell'
        :param float amount: how much of currency you want to trade in units of base currency
        :param float [price]: the price at which the order is to be fulfilled, in units of the quote currency, ignored in market orders
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :param str [params.timeInForce]: ioc, fok
        :param bool [params.postOnly]: True or False whether the order is post-only
        :param bool [params.reduceOnly]: True or False whether the order is reduce-only, only works for ioc and fok order
        :param float [params.triggerPrice]: The price at which a trigger order is triggered at
        :returns dict: an `order structure <https://docs.ccxt_zagrava.com/#/?id=order-structure>`
        """
        self.check_required_credentials()
        marketType = type.lower()
        isMarketOrder = marketType == 'market'
        if isMarketOrder and price is None:
            raise ArgumentsRequired(self.id + ' editOrder() requires a price argument for market order')
        await self.load_markets()
        market = self.market(symbol)
        marketId = self.parse_to_int(market['id'])
        defaultTimeInForce = 'fok' if (isMarketOrder) else None
        timeInForce = self.safe_string_lower(params, 'timeInForce', defaultTimeInForce)
        postOnly = self.safe_bool(params, 'postOnly', False)
        reduceOnly = self.safe_bool(params, 'reduceOnly', False)
        triggerPrice = self.safe_string_2(params, 'triggerPrice', 'stopPrice')
        stopLossPrice = self.safe_string(params, 'stopLossPrice', triggerPrice)
        takeProfitPrice = self.safe_string(params, 'takeProfitPrice')
        isTrigger = (stopLossPrice or takeProfitPrice)
        contracts = await self.query_contracts()
        chainId = self.safe_string(contracts, 'chain_id')
        bookAddresses = self.safe_list(contracts, 'book_addrs', [])
        verifyingContractAddressOrder = self.safe_string(bookAddresses, marketId)
        verifyingContractAddressCancel = self.safe_string(contracts, 'endpoint_addr')
        now = self.nonce()
        nonce = self.get_nonce(now, 90000)
        sender = self.convert_address_to_sender(self.walletAddress)
        if postOnly and reduceOnly:
            raise NotSupported(self.id + ' reduceOnly not supported when postOnly is enabled')
        if isTrigger:
            raise NotSupported(self.id + ' editOrder() not supported for trigger order')
        expiration = self.get_expiration(now, timeInForce, postOnly, reduceOnly)
        amountString = self.get_amount(amount, side)
        order = {
            'sender': sender,
            'priceX18': self.convert_to_x18(self.price_to_precision(symbol, price)),
            'amount': self.convert_to_x18(self.amount_to_precision(symbol, amountString)),
            'expiration': expiration,
            'nonce': nonce,
        }
        cancels = {
            'sender': sender,
            'productIds': [marketId],
            'digests': [id],
            'nonce': nonce,
        }
        request = {
            'cancel_and_place': {
                'cancel_tx': {
                    'sender': cancels['sender'],
                    'productIds': cancels['productIds'],
                    'digests': cancels['digests'],
                    'nonce': self.number_to_string(cancels['nonce']),
                },
                'cancel_signature': self.build_cancel_orders_sig(cancels, chainId, verifyingContractAddressCancel),
                'place_order': {
                    'product_id': marketId,
                    'order': {
                        'sender': order['sender'],
                        'priceX18': order['priceX18'],
                        'amount': order['amount'],
                        'expiration': self.number_to_string(order['expiration']),
                        'nonce': order['nonce'],
                    },
                    'signature': self.build_create_order_sig(order, chainId, verifyingContractAddressOrder),
                    'id': self.safe_integer(self.options, 'brokerId', 5930043274845996),
                },
            },
        }
        params = self.omit(params, ['timeInForce', 'reduceOnly', 'postOnly', 'triggerPrice', 'stopPrice', 'stopLossPrice', 'takeProfitPrice'])
        response = await self.v1GatewayPostExecute(self.extend(request, params))
        #
        # {
        #     "status": "success",
        #     "signature": {signature},
        #     "data": {
        #       "digest": {order digest}
        #     },
        #     "request_type": "execute_cancel_and_place"
        # }
        #
        data = self.safe_dict(response, 'data', {})
        return self.safe_order({
            'id': self.safe_string(data, 'digest'),
        })

    def parse_order_status(self, status):
        if status is not None:
            statuses = {
                'pending': 'open',
            }
            if isinstance(status, str):
                return self.safe_string(statuses, status, status)
            statusCancelled = self.safe_dict(status, 'cancelled')
            if statusCancelled is not None:
                return 'canceled'
            statusTriggered = self.safe_dict(status, 'triggered', {})
            triggeredStatus = self.safe_string(statusTriggered, 'status', 'failure')
            if triggeredStatus == 'success':
                return 'closed'
            return 'canceled'
        return status

    def parse_order(self, order, market: Market = None) -> Order:
        #
        # {
        #     "product_id": 1,
        #     "sender": "0x7a5ec2748e9065794491a8d29dcf3f9edb8d7c43000000000000000000000000",
        #     "price_x18": "1000000000000000000",
        #     "amount": "1000000000000000000",
        #     "expiration": "2000000000",
        #     "nonce": "1",
        #     "unfilled_amount": "1000000000000000000",
        #     "digest": "0x0000000000000000000000000000000000000000000000000000000000000000",
        #     "placed_at": 1681951347,
        #     "order_type": "ioc"
        # }
        # stop order
        # {
        #     "order": {
        #       "order": {
        #         "sender": "0x7a5ec2748e9065794491a8d29dcf3f9edb8d7c43000000000000000000000000",
        #         "priceX18": "1000000000000000000",
        #         "amount": "1000000000000000000",
        #         "expiration": "2000000000",
        #         "nonce": "1",
        #       },
        #       "signature": "0x...",
        #       "product_id": 1,
        #       "spot_leverage": True,
        #       "trigger": {
        #         "price_above": "1000000000000000000"
        #       },
        #       "digest": "0x..."
        #     },
        #     "status": "pending",
        #     "updated_at": 1688768157050
        # }
        #
        marketId = self.safe_string(order, 'product_id')
        timestamp = self.safe_timestamp(order, 'placed_at')
        amount = self.safe_string(order, 'amount')
        price = self.safe_string(order, 'price_x18')
        remaining = self.safe_string(order, 'unfilled_amount')
        triggerPriceNum = None
        status = self.safe_value(order, 'status')
        if status is not None:
            # trigger order
            outerOrder = self.safe_dict(order, 'order', {})
            innerOrder = self.safe_dict(outerOrder, 'order', {})
            marketId = self.safe_string(outerOrder, 'product_id')
            amount = self.safe_string(innerOrder, 'amount')
            price = self.safe_string(innerOrder, 'priceX18')
            timestamp = self.safe_timestamp(order, 'updated_at')
            trigger = self.safe_dict(outerOrder, 'trigger', {})
            triggerPrice = self.safe_string_n(trigger, ['price_above', 'price_below', 'last_price_above', 'last_price_below'])
            if triggerPrice is not None:
                triggerPriceNum = self.parse_to_numeric(self.convert_from_x18(triggerPrice))
        market = self.safe_market(marketId, market)
        symbol = market['symbol']
        priceNum = None
        if price is not None:
            priceNum = self.parse_to_numeric(self.convert_from_x18(price))
        amountNum = None
        if amount is not None:
            amountNum = self.parse_to_numeric(self.convert_from_x18(amount))
        remainingNum = None
        if remaining is not None:
            remainingNum = self.parse_to_numeric(self.convert_from_x18(remaining))
        side = None
        if amountNum is not None and remainingNum is not None:
            side = 'sell' if (amountNum < 0 or remainingNum < 0) else 'buy'
        tif = self.parse_time_in_force(self.safe_string(order, 'order_type'))
        isPostOnly = (tif == 'PO')
        return self.safe_order({
            'info': order,
            'id': self.safe_string(order, 'digest'),
            'clientOrderId': None,
            'timestamp': timestamp,
            'datetime': self.iso8601(timestamp),
            'lastTradeTimestamp': None,
            'lastUpdateTimestamp': None,
            'symbol': symbol,
            'type': None,
            'timeInForce': tif,
            'postOnly': isPostOnly,
            'reduceOnly': None,
            'side': side,
            'price': priceNum,
            'triggerPrice': triggerPriceNum,
            'amount': amountNum,
            'cost': None,
            'average': None,
            'filled': None,
            'remaining': remainingNum,
            'status': self.parse_order_status(status),
            'fee': None,
            'trades': None,
        }, market)

    def parse_time_in_force(self, timeInForce):
        timeInForces = {
            'POST_ONLY': 'PO',
        }
        return self.safe_string_upper(timeInForces, timeInForce, timeInForce)

    async def fetch_order(self, id: str, symbol: Str = None, params={}):
        """
        fetches information on an order made by the user
        :see: https://docs.vertexprotocol.com/developer-resources/api/gateway/queries/order
        :param str symbol: unified symbol of the market the order was made in
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict: An `order structure <https://docs.ccxt_zagrava.com/#/?id=order-structure>`
        """
        await self.load_markets()
        market = self.market(symbol)
        request = {
            'type': 'order',
            'product_id': self.parse_to_int(market['id']),
            'digest': id,
        }
        response = await self.v1GatewayGetQuery(self.extend(request, params))
        #
        # {
        #     "status": "success",
        #     "data": {
        #       "product_id": 1,
        #       "sender": "0x7a5ec2748e9065794491a8d29dcf3f9edb8d7c43000000000000000000000000",
        #       "price_x18": "1000000000000000000",
        #       "amount": "1000000000000000000",
        #       "expiration": "2000000000",
        #       "nonce": "1",
        #       "unfilled_amount": "1000000000000000000",
        #       "digest": "0x0000000000000000000000000000000000000000000000000000000000000000",
        #       "placed_at": 1681951347,
        #       "order_type": "ioc"
        #     },
        #     "request_type": "query_order",
        # }
        #
        data = self.safe_dict(response, 'data')
        return self.parse_order(data, market)

    async def fetch_open_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
        """
        fetch all unfilled currently open orders
        :see: https://docs.vertexprotocol.com/developer-resources/api/gateway/queries/orders
        :see: https://docs.vertexprotocol.com/developer-resources/api/trigger/queries/list-trigger-orders
        :param str symbol: unified market symbol
        :param int [since]: the earliest time in ms to fetch open orders for
        :param int [limit]: the maximum number of open orders structures to retrieve
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :param boolean [params.stop]: whether the order is a stop/algo order
        :param str [params.user]: user address, will default to self.walletAddress if not provided
        :returns Order[]: a list of `order structures <https://docs.ccxt_zagrava.com/#/?id=order-structure>`
        """
        self.check_required_credentials()
        await self.load_markets()
        userAddress = None
        userAddress, params = self.handle_public_address('fetchOpenOrders', params)
        request = {}
        market: Market = None
        stop = self.safe_bool_2(params, 'stop', 'trigger')
        params = self.omit(params, ['stop', 'trigger'])
        if symbol is not None:
            market = self.market(symbol)
            request['product_id'] = self.parse_to_numeric(market['id'])
        response = None
        if stop:
            contracts = await self.query_contracts()
            chainId = self.safe_string(contracts, 'chain_id')
            verifyingContractAddress = self.safe_string(contracts, 'endpoint_addr')
            tx = {
                'sender': self.convert_address_to_sender(userAddress),
                'recvTime': self.nonce() + 90000,
            }
            request['signature'] = self.build_list_trigger_tx_sig(tx, chainId, verifyingContractAddress)
            request['tx'] = {
                'sender': tx['sender'],
                'recvTime': self.number_to_string(tx['recvTime']),
            }
            request['type'] = 'list_trigger_orders'
            request['pending'] = True
            until = self.safe_integer(params, 'until')
            params = self.omit(params, 'until')
            if until is not None:
                request['max_update_time'] = until
            if limit is not None:
                request['limit'] = limit
            response = await self.v1TriggerPostQuery(self.extend(request, params))
            #
            # {
            #     "status": "success",
            #     "data": {
            #       "orders": [
            #         {
            #           "order": {
            #             "order": {
            #               "sender": "0x7a5ec2748e9065794491a8d29dcf3f9edb8d7c43000000000000000000000000",
            #               "priceX18": "1000000000000000000",
            #               "amount": "1000000000000000000",
            #               "expiration": "2000000000",
            #               "nonce": "1",
            #             },
            #             "signature": "0x...",
            #             "product_id": 1,
            #             "spot_leverage": True,
            #             "trigger": {
            #               "price_above": "1000000000000000000"
            #             },
            #             "digest": "0x..."
            #           },
            #           "status": "pending",
            #           "updated_at": 1688768157050
            #         }
            #       ]
            #     },
            #     "request_type": "query_list_trigger_orders"
            # }
            #
        else:
            self.check_required_argument('fetchOpenOrders', symbol, 'symbol')
            request['type'] = 'subaccount_orders'
            request['sender'] = self.convert_address_to_sender(userAddress)
            response = await self.v1GatewayPostQuery(self.extend(request, params))
            #
            # {
            #     "status": "success",
            #     "data": {
            #       "sender": "0x7a5ec2748e9065794491a8d29dcf3f9edb8d7c43000000000000000000000000",
            #       "product_id": 1,
            #       "orders": [
            #         {
            #           "product_id": 1,
            #           "sender": "0x7a5ec2748e9065794491a8d29dcf3f9edb8d7c43000000000000000000000000",
            #           "price_x18": "1000000000000000000",
            #           "amount": "1000000000000000000",
            #           "expiration": "2000000000",
            #           "nonce": "1",
            #           "order_type": "default",
            #           "unfilled_amount": "1000000000000000000",
            #           "digest": "0x0000000000000000000000000000000000000000000000000000000000000000",
            #           "placed_at": 1682437739,
            #           "order_type": "ioc"
            #         }
            #       ]
            #     },
            #     "request_type": "query_subaccount_orders"
            # }
            #
        data = self.safe_dict(response, 'data', {})
        orders = self.safe_list(data, 'orders')
        return self.parse_orders(orders, market, since, limit)

    async def fetch_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
        """
        fetches information on multiple orders made by the user
        :see: https://docs.vertexprotocol.com/developer-resources/api/trigger/queries/list-trigger-orders
        :param str symbol: unified market symbol
        :param int [since]: the earliest time in ms to fetch open orders for
        :param int [limit]: the maximum number of open orders structures to retrieve
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :param boolean [params.stop]: whether the order is a stop/algo order
        :param str [params.user]: user address, will default to self.walletAddress if not provided
        :returns Order[]: a list of `order structures <https://docs.ccxt_zagrava.com/#/?id=order-structure>`
        """
        self.check_required_credentials()
        stop = self.safe_bool_2(params, 'stop', 'trigger')
        params = self.omit(params, ['stop', 'trigger'])
        if not stop:
            raise NotSupported(self.id + ' fetchOrders only support trigger orders')
        userAddress = None
        userAddress, params = self.handle_public_address('fetchOrders', params)
        await self.load_markets()
        market: Market = None
        request = {
            'type': 'list_trigger_orders',
            'pending': False,
        }
        if symbol is not None:
            market = self.market(symbol)
            request['product_id'] = self.parse_to_numeric(market['id'])
        contracts = await self.query_contracts()
        chainId = self.safe_string(contracts, 'chain_id')
        verifyingContractAddress = self.safe_string(contracts, 'endpoint_addr')
        tx = {
            'sender': self.convert_address_to_sender(userAddress),
            'recvTime': self.nonce() + 90000,
        }
        request['signature'] = self.build_list_trigger_tx_sig(tx, chainId, verifyingContractAddress)
        request['tx'] = {
            'sender': tx['sender'],
            'recvTime': self.number_to_string(tx['recvTime']),
        }
        until = self.safe_integer(params, 'until')
        params = self.omit(params, 'until')
        if until is not None:
            request['max_update_time'] = until
        if limit is not None:
            request['limit'] = limit
        response = await self.v1TriggerPostQuery(self.extend(request, params))
        #
        # {
        #     "status": "success",
        #     "data": {
        #       "orders": [
        #         {
        #           "order": {
        #             "order": {
        #               "sender": "0x7a5ec2748e9065794491a8d29dcf3f9edb8d7c43000000000000000000000000",
        #               "priceX18": "1000000000000000000",
        #               "amount": "1000000000000000000",
        #               "expiration": "2000000000",
        #               "nonce": "1",
        #             },
        #             "signature": "0x...",
        #             "product_id": 1,
        #             "spot_leverage": True,
        #             "trigger": {
        #               "price_above": "1000000000000000000"
        #             },
        #             "digest": "0x..."
        #           },
        #           "status": "pending",
        #           "updated_at": 1688768157050
        #         }
        #       ]
        #     },
        #     "request_type": "query_list_trigger_orders"
        # }
        #
        data = self.safe_dict(response, 'data', {})
        orders = self.safe_list(data, 'orders')
        return self.parse_orders(orders, market, since, limit)

    async def cancel_all_orders(self, symbol: Str = None, params={}):
        """
        :see: https://docs.vertexprotocol.com/developer-resources/api/gateway/executes/cancel-product-orders
        :see: https://docs.vertexprotocol.com/developer-resources/api/trigger/executes/cancel-product-orders
        cancel all open orders in a market
        :param str symbol: unified market symbol
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :param boolean [params.stop]: whether the order is a stop/algo order
        :returns dict: an list of `order structures <https://docs.ccxt_zagrava.com/#/?id=order-structure>`
        """
        self.check_required_credentials()
        await self.load_markets()
        if symbol is None:
            raise ArgumentsRequired(self.id + ' cancelAllOrders() requires a symbol argument')
        market = self.market(symbol)
        marketId = market['id']
        contracts = await self.query_contracts()
        chainId = self.safe_string(contracts, 'chain_id')
        verifyingContractAddress = self.safe_string(contracts, 'endpoint_addr')
        now = self.nonce()
        nonce = self.get_nonce(now, 90000)
        cancels = {
            'sender': self.convert_address_to_sender(self.walletAddress),
            'productIds': [
                self.parse_to_numeric(marketId),
            ],
            'nonce': nonce,
        }
        request = {
            'cancel_product_orders': {
                'tx': {
                    'sender': cancels['sender'],
                    'productIds': cancels['productIds'],
                    'nonce': self.number_to_string(cancels['nonce']),
                },
                'signature': self.build_cancel_all_orders_sig(cancels, chainId, verifyingContractAddress),
            },
        }
        stop = self.safe_bool_2(params, 'stop', 'trigger')
        params = self.omit(params, ['stop', 'trigger'])
        response = None
        if stop:
            response = await self.v1TriggerPostExecute(self.extend(request, params))
            #
            # {
            #     "status": "success",
            #     "signature": {signature},
            #     "request_type": "execute_cancel_product_orders"
            # }
            #
        else:
            response = await self.v1GatewayPostExecute(self.extend(request, params))
            #
            # {
            #     "status": "success",
            #     "signature": {signature},
            #     "data": {
            #       "cancelled_orders": [
            #         {
            #           "product_id": 2,
            #           "sender": "0x7a5ec2748e9065794491a8d29dcf3f9edb8d7c43746573743000000000000000",
            #           "price_x18": "20000000000000000000000",
            #           "amount": "-100000000000000000",
            #           "expiration": "1686332748",
            #           "order_type": "post_only",
            #           "nonce": "1768248100142339392",
            #           "unfilled_amount": "-100000000000000000",
            #           "digest": "0x3195a7929feb8307edecf9c045j5ced68925108f0aa305f0ee5773854159377c",
            #           "placed_at": 1686332708
            #         },
            #         ...
            #       ]
            #     },
            #     "request_type": "execute_cancel_product_orders"
            # }
            #
        return response

    async def cancel_order(self, id: str, symbol: Str = None, params={}):
        """
        cancels an open order
        :see: https://docs.vertexprotocol.com/developer-resources/api/gateway/executes/cancel-orders
        :see: https://docs.vertexprotocol.com/developer-resources/api/trigger/executes/cancel-orders
        :param str id: order id
        :param str symbol: unified symbol of the market the order was made in
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict: An `order structure <https://docs.ccxt_zagrava.com/#/?id=order-structure>`
        """
        return await self.cancel_orders([id], symbol, params)

    async def cancel_orders(self, ids: List[str], symbol: Str = None, params={}):
        """
        cancel multiple orders
        :see: https://docs.vertexprotocol.com/developer-resources/api/gateway/executes/cancel-orders
        :see: https://docs.vertexprotocol.com/developer-resources/api/trigger/executes/cancel-orders
        :param str[] ids: order ids
        :param str [symbol]: unified market symbol
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict: an list of `order structures <https://docs.ccxt_zagrava.com/#/?id=order-structure>`
        """
        self.check_required_credentials()
        if symbol is None:
            raise ArgumentsRequired(self.id + ' cancelOrders() requires a symbol argument')
        await self.load_markets()
        market = self.market(symbol)
        marketId = market['id']
        contracts = await self.query_contracts()
        chainId = self.safe_string(contracts, 'chain_id')
        verifyingContractAddress = self.safe_string(contracts, 'endpoint_addr')
        now = self.nonce()
        nonce = self.get_nonce(now, 90000)
        cancels = {
            'sender': self.convert_address_to_sender(self.walletAddress),
            'productIds': [],
            'digests': ids,
            'nonce': nonce,
        }
        marketIdNum = self.parse_to_numeric(marketId)
        for i in range(0, len(ids)):
            cancels['productIds'].append(marketIdNum)
        request = {
            'cancel_orders': {
                'tx': {
                    'sender': cancels['sender'],
                    'productIds': cancels['productIds'],
                    'digests': cancels['digests'],
                    'nonce': self.number_to_string(cancels['nonce']),
                },
                'signature': self.build_cancel_orders_sig(cancels, chainId, verifyingContractAddress),
            },
        }
        stop = self.safe_bool_2(params, 'stop', 'trigger')
        params = self.omit(params, ['stop', 'trigger'])
        response = None
        if stop:
            response = await self.v1TriggerPostExecute(self.extend(request, params))
            #
            # {
            #     "status": "success",
            #     "signature": {signature},
            #     "request_type": "execute_cancel_orders"
            # }
            #
        else:
            response = await self.v1GatewayPostExecute(self.extend(request, params))
            #
            # {
            #     "status": "success",
            #     "signature": {signature},
            #     "data": {
            #       "cancelled_orders": [
            #         {
            #           "product_id": 2,
            #           "sender": "0x7a5ec2748e9065794491a8d29dcf3f9edb8d7c43746573743000000000000000",
            #           "price_x18": "20000000000000000000000",
            #           "amount": "-100000000000000000",
            #           "expiration": "1686332748",
            #           "order_type": "post_only",
            #           "nonce": "1768248100142339392",
            #           "unfilled_amount": "-100000000000000000",
            #           "digest": "0x3195a7929feb8307edecf9c045j5ced68925108f0aa305f0ee5773854159377c",
            #           "placed_at": 1686332708
            #         },
            #         ...
            #       ]
            #     },
            #     "request_type": "execute_cancel_orders"
            # }
            #
        return response

    async def fetch_balance(self, params={}) -> Balances:
        """
        query for balance and get the amount of funds available for trading or funds locked in orders
        :see: https://docs.vertexprotocol.com/developer-resources/api/gateway/queries/subaccount-info
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :param str [params.user]: user address, will default to self.walletAddress if not provided
        :returns dict: a `balance structure <https://docs.ccxt_zagrava.com/#/?id=balance-structure>`
        """
        userAddress = None
        userAddress, params = self.handle_public_address('fetchBalance', params)
        request = {
            'type': 'subaccount_info',
            'subaccount': self.convert_address_to_sender(userAddress),
        }
        response = await self.v1GatewayGetQuery(self.extend(request, params))
        #
        # {
        #     "status": "success",
        #     "data": {
        #       "subaccount": "0x265167ddfac55365d6ff07fc5943276319aa6b9f64656661756c740000000000",
        #       "exists": True,
        #       "healths": [
        #         {
        #           "assets": "75323297691833342306",
        #           "liabilities": "46329556869051092241",
        #           "health": "28993740822782250065"
        #         },
        #         {
        #           "assets": "75323297691833342306",
        #           "liabilities": "35968911700887320741",
        #           "health": "39354385990946021565"
        #         },
        #         {
        #           "assets": "80796966663601107565",
        #           "liabilities": "0",
        #           "health": "80796966663601107565"
        #         }
        #       ],
        #       "health_contributions": [
        #         [
        #           "75323297691833340000",
        #           "75323297691833340000",
        #           "75323297691833340000"
        #         ],
        #         [
        #           "0",
        #           "0",
        #           "0"
        #         ],
        #         [
        #           "0",
        #           "0",
        #           "0"
        #         ],
        #         [
        #           "0",
        #           "0",
        #           "0"
        #         ],
        #         [
        #           "-46329556869051090000",
        #           "-35968911700887323000",
        #           "5473668971767765000"
        #         ]
        #       ],
        #       "spot_count": 3,
        #       "perp_count": 2,
        #       "spot_balances": [
        #         {
        #           "product_id": 1,
        #           "lp_balance": {
        #             "amount": "0"
        #           },
        #           "balance": {
        #             "amount": "0",
        #             "last_cumulative_multiplier_x18": "1003419811982007193"
        #           }
        #         },
        #         {
        #           "product_id": 3,
        #           "lp_balance": {
        #             "amount": "0"
        #           },
        #           "balance": {
        #             "amount": "0",
        #             "last_cumulative_multiplier_x18": "1007584195035969404"
        #           }
        #         },
        #         {
        #           "product_id": 0,
        #           "lp_balance": {
        #             "amount": "0"
        #           },
        #           "balance": {
        #             "amount": "75323297691833342306",
        #             "last_cumulative_multiplier_x18": "1000000002391497578"
        #           }
        #         }
        #       ],
        #       "perp_balances": [
        #         {
        #           "product_id": 2,
        #           "lp_balance": {
        #             "amount": "0",
        #             "last_cumulative_funding_x18": "-284321955122859921"
        #           },
        #           "balance": {
        #             "amount": "0",
        #             "v_quote_balance": "0",
        #             "last_cumulative_funding_x18": "6363466629611946777168"
        #           }
        #         },
        #         {
        #           "product_id": 4,
        #           "lp_balance": {
        #             "amount": "0",
        #             "last_cumulative_funding_x18": "-90979748449893411"
        #           },
        #           "balance": {
        #             "amount": "-200000000000000000",
        #             "v_quote_balance": "419899475698318625259",
        #             "last_cumulative_funding_x18": "141182516563970577208"
        #           }
        #         }
        #       ],
        #       "spot_products": [
        #         {
        #           "product_id": 1,
        #           "oracle_price_x18": "30217830336443750750000",
        #           "risk": {
        #             "long_weight_initial_x18": "750000000000000000",
        #             "short_weight_initial_x18": "1250000000000000000",
        #             "long_weight_maintenance_x18": "800000000000000000",
        #             "short_weight_maintenance_x18": "1200000000000000000",
        #             "large_position_penalty_x18": "0"
        #           },
        #           "config": {
        #             "token": "0x5cc7c91690b2cbaee19a513473d73403e13fb431",
        #             "interest_inflection_util_x18": "800000000000000000",
        #             "interest_floor_x18": "10000000000000000",
        #             "interest_small_cap_x18": "40000000000000000",
        #             "interest_large_cap_x18": "1000000000000000000"
        #           },
        #           "state": {
        #             "cumulative_deposits_multiplier_x18": "1001304691727847318",
        #             "cumulative_borrows_multiplier_x18": "1003419811982007193",
        #             "total_deposits_normalized": "213107447159798397806318",
        #             "total_borrows_normalized": "4907820740150097483532"
        #           },
        #           "lp_state": {
        #             "supply": "1304981417419495030893348",
        #             "quote": {
        #               "amount": "2048495687410669565222259",
        #               "last_cumulative_multiplier_x18": "1000000002391497578"
        #             },
        #             "base": {
        #               "amount": "67623029247538886515",
        #               "last_cumulative_multiplier_x18": "1001304691727847318"
        #             }
        #           },
        #           "book_info": {
        #             "size_increment": "1000000000000000",
        #             "price_increment_x18": "1000000000000000000",
        #             "min_size": "10000000000000000",
        #             "collected_fees": "8865582805773573662738183",
        #             "lp_spread_x18": "3000000000000000"
        #           }
        #         },
        #         {
        #           "product_id": 3,
        #           "oracle_price_x18": "2075217009708333333333",
        #           "risk": {
        #             "long_weight_initial_x18": "750000000000000000",
        #             "short_weight_initial_x18": "1250000000000000000",
        #             "long_weight_maintenance_x18": "800000000000000000",
        #             "short_weight_maintenance_x18": "1200000000000000000",
        #             "large_position_penalty_x18": "0"
        #           },
        #           "config": {
        #             "token": "0xcc59686e3a32fb104c8ff84dd895676265efb8a6",
        #             "interest_inflection_util_x18": "800000000000000000",
        #             "interest_floor_x18": "10000000000000000",
        #             "interest_small_cap_x18": "40000000000000000",
        #             "interest_large_cap_x18": "1000000000000000000"
        #           },
        #           "state": {
        #             "cumulative_deposits_multiplier_x18": "1003722507760089346",
        #             "cumulative_borrows_multiplier_x18": "1007584195035969404",
        #             "total_deposits_normalized": "232750303205807326418622",
        #             "total_borrows_normalized": "110730726549469855171025"
        #           },
        #           "lp_state": {
        #             "supply": "902924999999999999774268",
        #             "quote": {
        #               "amount": "1165328092090344104989049",
        #               "last_cumulative_multiplier_x18": "1000000002391497578"
        #             },
        #             "base": {
        #               "amount": "563265647183403990588",
        #               "last_cumulative_multiplier_x18": "1003722507760089346"
        #             }
        #           },
        #           "book_info": {
        #             "size_increment": "10000000000000000",
        #             "price_increment_x18": "100000000000000000",
        #             "min_size": "100000000000000000",
        #             "collected_fees": "1801521329724633001446457",
        #             "lp_spread_x18": "3000000000000000"
        #           }
        #         },
        #         {
        #           "product_id": 0,
        #           "oracle_price_x18": "1000000000000000000",
        #           "risk": {
        #             "long_weight_initial_x18": "1000000000000000000",
        #             "short_weight_initial_x18": "1000000000000000000",
        #             "long_weight_maintenance_x18": "1000000000000000000",
        #             "short_weight_maintenance_x18": "1000000000000000000",
        #             "large_position_penalty_x18": "0"
        #           },
        #           "config": {
        #             "token": "0x179522635726710dd7d2035a81d856de4aa7836c",
        #             "interest_inflection_util_x18": "800000000000000000",
        #             "interest_floor_x18": "10000000000000000",
        #             "interest_small_cap_x18": "40000000000000000",
        #             "interest_large_cap_x18": "1000000000000000000"
        #           },
        #           "state": {
        #             "cumulative_deposits_multiplier_x18": "1000000002391497578",
        #             "cumulative_borrows_multiplier_x18": "1001593395547514024",
        #             "total_deposits_normalized": "60000256267437588885818752247843",
        #             "total_borrows_normalized": "391445043137305055810336885"
        #           },
        #           "lp_state": {
        #             "supply": "0",
        #             "quote": {
        #               "amount": "0",
        #               "last_cumulative_multiplier_x18": "0"
        #             },
        #             "base": {
        #               "amount": "0",
        #               "last_cumulative_multiplier_x18": "0"
        #             }
        #           },
        #           "book_info": {
        #             "size_increment": "0",
        #             "price_increment_x18": "0",
        #             "min_size": "0",
        #             "collected_fees": "0",
        #             "lp_spread_x18": "0"
        #           }
        #         }
        #       ],
        #       "perp_products": [
        #         {
        #           "product_id": 2,
        #           "oracle_price_x18": "30219079716463070000000",
        #           "risk": {
        #             "long_weight_initial_x18": "875000000000000000",
        #             "short_weight_initial_x18": "1125000000000000000",
        #             "long_weight_maintenance_x18": "900000000000000000",
        #             "short_weight_maintenance_x18": "1100000000000000000",
        #             "large_position_penalty_x18": "0"
        #           },
        #           "state": {
        #             "cumulative_funding_long_x18": "6363466629611946777168",
        #             "cumulative_funding_short_x18": "6363466629611946777168",
        #             "available_settle": "100612314098927536086702448",
        #             "open_interest": "57975708279961875623240"
        #           },
        #           "lp_state": {
        #             "supply": "783207415944433511804197",
        #             "last_cumulative_funding_x18": "6363466629611946777168",
        #             "cumulative_funding_per_lp_x18": "-284321955122859921",
        #             "base": "37321000000000000000",
        #             "quote": "1150991638943862165224593"
        #           },
        #           "book_info": {
        #             "size_increment": "1000000000000000",
        #             "price_increment_x18": "1000000000000000000",
        #             "min_size": "10000000000000000",
        #             "collected_fees": "7738341933653651206856235",
        #             "lp_spread_x18": "3000000000000000"
        #           }
        #         },
        #         {
        #           "product_id": 4,
        #           "oracle_price_x18": "2072129033632754300000",
        #           "risk": {
        #             "long_weight_initial_x18": "875000000000000000",
        #             "short_weight_initial_x18": "1125000000000000000",
        #             "long_weight_maintenance_x18": "900000000000000000",
        #             "short_weight_maintenance_x18": "1100000000000000000",
        #             "large_position_penalty_x18": "0"
        #           },
        #           "state": {
        #             "cumulative_funding_long_x18": "141182516563970577208",
        #             "cumulative_funding_short_x18": "141182516563970577208",
        #             "available_settle": "33807443862986950288685582",
        #             "open_interest": "316343836992291503987611"
        #           },
        #           "lp_state": {
        #             "supply": "541756546038144467864559",
        #             "last_cumulative_funding_x18": "141182516563970577208",
        #             "cumulative_funding_per_lp_x18": "-90979748449893411",
        #             "base": "362320000000000000000",
        #             "quote": "750080187685127907834038"
        #           },
        #           "book_info": {
        #             "size_increment": "10000000000000000",
        #             "price_increment_x18": "100000000000000000",
        #             "min_size": "100000000000000000",
        #             "collected_fees": "1893278317732551619694831",
        #             "lp_spread_x18": "3000000000000000"
        #           }
        #         }
        #       ]
        #     },
        #     "request_type": "query_subaccount_info"
        # }
        #
        data = self.safe_dict(response, 'data', {})
        balances = self.safe_list(data, 'spot_balances', [])
        result = {'info': response}
        for i in range(0, len(balances)):
            balance = balances[i]
            marketId = self.safe_string(balance, 'product_id')
            market = self.safe_market(marketId)
            isUsdcMarketId = marketId == '0'
            if market['id'] is None and not isUsdcMarketId:
                continue
            baseId = 'USDC' if (isUsdcMarketId) else self.safe_string(market, 'baseId')
            code = self.safe_currency_code(baseId)
            account = self.account()
            tokenBalance = self.safe_dict(balance, 'balance', {})
            total = self.convert_from_x18(self.safe_string(tokenBalance, 'amount'))
            account['total'] = total
            result[code] = account
        return self.safe_balance(result)

    def parse_position(self, position, market: Market = None):
        #
        # {
        #     "product_id": 2,
        #     "lp_balance": {
        #       "amount": "0",
        #       "last_cumulative_funding_x18": "-284321955122859921"
        #     },
        #     "balance": {
        #       "amount": "0",
        #       "v_quote_balance": "0",
        #       "last_cumulative_funding_x18": "6363466629611946777168"
        #     }
        #   },
        #   {
        #     "product_id": 4,
        #     "lp_balance": {
        #       "amount": "0",
        #       "last_cumulative_funding_x18": "-90979748449893411"
        #     },
        #     "balance": {
        #       "amount": "-200000000000000000",
        #       "v_quote_balance": "419899475698318625259",
        #       "last_cumulative_funding_x18": "141182516563970577208"
        #     }
        # }
        #
        marketId = self.safe_string(position, 'product_id')
        market = self.safe_market(marketId)
        balance = self.safe_dict(position, 'balance', {})
        contractSize = self.convert_from_x18(self.safe_string(balance, 'amount'))
        side = 'buy'
        if Precise.string_lt(contractSize, '1'):
            side = 'sell'
        return self.safe_position({
            'info': position,
            'id': None,
            'symbol': self.safe_string(market, 'symbol'),
            'timestamp': None,
            'datetime': None,
            'lastUpdateTimestamp': None,
            'initialMargin': None,
            'initialMarginPercentage': None,
            'maintenanceMargin': None,
            'maintenanceMarginPercentage': None,
            'entryPrice': None,
            'notional': None,
            'leverage': None,
            'unrealizedPnl': None,
            'contracts': None,
            'contractSize': self.parse_to_numeric(contractSize),
            'marginRatio': None,
            'liquidationPrice': None,
            'markPrice': None,
            'lastPrice': None,
            'collateral': None,
            'marginMode': 'cross',
            'marginType': None,
            'side': side,
            'percentage': None,
            'hedged': None,
            'stopLossPrice': None,
            'takeProfitPrice': None,
        })

    async def fetch_positions(self, symbols: Strings = None, params={}):
        """
        fetch all open positions
        :see: https://docs.vertexprotocol.com/developer-resources/api/gateway/queries/subaccount-info
        :param str[] [symbols]: list of unified market symbols
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :param str [params.user]: user address, will default to self.walletAddress if not provided
        :returns dict[]: a list of `position structure <https://docs.ccxt_zagrava.com/#/?id=position-structure>`
        """
        userAddress = None
        userAddress, params = self.handle_public_address('fetchPositions', params)
        request = {
            'type': 'subaccount_info',
            'subaccount': self.convert_address_to_sender(userAddress),
        }
        response = await self.v1GatewayGetQuery(self.extend(request, params))
        # the response is the same
        data = self.safe_dict(response, 'data', {})
        positions = self.safe_list(data, 'perp_balances', [])
        symbols = self.market_symbols(symbols)
        result = []
        for i in range(0, len(positions)):
            position = self.extend(self.parse_position(positions[i], None), params)
            if position['contractSize'] == 0:
                continue
            result.append(position)
        return self.filter_by_array_positions(result, 'symbol', symbols, False)

    async def query_nonces(self):
        request = {
            'type': 'nonces',
            'address': self.walletAddress,
        }
        response = await self.v1GatewayGetQuery(request)
        #
        # {
        #     "status":"success",
        #     "data":{
        #       "tx_nonce": 0,
        #       "order_nonce": 1753048133299863552
        #     },
        #     "request_type": "query_nonces",
        # }
        #
        return self.safe_dict(response, 'data', {})

    async def withdraw(self, code: str, amount, address, tag=None, params={}):
        """
        make a withdrawal
        :see: https://docs.vertexprotocol.com/developer-resources/api/withdrawing-on-chain
        :param str code: unified currency code
        :param float amount: the amount to withdraw
        :param str address: the address to withdraw to
        :param str tag:
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict: a `transaction structure <https://docs.ccxt_zagrava.com/#/?id=transaction-structure>`
        """
        self.check_required_credentials()
        await self.load_markets()
        currency = self.currency(code)
        contracts = await self.query_contracts()
        chainId = self.safe_string(contracts, 'chain_id')
        verifyingContractAddress = self.safe_string(contracts, 'endpoint_addr')
        nonces = await self.query_nonces()
        nonce = self.safe_number(nonces, 'tx_nonce')
        withdraw = {
            'sender': self.convert_address_to_sender(self.walletAddress),
            'productId': self.parse_to_numeric(currency['id']),
            'amount': str(amount),
            'nonce': nonce,
        }
        request = {
            'withdraw_collateral': {
                'tx': {
                    'sender': withdraw['sender'],
                    'productId': withdraw['productId'],
                    'amount': withdraw['amount'],
                    'nonce': self.number_to_string(withdraw['nonce']),
                },
                'signature': self.build_withdraw_sig(withdraw, chainId, verifyingContractAddress),
            },
        }
        response = await self.v1GatewayPostExecute(self.extend(request, params))
        #
        # {
        #     "status": "success",
        #     "signature": {signature},
        #     "request_type": "execute_withdraw_collateral"
        # }
        #
        return response

    def handle_public_address(self, methodName: str, params: dict):
        userAux = None
        userAux, params = self.handle_option_and_params(params, methodName, 'user')
        user = userAux
        user, params = self.handle_option_and_params(params, methodName, 'address', userAux)
        if (user is not None) and (user != ''):
            return [user, params]
        if (self.walletAddress is not None) and (self.walletAddress != ''):
            return [self.walletAddress, params]
        raise ArgumentsRequired(self.id + ' ' + methodName + '() requires a user parameter inside \'params\' or the wallet address set')

    def handle_errors(self, code, reason, url, method, headers, body, response, requestHeaders, requestBody):
        if not response:
            return None  # fallback to default error handler
        #
        #
        status = self.safe_string(response, 'status', '')
        if status == 'failure':
            message = self.safe_string(response, 'error')
            feedback = self.id + ' ' + body
            errorCode = self.safe_string(response, 'error_code')
            self.throw_exactly_matched_exception(self.exceptions['exact'], errorCode, feedback)
            self.throw_broadly_matched_exception(self.exceptions['broad'], message, feedback)
            raise ExchangeError(feedback)
        return None

    def sign(self, path, api='public', method='GET', params={}, headers=None, body=None):
        version = self.safe_string(api, 0)
        type = self.safe_string(api, 1)
        url = self.implode_hostname(self.urls['api'][version][type])
        if version != 'v1' or type != 'archive':
            url = url + '/' + path
        if method == 'POST':
            headers = {
                'Content-Type': 'application/json',
            }
            body = self.json(params)
        else:
            if params:
                url += '?' + self.urlencode(params)
        return {'url': url, 'method': method, 'body': body, 'headers': headers}
