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

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

from ccxt.base.exchange import Exchange
from ccxt.abstract.delta import ImplicitAPI
import hashlib
from ccxt.base.types import Balances, Currencies, Currency, Greeks, Int, Leverage, MarginMode, MarginModification, Market, MarketInterface, Num, Option, Order, OrderBook, OrderSide, OrderType, Position, Str, Strings, Ticker, Tickers, Trade
from typing import List
from ccxt.base.errors import ExchangeError
from ccxt.base.errors import AuthenticationError
from ccxt.base.errors import ArgumentsRequired
from ccxt.base.errors import BadRequest
from ccxt.base.errors import BadSymbol
from ccxt.base.errors import InsufficientFunds
from ccxt.base.errors import InvalidOrder
from ccxt.base.errors import OrderNotFound
from ccxt.base.errors import ExchangeNotAvailable
from ccxt.base.decimal_to_precision import TICK_SIZE
from ccxt.base.precise import Precise


class delta(Exchange, ImplicitAPI):

    def describe(self):
        return self.deep_extend(super(delta, self).describe(), {
            'id': 'delta',
            'name': 'Delta Exchange',
            'countries': ['VC'],  # Saint Vincent and the Grenadines
            'rateLimit': 300,
            'version': 'v2',
            # new metainfo interface
            'has': {
                'CORS': None,
                'spot': True,
                'margin': False,
                'swap': True,
                'future': False,
                'option': True,
                'addMargin': True,
                'cancelAllOrders': True,
                'cancelOrder': True,
                'closeAllPositions': True,
                'closePosition': False,
                'createOrder': True,
                'createReduceOnlyOrder': True,
                'editOrder': True,
                'fetchBalance': True,
                'fetchClosedOrders': True,
                'fetchCurrencies': True,
                'fetchDeposit': None,
                'fetchDepositAddress': True,
                'fetchDeposits': None,
                'fetchFundingHistory': False,
                'fetchFundingRate': True,
                'fetchFundingRateHistory': False,
                'fetchFundingRates': True,
                'fetchGreeks': True,
                'fetchIndexOHLCV': True,
                'fetchLedger': True,
                'fetchLeverage': True,
                'fetchLeverageTiers': False,  # An infinite number of tiers, see examples/js/delta-maintenance-margin-rate-max-leverage.js
                'fetchMarginMode': True,
                'fetchMarginModes': False,
                'fetchMarketLeverageTiers': False,
                'fetchMarkets': True,
                'fetchMarkOHLCV': True,
                'fetchMySettlementHistory': False,
                'fetchMyTrades': True,
                'fetchOHLCV': True,
                'fetchOpenInterest': True,
                'fetchOpenOrders': True,
                'fetchOption': True,
                'fetchOptionChain': False,
                'fetchOrderBook': True,
                'fetchPosition': True,
                'fetchPositionMode': False,
                'fetchPositions': True,
                'fetchPremiumIndexOHLCV': False,
                'fetchSettlementHistory': True,
                'fetchStatus': True,
                'fetchTicker': True,
                'fetchTickers': True,
                'fetchTime': True,
                'fetchTrades': True,
                'fetchTransfer': None,
                'fetchTransfers': None,
                'fetchUnderlyingAssets': False,
                'fetchVolatilityHistory': False,
                'fetchWithdrawal': None,
                'fetchWithdrawals': None,
                'reduceMargin': True,
                'setLeverage': True,
                'setMargin': False,
                'setMarginMode': False,
                'setPositionMode': False,
                'transfer': False,
                'withdraw': False,
            },
            'timeframes': {
                '1m': '1m',
                '3m': '3m',
                '5m': '5m',
                '15m': '15m',
                '30m': '30m',
                '1h': '1h',
                '2h': '2h',
                '4h': '4h',
                '6h': '6h',
                '1d': '1d',
                '7d': '7d',
                '1w': '1w',
                '2w': '2w',
                '1M': '30d',
            },
            'urls': {
                'logo': 'https://user-images.githubusercontent.com/1294454/99450025-3be60a00-2931-11eb-9302-f4fd8d8589aa.jpg',
                'test': {
                    'public': 'https://testnet-api.delta.exchange',
                    'private': 'https://testnet-api.delta.exchange',
                },
                'api': {
                    'public': 'https://api.delta.exchange',
                    'private': 'https://api.delta.exchange',
                },
                'www': 'https://www.delta.exchange',
                'doc': [
                    'https://docs.delta.exchange',
                ],
                'fees': 'https://www.delta.exchange/fees',
                'referral': 'https://www.delta.exchange/app/signup/?code=IULYNB',
            },
            'api': {
                'public': {
                    'get': [
                        'assets',
                        'indices',
                        'products',
                        'products/{symbol}',
                        'tickers',
                        'tickers/{symbol}',
                        'l2orderbook/{symbol}',
                        'trades/{symbol}',
                        'stats',
                        'history/candles',
                        'history/sparklines',
                        'settings',
                    ],
                },
                'private': {
                    'get': [
                        'orders',
                        'products/{product_id}/orders/leverage',
                        'positions/margined',
                        'positions',
                        'orders/history',
                        'fills',
                        'fills/history/download/csv',
                        'wallet/balances',
                        'wallet/transactions',
                        'wallet/transactions/download',
                        'wallets/sub_accounts_transfer_history',
                        'users/trading_preferences',
                        'sub_accounts',
                        'profile',
                        'deposits/address',
                        'orders/leverage',
                    ],
                    'post': [
                        'orders',
                        'orders/bracket',
                        'orders/batch',
                        'products/{product_id}/orders/leverage',
                        'positions/change_margin',
                        'positions/close_all',
                        'wallets/sub_account_balance_transfer',
                        'orders/cancel_after',
                        'orders/leverage',
                    ],
                    'put': [
                        'orders',
                        'orders/bracket',
                        'orders/batch',
                        'positions/auto_topup',
                        'users/update_mmp',
                        'users/reset_mmp',
                    ],
                    'delete': [
                        'orders',
                        'orders/all',
                        'orders/batch',
                    ],
                },
            },
            'fees': {
                'trading': {
                    'tierBased': True,
                    'percentage': True,
                    'taker': self.parse_number('0.0015'),
                    'maker': self.parse_number('0.0010'),
                    'tiers': {
                        'taker': [
                            [self.parse_number('0'), self.parse_number('0.0015')],
                            [self.parse_number('100'), self.parse_number('0.0013')],
                            [self.parse_number('250'), self.parse_number('0.0013')],
                            [self.parse_number('1000'), self.parse_number('0.001')],
                            [self.parse_number('5000'), self.parse_number('0.0009')],
                            [self.parse_number('10000'), self.parse_number('0.00075')],
                            [self.parse_number('20000'), self.parse_number('0.00065')],
                        ],
                        'maker': [
                            [self.parse_number('0'), self.parse_number('0.001')],
                            [self.parse_number('100'), self.parse_number('0.001')],
                            [self.parse_number('250'), self.parse_number('0.0009')],
                            [self.parse_number('1000'), self.parse_number('0.00075')],
                            [self.parse_number('5000'), self.parse_number('0.0006')],
                            [self.parse_number('10000'), self.parse_number('0.0005')],
                            [self.parse_number('20000'), self.parse_number('0.0005')],
                        ],
                    },
                },
            },
            'options': {
                'networks': {
                    'TRC20': 'TRC20(TRON)',
                    'BEP20': 'BEP20(BSC)',
                },
            },
            'precisionMode': TICK_SIZE,
            'requiredCredentials': {
                'apiKey': True,
                'secret': True,
            },
            'exceptions': {
                'exact': {
                    # Margin required to place order with selected leverage and quantity is insufficient.
                    'insufficient_margin': InsufficientFunds,  # {"error":{"code":"insufficient_margin","context":{"available_balance":"0.000000000000000000","required_additional_balance":"1.618626000000000000000000000"}},"success":false}
                    'order_size_exceed_available': InvalidOrder,  # The order book doesn't have sufficient liquidity, hence the order couldnt be filled, for example, ioc orders
                    'risk_limits_breached': BadRequest,  # orders couldn't be placed will breach allowed risk limits.
                    'invalid_contract': BadSymbol,  # The contract/product is either doesn't exist or has already expired.
                    'immediate_liquidation': InvalidOrder,  # Order will cause immediate liquidation.
                    'out_of_bankruptcy': InvalidOrder,  # Order prices are out of position bankruptcy limits.
                    'self_matching_disrupted_post_only': InvalidOrder,  # Self matching is not allowed during auction.
                    'immediate_execution_post_only': InvalidOrder,  # orders couldn't be placed includes post only orders which will be immediately executed
                    'bad_schema': BadRequest,  # {"error":{"code":"bad_schema","context":{"schema_errors":[{"code":"validation_error","message":"id is required","param":""}]}},"success":false}
                    'invalid_api_key': AuthenticationError,  # {"success":false,"error":{"code":"invalid_api_key"}}
                    'invalid_signature': AuthenticationError,  # {"success":false,"error":{"code":"invalid_signature"}}
                    'open_order_not_found': OrderNotFound,  # {"error":{"code":"open_order_not_found"},"success":false}
                    'unavailable': ExchangeNotAvailable,  # {"error":{"code":"unavailable"},"success":false}
                },
                'broad': {
                },
            },
        })

    def create_expired_option_market(self, symbol: str):
        # support expired option contracts
        quote = 'USDT'
        optionParts = symbol.split('-')
        symbolBase = symbol.split('/')
        base = None
        expiry = None
        optionType = None
        if symbol.find('/') > -1:
            base = self.safe_string(symbolBase, 0)
            expiry = self.safe_string(optionParts, 1)
            optionType = self.safe_string(optionParts, 3)
        else:
            base = self.safe_string(optionParts, 1)
            expiry = self.safe_string(optionParts, 3)
            optionType = self.safe_string(optionParts, 0)
        settle = quote
        strike = self.safe_string(optionParts, 2)
        datetime = self.convert_expire_date(expiry)
        timestamp = self.parse8601(datetime)
        return {
            'id': optionType + '-' + base + '-' + strike + '-' + expiry,
            'symbol': base + '/' + quote + ':' + settle + '-' + expiry + '-' + strike + '-' + optionType,
            'base': base,
            'quote': quote,
            'settle': settle,
            'baseId': base,
            'quoteId': quote,
            'settleId': settle,
            'active': False,
            'type': 'option',
            'linear': None,
            'inverse': None,
            'spot': False,
            'swap': False,
            'future': False,
            'option': True,
            'margin': False,
            'contract': True,
            'contractSize': self.parse_number('1'),
            'expiry': timestamp,
            'expiryDatetime': datetime,
            'optionType': 'call' if (optionType == 'C') else 'put',
            'strike': self.parse_number(strike),
            'precision': {
                'amount': None,
                'price': None,
            },
            'limits': {
                'amount': {
                    'min': None,
                    'max': None,
                },
                'price': {
                    'min': None,
                    'max': None,
                },
                'cost': {
                    'min': None,
                    'max': None,
                },
            },
            'info': None,
        }

    def safe_market(self, marketId: Str = None, market: Market = None, delimiter: Str = None, marketType: Str = None) -> MarketInterface:
        isOption = (marketId is not None) and ((marketId.endswith('-C')) or (marketId.endswith('-P')) or (marketId.startswith('C-')) or (marketId.startswith('P-')))
        if isOption and not (marketId in self.markets_by_id):
            # handle expired option contracts
            return self.create_expired_option_market(marketId)
        return super(delta, self).safe_market(marketId, market, delimiter, marketType)

    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 = self.publicGetSettings(params)
        # full response sample under `fetchStatus`
        result = self.safe_dict(response, 'result', {})
        return self.safe_integer_product(result, 'server_time', 0.001)

    def fetch_status(self, params={}):
        """
        the latest known information on the availability of the exchange API
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict: a `status structure <https://docs.ccxt.com/#/?id=exchange-status-structure>`
        """
        response = self.publicGetSettings(params)
        #
        #     {
        #         "result": {
        #           "deto_liquidity_mining_daily_reward": "40775",
        #           "deto_msp": "1.0",
        #           "deto_staking_daily_reward": "23764.08",
        #           "enabled_wallets": [
        #             "BTC",
        #             ...
        #           ],
        #           "portfolio_margin_params": {
        #             "enabled_portfolios": {
        #               ".DEAVAXUSDT": {
        #                 "asset_id": 5,
        #                 "futures_contingency_margin_percent": "1",
        #                 "interest_rate": "0",
        #                 "maintenance_margin_multiplier": "0.8",
        #                 "max_price_shock": "20",
        #                 "max_short_notional_limit": "2000",
        #                 "options_contingency_margin_percent": "1",
        #                 "options_discount_range": "10",
        #                 "options_liq_band_range_percentage": "25",
        #                 "settling_asset": "USDT",
        #                 "sort_priority": 5,
        #                 "underlying_asset": "AVAX",
        #                 "volatility_down_shock": "30",
        #                 "volatility_up_shock": "45"
        #               },
        #               ...
        #             },
        #             "portfolio_enabled_contracts": [
        #               "futures",
        #               "perpetual_futures",
        #               "call_options",
        #               "put_options"
        #             ]
        #           },
        #           "server_time": 1650640673500273,
        #           "trade_farming_daily_reward": "100000",
        #           "circulating_supply": "140000000",
        #           "circulating_supply_update_time": "1636752800",
        #           "deto_referral_mining_daily_reward": "0",
        #           "deto_total_reward_pool": "100000000",
        #           "deto_trade_mining_daily_reward": "0",
        #           "kyc_deposit_limit": "20",
        #           "kyc_withdrawal_limit": "10000",
        #           "maintenance_start_time": "1650387600000000",
        #           "msp_deto_commission_percent": "25",
        #           "under_maintenance": "false"
        #         },
        #         "success": True
        #     }
        #
        result = self.safe_dict(response, 'result', {})
        underMaintenance = self.safe_string(result, 'under_maintenance')
        status = 'maintenance' if (underMaintenance == 'true') else 'ok'
        updated = self.safe_integer_product(result, 'server_time', 0.001, self.milliseconds())
        return {
            'status': status,
            'updated': updated,
            'eta': None,
            'url': None,
            'info': response,
        }

    def fetch_currencies(self, params={}) -> Currencies:
        """
        fetches all available currencies on an exchange
        :see: https://docs.delta.exchange/#get-list-of-all-assets
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict: an associative dictionary of currencies
        """
        response = self.publicGetAssets(params)
        #
        #     {
        #         "result":[
        #             {
        #                 "base_withdrawal_fee":"0.0005",
        #                 "deposit_status":"enabled",
        #                 "id":2,
        #                 "interest_credit":true,
        #                 "interest_slabs":[
        #                     {"limit":"0.1","rate":"0"},
        #                     {"limit":"1","rate":"0.05"},
        #                     {"limit":"5","rate":"0.075"},
        #                     {"limit":"10","rate":"0.1"},
        #                     {"limit":"9999999999999999","rate":"0"}
        #                 ],
        #                 "kyc_deposit_limit":"10",
        #                 "kyc_withdrawal_limit":"2",
        #                 "min_withdrawal_amount":"0.001",
        #                 "minimum_precision":4,
        #                 "name":"Bitcoin",
        #                 "precision":8,
        #                 "sort_priority":1,
        #                 "symbol":"BTC",
        #                 "variable_withdrawal_fee":"0",
        #                 "withdrawal_status":"enabled"
        #             },
        #         ],
        #         "success":true
        #     }
        #
        currencies = self.safe_list(response, 'result', [])
        result: dict = {}
        for i in range(0, len(currencies)):
            currency = currencies[i]
            id = self.safe_string(currency, 'symbol')
            numericId = self.safe_integer(currency, 'id')
            code = self.safe_currency_code(id)
            depositStatus = self.safe_string(currency, 'deposit_status')
            withdrawalStatus = self.safe_string(currency, 'withdrawal_status')
            depositsEnabled = (depositStatus == 'enabled')
            withdrawalsEnabled = (withdrawalStatus == 'enabled')
            active = depositsEnabled and withdrawalsEnabled
            result[code] = {
                'id': id,
                'numericId': numericId,
                'code': code,
                'name': self.safe_string(currency, 'name'),
                'info': currency,  # the original payload
                'active': active,
                'deposit': depositsEnabled,
                'withdraw': withdrawalsEnabled,
                'fee': self.safe_number(currency, 'base_withdrawal_fee'),
                'precision': self.parse_number(self.parse_precision(self.safe_string(currency, 'precision'))),
                'limits': {
                    'amount': {'min': None, 'max': None},
                    'withdraw': {
                        'min': self.safe_number(currency, 'min_withdrawal_amount'),
                        'max': None,
                    },
                },
                'networks': {},
            }
        return result

    def load_markets(self, reload=False, params={}):
        markets = super(delta, self).load_markets(reload, params)
        currenciesByNumericId = self.safe_dict(self.options, 'currenciesByNumericId')
        if (currenciesByNumericId is None) or reload:
            self.options['currenciesByNumericId'] = self.index_by_stringified_numeric_id(self.currencies)
        marketsByNumericId = self.safe_dict(self.options, 'marketsByNumericId')
        if (marketsByNumericId is None) or reload:
            self.options['marketsByNumericId'] = self.index_by_stringified_numeric_id(self.markets)
        return markets

    def index_by_stringified_numeric_id(self, input):
        result: dict = {}
        if input is None:
            return None
        keys = list(input.keys())
        for i in range(0, len(keys)):
            key = keys[i]
            item = input[key]
            numericIdString = self.safe_string(item, 'numericId')
            if numericIdString is None:
                continue
            result[numericIdString] = item
        return result

    def fetch_markets(self, params={}) -> List[Market]:
        """
        retrieves data on all markets for delta
        :see: https://docs.delta.exchange/#get-list-of-products
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict[]: an array of objects representing market data
        """
        response = self.publicGetProducts(params)
        #
        #     {
        #         "meta":{"after":null, "before":null, "limit":100, "total_count":81},
        #         "result":[
        #             # the below response represents item from perpetual market
        #             {
        #                 "annualized_funding":"5.475000000000000000",
        #                 "is_quanto":false,
        #                 "ui_config":{
        #                     "default_trading_view_candle":"15",
        #                     "leverage_slider_values":[1,3,5,10,25,50],
        #                     "price_clubbing_values":[0.001,0.005,0.05,0.1,0.5,1,5],
        #                     "show_bracket_orders":false,
        #                     "sort_priority":29,
        #                     "tags":[]
        #                 },
        #                 "basis_factor_max_limit":"0.15",
        #                 "symbol":"P-LINK-D-151120",
        #                 "id":1584,
        #                 "default_leverage":"5.000000000000000000",
        #                 "maker_commission_rate":"0.0005",
        #                 "contract_unit_currency":"LINK",
        #                 "strike_price":"12.507948",
        #                 "settling_asset":{
        #                     # asset structure
        #                 },
        #                 "auction_start_time":null,
        #                 "auction_finish_time":null,
        #                 "settlement_time":"2020-11-15T12:00:00Z",
        #                 "launch_time":"2020-11-14T11:55:05Z",
        #                 "spot_index":{
        #                     # index structure
        #                 },
        #                 "trading_status":"operational",
        #                 "tick_size":"0.001",
        #                 "position_size_limit":100000,
        #                 "notional_type":"vanilla",  # vanilla, inverse
        #                 "price_band":"0.4",
        #                 "barrier_price":null,
        #                 "description":"Daily LINK PUT options quoted in USDT and settled in USDT",
        #                 "insurance_fund_margin_contribution":"1",
        #                 "quoting_asset":{
        #                     # asset structure
        #                 },
        #                 "liquidation_penalty_factor":"0.2",
        #                 "product_specs":{"max_volatility":3,"min_volatility":0.3,"spot_price_band":"0.40"},
        #                 "initial_margin_scaling_factor":"0.0001",
        #                 "underlying_asset":{
        #                     # asset structure
        #                 },
        #                 "state":"live",
        #                 "contract_value":"1",
        #                 "initial_margin":"2",
        #                 "impact_size":5000,
        #                 "settlement_price":null,
        #                 "contract_type":"put_options",  # put_options, call_options, move_options, perpetual_futures, interest_rate_swaps, futures, spreads
        #                 "taker_commission_rate":"0.0005",
        #                 "maintenance_margin":"1",
        #                 "short_description":"LINK Daily PUT Options",
        #                 "maintenance_margin_scaling_factor":"0.00005",
        #                 "funding_method":"mark_price",
        #                 "max_leverage_notional":"20000"
        #             },
        #             # the below response represents item from spot market
        #             {
        #                 "position_size_limit": 10000000,
        #                 "settlement_price": null,
        #                 "funding_method": "mark_price",
        #                 "settling_asset": null,
        #                 "impact_size": 10,
        #                 "id": 32258,
        #                 "auction_finish_time": null,
        #                 "description": "Solana tether spot market",
        #                 "trading_status": "operational",
        #                 "tick_size": "0.01",
        #                 "liquidation_penalty_factor": "1",
        #                 "spot_index": {
        #                     "config": {"quoting_asset": "USDT", "service_id": 8, "underlying_asset": "SOL"},
        #                     "constituent_exchanges": [
        #                         {"exchange": "binance", "health_interval": 60, "health_priority": 1, "weight": 1},
        #                         {"exchange": "huobi", "health_interval": 60, "health_priority": 2, "weight": 1}
        #                     ],
        #                     "constituent_indices": null,
        #                     "description": "Solana index from binance and huobi",
        #                     "health_interval": 300,
        #                     "id": 105,
        #                     "impact_size": "40.000000000000000000",
        #                     "index_type": "spot_pair",
        #                     "is_composite": False,
        #                     "price_method": "ltp",
        #                     "quoting_asset_id": 5,
        #                     "symbol": ".DESOLUSDT",
        #                     "tick_size": "0.000100000000000000",
        #                     "underlying_asset_id": 66
        #                 },
        #                 "contract_type": "spot",
        #                 "launch_time": "2022-02-03T10:18:11Z",
        #                 "symbol": "SOL_USDT",
        #                 "disruption_reason": null,
        #                 "settlement_time": null,
        #                 "insurance_fund_margin_contribution": "1",
        #                 "is_quanto": False,
        #                 "maintenance_margin": "5",
        #                 "taker_commission_rate": "0.0005",
        #                 "auction_start_time": null,
        #                 "max_leverage_notional": "10000000",
        #                 "state": "live",
        #                 "annualized_funding": "0",
        #                 "notional_type": "vanilla",
        #                 "price_band": "100",
        #                 "product_specs": {"kyc_required": False, "max_order_size": 2000, "min_order_size": 0.01, "quoting_precision": 4, "underlying_precision": 2},
        #                 "default_leverage": "1.000000000000000000",
        #                 "initial_margin": "10",
        #                 "maintenance_margin_scaling_factor": "1",
        #                 "ui_config": {
        #                     "default_trading_view_candle": "1d",
        #                     "leverage_slider_values": [],
        #                     "price_clubbing_values": [0.01, 0.05, 0.1, 0.5, 1, 2.5, 5],
        #                     "show_bracket_orders": False,
        #                     "sort_priority": 2,
        #                     "tags": []
        #                 },
        #                 "basis_factor_max_limit": "10000",
        #                 "contract_unit_currency": "SOL",
        #                 "strike_price": null,
        #                 "quoting_asset": {
        #                     "base_withdrawal_fee": "10.000000000000000000",
        #                     "deposit_status": "enabled",
        #                     "id": 5,
        #                     "interest_credit": False,
        #                     "interest_slabs": null,
        #                     "kyc_deposit_limit": "100000.000000000000000000",
        #                     "kyc_withdrawal_limit": "10000.000000000000000000",
        #                     "min_withdrawal_amount": "30.000000000000000000",
        #                     "minimum_precision": 2,
        #                     "name": "Tether",
        #                     "networks": [
        #                         {"base_withdrawal_fee": "25", "deposit_status": "enabled", "memo_required": False, "network": "ERC20", "variable_withdrawal_fee": "0", "withdrawal_status": "enabled"},
        #                         {"base_withdrawal_fee": "1", "deposit_status": "enabled", "memo_required": False, "network": "BEP20(BSC)", "variable_withdrawal_fee": "0", "withdrawal_status": "enabled"},
        #                         {"base_withdrawal_fee": "1", "deposit_status": "disabled", "memo_required": False, "network": "TRC20(TRON)", "variable_withdrawal_fee": "0", "withdrawal_status": "disabled"}
        #                     ],
        #                     "precision": 8,
        #                     "sort_priority": 1,
        #                     "symbol": "USDT",
        #                     "variable_withdrawal_fee": "0.000000000000000000",
        #                     "withdrawal_status": "enabled"
        #                 },
        #                 "maker_commission_rate": "0.0005",
        #                 "initial_margin_scaling_factor": "2",
        #                 "underlying_asset": {
        #                     "base_withdrawal_fee": "0.000000000000000000",
        #                     "deposit_status": "enabled",
        #                     "id": 66,
        #                     "interest_credit": False,
        #                     "interest_slabs": null,
        #                     "kyc_deposit_limit": "0.000000000000000000",
        #                     "kyc_withdrawal_limit": "0.000000000000000000",
        #                     "min_withdrawal_amount": "0.020000000000000000",
        #                     "minimum_precision": 4,
        #                     "name": "Solana",
        #                     "networks": [
        #                         {"base_withdrawal_fee": "0.01", "deposit_status": "enabled", "memo_required": False, "network": "SOLANA", "variable_withdrawal_fee": "0", "withdrawal_status": "enabled"},
        #                         {"base_withdrawal_fee": "0.01", "deposit_status": "enabled", "memo_required": False, "network": "BEP20(BSC)", "variable_withdrawal_fee": "0", "withdrawal_status": "enabled"}
        #                     ],
        #                     "precision": 8,
        #                     "sort_priority": 7,
        #                     "symbol": "SOL",
        #                     "variable_withdrawal_fee": "0.000000000000000000",
        #                     "withdrawal_status": "enabled"
        #                 },
        #                 "barrier_price": null,
        #                 "contract_value": "1",
        #                 "short_description": "SOL-USDT spot market"
        #             },
        #         ],
        #         "success":true
        #     }
        #
        markets = self.safe_list(response, 'result', [])
        result = []
        for i in range(0, len(markets)):
            market = markets[i]
            type = self.safe_string(market, 'contract_type')
            if type == 'options_combos':
                continue
            # settlingAsset = self.safe_value(market, 'settling_asset', {})
            quotingAsset = self.safe_dict(market, 'quoting_asset', {})
            underlyingAsset = self.safe_dict(market, 'underlying_asset', {})
            settlingAsset = self.safe_dict(market, 'settling_asset')
            productSpecs = self.safe_dict(market, 'product_specs', {})
            baseId = self.safe_string(underlyingAsset, 'symbol')
            quoteId = self.safe_string(quotingAsset, 'symbol')
            settleId = self.safe_string(settlingAsset, 'symbol')
            id = self.safe_string(market, 'symbol')
            numericId = self.safe_integer(market, 'id')
            base = self.safe_currency_code(baseId)
            quote = self.safe_currency_code(quoteId)
            settle = self.safe_currency_code(settleId)
            callOptions = (type == 'call_options')
            putOptions = (type == 'put_options')
            moveOptions = (type == 'move_options')
            spot = (type == 'spot')
            swap = (type == 'perpetual_futures')
            future = (type == 'futures')
            option = (callOptions or putOptions or moveOptions)
            strike = self.safe_string(market, 'strike_price')
            expiryDatetime = self.safe_string(market, 'settlement_time')
            expiry = self.parse8601(expiryDatetime)
            contractSize = self.safe_number(market, 'contract_value')
            amountPrecision = None
            if spot:
                amountPrecision = self.parse_number(self.parse_precision(self.safe_string(productSpecs, 'underlying_precision')))  # seems inverse of 'impact_size'
            else:
                # other markets(swap, futures, move, spread, irs) seem to use the step of '1' contract
                amountPrecision = self.parse_number('1')
            linear = (settle == base)
            optionType = None
            symbol = base + '/' + quote
            if swap or future or option:
                symbol = symbol + ':' + settle
                if future or option:
                    symbol = symbol + '-' + self.yymmdd(expiry)
                    if option:
                        type = 'option'
                        letter = 'C'
                        optionType = 'call'
                        if putOptions:
                            letter = 'P'
                            optionType = 'put'
                        elif moveOptions:
                            letter = 'M'
                            optionType = 'move'
                        symbol = symbol + '-' + strike + '-' + letter
                    else:
                        type = 'future'
                else:
                    type = 'swap'
            state = self.safe_string(market, 'state')
            result.append({
                'id': id,
                'numericId': numericId,
                'symbol': symbol,
                'base': base,
                'quote': quote,
                'settle': settle,
                'baseId': baseId,
                'quoteId': quoteId,
                'settleId': settleId,
                'type': type,
                'spot': spot,
                'margin': None if spot else False,
                'swap': swap,
                'future': future,
                'option': option,
                'active': (state == 'live'),
                'contract': not spot,
                'linear': None if spot else linear,
                'inverse': None if spot else not linear,
                'taker': self.safe_number(market, 'taker_commission_rate'),
                'maker': self.safe_number(market, 'maker_commission_rate'),
                'contractSize': contractSize,
                'expiry': expiry,
                'expiryDatetime': expiryDatetime,
                'strike': self.parse_number(strike),
                'optionType': optionType,
                'precision': {
                    'amount': amountPrecision,
                    'price': self.safe_number(market, 'tick_size'),
                },
                'limits': {
                    'leverage': {
                        'min': None,
                        'max': None,
                    },
                    'amount': {
                        'min': self.parse_number('1'),
                        'max': self.safe_number(market, 'position_size_limit'),
                    },
                    'price': {
                        'min': None,
                        'max': None,
                    },
                    'cost': {
                        'min': self.safe_number(market, 'min_size'),
                        'max': None,
                    },
                },
                'created': self.parse8601(self.safe_string(market, 'launch_time')),
                'info': market,
            })
        return result

    def parse_ticker(self, ticker: dict, market: Market = None) -> Ticker:
        #
        # spot: fetchTicker, fetchTickers
        #
        #     {
        #         "close": 30634.0,
        #         "contract_type": "spot",
        #         "greeks": null,
        #         "high": 30780.0,
        #         "low": 30340.5,
        #         "mark_price": "48000",
        #         "oi": "0.0000",
        #         "oi_change_usd_6h": "0.0000",
        #         "oi_contracts": "0",
        #         "oi_value": "0.0000",
        #         "oi_value_symbol": "BTC",
        #         "oi_value_usd": "0.0000",
        #         "open": 30464.0,
        #         "price_band": null,
        #         "product_id": 8320,
        #         "quotes": {},
        #         "size": 2.6816639999999996,
        #         "spot_price": "30637.91465121",
        #         "symbol": "BTC_USDT",
        #         "timestamp": 1689139767621299,
        #         "turnover": 2.6816639999999996,
        #         "turnover_symbol": "BTC",
        #         "turnover_usd": 81896.45613400004,
        #         "volume": 2.6816639999999996
        #     }
        #
        # swap: fetchTicker, fetchTickers
        #
        #     {
        #         "close": 30600.5,
        #         "contract_type": "perpetual_futures",
        #         "funding_rate": "0.00602961",
        #         "greeks": null,
        #         "high": 30803.0,
        #         "low": 30265.5,
        #         "mark_basis": "-0.45601594",
        #         "mark_price": "30600.10481568",
        #         "oi": "469.9190",
        #         "oi_change_usd_6h": "2226314.9900",
        #         "oi_contracts": "469919",
        #         "oi_value": "469.9190",
        #         "oi_value_symbol": "BTC",
        #         "oi_value_usd": "14385640.6802",
        #         "open": 30458.5,
        #         "price_band": {
        #             "lower_limit": "29067.08312627",
        #             "upper_limit": "32126.77608693"
        #         },
        #         "product_id": 139,
        #         "quotes": {
        #             "ask_iv": null,
        #             "ask_size": "965",
        #             "best_ask": "30600.5",
        #             "best_bid": "30599.5",
        #             "bid_iv": null,
        #             "bid_size": "196",
        #             "impact_mid_price": null,
        #             "mark_iv": "-0.44931641"
        #         },
        #         "size": 1226303,
        #         "spot_price": "30612.85362773",
        #         "symbol": "BTCUSDT",
        #         "timestamp": 1689136597460456,
        #         "turnover": 37392218.45999999,
        #         "turnover_symbol": "USDT",
        #         "turnover_usd": 37392218.45999999,
        #         "volume": 1226.3029999999485
        #     }
        #
        # option: fetchTicker, fetchTickers
        #
        #     {
        #         "contract_type": "call_options",
        #         "greeks": {
        #             "delta": "0.60873994",
        #             "gamma": "0.00014854",
        #             "rho": "7.71808010",
        #             "spot": "30598.49040622",
        #             "theta": "-30.44743017",
        #             "vega": "24.83508248"
        #         },
        #         "mark_price": "1347.74819696",
        #         "mark_vol": "0.39966303",
        #         "oi": "2.7810",
        #         "oi_change_usd_6h": "0.0000",
        #         "oi_contracts": "2781",
        #         "oi_value": "2.7810",
        #         "oi_value_symbol": "BTC",
        #         "oi_value_usd": "85127.4337",
        #         "price_band": {
        #             "lower_limit": "91.27423497",
        #             "upper_limit": "7846.19454697"
        #         },
        #         "product_id": 107150,
        #         "quotes": {
        #             "ask_iv": "0.41023239",
        #             "ask_size": "2397",
        #             "best_ask": "1374",
        #             "best_bid": "1322",
        #             "bid_iv": "0.38929375",
        #             "bid_size": "3995",
        #             "impact_mid_price": null,
        #             "mark_iv": "0.39965618"
        #         },
        #         "spot_price": "30598.43379314",
        #         "strike_price": "30000",
        #         "symbol": "C-BTC-30000-280723",
        #         "timestamp": 1689136932893181,
        #         "turnover_symbol": "USDT"
        #     }
        #
        timestamp = self.safe_integer_product(ticker, 'timestamp', 0.001)
        marketId = self.safe_string(ticker, 'symbol')
        symbol = self.safe_symbol(marketId, market)
        last = self.safe_string(ticker, 'close')
        quotes = self.safe_dict(ticker, 'quotes', {})
        return self.safe_ticker({
            'symbol': symbol,
            'timestamp': timestamp,
            'datetime': self.iso8601(timestamp),
            'high': self.safe_number(ticker, 'high'),
            'low': self.safe_number(ticker, 'low'),
            'bid': self.safe_number(quotes, 'best_bid'),
            'bidVolume': self.safe_number(quotes, 'bid_size'),
            'ask': self.safe_number(quotes, 'best_ask'),
            'askVolume': self.safe_number(quotes, 'ask_size'),
            'vwap': None,
            'open': self.safe_string(ticker, 'open'),
            'close': last,
            'last': last,
            'previousClose': None,
            'change': None,
            'percentage': None,
            'average': None,
            'baseVolume': self.safe_number(ticker, 'volume'),
            'quoteVolume': self.safe_number(ticker, 'turnover'),
            'info': ticker,
        }, market)

    def fetch_ticker(self, symbol: str, params={}) -> Ticker:
        """
        fetches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
        :see: https://docs.delta.exchange/#get-ticker-for-a-product-by-symbol
        :param str symbol: unified symbol of the market to fetch the ticker for
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
        """
        self.load_markets()
        market = self.market(symbol)
        request: dict = {
            'symbol': market['id'],
        }
        response = self.publicGetTickersSymbol(self.extend(request, params))
        #
        # spot
        #
        #     {
        #         "result": {
        #             "close": 30634.0,
        #             "contract_type": "spot",
        #             "greeks": null,
        #             "high": 30780.0,
        #             "low": 30340.5,
        #             "mark_price": "48000",
        #             "oi": "0.0000",
        #             "oi_change_usd_6h": "0.0000",
        #             "oi_contracts": "0",
        #             "oi_value": "0.0000",
        #             "oi_value_symbol": "BTC",
        #             "oi_value_usd": "0.0000",
        #             "open": 30464.0,
        #             "price_band": null,
        #             "product_id": 8320,
        #             "quotes": {},
        #             "size": 2.6816639999999996,
        #             "spot_price": "30637.91465121",
        #             "symbol": "BTC_USDT",
        #             "timestamp": 1689139767621299,
        #             "turnover": 2.6816639999999996,
        #             "turnover_symbol": "BTC",
        #             "turnover_usd": 81896.45613400004,
        #             "volume": 2.6816639999999996
        #         },
        #         "success": True
        #     }
        #
        # swap
        #
        #     {
        #         "result": {
        #             "close": 30600.5,
        #             "contract_type": "perpetual_futures",
        #             "funding_rate": "0.00602961",
        #             "greeks": null,
        #             "high": 30803.0,
        #             "low": 30265.5,
        #             "mark_basis": "-0.45601594",
        #             "mark_price": "30600.10481568",
        #             "oi": "469.9190",
        #             "oi_change_usd_6h": "2226314.9900",
        #             "oi_contracts": "469919",
        #             "oi_value": "469.9190",
        #             "oi_value_symbol": "BTC",
        #             "oi_value_usd": "14385640.6802",
        #             "open": 30458.5,
        #             "price_band": {
        #                 "lower_limit": "29067.08312627",
        #                 "upper_limit": "32126.77608693"
        #             },
        #             "product_id": 139,
        #             "quotes": {
        #                 "ask_iv": null,
        #                 "ask_size": "965",
        #                 "best_ask": "30600.5",
        #                 "best_bid": "30599.5",
        #                 "bid_iv": null,
        #                 "bid_size": "196",
        #                 "impact_mid_price": null,
        #                 "mark_iv": "-0.44931641"
        #             },
        #             "size": 1226303,
        #             "spot_price": "30612.85362773",
        #             "symbol": "BTCUSDT",
        #             "timestamp": 1689136597460456,
        #             "turnover": 37392218.45999999,
        #             "turnover_symbol": "USDT",
        #             "turnover_usd": 37392218.45999999,
        #             "volume": 1226.3029999999485
        #         },
        #         "success": True
        #     }
        #
        # option
        #
        #     {
        #         "result": {
        #             "contract_type": "call_options",
        #             "greeks": {
        #                 "delta": "0.60873994",
        #                 "gamma": "0.00014854",
        #                 "rho": "7.71808010",
        #                 "spot": "30598.49040622",
        #                 "theta": "-30.44743017",
        #                 "vega": "24.83508248"
        #             },
        #             "mark_price": "1347.74819696",
        #             "mark_vol": "0.39966303",
        #             "oi": "2.7810",
        #             "oi_change_usd_6h": "0.0000",
        #             "oi_contracts": "2781",
        #             "oi_value": "2.7810",
        #             "oi_value_symbol": "BTC",
        #             "oi_value_usd": "85127.4337",
        #             "price_band": {
        #                 "lower_limit": "91.27423497",
        #                 "upper_limit": "7846.19454697"
        #             },
        #             "product_id": 107150,
        #             "quotes": {
        #                 "ask_iv": "0.41023239",
        #                 "ask_size": "2397",
        #                 "best_ask": "1374",
        #                 "best_bid": "1322",
        #                 "bid_iv": "0.38929375",
        #                 "bid_size": "3995",
        #                 "impact_mid_price": null,
        #                 "mark_iv": "0.39965618"
        #             },
        #             "spot_price": "30598.43379314",
        #             "strike_price": "30000",
        #             "symbol": "C-BTC-30000-280723",
        #             "timestamp": 1689136932893181,
        #             "turnover_symbol": "USDT"
        #         },
        #         "success": True
        #     }
        #
        result = self.safe_dict(response, 'result', {})
        return self.parse_ticker(result, market)

    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.delta.exchange/#get-tickers-for-products
        :param str[]|None 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.com/#/?id=ticker-structure>`
        """
        self.load_markets()
        symbols = self.market_symbols(symbols)
        response = self.publicGetTickers(params)
        #
        # spot
        #
        #     {
        #         "result": [
        #             {
        #                 "close": 30634.0,
        #                 "contract_type": "spot",
        #                 "greeks": null,
        #                 "high": 30780.0,
        #                 "low": 30340.5,
        #                 "mark_price": "48000",
        #                 "oi": "0.0000",
        #                 "oi_change_usd_6h": "0.0000",
        #                 "oi_contracts": "0",
        #                 "oi_value": "0.0000",
        #                 "oi_value_symbol": "BTC",
        #                 "oi_value_usd": "0.0000",
        #                 "open": 30464.0,
        #                 "price_band": null,
        #                 "product_id": 8320,
        #                 "quotes": {},
        #                 "size": 2.6816639999999996,
        #                 "spot_price": "30637.91465121",
        #                 "symbol": "BTC_USDT",
        #                 "timestamp": 1689139767621299,
        #                 "turnover": 2.6816639999999996,
        #                 "turnover_symbol": "BTC",
        #                 "turnover_usd": 81896.45613400004,
        #                 "volume": 2.6816639999999996
        #             },
        #         ],
        #         "success":true
        #     }
        #
        # swap
        #
        #     {
        #         "result": [
        #             {
        #                 "close": 30600.5,
        #                 "contract_type": "perpetual_futures",
        #                 "funding_rate": "0.00602961",
        #                 "greeks": null,
        #                 "high": 30803.0,
        #                 "low": 30265.5,
        #                 "mark_basis": "-0.45601594",
        #                 "mark_price": "30600.10481568",
        #                 "oi": "469.9190",
        #                 "oi_change_usd_6h": "2226314.9900",
        #                 "oi_contracts": "469919",
        #                 "oi_value": "469.9190",
        #                 "oi_value_symbol": "BTC",
        #                 "oi_value_usd": "14385640.6802",
        #                 "open": 30458.5,
        #                 "price_band": {
        #                     "lower_limit": "29067.08312627",
        #                     "upper_limit": "32126.77608693"
        #                 },
        #                 "product_id": 139,
        #                 "quotes": {
        #                     "ask_iv": null,
        #                     "ask_size": "965",
        #                     "best_ask": "30600.5",
        #                     "best_bid": "30599.5",
        #                     "bid_iv": null,
        #                     "bid_size": "196",
        #                     "impact_mid_price": null,
        #                     "mark_iv": "-0.44931641"
        #                 },
        #                 "size": 1226303,
        #                 "spot_price": "30612.85362773",
        #                 "symbol": "BTCUSDT",
        #                 "timestamp": 1689136597460456,
        #                 "turnover": 37392218.45999999,
        #                 "turnover_symbol": "USDT",
        #                 "turnover_usd": 37392218.45999999,
        #                 "volume": 1226.3029999999485
        #             },
        #         ],
        #         "success":true
        #     }
        #
        # option
        #
        #     {
        #         "result": [
        #             {
        #                 "contract_type": "call_options",
        #                 "greeks": {
        #                     "delta": "0.60873994",
        #                     "gamma": "0.00014854",
        #                     "rho": "7.71808010",
        #                     "spot": "30598.49040622",
        #                     "theta": "-30.44743017",
        #                     "vega": "24.83508248"
        #                 },
        #                 "mark_price": "1347.74819696",
        #                 "mark_vol": "0.39966303",
        #                 "oi": "2.7810",
        #                 "oi_change_usd_6h": "0.0000",
        #                 "oi_contracts": "2781",
        #                 "oi_value": "2.7810",
        #                 "oi_value_symbol": "BTC",
        #                 "oi_value_usd": "85127.4337",
        #                 "price_band": {
        #                     "lower_limit": "91.27423497",
        #                     "upper_limit": "7846.19454697"
        #                 },
        #                 "product_id": 107150,
        #                 "quotes": {
        #                     "ask_iv": "0.41023239",
        #                     "ask_size": "2397",
        #                     "best_ask": "1374",
        #                     "best_bid": "1322",
        #                     "bid_iv": "0.38929375",
        #                     "bid_size": "3995",
        #                     "impact_mid_price": null,
        #                     "mark_iv": "0.39965618"
        #                 },
        #                 "spot_price": "30598.43379314",
        #                 "strike_price": "30000",
        #                 "symbol": "C-BTC-30000-280723",
        #                 "timestamp": 1689136932893181,
        #                 "turnover_symbol": "USDT"
        #             },
        #         ],
        #         "success":true
        #     }
        #
        tickers = self.safe_list(response, 'result', [])
        result: dict = {}
        for i in range(0, len(tickers)):
            ticker = self.parse_ticker(tickers[i])
            symbol = ticker['symbol']
            result[symbol] = ticker
        return self.filter_by_array_tickers(result, 'symbol', symbols)

    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.delta.exchange/#get-l2-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.com/#/?id=order-book-structure>` indexed by market symbols
        """
        self.load_markets()
        market = self.market(symbol)
        request: dict = {
            'symbol': market['id'],
        }
        if limit is not None:
            request['depth'] = limit
        response = self.publicGetL2orderbookSymbol(self.extend(request, params))
        #
        #     {
        #         "result":{
        #             "buy":[
        #                 {"price":"15814.0","size":912},
        #                 {"price":"15813.5","size":1279},
        #                 {"price":"15813.0","size":1634},
        #             ],
        #             "sell":[
        #                 {"price":"15814.5","size":625},
        #                 {"price":"15815.0","size":982},
        #                 {"price":"15815.5","size":1328},
        #             ],
        #             "symbol":"BTCUSDT"
        #         },
        #         "success":true
        #     }
        #
        result = self.safe_dict(response, 'result', {})
        return self.parse_order_book(result, market['symbol'], None, 'buy', 'sell', 'price', 'size')

    def parse_trade(self, trade: dict, market: Market = None) -> Trade:
        #
        # public fetchTrades
        #
        #     {
        #         "buyer_role":"maker",
        #         "price":"15896.5",
        #         "seller_role":"taker",
        #         "size":241,
        #         "symbol":"BTCUSDT",
        #         "timestamp":1605376684714595
        #     }
        #
        # private fetchMyTrades
        #
        #     {
        #         "commission":"0.008335000000000000",
        #         "created_at":"2020-11-16T19:07:19Z",
        #         "fill_type":"normal",
        #         "id":"e7ff05c233a74245b72381f8dd91d1ce",
        #         "meta_data":{
        #             "effective_commission_rate":"0.0005",
        #             "order_price":"16249",
        #             "order_size":1,
        #             "order_type":"market_order",
        #             "order_unfilled_size":0,
        #             "trading_fee_credits_used":"0"
        #         },
        #         "order_id":"152999629",
        #         "price":"16669",
        #         "product":{
        #             "contract_type":"perpetual_futures",
        #             "contract_unit_currency":"BTC",
        #             "contract_value":"0.001",
        #             "id":139,
        #             "notional_type":"vanilla",
        #             "quoting_asset":{"minimum_precision":2,"precision":6,"symbol":"USDT"},
        #             "settling_asset":{"minimum_precision":2,"precision":6,"symbol":"USDT"},
        #             "symbol":"BTCUSDT",
        #             "tick_size":"0.5",
        #             "underlying_asset":{"minimum_precision":4,"precision":8,"symbol":"BTC"}
        #         },
        #         "product_id":139,
        #         "role":"taker",
        #         "side":"sell",
        #         "size":1
        #     }
        #
        id = self.safe_string(trade, 'id')
        orderId = self.safe_string(trade, 'order_id')
        timestamp = self.parse8601(self.safe_string(trade, 'created_at'))
        timestamp = self.safe_integer_product(trade, 'timestamp', 0.001, timestamp)
        priceString = self.safe_string(trade, 'price')
        amountString = self.safe_string(trade, 'size')
        product = self.safe_dict(trade, 'product', {})
        marketId = self.safe_string(product, 'symbol')
        symbol = self.safe_symbol(marketId, market)
        sellerRole = self.safe_string(trade, 'seller_role')
        side = self.safe_string(trade, 'side')
        if side is None:
            if sellerRole == 'taker':
                side = 'sell'
            elif sellerRole == 'maker':
                side = 'buy'
        takerOrMaker = self.safe_string(trade, 'role')
        metaData = self.safe_dict(trade, 'meta_data', {})
        type = self.safe_string(metaData, 'order_type')
        if type is not None:
            type = type.replace('_order', '')
        feeCostString = self.safe_string(trade, 'commission')
        fee = None
        if feeCostString is not None:
            settlingAsset = self.safe_dict(product, 'settling_asset', {})
            feeCurrencyId = self.safe_string(settlingAsset, 'symbol')
            feeCurrencyCode = self.safe_currency_code(feeCurrencyId)
            fee = {
                'cost': feeCostString,
                'currency': feeCurrencyCode,
            }
        return self.safe_trade({
            'id': id,
            'order': orderId,
            'timestamp': timestamp,
            'datetime': self.iso8601(timestamp),
            'symbol': symbol,
            'type': type,
            'side': side,
            'price': priceString,
            'amount': amountString,
            'cost': None,
            'takerOrMaker': takerOrMaker,
            'fee': fee,
            'info': trade,
        }, market)

    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.delta.exchange/#get-public-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.com/#/?id=public-trades>`
        """
        self.load_markets()
        market = self.market(symbol)
        request: dict = {
            'symbol': market['id'],
        }
        response = self.publicGetTradesSymbol(self.extend(request, params))
        #
        #     {
        #         "result":[
        #             {
        #                 "buyer_role":"maker",
        #                 "price":"15896.5",
        #                 "seller_role":"taker",
        #                 "size":241,
        #                 "symbol":"BTCUSDT",
        #                 "timestamp":1605376684714595
        #             }
        #         ],
        #         "success":true
        #     }
        #
        result = self.safe_list(response, 'result', [])
        return self.parse_trades(result, market, since, limit)

    def parse_ohlcv(self, ohlcv, market: Market = None) -> list:
        #
        #     {
        #         "time":1605393120,
        #         "open":15989,
        #         "high":15989,
        #         "low":15987.5,
        #         "close":15987.5,
        #         "volume":565
        #     }
        #
        return [
            self.safe_timestamp(ohlcv, 'time'),
            self.safe_number(ohlcv, 'open'),
            self.safe_number(ohlcv, 'high'),
            self.safe_number(ohlcv, 'low'),
            self.safe_number(ohlcv, 'close'),
            self.safe_number(ohlcv, 'volume'),
        ]

    def fetch_ohlcv(self, symbol: str, timeframe='1m', since: Int = None, limit: Int = None, params={}) -> List[list]:
        """
        fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market
        :see: https://docs.delta.exchange/#get-ohlc-candles
        :param str symbol: unified symbol of the market to fetch OHLCV data for
        :param str timeframe: the length of time each candle represents
        :param int [since]: timestamp in ms of the earliest candle to fetch
        :param int [limit]: the maximum amount of candles to fetch
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns int[][]: A list of candles ordered, open, high, low, close, volume
        """
        self.load_markets()
        market = self.market(symbol)
        request: dict = {
            'resolution': self.safe_string(self.timeframes, timeframe, timeframe),
        }
        duration = self.parse_timeframe(timeframe)
        limit = limit if limit else 2000  # max 2000
        if since is None:
            end = self.seconds()
            request['end'] = end
            request['start'] = end - limit * duration
        else:
            start = self.parse_to_int(since / 1000)
            request['start'] = start
            request['end'] = self.sum(start, limit * duration)
        price = self.safe_string(params, 'price')
        if price == 'mark':
            request['symbol'] = 'MARK:' + market['id']
        elif price == 'index':
            request['symbol'] = market['info']['spot_index']['symbol']
        else:
            request['symbol'] = market['id']
        params = self.omit(params, 'price')
        response = self.publicGetHistoryCandles(self.extend(request, params))
        #
        #     {
        #         "success":true,
        #         "result":[
        #             {"time":1605393120,"open":15989,"high":15989,"low":15987.5,"close":15987.5,"volume":565},
        #             {"time":1605393180,"open":15966,"high":15966,"low":15959,"close":15959,"volume":24},
        #             {"time":1605393300,"open":15973,"high":15973,"low":15973,"close":15973,"volume":1288},
        #         ]
        #     }
        #
        result = self.safe_list(response, 'result', [])
        return self.parse_ohlcvs(result, market, timeframe, since, limit)

    def parse_balance(self, response) -> Balances:
        balances = self.safe_list(response, 'result', [])
        result: dict = {'info': response}
        currenciesByNumericId = self.safe_dict(self.options, 'currenciesByNumericId', {})
        for i in range(0, len(balances)):
            balance = balances[i]
            currencyId = self.safe_string(balance, 'asset_id')
            currency = self.safe_dict(currenciesByNumericId, currencyId)
            code = currencyId if (currency is None) else currency['code']
            account = self.account()
            account['total'] = self.safe_string(balance, 'balance')
            account['free'] = self.safe_string(balance, 'available_balance')
            result[code] = account
        return self.safe_balance(result)

    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.delta.exchange/#get-wallet-balances
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict: a `balance structure <https://docs.ccxt.com/#/?id=balance-structure>`
        """
        self.load_markets()
        response = self.privateGetWalletBalances(params)
        #
        #     {
        #         "result":[
        #             {
        #                 "asset_id":1,
        #                 "available_balance":"0",
        #                 "balance":"0",
        #                 "commission":"0",
        #                 "id":154883,
        #                 "interest_credit":"0",
        #                 "order_margin":"0",
        #                 "pending_referral_bonus":"0",
        #                 "pending_trading_fee_credit":"0",
        #                 "position_margin":"0",
        #                 "trading_fee_credit":"0",
        #                 "user_id":22142
        #             },
        #         ],
        #         "success":true
        #     }
        #
        return self.parse_balance(response)

    def fetch_position(self, symbol: str, params={}):
        """
        fetch data on a single open contract trade position
        :see: https://docs.delta.exchange/#get-position
        :param str symbol: unified market symbol of the market the position is held in, default is None
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict: a `position structure <https://docs.ccxt.com/#/?id=position-structure>`
        """
        self.load_markets()
        market = self.market(symbol)
        request: dict = {
            'product_id': market['numericId'],
        }
        response = self.privateGetPositions(self.extend(request, params))
        #
        #     {
        #         "result":{
        #             "entry_price":null,
        #             "size":0,
        #             "timestamp":1605454074268079
        #         },
        #         "success":true
        #     }
        #
        result = self.safe_dict(response, 'result', {})
        return self.parse_position(result, market)

    def fetch_positions(self, symbols: Strings = None, params={}):
        """
        fetch all open positions
        :see: https://docs.delta.exchange/#get-margined-positions
        :param str[]|None symbols: list of unified market symbols
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict[]: a list of `position structure <https://docs.ccxt.com/#/?id=position-structure>`
        """
        self.load_markets()
        response = self.privateGetPositionsMargined(params)
        #
        #     {
        #         "success": True,
        #         "result": [
        #           {
        #             "user_id": 0,
        #             "size": 0,
        #             "entry_price": "string",
        #             "margin": "string",
        #             "liquidation_price": "string",
        #             "bankruptcy_price": "string",
        #             "adl_level": 0,
        #             "product_id": 0,
        #             "product_symbol": "string",
        #             "commission": "string",
        #             "realized_pnl": "string",
        #             "realized_funding": "string"
        #           }
        #         ]
        #     }
        #
        result = self.safe_list(response, 'result', [])
        return self.parse_positions(result, symbols)

    def parse_position(self, position: dict, market: Market = None):
        #
        # fetchPosition
        #
        #     {
        #         "entry_price":null,
        #         "size":0,
        #         "timestamp":1605454074268079
        #     }
        #
        #
        # fetchPositions
        #
        #     {
        #         "user_id": 0,
        #         "size": 0,
        #         "entry_price": "string",
        #         "margin": "string",
        #         "liquidation_price": "string",
        #         "bankruptcy_price": "string",
        #         "adl_level": 0,
        #         "product_id": 0,
        #         "product_symbol": "string",
        #         "commission": "string",
        #         "realized_pnl": "string",
        #         "realized_funding": "string"
        #     }
        #
        marketId = self.safe_string(position, 'product_symbol')
        market = self.safe_market(marketId, market)
        symbol = market['symbol']
        timestamp = self.safe_integer_product(position, 'timestamp', 0.001)
        sizeString = self.safe_string(position, 'size')
        side = None
        if sizeString is not None:
            if Precise.string_gt(sizeString, '0'):
                side = 'buy'
            elif Precise.string_lt(sizeString, '0'):
                side = 'sell'
        return self.safe_position({
            'info': position,
            'id': None,
            'symbol': symbol,
            'notional': None,
            'marginMode': None,
            'liquidationPrice': self.safe_number(position, 'liquidation_price'),
            'entryPrice': self.safe_number(position, 'entry_price'),
            'unrealizedPnl': None,  # todo - realized_pnl ?
            'percentage': None,
            'contracts': self.parse_number(sizeString),
            'contractSize': self.safe_number(market, 'contractSize'),
            'markPrice': None,
            'side': side,
            'hedged': None,
            'timestamp': timestamp,
            'datetime': self.iso8601(timestamp),
            'maintenanceMargin': None,
            'maintenanceMarginPercentage': None,
            'collateral': None,
            'initialMargin': None,
            'initialMarginPercentage': None,
            'leverage': None,
            'marginRatio': None,
            'stopLossPrice': None,
            'takeProfitPrice': None,
        })

    def parse_order_status(self, status: Str):
        statuses: dict = {
            'open': 'open',
            'pending': 'open',
            'closed': 'closed',
            'cancelled': 'canceled',
        }
        return self.safe_string(statuses, status, status)

    def parse_order(self, order: dict, market: Market = None) -> Order:
        #
        # createOrder, cancelOrder, editOrder, fetchOpenOrders, fetchClosedOrders
        #
        #     {
        #         "average_fill_price":null,
        #         "bracket_order":null,
        #         "bracket_stop_loss_limit_price":null,
        #         "bracket_stop_loss_price":null,
        #         "bracket_take_profit_limit_price":null,
        #         "bracket_take_profit_price":null,
        #         "bracket_trail_amount":null,
        #         "cancellation_reason":null,
        #         "client_order_id":null,
        #         "close_on_trigger":"false",
        #         "commission":"0",
        #         "created_at":"2020-11-16T02:38:26Z",
        #         "id":152870626,
        #         "limit_price":"10000",
        #         "meta_data":{"source":"api"},
        #         "order_type":"limit_order",
        #         "paid_commission":"0",
        #         "product_id":139,
        #         "reduce_only":false,
        #         "side":"buy",
        #         "size":0,
        #         "state":"open",
        #         "stop_order_type":null,
        #         "stop_price":null,
        #         "stop_trigger_method":"mark_price",
        #         "time_in_force":"gtc",
        #         "trail_amount":null,
        #         "unfilled_size":0,
        #         "user_id":22142
        #     }
        #
        id = self.safe_string(order, 'id')
        clientOrderId = self.safe_string(order, 'client_order_id')
        timestamp = self.parse8601(self.safe_string(order, 'created_at'))
        marketId = self.safe_string(order, 'product_id')
        marketsByNumericId = self.safe_dict(self.options, 'marketsByNumericId', {})
        market = self.safe_value(marketsByNumericId, marketId, market)
        symbol = marketId if (market is None) else market['symbol']
        status = self.parse_order_status(self.safe_string(order, 'state'))
        side = self.safe_string(order, 'side')
        type = self.safe_string(order, 'order_type')
        type = type.replace('_order', '')
        price = self.safe_string(order, 'limit_price')
        amount = self.safe_string(order, 'size')
        remaining = self.safe_string(order, 'unfilled_size')
        average = self.safe_string(order, 'average_fill_price')
        fee = None
        feeCostString = self.safe_string(order, 'paid_commission')
        if feeCostString is not None:
            feeCurrencyCode = None
            if market is not None:
                settlingAsset = self.safe_dict(market['info'], 'settling_asset', {})
                feeCurrencyId = self.safe_string(settlingAsset, 'symbol')
                feeCurrencyCode = self.safe_currency_code(feeCurrencyId)
            fee = {
                'cost': feeCostString,
                'currency': feeCurrencyCode,
            }
        return self.safe_order({
            'info': order,
            'id': id,
            'clientOrderId': clientOrderId,
            'timestamp': timestamp,
            'datetime': self.iso8601(timestamp),
            'lastTradeTimestamp': None,
            'symbol': symbol,
            'type': type,
            'side': side,
            'price': price,
            'amount': amount,
            'cost': None,
            'average': average,
            'filled': None,
            'remaining': remaining,
            'status': status,
            'fee': fee,
            'trades': None,
        }, market)

    def create_order(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}):
        """
        create a trade order
        :see: https://docs.delta.exchange/#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 fullfilled, in units of the quote currency, ignored in market orders
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :param bool [params.reduceOnly]: *contract only* indicates if self order is to reduce the size of a position
        :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
        """
        self.load_markets()
        orderType = type + '_order'
        market = self.market(symbol)
        request: dict = {
            'product_id': market['numericId'],
            # 'limit_price': self.price_to_precision(market['symbol'], price),
            'size': self.amount_to_precision(market['symbol'], amount),
            'side': side,
            'order_type': orderType,
            # 'client_order_id': 'string',
            # 'time_in_force': 'gtc',  # gtc, ioc, fok
            # 'post_only': 'false',  # 'true',
            # 'reduce_only': 'false',  # 'true',
        }
        if type == 'limit':
            request['limit_price'] = self.price_to_precision(market['symbol'], price)
        clientOrderId = self.safe_string_2(params, 'clientOrderId', 'client_order_id')
        params = self.omit(params, ['clientOrderId', 'client_order_id'])
        if clientOrderId is not None:
            request['client_order_id'] = clientOrderId
        reduceOnly = self.safe_bool(params, 'reduceOnly')
        if reduceOnly:
            request['reduce_only'] = reduceOnly
            params = self.omit(params, 'reduceOnly')
        response = self.privatePostOrders(self.extend(request, params))
        #
        #     {
        #         "result":{
        #             "average_fill_price":null,
        #             "bracket_order":null,
        #             "bracket_stop_loss_limit_price":null,
        #             "bracket_stop_loss_price":null,
        #             "bracket_take_profit_limit_price":null,
        #             "bracket_take_profit_price":null,
        #             "bracket_trail_amount":null,
        #             "cancellation_reason":null,
        #             "client_order_id":null,
        #             "close_on_trigger":"false",
        #             "commission":"0",
        #             "created_at":"2020-11-16T02:38:26Z",
        #             "id":152870626,
        #             "limit_price":"10000",
        #             "meta_data":{"source":"api"},
        #             "order_type":"limit_order",
        #             "paid_commission":"0",
        #             "product_id":139,
        #             "reduce_only":false,
        #             "side":"buy",
        #             "size":0,
        #             "state":"open",
        #             "stop_order_type":null,
        #             "stop_price":null,
        #             "stop_trigger_method":"mark_price",
        #             "time_in_force":"gtc",
        #             "trail_amount":null,
        #             "unfilled_size":0,
        #             "user_id":22142
        #         },
        #         "success":true
        #     }
        #
        result = self.safe_dict(response, 'result', {})
        return self.parse_order(result, market)

    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.delta.exchange/#edit-order
        :param str id: 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 the currency you want to trade in units of the base currency
        :param float [price]: the price at which the order is to be fullfilled, in units of the quote currency
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
        """
        self.load_markets()
        market = self.market(symbol)
        request: dict = {
            'id': int(id),
            'product_id': market['numericId'],
            # "limit_price": self.price_to_precision(symbol, price),
            # "size": self.amount_to_precision(symbol, amount),
        }
        if amount is not None:
            request['size'] = int(self.amount_to_precision(symbol, amount))
        if price is not None:
            request['limit_price'] = self.price_to_precision(symbol, price)
        response = self.privatePutOrders(self.extend(request, params))
        #
        #     {
        #         "success": True,
        #         "result": {
        #             "id": "ashb1212",
        #             "product_id": 27,
        #             "limit_price": "9200",
        #             "side": "buy",
        #             "size": 100,
        #             "unfilled_size": 50,
        #             "user_id": 1,
        #             "order_type": "limit_order",
        #             "state": "open",
        #             "created_at": "..."
        #         }
        #     }
        #
        result = self.safe_dict(response, 'result')
        return self.parse_order(result, market)

    def cancel_order(self, id: str, symbol: Str = None, params={}):
        """
        cancels an open order
        :see: https://docs.delta.exchange/#cancel-order
        :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.com/#/?id=order-structure>`
        """
        if symbol is None:
            raise ArgumentsRequired(self.id + ' cancelOrder() requires a symbol argument')
        self.load_markets()
        market = self.market(symbol)
        request: dict = {
            'id': int(id),
            'product_id': market['numericId'],
        }
        response = self.privateDeleteOrders(self.extend(request, params))
        #
        #     {
        #         "result":{
        #             "average_fill_price":null,
        #             "bracket_order":null,
        #             "bracket_stop_loss_limit_price":null,
        #             "bracket_stop_loss_price":null,
        #             "bracket_take_profit_limit_price":null,
        #             "bracket_take_profit_price":null,
        #             "bracket_trail_amount":null,
        #             "cancellation_reason":"cancelled_by_user",
        #             "client_order_id":null,
        #             "close_on_trigger":"false",
        #             "commission":"0",
        #             "created_at":"2020-11-16T02:38:26Z",
        #             "id":152870626,
        #             "limit_price":"10000",
        #             "meta_data":{"source":"api"},
        #             "order_type":"limit_order",
        #             "paid_commission":"0",
        #             "product_id":139,
        #             "reduce_only":false,
        #             "side":"buy",
        #             "size":0,
        #             "state":"cancelled",
        #             "stop_order_type":null,
        #             "stop_price":null,
        #             "stop_trigger_method":"mark_price",
        #             "time_in_force":"gtc",
        #             "trail_amount":null,
        #             "unfilled_size":0,
        #             "user_id":22142
        #         },
        #         "success":true
        #     }
        #
        result = self.safe_dict(response, 'result')
        return self.parse_order(result, market)

    def cancel_all_orders(self, symbol: Str = None, params={}):
        """
        cancel all open orders in a market
        :see: https://docs.delta.exchange/#cancel-all-open-orders
        :param str symbol: unified market symbol of the market to cancel orders in
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
        """
        if symbol is None:
            raise ArgumentsRequired(self.id + ' cancelAllOrders() requires a symbol argument')
        self.load_markets()
        market = self.market(symbol)
        request: dict = {
            'product_id': market['numericId'],
            # 'cancel_limit_orders': 'true',
            # 'cancel_stop_orders': 'true',
        }
        response = self.privateDeleteOrdersAll(self.extend(request, params))
        #
        #     {
        #         "result":{},
        #         "success":true
        #     }
        #
        return response

    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.delta.exchange/#get-active-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 order structures to retrieve
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns Order[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
        """
        return self.fetch_orders_with_method('privateGetOrders', symbol, since, limit, params)

    def fetch_closed_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
        """
        fetches information on multiple closed orders made by the user
        :see: https://docs.delta.exchange/#get-order-history-cancelled-and-closed
        :param str symbol: unified market symbol of the market orders were made in
        :param int [since]: the earliest time in ms to fetch orders for
        :param int [limit]: the maximum number of order structures to retrieve
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns Order[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
        """
        return self.fetch_orders_with_method('privateGetOrdersHistory', symbol, since, limit, params)

    def fetch_orders_with_method(self, method, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
        self.load_markets()
        request: dict = {
            # 'product_ids': market['id'],  # comma-separated
            # 'contract_types': types,  # comma-separated, futures, perpetual_futures, call_options, put_options, interest_rate_swaps, move_options, spreads
            # 'order_types': types,  # comma-separated, market, limit, stop_market, stop_limit, all_stop
            # 'start_time': since * 1000,
            # 'end_time': self.microseconds(),
            # 'after',  # after cursor for pagination
            # 'before',  # before cursor for pagination
            # 'page_size': limit,  # number of records per page
        }
        market = None
        if symbol is not None:
            market = self.market(symbol)
            request['product_ids'] = market['numericId']  # accepts a comma-separated list of ids
        if since is not None:
            request['start_time'] = str(since) + '000'
        if limit is not None:
            request['page_size'] = limit
        response = None
        if method == 'privateGetOrders':
            response = self.privateGetOrders(self.extend(request, params))
        elif method == 'privateGetOrdersHistory':
            response = self.privateGetOrdersHistory(self.extend(request, params))
        #
        #     {
        #         "success": True,
        #         "result": [
        #             {
        #                 "id": "ashb1212",
        #                 "product_id": 27,
        #                 "limit_price": "9200",
        #                 "side": "buy",
        #                 "size": 100,
        #                 "unfilled_size": 50,
        #                 "user_id": 1,
        #                 "order_type": "limit_order",
        #                 "state": "open",
        #                 "created_at": "..."
        #             }
        #         ],
        #         "meta": {
        #             "after": "string",
        #             "before": "string"
        #         }
        #     }
        #
        result = self.safe_list(response, 'result', [])
        return self.parse_orders(result, market, since, limit)

    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.delta.exchange/#get-user-fills-by-filters
        :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
        :returns Trade[]: a list of `trade structures <https://docs.ccxt.com/#/?id=trade-structure>`
        """
        self.load_markets()
        request: dict = {
            # 'product_ids': market['id'],  # comma-separated
            # 'contract_types': types,  # comma-separated, futures, perpetual_futures, call_options, put_options, interest_rate_swaps, move_options, spreads
            # 'start_time': since * 1000,
            # 'end_time': self.microseconds(),
            # 'after',  # after cursor for pagination
            # 'before',  # before cursor for pagination
            # 'page_size': limit,  # number of records per page
        }
        market = None
        if symbol is not None:
            market = self.market(symbol)
            request['product_ids'] = market['numericId']  # accepts a comma-separated list of ids
        if since is not None:
            request['start_time'] = str(since) + '000'
        if limit is not None:
            request['page_size'] = limit
        response = self.privateGetFills(self.extend(request, params))
        #
        #     {
        #         "meta":{
        #             "after":null,
        #             "before":null,
        #             "limit":10,
        #             "total_count":2
        #         },
        #         "result":[
        #             {
        #                 "commission":"0.008335000000000000",
        #                 "created_at":"2020-11-16T19:07:19Z",
        #                 "fill_type":"normal",
        #                 "id":"e7ff05c233a74245b72381f8dd91d1ce",
        #                 "meta_data":{
        #                     "effective_commission_rate":"0.0005",
        #                     "order_price":"16249",
        #                     "order_size":1,
        #                     "order_type":"market_order",
        #                     "order_unfilled_size":0,
        #                     "trading_fee_credits_used":"0"
        #                 },
        #                 "order_id":"152999629",
        #                 "price":"16669",
        #                 "product":{
        #                     "contract_type":"perpetual_futures",
        #                     "contract_unit_currency":"BTC",
        #                     "contract_value":"0.001",
        #                     "id":139,
        #                     "notional_type":"vanilla",
        #                     "quoting_asset":{"minimum_precision":2,"precision":6,"symbol":"USDT"},
        #                     "settling_asset":{"minimum_precision":2,"precision":6,"symbol":"USDT"},
        #                     "symbol":"BTCUSDT",
        #                     "tick_size":"0.5",
        #                     "underlying_asset":{"minimum_precision":4,"precision":8,"symbol":"BTC"}
        #                 },
        #                 "product_id":139,
        #                 "role":"taker",
        #                 "side":"sell",
        #                 "size":1
        #             }
        #         ],
        #         "success":true
        #     }
        #
        result = self.safe_list(response, 'result', [])
        return self.parse_trades(result, market, since, limit)

    def fetch_ledger(self, code: Str = None, since: Int = None, limit: Int = None, params={}):
        """
        fetch the history of changes, actions done by the user or operations that altered balance of the user
        :see: https://docs.delta.exchange/#get-wallet-transactions
        :param str code: unified currency code, default is None
        :param int [since]: timestamp in ms of the earliest ledger entry, default is None
        :param int [limit]: max number of ledger entrys to return, default is None
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict: a `ledger structure <https://docs.ccxt.com/#/?id=ledger-structure>`
        """
        self.load_markets()
        request: dict = {
            # 'asset_id': currency['numericId'],
            # 'end_time': self.seconds(),
            # 'after': 'string',  # after cursor for pagination
            # 'before': 'string',  # before cursor for pagination
            # 'page_size': limit,
        }
        currency = None
        if code is not None:
            currency = self.currency(code)
            request['asset_id'] = currency['numericId']
        if limit is not None:
            request['page_size'] = limit
        response = self.privateGetWalletTransactions(self.extend(request, params))
        #
        #     {
        #         "meta":{"after":null,"before":null,"limit":10,"total_count":1},
        #         "result":[
        #             {
        #                 "amount":"29.889184",
        #                 "asset_id":5,
        #                 "balance":"29.889184",
        #                 "created_at":"2020-11-15T21:25:01Z",
        #                 "meta_data":{
        #                     "deposit_id":3884,
        #                     "transaction_id":"0x41a60174849828530abb5008e98fc63c9b598288743ec4ba9620bcce900a3b8d"
        #                 },
        #                 "transaction_type":"deposit",
        #                 "user_id":22142,
        #                 "uuid":"70bb5679da3c4637884e2dc63efaa846"
        #             }
        #         ],
        #         "success":true
        #     }
        #
        result = self.safe_list(response, 'result', [])
        return self.parse_ledger(result, currency, since, limit)

    def parse_ledger_entry_type(self, type):
        types: dict = {
            'pnl': 'pnl',
            'deposit': 'transaction',
            'withdrawal': 'transaction',
            'commission': 'fee',
            'conversion': 'trade',
            # 'perpetual_futures_funding': 'perpetual_futures_funding',
            # 'withdrawal_cancellation': 'withdrawal_cancellation',
            'referral_bonus': 'referral',
            'commission_rebate': 'rebate',
            # 'promo_credit': 'promo_credit',
        }
        return self.safe_string(types, type, type)

    def parse_ledger_entry(self, item: dict, currency: Currency = None):
        #
        #     {
        #         "amount":"29.889184",
        #         "asset_id":5,
        #         "balance":"29.889184",
        #         "created_at":"2020-11-15T21:25:01Z",
        #         "meta_data":{
        #             "deposit_id":3884,
        #             "transaction_id":"0x41a60174849828530abb5008e98fc63c9b598288743ec4ba9620bcce900a3b8d"
        #         },
        #         "transaction_type":"deposit",
        #         "user_id":22142,
        #         "uuid":"70bb5679da3c4637884e2dc63efaa846"
        #     }
        #
        id = self.safe_string(item, 'uuid')
        direction = None
        account = None
        metaData = self.safe_dict(item, 'meta_data', {})
        referenceId = self.safe_string(metaData, 'transaction_id')
        referenceAccount = None
        type = self.safe_string(item, 'transaction_type')
        if (type == 'deposit') or (type == 'commission_rebate') or (type == 'referral_bonus') or (type == 'pnl') or (type == 'withdrawal_cancellation') or (type == 'promo_credit'):
            direction = 'in'
        elif (type == 'withdrawal') or (type == 'commission') or (type == 'conversion') or (type == 'perpetual_futures_funding'):
            direction = 'out'
        type = self.parse_ledger_entry_type(type)
        currencyId = self.safe_string(item, 'asset_id')
        currenciesByNumericId = self.safe_dict(self.options, 'currenciesByNumericId')
        currency = self.safe_value(currenciesByNumericId, currencyId, currency)
        code = None if (currency is None) else currency['code']
        amount = self.safe_string(item, 'amount')
        timestamp = self.parse8601(self.safe_string(item, 'created_at'))
        after = self.safe_string(item, 'balance')
        before = Precise.string_max('0', Precise.string_sub(after, amount))
        status = 'ok'
        return {
            'info': item,
            'id': id,
            'direction': direction,
            'account': account,
            'referenceId': referenceId,
            'referenceAccount': referenceAccount,
            'type': type,
            'currency': code,
            'amount': self.parse_number(amount),
            'before': self.parse_number(before),
            'after': self.parse_number(after),
            'status': status,
            'timestamp': timestamp,
            'datetime': self.iso8601(timestamp),
            'fee': None,
        }

    def fetch_deposit_address(self, code: str, params={}):
        """
        fetch the deposit address for a currency associated with self account
        :param str code: unified currency code
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :param str [params.network]: unified network code
        :returns dict: an `address structure <https://docs.ccxt.com/#/?id=address-structure>`
        """
        self.load_markets()
        currency = self.currency(code)
        request: dict = {
            'asset_symbol': currency['id'],
        }
        networkCode = self.safe_string_upper(params, 'network')
        if networkCode is not None:
            request['network'] = self.network_code_to_id(networkCode, code)
            params = self.omit(params, 'network')
        response = self.privateGetDepositsAddress(self.extend(request, params))
        #
        #    {
        #        "success": True,
        #        "result": {
        #            "id": 1915615,
        #            "user_id": 27854758,
        #            "address": "TXYB4GdKsXKEWbeSNPsmGZu4ZVCkhVh1Zz",
        #            "memo": "",
        #            "status": "active",
        #            "updated_at": "2023-01-12T06:03:46.000Z",
        #            "created_at": "2023-01-12T06:03:46.000Z",
        #            "asset_symbol": "USDT",
        #            "network": "TRC20(TRON)",
        #            "custodian": "fireblocks"
        #        }
        #    }
        #
        result = self.safe_dict(response, 'result', {})
        return self.parse_deposit_address(result, currency)

    def parse_deposit_address(self, depositAddress, currency: Currency = None):
        #
        #    {
        #        "id": 1915615,
        #        "user_id": 27854758,
        #        "address": "TXYB4GdKsXKEWbeSNPsmGZu4ZVCkhVh1Zz",
        #        "memo": "",
        #        "status": "active",
        #        "updated_at": "2023-01-12T06:03:46.000Z",
        #        "created_at": "2023-01-12T06:03:46.000Z",
        #        "asset_symbol": "USDT",
        #        "network": "TRC20(TRON)",
        #        "custodian": "fireblocks"
        #    }
        #
        address = self.safe_string(depositAddress, 'address')
        marketId = self.safe_string(depositAddress, 'asset_symbol')
        networkId = self.safe_string(depositAddress, 'network')
        self.check_address(address)
        return {
            'currency': self.safe_currency_code(marketId, currency),
            'address': address,
            'tag': self.safe_string(depositAddress, 'memo'),
            'network': self.network_id_to_code(networkId),
            'info': depositAddress,
        }

    def fetch_funding_rate(self, symbol: str, params={}):
        """
        fetch the current funding rate
        :see: https://docs.delta.exchange/#get-ticker-for-a-product-by-symbol
        :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.com/#/?id=funding-rate-structure>`
        """
        self.load_markets()
        market = self.market(symbol)
        if not market['swap']:
            raise BadSymbol(self.id + ' fetchFundingRate() supports swap contracts only')
        request: dict = {
            'symbol': market['id'],
        }
        response = self.publicGetTickersSymbol(self.extend(request, params))
        #
        #     {
        #         "result": {
        #             "close": 30600.5,
        #             "contract_type": "perpetual_futures",
        #             "funding_rate": "0.00602961",
        #             "greeks": null,
        #             "high": 30803.0,
        #             "low": 30265.5,
        #             "mark_basis": "-0.45601594",
        #             "mark_price": "30600.10481568",
        #             "oi": "469.9190",
        #             "oi_change_usd_6h": "2226314.9900",
        #             "oi_contracts": "469919",
        #             "oi_value": "469.9190",
        #             "oi_value_symbol": "BTC",
        #             "oi_value_usd": "14385640.6802",
        #             "open": 30458.5,
        #             "price_band": {
        #                 "lower_limit": "29067.08312627",
        #                 "upper_limit": "32126.77608693"
        #             },
        #             "product_id": 139,
        #             "quotes": {
        #                 "ask_iv": null,
        #                 "ask_size": "965",
        #                 "best_ask": "30600.5",
        #                 "best_bid": "30599.5",
        #                 "bid_iv": null,
        #                 "bid_size": "196",
        #                 "impact_mid_price": null,
        #                 "mark_iv": "-0.44931641"
        #             },
        #             "size": 1226303,
        #             "spot_price": "30612.85362773",
        #             "symbol": "BTCUSDT",
        #             "timestamp": 1689136597460456,
        #             "turnover": 37392218.45999999,
        #             "turnover_symbol": "USDT",
        #             "turnover_usd": 37392218.45999999,
        #             "volume": 1226.3029999999485
        #         },
        #         "success": True
        #     }
        #
        result = self.safe_dict(response, 'result', {})
        return self.parse_funding_rate(result, market)

    def fetch_funding_rates(self, symbols: Strings = None, params={}):
        """
        fetch the funding rate for multiple markets
        :see: https://docs.delta.exchange/#get-tickers-for-products
        :param str[]|None symbols: list of unified market symbols
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict: a dictionary of `funding rates structures <https://docs.ccxt.com/#/?id=funding-rates-structure>`, indexe by market symbols
        """
        self.load_markets()
        symbols = self.market_symbols(symbols)
        request: dict = {
            'contract_types': 'perpetual_futures',
        }
        response = self.publicGetTickers(self.extend(request, params))
        #
        #     {
        #         "result": [
        #             {
        #                 "close": 30600.5,
        #                 "contract_type": "perpetual_futures",
        #                 "funding_rate": "0.00602961",
        #                 "greeks": null,
        #                 "high": 30803.0,
        #                 "low": 30265.5,
        #                 "mark_basis": "-0.45601594",
        #                 "mark_price": "30600.10481568",
        #                 "oi": "469.9190",
        #                 "oi_change_usd_6h": "2226314.9900",
        #                 "oi_contracts": "469919",
        #                 "oi_value": "469.9190",
        #                 "oi_value_symbol": "BTC",
        #                 "oi_value_usd": "14385640.6802",
        #                 "open": 30458.5,
        #                 "price_band": {
        #                     "lower_limit": "29067.08312627",
        #                     "upper_limit": "32126.77608693"
        #                 },
        #                 "product_id": 139,
        #                 "quotes": {
        #                     "ask_iv": null,
        #                     "ask_size": "965",
        #                     "best_ask": "30600.5",
        #                     "best_bid": "30599.5",
        #                     "bid_iv": null,
        #                     "bid_size": "196",
        #                     "impact_mid_price": null,
        #                     "mark_iv": "-0.44931641"
        #                 },
        #                 "size": 1226303,
        #                 "spot_price": "30612.85362773",
        #                 "symbol": "BTCUSDT",
        #                 "timestamp": 1689136597460456,
        #                 "turnover": 37392218.45999999,
        #                 "turnover_symbol": "USDT",
        #                 "turnover_usd": 37392218.45999999,
        #                 "volume": 1226.3029999999485
        #             },
        #         ],
        #         "success":true
        #     }
        #
        rates = self.safe_list(response, 'result', [])
        result = self.parse_funding_rates(rates)
        return self.filter_by_array(result, 'symbol', symbols)

    def parse_funding_rate(self, contract, market: Market = None):
        #
        #     {
        #         "close": 30600.5,
        #         "contract_type": "perpetual_futures",
        #         "funding_rate": "0.00602961",
        #         "greeks": null,
        #         "high": 30803.0,
        #         "low": 30265.5,
        #         "mark_basis": "-0.45601594",
        #         "mark_price": "30600.10481568",
        #         "oi": "469.9190",
        #         "oi_change_usd_6h": "2226314.9900",
        #         "oi_contracts": "469919",
        #         "oi_value": "469.9190",
        #         "oi_value_symbol": "BTC",
        #         "oi_value_usd": "14385640.6802",
        #         "open": 30458.5,
        #         "price_band": {
        #             "lower_limit": "29067.08312627",
        #             "upper_limit": "32126.77608693"
        #         },
        #         "product_id": 139,
        #         "quotes": {
        #             "ask_iv": null,
        #             "ask_size": "965",
        #             "best_ask": "30600.5",
        #             "best_bid": "30599.5",
        #             "bid_iv": null,
        #             "bid_size": "196",
        #             "impact_mid_price": null,
        #             "mark_iv": "-0.44931641"
        #         },
        #         "size": 1226303,
        #         "spot_price": "30612.85362773",
        #         "symbol": "BTCUSDT",
        #         "timestamp": 1689136597460456,
        #         "turnover": 37392218.45999999,
        #         "turnover_symbol": "USDT",
        #         "turnover_usd": 37392218.45999999,
        #         "volume": 1226.3029999999485
        #     }
        #
        timestamp = self.safe_integer_product(contract, 'timestamp', 0.001)
        marketId = self.safe_string(contract, 'symbol')
        fundingRateString = self.safe_string(contract, 'funding_rate')
        fundingRate = Precise.string_div(fundingRateString, '100')
        return {
            'info': contract,
            'symbol': self.safe_symbol(marketId, market),
            'markPrice': self.safe_number(contract, 'mark_price'),
            'indexPrice': self.safe_number(contract, 'spot_price'),
            'interestRate': None,
            'estimatedSettlePrice': None,
            'timestamp': timestamp,
            'datetime': self.iso8601(timestamp),
            'fundingRate': self.parse_number(fundingRate),
            'fundingTimestamp': None,
            'fundingDatetime': None,
            'nextFundingRate': None,
            'nextFundingTimestamp': None,
            'nextFundingDatetime': None,
            'previousFundingRate': None,
            'previousFundingTimestamp': None,
            'previousFundingDatetime': None,
        }

    def add_margin(self, symbol: str, amount: float, params={}) -> MarginModification:
        """
        add margin
        :see: https://docs.delta.exchange/#add-remove-position-margin
        :param str symbol: unified market symbol
        :param float amount: amount of margin to add
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict: a `margin structure <https://docs.ccxt.com/#/?id=add-margin-structure>`
        """
        return self.modify_margin_helper(symbol, amount, 'add', params)

    def reduce_margin(self, symbol: str, amount: float, params={}) -> MarginModification:
        """
        remove margin from a position
        :see: https://docs.delta.exchange/#add-remove-position-margin
        :param str symbol: unified market symbol
        :param float amount: the amount of margin to remove
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict: a `margin structure <https://docs.ccxt.com/#/?id=reduce-margin-structure>`
        """
        return self.modify_margin_helper(symbol, amount, 'reduce', params)

    def modify_margin_helper(self, symbol: str, amount, type, params={}) -> MarginModification:
        self.load_markets()
        market = self.market(symbol)
        amount = str(amount)
        if type == 'reduce':
            amount = Precise.string_mul(amount, '-1')
        request: dict = {
            'product_id': market['numericId'],
            'delta_margin': amount,
        }
        response = self.privatePostPositionsChangeMargin(self.extend(request, params))
        #
        #     {
        #         "result": {
        #             "auto_topup": False,
        #             "bankruptcy_price": "24934.12",
        #             "commission": "0.01197072",
        #             "created_at": "2023-07-20T03:49:09.159401Z",
        #             "entry_price": "29926.8",
        #             "liquidation_price": "25083.754",
        #             "margin": "4.99268",
        #             "margin_mode": "isolated",
        #             "product_id": 84,
        #             "product_symbol": "BTCUSDT",
        #             "realized_cashflow": "0",
        #             "realized_funding": "0",
        #             "realized_pnl": "0",
        #             "size": 1,
        #             "updated_at": "2023-07-20T03:49:09.159401Z",
        #             "user_id": 30084879
        #         },
        #         "success": True
        #     }
        #
        result = self.safe_dict(response, 'result', {})
        return self.parse_margin_modification(result, market)

    def parse_margin_modification(self, data: dict, market: Market = None) -> MarginModification:
        #
        #     {
        #         "auto_topup": False,
        #         "bankruptcy_price": "24934.12",
        #         "commission": "0.01197072",
        #         "created_at": "2023-07-20T03:49:09.159401Z",
        #         "entry_price": "29926.8",
        #         "liquidation_price": "25083.754",
        #         "margin": "4.99268",
        #         "margin_mode": "isolated",
        #         "product_id": 84,
        #         "product_symbol": "BTCUSDT",
        #         "realized_cashflow": "0",
        #         "realized_funding": "0",
        #         "realized_pnl": "0",
        #         "size": 1,
        #         "updated_at": "2023-07-20T03:49:09.159401Z",
        #         "user_id": 30084879
        #     }
        #
        marketId = self.safe_string(data, 'product_symbol')
        market = self.safe_market(marketId, market)
        return {
            'info': data,
            'symbol': market['symbol'],
            'type': None,
            'marginMode': 'isolated',
            'amount': None,
            'total': self.safe_number(data, 'margin'),
            'code': None,
            'status': None,
            'timestamp': None,
            'datetime': None,
        }

    def fetch_open_interest(self, symbol: str, params={}):
        """
        retrieves the open interest of a derivative market
        :see: https://docs.delta.exchange/#get-ticker-for-a-product-by-symbol
        :param str symbol: unified market symbol
        :param dict [params]: exchange specific parameters
        :returns dict} an open interest structure{@link https://docs.ccxt.com/#/?id=open-interest-structure:
        """
        self.load_markets()
        market = self.market(symbol)
        if not market['contract']:
            raise BadRequest(self.id + ' fetchOpenInterest() supports contract markets only')
        request: dict = {
            'symbol': market['id'],
        }
        response = self.publicGetTickersSymbol(self.extend(request, params))
        #
        #     {
        #         "result": {
        #             "close": 894.0,
        #             "contract_type": "call_options",
        #             "greeks": {
        #                 "delta": "0.67324861",
        #                 "gamma": "0.00022178",
        #                 "rho": "4.34638266",
        #                 "spot": "30178.53195697",
        #                 "theta": "-35.64972577",
        #                 "vega": "16.34381277"
        #             },
        #             "high": 946.0,
        #             "low": 893.0,
        #             "mark_price": "1037.07582681",
        #             "mark_vol": "0.35899491",
        #             "oi": "0.0910",
        #             "oi_change_usd_6h": "-90.5500",
        #             "oi_contracts": "91",
        #             "oi_value": "0.0910",
        #             "oi_value_symbol": "BTC",
        #             "oi_value_usd": "2746.3549",
        #             "open": 946.0,
        #             "price_band": {
        #                 "lower_limit": "133.37794509",
        #                 "upper_limit": "5663.66930164"
        #             },
        #             "product_id": 116171,
        #             "quotes": {
        #                 "ask_iv": "0.36932389",
        #                 "ask_size": "1321",
        #                 "best_ask": "1054",
        #                 "best_bid": "1020",
        #                 "bid_iv": "0.34851914",
        #                 "bid_size": "2202",
        #                 "impact_mid_price": null,
        #                 "mark_iv": "0.35896335"
        #             },
        #             "size": 152,
        #             "spot_price": "30178.53195697",
        #             "strike_price": "29500",
        #             "symbol": "C-BTC-29500-280723",
        #             "timestamp": 1689834695286094,
        #             "turnover": 4546.601744940001,
        #             "turnover_symbol": "USDT",
        #             "turnover_usd": 4546.601744940001,
        #             "volume": 0.15200000000000002
        #         },
        #         "success": True
        #     }
        #
        result = self.safe_dict(response, 'result', {})
        return self.parse_open_interest(result, market)

    def parse_open_interest(self, interest, market: Market = None):
        #
        #     {
        #         "close": 894.0,
        #         "contract_type": "call_options",
        #         "greeks": {
        #             "delta": "0.67324861",
        #             "gamma": "0.00022178",
        #             "rho": "4.34638266",
        #             "spot": "30178.53195697",
        #             "theta": "-35.64972577",
        #             "vega": "16.34381277"
        #         },
        #         "high": 946.0,
        #         "low": 893.0,
        #         "mark_price": "1037.07582681",
        #         "mark_vol": "0.35899491",
        #         "oi": "0.0910",
        #         "oi_change_usd_6h": "-90.5500",
        #         "oi_contracts": "91",
        #         "oi_value": "0.0910",
        #         "oi_value_symbol": "BTC",
        #         "oi_value_usd": "2746.3549",
        #         "open": 946.0,
        #         "price_band": {
        #             "lower_limit": "133.37794509",
        #             "upper_limit": "5663.66930164"
        #         },
        #         "product_id": 116171,
        #         "quotes": {
        #             "ask_iv": "0.36932389",
        #             "ask_size": "1321",
        #             "best_ask": "1054",
        #             "best_bid": "1020",
        #             "bid_iv": "0.34851914",
        #             "bid_size": "2202",
        #             "impact_mid_price": null,
        #             "mark_iv": "0.35896335"
        #         },
        #         "size": 152,
        #         "spot_price": "30178.53195697",
        #         "strike_price": "29500",
        #         "symbol": "C-BTC-29500-280723",
        #         "timestamp": 1689834695286094,
        #         "turnover": 4546.601744940001,
        #         "turnover_symbol": "USDT",
        #         "turnover_usd": 4546.601744940001,
        #         "volume": 0.15200000000000002
        #     }
        #
        timestamp = self.safe_integer_product(interest, 'timestamp', 0.001)
        marketId = self.safe_string(interest, 'symbol')
        return self.safe_open_interest({
            'symbol': self.safe_symbol(marketId, market),
            'baseVolume': self.safe_number(interest, 'oi_value'),
            'quoteVolume': self.safe_number(interest, 'oi_value_usd'),
            'openInterestAmount': self.safe_number(interest, 'oi_contracts'),
            'openInterestValue': self.safe_number(interest, 'oi'),
            'timestamp': timestamp,
            'datetime': self.iso8601(timestamp),
            'info': interest,
        }, market)

    def fetch_leverage(self, symbol: str, params={}) -> Leverage:
        """
        fetch the set leverage for a market
        :see: https://docs.delta.exchange/#get-order-leverage
        :param str symbol: unified market symbol
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict: a `leverage structure <https://docs.ccxt.com/#/?id=leverage-structure>`
        """
        self.load_markets()
        market = self.market(symbol)
        request: dict = {
            'product_id': market['numericId'],
        }
        response = self.privateGetProductsProductIdOrdersLeverage(self.extend(request, params))
        #
        #     {
        #         "result": {
        #             "index_symbol": null,
        #             "leverage": "10",
        #             "margin_mode": "isolated",
        #             "order_margin": "0",
        #             "product_id": 84,
        #             "user_id": 30084879
        #         },
        #         "success": True
        #     }
        #
        result = self.safe_dict(response, 'result', {})
        return self.parse_leverage(result, market)

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

    def set_leverage(self, leverage: Int, symbol: Str = None, params={}):
        """
        set the level of leverage for a market
        :see: https://docs.delta.exchange/#change-order-leverage
        :param float leverage: the rate of leverage
        :param str symbol: unified market symbol
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict: response from the exchange
        """
        if symbol is None:
            raise ArgumentsRequired(self.id + ' setLeverage() requires a symbol argument')
        self.load_markets()
        market = self.market(symbol)
        request: dict = {
            'product_id': market['numericId'],
            'leverage': leverage,
        }
        #
        #     {
        #         "result": {
        #             "leverage": "20",
        #             "margin_mode": "isolated",
        #             "order_margin": "0",
        #             "product_id": 84
        #         },
        #         "success": True
        #     }
        #
        return self.privatePostProductsProductIdOrdersLeverage(self.extend(request, params))

    def fetch_settlement_history(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
        """
        fetches historical settlement records
        :see: https://docs.delta.exchange/#get-product-settlement-prices
        :param str symbol: unified market symbol of the settlement history
        :param int [since]: timestamp in ms
        :param int [limit]: number of records
        :param dict [params]: exchange specific params
        :returns dict[]: a list of `settlement history objects <https://docs.ccxt.com/#/?id=settlement-history-structure>`
        """
        self.load_markets()
        market = None
        if symbol is not None:
            market = self.market(symbol)
        request: dict = {
            'states': 'expired',
        }
        if limit is not None:
            request['page_size'] = limit
        response = self.publicGetProducts(self.extend(request, params))
        #
        #     {
        #         "result": [
        #             {
        #                 "contract_value": "0.001",
        #                 "basis_factor_max_limit": "10.95",
        #                 "maker_commission_rate": "0.0003",
        #                 "launch_time": "2023-07-19T04:30:03Z",
        #                 "trading_status": "operational",
        #                 "product_specs": {
        #                     "backup_vol_expiry_time": 31536000,
        #                     "max_deviation_from_external_vol": 0.75,
        #                     "max_lower_deviation_from_external_vol": 0.75,
        #                     "max_upper_deviation_from_external_vol": 0.5,
        #                     "max_volatility": 3,
        #                     "min_volatility": 0.1,
        #                     "premium_commission_rate": 0.1,
        #                     "settlement_index_price": "29993.536675710806",
        #                     "vol_calculation_method": "orderbook",
        #                     "vol_expiry_time": 31536000
        #                 },
        #                 "description": "BTC call option expiring on 19-7-2023",
        #                 "settlement_price": "0",
        #                 "disruption_reason": null,
        #                 "settling_asset": {},
        #                 "initial_margin": "1",
        #                 "tick_size": "0.1",
        #                 "maintenance_margin": "0.5",
        #                 "id": 117542,
        #                 "notional_type": "vanilla",
        #                 "ui_config": {},
        #                 "contract_unit_currency": "BTC",
        #                 "symbol": "C-BTC-30900-190723",
        #                 "insurance_fund_margin_contribution": "1",
        #                 "price_band": "2",
        #                 "annualized_funding": "10.95",
        #                 "impact_size": 200,
        #                 "contract_type": "call_options",
        #                 "position_size_limit": 255633,
        #                 "max_leverage_notional": "200000",
        #                 "initial_margin_scaling_factor": "0.000002",
        #                 "strike_price": "30900",
        #                 "is_quanto": False,
        #                 "settlement_time": "2023-07-19T12:00:00Z",
        #                 "liquidation_penalty_factor": "0.5",
        #                 "funding_method": "mark_price",
        #                 "taker_commission_rate": "0.0003",
        #                 "default_leverage": "100.000000000000000000",
        #                 "state": "expired",
        #                 "auction_start_time": null,
        #                 "short_description": "BTC  Call",
        #                 "quoting_asset": {},
        #                 "maintenance_margin_scaling_factor":"0.000002"
        #             }
        #         ],
        #         "success": True
        #     }
        #
        result = self.safe_list(response, 'result', [])
        settlements = self.parse_settlements(result, market)
        sorted = self.sort_by(settlements, 'timestamp')
        return self.filter_by_symbol_since_limit(sorted, market['symbol'], since, limit)

    def parse_settlement(self, settlement, market):
        #
        #     {
        #         "contract_value": "0.001",
        #         "basis_factor_max_limit": "10.95",
        #         "maker_commission_rate": "0.0003",
        #         "launch_time": "2023-07-19T04:30:03Z",
        #         "trading_status": "operational",
        #         "product_specs": {
        #             "backup_vol_expiry_time": 31536000,
        #             "max_deviation_from_external_vol": 0.75,
        #             "max_lower_deviation_from_external_vol": 0.75,
        #             "max_upper_deviation_from_external_vol": 0.5,
        #             "max_volatility": 3,
        #             "min_volatility": 0.1,
        #             "premium_commission_rate": 0.1,
        #             "settlement_index_price": "29993.536675710806",
        #             "vol_calculation_method": "orderbook",
        #             "vol_expiry_time": 31536000
        #         },
        #         "description": "BTC call option expiring on 19-7-2023",
        #         "settlement_price": "0",
        #         "disruption_reason": null,
        #         "settling_asset": {},
        #         "initial_margin": "1",
        #         "tick_size": "0.1",
        #         "maintenance_margin": "0.5",
        #         "id": 117542,
        #         "notional_type": "vanilla",
        #         "ui_config": {},
        #         "contract_unit_currency": "BTC",
        #         "symbol": "C-BTC-30900-190723",
        #         "insurance_fund_margin_contribution": "1",
        #         "price_band": "2",
        #         "annualized_funding": "10.95",
        #         "impact_size": 200,
        #         "contract_type": "call_options",
        #         "position_size_limit": 255633,
        #         "max_leverage_notional": "200000",
        #         "initial_margin_scaling_factor": "0.000002",
        #         "strike_price": "30900",
        #         "is_quanto": False,
        #         "settlement_time": "2023-07-19T12:00:00Z",
        #         "liquidation_penalty_factor": "0.5",
        #         "funding_method": "mark_price",
        #         "taker_commission_rate": "0.0003",
        #         "default_leverage": "100.000000000000000000",
        #         "state": "expired",
        #         "auction_start_time": null,
        #         "short_description": "BTC  Call",
        #         "quoting_asset": {},
        #         "maintenance_margin_scaling_factor":"0.000002"
        #     }
        #
        datetime = self.safe_string(settlement, 'settlement_time')
        marketId = self.safe_string(settlement, 'symbol')
        return {
            'info': settlement,
            'symbol': self.safe_symbol(marketId, market),
            'price': self.safe_number(settlement, 'settlement_price'),
            'timestamp': self.parse8601(datetime),
            'datetime': datetime,
        }

    def parse_settlements(self, settlements, market):
        result = []
        for i in range(0, len(settlements)):
            result.append(self.parse_settlement(settlements[i], market))
        return result

    def fetch_greeks(self, symbol: str, params={}) -> Greeks:
        """
        fetches an option contracts greeks, financial metrics used to measure the factors that affect the price of an options contract
        :see: https://docs.delta.exchange/#get-ticker-for-a-product-by-symbol
        :param str symbol: unified symbol of the market to fetch greeks for
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict: a `greeks structure <https://docs.ccxt.com/#/?id=greeks-structure>`
        """
        self.load_markets()
        market = self.market(symbol)
        request: dict = {
            'symbol': market['id'],
        }
        response = self.publicGetTickersSymbol(self.extend(request, params))
        #
        #     {
        #         "result": {
        #             "close": 6793.0,
        #             "contract_type": "call_options",
        #             "greeks": {
        #                 "delta": "0.94739174",
        #                 "gamma": "0.00002206",
        #                 "rho": "11.00890725",
        #                 "spot": "36839.58124652",
        #                 "theta": "-18.18365310",
        #                 "vega": "7.85209698"
        #             },
        #             "high": 7556.0,
        #             "low": 6793.0,
        #             "mark_price": "6955.70698909",
        #             "mark_vol": "0.66916863",
        #             "oi": "1.8980",
        #             "oi_change_usd_6h": "110.4600",
        #             "oi_contracts": "1898",
        #             "oi_value": "1.8980",
        #             "oi_value_symbol": "BTC",
        #             "oi_value_usd": "69940.7319",
        #             "open": 7.2e3,
        #             "price_band": {
        #                 "lower_limit": "5533.89814767",
        #                 "upper_limit": "11691.37688371"
        #             },
        #             "product_id": 129508,
        #             "quotes": {
        #                 "ask_iv": "0.90180438",
        #                 "ask_size": "1898",
        #                 "best_ask": "7210",
        #                 "best_bid": "6913",
        #                 "bid_iv": "0.60881706",
        #                 "bid_size": "3163",
        #                 "impact_mid_price": null,
        #                 "mark_iv": "0.66973549"
        #             },
        #             "size": 5,
        #             "spot_price": "36839.58153868",
        #             "strike_price": "30000",
        #             "symbol": "C-BTC-30000-241123",
        #             "timestamp": 1699584998504530,
        #             "turnover": 184.41206804,
        #             "turnover_symbol": "USDT",
        #             "turnover_usd": 184.41206804,
        #             "volume": 0.005
        #         },
        #         "success": True
        #     }
        #
        result = self.safe_dict(response, 'result', {})
        return self.parse_greeks(result, market)

    def parse_greeks(self, greeks: dict, market: Market = None) -> Greeks:
        #
        #     {
        #         "close": 6793.0,
        #         "contract_type": "call_options",
        #         "greeks": {
        #             "delta": "0.94739174",
        #             "gamma": "0.00002206",
        #             "rho": "11.00890725",
        #             "spot": "36839.58124652",
        #             "theta": "-18.18365310",
        #             "vega": "7.85209698"
        #         },
        #         "high": 7556.0,
        #         "low": 6793.0,
        #         "mark_price": "6955.70698909",
        #         "mark_vol": "0.66916863",
        #         "oi": "1.8980",
        #         "oi_change_usd_6h": "110.4600",
        #         "oi_contracts": "1898",
        #         "oi_value": "1.8980",
        #         "oi_value_symbol": "BTC",
        #         "oi_value_usd": "69940.7319",
        #         "open": 7.2e3,
        #         "price_band": {
        #             "lower_limit": "5533.89814767",
        #             "upper_limit": "11691.37688371"
        #         },
        #         "product_id": 129508,
        #         "quotes": {
        #             "ask_iv": "0.90180438",
        #             "ask_size": "1898",
        #             "best_ask": "7210",
        #             "best_bid": "6913",
        #             "bid_iv": "0.60881706",
        #             "bid_size": "3163",
        #             "impact_mid_price": null,
        #             "mark_iv": "0.66973549"
        #         },
        #         "size": 5,
        #         "spot_price": "36839.58153868",
        #         "strike_price": "30000",
        #         "symbol": "C-BTC-30000-241123",
        #         "timestamp": 1699584998504530,
        #         "turnover": 184.41206804,
        #         "turnover_symbol": "USDT",
        #         "turnover_usd": 184.41206804,
        #         "volume": 0.005
        #     }
        #
        timestamp = self.safe_integer_product(greeks, 'timestamp', 0.001)
        marketId = self.safe_string(greeks, 'symbol')
        symbol = self.safe_symbol(marketId, market)
        stats = self.safe_dict(greeks, 'greeks', {})
        quotes = self.safe_dict(greeks, 'quotes', {})
        return {
            'symbol': symbol,
            'timestamp': timestamp,
            'datetime': self.iso8601(timestamp),
            'delta': self.safe_number(stats, 'delta'),
            'gamma': self.safe_number(stats, 'gamma'),
            'theta': self.safe_number(stats, 'theta'),
            'vega': self.safe_number(stats, 'vega'),
            'rho': self.safe_number(stats, 'rho'),
            'bidSize': self.safe_number(quotes, 'bid_size'),
            'askSize': self.safe_number(quotes, 'ask_size'),
            'bidImpliedVolatility': self.safe_number(quotes, 'bid_iv'),
            'askImpliedVolatility': self.safe_number(quotes, 'ask_iv'),
            'markImpliedVolatility': self.safe_number(quotes, 'mark_iv'),
            'bidPrice': self.safe_number(quotes, 'best_bid'),
            'askPrice': self.safe_number(quotes, 'best_ask'),
            'markPrice': self.safe_number(greeks, 'mark_price'),
            'lastPrice': None,
            'underlyingPrice': self.safe_number(greeks, 'spot_price'),
            'info': greeks,
        }

    def close_all_positions(self, params={}) -> List[Position]:
        """
        closes all open positions for a market type
        :see: https://docs.delta.exchange/#close-all-positions
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :param int [params.user_id]: the users id
        :returns dict[]: A list of `position structures <https://docs.ccxt.com/#/?id=position-structure>`
        """
        self.load_markets()
        request: dict = {
            'close_all_portfolio': True,
            'close_all_isolated': True,
            # 'user_id': 12345,
        }
        response = self.privatePostPositionsCloseAll(self.extend(request, params))
        #
        # {"result":{},"success":true}
        #
        position = self.parse_position(self.safe_dict(response, 'result', {}))
        return [position]

    def fetch_margin_mode(self, symbol: str, params={}) -> MarginMode:
        """
        fetches the margin mode of a trading pair
        :see: https://docs.delta.exchange/#get-user
        :param str symbol: unified symbol of the market to fetch the margin mode for
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict: a `margin mode structure <https://docs.ccxt.com/#/?id=margin-mode-structure>`
        """
        self.load_markets()
        market = None
        if symbol is not None:
            market = self.market(symbol)
        response = self.privateGetProfile(params)
        #
        #     {
        #         "result": {
        #             "is_password_set": True,
        #             "kyc_expiry_date": null,
        #             "phishing_code": "12345",
        #             "preferences": {
        #                 "favorites": []
        #             },
        #             "is_kyc_provisioned": False,
        #             "country": "Canada",
        #             "margin_mode": "isolated",
        #             "mfa_updated_at": "2023-07-19T01:04:43Z",
        #             "last_name": "",
        #             "oauth_apple_active": False,
        #             "pf_index_symbol": null,
        #             "proof_of_identity_status": "approved",
        #             "dob": null,
        #             "email": "abc_123@gmail.com",
        #             "force_change_password": False,
        #             "nick_name": "still-breeze-123",
        #             "oauth_google_active": False,
        #             "phone_verification_status": "verified",
        #             "id": 12345678,
        #             "last_seen": null,
        #             "is_withdrawal_enabled": True,
        #             "force_change_mfa": False,
        #             "enable_bots": False,
        #             "kyc_verified_on": null,
        #             "created_at": "2023-07-19T01:02:32Z",
        #             "withdrawal_blocked_till": null,
        #             "proof_of_address_status": "approved",
        #             "is_password_change_blocked": False,
        #             "is_mfa_enabled": True,
        #             "is_kyc_done": True,
        #             "oauth": null,
        #             "account_name": "Main",
        #             "sub_account_permissions": null,
        #             "phone_number": null,
        #             "tracking_info": {
        #                 "ga_cid": "1234.4321",
        #                 "is_kyc_gtm_tracked": True,
        #                 "sub_account_config": {
        #                     "cross": 2,
        #                     "isolated": 2,
        #                     "portfolio": 2
        #                 }
        #             },
        #             "first_name": "",
        #             "phone_verified_on": null,
        #             "seen_intro": False,
        #             "password_updated_at": null,
        #             "is_login_enabled": True,
        #             "registration_date": "2023-07-19T01:02:32Z",
        #             "permissions": {},
        #             "max_sub_accounts_limit": 2,
        #             "country_calling_code": null,
        #             "is_sub_account": False,
        #             "is_kyc_refresh_required": False
        #         },
        #         "success": True
        #     }
        #
        result = self.safe_dict(response, 'result', {})
        return self.parse_margin_mode(result, market)

    def parse_margin_mode(self, marginMode: dict, market=None) -> MarginMode:
        symbol = None
        if market is not None:
            symbol = market['symbol']
        return {
            'info': marginMode,
            'symbol': symbol,
            'marginMode': self.safe_string(marginMode, 'margin_mode'),
        }

    def fetch_option(self, symbol: str, params={}) -> Option:
        """
        fetches option data that is commonly found in an option chain
        :see: https://docs.delta.exchange/#get-ticker-for-a-product-by-symbol
        :param str symbol: unified market symbol
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict: an `option chain structure <https://docs.ccxt.com/#/?id=option-chain-structure>`
        """
        self.load_markets()
        market = self.market(symbol)
        request: dict = {
            'symbol': market['id'],
        }
        response = self.publicGetTickersSymbol(self.extend(request, params))
        #
        #     {
        #         "result": {
        #             "close": 6793.0,
        #             "contract_type": "call_options",
        #             "greeks": {
        #                 "delta": "0.94739174",
        #                 "gamma": "0.00002206",
        #                 "rho": "11.00890725",
        #                 "spot": "36839.58124652",
        #                 "theta": "-18.18365310",
        #                 "vega": "7.85209698"
        #             },
        #             "high": 7556.0,
        #             "low": 6793.0,
        #             "mark_price": "6955.70698909",
        #             "mark_vol": "0.66916863",
        #             "oi": "1.8980",
        #             "oi_change_usd_6h": "110.4600",
        #             "oi_contracts": "1898",
        #             "oi_value": "1.8980",
        #             "oi_value_symbol": "BTC",
        #             "oi_value_usd": "69940.7319",
        #             "open": 7.2e3,
        #             "price_band": {
        #                 "lower_limit": "5533.89814767",
        #                 "upper_limit": "11691.37688371"
        #             },
        #             "product_id": 129508,
        #             "quotes": {
        #                 "ask_iv": "0.90180438",
        #                 "ask_size": "1898",
        #                 "best_ask": "7210",
        #                 "best_bid": "6913",
        #                 "bid_iv": "0.60881706",
        #                 "bid_size": "3163",
        #                 "impact_mid_price": null,
        #                 "mark_iv": "0.66973549"
        #             },
        #             "size": 5,
        #             "spot_price": "36839.58153868",
        #             "strike_price": "30000",
        #             "symbol": "C-BTC-30000-241123",
        #             "timestamp": 1699584998504530,
        #             "turnover": 184.41206804,
        #             "turnover_symbol": "USDT",
        #             "turnover_usd": 184.41206804,
        #             "volume": 0.005
        #         },
        #         "success": True
        #     }
        #
        result = self.safe_dict(response, 'result', {})
        return self.parse_option(result, None, market)

    def parse_option(self, chain: dict, currency: Currency = None, market: Market = None) -> Option:
        #
        #     {
        #         "close": 6793.0,
        #         "contract_type": "call_options",
        #         "greeks": {
        #             "delta": "0.94739174",
        #             "gamma": "0.00002206",
        #             "rho": "11.00890725",
        #             "spot": "36839.58124652",
        #             "theta": "-18.18365310",
        #             "vega": "7.85209698"
        #         },
        #         "high": 7556.0,
        #         "low": 6793.0,
        #         "mark_price": "6955.70698909",
        #         "mark_vol": "0.66916863",
        #         "oi": "1.8980",
        #         "oi_change_usd_6h": "110.4600",
        #         "oi_contracts": "1898",
        #         "oi_value": "1.8980",
        #         "oi_value_symbol": "BTC",
        #         "oi_value_usd": "69940.7319",
        #         "open": 7.2e3,
        #         "price_band": {
        #             "lower_limit": "5533.89814767",
        #             "upper_limit": "11691.37688371"
        #         },
        #         "product_id": 129508,
        #         "quotes": {
        #             "ask_iv": "0.90180438",
        #             "ask_size": "1898",
        #             "best_ask": "7210",
        #             "best_bid": "6913",
        #             "bid_iv": "0.60881706",
        #             "bid_size": "3163",
        #             "impact_mid_price": null,
        #             "mark_iv": "0.66973549"
        #         },
        #         "size": 5,
        #         "spot_price": "36839.58153868",
        #         "strike_price": "30000",
        #         "symbol": "C-BTC-30000-241123",
        #         "timestamp": 1699584998504530,
        #         "turnover": 184.41206804,
        #         "turnover_symbol": "USDT",
        #         "turnover_usd": 184.41206804,
        #         "volume": 0.005
        #     }
        #
        marketId = self.safe_string(chain, 'symbol')
        market = self.safe_market(marketId, market)
        quotes = self.safe_dict(chain, 'quotes', {})
        timestamp = self.safe_integer_product(chain, 'timestamp', 0.001)
        return {
            'info': chain,
            'currency': None,
            'symbol': market['symbol'],
            'timestamp': timestamp,
            'datetime': self.iso8601(timestamp),
            'impliedVolatility': self.safe_number(quotes, 'mark_iv'),
            'openInterest': self.safe_number(chain, 'oi'),
            'bidPrice': self.safe_number(quotes, 'best_bid'),
            'askPrice': self.safe_number(quotes, 'best_ask'),
            'midPrice': self.safe_number(quotes, 'impact_mid_price'),
            'markPrice': self.safe_number(chain, 'mark_price'),
            'lastPrice': None,
            'underlyingPrice': self.safe_number(chain, 'spot_price'),
            'change': None,
            'percentage': None,
            'baseVolume': self.safe_number(chain, 'volume'),
            'quoteVolume': None,
        }

    def sign(self, path, api='public', method='GET', params={}, headers=None, body=None):
        requestPath = '/' + self.version + '/' + self.implode_params(path, params)
        url = self.urls['api'][api] + requestPath
        query = self.omit(params, self.extract_params(path))
        if api == 'public':
            if query:
                url += '?' + self.urlencode(query)
        elif api == 'private':
            self.check_required_credentials()
            timestamp = str(self.seconds())
            headers = {
                'api-key': self.apiKey,
                'timestamp': timestamp,
            }
            auth = method + timestamp + requestPath
            if (method == 'GET') or (method == 'DELETE'):
                if query:
                    queryString = '?' + self.urlencode(query)
                    auth += queryString
                    url += queryString
            else:
                body = self.json(query)
                auth += body
                headers['Content-Type'] = 'application/json'
            signature = self.hmac(self.encode(auth), self.encode(self.secret), hashlib.sha256)
            headers['signature'] = signature
        return {'url': url, 'method': method, 'body': body, 'headers': headers}

    def handle_errors(self, code: int, reason: str, url: str, method: str, headers: dict, body: str, response, requestHeaders, requestBody):
        if response is None:
            return None
        #
        # {"error":{"code":"insufficient_margin","context":{"available_balance":"0.000000000000000000","required_additional_balance":"1.618626000000000000000000000"}},"success":false}
        #
        error = self.safe_dict(response, 'error', {})
        errorCode = self.safe_string(error, 'code')
        if errorCode is not None:
            feedback = self.id + ' ' + body
            self.throw_exactly_matched_exception(self.exceptions['exact'], errorCode, feedback)
            self.throw_broadly_matched_exception(self.exceptions['broad'], errorCode, feedback)
            raise ExchangeError(feedback)  # unknown message
        return None
