1851 lines
78 KiB
Python
1851 lines
78 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.zebpay import ImplicitAPI
|
|
import hashlib
|
|
import json
|
|
from ccxt.base.types import Any, Balances, Currencies, Int, Leverage, Leverages, MarginModification, Market, Num, Order, OrderBook, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade, TradingFeeInterface, TradingFees
|
|
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 InsufficientFunds
|
|
from ccxt.base.errors import InvalidOrder
|
|
from ccxt.base.errors import OrderNotFound
|
|
from ccxt.base.errors import NotSupported
|
|
from ccxt.base.errors import RateLimitExceeded
|
|
from ccxt.base.errors import ExchangeNotAvailable
|
|
from ccxt.base.decimal_to_precision import TICK_SIZE
|
|
from ccxt.base.precise import Precise
|
|
|
|
|
|
class zebpay(Exchange, ImplicitAPI):
|
|
|
|
def describe(self) -> Any:
|
|
return self.deep_extend(super(zebpay, self).describe(), {
|
|
'id': 'zebpay',
|
|
'name': 'Zebpay',
|
|
'countries': ['IN'],
|
|
'rateLimit': 50,
|
|
'version': 'v1',
|
|
'certified': False,
|
|
'pro': False,
|
|
'has': {
|
|
'CORS': None,
|
|
'spot': True,
|
|
'margin': False,
|
|
'swap': True,
|
|
'future': False,
|
|
'option': None,
|
|
'addMargin': True,
|
|
'borrowCrossMargin': False,
|
|
'borrowIsolatedMargin': False,
|
|
'borrowMargin': False,
|
|
'cancelAllOrders': True,
|
|
'cancelOrder': True,
|
|
'cancelOrders': False,
|
|
'closePosition': True,
|
|
'createOrder': True,
|
|
'fetchBalance': True,
|
|
'fetchBorrowInterest': False,
|
|
'fetchBorrowRate': False,
|
|
'fetchBorrowRateHistories': False,
|
|
'fetchBorrowRateHistory': False,
|
|
'fetchBorrowRates': False,
|
|
'fetchBorrowRatesPerSymbol': False,
|
|
'fetchCrossBorrowRate': False,
|
|
'fetchCrossBorrowRates': False,
|
|
'fetchCurrencies': True,
|
|
'fetchIsolatedBorrowRate': False,
|
|
'fetchIsolatedBorrowRates': False,
|
|
'fetchLeverage': True,
|
|
'fetchLeverages': True,
|
|
'fetchMarkets': True,
|
|
'fetchMyTrades': True,
|
|
'fetchOHLCV': True,
|
|
'fetchOpenOrders': True,
|
|
'fetchOrder': True,
|
|
'fetchOrderBook': True,
|
|
'fetchOrderTrades': True,
|
|
'fetchPositions': True,
|
|
'fetchTicker': True,
|
|
'fetchTickers': True,
|
|
'fetchTrades': True,
|
|
'fetchTradingFee': True,
|
|
'reduceMargin': True,
|
|
'repayCrossMargin': False,
|
|
'repayIsolatedMargin': False,
|
|
'setLeverage': True,
|
|
},
|
|
'timeframes': {
|
|
'1m': 1,
|
|
'5m': 5,
|
|
'15m': 15,
|
|
'30m': 30,
|
|
'1h': 60,
|
|
'2h': 120,
|
|
'4h': 480,
|
|
'12h': 720,
|
|
'1d': 1440,
|
|
'1w': 10080,
|
|
},
|
|
'urls': {
|
|
'logo': 'https://github.com/user-attachments/assets/8094e7be-55a7-46f4-a087-0ca31b48ecad',
|
|
'api': {
|
|
'spot': 'https://sapi.zebpay.com',
|
|
'swap': 'https://futuresbe.zebpay.com',
|
|
},
|
|
'test': {
|
|
'spot': 'https://www.zebstage.com',
|
|
'swap': 'https://dev-futuresbe.zebstage.com',
|
|
},
|
|
'www': 'https://www.zebpay.com',
|
|
'doc': 'https://github.com/zebpay/zebpay-api-references',
|
|
'fees': 'https://zebpay.com/in/features/pricing',
|
|
},
|
|
'api': {
|
|
'public': {
|
|
'spot': {
|
|
'get': {
|
|
'v2/system/time': 10,
|
|
'v2/system/status': 10,
|
|
'v2/market/orderbook': 10,
|
|
'v2/market/trades': 10,
|
|
'v2/market/ticker': 10,
|
|
'v2/market/allTickers': 10,
|
|
'v2/ex/exchangeInfo': 10,
|
|
'v2/ex/currencies': 10,
|
|
'v2/market/klines': 10,
|
|
'v2/ex/tradefees': 10,
|
|
},
|
|
},
|
|
'swap': {
|
|
'get': {
|
|
'v1/system/time': 10,
|
|
'v1/system/status': 10,
|
|
'v1/exchange/tradefee': 10,
|
|
'v1/exchange/tradefees': 10,
|
|
'v1/market/orderBook': 10,
|
|
'v1/market/ticker24Hr': 10,
|
|
'v1/market/markets': 10,
|
|
'v1/market/aggTrade': 10,
|
|
},
|
|
'post': {
|
|
'v1/market/klines': 10,
|
|
},
|
|
},
|
|
},
|
|
'private': {
|
|
'spot': {
|
|
'post': {
|
|
'v2/ex/orders': 10,
|
|
},
|
|
'get': {
|
|
'v2/ex/orders': 10,
|
|
'v2/account/balance': 10,
|
|
'v2/ex/tradefee': 10,
|
|
'v2/ex/order': 10,
|
|
'v2/ex/order/fills': 10,
|
|
},
|
|
'delete': {
|
|
'v2/ex/order': 10,
|
|
'v2/ex/orders': 10,
|
|
'v2/ex/orders/cancelAll': 10,
|
|
},
|
|
},
|
|
'swap': {
|
|
'get': {
|
|
'v1/wallet/balance': 10,
|
|
'v1/trade/order': 10,
|
|
'v1/trade/order/open-orders': 10,
|
|
'v1/trade/userLeverages': 10,
|
|
'v1/trade/userLeverage': 10,
|
|
'v1/trade/positions': 10,
|
|
'v1/trade/history': 10,
|
|
},
|
|
'post': {
|
|
'v1/trade/order': 10,
|
|
'v1/trade/order/addTPSL': 10,
|
|
'v1/trade/addMargin': 10,
|
|
'v1/trade/reduceMargin': 10,
|
|
'v1/trade/position/close': 10,
|
|
'v1/trade/update/userLeverage': 10,
|
|
},
|
|
'delete': {
|
|
'v1/trade/order': 10,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
'precisionMode': TICK_SIZE,
|
|
'fees': {},
|
|
'commonCurrencies': {
|
|
},
|
|
'requiredCredentials': {
|
|
'apiKey': True,
|
|
'secret': True,
|
|
},
|
|
'options': {
|
|
'fetchMarkets': {
|
|
'types': ['spot', 'swap'],
|
|
},
|
|
'defaultType': 'spot', # 'spot', 'swap'
|
|
},
|
|
'features': {
|
|
'default': {
|
|
'fetchOHLCV': {
|
|
'limit': 100,
|
|
},
|
|
},
|
|
},
|
|
'exceptions': {
|
|
'exact': {
|
|
'77': InvalidOrder,
|
|
'400': BadRequest, # Bad Request -- Invalid request format
|
|
'401': AuthenticationError, # Unauthorized -- Invalid API Key
|
|
'403': NotSupported, # Forbidden -- The request is forbidden
|
|
'404': NotSupported, # Not Found -- The specified resource could not be found
|
|
'429': RateLimitExceeded, # Too Many Requests -- Access limit breached
|
|
'500': ExchangeNotAvailable, # Internal Server Error -- We had a problem with our server. Try again later.
|
|
'503': ExchangeNotAvailable, # Service Unavailable -- We're temporarily offline for maintenance. Please try again later.
|
|
'3013': OrderNotFound,
|
|
'Order quantity is out of range': InvalidOrder,
|
|
'Invalid trade order type': InvalidOrder,
|
|
'Insufficient margin': InsufficientFunds,
|
|
'insufficient balance': InsufficientFunds,
|
|
'leverage must be in [1,8]': BadRequest,
|
|
'the request you sent is invalid': BadRequest,
|
|
},
|
|
'broad': {
|
|
'InvalidOrder': InvalidOrder, # Rate should be in the range of
|
|
},
|
|
},
|
|
})
|
|
|
|
def fetch_status(self, params={}):
|
|
"""
|
|
the latest known information on the availability of the exchange API
|
|
|
|
[Spot] https://github.com/zebpay/zebpay-api-references/blob/main/spot/api-reference/public-endpoints.md#system-status
|
|
[Swap] https://github.com/zebpay/zebpay-api-references/blob/main/futures/api-reference/public-endpoints/system.md#get-system-status
|
|
|
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
:returns dict: a `status structure <https://docs.ccxt.com/?id=exchange-status-structure>`
|
|
"""
|
|
type = None
|
|
type, params = self.handle_market_type_and_params('fetchStatus', None, params)
|
|
isSpot = (type == 'spot')
|
|
response = None
|
|
data = {}
|
|
if isSpot:
|
|
response = self.publicSpotGetV2SystemStatus(params)
|
|
data = response
|
|
else:
|
|
response = self.publicSwapGetV1SystemStatus(params)
|
|
data = self.safe_dict(response, 'data', {})
|
|
#
|
|
# {
|
|
# "statusDescription": "OK",
|
|
# "data":
|
|
# {
|
|
# "systemStatus": "ok"
|
|
# }
|
|
# "statusCode": 200,
|
|
# "customMessage": ["OK"]
|
|
# }
|
|
#
|
|
status = self.safe_string_2(data, 'systemStatus', 'status')
|
|
return {
|
|
'status': status,
|
|
'updated': None,
|
|
'eta': None,
|
|
'url': None,
|
|
'info': response,
|
|
}
|
|
|
|
def fetch_time(self, params={}) -> Int:
|
|
"""
|
|
fetches the current integer timestamp in milliseconds from the poloniexfutures server
|
|
|
|
[Spot] https://github.com/zebpay/zebpay-api-references/blob/main/spot/api-reference/public-endpoints.md#get-server-time
|
|
[Swap] https://github.com/zebpay/zebpay-api-references/blob/main/futures/api-reference/public-endpoints/system.md#get-system-time
|
|
|
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
:returns int: the current integer timestamp in milliseconds from the poloniexfutures server
|
|
"""
|
|
type = None
|
|
type, params = self.handle_market_type_and_params('fetchTime', None, params)
|
|
isSpot = (type == 'spot')
|
|
response = None
|
|
data = {}
|
|
if isSpot:
|
|
response = self.publicSpotGetV2SystemTime(params)
|
|
data = response
|
|
else:
|
|
response = self.publicSwapGetV1SystemTime(params)
|
|
data = self.safe_dict(response, 'data', {})
|
|
#
|
|
# {
|
|
# "statusDescription": "OK",
|
|
# "data":
|
|
# {
|
|
# "timestamp": 1546837113087
|
|
# }
|
|
# "statusCode": 200,
|
|
# "customMessage": ["OK"]
|
|
# }
|
|
#
|
|
time = self.safe_integer(data, 'timestamp')
|
|
return time
|
|
|
|
def fetch_markets(self, params={}) -> List[Market]:
|
|
"""
|
|
retrieves data on all markets for zebpay
|
|
|
|
[Spot] https://github.com/zebpay/zebpay-api-references/blob/main/spot/api-reference/public-endpoints.md#get-trading-pairs
|
|
[Swap] https://github.com/zebpay/zebpay-api-references/blob/main/futures/api-reference/public-endpoints/market.md#fetch-markets
|
|
|
|
:param dict [params]: extra parameters specific to the exchange api endpoint
|
|
:returns dict[]: an array of objects representing market data
|
|
"""
|
|
promisesUnresolved = []
|
|
fetchMarketsOptions = self.safe_dict(self.options, 'fetchMarkets')
|
|
defaultMarkets = ['spot', 'swap']
|
|
types = self.safe_list(fetchMarketsOptions, 'types', defaultMarkets)
|
|
for i in range(0, len(types)):
|
|
type = types[i]
|
|
if type == 'spot':
|
|
promisesUnresolved.append(self.fetch_spot_markets(params))
|
|
elif type == 'swap':
|
|
promisesUnresolved.append(self.fetch_swap_markets(params))
|
|
else:
|
|
raise ExchangeError(self.id + ' fetchMarkets() self.options fetchMarkets "' + type + '" is not a supported market type')
|
|
promises = promisesUnresolved
|
|
spotMarkets = self.safe_list(promises, 0, [])
|
|
futureMarkets = self.safe_list(promises, 1, [])
|
|
return self.array_concat(spotMarkets, futureMarkets)
|
|
|
|
def fetch_currencies(self, params={}) -> Currencies:
|
|
"""
|
|
fetches all available currencies on an exchange
|
|
|
|
[Spot] https://github.com/zebpay/zebpay-api-references/blob/main/spot/api-reference/public-endpoints.md#get-coin-settings
|
|
|
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
:returns dict: an associative dictionary of currencies
|
|
"""
|
|
response = self.publicSpotGetV2ExCurrencies(params)
|
|
#
|
|
# {
|
|
# "data": [
|
|
# {
|
|
# "currency": "BTC",
|
|
# "name": "BTC",
|
|
# "fullName": "150",
|
|
# "precision": "0.2",
|
|
# "type": "fiat",
|
|
# "isDebitEnabled": False,
|
|
# "chains": [
|
|
# {
|
|
# "chainName": "Bitcoin",
|
|
# "withdrawalMinSize": "0.000482",
|
|
# "depositMinSize": "0.00000001",
|
|
# "withdrawalFee": "0.00040000",
|
|
# "isWithdrawEnabled": "true",
|
|
# "isDepositEnabled": "true",
|
|
# "contractAddress": "0x095418A82BC2439703b69fbE1210824F2247D77c",
|
|
# "withdrawPrecision": "8",
|
|
# "maxWithdraw": "2.43090487000000",
|
|
# "maxDeposit": "100.00000000",
|
|
# "needTag": "false",
|
|
# "chainId": "bitcoin",
|
|
# "AddressRegex": "^tb1[qpzry9x8gf2tvdw0s3jn54khce6mua7l]{39,59}|m[a-zA-Z0-9]{25,34}|n[a-zA-Z0-9]{25,34}|^2[a-zA-Z0-9]{25,34}$"
|
|
# }
|
|
# ]
|
|
# }
|
|
# ]
|
|
# }
|
|
#
|
|
rows = self.safe_list(response, 'data', [])
|
|
result: dict = {}
|
|
for i in range(0, len(rows)):
|
|
currency = rows[i]
|
|
currencyId = self.safe_string(currency, 'currency')
|
|
code = self.safe_currency_code(currencyId)
|
|
name = self.safe_string(currency, 'name')
|
|
precision = self.parse_number(self.parse_precision(self.safe_string(currency, 'precision')))
|
|
chains = self.safe_list(currency, 'chains', [])
|
|
networks: dict = {}
|
|
minWithdrawFeeString = None
|
|
minWithdrawString = None
|
|
minDepositString = None
|
|
deposit = False
|
|
withdraw = False
|
|
for j in range(0, len(chains)):
|
|
chain = chains[j]
|
|
networkId = self.safe_string(chain, 'chainId')
|
|
networkCode = self.network_id_to_code(networkId)
|
|
depositAllowed = self.safe_bool(chain, 'isDepositEnabled') is True
|
|
deposit = depositAllowed if (depositAllowed) else deposit
|
|
withdrawAllowed = self.safe_bool(chain, 'isWithdrawEnabled') is True
|
|
withdraw = withdrawAllowed if (withdrawAllowed) else withdraw
|
|
withdrawFeeString = self.safe_string(chain, 'withdrawalFee')
|
|
if withdrawFeeString is not None:
|
|
minWithdrawFeeString = withdrawFeeString if (minWithdrawFeeString is None) else Precise.string_min(withdrawFeeString, minWithdrawFeeString)
|
|
minNetworkWithdrawString = self.safe_string(chain, 'withdrawalMinSize')
|
|
if minNetworkWithdrawString is not None:
|
|
minWithdrawString = minNetworkWithdrawString if (minWithdrawString is None) else Precise.string_min(minNetworkWithdrawString, minWithdrawString)
|
|
minNetworkDepositString = self.safe_string(chain, 'depositMinSize')
|
|
if minNetworkDepositString is not None:
|
|
minDepositString = minNetworkDepositString if (minDepositString is None) else Precise.string_min(minNetworkDepositString, minDepositString)
|
|
networks[networkCode] = {
|
|
'info': chain,
|
|
'id': networkId,
|
|
'network': networkCode,
|
|
'active': depositAllowed and withdrawAllowed,
|
|
'deposit': depositAllowed,
|
|
'withdraw': withdrawAllowed,
|
|
'fee': self.parse_number(withdrawFeeString),
|
|
'precision': precision,
|
|
'limits': {
|
|
'withdraw': {
|
|
'min': self.parse_number(minNetworkWithdrawString),
|
|
'max': None,
|
|
},
|
|
'deposit': {
|
|
'min': self.parse_number(minNetworkDepositString),
|
|
'max': None,
|
|
},
|
|
},
|
|
}
|
|
result[code] = self.safe_currency_structure({
|
|
'info': currency,
|
|
'code': code,
|
|
'id': currencyId,
|
|
'name': name,
|
|
'active': deposit and withdraw,
|
|
'deposit': deposit,
|
|
'withdraw': withdraw,
|
|
'fee': self.parse_number(minWithdrawFeeString),
|
|
'precision': precision,
|
|
'limits': {
|
|
'amount': {
|
|
'min': None,
|
|
'max': None,
|
|
},
|
|
'withdraw': {
|
|
'min': self.parse_number(minWithdrawString),
|
|
'max': None,
|
|
},
|
|
'deposit': {
|
|
'min': self.parse_number(minDepositString),
|
|
'max': None,
|
|
},
|
|
},
|
|
'networks': networks,
|
|
})
|
|
return result
|
|
|
|
def fetch_trading_fee(self, symbol: str, params={}) -> TradingFeeInterface:
|
|
"""
|
|
fetch the trading fees for a market
|
|
|
|
[Spot] https://github.com/zebpay/zebpay-api-references/blob/main/spot/api-reference/private-endpoints.md#get-exchange-fee
|
|
[Swap] https://github.com/zebpay/zebpay-api-references/blob/main/futures/api-reference/public-endpoints/exchange.md#get-trade-fee-single-symbol
|
|
|
|
:param str symbol: unified symbol of the market to fetch the order book for
|
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
:param dict [params.side]: side to fetch trading fee
|
|
:returns dict: a `status structure <https://docs.ccxt.com/?id=exchange-status-structure>`
|
|
"""
|
|
self.load_markets()
|
|
market = self.market(symbol)
|
|
response = None
|
|
data
|
|
request: dict = {
|
|
'symbol': market['id'],
|
|
}
|
|
if market['spot']:
|
|
response = self.privateSpotGetV2ExTradefee(self.extend(request, params))
|
|
#
|
|
# {
|
|
# "statusDescription": "Success",
|
|
# "data":
|
|
# {
|
|
# "symbol": "BTCINR",
|
|
# "takerFeeRate": "0.01",
|
|
# "makerFeeRate": "0.05",
|
|
# "percentage": True
|
|
# } ,
|
|
# "statusCode": 200,
|
|
# }
|
|
data = self.safe_dict(response, 'data', {})
|
|
else:
|
|
response = self.publicSwapGetV1ExchangeTradefee(self.extend(request, params))
|
|
#
|
|
# {
|
|
# "statusDescription": "OK",
|
|
# "data":
|
|
# [
|
|
# {
|
|
# "symbol": "BTCINR",
|
|
# "takerFee": "0.01",
|
|
# "makerFee": "0.05"
|
|
# }
|
|
# ] ,
|
|
# "statusCode": 200,
|
|
# "customMessage": ["OK"]
|
|
# }
|
|
#
|
|
responseData = self.safe_list(response, 'data', [])
|
|
data = self.safe_dict(responseData, 0)
|
|
return self.parse_trading_fee(data, market)
|
|
|
|
def fetch_trading_fees(self, params={}) -> TradingFees:
|
|
"""
|
|
fetch the trading fees for multiple markets
|
|
|
|
[Swap] https://github.com/zebpay/zebpay-api-references/blob/main/futures/api-reference/public-endpoints/exchange.md#get-trade-fees-all-symbols
|
|
|
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
:returns dict: a `status structure <https://docs.ccxt.com/?id=exchange-status-structure>`
|
|
"""
|
|
type = None
|
|
type, params = self.handle_market_type_and_params('fetchTradingFees', None, params)
|
|
response = None
|
|
if type == 'spot':
|
|
response = self.publicSpotGetV2ExTradefees(params)
|
|
else:
|
|
response = self.publicSwapGetV1ExchangeTradefees(params)
|
|
#
|
|
# {
|
|
# "statusDescription": "OK",
|
|
# "data": [
|
|
# {
|
|
# "symbol": "BTCINR",
|
|
# "takerFee": "0.01",
|
|
# "makerFee": "0.05"
|
|
# }
|
|
# ],
|
|
# "statusCode": 200,
|
|
# "customMessage": ["OK"]
|
|
# }
|
|
#
|
|
fees = self.safe_list(response, 'data', [])
|
|
result: dict = {}
|
|
for i in range(0, len(fees)):
|
|
fee = self.parse_trading_fee(fees[i])
|
|
symbol = fee['symbol']
|
|
result[symbol] = fee
|
|
return result
|
|
|
|
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
|
|
|
|
[Spot] https://github.com/zebpay/zebpay-api-references/blob/main/spot/api-reference/public-endpoints.md#get-order-book
|
|
[Swap] https://github.com/zebpay/zebpay-api-references/blob/main/futures/api-reference/public-endpoints/market.md#get-order-book
|
|
|
|
: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'],
|
|
}
|
|
response = None
|
|
if market['spot']:
|
|
if limit is not None:
|
|
request['limit'] = limit
|
|
#
|
|
# {
|
|
# "asks": [
|
|
# [5000, 1000], #Price, quantity
|
|
# [6000, 1983] #Price, quantity
|
|
# ],
|
|
# "bids": [
|
|
# [3200, 800], #Price, quantity
|
|
# [3100, 100] #Price, quantity
|
|
# ],
|
|
# }
|
|
# }
|
|
response = self.publicSpotGetV2MarketOrderbook(self.extend(request, params))
|
|
else:
|
|
response = self.publicSwapGetV1MarketOrderBook(self.extend(request, params))
|
|
bookData = self.safe_dict(response, 'data', {})
|
|
orderbook = self.parse_order_book(bookData, market['symbol'], None, 'bids', 'asks', 0, 1)
|
|
orderbook['nonce'] = self.safe_integer(bookData, 'nonce')
|
|
return orderbook
|
|
|
|
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
|
|
|
|
[Spot] https://github.com/zebpay/zebpay-api-references/blob/main/spot/api-reference/public-endpoints.md#get-ticker
|
|
[Swap] https://github.com/zebpay/zebpay-api-references/blob/main/futures/api-reference/public-endpoints/market.md#get-24hr-ticker
|
|
|
|
: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 = None
|
|
if market['spot']:
|
|
response = self.publicSpotGetV2MarketTicker(self.extend(request, params))
|
|
#
|
|
# [
|
|
# {
|
|
# "symbol": "BTC-INR",
|
|
# "bestBid": "4900000",
|
|
# "bestBidQty": "0.00014938",
|
|
# "bestAsk": "",
|
|
# "bestAskQty": "0",
|
|
# "priceChange": "-98134.56",
|
|
# "priceChangePercent": "-1.84",
|
|
# "high": "5433400",
|
|
# "low": "5333400",
|
|
# "vol": "0.0002",
|
|
# "volValue": "1066.68",
|
|
# "last": "5333400"
|
|
# }
|
|
# ]
|
|
#
|
|
else:
|
|
response = self.publicSwapGetV1MarketTicker24Hr(self.extend(request, params))
|
|
data = self.safe_dict(response, 'data', {})
|
|
return self.parse_ticker(data, 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
|
|
|
|
[Spot] https://github.com/zebpay/zebpay-api-references/blob/main/spot/api-reference/public-endpoints.md#get-all-tickers
|
|
|
|
: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>`
|
|
"""
|
|
type = None
|
|
type, params = self.handle_market_type_and_params('fetchTickers', None, params)
|
|
if type != 'spot':
|
|
raise NotSupported(self.id + ' fetchTickers() does not support ' + type + ' markets')
|
|
self.load_markets()
|
|
symbols = self.market_symbols(symbols)
|
|
response = self.publicSpotGetV2MarketAllTickers(params)
|
|
#
|
|
# [
|
|
# {
|
|
# "symbol": "BTC-INR",
|
|
# "bestBid": "4900000",
|
|
# "bestBidQty": "0.00014938",
|
|
# "bestAsk": "",
|
|
# "bestAskQty": "0",
|
|
# "priceChange": "-98134.56",
|
|
# "priceChangePercent": "-1.84",
|
|
# "high": "5433400",
|
|
# "low": "5333400",
|
|
# "vol": "0.0002",
|
|
# "volValue": "1066.68",
|
|
# "last": "5333400"
|
|
# }
|
|
# ]
|
|
#
|
|
tickerList = self.safe_list(response, 'data', [])
|
|
return self.parse_tickers(tickerList, symbols)
|
|
|
|
def fetch_ohlcv(self, symbol: str, timeframe='1m', since: Int = None, limit: Int = None, params={}) -> List[list]:
|
|
"""
|
|
fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market
|
|
|
|
[Spot] https://github.com/zebpay/zebpay-api-references/blob/main/spot/api-reference/public-endpoints.md#get-klinescandlesticks
|
|
[Swap] https://github.com/zebpay/zebpay-api-references/blob/main/futures/api-reference/public-endpoints/market.md#-get-k-lines-ohlcv-data
|
|
|
|
: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 int [params.endtime]: the latest time in ms to fetch orders for
|
|
:returns int[][]: A list of candles ordered, open, high, low, close, volume
|
|
"""
|
|
self.load_markets()
|
|
market = self.market(symbol)
|
|
if limit is None:
|
|
limit = 100 # default is 200
|
|
request: dict = {
|
|
'symbol': market['id'],
|
|
}
|
|
if market['spot']:
|
|
request['interval'] = self.safe_string(self.timeframes, timeframe, timeframe)
|
|
else:
|
|
request['interval'] = timeframe
|
|
if market['contract'] and (limit is not None):
|
|
request['limit'] = limit
|
|
if since is not None:
|
|
if market['spot']:
|
|
request['startTime'] = since
|
|
else:
|
|
request['since'] = since
|
|
until = self.safe_integer_2(params, 'until', 'endtime')
|
|
if until is not None:
|
|
request['endTime'] = until
|
|
params = self.omit(params, ['endtime', 'until'])
|
|
response = None
|
|
if market['spot']:
|
|
if until is None or since is None:
|
|
raise ArgumentsRequired(self.id + ' fetchOHLCV() requires a both a since and until/endtime parameter for spot markets')
|
|
response = self.publicSpotGetV2MarketKlines(self.extend(request, params))
|
|
else:
|
|
response = self.publicSwapPostV1MarketKlines(self.extend(request, params))
|
|
#
|
|
# [
|
|
# [
|
|
# "1670608800000",
|
|
# "17071",
|
|
# "17073",
|
|
# "17027",
|
|
# "17055.5",
|
|
# "268611",
|
|
# "15.74462667"
|
|
# ],
|
|
# [
|
|
# "1670605200000",
|
|
# "17071.5",
|
|
# "17071.5",
|
|
# "17061",
|
|
# "17071",
|
|
# "4177",
|
|
# "0.24469757"
|
|
# ],
|
|
# [
|
|
# "1670601600000",
|
|
# "17086.5",
|
|
# "17088",
|
|
# "16978",
|
|
# "17071.5",
|
|
# "6356",
|
|
# "0.37288112"
|
|
# ]
|
|
# ]
|
|
#
|
|
data = self.safe_list(response, 'data', [])
|
|
return self.parse_ohlcvs(data, market, timeframe, since, limit)
|
|
|
|
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
|
|
|
|
[Spot] https://github.com/zebpay/zebpay-api-references/blob/main/spot/api-reference/public-endpoints.md#get-recent-trades
|
|
https://github.com/zebpay/zebpay-api-references/blob/main/futures/api-reference/public-endpoints/market.md#get-aggregate-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'],
|
|
}
|
|
if market['spot'] and limit is not None:
|
|
request['limit'] = limit
|
|
response = None
|
|
if market['spot']:
|
|
response = self.publicSpotGetV2MarketTrades(self.extend(request, params))
|
|
else:
|
|
response = self.publicSwapGetV1MarketAggTrade(self.extend(request, params))
|
|
#
|
|
# [
|
|
# {
|
|
# "id" : "60014521",
|
|
# "price" : "23162.94",
|
|
# "qty" : "0.00009",
|
|
# "side" : "SELL",
|
|
# "time" : 1659684602042,
|
|
# "isBuyerMaker" : 1659684602036
|
|
# }
|
|
# ]
|
|
#
|
|
data = self.safe_list(response, 'data', [])
|
|
return self.parse_trades(data, market, since, limit)
|
|
|
|
def fetch_my_trades(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
|
|
"""
|
|
get the list of most recent trades for a particular symbol
|
|
|
|
https://github.com/zebpay/zebpay-api-references/blob/main/futures/api-reference/private-endpoints/trade.md#-get-trade-history
|
|
|
|
: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 = None
|
|
if symbol is not None:
|
|
market = self.market(symbol)
|
|
type = None
|
|
type, params = self.handle_market_type_and_params('fetchMyTrades', market, params)
|
|
response = None
|
|
if type == 'spot':
|
|
raise NotSupported(self.id + ' fetchMyTrades() does not support spot markets')
|
|
else:
|
|
response = self.privateSwapGetV1TradeHistory(params)
|
|
data = self.safe_dict(response, 'data', {})
|
|
items = self.safe_list(data, 'items', [])
|
|
return self.parse_trades(items, market, since, limit)
|
|
|
|
def fetch_order_trades(self, id: str, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
|
|
"""
|
|
fetch all the trades made from a single order
|
|
|
|
[Spot] https://github.com/zebpay/zebpay-api-references/blob/main/spot/api-reference/private-endpoints.md#get-order-fills
|
|
|
|
:param str id: order id
|
|
: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 to retrieve
|
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
:returns dict[]: a list of `trade structures <https://docs.ccxt.com/?id=trade-structure>`
|
|
"""
|
|
type = None
|
|
type, params = self.handle_market_type_and_params('fetchOrderTrades', None, params)
|
|
if type != 'spot':
|
|
raise NotSupported(self.id + ' fetchOrderTrades() does not support ' + type + ' markets')
|
|
self.load_markets()
|
|
request: dict = {
|
|
'orderId': id,
|
|
}
|
|
response = self.privateSpotGetV2ExOrderFills(self.extend(request, params))
|
|
#
|
|
# {
|
|
# "orderId": "456789",
|
|
# "symbol": "LINK_USDT",
|
|
# "origQty": "1.5",
|
|
# "orderId": "30249408733945856",
|
|
# "side": "BUY",
|
|
# "type": "LIMIT",
|
|
# "matchRole": "MAKER",
|
|
# "createTime": 1648200366864,
|
|
# "price": "3.1",
|
|
# "avgExecutedPrice": "2.3456"
|
|
# "openQty": "1",
|
|
# "filledQty": "0",
|
|
# "fees": "0.00145",
|
|
# }
|
|
#
|
|
data = self.safe_dict(response, 'data', {})
|
|
trades = [data]
|
|
return self.parse_trades(trades)
|
|
|
|
def parse_trade(self, trade: dict, market: Market = None) -> Trade:
|
|
#
|
|
# fetchMyTrades
|
|
#
|
|
# {
|
|
# "id": "32164924331503616",
|
|
# "symbol": "LINK_USDT",
|
|
# "accountType": "SPOT",
|
|
# "orderId": "32164923987566592",
|
|
# "side": "SELL",
|
|
# "type": "MARKET",
|
|
# "matchRole": "TAKER",
|
|
# "createTime": 1648635115525,
|
|
# "price": "11",
|
|
# "quantity": "0.5",
|
|
# "amount": "5.5",
|
|
# "feeCurrency": "USDT",
|
|
# "feeAmount": "0.007975",
|
|
# "pageId": "32164924331503616",
|
|
# "clientOrderId": "myOwnId-321"
|
|
# }
|
|
# {
|
|
# aggregateTradeId: '2659115835',
|
|
# symbol: 'ETHINR',
|
|
# price: '292848',
|
|
# quantity: '0.147',
|
|
# firstTradeId: '7018766077',
|
|
# lastTradeId: '7018766081',
|
|
# tradeTime: '1765381971447',
|
|
# isBuyerMarketMaker: True
|
|
# }
|
|
#
|
|
#
|
|
id = self.safe_string_2(trade, 'id', 'aggregateTradeId')
|
|
orderId = self.safe_string_2(trade, 'id', 'order')
|
|
timestamp = self.safe_integer_2(trade, 'timestamp', 'tradeTime')
|
|
marketId = self.safe_string(trade, 'symbol')
|
|
market = self.safe_market(marketId, market, '_')
|
|
symbol = market['symbol']
|
|
side = self.safe_string_lower(trade, 'side')
|
|
priceString = self.safe_string(trade, 'price')
|
|
amountString = self.safe_string_2(trade, 'amount', 'quantity')
|
|
return self.safe_trade({
|
|
'id': id,
|
|
'info': trade,
|
|
'timestamp': timestamp,
|
|
'datetime': self.iso8601(timestamp),
|
|
'symbol': symbol,
|
|
'order': orderId,
|
|
'type': self.safe_string_lower(trade, 'type'),
|
|
'side': side,
|
|
'takerOrMaker': None,
|
|
'price': priceString,
|
|
'amount': amountString,
|
|
'cost': self.safe_string(trade, 'cost'),
|
|
'fee': self.safe_dict(trade, 'fee'),
|
|
}, market)
|
|
|
|
def fetch_balance(self, params={}) -> Balances:
|
|
"""
|
|
query for balance and get the amount of funds available for trading or funds locked in orders
|
|
|
|
[Spot] https://github.com/zebpay/zebpay-api-references/blob/main/spot/api-reference/private-endpoints.md#get-account-balance
|
|
[Swap] https://github.com/zebpay/zebpay-api-references/blob/main/futures/api-reference/private-endpoints/wallet.md#get-wallet-balance
|
|
|
|
: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()
|
|
type = None
|
|
type, params = self.handle_market_type_and_params('fetchBalance', None, params)
|
|
isSpot = (type == 'spot')
|
|
response = None
|
|
if isSpot:
|
|
response = self.privateSpotGetV2AccountBalance(params)
|
|
else:
|
|
response = self.privateSwapGetV1WalletBalance(params)
|
|
#
|
|
# {
|
|
# "data": [
|
|
# {
|
|
# "free": 200,
|
|
# "used": 100,
|
|
# "total": 300,
|
|
# "currency": "INR"
|
|
# },
|
|
# {
|
|
# "free": 0,
|
|
# "used": 0,
|
|
# "total": 0,
|
|
# "currency": "USDT"
|
|
# }
|
|
# ]
|
|
# }
|
|
#
|
|
return self.parse_balance(response)
|
|
|
|
def create_order(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}):
|
|
"""
|
|
Create an order on the exchange
|
|
|
|
[Spot] https://github.com/zebpay/zebpay-api-references/blob/main/spot/api-reference/private-endpoints.md#place-new-order
|
|
[Swap] https://github.com/zebpay/zebpay-api-references/blob/main/futures/api-reference/private-endpoints/trade.md#--create-order
|
|
|
|
:param str symbol: Unified CCXT market symbol
|
|
:param str type: 'limit' or 'market'
|
|
:param str side: 'buy' or 'sell'
|
|
:param float amount: the amount of currency to trade
|
|
: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 str [params.formType]: The price at which a trigger order is triggered at
|
|
:param str [params.marginAsset]: The asset the order creates, default is INR.
|
|
:param boolean [params.takeProfit]: Takeprofit flag for the order.
|
|
:param boolean [params.stopLoss]: Stop loss flag for the order.
|
|
:param str [params.positionId]: PositionId of the order.
|
|
:returns dict: an `order structure <https://docs.ccxt.com/?id=order-structure>`
|
|
"""
|
|
self.load_markets()
|
|
market = self.market(symbol)
|
|
upperCaseType = type.upper()
|
|
takeProfitPrice = self.safe_string(params, 'takeProfitPrice')
|
|
stopLossPrice = self.safe_string(params, 'stopLossPrice')
|
|
params = self.omit(params, ['marginAsset', 'takeProfitPrice', 'takeProfitPrice'])
|
|
request: dict = {
|
|
'symbol': market['id'],
|
|
'side': side.upper(),
|
|
}
|
|
response = None
|
|
if market['spot']:
|
|
request, params = self.order_request(symbol, type, amount, request, price, params)
|
|
response = self.privateSpotPostV2ExOrders(self.extend(request, params))
|
|
else:
|
|
marginAsset = self.safe_string(params, 'marginAsset', 'INR')
|
|
formType = self.safe_string_upper(params, 'formType', 'ORDER_FORM')
|
|
request['formType'] = formType
|
|
request['amount'] = self.parse_to_numeric(self.amount_to_precision(market['id'], amount))
|
|
request['marginAsset'] = marginAsset
|
|
hasTP = takeProfitPrice is not None
|
|
hasSL = stopLossPrice is not None
|
|
if hasTP or hasSL:
|
|
if hasTP:
|
|
request['takeProfitPrice'] = self.parse_to_numeric(self.price_to_precision(symbol, takeProfitPrice))
|
|
if hasSL:
|
|
request['stopLossPrice'] = self.parse_to_numeric(self.price_to_precision(symbol, stopLossPrice))
|
|
response = self.privateSwapPostV1TradeOrderAddTPSL(self.extend(request, params))
|
|
else:
|
|
request['type'] = upperCaseType
|
|
if type == 'limit':
|
|
if price is None:
|
|
raise ArgumentsRequired(self.id + ' createOrder() requires a price argument for limit orders')
|
|
request['price'] = self.parse_to_numeric(self.price_to_precision(symbol, price))
|
|
response = self.privateSwapPostV1TradeOrder(self.extend(request, params))
|
|
#
|
|
# {
|
|
# "data": {
|
|
# "clientOrderId": "619717484f1d010001510cde",
|
|
# },
|
|
# }
|
|
#
|
|
data = self.safe_dict(response, 'data', {})
|
|
return self.parse_order(data, market)
|
|
|
|
def order_request(self, symbol, type, amount, request, price=None, params={}):
|
|
upperCaseType = type.upper()
|
|
triggerPrice = self.safe_string(params, 'stopLossPrice', None)
|
|
quoteOrderQty = self.safe_string_2(params, 'quoteOrderQty', 'cost', None)
|
|
timeInForce = self.safe_string(params, 'timeInForce', 'GTC')
|
|
clientOrderId = self.safe_string(params, 'clientOrderId', self.uuid())
|
|
params = self.omit(params, ['stopLossPrice', 'cost', 'timeInForce', 'clientOrderId'])
|
|
request['type'] = upperCaseType
|
|
request['clientOrderId'] = clientOrderId
|
|
request['timeInForce'] = timeInForce
|
|
if upperCaseType == 'MARKET':
|
|
if quoteOrderQty is None:
|
|
raise ExchangeError(self.id + ' spot market orders require cost in params')
|
|
request['quoteOrderAmount'] = self.cost_to_precision(symbol, quoteOrderQty)
|
|
else:
|
|
if triggerPrice is not None:
|
|
request['stopLossPrice'] = self.price_to_precision(symbol, triggerPrice)
|
|
request['amount'] = self.amount_to_precision(symbol, amount)
|
|
request['price'] = self.price_to_precision(symbol, price)
|
|
return [request, params]
|
|
|
|
def cancel_order(self, id: str, symbol: Str = None, params={}):
|
|
"""
|
|
cancels an open order
|
|
|
|
[Spot] https://github.com/zebpay/zebpay-api-references/blob/main/spot/api-reference/private-endpoints.md#cancel-order
|
|
[Swap] https://github.com/zebpay/zebpay-api-references/blob/main/futures/api-reference/private-endpoints/trade.md#-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
|
|
:param dict [params.timestamp]: 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)
|
|
response = None
|
|
request: dict = {}
|
|
if market['spot']:
|
|
request['orderId'] = id
|
|
response = self.privateSpotDeleteV2ExOrder(self.extend(request, params))
|
|
else:
|
|
clientOrderId = self.safe_string(params, 'clientOrderId')
|
|
if clientOrderId is None:
|
|
raise ArgumentsRequired(self.id + ' cancelOrder() requires a clientOrderId parameter for swap orders')
|
|
request['clientOrderId'] = clientOrderId
|
|
request['symbol'] = market['id']
|
|
response = self.privateSwapDeleteV1TradeOrder(self.extend(request, params))
|
|
#
|
|
# {
|
|
# "data": {
|
|
# "clientOrderId": "619714b8b6353000014c505a",
|
|
# "status": "canceled"
|
|
# },
|
|
# }
|
|
#
|
|
return self.parse_order(self.safe_dict(response, 'data'))
|
|
|
|
def cancel_all_orders(self, symbol: Str = None, params={}):
|
|
"""
|
|
cancels all open orders
|
|
|
|
[Spot] https://github.com/zebpay/zebpay-api-references/blob/main/spot/api-reference/private-endpoints.md#cancel-all-orders
|
|
|
|
: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 dict [params.timestamp]: extra parameters specific to the exchange API endpoint
|
|
:returns dict: An `order structure <https://docs.ccxt.com/?id=order-structure>`
|
|
"""
|
|
type = None
|
|
type, params = self.handle_market_type_and_params('cancelAllOrders', None, params)
|
|
if type != 'spot':
|
|
raise NotSupported(self.id + ' cancelAllOrders() does not support ' + type + ' markets')
|
|
self.load_markets()
|
|
response = self.privateSpotDeleteV2ExOrdersCancelAll(params)
|
|
#
|
|
# {
|
|
# "data": {
|
|
# "orderId": "12345",
|
|
# "symbol": 'BTC-INR
|
|
# },
|
|
# }
|
|
#
|
|
data = self.safe_dict(response, 'data', {})
|
|
parsedOrder = self.parse_order(data)
|
|
return [parsedOrder]
|
|
|
|
def fetch_open_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
|
|
"""
|
|
fetches information on multiple open orders made by the user
|
|
|
|
[Spot] https://github.com/zebpay/zebpay-api-references/blob/main/spot/api-reference/private-endpoints.md#get-orders
|
|
[Swap] https://github.com/zebpay/zebpay-api-references/blob/main/futures/api-reference/private-endpoints/trade.md#-get-open-orders
|
|
|
|
: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>`
|
|
"""
|
|
self.load_markets()
|
|
market = self.market(symbol)
|
|
request: dict = {
|
|
'symbol': market['id'],
|
|
}
|
|
response = None
|
|
orders = []
|
|
if market['spot']:
|
|
request['currentPage'] = 1
|
|
if limit is not None:
|
|
request['pageSize'] = limit
|
|
response = self.privateSpotGetV2ExOrders(self.extend(request, params))
|
|
responseData = self.safe_dict(response, 'data', {})
|
|
orders = self.safe_list(responseData, 'items', [])
|
|
else:
|
|
if since is not None:
|
|
request['since'] = since
|
|
if limit is not None:
|
|
request['limit'] = limit
|
|
response = self.privateSwapGetV1TradeOrderOpenOrders(self.extend(request, params))
|
|
responseData = self.safe_dict(response, 'data', {})
|
|
orders = self.safe_list(responseData, 'data', [])
|
|
#
|
|
# {
|
|
# "data": {
|
|
# "nextTimeStamp": null,
|
|
# "totalCount": 100,
|
|
# "data": [
|
|
# {
|
|
# "clientOrderId": "64507d02921f1c0001ff6892-123-zeb",
|
|
# "datetime": "2025-03-14T14:34:34.4567",
|
|
# "timestamp": 1741962557553,
|
|
# "status": "open",
|
|
# "symbol": "BTCINR",
|
|
# "type": "market",
|
|
# "timeInForce": "GTC",
|
|
# "side": "buy",
|
|
# "price": 700000,
|
|
# "amount": 0.002,
|
|
# "filled": null,
|
|
# "remaining": 0.002,
|
|
# "trades": []
|
|
# }
|
|
# ]
|
|
# }
|
|
# }
|
|
#
|
|
return self.parse_orders(orders, market, None, limit)
|
|
|
|
def fetch_order(self, id: Str, symbol: Str = None, params={}):
|
|
"""
|
|
fetches information on an order made by the user
|
|
|
|
[Spot] https://github.com/zebpay/zebpay-api-references/blob/main/spot/api-reference/private-endpoints.md#get-order-details
|
|
[Swap] https://github.com/zebpay/zebpay-api-references/blob/main/futures/api-reference/private-endpoints/trade.md#-get-order-details
|
|
|
|
: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
|
|
:param str [params.clientOrderId]: cancel order by client order id
|
|
:param str [params.timestamp]: cancel order by client order id
|
|
:returns dict: An `order structure <https://docs.ccxt.com/?id=order-structure>`
|
|
"""
|
|
self.load_markets()
|
|
market = self.market(symbol)
|
|
request: dict = {}
|
|
response = None
|
|
if market['spot']:
|
|
request['orderId'] = id
|
|
response = self.privateSpotGetV2ExOrder(self.extend(request, params))
|
|
else:
|
|
request['id'] = id
|
|
response = self.privateSwapGetV1TradeOrder(self.extend(request, params))
|
|
#
|
|
# {
|
|
# "data": {
|
|
# "nextTimeStamp": null,
|
|
# "totalCount": 100,
|
|
# "data": [
|
|
# {
|
|
# "clientOrderId": "64507d02921f1c0001ff6892-123-zeb",
|
|
# "datetime": "2025-03-14T14:34:34.4567",
|
|
# "timestamp": 1741962557553,
|
|
# "status": "open",
|
|
# "symbol": "BTCINR",
|
|
# "type": "market",
|
|
# "timeInForce": "GTC",
|
|
# "side": "buy",
|
|
# "price": 700000,
|
|
# "amount": 0.002,
|
|
# "filled": null,
|
|
# "remaining": 0.002,
|
|
# "trades": []
|
|
# }
|
|
# ]
|
|
# }
|
|
# }
|
|
#
|
|
responseData = self.safe_dict(response, 'data')
|
|
return self.parse_order(responseData, market)
|
|
|
|
def parse_order(self, order: dict, market: Market = None) -> Order:
|
|
#
|
|
# {
|
|
# "clientOrderId": "64507d02921f1c0001ff6892-123-zeb",
|
|
# "datetime": "2025-03-14T14:34:34.4567",
|
|
# "timestamp": 1741962557553,
|
|
# "status": "open",
|
|
# "symbol": "BTCINR",
|
|
# "type": "market",
|
|
# "timeInForce": "GTC",
|
|
# "side": "buy",
|
|
# "price": 700000,
|
|
# "amount": 0.002,
|
|
# "filled": null,
|
|
# "remaining": 0.002,
|
|
# "trades": []
|
|
# }
|
|
#
|
|
marketId = self.safe_string(order, 'symbol')
|
|
market = self.safe_market(marketId, market)
|
|
symbol = market['symbol']
|
|
type = self.safe_string(order, 'type')
|
|
timestamp = self.safe_number(order, 'timestamp')
|
|
datetime = self.iso8601(timestamp)
|
|
price = self.safe_string(order, 'price')
|
|
side = self.safe_string(order, 'side')
|
|
amount = self.safe_string(order, 'amount')
|
|
clientOrderId = self.safe_string(order, 'clientOrderId')
|
|
timeInForce = self.safe_string(order, 'timeInForce')
|
|
status = self.safe_string_lower(order, 'status')
|
|
orderId = self.safe_string(order, 'orderId', None)
|
|
parsedOrder = self.safe_order({
|
|
'id': orderId,
|
|
'clientOrderId': clientOrderId,
|
|
'symbol': symbol,
|
|
'type': type,
|
|
'timeInForce': timeInForce,
|
|
'postOnly': None,
|
|
'reduceOnly': None,
|
|
'side': side,
|
|
'amount': amount,
|
|
'price': price,
|
|
'triggerPrice': None,
|
|
'cost': None,
|
|
'filled': None,
|
|
'remaining': None,
|
|
'timestamp': timestamp,
|
|
'datetime': datetime,
|
|
'fee': None,
|
|
'status': status,
|
|
'info': order,
|
|
'lastTradeTimestamp': None,
|
|
'lastUpdateTimestamp': None,
|
|
'average': None,
|
|
'trades': None,
|
|
}, market)
|
|
return parsedOrder
|
|
|
|
def close_position(self, symbol: str, side: OrderSide = None, params={}) -> Order:
|
|
"""
|
|
closes open positions for a market
|
|
|
|
[Swap] https://github.com/zebpay/zebpay-api-references/blob/main/futures/api-reference/private-endpoints/trade.md#-close-position
|
|
|
|
:param str symbol: Unified CCXT market symbol
|
|
:param str side: not used by kucoinfutures closePositions
|
|
:param dict [params]: extra parameters specific to the okx api endpoint
|
|
:param str [params.positionId]: client order id of the order
|
|
:returns dict[]: `A list of position structures <https://docs.ccxt.com/?id=position-structure>`
|
|
"""
|
|
self.load_markets()
|
|
market = self.market(symbol)
|
|
request: dict = {
|
|
'symbol': market['id'],
|
|
}
|
|
response = self.privateSwapPostV1TradePositionClose(self.extend(request, params))
|
|
data = self.safe_dict(response, 'data', {})
|
|
return self.parse_order(data, market)
|
|
|
|
def fetch_leverages(self, symbols: Strings = None, params={}) -> Leverages:
|
|
"""
|
|
fetch the set leverage for all contract and margin markets
|
|
|
|
[Swap] https://github.com/zebpay/zebpay-api-references/blob/main/futures/api-reference/private-endpoints/trade.md#-get-all-user-leverages
|
|
|
|
:param str[] [symbols]: a list of unified market symbols
|
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
:returns dict: a list of `leverage structures <https://docs.ccxt.com/?id=leverage-structure>`
|
|
"""
|
|
self.load_markets()
|
|
response = self.privateSwapGetV1TradeUserLeverages(params)
|
|
#
|
|
# {
|
|
# "leveragePreferences": [
|
|
# {
|
|
# "symbol": "ETHINR",
|
|
# "shortLeverage": 1,
|
|
# "longLeverage": 10,
|
|
# "marginMode": "isolated"
|
|
# },
|
|
# ]
|
|
# }
|
|
#
|
|
leveragePreferences = self.safe_list(response, 'data', [])
|
|
return self.parse_leverages(leveragePreferences, symbols, 'symbol')
|
|
|
|
def fetch_leverage(self, symbol: str, params={}) -> Leverage:
|
|
"""
|
|
fetch the set leverage for a market
|
|
|
|
[Swap] https://github.com/zebpay/zebpay-api-references/blob/main/futures/api-reference/private-endpoints/trade.md#get-user-leverage-single-symbol
|
|
|
|
: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 = {
|
|
'symbol': market['id'].upper(),
|
|
}
|
|
response = self.privateSwapGetV1TradeUserLeverage(self.extend(request, params))
|
|
#
|
|
# {
|
|
# "data": {symbol: "ETHINR", longLeverage: 1, shortLeverage: 1, marginMode: "isolated"}
|
|
# }
|
|
#
|
|
data = self.safe_dict(response, 'data', {})
|
|
return self.parse_leverage(data, market)
|
|
|
|
def set_leverage(self, leverage: int, symbol: Str = None, params={}):
|
|
"""
|
|
set the level of leverage for a market
|
|
|
|
[Swap] https://github.com/zebpay/zebpay-api-references/blob/main/futures/api-reference/private-endpoints/trade.md#-update-user-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 = {
|
|
'leverage': leverage,
|
|
'symbol': market['id'],
|
|
}
|
|
#
|
|
# {data: {"symbol", "longLeverage": 10, "shortLeverage": 1, "marginMode": "isolated"}
|
|
#
|
|
response = self.privateSwapPostV1TradeUpdateUserLeverage(self.extend(request, params))
|
|
return response
|
|
|
|
def fetch_positions(self, symbols: Strings = None, params={}):
|
|
"""
|
|
|
|
[Swap] https://github.com/zebpay/zebpay-api-references/blob/main/futures/api-reference/private-endpoints/trade.md#--get-positions
|
|
|
|
Fetches current contract trading positions
|
|
:param str[] symbols: List of unified symbols
|
|
:param dict [params]: Not used by krakenfutures
|
|
:returns: Parsed exchange response for positions
|
|
"""
|
|
self.load_markets()
|
|
request = {}
|
|
if symbols is not None:
|
|
request['symbols'] = self.market_ids(symbols)
|
|
response = self.privateSwapGetV1TradePositions(self.extend(request, params))
|
|
#
|
|
# {
|
|
# "data": [
|
|
# {
|
|
# "id": "31998678-6056-413f-9d0d-fc3678641650",
|
|
# "symbol": "ETHINR",
|
|
# "entryPrice": "0.7533",
|
|
# "datetime": "2022-03-03T22:51:16.566Z",
|
|
# "contractSize": "230"
|
|
# }
|
|
# ],
|
|
# }
|
|
#
|
|
positions = self.safe_list(response, 'data', [])
|
|
result = self.parse_positions(positions)
|
|
return self.filter_by_array_positions(result, 'symbol', symbols, False)
|
|
|
|
def add_margin(self, symbol: str, amount: float, params={}) -> MarginModification:
|
|
"""
|
|
add margin
|
|
|
|
[Swap] https://github.com/zebpay/zebpay-api-references/blob/main/futures/api-reference/private-endpoints/trade.md#-add-margin-to-position
|
|
|
|
: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.
|
|
:param str [params.positionId]: PositionId of the order to add margin.
|
|
:param str [params.timestamp]: Tiemstamp.
|
|
:returns dict: a `margin structure <https://docs.ccxt.com/?id=margin-structure>`
|
|
"""
|
|
self.load_markets()
|
|
market = self.market(symbol)
|
|
request: dict = {
|
|
'symbol': market['id'],
|
|
'amount': amount,
|
|
}
|
|
response = self.privateSwapPostV1TradeAddMargin(self.extend(request, params))
|
|
#
|
|
# {
|
|
# "code": "200000",
|
|
# "data": {
|
|
# "symbol": "BTCINR",
|
|
# "type": "add",
|
|
# "amount": 1000,
|
|
# "code": "INR",
|
|
# "status": "ok"
|
|
# }
|
|
# }
|
|
#
|
|
#
|
|
# {
|
|
# "code":"200000",
|
|
# "msg":"Position does not exist"
|
|
# }
|
|
#
|
|
data = self.safe_dict(response, 'data', {})
|
|
return self.extend(self.parse_margin_modification(data, market), {
|
|
'amount': amount,
|
|
'direction': 'in',
|
|
})
|
|
|
|
def reduce_margin(self, symbol: str, amount: float, params={}) -> MarginModification:
|
|
"""
|
|
add margin
|
|
|
|
[Swap] https://github.com/zebpay/zebpay-api-references/blob/main/futures/api-reference/private-endpoints/trade.md#-reduce-margin-from-position
|
|
|
|
: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.
|
|
:param str [params.positionId]: PositionId of the order to add margin.
|
|
:param str [params.timestamp]: Tiemstamp.
|
|
:returns dict: a `margin structure <https://docs.ccxt.com/?id=margin-structure>`
|
|
"""
|
|
self.load_markets()
|
|
market = self.market(symbol)
|
|
request: dict = {
|
|
'symbol': market['id'],
|
|
'amount': amount,
|
|
}
|
|
response = self.privateSwapPostV1TradeReduceMargin(self.extend(request, params))
|
|
#
|
|
# {
|
|
# "code": "200000",
|
|
# "data": {
|
|
# "symbol": "BTCINR",
|
|
# "type": "reduce",
|
|
# "amount": 1000,
|
|
# "code": "INR",
|
|
# "status": "ok"
|
|
# }
|
|
# }
|
|
#
|
|
data = self.safe_dict(response, 'data', {})
|
|
return self.extend(self.parse_margin_modification(data, market), {
|
|
'amount': amount,
|
|
'direction': 'out',
|
|
})
|
|
|
|
def fetch_spot_markets(self, params={}) -> List[Market]:
|
|
response = self.publicSpotGetV2ExExchangeInfo(params)
|
|
#
|
|
# {
|
|
# "data": {
|
|
# "symbol": "ETH-INR",
|
|
# "name": "ETH-INR",
|
|
# "baseCurrency": "ETH",
|
|
# "quoteCurrency": "INR",
|
|
# "feeCurrency": "INR",
|
|
# "baseMinSize": "",
|
|
# "quoteMinSize": "100",
|
|
# "baseMaxSize": "",
|
|
# "quoteMaxSize": "2000",
|
|
# "baseIncrement": "0.00001"
|
|
# "quoteIncrement": "0.00001",
|
|
# "enableTrading": True
|
|
# }
|
|
# }
|
|
#
|
|
result = []
|
|
data = self.safe_dict(response, 'data', {})
|
|
markets = self.safe_list(data, 'symbols', [])
|
|
for i in range(0, len(markets)):
|
|
market = markets[i]
|
|
id = self.safe_string(market, 'symbol')
|
|
baseId = self.safe_string(market, 'baseAsset')
|
|
quoteId = self.safe_string(market, 'quoteAsset')
|
|
base = self.safe_currency_code(baseId)
|
|
quote = self.safe_currency_code(quoteId)
|
|
symbol = base + '/' + quote
|
|
result.append({
|
|
'id': id,
|
|
'symbol': symbol,
|
|
'base': base,
|
|
'quote': quote,
|
|
'baseId': baseId,
|
|
'quoteId': quoteId,
|
|
'type': 'spot',
|
|
'spot': True,
|
|
'swap': False,
|
|
'margin': False,
|
|
'future': False,
|
|
'option': False,
|
|
'active': None,
|
|
'contract': None,
|
|
'taker': self.safe_number(market, 'takerFee'),
|
|
'maker': self.safe_number(market, 'makerFee'),
|
|
'strike': None,
|
|
'optionType': None,
|
|
'precision': {
|
|
'amount': self.safe_number(market, 'lotSz'),
|
|
'price': self.safe_number(market, 'tickSz'),
|
|
},
|
|
'limits': {
|
|
'amount': {
|
|
'min': None,
|
|
'max': None,
|
|
},
|
|
'price': {
|
|
'min': None,
|
|
'max': None,
|
|
},
|
|
'cost': {
|
|
'min': None,
|
|
'max': None,
|
|
},
|
|
},
|
|
'info': market,
|
|
})
|
|
return result
|
|
|
|
def fetch_swap_markets(self, params={}) -> List[Market]:
|
|
response = self.publicSwapGetV1MarketMarkets(params)
|
|
#
|
|
# {
|
|
# "data": {
|
|
# "symbol": "ETHUSDT",
|
|
# "status": "TRADING",
|
|
# "mainMarginPercent": "10",
|
|
# "baseAsset": "ETH",
|
|
# "quoteAsset": "USDT",
|
|
# "pricePrecision": 1,
|
|
# "quantityPrecision": 0.05,
|
|
# "baseAssetPrecision": 0,
|
|
# "quotePrecision": 0,
|
|
# "orderType": ["LIMIT", "MARKET"]
|
|
# "timeInForce": ["GTC"],
|
|
# "makerFee": "0.01",
|
|
# "takerFee": "0.01",
|
|
# "minLeverage": "1",
|
|
# "maxLeverage": "20"
|
|
# "tickSz": "0.1",
|
|
# "lotSz": "0.1"
|
|
# }
|
|
# }
|
|
#
|
|
result = []
|
|
data = self.safe_dict(response, 'data', {})
|
|
markets = self.safe_list(data, 'symbols', [])
|
|
for i in range(0, len(markets)):
|
|
market = markets[i]
|
|
id = self.safe_string(market, 'symbol')
|
|
baseId = self.safe_string(market, 'baseAsset')
|
|
quoteId = self.safe_string(market, 'quoteAsset')
|
|
base = self.safe_currency_code(baseId)
|
|
quote = self.safe_currency_code(quoteId)
|
|
settle = self.safe_currency_code(quoteId)
|
|
status = self.safe_string(market, 'status')
|
|
symbol = base + '/' + quote
|
|
result.append(self.safe_market_structure({
|
|
'id': id,
|
|
'symbol': symbol + ':' + settle,
|
|
'base': base,
|
|
'quote': quote,
|
|
'baseId': baseId,
|
|
'quoteId': quoteId,
|
|
'spot': False,
|
|
'margin': False,
|
|
'swap': True,
|
|
'future': False,
|
|
'type': 'swap',
|
|
'option': False,
|
|
'active': (status == 'Open'),
|
|
'contract': True,
|
|
'taker': self.safe_number(market, 'takerFee'),
|
|
'maker': self.safe_number(market, 'makerFee'),
|
|
'strike': None,
|
|
'optionType': None,
|
|
'precision': {
|
|
'amount': self.safe_number(market, 'lotSz'),
|
|
'price': self.safe_number(market, 'tickSz'),
|
|
},
|
|
'limits': {
|
|
'leverage': {
|
|
'min': self.safe_number(market, 'minLeverage'),
|
|
'max': self.safe_number(market, 'maxLeverage'),
|
|
},
|
|
},
|
|
'info': market,
|
|
}))
|
|
return result
|
|
|
|
def parse_balance(self, response) -> Balances:
|
|
result: dict = {
|
|
'info': response,
|
|
'timestamp': None,
|
|
'datetime': None,
|
|
}
|
|
currencyList = self.safe_list(response, 'data', [])
|
|
for i in range(0, len(currencyList)):
|
|
entry = currencyList[i]
|
|
account = self.account()
|
|
account['total'] = self.safe_string(entry, 'total')
|
|
account['free'] = self.safe_string(entry, 'free')
|
|
account['used'] = self.safe_string(entry, 'used')
|
|
currencyId = self.safe_string(entry, 'currency')
|
|
code = self.safe_currency_code(currencyId)
|
|
result[code] = account
|
|
return self.safe_balance(result)
|
|
|
|
def parse_position(self, position: dict, market: Market = None):
|
|
#
|
|
# isolated
|
|
# {
|
|
# "id":"long",
|
|
# "symbol":"pf_ftmusd",
|
|
# "entryPrice":"0.4921",
|
|
# "datetime":"2023-02-22T11:37:16.685Z",
|
|
# "contractSize":"1",
|
|
# "leverage":"1.0"
|
|
# }
|
|
#
|
|
leverage = self.safe_number(position, 'leverage')
|
|
datetime = self.safe_string(position, 'datetime')
|
|
marketId = self.safe_string(position, 'symbol')
|
|
market = self.safe_market(marketId, market)
|
|
return {
|
|
'info': position,
|
|
'symbol': marketId,
|
|
'timestamp': self.parse8601(datetime),
|
|
'datetime': datetime,
|
|
'initialMargin': self.safe_number(position, 'initialMargin'),
|
|
'initialMarginPercentage': None,
|
|
'maintenanceMargin': None,
|
|
'maintenanceMarginPercentage': None,
|
|
'entryPrice': self.safe_number(position, 'entryPrice'),
|
|
'notional': self.safe_number(position, 'notional'),
|
|
'leverage': leverage,
|
|
'unrealizedPnl': None,
|
|
'contracts': self.safe_number(position, 'contracts'),
|
|
'contractSize': self.safe_number(market, 'contractSize'),
|
|
'marginRatio': None,
|
|
'liquidationPrice': self.safe_number(position, 'liquidationPrice'),
|
|
'markPrice': None,
|
|
'collateral': None,
|
|
'marginType': 'isolated',
|
|
'side': self.safe_string(position, 'side'),
|
|
'percentage': None,
|
|
}
|
|
|
|
def parse_leverage(self, leverage: dict, market: Market = None) -> Leverage:
|
|
marketId = self.safe_string(leverage, 'symbol')
|
|
info = self.safe_dict(leverage, 'info')
|
|
leverageValue = self.safe_integer(leverage, 'longLeverage')
|
|
leverageValueShort = self.safe_integer(leverage, 'shortLeverage')
|
|
marginMode = self.safe_string(leverage, 'marginMode')
|
|
return {
|
|
'info': info,
|
|
'symbol': marketId,
|
|
'marginMode': marginMode,
|
|
'longLeverage': leverageValue,
|
|
'shortLeverage': leverageValueShort,
|
|
}
|
|
|
|
def parse_trading_fee(self, fee: dict, market: Market = None) -> TradingFeeInterface:
|
|
marketId = self.safe_string(fee, 'symbol')
|
|
symbol = self.safe_symbol(marketId, market)
|
|
return {
|
|
'info': fee,
|
|
'symbol': symbol,
|
|
'maker': self.safe_number_2(fee, 'makerFeeRate', 'makerFee'),
|
|
'taker': self.safe_number_2(fee, 'takerFeeRate', 'takerFee'),
|
|
'percentage': None,
|
|
'tierBased': None,
|
|
}
|
|
|
|
def parse_ticker(self, ticker: dict, market: Market = None) -> Ticker:
|
|
#
|
|
# [
|
|
# {
|
|
# "symbol": "BTC-INR",
|
|
# "bestBid": "4900000",
|
|
# "bestBidQty": "0.00014938",
|
|
# "bestAsk": "",
|
|
# "bestAskQty": "0",
|
|
# "priceChange": "-98134.56",
|
|
# "priceChangePercent": "-1.84",
|
|
# "high": "5433400",
|
|
# "low": "5333400",
|
|
# "vol": "0.0002",
|
|
# "volValue": "1066.68",
|
|
# "last": "5333400"
|
|
# }
|
|
# ]
|
|
#
|
|
timestamp = self.safe_integer_2(ticker, 'timestamp', 'ts')
|
|
marketId = self.safe_string(ticker, 'symbol')
|
|
market = self.safe_market(marketId)
|
|
close = self.safe_string(ticker, 'close')
|
|
last = self.safe_string(ticker, 'last')
|
|
percentage = self.safe_string(ticker, 'percentage')
|
|
bidVolume = self.safe_string(ticker, 'bidVolume')
|
|
askVolume = self.safe_string(ticker, 'askVolume')
|
|
return self.safe_ticker({
|
|
'id': marketId,
|
|
'symbol': market['symbol'],
|
|
'timestamp': timestamp,
|
|
'datetime': self.iso8601(timestamp),
|
|
'high': self.safe_string(ticker, 'high'),
|
|
'low': self.safe_string(ticker, 'low'),
|
|
'bid': self.safe_string(ticker, 'bid'),
|
|
'bidVolume': bidVolume,
|
|
'ask': self.safe_string(ticker, 'ask'),
|
|
'askVolume': askVolume,
|
|
'vwap': None,
|
|
'open': None,
|
|
'close': close,
|
|
'last': last,
|
|
'previousClose': self.safe_string(ticker, 'previousClose'),
|
|
'change': self.safe_string(ticker, 'change'),
|
|
'percentage': percentage,
|
|
'average': self.safe_string(ticker, 'average'),
|
|
'baseVolume': self.safe_string(ticker, 'baseVolume'),
|
|
'quoteVolume': self.safe_string(ticker, 'quoteVolume'),
|
|
'markPrice': None,
|
|
'info': ticker,
|
|
}, market)
|
|
|
|
def parse_margin_modification(self, info, market: Market = None) -> MarginModification:
|
|
#
|
|
# {
|
|
# "symbol": "BTCINR",
|
|
# "type": "reduce",
|
|
# "amount": 1000,
|
|
# "code": "INR",
|
|
# "status": "ok"
|
|
# }
|
|
#
|
|
timestamp = self.milliseconds()
|
|
return {
|
|
'info': info,
|
|
'symbol': market['id'],
|
|
'type': None,
|
|
'marginMode': None,
|
|
'amount': self.safe_number(info, 'amount'),
|
|
'total': None,
|
|
'code': self.safe_string(info, 'code'),
|
|
'status': self.safe_string(info, 'status'),
|
|
'timestamp': timestamp,
|
|
'datetime': self.iso8601(timestamp),
|
|
}
|
|
|
|
def sign(self, path, api='public', method='GET', params={}, headers=None, body=None):
|
|
params = self.omit(params, 'defaultType')
|
|
isV1 = path.find('v1/') > -1
|
|
marketType = 'swap' if isV1 else 'spot'
|
|
url = self.urls['api'][marketType]
|
|
tail = '/api/' + self.implode_params(path, params)
|
|
url += tail
|
|
timestamp = str(self.milliseconds())
|
|
signature = ''
|
|
query = self.omit(params, self.extract_params(path))
|
|
queryLength = query
|
|
access = self.safe_string(api, 0, 'public')
|
|
if access == 'public':
|
|
if method == 'GET' or method == 'DELETE':
|
|
if queryLength:
|
|
url += '?' + self.urlencode(query)
|
|
else:
|
|
body = json.dumps(params)
|
|
headers = {
|
|
'Referrer': 'ccxt',
|
|
'Content-Type': 'application/json',
|
|
}
|
|
else:
|
|
self.check_required_credentials()
|
|
isSpot = marketType == 'spot'
|
|
params['timestamp'] = timestamp
|
|
if method == 'GET' or (method == 'DELETE' and isSpot):
|
|
# For GET/DELETE: Append params to URL and sign the query string
|
|
queryString = self.urlencode(params)
|
|
signature = self.hmac(self.encode(queryString), self.encode(self.secret), hashlib.sha256, 'hex')
|
|
url += '?' + queryString
|
|
else:
|
|
# For POST/PUT: Convert body to JSON and sign the stringified payload
|
|
body = self.json(params)
|
|
signature = self.hmac(self.encode(body), self.encode(self.secret), hashlib.sha256, 'hex')
|
|
headers = {
|
|
'Referrer': 'ccxt',
|
|
'X-AUTH-APIKEY': self.apiKey,
|
|
'X-AUTH-SIGNATURE': signature,
|
|
}
|
|
headers['Content-Type'] = 'application/json'
|
|
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 not response:
|
|
self.throw_broadly_matched_exception(self.exceptions['broad'], body, body)
|
|
return None
|
|
#
|
|
# bad
|
|
# {"code": "400100", "msg": "validation.createOrder.clientOidIsRequired"}
|
|
# good
|
|
# {code: "200000", data: {...}}
|
|
# {"statusDescription":"Order quantity is out of range","data":{},"statusCode":400,"customMessage":["Order quantity is out of range"]}
|
|
#
|
|
errorCode = self.safe_string_2(response, 'code', 'statusCode')
|
|
message = self.safe_string_2(response, 'msg', 'statusDescription')
|
|
feedback = self.id + ' ' + message
|
|
self.throw_broadly_matched_exception(self.exceptions['broad'], message, feedback)
|
|
self.throw_exactly_matched_exception(self.exceptions['exact'], message, feedback)
|
|
self.throw_exactly_matched_exception(self.exceptions['exact'], errorCode, feedback)
|
|
return None
|