# -*- 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 Any, Balances, Currencies, Currency, DepositAddress, Greeks, Int, LedgerEntry, Leverage, MarginMode, MarginModification, Market, Num, Option, Order, OrderBook, OrderSide, OrderType, Position, Str, Strings, Ticker, Tickers, FundingRate, FundingRates, Trade, MarketInterface
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) -> Any:
        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,
                'fetchDepositAddresses': False,
                'fetchDepositAddressesByNetwork': False,
                '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,
                'fetchOrder': True,
                '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',
                        'orders/{order_id}',
                        'orders/client_order_id/{client_oid}',
                        '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',
                        'heartbeat',
                        'deposits/address',
                    ],
                    'post': [
                        'orders',
                        'orders/bracket',
                        'orders/batch',
                        'products/{product_id}/orders/leverage',
                        'positions/change_margin',
                        'positions/close_all',
                        'wallets/sub_account_balance_transfer',
                        'heartbeat/create',
                        'heartbeat',
                        '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')],
                        ],
                    },
                },
            },
            'userAgent': self.userAgents['chrome39'],  # needed for C#
            'options': {
                'networks': {
                    'TRC20': 'TRC20(TRON)',
                    'BEP20': 'BEP20(BSC)',
                },
            },
            'features': {
                'default': {
                    'sandbox': True,
                    'createOrder': {
                        'marginMode': False,
                        'triggerPrice': True,  # todo implement
                        # todo implement
                        'triggerPriceType': {
                            'last': True,
                            'mark': True,
                            'index': True,
                        },
                        'triggerDirection': False,
                        'stopLossPrice': False,  # todo
                        'takeProfitPrice': False,  # todo
                        'attachedStopLossTakeProfit': {
                            'triggerPriceType': None,
                            'price': True,
                        },
                        # todo implementation
                        'timeInForce': {
                            'IOC': True,
                            'FOK': True,
                            'PO': True,
                            'GTD': False,
                        },
                        'hedged': False,
                        'selfTradePrevention': False,
                        'trailing': False,  # todo: implement
                        'iceberg': False,
                        'leverage': False,
                        'marketBuyByCost': False,
                        'marketBuyRequiresPrice': False,
                    },
                    'createOrders': None,  # todo: implement
                    'fetchMyTrades': {
                        'marginMode': False,
                        'limit': 100,  # todo: revise
                        'daysBack': 100000,
                        'untilDays': 100000,
                        'symbolRequired': False,
                    },
                    'fetchOrder': None,
                    'fetchOpenOrders': {
                        'marginMode': False,
                        'limit': 100,  # todo: revise
                        'trigger': False,
                        'trailing': False,
                        'symbolRequired': False,
                    },
                    'fetchOrders': None,
                    'fetchClosedOrders': {
                        'marginMode': False,
                        'limit': 500,
                        'daysBack': 100000,
                        'daysBackCanceled': 1,
                        'untilDays': 100000,
                        'trigger': False,
                        'trailing': False,
                        'symbolRequired': False,
                    },
                    'fetchOHLCV': {
                        'limit': 2000,  # todo: recheck
                    },
                },
                'spot': {
                    'extends': 'default',
                },
                'swap': {
                    'linear': {
                        'extends': 'default',
                    },
                    'inverse': {
                        'extends': 'default',
                    },
                },
                'future': {
                    'linear': {
                        'extends': 'default',
                    },
                    'inverse': {
                        'extends': 'default',
                    },
                },
            },
            '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)
        if expiry is not None:
            expiry = expiry[4:] + expiry[2:4] + expiry[0:2]
        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={}) -> Int:
        """
        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

        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.005000000000000000",
        #                "id": "1",
        #                "interest_credit": False,
        #                "interest_slabs": null,
        #                "kyc_deposit_limit": "0.000000000000000000",
        #                "kyc_withdrawal_limit": "0.000000000000000000",
        #                "min_withdrawal_amount": "0.010000000000000000",
        #                "minimum_precision": "4",
        #                "name": "Ethereum",
        #                "networks": [
        #                    {
        #                        "allowed_deposit_groups": null,
        #                        "base_withdrawal_fee": "0.0025",
        #                        "deposit_status": "enabled",
        #                        "memo_required": False,
        #                        "min_deposit_amount": "0.000050000000000000",
        #                        "min_withdrawal_amount": "0.010000000000000000",
        #                        "minimum_deposit_confirmations": "12",
        #                        "network": "ERC20",
        #                        "variable_withdrawal_fee": "0",
        #                        "withdrawal_status": "enabled"
        #                    },
        #                    {
        #                        "allowed_deposit_groups": null,
        #                        "base_withdrawal_fee": "0.0001",
        #                        "deposit_status": "enabled",
        #                        "memo_required": False,
        #                        "min_deposit_amount": "0.000050000000000000",
        #                        "min_withdrawal_amount": "0.000300000000000000",
        #                        "minimum_deposit_confirmations": "15",
        #                        "network": "BEP20(BSC)",
        #                        "variable_withdrawal_fee": "0",
        #                        "withdrawal_status": "enabled"
        #                    }
        #                ],
        #                "precision": "18",
        #                "sort_priority": "3",
        #                "symbol": "ETH",
        #                "variable_withdrawal_fee": "0.000000000000000000"
        #            },
        #         ],
        #         "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)
            chains = self.safe_list(currency, 'networks', [])
            networks = {}
            for j in range(0, len(chains)):
                chain = chains[j]
                networkId = self.safe_string(chain, 'network')
                networkCode = self.network_id_to_code(networkId)
                networks[networkCode] = {
                    'id': networkId,
                    'network': networkCode,
                    'name': self.safe_string(chain, 'name'),
                    'info': chain,
                    'active': self.safe_string(chain, 'status') == 'enabled',
                    'deposit': self.safe_string(chain, 'deposit_status') == 'enabled',
                    'withdraw': self.safe_string(chain, 'withdrawal_status') == 'enabled',
                    'fee': self.safe_number(chain, 'base_withdrawal_fee'),
                    'limits': {
                        'deposit': {
                            'min': self.safe_number(chain, 'min_deposit_amount'),
                            'max': None,
                        },
                        'withdraw': {
                            'min': self.safe_number(chain, 'min_withdrawal_amount'),
                            'max': None,
                        },
                    },
                }
            result[code] = self.safe_currency_structure({
                'id': id,
                'numericId': numericId,
                'code': code,
                'name': self.safe_string(currency, 'name'),
                'info': currency,  # the original payload
                'active': None,
                'deposit': self.safe_string(currency, 'deposit_status') == 'enabled',
                'withdraw': self.safe_string(currency, 'withdrawal_status') == 'enabled',
                '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': networks,
                'type': 'crypto',
            })
        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

        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 == quote)
            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': None if spot else contractSize,
                'expiry': expiry,
                'expiryDatetime': self.iso8601(expiry),  # do not use raw expiry string
                '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'),
            'markPrice': self.safe_number(ticker, 'mark_price'),
            'indexPrice': self.safe_number(ticker, 'spot_price'),
            '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

        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

        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

        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

        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: str = '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

        https://docs.delta.exchange/#delta-exchange-api-v2-historical-ohlc-candles-sparklines

        :param str symbol: unified symbol of the market to fetch OHLCV data for
        :param str timeframe: the length of time each candle represents
        :param int [since]: timestamp in ms of the earliest candle to fetch
        :param int [limit]: the maximum amount of candles to fetch
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :param str [params.until]: timestamp in ms of the latest candle to fetch
        :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
        until = self.safe_integer_product(params, 'until', 0.001)
        untilIsDefined = (until is not None)
        if untilIsDefined:
            until = self.parse_to_int(until)
        if since is None:
            end = until if untilIsDefined else self.seconds()
            request['end'] = end
            request['start'] = end - limit * duration
        else:
            start = self.parse_to_int(since / 1000)
            request['start'] = start
            request['end'] = until if untilIsDefined else 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', 'until'])
        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

        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

        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={}) -> List[Position]:
        """
        fetch all open positions

        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
        #     }
        #
        # fetchOrder
        #
        #     {
        #         "id": 123,
        #         "user_id": 453671,
        #         "size": 10,
        #         "unfilled_size": 2,
        #         "side": "buy",
        #         "order_type": "limit_order",
        #         "limit_price": "59000",
        #         "stop_order_type": "stop_loss_order",
        #         "stop_price": "55000",
        #         "paid_commission": "0.5432",
        #         "commission": "0.5432",
        #         "reduce_only": False,
        #         "client_order_id": "my_signal_34521712",
        #         "state": "open",
        #         "created_at": "1725865012000000",
        #         "product_id": 27,
        #         "product_symbol": "BTCUSD"
        #     }
        #
        id = self.safe_string(order, 'id')
        clientOrderId = self.safe_string(order, 'client_order_id')
        createdAt = self.safe_string(order, 'created_at')
        timestamp = None
        if createdAt is not None:
            if createdAt.find('-') >= 0:
                timestamp = self.parse8601(createdAt)
            else:
                timestamp = self.safe_integer_product(order, 'created_at', 0.001)
        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')
        if type is not None:
            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

        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 fulfilled, 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

        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 fulfilled, 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

        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

        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 [
            self.safe_order({
                'info': response,
            }),
        ]

    def fetch_order(self, id: str, symbol: Str = None, params={}) -> Order:
        """
        fetches information on an order made by the user

        https://docs.delta.exchange/#get-order-by-id
        https://docs.delta.exchange/#get-order-by-client-oid

        :param str id: the 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
        :param str [params.clientOrderId]: client order id of the order
        :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
        """
        self.load_markets()
        market = None
        if symbol is not None:
            market = self.market(symbol)
        clientOrderId = self.safe_string_n(params, ['clientOrderId', 'client_oid', 'clientOid'])
        params = self.omit(params, ['clientOrderId', 'client_oid', 'clientOid'])
        request: dict = {}
        response = None
        if clientOrderId is not None:
            request['client_oid'] = clientOrderId
            response = self.privateGetOrdersClientOrderIdClientOid(self.extend(request, params))
        else:
            request['order_id'] = id
            response = self.privateGetOrdersOrderId(self.extend(request, params))
        #
        #     {
        #         "success": True,
        #         "result": {
        #             "id": 123,
        #             "user_id": 453671,
        #             "size": 10,
        #             "unfilled_size": 2,
        #             "side": "buy",
        #             "order_type": "limit_order",
        #             "limit_price": "59000",
        #             "stop_order_type": "stop_loss_order",
        #             "stop_price": "55000",
        #             "paid_commission": "0.5432",
        #             "commission": "0.5432",
        #             "reduce_only": False,
        #             "client_order_id": "my_signal_34521712",
        #             "state": "open",
        #             "created_at": "1725865012000000",
        #             "product_id": 27,
        #             "product_symbol": "BTCUSD"
        #         }
        #     }
        #
        result = self.safe_dict(response, 'result', {})
        return self.parse_order(result, market)

    def fetch_open_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
        """
        fetch all unfilled currently open orders

        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

        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

        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={}) -> List[LedgerEntry]:
        """
        fetch the history of changes, actions done by the user or operations that altered the balance of the user

        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 entries 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>`
        """
        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) -> LedgerEntry:
        #
        #     {
        #         "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 self.safe_ledger_entry({
            '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,
        }, currency)

    def fetch_deposit_address(self, code: str, params={}) -> DepositAddress:
        """
        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) -> DepositAddress:
        #
        #    {
        #        "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 {
            'info': depositAddress,
            'currency': self.safe_currency_code(marketId, currency),
            'network': self.network_id_to_code(networkId),
            'address': address,
            'tag': self.safe_string(depositAddress, 'memo'),
        }

    def fetch_funding_rate(self, symbol: str, params={}) -> FundingRate:
        """
        fetch the current funding rate

        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={}) -> FundingRates:
        """
        fetch the funding rate for multiple markets

        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 list of `funding rate structures <https://docs.ccxt.com/#/?id=funding-rates-structure>`, indexed 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', [])
        return self.parse_funding_rates(rates, symbols)

    def parse_funding_rate(self, contract, market: Market = None) -> FundingRate:
        #
        #     {
        #         "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,
            'interval': None,
        }

    def add_margin(self, symbol: str, amount: float, params={}) -> MarginModification:
        """
        add margin

        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

        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

        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

        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

        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

        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

        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

        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

        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

        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':
                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
