# -*- 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.async_support.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)

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

    async 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 = await 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,
        }

    async 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 = await 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

    async def load_markets(self, reload=False, params={}):
        markets = await 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

    async 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 = await 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)

    async 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>`
        """
        await self.load_markets()
        market = self.market(symbol)
        request: dict = {
            'symbol': market['id'],
        }
        response = await 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)

    async def fetch_tickers(self, symbols: Strings = None, params={}) -> Tickers:
        """
        fetches price tickers for multiple markets, statistical information calculated over the past 24 hours for each market

        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>`
        """
        await self.load_markets()
        symbols = self.market_symbols(symbols)
        response = await 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)

    async def fetch_order_book(self, symbol: str, limit: Int = None, params={}) -> OrderBook:
        """
        fetches information on open orders with bid(buy) and ask(sell) prices, volumes and other data

        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
        """
        await self.load_markets()
        market = self.market(symbol)
        request: dict = {
            'symbol': market['id'],
        }
        if limit is not None:
            request['depth'] = limit
        response = await 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)

    async def fetch_trades(self, symbol: str, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
        """
        get the list of most recent trades for a particular symbol

        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>`
        """
        await self.load_markets()
        market = self.market(symbol)
        request: dict = {
            'symbol': market['id'],
        }
        response = await 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'),
        ]

    async 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
        """
        await 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 = await 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)

    async 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>`
        """
        await self.load_markets()
        response = await 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)

    async 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>`
        """
        await self.load_markets()
        market = self.market(symbol)
        request: dict = {
            'product_id': market['numericId'],
        }
        response = await 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)

    async 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>`
        """
        await self.load_markets()
        response = await 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)

    async 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>`
        """
        await 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 = await 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)

    async 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>`
        """
        await 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 = await 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)

    async 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')
        await self.load_markets()
        market = self.market(symbol)
        request: dict = {
            'id': int(id),
            'product_id': market['numericId'],
        }
        response = await 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)

    async 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')
        await 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,
            }),
        ]

    async 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>`
        """
        await 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 = await self.privateGetOrdersClientOrderIdClientOid(self.extend(request, params))
        else:
            request['order_id'] = id
            response = await 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)

    async 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 await self.fetch_orders_with_method('privateGetOrders', symbol, since, limit, params)

    async 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 await self.fetch_orders_with_method('privateGetOrdersHistory', symbol, since, limit, params)

    async def fetch_orders_with_method(self, method, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
        await 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 = await self.privateGetOrders(self.extend(request, params))
        elif method == 'privateGetOrdersHistory':
            response = await 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)

    async 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>`
        """
        await 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 = await 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)

    async 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>`
        """
        await 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 = await 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)

    async 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>`
        """
        await 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 = await 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'),
        }

    async 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>`
        """
        await 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 = await 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)

    async 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
        """
        await self.load_markets()
        symbols = self.market_symbols(symbols)
        request: dict = {
            'contract_types': 'perpetual_futures',
        }
        response = await 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,
        }

    async 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 await self.modify_margin_helper(symbol, amount, 'add', params)

    async 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 await self.modify_margin_helper(symbol, amount, 'reduce', params)

    async def modify_margin_helper(self, symbol: str, amount, type, params={}) -> MarginModification:
        await 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 = await 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,
        }

    async 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:
        """
        await 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 = await 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)

    async 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>`
        """
        await self.load_markets()
        market = self.market(symbol)
        request: dict = {
            'product_id': market['numericId'],
        }
        response = await 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,
        }

    async 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')
        await 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 await self.privatePostProductsProductIdOrdersLeverage(self.extend(request, params))

    async 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>`
        """
        await 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 = await 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

    async 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>`
        """
        await self.load_markets()
        market = self.market(symbol)
        request: dict = {
            'symbol': market['id'],
        }
        response = await 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,
        }

    async 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>`
        """
        await self.load_markets()
        request: dict = {
            'close_all_portfolio': True,
            'close_all_isolated': True,
            # 'user_id': 12345,
        }
        response = await self.privatePostPositionsCloseAll(self.extend(request, params))
        #
        # {"result":{},"success":true}
        #
        position = self.parse_position(self.safe_dict(response, 'result', {}))
        return [position]

    async 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>`
        """
        await self.load_markets()
        market = None
        if symbol is not None:
            market = self.market(symbol)
        response = await 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'),
        }

    async 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>`
        """
        await self.load_markets()
        market = self.market(symbol)
        request: dict = {
            'symbol': market['id'],
        }
        response = await 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
