3666 lines
158 KiB
Python
3666 lines
158 KiB
Python
# -*- 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
|