Files
ccxt_with_mt5/ccxt/delta.py
lz_db 0fab423a18 add
2025-11-16 12:31:03 +08:00

3666 lines
157 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.base.exchange import Exchange
from ccxt.abstract.delta import ImplicitAPI
import hashlib
from ccxt.base.types import Any, Balances, Currencies, Currency, DepositAddress, Greeks, Int, LedgerEntry, Leverage, MarginMode, MarginModification, Market, Num, Option, Order, OrderBook, OrderSide, OrderType, Position, Str, Strings, Ticker, Tickers, FundingRate, FundingRates, Trade, MarketInterface
from typing import List
from ccxt.base.errors import ExchangeError
from ccxt.base.errors import AuthenticationError
from ccxt.base.errors import ArgumentsRequired
from ccxt.base.errors import BadRequest
from ccxt.base.errors import BadSymbol
from ccxt.base.errors import InsufficientFunds
from ccxt.base.errors import InvalidOrder
from ccxt.base.errors import OrderNotFound
from ccxt.base.errors import ExchangeNotAvailable
from ccxt.base.decimal_to_precision import TICK_SIZE
from ccxt.base.precise import Precise
class delta(Exchange, ImplicitAPI):
def describe(self) -> Any:
return self.deep_extend(super(delta, self).describe(), {
'id': 'delta',
'name': 'Delta Exchange',
'countries': ['VC'], # Saint Vincent and the Grenadines
'rateLimit': 300,
'version': 'v2',
# new metainfo interface
'has': {
'CORS': None,
'spot': True,
'margin': False,
'swap': True,
'future': False,
'option': True,
'addMargin': True,
'cancelAllOrders': True,
'cancelOrder': True,
'closeAllPositions': True,
'closePosition': False,
'createOrder': True,
'createReduceOnlyOrder': True,
'editOrder': True,
'fetchBalance': True,
'fetchClosedOrders': True,
'fetchCurrencies': True,
'fetchDeposit': None,
'fetchDepositAddress': True,
'fetchDepositAddresses': False,
'fetchDepositAddressesByNetwork': False,
'fetchDeposits': None,
'fetchFundingHistory': False,
'fetchFundingRate': True,
'fetchFundingRateHistory': False,
'fetchFundingRates': True,
'fetchGreeks': True,
'fetchIndexOHLCV': True,
'fetchLedger': True,
'fetchLeverage': True,
'fetchLeverageTiers': False, # An infinite number of tiers, see examples/js/delta-maintenance-margin-rate-max-leverage.js
'fetchMarginMode': True,
'fetchMarginModes': False,
'fetchMarketLeverageTiers': False,
'fetchMarkets': True,
'fetchMarkOHLCV': True,
'fetchMySettlementHistory': False,
'fetchMyTrades': True,
'fetchOHLCV': True,
'fetchOpenInterest': True,
'fetchOpenOrders': True,
'fetchOption': True,
'fetchOptionChain': False,
'fetchOrder': True,
'fetchOrderBook': True,
'fetchPosition': True,
'fetchPositionMode': False,
'fetchPositions': True,
'fetchPremiumIndexOHLCV': False,
'fetchSettlementHistory': True,
'fetchStatus': True,
'fetchTicker': True,
'fetchTickers': True,
'fetchTime': True,
'fetchTrades': True,
'fetchTransfer': None,
'fetchTransfers': None,
'fetchUnderlyingAssets': False,
'fetchVolatilityHistory': False,
'fetchWithdrawal': None,
'fetchWithdrawals': None,
'reduceMargin': True,
'setLeverage': True,
'setMargin': False,
'setMarginMode': False,
'setPositionMode': False,
'transfer': False,
'withdraw': False,
},
'timeframes': {
'1m': '1m',
'3m': '3m',
'5m': '5m',
'15m': '15m',
'30m': '30m',
'1h': '1h',
'2h': '2h',
'4h': '4h',
'6h': '6h',
'1d': '1d',
'7d': '7d',
'1w': '1w',
'2w': '2w',
'1M': '30d',
},
'urls': {
'logo': 'https://user-images.githubusercontent.com/1294454/99450025-3be60a00-2931-11eb-9302-f4fd8d8589aa.jpg',
'test': {
'public': 'https://testnet-api.delta.exchange',
'private': 'https://testnet-api.delta.exchange',
},
'api': {
'public': 'https://api.delta.exchange',
'private': 'https://api.delta.exchange',
},
'www': 'https://www.delta.exchange',
'doc': [
'https://docs.delta.exchange',
],
'fees': 'https://www.delta.exchange/fees',
'referral': 'https://www.delta.exchange/app/signup/?code=IULYNB',
},
'api': {
'public': {
'get': [
'assets',
'indices',
'products',
'products/{symbol}',
'tickers',
'tickers/{symbol}',
'l2orderbook/{symbol}',
'trades/{symbol}',
'stats',
'history/candles',
'history/sparklines',
'settings',
],
},
'private': {
'get': [
'orders',
'orders/{order_id}',
'orders/client_order_id/{client_oid}',
'products/{product_id}/orders/leverage',
'positions/margined',
'positions',
'orders/history',
'fills',
'fills/history/download/csv',
'wallet/balances',
'wallet/transactions',
'wallet/transactions/download',
'wallets/sub_accounts_transfer_history',
'users/trading_preferences',
'sub_accounts',
'profile',
'heartbeat',
'deposits/address',
],
'post': [
'orders',
'orders/bracket',
'orders/batch',
'products/{product_id}/orders/leverage',
'positions/change_margin',
'positions/close_all',
'wallets/sub_account_balance_transfer',
'heartbeat/create',
'heartbeat',
'orders/cancel_after',
'orders/leverage',
],
'put': [
'orders',
'orders/bracket',
'orders/batch',
'positions/auto_topup',
'users/update_mmp',
'users/reset_mmp',
],
'delete': [
'orders',
'orders/all',
'orders/batch',
],
},
},
'fees': {
'trading': {
'tierBased': True,
'percentage': True,
'taker': self.parse_number('0.0015'),
'maker': self.parse_number('0.0010'),
'tiers': {
'taker': [
[self.parse_number('0'), self.parse_number('0.0015')],
[self.parse_number('100'), self.parse_number('0.0013')],
[self.parse_number('250'), self.parse_number('0.0013')],
[self.parse_number('1000'), self.parse_number('0.001')],
[self.parse_number('5000'), self.parse_number('0.0009')],
[self.parse_number('10000'), self.parse_number('0.00075')],
[self.parse_number('20000'), self.parse_number('0.00065')],
],
'maker': [
[self.parse_number('0'), self.parse_number('0.001')],
[self.parse_number('100'), self.parse_number('0.001')],
[self.parse_number('250'), self.parse_number('0.0009')],
[self.parse_number('1000'), self.parse_number('0.00075')],
[self.parse_number('5000'), self.parse_number('0.0006')],
[self.parse_number('10000'), self.parse_number('0.0005')],
[self.parse_number('20000'), self.parse_number('0.0005')],
],
},
},
},
'userAgent': self.userAgents['chrome39'], # needed for C#
'options': {
'networks': {
'TRC20': 'TRC20(TRON)',
'BEP20': 'BEP20(BSC)',
},
},
'features': {
'default': {
'sandbox': True,
'createOrder': {
'marginMode': False,
'triggerPrice': True, # todo implement
# todo implement
'triggerPriceType': {
'last': True,
'mark': True,
'index': True,
},
'triggerDirection': False,
'stopLossPrice': False, # todo
'takeProfitPrice': False, # todo
'attachedStopLossTakeProfit': {
'triggerPriceType': None,
'price': True,
},
# todo implementation
'timeInForce': {
'IOC': True,
'FOK': True,
'PO': True,
'GTD': False,
},
'hedged': False,
'selfTradePrevention': False,
'trailing': False, # todo: implement
'iceberg': False,
'leverage': False,
'marketBuyByCost': False,
'marketBuyRequiresPrice': False,
},
'createOrders': None, # todo: implement
'fetchMyTrades': {
'marginMode': False,
'limit': 100, # todo: revise
'daysBack': 100000,
'untilDays': 100000,
'symbolRequired': False,
},
'fetchOrder': None,
'fetchOpenOrders': {
'marginMode': False,
'limit': 100, # todo: revise
'trigger': False,
'trailing': False,
'symbolRequired': False,
},
'fetchOrders': None,
'fetchClosedOrders': {
'marginMode': False,
'limit': 500,
'daysBack': 100000,
'daysBackCanceled': 1,
'untilDays': 100000,
'trigger': False,
'trailing': False,
'symbolRequired': False,
},
'fetchOHLCV': {
'limit': 2000, # todo: recheck
},
},
'spot': {
'extends': 'default',
},
'swap': {
'linear': {
'extends': 'default',
},
'inverse': {
'extends': 'default',
},
},
'future': {
'linear': {
'extends': 'default',
},
'inverse': {
'extends': 'default',
},
},
},
'precisionMode': TICK_SIZE,
'requiredCredentials': {
'apiKey': True,
'secret': True,
},
'exceptions': {
'exact': {
# Margin required to place order with selected leverage and quantity is insufficient.
'insufficient_margin': InsufficientFunds, # {"error":{"code":"insufficient_margin","context":{"available_balance":"0.000000000000000000","required_additional_balance":"1.618626000000000000000000000"}},"success":false}
'order_size_exceed_available': InvalidOrder, # The order book doesn't have sufficient liquidity, hence the order couldnt be filled, for example, ioc orders
'risk_limits_breached': BadRequest, # orders couldn't be placed will breach allowed risk limits.
'invalid_contract': BadSymbol, # The contract/product is either doesn't exist or has already expired.
'immediate_liquidation': InvalidOrder, # Order will cause immediate liquidation.
'out_of_bankruptcy': InvalidOrder, # Order prices are out of position bankruptcy limits.
'self_matching_disrupted_post_only': InvalidOrder, # Self matching is not allowed during auction.
'immediate_execution_post_only': InvalidOrder, # orders couldn't be placed includes post only orders which will be immediately executed
'bad_schema': BadRequest, # {"error":{"code":"bad_schema","context":{"schema_errors":[{"code":"validation_error","message":"id is required","param":""}]}},"success":false}
'invalid_api_key': AuthenticationError, # {"success":false,"error":{"code":"invalid_api_key"}}
'invalid_signature': AuthenticationError, # {"success":false,"error":{"code":"invalid_signature"}}
'open_order_not_found': OrderNotFound, # {"error":{"code":"open_order_not_found"},"success":false}
'unavailable': ExchangeNotAvailable, # {"error":{"code":"unavailable"},"success":false}
},
'broad': {
},
},
})
def create_expired_option_market(self, symbol: str):
# support expired option contracts
quote = 'USDT'
optionParts = symbol.split('-')
symbolBase = symbol.split('/')
base = None
expiry = None
optionType = None
if symbol.find('/') > -1:
base = self.safe_string(symbolBase, 0)
expiry = self.safe_string(optionParts, 1)
optionType = self.safe_string(optionParts, 3)
else:
base = self.safe_string(optionParts, 1)
expiry = self.safe_string(optionParts, 3)
optionType = self.safe_string(optionParts, 0)
if expiry is not None:
expiry = expiry[4:] + expiry[2:4] + expiry[0:2]
settle = quote
strike = self.safe_string(optionParts, 2)
datetime = self.convert_expire_date(expiry)
timestamp = self.parse8601(datetime)
return {
'id': optionType + '-' + base + '-' + strike + '-' + expiry,
'symbol': base + '/' + quote + ':' + settle + '-' + expiry + '-' + strike + '-' + optionType,
'base': base,
'quote': quote,
'settle': settle,
'baseId': base,
'quoteId': quote,
'settleId': settle,
'active': False,
'type': 'option',
'linear': None,
'inverse': None,
'spot': False,
'swap': False,
'future': False,
'option': True,
'margin': False,
'contract': True,
'contractSize': self.parse_number('1'),
'expiry': timestamp,
'expiryDatetime': datetime,
'optionType': 'call' if (optionType == 'C') else 'put',
'strike': self.parse_number(strike),
'precision': {
'amount': None,
'price': None,
},
'limits': {
'amount': {
'min': None,
'max': None,
},
'price': {
'min': None,
'max': None,
},
'cost': {
'min': None,
'max': None,
},
},
'info': None,
}
def safe_market(self, marketId: Str = None, market: Market = None, delimiter: Str = None, marketType: Str = None) -> MarketInterface:
isOption = (marketId is not None) and ((marketId.endswith('-C')) or (marketId.endswith('-P')) or (marketId.startswith('C-')) or (marketId.startswith('P-')))
if isOption and not (marketId in self.markets_by_id):
# handle expired option contracts
return self.create_expired_option_market(marketId)
return super(delta, self).safe_market(marketId, market, delimiter, marketType)
def fetch_time(self, params={}) -> Int:
"""
fetches the current integer timestamp in milliseconds from the exchange server
:param dict [params]: extra parameters specific to the exchange API endpoint
:returns int: the current integer timestamp in milliseconds from the exchange server
"""
response = self.publicGetSettings(params)
# full response sample under `fetchStatus`
result = self.safe_dict(response, 'result', {})
return self.safe_integer_product(result, 'server_time', 0.001)
def fetch_status(self, params={}):
"""
the latest known information on the availability of the exchange API
:param dict [params]: extra parameters specific to the exchange API endpoint
:returns dict: a `status structure <https://docs.ccxt.com/#/?id=exchange-status-structure>`
"""
response = self.publicGetSettings(params)
#
# {
# "result": {
# "deto_liquidity_mining_daily_reward": "40775",
# "deto_msp": "1.0",
# "deto_staking_daily_reward": "23764.08",
# "enabled_wallets": [
# "BTC",
# ...
# ],
# "portfolio_margin_params": {
# "enabled_portfolios": {
# ".DEAVAXUSDT": {
# "asset_id": 5,
# "futures_contingency_margin_percent": "1",
# "interest_rate": "0",
# "maintenance_margin_multiplier": "0.8",
# "max_price_shock": "20",
# "max_short_notional_limit": "2000",
# "options_contingency_margin_percent": "1",
# "options_discount_range": "10",
# "options_liq_band_range_percentage": "25",
# "settling_asset": "USDT",
# "sort_priority": 5,
# "underlying_asset": "AVAX",
# "volatility_down_shock": "30",
# "volatility_up_shock": "45"
# },
# ...
# },
# "portfolio_enabled_contracts": [
# "futures",
# "perpetual_futures",
# "call_options",
# "put_options"
# ]
# },
# "server_time": 1650640673500273,
# "trade_farming_daily_reward": "100000",
# "circulating_supply": "140000000",
# "circulating_supply_update_time": "1636752800",
# "deto_referral_mining_daily_reward": "0",
# "deto_total_reward_pool": "100000000",
# "deto_trade_mining_daily_reward": "0",
# "kyc_deposit_limit": "20",
# "kyc_withdrawal_limit": "10000",
# "maintenance_start_time": "1650387600000000",
# "msp_deto_commission_percent": "25",
# "under_maintenance": "false"
# },
# "success": True
# }
#
result = self.safe_dict(response, 'result', {})
underMaintenance = self.safe_string(result, 'under_maintenance')
status = 'maintenance' if (underMaintenance == 'true') else 'ok'
updated = self.safe_integer_product(result, 'server_time', 0.001, self.milliseconds())
return {
'status': status,
'updated': updated,
'eta': None,
'url': None,
'info': response,
}
def fetch_currencies(self, params={}) -> Currencies:
"""
fetches all available currencies on an exchange
https://docs.delta.exchange/#get-list-of-all-assets
:param dict [params]: extra parameters specific to the exchange API endpoint
:returns dict: an associative dictionary of currencies
"""
response = self.publicGetAssets(params)
#
# {
# "result": [
# {
# "base_withdrawal_fee": "0.005000000000000000",
# "id": "1",
# "interest_credit": False,
# "interest_slabs": null,
# "kyc_deposit_limit": "0.000000000000000000",
# "kyc_withdrawal_limit": "0.000000000000000000",
# "min_withdrawal_amount": "0.010000000000000000",
# "minimum_precision": "4",
# "name": "Ethereum",
# "networks": [
# {
# "allowed_deposit_groups": null,
# "base_withdrawal_fee": "0.0025",
# "deposit_status": "enabled",
# "memo_required": False,
# "min_deposit_amount": "0.000050000000000000",
# "min_withdrawal_amount": "0.010000000000000000",
# "minimum_deposit_confirmations": "12",
# "network": "ERC20",
# "variable_withdrawal_fee": "0",
# "withdrawal_status": "enabled"
# },
# {
# "allowed_deposit_groups": null,
# "base_withdrawal_fee": "0.0001",
# "deposit_status": "enabled",
# "memo_required": False,
# "min_deposit_amount": "0.000050000000000000",
# "min_withdrawal_amount": "0.000300000000000000",
# "minimum_deposit_confirmations": "15",
# "network": "BEP20(BSC)",
# "variable_withdrawal_fee": "0",
# "withdrawal_status": "enabled"
# }
# ],
# "precision": "18",
# "sort_priority": "3",
# "symbol": "ETH",
# "variable_withdrawal_fee": "0.000000000000000000"
# },
# ],
# "success":true
# }
#
currencies = self.safe_list(response, 'result', [])
result: dict = {}
for i in range(0, len(currencies)):
currency = currencies[i]
id = self.safe_string(currency, 'symbol')
numericId = self.safe_integer(currency, 'id')
code = self.safe_currency_code(id)
chains = self.safe_list(currency, 'networks', [])
networks = {}
for j in range(0, len(chains)):
chain = chains[j]
networkId = self.safe_string(chain, 'network')
networkCode = self.network_id_to_code(networkId)
networks[networkCode] = {
'id': networkId,
'network': networkCode,
'name': self.safe_string(chain, 'name'),
'info': chain,
'active': self.safe_string(chain, 'status') == 'enabled',
'deposit': self.safe_string(chain, 'deposit_status') == 'enabled',
'withdraw': self.safe_string(chain, 'withdrawal_status') == 'enabled',
'fee': self.safe_number(chain, 'base_withdrawal_fee'),
'limits': {
'deposit': {
'min': self.safe_number(chain, 'min_deposit_amount'),
'max': None,
},
'withdraw': {
'min': self.safe_number(chain, 'min_withdrawal_amount'),
'max': None,
},
},
}
result[code] = self.safe_currency_structure({
'id': id,
'numericId': numericId,
'code': code,
'name': self.safe_string(currency, 'name'),
'info': currency, # the original payload
'active': None,
'deposit': self.safe_string(currency, 'deposit_status') == 'enabled',
'withdraw': self.safe_string(currency, 'withdrawal_status') == 'enabled',
'fee': self.safe_number(currency, 'base_withdrawal_fee'),
'precision': self.parse_number(self.parse_precision(self.safe_string(currency, 'precision'))),
'limits': {
'amount': {'min': None, 'max': None},
'withdraw': {
'min': self.safe_number(currency, 'min_withdrawal_amount'),
'max': None,
},
},
'networks': networks,
'type': 'crypto',
})
return result
def load_markets(self, reload=False, params={}):
markets = super(delta, self).load_markets(reload, params)
currenciesByNumericId = self.safe_dict(self.options, 'currenciesByNumericId')
if (currenciesByNumericId is None) or reload:
self.options['currenciesByNumericId'] = self.index_by_stringified_numeric_id(self.currencies)
marketsByNumericId = self.safe_dict(self.options, 'marketsByNumericId')
if (marketsByNumericId is None) or reload:
self.options['marketsByNumericId'] = self.index_by_stringified_numeric_id(self.markets)
return markets
def index_by_stringified_numeric_id(self, input):
result: dict = {}
if input is None:
return None
keys = list(input.keys())
for i in range(0, len(keys)):
key = keys[i]
item = input[key]
numericIdString = self.safe_string(item, 'numericId')
if numericIdString is None:
continue
result[numericIdString] = item
return result
def fetch_markets(self, params={}) -> List[Market]:
"""
retrieves data on all markets for delta
https://docs.delta.exchange/#get-list-of-products
:param dict [params]: extra parameters specific to the exchange API endpoint
:returns dict[]: an array of objects representing market data
"""
response = self.publicGetProducts(params)
#
# {
# "meta":{"after":null, "before":null, "limit":100, "total_count":81},
# "result":[
# # the below response represents item from perpetual market
# {
# "annualized_funding":"5.475000000000000000",
# "is_quanto":false,
# "ui_config":{
# "default_trading_view_candle":"15",
# "leverage_slider_values":[1,3,5,10,25,50],
# "price_clubbing_values":[0.001,0.005,0.05,0.1,0.5,1,5],
# "show_bracket_orders":false,
# "sort_priority":29,
# "tags":[]
# },
# "basis_factor_max_limit":"0.15",
# "symbol":"P-LINK-D-151120",
# "id":1584,
# "default_leverage":"5.000000000000000000",
# "maker_commission_rate":"0.0005",
# "contract_unit_currency":"LINK",
# "strike_price":"12.507948",
# "settling_asset":{
# # asset structure
# },
# "auction_start_time":null,
# "auction_finish_time":null,
# "settlement_time":"2020-11-15T12:00:00Z",
# "launch_time":"2020-11-14T11:55:05Z",
# "spot_index":{
# # index structure
# },
# "trading_status":"operational",
# "tick_size":"0.001",
# "position_size_limit":100000,
# "notional_type":"vanilla", # vanilla, inverse
# "price_band":"0.4",
# "barrier_price":null,
# "description":"Daily LINK PUT options quoted in USDT and settled in USDT",
# "insurance_fund_margin_contribution":"1",
# "quoting_asset":{
# # asset structure
# },
# "liquidation_penalty_factor":"0.2",
# "product_specs":{"max_volatility":3,"min_volatility":0.3,"spot_price_band":"0.40"},
# "initial_margin_scaling_factor":"0.0001",
# "underlying_asset":{
# # asset structure
# },
# "state":"live",
# "contract_value":"1",
# "initial_margin":"2",
# "impact_size":5000,
# "settlement_price":null,
# "contract_type":"put_options", # put_options, call_options, move_options, perpetual_futures, interest_rate_swaps, futures, spreads
# "taker_commission_rate":"0.0005",
# "maintenance_margin":"1",
# "short_description":"LINK Daily PUT Options",
# "maintenance_margin_scaling_factor":"0.00005",
# "funding_method":"mark_price",
# "max_leverage_notional":"20000"
# },
# # the below response represents item from spot market
# {
# "position_size_limit": 10000000,
# "settlement_price": null,
# "funding_method": "mark_price",
# "settling_asset": null,
# "impact_size": 10,
# "id": 32258,
# "auction_finish_time": null,
# "description": "Solana tether spot market",
# "trading_status": "operational",
# "tick_size": "0.01",
# "liquidation_penalty_factor": "1",
# "spot_index": {
# "config": {"quoting_asset": "USDT", "service_id": 8, "underlying_asset": "SOL"},
# "constituent_exchanges": [
# {"exchange": "binance", "health_interval": 60, "health_priority": 1, "weight": 1},
# {"exchange": "huobi", "health_interval": 60, "health_priority": 2, "weight": 1}
# ],
# "constituent_indices": null,
# "description": "Solana index from binance and huobi",
# "health_interval": 300,
# "id": 105,
# "impact_size": "40.000000000000000000",
# "index_type": "spot_pair",
# "is_composite": False,
# "price_method": "ltp",
# "quoting_asset_id": 5,
# "symbol": ".DESOLUSDT",
# "tick_size": "0.000100000000000000",
# "underlying_asset_id": 66
# },
# "contract_type": "spot",
# "launch_time": "2022-02-03T10:18:11Z",
# "symbol": "SOL_USDT",
# "disruption_reason": null,
# "settlement_time": null,
# "insurance_fund_margin_contribution": "1",
# "is_quanto": False,
# "maintenance_margin": "5",
# "taker_commission_rate": "0.0005",
# "auction_start_time": null,
# "max_leverage_notional": "10000000",
# "state": "live",
# "annualized_funding": "0",
# "notional_type": "vanilla",
# "price_band": "100",
# "product_specs": {"kyc_required": False, "max_order_size": 2000, "min_order_size": 0.01, "quoting_precision": 4, "underlying_precision": 2},
# "default_leverage": "1.000000000000000000",
# "initial_margin": "10",
# "maintenance_margin_scaling_factor": "1",
# "ui_config": {
# "default_trading_view_candle": "1d",
# "leverage_slider_values": [],
# "price_clubbing_values": [0.01, 0.05, 0.1, 0.5, 1, 2.5, 5],
# "show_bracket_orders": False,
# "sort_priority": 2,
# "tags": []
# },
# "basis_factor_max_limit": "10000",
# "contract_unit_currency": "SOL",
# "strike_price": null,
# "quoting_asset": {
# "base_withdrawal_fee": "10.000000000000000000",
# "deposit_status": "enabled",
# "id": 5,
# "interest_credit": False,
# "interest_slabs": null,
# "kyc_deposit_limit": "100000.000000000000000000",
# "kyc_withdrawal_limit": "10000.000000000000000000",
# "min_withdrawal_amount": "30.000000000000000000",
# "minimum_precision": 2,
# "name": "Tether",
# "networks": [
# {"base_withdrawal_fee": "25", "deposit_status": "enabled", "memo_required": False, "network": "ERC20", "variable_withdrawal_fee": "0", "withdrawal_status": "enabled"},
# {"base_withdrawal_fee": "1", "deposit_status": "enabled", "memo_required": False, "network": "BEP20(BSC)", "variable_withdrawal_fee": "0", "withdrawal_status": "enabled"},
# {"base_withdrawal_fee": "1", "deposit_status": "disabled", "memo_required": False, "network": "TRC20(TRON)", "variable_withdrawal_fee": "0", "withdrawal_status": "disabled"}
# ],
# "precision": 8,
# "sort_priority": 1,
# "symbol": "USDT",
# "variable_withdrawal_fee": "0.000000000000000000",
# "withdrawal_status": "enabled"
# },
# "maker_commission_rate": "0.0005",
# "initial_margin_scaling_factor": "2",
# "underlying_asset": {
# "base_withdrawal_fee": "0.000000000000000000",
# "deposit_status": "enabled",
# "id": 66,
# "interest_credit": False,
# "interest_slabs": null,
# "kyc_deposit_limit": "0.000000000000000000",
# "kyc_withdrawal_limit": "0.000000000000000000",
# "min_withdrawal_amount": "0.020000000000000000",
# "minimum_precision": 4,
# "name": "Solana",
# "networks": [
# {"base_withdrawal_fee": "0.01", "deposit_status": "enabled", "memo_required": False, "network": "SOLANA", "variable_withdrawal_fee": "0", "withdrawal_status": "enabled"},
# {"base_withdrawal_fee": "0.01", "deposit_status": "enabled", "memo_required": False, "network": "BEP20(BSC)", "variable_withdrawal_fee": "0", "withdrawal_status": "enabled"}
# ],
# "precision": 8,
# "sort_priority": 7,
# "symbol": "SOL",
# "variable_withdrawal_fee": "0.000000000000000000",
# "withdrawal_status": "enabled"
# },
# "barrier_price": null,
# "contract_value": "1",
# "short_description": "SOL-USDT spot market"
# },
# ],
# "success":true
# }
#
markets = self.safe_list(response, 'result', [])
result = []
for i in range(0, len(markets)):
market = markets[i]
type = self.safe_string(market, 'contract_type')
if type == 'options_combos':
continue
# settlingAsset = self.safe_value(market, 'settling_asset', {})
quotingAsset = self.safe_dict(market, 'quoting_asset', {})
underlyingAsset = self.safe_dict(market, 'underlying_asset', {})
settlingAsset = self.safe_dict(market, 'settling_asset')
productSpecs = self.safe_dict(market, 'product_specs', {})
baseId = self.safe_string(underlyingAsset, 'symbol')
quoteId = self.safe_string(quotingAsset, 'symbol')
settleId = self.safe_string(settlingAsset, 'symbol')
id = self.safe_string(market, 'symbol')
numericId = self.safe_integer(market, 'id')
base = self.safe_currency_code(baseId)
quote = self.safe_currency_code(quoteId)
settle = self.safe_currency_code(settleId)
callOptions = (type == 'call_options')
putOptions = (type == 'put_options')
moveOptions = (type == 'move_options')
spot = (type == 'spot')
swap = (type == 'perpetual_futures')
future = (type == 'futures')
option = (callOptions or putOptions or moveOptions)
strike = self.safe_string(market, 'strike_price')
expiryDatetime = self.safe_string(market, 'settlement_time')
expiry = self.parse8601(expiryDatetime)
contractSize = self.safe_number(market, 'contract_value')
amountPrecision = None
if spot:
amountPrecision = self.parse_number(self.parse_precision(self.safe_string(productSpecs, 'underlying_precision'))) # seems inverse of 'impact_size'
else:
# other markets(swap, futures, move, spread, irs) seem to use the step of '1' contract
amountPrecision = self.parse_number('1')
linear = (settle == quote)
optionType = None
symbol = base + '/' + quote
if swap or future or option:
symbol = symbol + ':' + settle
if future or option:
symbol = symbol + '-' + self.yymmdd(expiry)
if option:
type = 'option'
letter = 'C'
optionType = 'call'
if putOptions:
letter = 'P'
optionType = 'put'
elif moveOptions:
letter = 'M'
optionType = 'move'
symbol = symbol + '-' + strike + '-' + letter
else:
type = 'future'
else:
type = 'swap'
state = self.safe_string(market, 'state')
result.append({
'id': id,
'numericId': numericId,
'symbol': symbol,
'base': base,
'quote': quote,
'settle': settle,
'baseId': baseId,
'quoteId': quoteId,
'settleId': settleId,
'type': type,
'spot': spot,
'margin': None if spot else False,
'swap': swap,
'future': future,
'option': option,
'active': (state == 'live'),
'contract': not spot,
'linear': None if spot else linear,
'inverse': None if spot else not linear,
'taker': self.safe_number(market, 'taker_commission_rate'),
'maker': self.safe_number(market, 'maker_commission_rate'),
'contractSize': None if spot else contractSize,
'expiry': expiry,
'expiryDatetime': self.iso8601(expiry), # do not use raw expiry string
'strike': self.parse_number(strike),
'optionType': optionType,
'precision': {
'amount': amountPrecision,
'price': self.safe_number(market, 'tick_size'),
},
'limits': {
'leverage': {
'min': None,
'max': None,
},
'amount': {
'min': self.parse_number('1'),
'max': self.safe_number(market, 'position_size_limit'),
},
'price': {
'min': None,
'max': None,
},
'cost': {
'min': self.safe_number(market, 'min_size'),
'max': None,
},
},
'created': self.parse8601(self.safe_string(market, 'launch_time')),
'info': market,
})
return result
def parse_ticker(self, ticker: dict, market: Market = None) -> Ticker:
#
# spot: fetchTicker, fetchTickers
#
# {
# "close": 30634.0,
# "contract_type": "spot",
# "greeks": null,
# "high": 30780.0,
# "low": 30340.5,
# "mark_price": "48000",
# "oi": "0.0000",
# "oi_change_usd_6h": "0.0000",
# "oi_contracts": "0",
# "oi_value": "0.0000",
# "oi_value_symbol": "BTC",
# "oi_value_usd": "0.0000",
# "open": 30464.0,
# "price_band": null,
# "product_id": 8320,
# "quotes": {},
# "size": 2.6816639999999996,
# "spot_price": "30637.91465121",
# "symbol": "BTC_USDT",
# "timestamp": 1689139767621299,
# "turnover": 2.6816639999999996,
# "turnover_symbol": "BTC",
# "turnover_usd": 81896.45613400004,
# "volume": 2.6816639999999996
# }
#
# swap: fetchTicker, fetchTickers
#
# {
# "close": 30600.5,
# "contract_type": "perpetual_futures",
# "funding_rate": "0.00602961",
# "greeks": null,
# "high": 30803.0,
# "low": 30265.5,
# "mark_basis": "-0.45601594",
# "mark_price": "30600.10481568",
# "oi": "469.9190",
# "oi_change_usd_6h": "2226314.9900",
# "oi_contracts": "469919",
# "oi_value": "469.9190",
# "oi_value_symbol": "BTC",
# "oi_value_usd": "14385640.6802",
# "open": 30458.5,
# "price_band": {
# "lower_limit": "29067.08312627",
# "upper_limit": "32126.77608693"
# },
# "product_id": 139,
# "quotes": {
# "ask_iv": null,
# "ask_size": "965",
# "best_ask": "30600.5",
# "best_bid": "30599.5",
# "bid_iv": null,
# "bid_size": "196",
# "impact_mid_price": null,
# "mark_iv": "-0.44931641"
# },
# "size": 1226303,
# "spot_price": "30612.85362773",
# "symbol": "BTCUSDT",
# "timestamp": 1689136597460456,
# "turnover": 37392218.45999999,
# "turnover_symbol": "USDT",
# "turnover_usd": 37392218.45999999,
# "volume": 1226.3029999999485
# }
#
# option: fetchTicker, fetchTickers
#
# {
# "contract_type": "call_options",
# "greeks": {
# "delta": "0.60873994",
# "gamma": "0.00014854",
# "rho": "7.71808010",
# "spot": "30598.49040622",
# "theta": "-30.44743017",
# "vega": "24.83508248"
# },
# "mark_price": "1347.74819696",
# "mark_vol": "0.39966303",
# "oi": "2.7810",
# "oi_change_usd_6h": "0.0000",
# "oi_contracts": "2781",
# "oi_value": "2.7810",
# "oi_value_symbol": "BTC",
# "oi_value_usd": "85127.4337",
# "price_band": {
# "lower_limit": "91.27423497",
# "upper_limit": "7846.19454697"
# },
# "product_id": 107150,
# "quotes": {
# "ask_iv": "0.41023239",
# "ask_size": "2397",
# "best_ask": "1374",
# "best_bid": "1322",
# "bid_iv": "0.38929375",
# "bid_size": "3995",
# "impact_mid_price": null,
# "mark_iv": "0.39965618"
# },
# "spot_price": "30598.43379314",
# "strike_price": "30000",
# "symbol": "C-BTC-30000-280723",
# "timestamp": 1689136932893181,
# "turnover_symbol": "USDT"
# }
#
timestamp = self.safe_integer_product(ticker, 'timestamp', 0.001)
marketId = self.safe_string(ticker, 'symbol')
symbol = self.safe_symbol(marketId, market)
last = self.safe_string(ticker, 'close')
quotes = self.safe_dict(ticker, 'quotes', {})
return self.safe_ticker({
'symbol': symbol,
'timestamp': timestamp,
'datetime': self.iso8601(timestamp),
'high': self.safe_number(ticker, 'high'),
'low': self.safe_number(ticker, 'low'),
'bid': self.safe_number(quotes, 'best_bid'),
'bidVolume': self.safe_number(quotes, 'bid_size'),
'ask': self.safe_number(quotes, 'best_ask'),
'askVolume': self.safe_number(quotes, 'ask_size'),
'vwap': None,
'open': self.safe_string(ticker, 'open'),
'close': last,
'last': last,
'previousClose': None,
'change': None,
'percentage': None,
'average': None,
'baseVolume': self.safe_number(ticker, 'volume'),
'quoteVolume': self.safe_number(ticker, 'turnover'),
'markPrice': self.safe_number(ticker, 'mark_price'),
'indexPrice': self.safe_number(ticker, 'spot_price'),
'info': ticker,
}, market)
def fetch_ticker(self, symbol: str, params={}) -> Ticker:
"""
fetches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
https://docs.delta.exchange/#get-ticker-for-a-product-by-symbol
:param str symbol: unified symbol of the market to fetch the ticker for
:param dict [params]: extra parameters specific to the exchange API endpoint
:returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
"""
self.load_markets()
market = self.market(symbol)
request: dict = {
'symbol': market['id'],
}
response = self.publicGetTickersSymbol(self.extend(request, params))
#
# spot
#
# {
# "result": {
# "close": 30634.0,
# "contract_type": "spot",
# "greeks": null,
# "high": 30780.0,
# "low": 30340.5,
# "mark_price": "48000",
# "oi": "0.0000",
# "oi_change_usd_6h": "0.0000",
# "oi_contracts": "0",
# "oi_value": "0.0000",
# "oi_value_symbol": "BTC",
# "oi_value_usd": "0.0000",
# "open": 30464.0,
# "price_band": null,
# "product_id": 8320,
# "quotes": {},
# "size": 2.6816639999999996,
# "spot_price": "30637.91465121",
# "symbol": "BTC_USDT",
# "timestamp": 1689139767621299,
# "turnover": 2.6816639999999996,
# "turnover_symbol": "BTC",
# "turnover_usd": 81896.45613400004,
# "volume": 2.6816639999999996
# },
# "success": True
# }
#
# swap
#
# {
# "result": {
# "close": 30600.5,
# "contract_type": "perpetual_futures",
# "funding_rate": "0.00602961",
# "greeks": null,
# "high": 30803.0,
# "low": 30265.5,
# "mark_basis": "-0.45601594",
# "mark_price": "30600.10481568",
# "oi": "469.9190",
# "oi_change_usd_6h": "2226314.9900",
# "oi_contracts": "469919",
# "oi_value": "469.9190",
# "oi_value_symbol": "BTC",
# "oi_value_usd": "14385640.6802",
# "open": 30458.5,
# "price_band": {
# "lower_limit": "29067.08312627",
# "upper_limit": "32126.77608693"
# },
# "product_id": 139,
# "quotes": {
# "ask_iv": null,
# "ask_size": "965",
# "best_ask": "30600.5",
# "best_bid": "30599.5",
# "bid_iv": null,
# "bid_size": "196",
# "impact_mid_price": null,
# "mark_iv": "-0.44931641"
# },
# "size": 1226303,
# "spot_price": "30612.85362773",
# "symbol": "BTCUSDT",
# "timestamp": 1689136597460456,
# "turnover": 37392218.45999999,
# "turnover_symbol": "USDT",
# "turnover_usd": 37392218.45999999,
# "volume": 1226.3029999999485
# },
# "success": True
# }
#
# option
#
# {
# "result": {
# "contract_type": "call_options",
# "greeks": {
# "delta": "0.60873994",
# "gamma": "0.00014854",
# "rho": "7.71808010",
# "spot": "30598.49040622",
# "theta": "-30.44743017",
# "vega": "24.83508248"
# },
# "mark_price": "1347.74819696",
# "mark_vol": "0.39966303",
# "oi": "2.7810",
# "oi_change_usd_6h": "0.0000",
# "oi_contracts": "2781",
# "oi_value": "2.7810",
# "oi_value_symbol": "BTC",
# "oi_value_usd": "85127.4337",
# "price_band": {
# "lower_limit": "91.27423497",
# "upper_limit": "7846.19454697"
# },
# "product_id": 107150,
# "quotes": {
# "ask_iv": "0.41023239",
# "ask_size": "2397",
# "best_ask": "1374",
# "best_bid": "1322",
# "bid_iv": "0.38929375",
# "bid_size": "3995",
# "impact_mid_price": null,
# "mark_iv": "0.39965618"
# },
# "spot_price": "30598.43379314",
# "strike_price": "30000",
# "symbol": "C-BTC-30000-280723",
# "timestamp": 1689136932893181,
# "turnover_symbol": "USDT"
# },
# "success": True
# }
#
result = self.safe_dict(response, 'result', {})
return self.parse_ticker(result, market)
def fetch_tickers(self, symbols: Strings = None, params={}) -> Tickers:
"""
fetches price tickers for multiple markets, statistical information calculated over the past 24 hours for each market
https://docs.delta.exchange/#get-tickers-for-products
:param str[]|None symbols: unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned
:param dict [params]: extra parameters specific to the exchange API endpoint
:returns dict: a dictionary of `ticker structures <https://docs.ccxt.com/#/?id=ticker-structure>`
"""
self.load_markets()
symbols = self.market_symbols(symbols)
response = self.publicGetTickers(params)
#
# spot
#
# {
# "result": [
# {
# "close": 30634.0,
# "contract_type": "spot",
# "greeks": null,
# "high": 30780.0,
# "low": 30340.5,
# "mark_price": "48000",
# "oi": "0.0000",
# "oi_change_usd_6h": "0.0000",
# "oi_contracts": "0",
# "oi_value": "0.0000",
# "oi_value_symbol": "BTC",
# "oi_value_usd": "0.0000",
# "open": 30464.0,
# "price_band": null,
# "product_id": 8320,
# "quotes": {},
# "size": 2.6816639999999996,
# "spot_price": "30637.91465121",
# "symbol": "BTC_USDT",
# "timestamp": 1689139767621299,
# "turnover": 2.6816639999999996,
# "turnover_symbol": "BTC",
# "turnover_usd": 81896.45613400004,
# "volume": 2.6816639999999996
# },
# ],
# "success":true
# }
#
# swap
#
# {
# "result": [
# {
# "close": 30600.5,
# "contract_type": "perpetual_futures",
# "funding_rate": "0.00602961",
# "greeks": null,
# "high": 30803.0,
# "low": 30265.5,
# "mark_basis": "-0.45601594",
# "mark_price": "30600.10481568",
# "oi": "469.9190",
# "oi_change_usd_6h": "2226314.9900",
# "oi_contracts": "469919",
# "oi_value": "469.9190",
# "oi_value_symbol": "BTC",
# "oi_value_usd": "14385640.6802",
# "open": 30458.5,
# "price_band": {
# "lower_limit": "29067.08312627",
# "upper_limit": "32126.77608693"
# },
# "product_id": 139,
# "quotes": {
# "ask_iv": null,
# "ask_size": "965",
# "best_ask": "30600.5",
# "best_bid": "30599.5",
# "bid_iv": null,
# "bid_size": "196",
# "impact_mid_price": null,
# "mark_iv": "-0.44931641"
# },
# "size": 1226303,
# "spot_price": "30612.85362773",
# "symbol": "BTCUSDT",
# "timestamp": 1689136597460456,
# "turnover": 37392218.45999999,
# "turnover_symbol": "USDT",
# "turnover_usd": 37392218.45999999,
# "volume": 1226.3029999999485
# },
# ],
# "success":true
# }
#
# option
#
# {
# "result": [
# {
# "contract_type": "call_options",
# "greeks": {
# "delta": "0.60873994",
# "gamma": "0.00014854",
# "rho": "7.71808010",
# "spot": "30598.49040622",
# "theta": "-30.44743017",
# "vega": "24.83508248"
# },
# "mark_price": "1347.74819696",
# "mark_vol": "0.39966303",
# "oi": "2.7810",
# "oi_change_usd_6h": "0.0000",
# "oi_contracts": "2781",
# "oi_value": "2.7810",
# "oi_value_symbol": "BTC",
# "oi_value_usd": "85127.4337",
# "price_band": {
# "lower_limit": "91.27423497",
# "upper_limit": "7846.19454697"
# },
# "product_id": 107150,
# "quotes": {
# "ask_iv": "0.41023239",
# "ask_size": "2397",
# "best_ask": "1374",
# "best_bid": "1322",
# "bid_iv": "0.38929375",
# "bid_size": "3995",
# "impact_mid_price": null,
# "mark_iv": "0.39965618"
# },
# "spot_price": "30598.43379314",
# "strike_price": "30000",
# "symbol": "C-BTC-30000-280723",
# "timestamp": 1689136932893181,
# "turnover_symbol": "USDT"
# },
# ],
# "success":true
# }
#
tickers = self.safe_list(response, 'result', [])
result: dict = {}
for i in range(0, len(tickers)):
ticker = self.parse_ticker(tickers[i])
symbol = ticker['symbol']
result[symbol] = ticker
return self.filter_by_array_tickers(result, 'symbol', symbols)
def fetch_order_book(self, symbol: str, limit: Int = None, params={}) -> OrderBook:
"""
fetches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
https://docs.delta.exchange/#get-l2-orderbook
:param str symbol: unified symbol of the market to fetch the order book for
:param int [limit]: the maximum amount of order book entries to return
:param dict [params]: extra parameters specific to the exchange API endpoint
:returns dict: A dictionary of `order book structures <https://docs.ccxt.com/#/?id=order-book-structure>` indexed by market symbols
"""
self.load_markets()
market = self.market(symbol)
request: dict = {
'symbol': market['id'],
}
if limit is not None:
request['depth'] = limit
response = self.publicGetL2orderbookSymbol(self.extend(request, params))
#
# {
# "result":{
# "buy":[
# {"price":"15814.0","size":912},
# {"price":"15813.5","size":1279},
# {"price":"15813.0","size":1634},
# ],
# "sell":[
# {"price":"15814.5","size":625},
# {"price":"15815.0","size":982},
# {"price":"15815.5","size":1328},
# ],
# "symbol":"BTCUSDT"
# },
# "success":true
# }
#
result = self.safe_dict(response, 'result', {})
return self.parse_order_book(result, market['symbol'], None, 'buy', 'sell', 'price', 'size')
def parse_trade(self, trade: dict, market: Market = None) -> Trade:
#
# public fetchTrades
#
# {
# "buyer_role":"maker",
# "price":"15896.5",
# "seller_role":"taker",
# "size":241,
# "symbol":"BTCUSDT",
# "timestamp":1605376684714595
# }
#
# private fetchMyTrades
#
# {
# "commission":"0.008335000000000000",
# "created_at":"2020-11-16T19:07:19Z",
# "fill_type":"normal",
# "id":"e7ff05c233a74245b72381f8dd91d1ce",
# "meta_data":{
# "effective_commission_rate":"0.0005",
# "order_price":"16249",
# "order_size":1,
# "order_type":"market_order",
# "order_unfilled_size":0,
# "trading_fee_credits_used":"0"
# },
# "order_id":"152999629",
# "price":"16669",
# "product":{
# "contract_type":"perpetual_futures",
# "contract_unit_currency":"BTC",
# "contract_value":"0.001",
# "id":139,
# "notional_type":"vanilla",
# "quoting_asset":{"minimum_precision":2,"precision":6,"symbol":"USDT"},
# "settling_asset":{"minimum_precision":2,"precision":6,"symbol":"USDT"},
# "symbol":"BTCUSDT",
# "tick_size":"0.5",
# "underlying_asset":{"minimum_precision":4,"precision":8,"symbol":"BTC"}
# },
# "product_id":139,
# "role":"taker",
# "side":"sell",
# "size":1
# }
#
id = self.safe_string(trade, 'id')
orderId = self.safe_string(trade, 'order_id')
timestamp = self.parse8601(self.safe_string(trade, 'created_at'))
timestamp = self.safe_integer_product(trade, 'timestamp', 0.001, timestamp)
priceString = self.safe_string(trade, 'price')
amountString = self.safe_string(trade, 'size')
product = self.safe_dict(trade, 'product', {})
marketId = self.safe_string(product, 'symbol')
symbol = self.safe_symbol(marketId, market)
sellerRole = self.safe_string(trade, 'seller_role')
side = self.safe_string(trade, 'side')
if side is None:
if sellerRole == 'taker':
side = 'sell'
elif sellerRole == 'maker':
side = 'buy'
takerOrMaker = self.safe_string(trade, 'role')
metaData = self.safe_dict(trade, 'meta_data', {})
type = self.safe_string(metaData, 'order_type')
if type is not None:
type = type.replace('_order', '')
feeCostString = self.safe_string(trade, 'commission')
fee = None
if feeCostString is not None:
settlingAsset = self.safe_dict(product, 'settling_asset', {})
feeCurrencyId = self.safe_string(settlingAsset, 'symbol')
feeCurrencyCode = self.safe_currency_code(feeCurrencyId)
fee = {
'cost': feeCostString,
'currency': feeCurrencyCode,
}
return self.safe_trade({
'id': id,
'order': orderId,
'timestamp': timestamp,
'datetime': self.iso8601(timestamp),
'symbol': symbol,
'type': type,
'side': side,
'price': priceString,
'amount': amountString,
'cost': None,
'takerOrMaker': takerOrMaker,
'fee': fee,
'info': trade,
}, market)
def fetch_trades(self, symbol: str, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
"""
get the list of most recent trades for a particular symbol
https://docs.delta.exchange/#get-public-trades
:param str symbol: unified symbol of the market to fetch trades for
:param int [since]: timestamp in ms of the earliest trade to fetch
:param int [limit]: the maximum amount of trades to fetch
:param dict [params]: extra parameters specific to the exchange API endpoint
:returns Trade[]: a list of `trade structures <https://docs.ccxt.com/#/?id=public-trades>`
"""
self.load_markets()
market = self.market(symbol)
request: dict = {
'symbol': market['id'],
}
response = self.publicGetTradesSymbol(self.extend(request, params))
#
# {
# "result":[
# {
# "buyer_role":"maker",
# "price":"15896.5",
# "seller_role":"taker",
# "size":241,
# "symbol":"BTCUSDT",
# "timestamp":1605376684714595
# }
# ],
# "success":true
# }
#
result = self.safe_list(response, 'result', [])
return self.parse_trades(result, market, since, limit)
def parse_ohlcv(self, ohlcv, market: Market = None) -> list:
#
# {
# "time":1605393120,
# "open":15989,
# "high":15989,
# "low":15987.5,
# "close":15987.5,
# "volume":565
# }
#
return [
self.safe_timestamp(ohlcv, 'time'),
self.safe_number(ohlcv, 'open'),
self.safe_number(ohlcv, 'high'),
self.safe_number(ohlcv, 'low'),
self.safe_number(ohlcv, 'close'),
self.safe_number(ohlcv, 'volume'),
]
def fetch_ohlcv(self, symbol: str, timeframe: str = '1m', since: Int = None, limit: Int = None, params={}) -> List[list]:
"""
fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market
https://docs.delta.exchange/#delta-exchange-api-v2-historical-ohlc-candles-sparklines
:param str symbol: unified symbol of the market to fetch OHLCV data for
:param str timeframe: the length of time each candle represents
:param int [since]: timestamp in ms of the earliest candle to fetch
:param int [limit]: the maximum amount of candles to fetch
:param dict [params]: extra parameters specific to the exchange API endpoint
:param str [params.until]: timestamp in ms of the latest candle to fetch
:returns int[][]: A list of candles ordered, open, high, low, close, volume
"""
self.load_markets()
market = self.market(symbol)
request: dict = {
'resolution': self.safe_string(self.timeframes, timeframe, timeframe),
}
duration = self.parse_timeframe(timeframe)
limit = limit if limit else 2000 # max 2000
until = self.safe_integer_product(params, 'until', 0.001)
untilIsDefined = (until is not None)
if untilIsDefined:
until = self.parse_to_int(until)
if since is None:
end = until if untilIsDefined else self.seconds()
request['end'] = end
request['start'] = end - limit * duration
else:
start = self.parse_to_int(since / 1000)
request['start'] = start
request['end'] = until if untilIsDefined else self.sum(start, limit * duration)
price = self.safe_string(params, 'price')
if price == 'mark':
request['symbol'] = 'MARK:' + market['id']
elif price == 'index':
request['symbol'] = market['info']['spot_index']['symbol']
else:
request['symbol'] = market['id']
params = self.omit(params, ['price', 'until'])
response = self.publicGetHistoryCandles(self.extend(request, params))
#
# {
# "success":true,
# "result":[
# {"time":1605393120,"open":15989,"high":15989,"low":15987.5,"close":15987.5,"volume":565},
# {"time":1605393180,"open":15966,"high":15966,"low":15959,"close":15959,"volume":24},
# {"time":1605393300,"open":15973,"high":15973,"low":15973,"close":15973,"volume":1288},
# ]
# }
#
result = self.safe_list(response, 'result', [])
return self.parse_ohlcvs(result, market, timeframe, since, limit)
def parse_balance(self, response) -> Balances:
balances = self.safe_list(response, 'result', [])
result: dict = {'info': response}
currenciesByNumericId = self.safe_dict(self.options, 'currenciesByNumericId', {})
for i in range(0, len(balances)):
balance = balances[i]
currencyId = self.safe_string(balance, 'asset_id')
currency = self.safe_dict(currenciesByNumericId, currencyId)
code = currencyId if (currency is None) else currency['code']
account = self.account()
account['total'] = self.safe_string(balance, 'balance')
account['free'] = self.safe_string(balance, 'available_balance')
result[code] = account
return self.safe_balance(result)
def fetch_balance(self, params={}) -> Balances:
"""
query for balance and get the amount of funds available for trading or funds locked in orders
https://docs.delta.exchange/#get-wallet-balances
:param dict [params]: extra parameters specific to the exchange API endpoint
:returns dict: a `balance structure <https://docs.ccxt.com/#/?id=balance-structure>`
"""
self.load_markets()
response = self.privateGetWalletBalances(params)
#
# {
# "result":[
# {
# "asset_id":1,
# "available_balance":"0",
# "balance":"0",
# "commission":"0",
# "id":154883,
# "interest_credit":"0",
# "order_margin":"0",
# "pending_referral_bonus":"0",
# "pending_trading_fee_credit":"0",
# "position_margin":"0",
# "trading_fee_credit":"0",
# "user_id":22142
# },
# ],
# "success":true
# }
#
return self.parse_balance(response)
def fetch_position(self, symbol: str, params={}):
"""
fetch data on a single open contract trade position
https://docs.delta.exchange/#get-position
:param str symbol: unified market symbol of the market the position is held in, default is None
:param dict [params]: extra parameters specific to the exchange API endpoint
:returns dict: a `position structure <https://docs.ccxt.com/#/?id=position-structure>`
"""
self.load_markets()
market = self.market(symbol)
request: dict = {
'product_id': market['numericId'],
}
response = self.privateGetPositions(self.extend(request, params))
#
# {
# "result":{
# "entry_price":null,
# "size":0,
# "timestamp":1605454074268079
# },
# "success":true
# }
#
result = self.safe_dict(response, 'result', {})
return self.parse_position(result, market)
def fetch_positions(self, symbols: Strings = None, params={}) -> List[Position]:
"""
fetch all open positions
https://docs.delta.exchange/#get-margined-positions
:param str[]|None symbols: list of unified market symbols
:param dict [params]: extra parameters specific to the exchange API endpoint
:returns dict[]: a list of `position structure <https://docs.ccxt.com/#/?id=position-structure>`
"""
self.load_markets()
response = self.privateGetPositionsMargined(params)
#
# {
# "success": True,
# "result": [
# {
# "user_id": 0,
# "size": 0,
# "entry_price": "string",
# "margin": "string",
# "liquidation_price": "string",
# "bankruptcy_price": "string",
# "adl_level": 0,
# "product_id": 0,
# "product_symbol": "string",
# "commission": "string",
# "realized_pnl": "string",
# "realized_funding": "string"
# }
# ]
# }
#
result = self.safe_list(response, 'result', [])
return self.parse_positions(result, symbols)
def parse_position(self, position: dict, market: Market = None):
#
# fetchPosition
#
# {
# "entry_price":null,
# "size":0,
# "timestamp":1605454074268079
# }
#
#
# fetchPositions
#
# {
# "user_id": 0,
# "size": 0,
# "entry_price": "string",
# "margin": "string",
# "liquidation_price": "string",
# "bankruptcy_price": "string",
# "adl_level": 0,
# "product_id": 0,
# "product_symbol": "string",
# "commission": "string",
# "realized_pnl": "string",
# "realized_funding": "string"
# }
#
marketId = self.safe_string(position, 'product_symbol')
market = self.safe_market(marketId, market)
symbol = market['symbol']
timestamp = self.safe_integer_product(position, 'timestamp', 0.001)
sizeString = self.safe_string(position, 'size')
side = None
if sizeString is not None:
if Precise.string_gt(sizeString, '0'):
side = 'buy'
elif Precise.string_lt(sizeString, '0'):
side = 'sell'
return self.safe_position({
'info': position,
'id': None,
'symbol': symbol,
'notional': None,
'marginMode': None,
'liquidationPrice': self.safe_number(position, 'liquidation_price'),
'entryPrice': self.safe_number(position, 'entry_price'),
'unrealizedPnl': None, # todo - realized_pnl ?
'percentage': None,
'contracts': self.parse_number(sizeString),
'contractSize': self.safe_number(market, 'contractSize'),
'markPrice': None,
'side': side,
'hedged': None,
'timestamp': timestamp,
'datetime': self.iso8601(timestamp),
'maintenanceMargin': None,
'maintenanceMarginPercentage': None,
'collateral': None,
'initialMargin': None,
'initialMarginPercentage': None,
'leverage': None,
'marginRatio': None,
'stopLossPrice': None,
'takeProfitPrice': None,
})
def parse_order_status(self, status: Str):
statuses: dict = {
'open': 'open',
'pending': 'open',
'closed': 'closed',
'cancelled': 'canceled',
}
return self.safe_string(statuses, status, status)
def parse_order(self, order: dict, market: Market = None) -> Order:
#
# createOrder, cancelOrder, editOrder, fetchOpenOrders, fetchClosedOrders
#
# {
# "average_fill_price":null,
# "bracket_order":null,
# "bracket_stop_loss_limit_price":null,
# "bracket_stop_loss_price":null,
# "bracket_take_profit_limit_price":null,
# "bracket_take_profit_price":null,
# "bracket_trail_amount":null,
# "cancellation_reason":null,
# "client_order_id":null,
# "close_on_trigger":"false",
# "commission":"0",
# "created_at":"2020-11-16T02:38:26Z",
# "id":152870626,
# "limit_price":"10000",
# "meta_data":{"source":"api"},
# "order_type":"limit_order",
# "paid_commission":"0",
# "product_id":139,
# "reduce_only":false,
# "side":"buy",
# "size":0,
# "state":"open",
# "stop_order_type":null,
# "stop_price":null,
# "stop_trigger_method":"mark_price",
# "time_in_force":"gtc",
# "trail_amount":null,
# "unfilled_size":0,
# "user_id":22142
# }
#
# fetchOrder
#
# {
# "id": 123,
# "user_id": 453671,
# "size": 10,
# "unfilled_size": 2,
# "side": "buy",
# "order_type": "limit_order",
# "limit_price": "59000",
# "stop_order_type": "stop_loss_order",
# "stop_price": "55000",
# "paid_commission": "0.5432",
# "commission": "0.5432",
# "reduce_only": False,
# "client_order_id": "my_signal_34521712",
# "state": "open",
# "created_at": "1725865012000000",
# "product_id": 27,
# "product_symbol": "BTCUSD"
# }
#
id = self.safe_string(order, 'id')
clientOrderId = self.safe_string(order, 'client_order_id')
createdAt = self.safe_string(order, 'created_at')
timestamp = None
if createdAt is not None:
if createdAt.find('-') >= 0:
timestamp = self.parse8601(createdAt)
else:
timestamp = self.safe_integer_product(order, 'created_at', 0.001)
marketId = self.safe_string(order, 'product_id')
marketsByNumericId = self.safe_dict(self.options, 'marketsByNumericId', {})
market = self.safe_value(marketsByNumericId, marketId, market)
symbol = marketId if (market is None) else market['symbol']
status = self.parse_order_status(self.safe_string(order, 'state'))
side = self.safe_string(order, 'side')
type = self.safe_string(order, 'order_type')
if type is not None:
type = type.replace('_order', '')
price = self.safe_string(order, 'limit_price')
amount = self.safe_string(order, 'size')
remaining = self.safe_string(order, 'unfilled_size')
average = self.safe_string(order, 'average_fill_price')
fee = None
feeCostString = self.safe_string(order, 'paid_commission')
if feeCostString is not None:
feeCurrencyCode = None
if market is not None:
settlingAsset = self.safe_dict(market['info'], 'settling_asset', {})
feeCurrencyId = self.safe_string(settlingAsset, 'symbol')
feeCurrencyCode = self.safe_currency_code(feeCurrencyId)
fee = {
'cost': feeCostString,
'currency': feeCurrencyCode,
}
return self.safe_order({
'info': order,
'id': id,
'clientOrderId': clientOrderId,
'timestamp': timestamp,
'datetime': self.iso8601(timestamp),
'lastTradeTimestamp': None,
'symbol': symbol,
'type': type,
'side': side,
'price': price,
'amount': amount,
'cost': None,
'average': average,
'filled': None,
'remaining': remaining,
'status': status,
'fee': fee,
'trades': None,
}, market)
def create_order(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}):
"""
create a trade order
https://docs.delta.exchange/#place-order
:param str symbol: unified symbol of the market to create an order in
:param str type: 'market' or 'limit'
:param str side: 'buy' or 'sell'
:param float amount: how much of currency you want to trade in units of base currency
:param float [price]: the price at which the order is to be fulfilled, in units of the quote currency, ignored in market orders
:param dict [params]: extra parameters specific to the exchange API endpoint
:param bool [params.reduceOnly]: *contract only* indicates if self order is to reduce the size of a position
:returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
"""
self.load_markets()
orderType = type + '_order'
market = self.market(symbol)
request: dict = {
'product_id': market['numericId'],
# 'limit_price': self.price_to_precision(market['symbol'], price),
'size': self.amount_to_precision(market['symbol'], amount),
'side': side,
'order_type': orderType,
# 'client_order_id': 'string',
# 'time_in_force': 'gtc', # gtc, ioc, fok
# 'post_only': 'false', # 'true',
# 'reduce_only': 'false', # 'true',
}
if type == 'limit':
request['limit_price'] = self.price_to_precision(market['symbol'], price)
clientOrderId = self.safe_string_2(params, 'clientOrderId', 'client_order_id')
params = self.omit(params, ['clientOrderId', 'client_order_id'])
if clientOrderId is not None:
request['client_order_id'] = clientOrderId
reduceOnly = self.safe_bool(params, 'reduceOnly')
if reduceOnly:
request['reduce_only'] = reduceOnly
params = self.omit(params, 'reduceOnly')
response = self.privatePostOrders(self.extend(request, params))
#
# {
# "result":{
# "average_fill_price":null,
# "bracket_order":null,
# "bracket_stop_loss_limit_price":null,
# "bracket_stop_loss_price":null,
# "bracket_take_profit_limit_price":null,
# "bracket_take_profit_price":null,
# "bracket_trail_amount":null,
# "cancellation_reason":null,
# "client_order_id":null,
# "close_on_trigger":"false",
# "commission":"0",
# "created_at":"2020-11-16T02:38:26Z",
# "id":152870626,
# "limit_price":"10000",
# "meta_data":{"source":"api"},
# "order_type":"limit_order",
# "paid_commission":"0",
# "product_id":139,
# "reduce_only":false,
# "side":"buy",
# "size":0,
# "state":"open",
# "stop_order_type":null,
# "stop_price":null,
# "stop_trigger_method":"mark_price",
# "time_in_force":"gtc",
# "trail_amount":null,
# "unfilled_size":0,
# "user_id":22142
# },
# "success":true
# }
#
result = self.safe_dict(response, 'result', {})
return self.parse_order(result, market)
def edit_order(self, id: str, symbol: str, type: OrderType, side: OrderSide, amount: Num = None, price: Num = None, params={}):
"""
edit a trade order
https://docs.delta.exchange/#edit-order
:param str id: order id
:param str symbol: unified symbol of the market to create an order in
:param str type: 'market' or 'limit'
:param str side: 'buy' or 'sell'
:param float amount: how much of the currency you want to trade in units of the base currency
:param float [price]: the price at which the order is to be fulfilled, in units of the quote currency
:param dict [params]: extra parameters specific to the exchange API endpoint
:returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
"""
self.load_markets()
market = self.market(symbol)
request: dict = {
'id': int(id),
'product_id': market['numericId'],
# "limit_price": self.price_to_precision(symbol, price),
# "size": self.amount_to_precision(symbol, amount),
}
if amount is not None:
request['size'] = int(self.amount_to_precision(symbol, amount))
if price is not None:
request['limit_price'] = self.price_to_precision(symbol, price)
response = self.privatePutOrders(self.extend(request, params))
#
# {
# "success": True,
# "result": {
# "id": "ashb1212",
# "product_id": 27,
# "limit_price": "9200",
# "side": "buy",
# "size": 100,
# "unfilled_size": 50,
# "user_id": 1,
# "order_type": "limit_order",
# "state": "open",
# "created_at": "..."
# }
# }
#
result = self.safe_dict(response, 'result')
return self.parse_order(result, market)
def cancel_order(self, id: str, symbol: Str = None, params={}):
"""
cancels an open order
https://docs.delta.exchange/#cancel-order
:param str id: order id
:param str symbol: unified symbol of the market the order was made in
:param dict [params]: extra parameters specific to the exchange API endpoint
:returns dict: An `order structure <https://docs.ccxt.com/#/?id=order-structure>`
"""
if symbol is None:
raise ArgumentsRequired(self.id + ' cancelOrder() requires a symbol argument')
self.load_markets()
market = self.market(symbol)
request: dict = {
'id': int(id),
'product_id': market['numericId'],
}
response = self.privateDeleteOrders(self.extend(request, params))
#
# {
# "result":{
# "average_fill_price":null,
# "bracket_order":null,
# "bracket_stop_loss_limit_price":null,
# "bracket_stop_loss_price":null,
# "bracket_take_profit_limit_price":null,
# "bracket_take_profit_price":null,
# "bracket_trail_amount":null,
# "cancellation_reason":"cancelled_by_user",
# "client_order_id":null,
# "close_on_trigger":"false",
# "commission":"0",
# "created_at":"2020-11-16T02:38:26Z",
# "id":152870626,
# "limit_price":"10000",
# "meta_data":{"source":"api"},
# "order_type":"limit_order",
# "paid_commission":"0",
# "product_id":139,
# "reduce_only":false,
# "side":"buy",
# "size":0,
# "state":"cancelled",
# "stop_order_type":null,
# "stop_price":null,
# "stop_trigger_method":"mark_price",
# "time_in_force":"gtc",
# "trail_amount":null,
# "unfilled_size":0,
# "user_id":22142
# },
# "success":true
# }
#
result = self.safe_dict(response, 'result')
return self.parse_order(result, market)
def cancel_all_orders(self, symbol: Str = None, params={}):
"""
cancel all open orders in a market
https://docs.delta.exchange/#cancel-all-open-orders
:param str symbol: unified market symbol of the market to cancel orders in
:param dict [params]: extra parameters specific to the exchange API endpoint
:returns dict[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
"""
if symbol is None:
raise ArgumentsRequired(self.id + ' cancelAllOrders() requires a symbol argument')
self.load_markets()
market = self.market(symbol)
request: dict = {
'product_id': market['numericId'],
# 'cancel_limit_orders': 'true',
# 'cancel_stop_orders': 'true',
}
response = self.privateDeleteOrdersAll(self.extend(request, params))
#
# {
# "result":{},
# "success":true
# }
#
return [
self.safe_order({
'info': response,
}),
]
def fetch_order(self, id: str, symbol: Str = None, params={}) -> Order:
"""
fetches information on an order made by the user
https://docs.delta.exchange/#get-order-by-id
https://docs.delta.exchange/#get-order-by-client-oid
:param str id: the order id
:param str [symbol]: unified symbol of the market the order was made in
:param dict [params]: extra parameters specific to the exchange API endpoint
:param str [params.clientOrderId]: client order id of the order
:returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
"""
self.load_markets()
market = None
if symbol is not None:
market = self.market(symbol)
clientOrderId = self.safe_string_n(params, ['clientOrderId', 'client_oid', 'clientOid'])
params = self.omit(params, ['clientOrderId', 'client_oid', 'clientOid'])
request: dict = {}
response = None
if clientOrderId is not None:
request['client_oid'] = clientOrderId
response = self.privateGetOrdersClientOrderIdClientOid(self.extend(request, params))
else:
request['order_id'] = id
response = self.privateGetOrdersOrderId(self.extend(request, params))
#
# {
# "success": True,
# "result": {
# "id": 123,
# "user_id": 453671,
# "size": 10,
# "unfilled_size": 2,
# "side": "buy",
# "order_type": "limit_order",
# "limit_price": "59000",
# "stop_order_type": "stop_loss_order",
# "stop_price": "55000",
# "paid_commission": "0.5432",
# "commission": "0.5432",
# "reduce_only": False,
# "client_order_id": "my_signal_34521712",
# "state": "open",
# "created_at": "1725865012000000",
# "product_id": 27,
# "product_symbol": "BTCUSD"
# }
# }
#
result = self.safe_dict(response, 'result', {})
return self.parse_order(result, market)
def fetch_open_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
"""
fetch all unfilled currently open orders
https://docs.delta.exchange/#get-active-orders
:param str symbol: unified market symbol
:param int [since]: the earliest time in ms to fetch open orders for
:param int [limit]: the maximum number of open order structures to retrieve
:param dict [params]: extra parameters specific to the exchange API endpoint
:returns Order[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
"""
return self.fetch_orders_with_method('privateGetOrders', symbol, since, limit, params)
def fetch_closed_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
"""
fetches information on multiple closed orders made by the user
https://docs.delta.exchange/#get-order-history-cancelled-and-closed
:param str symbol: unified market symbol of the market orders were made in
:param int [since]: the earliest time in ms to fetch orders for
:param int [limit]: the maximum number of order structures to retrieve
:param dict [params]: extra parameters specific to the exchange API endpoint
:returns Order[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
"""
return self.fetch_orders_with_method('privateGetOrdersHistory', symbol, since, limit, params)
def fetch_orders_with_method(self, method, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
self.load_markets()
request: dict = {
# 'product_ids': market['id'], # comma-separated
# 'contract_types': types, # comma-separated, futures, perpetual_futures, call_options, put_options, interest_rate_swaps, move_options, spreads
# 'order_types': types, # comma-separated, market, limit, stop_market, stop_limit, all_stop
# 'start_time': since * 1000,
# 'end_time': self.microseconds(),
# 'after', # after cursor for pagination
# 'before', # before cursor for pagination
# 'page_size': limit, # number of records per page
}
market = None
if symbol is not None:
market = self.market(symbol)
request['product_ids'] = market['numericId'] # accepts a comma-separated list of ids
if since is not None:
request['start_time'] = str(since) + '000'
if limit is not None:
request['page_size'] = limit
response = None
if method == 'privateGetOrders':
response = self.privateGetOrders(self.extend(request, params))
elif method == 'privateGetOrdersHistory':
response = self.privateGetOrdersHistory(self.extend(request, params))
#
# {
# "success": True,
# "result": [
# {
# "id": "ashb1212",
# "product_id": 27,
# "limit_price": "9200",
# "side": "buy",
# "size": 100,
# "unfilled_size": 50,
# "user_id": 1,
# "order_type": "limit_order",
# "state": "open",
# "created_at": "..."
# }
# ],
# "meta": {
# "after": "string",
# "before": "string"
# }
# }
#
result = self.safe_list(response, 'result', [])
return self.parse_orders(result, market, since, limit)
def fetch_my_trades(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
"""
fetch all trades made by the user
https://docs.delta.exchange/#get-user-fills-by-filters
:param str symbol: unified market symbol
:param int [since]: the earliest time in ms to fetch trades for
:param int [limit]: the maximum number of trades structures to retrieve
:param dict [params]: extra parameters specific to the exchange API endpoint
:returns Trade[]: a list of `trade structures <https://docs.ccxt.com/#/?id=trade-structure>`
"""
self.load_markets()
request: dict = {
# 'product_ids': market['id'], # comma-separated
# 'contract_types': types, # comma-separated, futures, perpetual_futures, call_options, put_options, interest_rate_swaps, move_options, spreads
# 'start_time': since * 1000,
# 'end_time': self.microseconds(),
# 'after', # after cursor for pagination
# 'before', # before cursor for pagination
# 'page_size': limit, # number of records per page
}
market = None
if symbol is not None:
market = self.market(symbol)
request['product_ids'] = market['numericId'] # accepts a comma-separated list of ids
if since is not None:
request['start_time'] = str(since) + '000'
if limit is not None:
request['page_size'] = limit
response = self.privateGetFills(self.extend(request, params))
#
# {
# "meta":{
# "after":null,
# "before":null,
# "limit":10,
# "total_count":2
# },
# "result":[
# {
# "commission":"0.008335000000000000",
# "created_at":"2020-11-16T19:07:19Z",
# "fill_type":"normal",
# "id":"e7ff05c233a74245b72381f8dd91d1ce",
# "meta_data":{
# "effective_commission_rate":"0.0005",
# "order_price":"16249",
# "order_size":1,
# "order_type":"market_order",
# "order_unfilled_size":0,
# "trading_fee_credits_used":"0"
# },
# "order_id":"152999629",
# "price":"16669",
# "product":{
# "contract_type":"perpetual_futures",
# "contract_unit_currency":"BTC",
# "contract_value":"0.001",
# "id":139,
# "notional_type":"vanilla",
# "quoting_asset":{"minimum_precision":2,"precision":6,"symbol":"USDT"},
# "settling_asset":{"minimum_precision":2,"precision":6,"symbol":"USDT"},
# "symbol":"BTCUSDT",
# "tick_size":"0.5",
# "underlying_asset":{"minimum_precision":4,"precision":8,"symbol":"BTC"}
# },
# "product_id":139,
# "role":"taker",
# "side":"sell",
# "size":1
# }
# ],
# "success":true
# }
#
result = self.safe_list(response, 'result', [])
return self.parse_trades(result, market, since, limit)
def fetch_ledger(self, code: Str = None, since: Int = None, limit: Int = None, params={}) -> List[LedgerEntry]:
"""
fetch the history of changes, actions done by the user or operations that altered the balance of the user
https://docs.delta.exchange/#get-wallet-transactions
:param str [code]: unified currency code, default is None
:param int [since]: timestamp in ms of the earliest ledger entry, default is None
:param int [limit]: max number of ledger entries to return, default is None
:param dict [params]: extra parameters specific to the exchange API endpoint
:returns dict: a `ledger structure <https://docs.ccxt.com/#/?id=ledger>`
"""
self.load_markets()
request: dict = {
# 'asset_id': currency['numericId'],
# 'end_time': self.seconds(),
# 'after': 'string', # after cursor for pagination
# 'before': 'string', # before cursor for pagination
# 'page_size': limit,
}
currency = None
if code is not None:
currency = self.currency(code)
request['asset_id'] = currency['numericId']
if limit is not None:
request['page_size'] = limit
response = self.privateGetWalletTransactions(self.extend(request, params))
#
# {
# "meta":{"after":null,"before":null,"limit":10,"total_count":1},
# "result":[
# {
# "amount":"29.889184",
# "asset_id":5,
# "balance":"29.889184",
# "created_at":"2020-11-15T21:25:01Z",
# "meta_data":{
# "deposit_id":3884,
# "transaction_id":"0x41a60174849828530abb5008e98fc63c9b598288743ec4ba9620bcce900a3b8d"
# },
# "transaction_type":"deposit",
# "user_id":22142,
# "uuid":"70bb5679da3c4637884e2dc63efaa846"
# }
# ],
# "success":true
# }
#
result = self.safe_list(response, 'result', [])
return self.parse_ledger(result, currency, since, limit)
def parse_ledger_entry_type(self, type):
types: dict = {
'pnl': 'pnl',
'deposit': 'transaction',
'withdrawal': 'transaction',
'commission': 'fee',
'conversion': 'trade',
# 'perpetual_futures_funding': 'perpetual_futures_funding',
# 'withdrawal_cancellation': 'withdrawal_cancellation',
'referral_bonus': 'referral',
'commission_rebate': 'rebate',
# 'promo_credit': 'promo_credit',
}
return self.safe_string(types, type, type)
def parse_ledger_entry(self, item: dict, currency: Currency = None) -> LedgerEntry:
#
# {
# "amount":"29.889184",
# "asset_id":5,
# "balance":"29.889184",
# "created_at":"2020-11-15T21:25:01Z",
# "meta_data":{
# "deposit_id":3884,
# "transaction_id":"0x41a60174849828530abb5008e98fc63c9b598288743ec4ba9620bcce900a3b8d"
# },
# "transaction_type":"deposit",
# "user_id":22142,
# "uuid":"70bb5679da3c4637884e2dc63efaa846"
# }
#
id = self.safe_string(item, 'uuid')
direction = None
account = None
metaData = self.safe_dict(item, 'meta_data', {})
referenceId = self.safe_string(metaData, 'transaction_id')
referenceAccount = None
type = self.safe_string(item, 'transaction_type')
if (type == 'deposit') or (type == 'commission_rebate') or (type == 'referral_bonus') or (type == 'pnl') or (type == 'withdrawal_cancellation') or (type == 'promo_credit'):
direction = 'in'
elif (type == 'withdrawal') or (type == 'commission') or (type == 'conversion') or (type == 'perpetual_futures_funding'):
direction = 'out'
type = self.parse_ledger_entry_type(type)
currencyId = self.safe_string(item, 'asset_id')
currenciesByNumericId = self.safe_dict(self.options, 'currenciesByNumericId')
currency = self.safe_value(currenciesByNumericId, currencyId, currency)
code = None if (currency is None) else currency['code']
amount = self.safe_string(item, 'amount')
timestamp = self.parse8601(self.safe_string(item, 'created_at'))
after = self.safe_string(item, 'balance')
before = Precise.string_max('0', Precise.string_sub(after, amount))
status = 'ok'
return self.safe_ledger_entry({
'info': item,
'id': id,
'direction': direction,
'account': account,
'referenceId': referenceId,
'referenceAccount': referenceAccount,
'type': type,
'currency': code,
'amount': self.parse_number(amount),
'before': self.parse_number(before),
'after': self.parse_number(after),
'status': status,
'timestamp': timestamp,
'datetime': self.iso8601(timestamp),
'fee': None,
}, currency)
def fetch_deposit_address(self, code: str, params={}) -> DepositAddress:
"""
fetch the deposit address for a currency associated with self account
:param str code: unified currency code
:param dict [params]: extra parameters specific to the exchange API endpoint
:param str [params.network]: unified network code
:returns dict: an `address structure <https://docs.ccxt.com/#/?id=address-structure>`
"""
self.load_markets()
currency = self.currency(code)
request: dict = {
'asset_symbol': currency['id'],
}
networkCode = self.safe_string_upper(params, 'network')
if networkCode is not None:
request['network'] = self.network_code_to_id(networkCode, code)
params = self.omit(params, 'network')
response = self.privateGetDepositsAddress(self.extend(request, params))
#
# {
# "success": True,
# "result": {
# "id": 1915615,
# "user_id": 27854758,
# "address": "TXYB4GdKsXKEWbeSNPsmGZu4ZVCkhVh1Zz",
# "memo": "",
# "status": "active",
# "updated_at": "2023-01-12T06:03:46.000Z",
# "created_at": "2023-01-12T06:03:46.000Z",
# "asset_symbol": "USDT",
# "network": "TRC20(TRON)",
# "custodian": "fireblocks"
# }
# }
#
result = self.safe_dict(response, 'result', {})
return self.parse_deposit_address(result, currency)
def parse_deposit_address(self, depositAddress, currency: Currency = None) -> DepositAddress:
#
# {
# "id": 1915615,
# "user_id": 27854758,
# "address": "TXYB4GdKsXKEWbeSNPsmGZu4ZVCkhVh1Zz",
# "memo": "",
# "status": "active",
# "updated_at": "2023-01-12T06:03:46.000Z",
# "created_at": "2023-01-12T06:03:46.000Z",
# "asset_symbol": "USDT",
# "network": "TRC20(TRON)",
# "custodian": "fireblocks"
# }
#
address = self.safe_string(depositAddress, 'address')
marketId = self.safe_string(depositAddress, 'asset_symbol')
networkId = self.safe_string(depositAddress, 'network')
self.check_address(address)
return {
'info': depositAddress,
'currency': self.safe_currency_code(marketId, currency),
'network': self.network_id_to_code(networkId),
'address': address,
'tag': self.safe_string(depositAddress, 'memo'),
}
def fetch_funding_rate(self, symbol: str, params={}) -> FundingRate:
"""
fetch the current funding rate
https://docs.delta.exchange/#get-ticker-for-a-product-by-symbol
:param str symbol: unified market symbol
:param dict [params]: extra parameters specific to the exchange API endpoint
:returns dict: a `funding rate structure <https://docs.ccxt.com/#/?id=funding-rate-structure>`
"""
self.load_markets()
market = self.market(symbol)
if not market['swap']:
raise BadSymbol(self.id + ' fetchFundingRate() supports swap contracts only')
request: dict = {
'symbol': market['id'],
}
response = self.publicGetTickersSymbol(self.extend(request, params))
#
# {
# "result": {
# "close": 30600.5,
# "contract_type": "perpetual_futures",
# "funding_rate": "0.00602961",
# "greeks": null,
# "high": 30803.0,
# "low": 30265.5,
# "mark_basis": "-0.45601594",
# "mark_price": "30600.10481568",
# "oi": "469.9190",
# "oi_change_usd_6h": "2226314.9900",
# "oi_contracts": "469919",
# "oi_value": "469.9190",
# "oi_value_symbol": "BTC",
# "oi_value_usd": "14385640.6802",
# "open": 30458.5,
# "price_band": {
# "lower_limit": "29067.08312627",
# "upper_limit": "32126.77608693"
# },
# "product_id": 139,
# "quotes": {
# "ask_iv": null,
# "ask_size": "965",
# "best_ask": "30600.5",
# "best_bid": "30599.5",
# "bid_iv": null,
# "bid_size": "196",
# "impact_mid_price": null,
# "mark_iv": "-0.44931641"
# },
# "size": 1226303,
# "spot_price": "30612.85362773",
# "symbol": "BTCUSDT",
# "timestamp": 1689136597460456,
# "turnover": 37392218.45999999,
# "turnover_symbol": "USDT",
# "turnover_usd": 37392218.45999999,
# "volume": 1226.3029999999485
# },
# "success": True
# }
#
result = self.safe_dict(response, 'result', {})
return self.parse_funding_rate(result, market)
def fetch_funding_rates(self, symbols: Strings = None, params={}) -> FundingRates:
"""
fetch the funding rate for multiple markets
https://docs.delta.exchange/#get-tickers-for-products
:param str[]|None symbols: list of unified market symbols
:param dict [params]: extra parameters specific to the exchange API endpoint
:returns dict[]: a list of `funding rate structures <https://docs.ccxt.com/#/?id=funding-rates-structure>`, indexed by market symbols
"""
self.load_markets()
symbols = self.market_symbols(symbols)
request: dict = {
'contract_types': 'perpetual_futures',
}
response = self.publicGetTickers(self.extend(request, params))
#
# {
# "result": [
# {
# "close": 30600.5,
# "contract_type": "perpetual_futures",
# "funding_rate": "0.00602961",
# "greeks": null,
# "high": 30803.0,
# "low": 30265.5,
# "mark_basis": "-0.45601594",
# "mark_price": "30600.10481568",
# "oi": "469.9190",
# "oi_change_usd_6h": "2226314.9900",
# "oi_contracts": "469919",
# "oi_value": "469.9190",
# "oi_value_symbol": "BTC",
# "oi_value_usd": "14385640.6802",
# "open": 30458.5,
# "price_band": {
# "lower_limit": "29067.08312627",
# "upper_limit": "32126.77608693"
# },
# "product_id": 139,
# "quotes": {
# "ask_iv": null,
# "ask_size": "965",
# "best_ask": "30600.5",
# "best_bid": "30599.5",
# "bid_iv": null,
# "bid_size": "196",
# "impact_mid_price": null,
# "mark_iv": "-0.44931641"
# },
# "size": 1226303,
# "spot_price": "30612.85362773",
# "symbol": "BTCUSDT",
# "timestamp": 1689136597460456,
# "turnover": 37392218.45999999,
# "turnover_symbol": "USDT",
# "turnover_usd": 37392218.45999999,
# "volume": 1226.3029999999485
# },
# ],
# "success":true
# }
#
rates = self.safe_list(response, 'result', [])
return self.parse_funding_rates(rates, symbols)
def parse_funding_rate(self, contract, market: Market = None) -> FundingRate:
#
# {
# "close": 30600.5,
# "contract_type": "perpetual_futures",
# "funding_rate": "0.00602961",
# "greeks": null,
# "high": 30803.0,
# "low": 30265.5,
# "mark_basis": "-0.45601594",
# "mark_price": "30600.10481568",
# "oi": "469.9190",
# "oi_change_usd_6h": "2226314.9900",
# "oi_contracts": "469919",
# "oi_value": "469.9190",
# "oi_value_symbol": "BTC",
# "oi_value_usd": "14385640.6802",
# "open": 30458.5,
# "price_band": {
# "lower_limit": "29067.08312627",
# "upper_limit": "32126.77608693"
# },
# "product_id": 139,
# "quotes": {
# "ask_iv": null,
# "ask_size": "965",
# "best_ask": "30600.5",
# "best_bid": "30599.5",
# "bid_iv": null,
# "bid_size": "196",
# "impact_mid_price": null,
# "mark_iv": "-0.44931641"
# },
# "size": 1226303,
# "spot_price": "30612.85362773",
# "symbol": "BTCUSDT",
# "timestamp": 1689136597460456,
# "turnover": 37392218.45999999,
# "turnover_symbol": "USDT",
# "turnover_usd": 37392218.45999999,
# "volume": 1226.3029999999485
# }
#
timestamp = self.safe_integer_product(contract, 'timestamp', 0.001)
marketId = self.safe_string(contract, 'symbol')
fundingRateString = self.safe_string(contract, 'funding_rate')
fundingRate = Precise.string_div(fundingRateString, '100')
return {
'info': contract,
'symbol': self.safe_symbol(marketId, market),
'markPrice': self.safe_number(contract, 'mark_price'),
'indexPrice': self.safe_number(contract, 'spot_price'),
'interestRate': None,
'estimatedSettlePrice': None,
'timestamp': timestamp,
'datetime': self.iso8601(timestamp),
'fundingRate': self.parse_number(fundingRate),
'fundingTimestamp': None,
'fundingDatetime': None,
'nextFundingRate': None,
'nextFundingTimestamp': None,
'nextFundingDatetime': None,
'previousFundingRate': None,
'previousFundingTimestamp': None,
'previousFundingDatetime': None,
'interval': None,
}
def add_margin(self, symbol: str, amount: float, params={}) -> MarginModification:
"""
add margin
https://docs.delta.exchange/#add-remove-position-margin
:param str symbol: unified market symbol
:param float amount: amount of margin to add
:param dict [params]: extra parameters specific to the exchange API endpoint
:returns dict: a `margin structure <https://docs.ccxt.com/#/?id=add-margin-structure>`
"""
return self.modify_margin_helper(symbol, amount, 'add', params)
def reduce_margin(self, symbol: str, amount: float, params={}) -> MarginModification:
"""
remove margin from a position
https://docs.delta.exchange/#add-remove-position-margin
:param str symbol: unified market symbol
:param float amount: the amount of margin to remove
:param dict [params]: extra parameters specific to the exchange API endpoint
:returns dict: a `margin structure <https://docs.ccxt.com/#/?id=reduce-margin-structure>`
"""
return self.modify_margin_helper(symbol, amount, 'reduce', params)
def modify_margin_helper(self, symbol: str, amount, type, params={}) -> MarginModification:
self.load_markets()
market = self.market(symbol)
amount = str(amount)
if type == 'reduce':
amount = Precise.string_mul(amount, '-1')
request: dict = {
'product_id': market['numericId'],
'delta_margin': amount,
}
response = self.privatePostPositionsChangeMargin(self.extend(request, params))
#
# {
# "result": {
# "auto_topup": False,
# "bankruptcy_price": "24934.12",
# "commission": "0.01197072",
# "created_at": "2023-07-20T03:49:09.159401Z",
# "entry_price": "29926.8",
# "liquidation_price": "25083.754",
# "margin": "4.99268",
# "margin_mode": "isolated",
# "product_id": 84,
# "product_symbol": "BTCUSDT",
# "realized_cashflow": "0",
# "realized_funding": "0",
# "realized_pnl": "0",
# "size": 1,
# "updated_at": "2023-07-20T03:49:09.159401Z",
# "user_id": 30084879
# },
# "success": True
# }
#
result = self.safe_dict(response, 'result', {})
return self.parse_margin_modification(result, market)
def parse_margin_modification(self, data: dict, market: Market = None) -> MarginModification:
#
# {
# "auto_topup": False,
# "bankruptcy_price": "24934.12",
# "commission": "0.01197072",
# "created_at": "2023-07-20T03:49:09.159401Z",
# "entry_price": "29926.8",
# "liquidation_price": "25083.754",
# "margin": "4.99268",
# "margin_mode": "isolated",
# "product_id": 84,
# "product_symbol": "BTCUSDT",
# "realized_cashflow": "0",
# "realized_funding": "0",
# "realized_pnl": "0",
# "size": 1,
# "updated_at": "2023-07-20T03:49:09.159401Z",
# "user_id": 30084879
# }
#
marketId = self.safe_string(data, 'product_symbol')
market = self.safe_market(marketId, market)
return {
'info': data,
'symbol': market['symbol'],
'type': None,
'marginMode': 'isolated',
'amount': None,
'total': self.safe_number(data, 'margin'),
'code': None,
'status': None,
'timestamp': None,
'datetime': None,
}
def fetch_open_interest(self, symbol: str, params={}):
"""
retrieves the open interest of a derivative market
https://docs.delta.exchange/#get-ticker-for-a-product-by-symbol
:param str symbol: unified market symbol
:param dict [params]: exchange specific parameters
:returns dict} an open interest structure{@link https://docs.ccxt.com/#/?id=open-interest-structure:
"""
self.load_markets()
market = self.market(symbol)
if not market['contract']:
raise BadRequest(self.id + ' fetchOpenInterest() supports contract markets only')
request: dict = {
'symbol': market['id'],
}
response = self.publicGetTickersSymbol(self.extend(request, params))
#
# {
# "result": {
# "close": 894.0,
# "contract_type": "call_options",
# "greeks": {
# "delta": "0.67324861",
# "gamma": "0.00022178",
# "rho": "4.34638266",
# "spot": "30178.53195697",
# "theta": "-35.64972577",
# "vega": "16.34381277"
# },
# "high": 946.0,
# "low": 893.0,
# "mark_price": "1037.07582681",
# "mark_vol": "0.35899491",
# "oi": "0.0910",
# "oi_change_usd_6h": "-90.5500",
# "oi_contracts": "91",
# "oi_value": "0.0910",
# "oi_value_symbol": "BTC",
# "oi_value_usd": "2746.3549",
# "open": 946.0,
# "price_band": {
# "lower_limit": "133.37794509",
# "upper_limit": "5663.66930164"
# },
# "product_id": 116171,
# "quotes": {
# "ask_iv": "0.36932389",
# "ask_size": "1321",
# "best_ask": "1054",
# "best_bid": "1020",
# "bid_iv": "0.34851914",
# "bid_size": "2202",
# "impact_mid_price": null,
# "mark_iv": "0.35896335"
# },
# "size": 152,
# "spot_price": "30178.53195697",
# "strike_price": "29500",
# "symbol": "C-BTC-29500-280723",
# "timestamp": 1689834695286094,
# "turnover": 4546.601744940001,
# "turnover_symbol": "USDT",
# "turnover_usd": 4546.601744940001,
# "volume": 0.15200000000000002
# },
# "success": True
# }
#
result = self.safe_dict(response, 'result', {})
return self.parse_open_interest(result, market)
def parse_open_interest(self, interest, market: Market = None):
#
# {
# "close": 894.0,
# "contract_type": "call_options",
# "greeks": {
# "delta": "0.67324861",
# "gamma": "0.00022178",
# "rho": "4.34638266",
# "spot": "30178.53195697",
# "theta": "-35.64972577",
# "vega": "16.34381277"
# },
# "high": 946.0,
# "low": 893.0,
# "mark_price": "1037.07582681",
# "mark_vol": "0.35899491",
# "oi": "0.0910",
# "oi_change_usd_6h": "-90.5500",
# "oi_contracts": "91",
# "oi_value": "0.0910",
# "oi_value_symbol": "BTC",
# "oi_value_usd": "2746.3549",
# "open": 946.0,
# "price_band": {
# "lower_limit": "133.37794509",
# "upper_limit": "5663.66930164"
# },
# "product_id": 116171,
# "quotes": {
# "ask_iv": "0.36932389",
# "ask_size": "1321",
# "best_ask": "1054",
# "best_bid": "1020",
# "bid_iv": "0.34851914",
# "bid_size": "2202",
# "impact_mid_price": null,
# "mark_iv": "0.35896335"
# },
# "size": 152,
# "spot_price": "30178.53195697",
# "strike_price": "29500",
# "symbol": "C-BTC-29500-280723",
# "timestamp": 1689834695286094,
# "turnover": 4546.601744940001,
# "turnover_symbol": "USDT",
# "turnover_usd": 4546.601744940001,
# "volume": 0.15200000000000002
# }
#
timestamp = self.safe_integer_product(interest, 'timestamp', 0.001)
marketId = self.safe_string(interest, 'symbol')
return self.safe_open_interest({
'symbol': self.safe_symbol(marketId, market),
'baseVolume': self.safe_number(interest, 'oi_value'),
'quoteVolume': self.safe_number(interest, 'oi_value_usd'),
'openInterestAmount': self.safe_number(interest, 'oi_contracts'),
'openInterestValue': self.safe_number(interest, 'oi'),
'timestamp': timestamp,
'datetime': self.iso8601(timestamp),
'info': interest,
}, market)
def fetch_leverage(self, symbol: str, params={}) -> Leverage:
"""
fetch the set leverage for a market
https://docs.delta.exchange/#get-order-leverage
:param str symbol: unified market symbol
:param dict [params]: extra parameters specific to the exchange API endpoint
:returns dict: a `leverage structure <https://docs.ccxt.com/#/?id=leverage-structure>`
"""
self.load_markets()
market = self.market(symbol)
request: dict = {
'product_id': market['numericId'],
}
response = self.privateGetProductsProductIdOrdersLeverage(self.extend(request, params))
#
# {
# "result": {
# "index_symbol": null,
# "leverage": "10",
# "margin_mode": "isolated",
# "order_margin": "0",
# "product_id": 84,
# "user_id": 30084879
# },
# "success": True
# }
#
result = self.safe_dict(response, 'result', {})
return self.parse_leverage(result, market)
def parse_leverage(self, leverage: dict, market: Market = None) -> Leverage:
marketId = self.safe_string(leverage, 'index_symbol')
leverageValue = self.safe_integer(leverage, 'leverage')
return {
'info': leverage,
'symbol': self.safe_symbol(marketId, market),
'marginMode': self.safe_string_lower(leverage, 'margin_mode'),
'longLeverage': leverageValue,
'shortLeverage': leverageValue,
}
def set_leverage(self, leverage: int, symbol: Str = None, params={}):
"""
set the level of leverage for a market
https://docs.delta.exchange/#change-order-leverage
:param float leverage: the rate of leverage
:param str symbol: unified market symbol
:param dict [params]: extra parameters specific to the exchange API endpoint
:returns dict: response from the exchange
"""
if symbol is None:
raise ArgumentsRequired(self.id + ' setLeverage() requires a symbol argument')
self.load_markets()
market = self.market(symbol)
request: dict = {
'product_id': market['numericId'],
'leverage': leverage,
}
#
# {
# "result": {
# "leverage": "20",
# "margin_mode": "isolated",
# "order_margin": "0",
# "product_id": 84
# },
# "success": True
# }
#
return self.privatePostProductsProductIdOrdersLeverage(self.extend(request, params))
def fetch_settlement_history(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
"""
fetches historical settlement records
https://docs.delta.exchange/#get-product-settlement-prices
:param str symbol: unified market symbol of the settlement history
:param int [since]: timestamp in ms
:param int [limit]: number of records
:param dict [params]: exchange specific params
:returns dict[]: a list of `settlement history objects <https://docs.ccxt.com/#/?id=settlement-history-structure>`
"""
self.load_markets()
market = None
if symbol is not None:
market = self.market(symbol)
request: dict = {
'states': 'expired',
}
if limit is not None:
request['page_size'] = limit
response = self.publicGetProducts(self.extend(request, params))
#
# {
# "result": [
# {
# "contract_value": "0.001",
# "basis_factor_max_limit": "10.95",
# "maker_commission_rate": "0.0003",
# "launch_time": "2023-07-19T04:30:03Z",
# "trading_status": "operational",
# "product_specs": {
# "backup_vol_expiry_time": 31536000,
# "max_deviation_from_external_vol": 0.75,
# "max_lower_deviation_from_external_vol": 0.75,
# "max_upper_deviation_from_external_vol": 0.5,
# "max_volatility": 3,
# "min_volatility": 0.1,
# "premium_commission_rate": 0.1,
# "settlement_index_price": "29993.536675710806",
# "vol_calculation_method": "orderbook",
# "vol_expiry_time": 31536000
# },
# "description": "BTC call option expiring on 19-7-2023",
# "settlement_price": "0",
# "disruption_reason": null,
# "settling_asset": {},
# "initial_margin": "1",
# "tick_size": "0.1",
# "maintenance_margin": "0.5",
# "id": 117542,
# "notional_type": "vanilla",
# "ui_config": {},
# "contract_unit_currency": "BTC",
# "symbol": "C-BTC-30900-190723",
# "insurance_fund_margin_contribution": "1",
# "price_band": "2",
# "annualized_funding": "10.95",
# "impact_size": 200,
# "contract_type": "call_options",
# "position_size_limit": 255633,
# "max_leverage_notional": "200000",
# "initial_margin_scaling_factor": "0.000002",
# "strike_price": "30900",
# "is_quanto": False,
# "settlement_time": "2023-07-19T12:00:00Z",
# "liquidation_penalty_factor": "0.5",
# "funding_method": "mark_price",
# "taker_commission_rate": "0.0003",
# "default_leverage": "100.000000000000000000",
# "state": "expired",
# "auction_start_time": null,
# "short_description": "BTC Call",
# "quoting_asset": {},
# "maintenance_margin_scaling_factor":"0.000002"
# }
# ],
# "success": True
# }
#
result = self.safe_list(response, 'result', [])
settlements = self.parse_settlements(result, market)
sorted = self.sort_by(settlements, 'timestamp')
return self.filter_by_symbol_since_limit(sorted, market['symbol'], since, limit)
def parse_settlement(self, settlement, market):
#
# {
# "contract_value": "0.001",
# "basis_factor_max_limit": "10.95",
# "maker_commission_rate": "0.0003",
# "launch_time": "2023-07-19T04:30:03Z",
# "trading_status": "operational",
# "product_specs": {
# "backup_vol_expiry_time": 31536000,
# "max_deviation_from_external_vol": 0.75,
# "max_lower_deviation_from_external_vol": 0.75,
# "max_upper_deviation_from_external_vol": 0.5,
# "max_volatility": 3,
# "min_volatility": 0.1,
# "premium_commission_rate": 0.1,
# "settlement_index_price": "29993.536675710806",
# "vol_calculation_method": "orderbook",
# "vol_expiry_time": 31536000
# },
# "description": "BTC call option expiring on 19-7-2023",
# "settlement_price": "0",
# "disruption_reason": null,
# "settling_asset": {},
# "initial_margin": "1",
# "tick_size": "0.1",
# "maintenance_margin": "0.5",
# "id": 117542,
# "notional_type": "vanilla",
# "ui_config": {},
# "contract_unit_currency": "BTC",
# "symbol": "C-BTC-30900-190723",
# "insurance_fund_margin_contribution": "1",
# "price_band": "2",
# "annualized_funding": "10.95",
# "impact_size": 200,
# "contract_type": "call_options",
# "position_size_limit": 255633,
# "max_leverage_notional": "200000",
# "initial_margin_scaling_factor": "0.000002",
# "strike_price": "30900",
# "is_quanto": False,
# "settlement_time": "2023-07-19T12:00:00Z",
# "liquidation_penalty_factor": "0.5",
# "funding_method": "mark_price",
# "taker_commission_rate": "0.0003",
# "default_leverage": "100.000000000000000000",
# "state": "expired",
# "auction_start_time": null,
# "short_description": "BTC Call",
# "quoting_asset": {},
# "maintenance_margin_scaling_factor":"0.000002"
# }
#
datetime = self.safe_string(settlement, 'settlement_time')
marketId = self.safe_string(settlement, 'symbol')
return {
'info': settlement,
'symbol': self.safe_symbol(marketId, market),
'price': self.safe_number(settlement, 'settlement_price'),
'timestamp': self.parse8601(datetime),
'datetime': datetime,
}
def parse_settlements(self, settlements, market):
result = []
for i in range(0, len(settlements)):
result.append(self.parse_settlement(settlements[i], market))
return result
def fetch_greeks(self, symbol: str, params={}) -> Greeks:
"""
fetches an option contracts greeks, financial metrics used to measure the factors that affect the price of an options contract
https://docs.delta.exchange/#get-ticker-for-a-product-by-symbol
:param str symbol: unified symbol of the market to fetch greeks for
:param dict [params]: extra parameters specific to the exchange API endpoint
:returns dict: a `greeks structure <https://docs.ccxt.com/#/?id=greeks-structure>`
"""
self.load_markets()
market = self.market(symbol)
request: dict = {
'symbol': market['id'],
}
response = self.publicGetTickersSymbol(self.extend(request, params))
#
# {
# "result": {
# "close": 6793.0,
# "contract_type": "call_options",
# "greeks": {
# "delta": "0.94739174",
# "gamma": "0.00002206",
# "rho": "11.00890725",
# "spot": "36839.58124652",
# "theta": "-18.18365310",
# "vega": "7.85209698"
# },
# "high": 7556.0,
# "low": 6793.0,
# "mark_price": "6955.70698909",
# "mark_vol": "0.66916863",
# "oi": "1.8980",
# "oi_change_usd_6h": "110.4600",
# "oi_contracts": "1898",
# "oi_value": "1.8980",
# "oi_value_symbol": "BTC",
# "oi_value_usd": "69940.7319",
# "open": 7.2e3,
# "price_band": {
# "lower_limit": "5533.89814767",
# "upper_limit": "11691.37688371"
# },
# "product_id": 129508,
# "quotes": {
# "ask_iv": "0.90180438",
# "ask_size": "1898",
# "best_ask": "7210",
# "best_bid": "6913",
# "bid_iv": "0.60881706",
# "bid_size": "3163",
# "impact_mid_price": null,
# "mark_iv": "0.66973549"
# },
# "size": 5,
# "spot_price": "36839.58153868",
# "strike_price": "30000",
# "symbol": "C-BTC-30000-241123",
# "timestamp": 1699584998504530,
# "turnover": 184.41206804,
# "turnover_symbol": "USDT",
# "turnover_usd": 184.41206804,
# "volume": 0.005
# },
# "success": True
# }
#
result = self.safe_dict(response, 'result', {})
return self.parse_greeks(result, market)
def parse_greeks(self, greeks: dict, market: Market = None) -> Greeks:
#
# {
# "close": 6793.0,
# "contract_type": "call_options",
# "greeks": {
# "delta": "0.94739174",
# "gamma": "0.00002206",
# "rho": "11.00890725",
# "spot": "36839.58124652",
# "theta": "-18.18365310",
# "vega": "7.85209698"
# },
# "high": 7556.0,
# "low": 6793.0,
# "mark_price": "6955.70698909",
# "mark_vol": "0.66916863",
# "oi": "1.8980",
# "oi_change_usd_6h": "110.4600",
# "oi_contracts": "1898",
# "oi_value": "1.8980",
# "oi_value_symbol": "BTC",
# "oi_value_usd": "69940.7319",
# "open": 7.2e3,
# "price_band": {
# "lower_limit": "5533.89814767",
# "upper_limit": "11691.37688371"
# },
# "product_id": 129508,
# "quotes": {
# "ask_iv": "0.90180438",
# "ask_size": "1898",
# "best_ask": "7210",
# "best_bid": "6913",
# "bid_iv": "0.60881706",
# "bid_size": "3163",
# "impact_mid_price": null,
# "mark_iv": "0.66973549"
# },
# "size": 5,
# "spot_price": "36839.58153868",
# "strike_price": "30000",
# "symbol": "C-BTC-30000-241123",
# "timestamp": 1699584998504530,
# "turnover": 184.41206804,
# "turnover_symbol": "USDT",
# "turnover_usd": 184.41206804,
# "volume": 0.005
# }
#
timestamp = self.safe_integer_product(greeks, 'timestamp', 0.001)
marketId = self.safe_string(greeks, 'symbol')
symbol = self.safe_symbol(marketId, market)
stats = self.safe_dict(greeks, 'greeks', {})
quotes = self.safe_dict(greeks, 'quotes', {})
return {
'symbol': symbol,
'timestamp': timestamp,
'datetime': self.iso8601(timestamp),
'delta': self.safe_number(stats, 'delta'),
'gamma': self.safe_number(stats, 'gamma'),
'theta': self.safe_number(stats, 'theta'),
'vega': self.safe_number(stats, 'vega'),
'rho': self.safe_number(stats, 'rho'),
'bidSize': self.safe_number(quotes, 'bid_size'),
'askSize': self.safe_number(quotes, 'ask_size'),
'bidImpliedVolatility': self.safe_number(quotes, 'bid_iv'),
'askImpliedVolatility': self.safe_number(quotes, 'ask_iv'),
'markImpliedVolatility': self.safe_number(quotes, 'mark_iv'),
'bidPrice': self.safe_number(quotes, 'best_bid'),
'askPrice': self.safe_number(quotes, 'best_ask'),
'markPrice': self.safe_number(greeks, 'mark_price'),
'lastPrice': None,
'underlyingPrice': self.safe_number(greeks, 'spot_price'),
'info': greeks,
}
def close_all_positions(self, params={}) -> List[Position]:
"""
closes all open positions for a market type
https://docs.delta.exchange/#close-all-positions
:param dict [params]: extra parameters specific to the exchange API endpoint
:param int [params.user_id]: the users id
:returns dict[]: A list of `position structures <https://docs.ccxt.com/#/?id=position-structure>`
"""
self.load_markets()
request: dict = {
'close_all_portfolio': True,
'close_all_isolated': True,
# 'user_id': 12345,
}
response = self.privatePostPositionsCloseAll(self.extend(request, params))
#
# {"result":{},"success":true}
#
position = self.parse_position(self.safe_dict(response, 'result', {}))
return [position]
def fetch_margin_mode(self, symbol: str, params={}) -> MarginMode:
"""
fetches the margin mode of a trading pair
https://docs.delta.exchange/#get-user
:param str symbol: unified symbol of the market to fetch the margin mode for
:param dict [params]: extra parameters specific to the exchange API endpoint
:returns dict: a `margin mode structure <https://docs.ccxt.com/#/?id=margin-mode-structure>`
"""
self.load_markets()
market = None
if symbol is not None:
market = self.market(symbol)
response = self.privateGetProfile(params)
#
# {
# "result": {
# "is_password_set": True,
# "kyc_expiry_date": null,
# "phishing_code": "12345",
# "preferences": {
# "favorites": []
# },
# "is_kyc_provisioned": False,
# "country": "Canada",
# "margin_mode": "isolated",
# "mfa_updated_at": "2023-07-19T01:04:43Z",
# "last_name": "",
# "oauth_apple_active": False,
# "pf_index_symbol": null,
# "proof_of_identity_status": "approved",
# "dob": null,
# "email": "abc_123@gmail.com",
# "force_change_password": False,
# "nick_name": "still-breeze-123",
# "oauth_google_active": False,
# "phone_verification_status": "verified",
# "id": 12345678,
# "last_seen": null,
# "is_withdrawal_enabled": True,
# "force_change_mfa": False,
# "enable_bots": False,
# "kyc_verified_on": null,
# "created_at": "2023-07-19T01:02:32Z",
# "withdrawal_blocked_till": null,
# "proof_of_address_status": "approved",
# "is_password_change_blocked": False,
# "is_mfa_enabled": True,
# "is_kyc_done": True,
# "oauth": null,
# "account_name": "Main",
# "sub_account_permissions": null,
# "phone_number": null,
# "tracking_info": {
# "ga_cid": "1234.4321",
# "is_kyc_gtm_tracked": True,
# "sub_account_config": {
# "cross": 2,
# "isolated": 2,
# "portfolio": 2
# }
# },
# "first_name": "",
# "phone_verified_on": null,
# "seen_intro": False,
# "password_updated_at": null,
# "is_login_enabled": True,
# "registration_date": "2023-07-19T01:02:32Z",
# "permissions": {},
# "max_sub_accounts_limit": 2,
# "country_calling_code": null,
# "is_sub_account": False,
# "is_kyc_refresh_required": False
# },
# "success": True
# }
#
result = self.safe_dict(response, 'result', {})
return self.parse_margin_mode(result, market)
def parse_margin_mode(self, marginMode: dict, market=None) -> MarginMode:
symbol = None
if market is not None:
symbol = market['symbol']
return {
'info': marginMode,
'symbol': symbol,
'marginMode': self.safe_string(marginMode, 'margin_mode'),
}
def fetch_option(self, symbol: str, params={}) -> Option:
"""
fetches option data that is commonly found in an option chain
https://docs.delta.exchange/#get-ticker-for-a-product-by-symbol
:param str symbol: unified market symbol
:param dict [params]: extra parameters specific to the exchange API endpoint
:returns dict: an `option chain structure <https://docs.ccxt.com/#/?id=option-chain-structure>`
"""
self.load_markets()
market = self.market(symbol)
request: dict = {
'symbol': market['id'],
}
response = self.publicGetTickersSymbol(self.extend(request, params))
#
# {
# "result": {
# "close": 6793.0,
# "contract_type": "call_options",
# "greeks": {
# "delta": "0.94739174",
# "gamma": "0.00002206",
# "rho": "11.00890725",
# "spot": "36839.58124652",
# "theta": "-18.18365310",
# "vega": "7.85209698"
# },
# "high": 7556.0,
# "low": 6793.0,
# "mark_price": "6955.70698909",
# "mark_vol": "0.66916863",
# "oi": "1.8980",
# "oi_change_usd_6h": "110.4600",
# "oi_contracts": "1898",
# "oi_value": "1.8980",
# "oi_value_symbol": "BTC",
# "oi_value_usd": "69940.7319",
# "open": 7.2e3,
# "price_band": {
# "lower_limit": "5533.89814767",
# "upper_limit": "11691.37688371"
# },
# "product_id": 129508,
# "quotes": {
# "ask_iv": "0.90180438",
# "ask_size": "1898",
# "best_ask": "7210",
# "best_bid": "6913",
# "bid_iv": "0.60881706",
# "bid_size": "3163",
# "impact_mid_price": null,
# "mark_iv": "0.66973549"
# },
# "size": 5,
# "spot_price": "36839.58153868",
# "strike_price": "30000",
# "symbol": "C-BTC-30000-241123",
# "timestamp": 1699584998504530,
# "turnover": 184.41206804,
# "turnover_symbol": "USDT",
# "turnover_usd": 184.41206804,
# "volume": 0.005
# },
# "success": True
# }
#
result = self.safe_dict(response, 'result', {})
return self.parse_option(result, None, market)
def parse_option(self, chain: dict, currency: Currency = None, market: Market = None) -> Option:
#
# {
# "close": 6793.0,
# "contract_type": "call_options",
# "greeks": {
# "delta": "0.94739174",
# "gamma": "0.00002206",
# "rho": "11.00890725",
# "spot": "36839.58124652",
# "theta": "-18.18365310",
# "vega": "7.85209698"
# },
# "high": 7556.0,
# "low": 6793.0,
# "mark_price": "6955.70698909",
# "mark_vol": "0.66916863",
# "oi": "1.8980",
# "oi_change_usd_6h": "110.4600",
# "oi_contracts": "1898",
# "oi_value": "1.8980",
# "oi_value_symbol": "BTC",
# "oi_value_usd": "69940.7319",
# "open": 7.2e3,
# "price_band": {
# "lower_limit": "5533.89814767",
# "upper_limit": "11691.37688371"
# },
# "product_id": 129508,
# "quotes": {
# "ask_iv": "0.90180438",
# "ask_size": "1898",
# "best_ask": "7210",
# "best_bid": "6913",
# "bid_iv": "0.60881706",
# "bid_size": "3163",
# "impact_mid_price": null,
# "mark_iv": "0.66973549"
# },
# "size": 5,
# "spot_price": "36839.58153868",
# "strike_price": "30000",
# "symbol": "C-BTC-30000-241123",
# "timestamp": 1699584998504530,
# "turnover": 184.41206804,
# "turnover_symbol": "USDT",
# "turnover_usd": 184.41206804,
# "volume": 0.005
# }
#
marketId = self.safe_string(chain, 'symbol')
market = self.safe_market(marketId, market)
quotes = self.safe_dict(chain, 'quotes', {})
timestamp = self.safe_integer_product(chain, 'timestamp', 0.001)
return {
'info': chain,
'currency': None,
'symbol': market['symbol'],
'timestamp': timestamp,
'datetime': self.iso8601(timestamp),
'impliedVolatility': self.safe_number(quotes, 'mark_iv'),
'openInterest': self.safe_number(chain, 'oi'),
'bidPrice': self.safe_number(quotes, 'best_bid'),
'askPrice': self.safe_number(quotes, 'best_ask'),
'midPrice': self.safe_number(quotes, 'impact_mid_price'),
'markPrice': self.safe_number(chain, 'mark_price'),
'lastPrice': None,
'underlyingPrice': self.safe_number(chain, 'spot_price'),
'change': None,
'percentage': None,
'baseVolume': self.safe_number(chain, 'volume'),
'quoteVolume': None,
}
def sign(self, path, api='public', method='GET', params={}, headers=None, body=None):
requestPath = '/' + self.version + '/' + self.implode_params(path, params)
url = self.urls['api'][api] + requestPath
query = self.omit(params, self.extract_params(path))
if api == 'public':
if query:
url += '?' + self.urlencode(query)
elif api == 'private':
self.check_required_credentials()
timestamp = str(self.seconds())
headers = {
'api-key': self.apiKey,
'timestamp': timestamp,
}
auth = method + timestamp + requestPath
if method == 'GET':
if query:
queryString = '?' + self.urlencode(query)
auth += queryString
url += queryString
else:
body = self.json(query)
auth += body
headers['Content-Type'] = 'application/json'
signature = self.hmac(self.encode(auth), self.encode(self.secret), hashlib.sha256)
headers['signature'] = signature
return {'url': url, 'method': method, 'body': body, 'headers': headers}
def handle_errors(self, code: int, reason: str, url: str, method: str, headers: dict, body: str, response, requestHeaders, requestBody):
if response is None:
return None
#
# {"error":{"code":"insufficient_margin","context":{"available_balance":"0.000000000000000000","required_additional_balance":"1.618626000000000000000000000"}},"success":false}
#
error = self.safe_dict(response, 'error', {})
errorCode = self.safe_string(error, 'code')
if errorCode is not None:
feedback = self.id + ' ' + body
self.throw_exactly_matched_exception(self.exceptions['exact'], errorCode, feedback)
self.throw_broadly_matched_exception(self.exceptions['broad'], errorCode, feedback)
raise ExchangeError(feedback) # unknown message
return None