ccxt 3.1.60__py2.py3-none-any.whl → 4.0.3__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ccxt/__init__.py +1 -1
- ccxt/async_support/__init__.py +1 -1
- ccxt/async_support/base/exchange.py +1 -1
- ccxt/base/exchange.py +1 -1
- ccxt/pro/__init__.py +1 -1
- {ccxt-3.1.60.dist-info → ccxt-4.0.3.dist-info}/METADATA +4 -4
- {ccxt-3.1.60.dist-info → ccxt-4.0.3.dist-info}/RECORD +9 -23
- ccxt/async_support/btcex.py +0 -2519
- ccxt/async_support/buda.py +0 -1063
- ccxt/async_support/itbit.py +0 -771
- ccxt/async_support/ripio.py +0 -1102
- ccxt/async_support/stex.py +0 -2508
- ccxt/async_support/xt.py +0 -4420
- ccxt/async_support/zb.py +0 -4127
- ccxt/btcex.py +0 -2519
- ccxt/buda.py +0 -1063
- ccxt/itbit.py +0 -771
- ccxt/ripio.py +0 -1102
- ccxt/stex.py +0 -2508
- ccxt/xt.py +0 -4419
- ccxt/zb.py +0 -4126
- {ccxt-3.1.60.dist-info → ccxt-4.0.3.dist-info}/WHEEL +0 -0
- {ccxt-3.1.60.dist-info → ccxt-4.0.3.dist-info}/top_level.txt +0 -0
ccxt/async_support/btcex.py
DELETED
@@ -1,2519 +0,0 @@
|
|
1
|
-
# -*- coding: utf-8 -*-
|
2
|
-
|
3
|
-
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
4
|
-
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
5
|
-
|
6
|
-
from ccxt.async_support.base.exchange import Exchange
|
7
|
-
from ccxt.abstract.btcex import ImplicitAPI
|
8
|
-
from ccxt.base.types import OrderSide
|
9
|
-
from ccxt.base.types import OrderType
|
10
|
-
from typing import Optional
|
11
|
-
from typing import List
|
12
|
-
from ccxt.base.errors import ExchangeError
|
13
|
-
from ccxt.base.errors import PermissionDenied
|
14
|
-
from ccxt.base.errors import ArgumentsRequired
|
15
|
-
from ccxt.base.errors import BadRequest
|
16
|
-
from ccxt.base.errors import InsufficientFunds
|
17
|
-
from ccxt.base.errors import InvalidAddress
|
18
|
-
from ccxt.base.errors import InvalidOrder
|
19
|
-
from ccxt.base.errors import OrderNotFound
|
20
|
-
from ccxt.base.errors import NotSupported
|
21
|
-
from ccxt.base.errors import DDoSProtection
|
22
|
-
from ccxt.base.errors import ExchangeNotAvailable
|
23
|
-
from ccxt.base.errors import RequestTimeout
|
24
|
-
from ccxt.base.errors import AuthenticationError
|
25
|
-
from ccxt.base.decimal_to_precision import TICK_SIZE
|
26
|
-
from ccxt.base.precise import Precise
|
27
|
-
|
28
|
-
|
29
|
-
class btcex(Exchange, ImplicitAPI):
|
30
|
-
|
31
|
-
def describe(self):
|
32
|
-
return self.deep_extend(super(btcex, self).describe(), {
|
33
|
-
'id': 'btcex',
|
34
|
-
'name': 'BTCEX',
|
35
|
-
'countries': ['CA'], # Canada
|
36
|
-
'version': 'v1',
|
37
|
-
'certified': False,
|
38
|
-
'pro': True,
|
39
|
-
'requiredCredentials': {
|
40
|
-
'apiKey': True,
|
41
|
-
'secret': True,
|
42
|
-
},
|
43
|
-
'urls': {
|
44
|
-
'logo': 'https://user-images.githubusercontent.com/1294454/173489620-d49807a4-55cd-4f4e-aca9-534921298bbf.jpg',
|
45
|
-
'www': 'https://www.btcex.com/',
|
46
|
-
'api': {
|
47
|
-
'rest': 'https://api.btcex.com',
|
48
|
-
},
|
49
|
-
'doc': 'https://docs.btcex.com/',
|
50
|
-
'fees': 'https://support.btcex.com/hc/en-us/articles/4415995130647',
|
51
|
-
'referral': {
|
52
|
-
'url': 'https://www.btcex.com/en-us/register?i=48biatg1',
|
53
|
-
'discount': 0.1,
|
54
|
-
},
|
55
|
-
},
|
56
|
-
'has': {
|
57
|
-
'CORS': None,
|
58
|
-
'spot': True,
|
59
|
-
'margin': True,
|
60
|
-
'swap': True,
|
61
|
-
'future': True,
|
62
|
-
'option': True,
|
63
|
-
'cancelAllOrders': True,
|
64
|
-
'cancelOrder': True,
|
65
|
-
'createLimitBuyOrder': True,
|
66
|
-
'createLimitSellOrder': True,
|
67
|
-
'createMarketBuyOrder': True,
|
68
|
-
'createMarketSellOrder': True,
|
69
|
-
'createOrder': True,
|
70
|
-
'createPostOnlyOrder': True,
|
71
|
-
'createReduceOnlyOrder': True,
|
72
|
-
'createStopLimitOrder': True,
|
73
|
-
'createStopMarketOrder': True,
|
74
|
-
'createStopOrder': True,
|
75
|
-
'editOrder': False,
|
76
|
-
'fetchBalance': True,
|
77
|
-
'fetchBorrowRate': False,
|
78
|
-
'fetchBorrowRateHistories': False,
|
79
|
-
'fetchBorrowRateHistory': False,
|
80
|
-
'fetchBorrowRates': False,
|
81
|
-
'fetchClosedOrders': True,
|
82
|
-
'fetchCurrencies': False,
|
83
|
-
'fetchDepositAddress': False,
|
84
|
-
'fetchDeposits': True,
|
85
|
-
'fetchFundingHistory': False,
|
86
|
-
'fetchFundingRate': True,
|
87
|
-
'fetchFundingRateHistory': False,
|
88
|
-
'fetchFundingRates': True,
|
89
|
-
'fetchIndexOHLCV': False,
|
90
|
-
'fetchLeverage': True,
|
91
|
-
'fetchLeverageTiers': True,
|
92
|
-
'fetchMarginMode': False,
|
93
|
-
'fetchMarketLeverageTiers': True,
|
94
|
-
'fetchMarkets': True,
|
95
|
-
'fetchMarkOHLCV': False,
|
96
|
-
'fetchMyTrades': True,
|
97
|
-
'fetchOHLCV': True,
|
98
|
-
'fetchOpenInterest': True,
|
99
|
-
'fetchOpenInterestHistory': False,
|
100
|
-
'fetchOpenOrders': True,
|
101
|
-
'fetchOrder': True,
|
102
|
-
'fetchOrderBook': True,
|
103
|
-
'fetchOrders': True,
|
104
|
-
'fetchOrderTrades': True,
|
105
|
-
'fetchPosition': True,
|
106
|
-
'fetchPositionMode': False,
|
107
|
-
'fetchPositions': True,
|
108
|
-
'fetchPremiumIndexOHLCV': False,
|
109
|
-
'fetchTicker': True,
|
110
|
-
'fetchTickers': False,
|
111
|
-
'fetchTime': False,
|
112
|
-
'fetchTrades': True,
|
113
|
-
'fetchTradingFee': False,
|
114
|
-
'fetchTradingFees': False,
|
115
|
-
'fetchTransactionFees': None,
|
116
|
-
'fetchWithdrawal': True,
|
117
|
-
'fetchWithdrawals': True,
|
118
|
-
'setLeverage': True,
|
119
|
-
'setMarginMode': True,
|
120
|
-
'signIn': True,
|
121
|
-
'transfer': True,
|
122
|
-
'withdraw': False,
|
123
|
-
},
|
124
|
-
'timeframes': {
|
125
|
-
'1m': '1',
|
126
|
-
'3m': '3',
|
127
|
-
'5m': '5',
|
128
|
-
'15m': '15',
|
129
|
-
'30m': '30',
|
130
|
-
'1h': '60',
|
131
|
-
'2h': '120',
|
132
|
-
'3h': '180',
|
133
|
-
'4h': '240',
|
134
|
-
'6h': '360',
|
135
|
-
'12h': '720',
|
136
|
-
'1d': '1D',
|
137
|
-
'3d': '3D',
|
138
|
-
'1M': '30D',
|
139
|
-
},
|
140
|
-
'api': {
|
141
|
-
'public': {
|
142
|
-
'get': [
|
143
|
-
# Market data
|
144
|
-
'get_last_trades_by_currency',
|
145
|
-
'get_last_trades_by_instrument',
|
146
|
-
'get_order_book',
|
147
|
-
'tickers',
|
148
|
-
'get_instruments',
|
149
|
-
'get_tradingview_chart_data',
|
150
|
-
# CMC
|
151
|
-
'cmc_spot_summary',
|
152
|
-
'cmc_spot_ticker',
|
153
|
-
'cmc_spot_orderbook',
|
154
|
-
'cmc_market_trades',
|
155
|
-
'cmc_contracts',
|
156
|
-
'cmc_contract_orderbook',
|
157
|
-
# CoinGecko
|
158
|
-
'coin_gecko_spot_pairs',
|
159
|
-
'coin_gecko_spot_ticker',
|
160
|
-
'coin_gecko_spot_orderbook',
|
161
|
-
'coin_gecko_market_trades',
|
162
|
-
'coin_gecko_contracts',
|
163
|
-
'coin_gecko_contract_orderbook',
|
164
|
-
'get_perpetual_leverage_bracket',
|
165
|
-
'get_perpetual_leverage_bracket_all',
|
166
|
-
],
|
167
|
-
'post': [
|
168
|
-
'auth',
|
169
|
-
],
|
170
|
-
},
|
171
|
-
'private': {
|
172
|
-
'get': [
|
173
|
-
# wallet
|
174
|
-
'get_deposit_record',
|
175
|
-
'get_withdraw_record',
|
176
|
-
# trade
|
177
|
-
'get_position',
|
178
|
-
'get_positions',
|
179
|
-
'get_open_orders_by_currency',
|
180
|
-
'get_open_orders_by_instrument',
|
181
|
-
'get_order_history_by_currency',
|
182
|
-
'get_order_history_by_instrument',
|
183
|
-
'get_order_state',
|
184
|
-
'get_user_trades_by_currency',
|
185
|
-
'get_user_trades_by_instrument',
|
186
|
-
'get_user_trades_by_order',
|
187
|
-
'get_perpetual_user_config',
|
188
|
-
],
|
189
|
-
'post': [
|
190
|
-
# auth
|
191
|
-
'logout',
|
192
|
-
# wallet
|
193
|
-
'get_assets_info',
|
194
|
-
'add_withdraw_address',
|
195
|
-
# trade
|
196
|
-
'buy',
|
197
|
-
'sell',
|
198
|
-
'cancel',
|
199
|
-
'cancel_all_by_currency',
|
200
|
-
'cancel_all_by_instrument',
|
201
|
-
'close_position',
|
202
|
-
'adjust_perpetual_leverage',
|
203
|
-
'adjust_perpetual_margin_type',
|
204
|
-
'submit_transfer',
|
205
|
-
],
|
206
|
-
'delete': [],
|
207
|
-
},
|
208
|
-
},
|
209
|
-
'fees': {
|
210
|
-
'trading': {
|
211
|
-
'tierBased': False,
|
212
|
-
'percentage': True,
|
213
|
-
'maker': self.parse_number('0.001'),
|
214
|
-
'taker': self.parse_number('0.001'),
|
215
|
-
},
|
216
|
-
'margin': {
|
217
|
-
'tierBased': False,
|
218
|
-
'percentage': True,
|
219
|
-
'maker': self.parse_number('0.001'),
|
220
|
-
'taker': self.parse_number('0.001'),
|
221
|
-
},
|
222
|
-
'perpetual': {
|
223
|
-
'tierBased': False,
|
224
|
-
'percentage': True,
|
225
|
-
'maker': self.parse_number('0.002'),
|
226
|
-
'taker': self.parse_number('0.002'),
|
227
|
-
},
|
228
|
-
},
|
229
|
-
'exceptions': {
|
230
|
-
'exact': {
|
231
|
-
'9999': ExchangeError, # SYSTEM_INNER_ERROR System error, please try again later
|
232
|
-
'9900': ExchangeNotAvailable, # SERVICE_BUSY Service is busy,please try again later
|
233
|
-
'401': AuthenticationError, # UNAUTHENTICATION_ERROR UnAuthentication
|
234
|
-
'403': AuthenticationError, # ACCESS_DENIED_ERROR Access denied
|
235
|
-
'1000': ExchangeNotAvailable, # NO_SERVICE No service found
|
236
|
-
'1001': BadRequest, # BAD_REQUEST Bad requested
|
237
|
-
'1005': DDoSProtection, # {"code":1005,"message":"Operate too frequently"}
|
238
|
-
'2000': AuthenticationError, # NEED_LOGIN Login is required
|
239
|
-
'2001': AuthenticationError, # ACCOUNT_NOT_MATCH Account information does not match
|
240
|
-
'2002': AuthenticationError, # ACCOUNT_NEED_ENABLE Account needs to be activated
|
241
|
-
'2003': AuthenticationError, # ACCOUNT_NOT_AVAILABLE Account not available
|
242
|
-
'2010': PermissionDenied, # {"code":2010,"message":"Access denied","data":{}}
|
243
|
-
'3000': AuthenticationError, # TEST user
|
244
|
-
'3002': AuthenticationError, # NICKNAME_EXIST Nicknames exist
|
245
|
-
'3003': AuthenticationError, # ACCOUNT_NOT_EXIST No account
|
246
|
-
'3004': BadRequest, # PARAM_ERROR Parameter exception
|
247
|
-
'3005': NotSupported, # LANGUAGE_NONSUPPORT Unsupported languages
|
248
|
-
'3007': AuthenticationError, # ONLY_SUBACCOUNT_OPE Sub-account operations only
|
249
|
-
'3008': AuthenticationError, # LOGIN_ENABLE Account not logged
|
250
|
-
'3009': AuthenticationError, # TFA_EXPIRE_ERROR Google key failed
|
251
|
-
'3011': AuthenticationError, # PASSWORD_ERROR Password error
|
252
|
-
'3012': AuthenticationError, # TFA_UUID_ERROR One-time unlock code error
|
253
|
-
'3013': RequestTimeout, # TIME_OUT time out
|
254
|
-
'3015': AuthenticationError, # ID_IS_ERROR id_is_error
|
255
|
-
'3016': AuthenticationError, # WRONG_SUBACCOUNT_NAME already taken
|
256
|
-
'3018': BadRequest, # USER_NAME_AT_LEAST_5_BYTE The user name must have at least 5 digits
|
257
|
-
'3019': BadRequest, # PASSWORD_AT_LEAST_8_BYTE 8-32 bits contain at least three of the numbers, capital, lowercase letters and special symbols!
|
258
|
-
'3020': BadRequest, # TFA_ALREADY_SET GoogleCode Already Set
|
259
|
-
'3021': BadRequest, # PWD_MATCH_ERROR pwd_match_error
|
260
|
-
'3022': BadRequest, # ILLEGAL_OPERATION illegal operation
|
261
|
-
'3023': BadRequest, # REMOVE_SUBACCOUNT_OVER_LIMIT remove subaccount over limit
|
262
|
-
'3024': BadRequest, # GOOGLE_VERIFICATION_CODE_TURNED_ON Google verification code turned on
|
263
|
-
'3025': BadRequest, # OPERATION_FAILURE The operation failure
|
264
|
-
'3026': BadRequest, # ACCOUNT_ACTIVED Account has Actived
|
265
|
-
'3027': BadRequest, # INVALID_EMAIL_ADDRESS Invalid email address!
|
266
|
-
'3028': BadRequest, # PASSWORD_FORMAT_ERROR Password format err
|
267
|
-
'3029': DDoSProtection, # ONE_MINUTE_LIMIT Only one operation per minute and the remaining ${times}s
|
268
|
-
'3030': DDoSProtection, # ONE_HOUR_LIMIT Do self up to 5 times per hour
|
269
|
-
'3031': BadRequest, # USER_NAME_UP_12_BYTE Up to 12 characters, only letters and numbers are supported
|
270
|
-
'3032': BadRequest, # EMAIL_SETTED You need to set email address and password first
|
271
|
-
'3033': BadRequest, # PASSWORD_SETTED You need to set password first
|
272
|
-
'3034': AuthenticationError, # SUBACCOUNT_EMAIL_ACTIVATE You need to wait for email confirmation
|
273
|
-
'3035': BadRequest, # API_NOT_EXIST No api message
|
274
|
-
'3036': BadRequest, # UNAVAILABLE_IN_SUBACCOUNT Unavailable in subaccount
|
275
|
-
'3037': BadRequest, # MAX_SUBACCOUNT_NUMBER Limit of subaccounts is reached
|
276
|
-
'3038': BadRequest, # MAIN_SUBACCOUNT_EMAIL_SAME Provided email address is already used for your other subaccount
|
277
|
-
'3039': BadRequest, # MAX_API_KEY_NUMBER You cannot have more than 8 API keys
|
278
|
-
'3040': AuthenticationError, # ALPHA_TEST Non-invited users shall contact BTCEX Team to obtain the internal tests qualification
|
279
|
-
'3041': BadRequest, # API_NAME_MAX_LENGTH Name of key maximum length - 16 characters
|
280
|
-
'4000': BadRequest, # WALLET_ERROR Wallet error or RECHARGE_CLOSED Recharge closed
|
281
|
-
'4001': InvalidAddress, # WRONG_WITHDRAWAL_ADDRESS Wrong withdrawal address
|
282
|
-
'4002': InvalidAddress, # ADDRESS_DOES_NOT_EXIST Address does not exist
|
283
|
-
'4003': BadRequest, # WITHDRAWAL_CLOSED Withdrawal closed or TOO_SMALL_WITHDRAWAL_AMOUNT Too small withdrawal amount
|
284
|
-
'4004': NotSupported, # INTERNAL_TRANSFER_IS_NOT_SUPPORTED_TEMPORARILY Internal transfer is not supported temporarily
|
285
|
-
'4005': ExchangeError, # WITHDRAW_FAIL Withdrawal failed
|
286
|
-
'4006': InsufficientFunds, # INSUFFICIENT_ASSET ser asset not enough
|
287
|
-
'4007': BadRequest, # TRANSFER_ACCOUNT_ERROR Transfer account error
|
288
|
-
'4008': NotSupported, # AMOUNT_ERROR Amount error
|
289
|
-
'4009': InvalidAddress, # NO_RECHARGE_ADDRESS No recharge address
|
290
|
-
'4010': BadRequest, # GET_TRANSFER_SUBACCOUNT_ERROR Get transfer subaccount error
|
291
|
-
'4011': BadRequest, # TRANSFER_SUBMIT_URL_ERROR Transfer submit url error
|
292
|
-
'5001': InvalidOrder, # ORDER_PARAM_WRONG Order's param wrong.
|
293
|
-
'5002': OrderNotFound, # ORDER_DOSE_NOT_EXIST Order does not exist.
|
294
|
-
'5003': InvalidOrder, # CONTRACT_DOSE_NOT_EXIST Contract does not exist.
|
295
|
-
'5004': InvalidOrder, # ORDER_STATUS_ERR Order status error.
|
296
|
-
'5005': InvalidOrder, # ORDER_AMOUNT_MIN_TRANCSACTION_ERR Order amount min transaction error.
|
297
|
-
'5006': InvalidOrder, # ORDER_PRICE_MIN_TRANCSACTION_ERR Order price min price error.
|
298
|
-
'5007': InvalidOrder, # ORDER_PRICE_TICK_SIZE_ERR Order price tick size error.
|
299
|
-
'5008': InvalidOrder, # ORDER_TYPE_ERR Order type error.
|
300
|
-
'5009': InvalidOrder, # ORDER_OPTION_IS_EXPIRED Order option is expired.
|
301
|
-
'5010': InvalidOrder, # ORDER_IS_NOT_ACTIVE Order is not active.
|
302
|
-
'5011': InvalidOrder, # IV_ORDER_ARE_NOT_SUPPORTED Iv orders are not supported.
|
303
|
-
'5012': InvalidOrder, # ORDER_NO_MARK_PRICE_ERROR No mark price error.
|
304
|
-
'5013': InvalidOrder, # ORDER_PRICE_RANGE_IS_TOO_HIGH order price range is too high.
|
305
|
-
'5014': InvalidOrder, # ORDER_PRICE_RANGE_IS_TOO_LOW Order price range is too low.
|
306
|
-
'5109': InvalidOrder, # ORDER_PRICE_RANGE_IS_TOO_LOW Order price range is too low.
|
307
|
-
'5119': InvalidOrder, # {"code":5119,"message":"Cannot be less than the minimum order value:10USDT, instrument: GXE/USDT","data":{"coinType":"USDT","amount":"10","instrumentName":"GXE/USDT"}}
|
308
|
-
'5135': InvalidOrder, # The quantity should be larger than: 0.01
|
309
|
-
'5901': InvalidOrder, # TRANSFER_RESULT transfer out success.
|
310
|
-
'5902': InvalidOrder, # ORDER_SUCCESS place order success.
|
311
|
-
'5903': InvalidOrder, # ORDER_FAIL place order fail.
|
312
|
-
'5904': InvalidOrder, # PRICE_TRIGGER_LIQ price trigger liquidation
|
313
|
-
'5905': InvalidOrder, # LIQ_CANCEL liquidation make order cancel.
|
314
|
-
'5906': InvalidOrder, # LIQ_ORDER liquidation place a new order
|
315
|
-
'5907': InsufficientFunds, # ASSET_NOT_ENOUTH asset not enough
|
316
|
-
'8000': BadRequest, # PARAM_ERROR Request params not valid!
|
317
|
-
'8001': BadRequest, # DATA_NOT_EXIST The data doesn't exist!
|
318
|
-
'8100': BadRequest, # CODE_CHECK_FAIL Incorrect verification code
|
319
|
-
'8101': RequestTimeout, # CODE_NOT_EXIST Verification code time out, please retry later
|
320
|
-
'8102': DDoSProtection, # CODE_CHECK_FAIL_LIMIT Errors exceed the limit. Please try again after 24H.
|
321
|
-
'8103': BadRequest, # SMS_CODE_CHECK_FAIL Incorrect SMS verification code
|
322
|
-
'8104': BadRequest, # MAIL_CODE_CHECK_FAIL Incorrect mail verification code
|
323
|
-
'8105': BadRequest, # GOOGLE_CODE_CHECK_FAIL 2FA Code error!
|
324
|
-
'8106': DDoSProtection, # SMS_CODE_LIMIT Your message service is over limit today, please try tomorrow
|
325
|
-
'8107': ExchangeError, # REQUEST_FAILED Request failed
|
326
|
-
'10000': AuthenticationError, # Authentication Failure
|
327
|
-
'11000': BadRequest, # CHANNEL_REGEX_ERROR channel regex not match
|
328
|
-
},
|
329
|
-
'broad': {
|
330
|
-
},
|
331
|
-
},
|
332
|
-
'precisionMode': TICK_SIZE,
|
333
|
-
'options': {
|
334
|
-
'accountsByType': {
|
335
|
-
'wallet': 'WALLET',
|
336
|
-
'spot': 'SPOT',
|
337
|
-
'perpetual': 'PERPETUAL',
|
338
|
-
'margin': 'MARGIN',
|
339
|
-
'swap': 'PERPETUAL',
|
340
|
-
'BTC': 'BTC',
|
341
|
-
'ETH': 'ETH',
|
342
|
-
},
|
343
|
-
'createMarketBuyOrderRequiresPrice': True,
|
344
|
-
},
|
345
|
-
'commonCurrencies': {
|
346
|
-
'ALT': 'ArchLoot',
|
347
|
-
},
|
348
|
-
})
|
349
|
-
|
350
|
-
async def fetch_markets(self, params={}):
|
351
|
-
response = await self.publicGetGetInstruments(params)
|
352
|
-
markets = self.safe_value(response, 'result', [])
|
353
|
-
#
|
354
|
-
# {
|
355
|
-
# "jsonrpc":"2.0",
|
356
|
-
# "usIn":1647533492507,
|
357
|
-
# "usOut":1647533492511,
|
358
|
-
# "usDiff":4,
|
359
|
-
# "result":[{
|
360
|
-
# "currency":"BTC",
|
361
|
-
# "base_currency":"USDT",
|
362
|
-
# "contract_size":"0.01",
|
363
|
-
# "creation_timestamp":"1632384961348",
|
364
|
-
# "expiration_timestamp":"1648195200000",
|
365
|
-
# "instrument_name":"BTC-25MAR22",
|
366
|
-
# "show_name":"BTC-25MAR22",
|
367
|
-
# "is_active":true,
|
368
|
-
# "kind":"future",
|
369
|
-
# "leverage":0,
|
370
|
-
# "maker_commission":"10",
|
371
|
-
# "taker_commission":"17",
|
372
|
-
# "min_trade_amount":"0.01",
|
373
|
-
# "option_type":"init",
|
374
|
-
# "quote_currency":"USDT",
|
375
|
-
# "settlement_period":"week",
|
376
|
-
# "strike":"0",
|
377
|
-
# "tick_size":"0.1",
|
378
|
-
# "instr_multiple":"0.01",
|
379
|
-
# "order_price_low_rate":"0.8",
|
380
|
-
# "order_price_high_rate":"1.2",
|
381
|
-
# "order_price_limit_type":0,
|
382
|
-
# "min_qty":"0.01",
|
383
|
-
# "min_notional":"0",
|
384
|
-
# "support_trace_trade":false
|
385
|
-
# }]
|
386
|
-
# }
|
387
|
-
#
|
388
|
-
result = []
|
389
|
-
for i in range(0, len(markets)):
|
390
|
-
market = markets[i]
|
391
|
-
id = self.safe_string(market, 'instrument_name')
|
392
|
-
type = self.safe_string(market, 'kind')
|
393
|
-
unifiedType = type
|
394
|
-
if type == 'perpetual':
|
395
|
-
unifiedType = 'swap'
|
396
|
-
baseId = self.safe_string(market, 'quote_currency')
|
397
|
-
quoteId = self.safe_string(market, 'base_currency')
|
398
|
-
swap = (type == 'perpetual')
|
399
|
-
spot = (type == 'spot')
|
400
|
-
margin = (type == 'margin')
|
401
|
-
option = (type == 'option')
|
402
|
-
future = (type == 'future')
|
403
|
-
contract = swap or future or option
|
404
|
-
expiry = None
|
405
|
-
if option or future:
|
406
|
-
baseId = self.safe_string(market, 'currency')
|
407
|
-
expiry = self.safe_integer(market, 'expiration_timestamp')
|
408
|
-
contractSize = None
|
409
|
-
settleId = None
|
410
|
-
settle = None
|
411
|
-
if contract:
|
412
|
-
settleId = quoteId
|
413
|
-
settle = self.safe_currency_code(settleId)
|
414
|
-
optionType = None
|
415
|
-
strike = None
|
416
|
-
if option:
|
417
|
-
optionType = self.safe_string(market, 'option_type')
|
418
|
-
strike = self.safe_number(market, 'strike')
|
419
|
-
base = self.safe_currency_code(baseId)
|
420
|
-
quote = self.safe_currency_code(quoteId)
|
421
|
-
symbol = None
|
422
|
-
if margin:
|
423
|
-
symbol = id
|
424
|
-
else:
|
425
|
-
symbol = base + '/' + quote
|
426
|
-
if contract:
|
427
|
-
contractSize = self.safe_number(market, 'contract_size')
|
428
|
-
symbol = symbol + ':' + settle
|
429
|
-
if future or option:
|
430
|
-
symbol = symbol + '-' + self.yymmdd(expiry)
|
431
|
-
if option:
|
432
|
-
letter = 'C' if (optionType == 'call') else 'P'
|
433
|
-
symbol = symbol + ':' + self.number_to_string(strike) + ':' + letter
|
434
|
-
minTradeAmount = self.safe_number(market, 'min_trade_amount')
|
435
|
-
tickSize = self.safe_number(market, 'tick_size')
|
436
|
-
maker = self.safe_number(market, 'maker_commission')
|
437
|
-
taker = self.safe_number(market, 'taker_commission')
|
438
|
-
percentage = not (option or future)
|
439
|
-
result.append({
|
440
|
-
'id': id,
|
441
|
-
'symbol': symbol,
|
442
|
-
'base': base,
|
443
|
-
'quote': quote,
|
444
|
-
'baseId': baseId,
|
445
|
-
'quoteId': quoteId,
|
446
|
-
'settleId': settleId,
|
447
|
-
'settle': settle,
|
448
|
-
'type': unifiedType,
|
449
|
-
'maker': maker,
|
450
|
-
'taker': taker,
|
451
|
-
'percentage': percentage,
|
452
|
-
'spot': spot,
|
453
|
-
'margin': margin,
|
454
|
-
'swap': swap,
|
455
|
-
'future': future,
|
456
|
-
'option': option,
|
457
|
-
'active': self.safe_value(market, 'is_active'),
|
458
|
-
'contract': contract,
|
459
|
-
'linear': True if contract else None,
|
460
|
-
'inverse': False if contract else None,
|
461
|
-
'contractSize': contractSize,
|
462
|
-
'expiry': expiry,
|
463
|
-
'expiryDatetime': self.iso8601(expiry),
|
464
|
-
'strike': strike,
|
465
|
-
'optionType': optionType,
|
466
|
-
'precision': {
|
467
|
-
'amount': minTradeAmount,
|
468
|
-
'price': tickSize,
|
469
|
-
},
|
470
|
-
'limits': {
|
471
|
-
'leverage': {
|
472
|
-
'min': None,
|
473
|
-
'max': self.safe_string(market, 'leverage'),
|
474
|
-
},
|
475
|
-
'amount': {
|
476
|
-
'min': minTradeAmount,
|
477
|
-
'max': None,
|
478
|
-
},
|
479
|
-
'price': {
|
480
|
-
'min': tickSize,
|
481
|
-
'max': None,
|
482
|
-
},
|
483
|
-
'cost': {
|
484
|
-
'min': None,
|
485
|
-
'max': None,
|
486
|
-
},
|
487
|
-
},
|
488
|
-
'info': market,
|
489
|
-
})
|
490
|
-
return result
|
491
|
-
|
492
|
-
def parse_ticker(self, ticker, market=None):
|
493
|
-
#
|
494
|
-
# {
|
495
|
-
# "best_ask_amount":"0.20962",
|
496
|
-
# "best_ask_price":"40491.7",
|
497
|
-
# "best_bid_amount":"0.08855",
|
498
|
-
# "best_bid_price":"40491.6",
|
499
|
-
# "instrument_name":"BTC-USDT",
|
500
|
-
# "last_price":"40493",
|
501
|
-
# "mark_price":"40493.10644717",
|
502
|
-
# "state":"open",
|
503
|
-
# "stats":{
|
504
|
-
# "high":"41468.8",
|
505
|
-
# "low":"40254.9",
|
506
|
-
# "price_change":"-0.0159",
|
507
|
-
# "volume":"3847.35240000000000005"
|
508
|
-
# "turnover":"1109811189.67100102035328746"
|
509
|
-
# },
|
510
|
-
# "timestamp":"1647569486224"
|
511
|
-
# }
|
512
|
-
#
|
513
|
-
marketId = self.safe_string(ticker, 'instrument_name')
|
514
|
-
if marketId.find('PERPETUAL') < 0:
|
515
|
-
marketId = marketId + '-SPOT'
|
516
|
-
market = self.safe_market(marketId, market)
|
517
|
-
symbol = self.safe_symbol(marketId, market, '-')
|
518
|
-
timestamp = self.safe_integer(ticker, 'timestamp')
|
519
|
-
stats = self.safe_value(ticker, 'stats')
|
520
|
-
return self.safe_ticker({
|
521
|
-
'symbol': symbol,
|
522
|
-
'timestamp': timestamp,
|
523
|
-
'datetime': self.iso8601(timestamp),
|
524
|
-
'high': self.safe_string(stats, 'high'),
|
525
|
-
'low': self.safe_string(stats, 'low'),
|
526
|
-
'bid': self.safe_string(ticker, 'best_bid_price'),
|
527
|
-
'bidVolume': self.safe_string(ticker, 'best_bid_amount'),
|
528
|
-
'ask': self.safe_string(ticker, 'best_ask_price'),
|
529
|
-
'askVolume': self.safe_string(ticker, 'best_ask_amount'),
|
530
|
-
'vwap': None,
|
531
|
-
'open': None,
|
532
|
-
'close': self.safe_string(ticker, 'last_price'),
|
533
|
-
'last': self.safe_string(ticker, 'last_price'),
|
534
|
-
'previousClose': None,
|
535
|
-
'change': None,
|
536
|
-
'percentage': self.safe_string(stats, 'price_change'),
|
537
|
-
'average': None,
|
538
|
-
'baseVolume': self.safe_string(stats, 'volume'),
|
539
|
-
'quoteVolume': self.safe_string(stats, 'turnover'),
|
540
|
-
'info': ticker,
|
541
|
-
}, market)
|
542
|
-
|
543
|
-
async def fetch_ticker(self, symbol: str, params={}):
|
544
|
-
await self.load_markets()
|
545
|
-
market = self.market(symbol)
|
546
|
-
request = {
|
547
|
-
'instrument_name': market['id'],
|
548
|
-
}
|
549
|
-
response = await self.publicGetTickers(self.extend(request, params))
|
550
|
-
result = self.safe_value(response, 'result', {})
|
551
|
-
#
|
552
|
-
# {
|
553
|
-
# "jsonrpc":"2.0",
|
554
|
-
# "usIn":1647569487238,
|
555
|
-
# "usOut":1647569487240,
|
556
|
-
# "usDiff":2,
|
557
|
-
# "result":[{
|
558
|
-
# "best_ask_amount":"0.20962",
|
559
|
-
# "best_ask_price":"40491.7",
|
560
|
-
# "best_bid_amount":"0.08855",
|
561
|
-
# "best_bid_price":"40491.6",
|
562
|
-
# "instrument_name":"BTC-USDT",
|
563
|
-
# "last_price":"40493",
|
564
|
-
# "mark_price":"40493.10644717",
|
565
|
-
# "state":"open",
|
566
|
-
# "stats":{
|
567
|
-
# "high":"41468.8",
|
568
|
-
# "low":"40254.9",
|
569
|
-
# "price_change":"-0.0159",
|
570
|
-
# "volume":"3847.35240000000000005"
|
571
|
-
# },
|
572
|
-
# "timestamp":"1647569486224"
|
573
|
-
# }]
|
574
|
-
# }
|
575
|
-
#
|
576
|
-
ticker = self.safe_value(result, 0)
|
577
|
-
return self.parse_ticker(ticker, market)
|
578
|
-
|
579
|
-
async def fetch_order_book(self, symbol: str, limit: Optional[int] = None, params={}):
|
580
|
-
await self.load_markets()
|
581
|
-
market = self.market(symbol)
|
582
|
-
request = {
|
583
|
-
'instrument_name': market['id'],
|
584
|
-
}
|
585
|
-
if limit is not None:
|
586
|
-
request['depth'] = limit
|
587
|
-
response = await self.publicGetGetOrderBook(self.extend(request, params))
|
588
|
-
result = self.safe_value(response, 'result', {})
|
589
|
-
#
|
590
|
-
# {
|
591
|
-
# "jsonrpc":"2.0",
|
592
|
-
# "usIn":1647573916524,
|
593
|
-
# "usOut":1647573916526,
|
594
|
-
# "usDiff":2,
|
595
|
-
# "result":{
|
596
|
-
# "asks":[["10155.00000","0.200","186.980","0.000"],["10663.00000","0.200","217.480","0.000"]],
|
597
|
-
# "bids":[["7896.00000","0.200","1.000","0.000"],["7481.00000","0.200","1.000","0.000"]],
|
598
|
-
# "timestamp":"1647573916525",
|
599
|
-
# "instrument_name":"BTC-25MAR22-32000-C",
|
600
|
-
# "version":1002541
|
601
|
-
# }
|
602
|
-
# }
|
603
|
-
#
|
604
|
-
timestamp = self.safe_integer(result, 'timestamp')
|
605
|
-
orderBook = self.parse_order_book(result, market['symbol'], timestamp)
|
606
|
-
orderBook['nonce'] = self.safe_integer(result, 'version')
|
607
|
-
return orderBook
|
608
|
-
|
609
|
-
def parse_ohlcv(self, ohlcv, market=None):
|
610
|
-
#
|
611
|
-
# {
|
612
|
-
# "tick":1647547200,
|
613
|
-
# "open":"40868.16800000",
|
614
|
-
# "high":"40877.65600000",
|
615
|
-
# "low":"40647.00000000",
|
616
|
-
# "close":"40699.10000000",
|
617
|
-
# "volume":"100.27789000",
|
618
|
-
# "cost":"4083185.78337596"
|
619
|
-
# }
|
620
|
-
#
|
621
|
-
return [
|
622
|
-
self.safe_timestamp(ohlcv, 'tick'),
|
623
|
-
self.safe_number(ohlcv, 'open'),
|
624
|
-
self.safe_number(ohlcv, 'high'),
|
625
|
-
self.safe_number(ohlcv, 'low'),
|
626
|
-
self.safe_number(ohlcv, 'close'),
|
627
|
-
self.safe_number(ohlcv, 'volume'),
|
628
|
-
]
|
629
|
-
|
630
|
-
async def fetch_ohlcv(self, symbol: str, timeframe='1m', since: Optional[int] = None, limit: Optional[int] = None, params={}):
|
631
|
-
await self.load_markets()
|
632
|
-
market = self.market(symbol)
|
633
|
-
if limit is None:
|
634
|
-
limit = 10
|
635
|
-
request = {
|
636
|
-
'resolution': self.safe_string(self.timeframes, timeframe, timeframe),
|
637
|
-
# 'start_timestamp': 0,
|
638
|
-
# 'end_timestamp': 0,
|
639
|
-
}
|
640
|
-
marketId = market['id']
|
641
|
-
if market['spot'] or market['margin']:
|
642
|
-
marketId = market['baseId'] + '-' + market['quoteId']
|
643
|
-
request['instrument_name'] = marketId
|
644
|
-
if since is None:
|
645
|
-
request['end_timestamp'] = self.milliseconds()
|
646
|
-
request['start_timestamp'] = 0
|
647
|
-
else:
|
648
|
-
timeframeInSeconds = self.parse_timeframe(timeframe)
|
649
|
-
timeframeInMilliseconds = timeframeInSeconds * 1000
|
650
|
-
request['start_timestamp'] = since
|
651
|
-
request['end_timestamp'] = self.sum(request['start_timestamp'], limit * timeframeInMilliseconds)
|
652
|
-
response = await self.publicGetGetTradingviewChartData(self.extend(request, params))
|
653
|
-
result = self.safe_value(response, 'result', [])
|
654
|
-
#
|
655
|
-
# {
|
656
|
-
# "jsonrpc":"2.0",
|
657
|
-
# "usIn":1647578562427,
|
658
|
-
# "usOut":1647578562428,
|
659
|
-
# "usDiff":1,
|
660
|
-
# "result":[{
|
661
|
-
# "tick":1647547200,
|
662
|
-
# "open":"40868.16800000",
|
663
|
-
# "high":"40877.65600000",
|
664
|
-
# "low":"40647.00000000",
|
665
|
-
# "close":"40699.10000000",
|
666
|
-
# "volume":"100.27789000",
|
667
|
-
# "cost":"4083185.78337596"
|
668
|
-
# }]
|
669
|
-
# }
|
670
|
-
#
|
671
|
-
return self.parse_ohlcvs(result, market, timeframe, since, limit)
|
672
|
-
|
673
|
-
def parse_trade(self, trade, market=None):
|
674
|
-
#
|
675
|
-
# fetchTrades(public)
|
676
|
-
#
|
677
|
-
# {
|
678
|
-
# "amount":"0.0003",
|
679
|
-
# "direction":"sell",
|
680
|
-
# "iv":"0",
|
681
|
-
# "price":"40767.18",
|
682
|
-
# "timestamp":"1647582687050",
|
683
|
-
# "instrument_name":"BTC-USDT-SPOT",
|
684
|
-
# "trade_id":57499240
|
685
|
-
# }
|
686
|
-
#
|
687
|
-
# fetchOrderTrades or fetchMyTrades
|
688
|
-
#
|
689
|
-
# {
|
690
|
-
# "direction":"sell",
|
691
|
-
# "amount":"0.03",
|
692
|
-
# "price":"397.8",
|
693
|
-
# "fee":"0.011934",
|
694
|
-
# "timestamp":1647668570759,
|
695
|
-
# "role":"taker",
|
696
|
-
# "trade_id":"58319385",
|
697
|
-
# "order_id":"250979478947823616",
|
698
|
-
# "instrument_name":"BNB-USDT-SPOT",
|
699
|
-
# "order_type":"market",
|
700
|
-
# "fee_use_coupon":false,
|
701
|
-
# "fee_coin_type":"USDT",
|
702
|
-
# "index_price":"",
|
703
|
-
# "self_trade":false
|
704
|
-
# }
|
705
|
-
#
|
706
|
-
id = self.safe_string(trade, 'trade_id')
|
707
|
-
marketId = self.safe_string(trade, 'instrument_name')
|
708
|
-
symbol = self.safe_symbol(marketId, market)
|
709
|
-
timestamp = self.safe_integer(trade, 'timestamp')
|
710
|
-
side = self.safe_string(trade, 'direction')
|
711
|
-
priceString = self.safe_string(trade, 'price')
|
712
|
-
amountString = self.safe_string(trade, 'amount')
|
713
|
-
takerOrMaker = self.safe_string(trade, 'role')
|
714
|
-
feeCostString = self.safe_string(trade, 'fee')
|
715
|
-
fee = None
|
716
|
-
if feeCostString is not None:
|
717
|
-
feeCurrencyId = self.safe_string(trade, 'fee_coin_type')
|
718
|
-
feeCurrencyCode = self.safe_currency_code(feeCurrencyId)
|
719
|
-
fee = {
|
720
|
-
'cost': feeCostString,
|
721
|
-
'currency': feeCurrencyCode,
|
722
|
-
}
|
723
|
-
return self.safe_trade({
|
724
|
-
'info': trade,
|
725
|
-
'id': id,
|
726
|
-
'timestamp': timestamp,
|
727
|
-
'datetime': self.iso8601(timestamp),
|
728
|
-
'symbol': symbol,
|
729
|
-
'order': self.safe_string(trade, 'order_id'),
|
730
|
-
'type': self.safe_string(trade, 'order_type'),
|
731
|
-
'side': side,
|
732
|
-
'takerOrMaker': takerOrMaker,
|
733
|
-
'price': priceString,
|
734
|
-
'amount': amountString,
|
735
|
-
'cost': None,
|
736
|
-
'fee': fee,
|
737
|
-
}, market)
|
738
|
-
|
739
|
-
async def fetch_trades(self, symbol: str, since: Optional[int] = None, limit: Optional[int] = None, params={}):
|
740
|
-
await self.load_markets()
|
741
|
-
market = self.market(symbol)
|
742
|
-
request = {
|
743
|
-
'instrument_name': market['id'],
|
744
|
-
# 'start_id' : 0,
|
745
|
-
# 'end_id': 0,
|
746
|
-
# 'sorting': 'asc', # asc | desc
|
747
|
-
}
|
748
|
-
if limit is not None:
|
749
|
-
request['count'] = limit # default 10
|
750
|
-
response = await self.publicGetGetLastTradesByInstrument(self.extend(request, params))
|
751
|
-
result = self.safe_value(response, 'result', {})
|
752
|
-
#
|
753
|
-
# {
|
754
|
-
# "jsonrpc":"2.0",
|
755
|
-
# "usIn":1647582703220,
|
756
|
-
# "usOut":1647582703253,
|
757
|
-
# "usDiff":33,
|
758
|
-
# "result":{
|
759
|
-
# "trades":[{
|
760
|
-
# "amount":"0.0003",
|
761
|
-
# "direction":"sell",
|
762
|
-
# "iv":"0",
|
763
|
-
# "price":"40767.18",
|
764
|
-
# "timestamp":"1647582687050",
|
765
|
-
# "instrument_name":"BTC-USDT-SPOT",
|
766
|
-
# "trade_id":57499240
|
767
|
-
# }],
|
768
|
-
# "has_more":true
|
769
|
-
# }
|
770
|
-
# }
|
771
|
-
#
|
772
|
-
trades = self.safe_value(result, 'trades', [])
|
773
|
-
return self.parse_trades(trades, market, since, limit)
|
774
|
-
|
775
|
-
async def sign_in(self, params={}):
|
776
|
-
accessToken = self.safe_string(self.options, 'accessToken')
|
777
|
-
if accessToken is not None:
|
778
|
-
return accessToken
|
779
|
-
self.check_required_credentials()
|
780
|
-
request = {
|
781
|
-
'grant_type': 'client_credentials', # client_signature or refresh_token
|
782
|
-
'client_id': self.apiKey,
|
783
|
-
'client_secret': self.secret,
|
784
|
-
# 'refresh_token': '', # Required for grant type refresh_token
|
785
|
-
# 'signature': '', # Required for grant type client_signature
|
786
|
-
}
|
787
|
-
response = await self.publicPostAuth(self.extend(request, params))
|
788
|
-
result = self.safe_value(response, 'result')
|
789
|
-
#
|
790
|
-
# {
|
791
|
-
# jsonrpc: '2.0',
|
792
|
-
# usIn: '1647601525586',
|
793
|
-
# usOut: '1647601525597',
|
794
|
-
# usDiff: '11',
|
795
|
-
# result: {
|
796
|
-
# access_token: '',
|
797
|
-
# token_type: 'bearer',
|
798
|
-
# refresh_token: '',
|
799
|
-
# expires_in: '604799',
|
800
|
-
# scope: 'account:read_write block_trade:read_write trade:read_write wallet:read_write'
|
801
|
-
# }
|
802
|
-
# }
|
803
|
-
#
|
804
|
-
accessToken = self.safe_string(result, 'access_token')
|
805
|
-
self.options['accessToken'] = accessToken
|
806
|
-
return accessToken
|
807
|
-
|
808
|
-
def parse_balance(self, response):
|
809
|
-
#
|
810
|
-
# {
|
811
|
-
# "WALLET":{
|
812
|
-
# "total":"0",
|
813
|
-
# "coupon":"0",
|
814
|
-
# "details":[{
|
815
|
-
# "available":"0",
|
816
|
-
# "freeze":"0",
|
817
|
-
# "coin_type":"1INCH",
|
818
|
-
# "current_mark_price":"1.657"
|
819
|
-
# }]
|
820
|
-
# },
|
821
|
-
# "MARGIN":{
|
822
|
-
# "total":"0",
|
823
|
-
# "net":"0",
|
824
|
-
# "available":"0",
|
825
|
-
# "borrowed":"0",
|
826
|
-
# "details":[],
|
827
|
-
# "maintenance_margin":"0",
|
828
|
-
# "interest_owed":"0"
|
829
|
-
# },
|
830
|
-
# "SPOT":{
|
831
|
-
# "total":"3.965",
|
832
|
-
# "available":"15.887066",
|
833
|
-
# "details":[{
|
834
|
-
# "available":"0",
|
835
|
-
# "freeze":"0",
|
836
|
-
# "total":"0",
|
837
|
-
# "coin_type":"1INCH",
|
838
|
-
# "current_mark_price":"1.657"
|
839
|
-
# }]
|
840
|
-
# },
|
841
|
-
# "BTC":{
|
842
|
-
# "currency":"BTC",
|
843
|
-
# "balance":"0",
|
844
|
-
# "freeze":"0",
|
845
|
-
# "equity":"0",
|
846
|
-
# "base_currency":"USDT",
|
847
|
-
# "available_funds":"0",
|
848
|
-
# "available_withdrawal_funds":"0",
|
849
|
-
# "initial_margin":"0",
|
850
|
-
# "maintenance_margin":"0",
|
851
|
-
# "margin_balance":"0",
|
852
|
-
# "session_funding":"0",
|
853
|
-
# "session_rpl":"0",
|
854
|
-
# "session_upl":"0",
|
855
|
-
# "futures_pl":"0",
|
856
|
-
# "futures_session_rpl":"0",
|
857
|
-
# "futures_session_upl":"0",
|
858
|
-
# "options_value":"0",
|
859
|
-
# "options_pl":"0",
|
860
|
-
# "options_session_rpl":"0",
|
861
|
-
# "options_session_upl":"0",
|
862
|
-
# "total_pl":"0",
|
863
|
-
# "options_delta":"0",
|
864
|
-
# "options_gamma":"0",
|
865
|
-
# "options_theta":"0",
|
866
|
-
# "options_vega":"0",
|
867
|
-
# "delta_total":"0"
|
868
|
-
# },
|
869
|
-
# "ETH":{
|
870
|
-
# "currency":"ETH",
|
871
|
-
# "balance":"0",
|
872
|
-
# "freeze":"0",
|
873
|
-
# "equity":"0",
|
874
|
-
# "base_currency":"USDT",
|
875
|
-
# "available_funds":"0",
|
876
|
-
# "available_withdrawal_funds":"0",
|
877
|
-
# "initial_margin":"0",
|
878
|
-
# "maintenance_margin":"0",
|
879
|
-
# "margin_balance":"0",
|
880
|
-
# "session_funding":"0",
|
881
|
-
# "session_rpl":"0",
|
882
|
-
# "session_upl":"0",
|
883
|
-
# "futures_pl":"0",
|
884
|
-
# "futures_session_rpl":"0",
|
885
|
-
# "futures_session_upl":"0",
|
886
|
-
# "options_value":"0",
|
887
|
-
# "options_pl":"0",
|
888
|
-
# "options_session_rpl":"0",
|
889
|
-
# "options_session_upl":"0",
|
890
|
-
# "total_pl":"0",
|
891
|
-
# "options_delta":"0",
|
892
|
-
# "options_gamma":"0",
|
893
|
-
# "options_theta":"0",
|
894
|
-
# "options_vega":"0",
|
895
|
-
# "delta_total":"0"
|
896
|
-
# },
|
897
|
-
# "PERPETUAL":{
|
898
|
-
# "bonus":"0",
|
899
|
-
# "global_state":0,
|
900
|
-
# "available_funds":"0",
|
901
|
-
# "wallet_balance":"0",
|
902
|
-
# "available_withdraw_funds":"0",
|
903
|
-
# "total_pl":"0",
|
904
|
-
# "total_upl":"0",
|
905
|
-
# "position_rpl":"0",
|
906
|
-
# "total_upl_isolated":"0",
|
907
|
-
# "total_upl_cross":"0",
|
908
|
-
# "total_initial_margin_cross":"0",
|
909
|
-
# "total_initial_margin_isolated":"0",
|
910
|
-
# "total_margin_balance_isolated":"0",
|
911
|
-
# "total_margin_balance":"0",
|
912
|
-
# "total_margin_balance_cross":"0",
|
913
|
-
# "total_maintenance_margin_cross":"0",
|
914
|
-
# "total_wallet_balance_isolated":"0",
|
915
|
-
# "order_frozen":"0",
|
916
|
-
# "order_cross_frozen":"0",
|
917
|
-
# "order_isolated_frozen":"0",
|
918
|
-
# "risk_level":"0",
|
919
|
-
# "bonus_max":"0"
|
920
|
-
# }
|
921
|
-
# }
|
922
|
-
#
|
923
|
-
result = {'info': response}
|
924
|
-
assetTypes = list(response.keys())
|
925
|
-
for i in range(0, len(assetTypes)):
|
926
|
-
assetType = assetTypes[i]
|
927
|
-
currency = self.safe_value(response, assetType)
|
928
|
-
if (assetType == 'WALLET') or (assetType == 'SPOT'):
|
929
|
-
details = self.safe_value(currency, 'details')
|
930
|
-
if details is not None:
|
931
|
-
for j in range(0, len(details)):
|
932
|
-
detail = details[j]
|
933
|
-
coinType = self.safe_string(detail, 'coin_type')
|
934
|
-
code = self.safe_currency_code(coinType)
|
935
|
-
account = self.safe_value(result, code, self.account())
|
936
|
-
account['free'] = self.safe_string(detail, 'available')
|
937
|
-
account['used'] = self.safe_string(detail, 'freeze')
|
938
|
-
account['total'] = self.safe_string(detail, 'total')
|
939
|
-
result[code] = account
|
940
|
-
else:
|
941
|
-
# all other wallets are linear futures
|
942
|
-
code = 'USDT'
|
943
|
-
account = self.account()
|
944
|
-
account['total'] = self.safe_string(currency, 'wallet_balance')
|
945
|
-
account['free'] = self.safe_string(currency, 'available_withdraw_funds')
|
946
|
-
result[code] = account
|
947
|
-
return self.safe_balance(result)
|
948
|
-
|
949
|
-
async def fetch_balance(self, params={}):
|
950
|
-
await self.sign_in()
|
951
|
-
await self.load_markets()
|
952
|
-
type = self.safe_string_lower(params, 'type', 'spot')
|
953
|
-
types = self.safe_value(self.options, 'accountsByType', {})
|
954
|
-
assetType = self.safe_string(types, type, type)
|
955
|
-
params = self.omit(params, 'type')
|
956
|
-
request = {
|
957
|
-
'asset_type': [assetType],
|
958
|
-
}
|
959
|
-
response = await self.privatePostGetAssetsInfo(self.extend(request, params))
|
960
|
-
result = self.safe_value(response, 'result', [])
|
961
|
-
#
|
962
|
-
# {
|
963
|
-
# "id":"1647675393",
|
964
|
-
# "jsonrpc":"2.0",
|
965
|
-
# "usIn":1647675394091,
|
966
|
-
# "usOut":1647675394104,
|
967
|
-
# "usDiff":13,
|
968
|
-
# "result":{
|
969
|
-
# "WALLET":{
|
970
|
-
# "total":"0",
|
971
|
-
# "coupon":"0",
|
972
|
-
# "details":[{
|
973
|
-
# "available":"0",
|
974
|
-
# "freeze":"0",
|
975
|
-
# "coin_type":"1INCH",
|
976
|
-
# "current_mark_price":"1.657"
|
977
|
-
# }]
|
978
|
-
# },
|
979
|
-
# "MARGIN":{
|
980
|
-
# "total":"0",
|
981
|
-
# "net":"0",
|
982
|
-
# "available":"0",
|
983
|
-
# "borrowed":"0",
|
984
|
-
# "details":[],
|
985
|
-
# "maintenance_margin":"0",
|
986
|
-
# "interest_owed":"0"
|
987
|
-
# },
|
988
|
-
# "SPOT":{
|
989
|
-
# "total":"3.965",
|
990
|
-
# "available":"15.887066",
|
991
|
-
# "details":[{
|
992
|
-
# "available":"0",
|
993
|
-
# "freeze":"0",
|
994
|
-
# "total":"0",
|
995
|
-
# "coin_type":"1INCH",
|
996
|
-
# "current_mark_price":"1.657"
|
997
|
-
# }]
|
998
|
-
# },
|
999
|
-
# "BTC":{
|
1000
|
-
# "currency":"BTC",
|
1001
|
-
# "balance":"0",
|
1002
|
-
# "freeze":"0",
|
1003
|
-
# "equity":"0",
|
1004
|
-
# "base_currency":"USDT",
|
1005
|
-
# "available_funds":"0",
|
1006
|
-
# "available_withdrawal_funds":"0",
|
1007
|
-
# "initial_margin":"0",
|
1008
|
-
# "maintenance_margin":"0",
|
1009
|
-
# "margin_balance":"0",
|
1010
|
-
# "session_funding":"0",
|
1011
|
-
# "session_rpl":"0",
|
1012
|
-
# "session_upl":"0",
|
1013
|
-
# "futures_pl":"0",
|
1014
|
-
# "futures_session_rpl":"0",
|
1015
|
-
# "futures_session_upl":"0",
|
1016
|
-
# "options_value":"0",
|
1017
|
-
# "options_pl":"0",
|
1018
|
-
# "options_session_rpl":"0",
|
1019
|
-
# "options_session_upl":"0",
|
1020
|
-
# "total_pl":"0",
|
1021
|
-
# "options_delta":"0",
|
1022
|
-
# "options_gamma":"0",
|
1023
|
-
# "options_theta":"0",
|
1024
|
-
# "options_vega":"0",
|
1025
|
-
# "delta_total":"0"
|
1026
|
-
# },
|
1027
|
-
# "ETH":{
|
1028
|
-
# "currency":"ETH",
|
1029
|
-
# "balance":"0",
|
1030
|
-
# "freeze":"0",
|
1031
|
-
# "equity":"0",
|
1032
|
-
# "base_currency":"USDT",
|
1033
|
-
# "available_funds":"0",
|
1034
|
-
# "available_withdrawal_funds":"0",
|
1035
|
-
# "initial_margin":"0",
|
1036
|
-
# "maintenance_margin":"0",
|
1037
|
-
# "margin_balance":"0",
|
1038
|
-
# "session_funding":"0",
|
1039
|
-
# "session_rpl":"0",
|
1040
|
-
# "session_upl":"0",
|
1041
|
-
# "futures_pl":"0",
|
1042
|
-
# "futures_session_rpl":"0",
|
1043
|
-
# "futures_session_upl":"0",
|
1044
|
-
# "options_value":"0",
|
1045
|
-
# "options_pl":"0",
|
1046
|
-
# "options_session_rpl":"0",
|
1047
|
-
# "options_session_upl":"0",
|
1048
|
-
# "total_pl":"0",
|
1049
|
-
# "options_delta":"0",
|
1050
|
-
# "options_gamma":"0",
|
1051
|
-
# "options_theta":"0",
|
1052
|
-
# "options_vega":"0",
|
1053
|
-
# "delta_total":"0"
|
1054
|
-
# },
|
1055
|
-
# "PERPETUAL":{
|
1056
|
-
# "bonus":"0",
|
1057
|
-
# "global_state":0,
|
1058
|
-
# "available_funds":"0",
|
1059
|
-
# "wallet_balance":"0",
|
1060
|
-
# "available_withdraw_funds":"0",
|
1061
|
-
# "total_pl":"0",
|
1062
|
-
# "total_upl":"0",
|
1063
|
-
# "position_rpl":"0",
|
1064
|
-
# "total_upl_isolated":"0",
|
1065
|
-
# "total_upl_cross":"0",
|
1066
|
-
# "total_initial_margin_cross":"0",
|
1067
|
-
# "total_initial_margin_isolated":"0",
|
1068
|
-
# "total_margin_balance_isolated":"0",
|
1069
|
-
# "total_margin_balance":"0",
|
1070
|
-
# "total_margin_balance_cross":"0",
|
1071
|
-
# "total_maintenance_margin_cross":"0",
|
1072
|
-
# "total_wallet_balance_isolated":"0",
|
1073
|
-
# "order_frozen":"0",
|
1074
|
-
# "order_cross_frozen":"0",
|
1075
|
-
# "order_isolated_frozen":"0",
|
1076
|
-
# "risk_level":"0",
|
1077
|
-
# "bonus_max":"0"
|
1078
|
-
# }
|
1079
|
-
# }
|
1080
|
-
# }
|
1081
|
-
#
|
1082
|
-
return self.parse_balance(result)
|
1083
|
-
|
1084
|
-
def parse_order_status(self, status):
|
1085
|
-
statuses = {
|
1086
|
-
'open': 'open',
|
1087
|
-
'cancelled': 'canceled',
|
1088
|
-
'filled': 'closed',
|
1089
|
-
'rejected': 'rejected',
|
1090
|
-
}
|
1091
|
-
return self.safe_string(statuses, status, status)
|
1092
|
-
|
1093
|
-
def parse_time_in_force(self, timeInForce):
|
1094
|
-
if timeInForce == '-':
|
1095
|
-
return None
|
1096
|
-
timeInForces = {
|
1097
|
-
'good_til_cancelled': 'GTC',
|
1098
|
-
'good_til_date': 'GTD',
|
1099
|
-
'fill_or_kill': 'FOK',
|
1100
|
-
'immediate_or_cancel': 'IOC',
|
1101
|
-
}
|
1102
|
-
return self.safe_string(timeInForces, timeInForce, timeInForce)
|
1103
|
-
|
1104
|
-
def parse_order(self, order, market=None):
|
1105
|
-
#
|
1106
|
-
# fetchOrder or fetchOpenOrders or fetchClosedOrders
|
1107
|
-
# {
|
1108
|
-
# "kind":"spot",
|
1109
|
-
# "direction":"sell",
|
1110
|
-
# "amount":"0.02",
|
1111
|
-
# "price":"900",
|
1112
|
-
# "advanced":"usdt",
|
1113
|
-
# "source":"api",
|
1114
|
-
# "mmp":false,
|
1115
|
-
# "version":1,
|
1116
|
-
# "order_id":"250971492850401280",
|
1117
|
-
# "order_state":"open",
|
1118
|
-
# "instrument_name":"BNB-USDT-SPOT",
|
1119
|
-
# "filled_amount":"0",
|
1120
|
-
# "average_price":"0",
|
1121
|
-
# "order_type":"limit",
|
1122
|
-
# "time_in_force":"GTC",
|
1123
|
-
# "post_only":false,
|
1124
|
-
# "reduce_only":false,
|
1125
|
-
# "creation_timestamp":1647666666723,
|
1126
|
-
# "last_update_timestamp":1647666666725
|
1127
|
-
# }
|
1128
|
-
#
|
1129
|
-
# createOrder
|
1130
|
-
#
|
1131
|
-
# {
|
1132
|
-
# "order_id":"251052889774161920",
|
1133
|
-
# "custom_order_id":"-"
|
1134
|
-
# }
|
1135
|
-
#
|
1136
|
-
# closeOrder
|
1137
|
-
# {
|
1138
|
-
# "order_id":"250979354159153152"
|
1139
|
-
# }
|
1140
|
-
#
|
1141
|
-
timestamp = self.safe_integer(order, 'creation_timestamp')
|
1142
|
-
lastUpdate = self.safe_integer(order, 'last_update_timestamp')
|
1143
|
-
id = self.safe_string(order, 'order_id')
|
1144
|
-
priceString = self.safe_string(order, 'price')
|
1145
|
-
if priceString == '-1':
|
1146
|
-
priceString = None
|
1147
|
-
averageString = self.safe_string(order, 'average_price')
|
1148
|
-
amountString = self.safe_string(order, 'amount')
|
1149
|
-
filledString = self.safe_string(order, 'filled_amount')
|
1150
|
-
status = self.parse_order_status(self.safe_string(order, 'order_state'))
|
1151
|
-
marketId = self.safe_string(order, 'instrument_name')
|
1152
|
-
market = self.safe_market(marketId, market)
|
1153
|
-
side = self.safe_string_lower(order, 'direction')
|
1154
|
-
feeCostString = self.safe_string(order, 'commission')
|
1155
|
-
fee = None
|
1156
|
-
if feeCostString is not None:
|
1157
|
-
feeCostString = Precise.string_abs(feeCostString)
|
1158
|
-
fee = {
|
1159
|
-
'cost': feeCostString,
|
1160
|
-
'currency': market['base'],
|
1161
|
-
}
|
1162
|
-
# injected in createOrder
|
1163
|
-
trades = self.safe_value(order, 'trades')
|
1164
|
-
stopPrice = self.safe_number(order, 'trigger_price')
|
1165
|
-
return self.safe_order({
|
1166
|
-
'info': order,
|
1167
|
-
'id': id,
|
1168
|
-
'clientOrderId': None,
|
1169
|
-
'timestamp': timestamp,
|
1170
|
-
'datetime': self.iso8601(timestamp),
|
1171
|
-
'lastTradeTimestamp': lastUpdate,
|
1172
|
-
'symbol': market['symbol'],
|
1173
|
-
'type': self.safe_string(order, 'order_type'),
|
1174
|
-
'timeInForce': self.parse_time_in_force(self.safe_string(order, 'time_in_force')),
|
1175
|
-
'postOnly': self.safe_value(order, 'post_only'),
|
1176
|
-
'side': side,
|
1177
|
-
'price': self.parse_number(priceString),
|
1178
|
-
'stopPrice': stopPrice,
|
1179
|
-
'triggerPrice': stopPrice,
|
1180
|
-
'stopLossPrice': self.safe_number(order, 'stop_loss_price'),
|
1181
|
-
'takeProfitPrice': self.safe_number(order, 'take_profit_price'),
|
1182
|
-
'amount': amountString,
|
1183
|
-
'cost': None,
|
1184
|
-
'average': averageString,
|
1185
|
-
'filled': filledString,
|
1186
|
-
'remaining': None,
|
1187
|
-
'status': status,
|
1188
|
-
'fee': fee,
|
1189
|
-
'trades': trades,
|
1190
|
-
}, market)
|
1191
|
-
|
1192
|
-
async def fetch_order(self, id: str, symbol: Optional[str] = None, params={}):
|
1193
|
-
await self.sign_in()
|
1194
|
-
await self.load_markets()
|
1195
|
-
request = {
|
1196
|
-
'order_id': id,
|
1197
|
-
}
|
1198
|
-
response = await self.privateGetGetOrderState(self.extend(request, params))
|
1199
|
-
result = self.safe_value(response, 'result')
|
1200
|
-
#
|
1201
|
-
# {
|
1202
|
-
# "jsonrpc":"2.0",
|
1203
|
-
# "usIn":1647672034018,
|
1204
|
-
# "usOut":1647672034033,
|
1205
|
-
# "usDiff":15,
|
1206
|
-
# "result":{
|
1207
|
-
# "currency":"SPOT",
|
1208
|
-
# "kind":"spot",
|
1209
|
-
# "direction":"sell",
|
1210
|
-
# "amount":"0.03",
|
1211
|
-
# "price":"-1",
|
1212
|
-
# "advanced":"usdt",
|
1213
|
-
# "source":"api",
|
1214
|
-
# "mmp":false,
|
1215
|
-
# "version":1,
|
1216
|
-
# "order_id":"250979478947823616",
|
1217
|
-
# "order_state":"filled",
|
1218
|
-
# "instrument_name":"BNB-USDT-SPOT",
|
1219
|
-
# "filled_amount":"0.03",
|
1220
|
-
# "average_price":"397.8",
|
1221
|
-
# "order_type":"market",
|
1222
|
-
# "time_in_force":"GTC",
|
1223
|
-
# "post_only":false,
|
1224
|
-
# "reduce_only":false,
|
1225
|
-
# "creation_timestamp":1647668570759,
|
1226
|
-
# "last_update_timestamp":1647668570761
|
1227
|
-
# }
|
1228
|
-
# }
|
1229
|
-
#
|
1230
|
-
return self.parse_order(result)
|
1231
|
-
|
1232
|
-
async def create_order(self, symbol: str, type: OrderType, side: OrderSide, amount, price=None, params={}):
|
1233
|
-
"""
|
1234
|
-
create a trade order
|
1235
|
-
:param str symbol: unified symbol of the market to create an order in
|
1236
|
-
:param str type: 'market' or 'limit'
|
1237
|
-
:param str side: 'buy' or 'sell'
|
1238
|
-
:param float amount: how much of currency you want to trade in units of the base currency
|
1239
|
-
:param float|None price: the price at which the order is to be fullfilled, in units of the quote currency, ignored in market orders
|
1240
|
-
:param dict params: extra parameters specific to the btcex api endpoint
|
1241
|
-
* ----------------- Exchange Specific Parameters -----------------
|
1242
|
-
:param float|None params['cost']: amount in USDT to spend for market orders
|
1243
|
-
:param float|None params['triggerPrice']: price to trigger stop orders
|
1244
|
-
:param float|None params['stopPrice']: price to trigger stop orders
|
1245
|
-
:param float|None params['stopLossPrice']: price to trigger stop-loss orders(only for perpetuals)
|
1246
|
-
:param float|None params['takeProfitPrice']: price to trigger take-profit orders(only for perpetuals)
|
1247
|
-
:param dict|None params['stopLoss']: for setting a stop-loss attached to an order, set the value of the stopLoss key 'price'(only for perpetuals)
|
1248
|
-
:param dict|None params['takeProfit']: for setting a take-profit attached to an order, set the value of the takeProfit key 'price'(only for perpetuals)
|
1249
|
-
:param int|None params['trigger_price_type']: 1: mark-price, 2: last-price.(only for perpetuals)
|
1250
|
-
:param int|None params['stop_loss_type']: 1: mark-price, 2: last-price(only for perpetuals)
|
1251
|
-
:param int|None params['take_profit_type']: 1: mark-price, 2: last-price(only for perpetuals)
|
1252
|
-
:param bool|None params['market_amount_order']: if set to True,then the amount field means USDT value(only for perpetuals)
|
1253
|
-
:param str|None params['condition_type']: 'NORMAL', 'STOP', 'TRAILING', 'IF_TOUCHED'
|
1254
|
-
:param str|None params['position_side']: 'BOTH', for one-way mode 'LONG' or 'SHORT', for hedge-mode
|
1255
|
-
:param str|None params['timeInForce']: 'GTC', 'IOC', 'FOK'
|
1256
|
-
:param bool|None params.postOnly:
|
1257
|
-
:param bool|None params.reduceOnly:
|
1258
|
-
:returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
|
1259
|
-
"""
|
1260
|
-
await self.sign_in()
|
1261
|
-
await self.load_markets()
|
1262
|
-
market = self.market(symbol)
|
1263
|
-
request = {
|
1264
|
-
'instrument_name': market['id'],
|
1265
|
-
'type': type,
|
1266
|
-
}
|
1267
|
-
if side == 'sell' or type == 'limit':
|
1268
|
-
request['amount'] = self.amount_to_precision(symbol, amount)
|
1269
|
-
if type == 'limit':
|
1270
|
-
request['price'] = self.price_to_precision(symbol, price)
|
1271
|
-
else:
|
1272
|
-
costParam = self.safe_number(params, 'cost')
|
1273
|
-
amountString = self.number_to_string(amount)
|
1274
|
-
priceString = self.number_to_string(price)
|
1275
|
-
cost = self.parse_number(Precise.string_mul(amountString, priceString), costParam)
|
1276
|
-
if market['swap']:
|
1277
|
-
if cost is not None:
|
1278
|
-
request['amount'] = self.price_to_precision(symbol, cost)
|
1279
|
-
request['market_amount_order'] = True
|
1280
|
-
else:
|
1281
|
-
request['market_amount_order'] = False
|
1282
|
-
request['amount'] = self.amount_to_precision(symbol, amount)
|
1283
|
-
else:
|
1284
|
-
if side == 'buy':
|
1285
|
-
createMarketBuyOrderRequiresPrice = self.safe_value(self.options, 'createMarketBuyOrderRequiresPrice', True)
|
1286
|
-
if createMarketBuyOrderRequiresPrice:
|
1287
|
-
if cost is None:
|
1288
|
-
raise InvalidOrder(self.id + ' createOrder() requires a price argument for market buy orders on spot markets to calculate the total amount to spend(amount * price), alternatively set the createMarketBuyOrderRequiresPrice option to False and pass in the cost to spend into the amount parameter')
|
1289
|
-
else:
|
1290
|
-
request['amount'] = self.price_to_precision(symbol, cost)
|
1291
|
-
else:
|
1292
|
-
request['amount'] = self.price_to_precision(symbol, amount)
|
1293
|
-
params = self.omit(params, 'cost')
|
1294
|
-
if market['swap']:
|
1295
|
-
timeInForce = self.safe_string_upper(params, 'timeInForce')
|
1296
|
-
if timeInForce == 'GTC':
|
1297
|
-
request['time_in_force'] = 'good_till_cancelled'
|
1298
|
-
elif timeInForce == 'FOK':
|
1299
|
-
request['time_in_force'] = 'fill_or_kill'
|
1300
|
-
elif timeInForce == 'IOC':
|
1301
|
-
request['time_in_force'] = 'immediate_or_cancel'
|
1302
|
-
isMarketOrder = type == 'market'
|
1303
|
-
exchangeSpecificParam = self.safe_value(params, 'post_only', False)
|
1304
|
-
postOnly = self.is_post_only(isMarketOrder, exchangeSpecificParam, params)
|
1305
|
-
if postOnly:
|
1306
|
-
request['post_only'] = True
|
1307
|
-
reduceOnly = self.safe_value(params, 'reduceOnly', False)
|
1308
|
-
if reduceOnly:
|
1309
|
-
request['reduce_only'] = True
|
1310
|
-
if side == 'buy':
|
1311
|
-
requestType = 'SHORT' if (reduceOnly) else 'LONG'
|
1312
|
-
request['position_side'] = requestType
|
1313
|
-
else:
|
1314
|
-
requestType = 'LONG' if (reduceOnly) else 'SHORT'
|
1315
|
-
request['position_side'] = requestType
|
1316
|
-
stopPrice = self.safe_number_2(params, 'triggerPrice', 'stopPrice')
|
1317
|
-
stopLossPrice = self.safe_number(params, 'stopLossPrice')
|
1318
|
-
takeProfitPrice = self.safe_number(params, 'takeProfitPrice')
|
1319
|
-
isStopLoss = self.safe_value(params, 'stopLoss')
|
1320
|
-
isTakeProfit = self.safe_value(params, 'takeProfit')
|
1321
|
-
if stopPrice:
|
1322
|
-
request['condition_type'] = 'STOP'
|
1323
|
-
request['trigger_price'] = self.price_to_precision(symbol, stopPrice)
|
1324
|
-
request['trigger_price_type'] = 1
|
1325
|
-
elif stopLossPrice or takeProfitPrice:
|
1326
|
-
request['condition_type'] = 'STOP'
|
1327
|
-
if stopLossPrice:
|
1328
|
-
request['trigger_price'] = self.price_to_precision(symbol, stopLossPrice)
|
1329
|
-
else:
|
1330
|
-
request['trigger_price'] = self.price_to_precision(symbol, takeProfitPrice)
|
1331
|
-
request['reduce_only'] = True
|
1332
|
-
request['trigger_price_type'] = 1
|
1333
|
-
elif isStopLoss or isTakeProfit:
|
1334
|
-
if isStopLoss:
|
1335
|
-
stopLossPrice = self.safe_number(isStopLoss, 'price')
|
1336
|
-
request['stop_loss_price'] = self.price_to_precision(symbol, stopLossPrice)
|
1337
|
-
request['stop_loss_type'] = 1
|
1338
|
-
else:
|
1339
|
-
takeProfitPrice = self.safe_number(isTakeProfit, 'price')
|
1340
|
-
request['take_profit_price'] = self.price_to_precision(symbol, takeProfitPrice)
|
1341
|
-
request['take_profit_type'] = 1
|
1342
|
-
params = self.omit(params, ['timeInForce', 'postOnly', 'reduceOnly', 'stopPrice', 'triggerPrice', 'stopLossPrice', 'takeProfitPrice', 'stopLoss', 'takeProfit'])
|
1343
|
-
method = 'privatePost' + self.capitalize(side)
|
1344
|
-
response = await getattr(self, method)(self.extend(request, params))
|
1345
|
-
result = self.safe_value(response, 'result', {})
|
1346
|
-
#
|
1347
|
-
# {
|
1348
|
-
# "id":"1647686073",
|
1349
|
-
# "jsonrpc":"2.0",
|
1350
|
-
# "usIn":1647686073252,
|
1351
|
-
# "usOut":1647686073264,
|
1352
|
-
# "usDiff":12,
|
1353
|
-
# "result":{
|
1354
|
-
# "order":{
|
1355
|
-
# "order_id":"251052889774161920",
|
1356
|
-
# "custom_order_id":"-"
|
1357
|
-
# }
|
1358
|
-
# }
|
1359
|
-
# }
|
1360
|
-
#
|
1361
|
-
order = self.safe_value(result, 'order')
|
1362
|
-
return self.parse_order(order, market)
|
1363
|
-
|
1364
|
-
async def cancel_order(self, id: str, symbol: Optional[str] = None, params={}):
|
1365
|
-
await self.sign_in()
|
1366
|
-
await self.load_markets()
|
1367
|
-
request = {
|
1368
|
-
'order_id': id,
|
1369
|
-
}
|
1370
|
-
response = await self.privatePostCancel(self.extend(request, params))
|
1371
|
-
result = self.safe_value(response, 'result', {})
|
1372
|
-
#
|
1373
|
-
# {
|
1374
|
-
# "id":"1647675007",
|
1375
|
-
# "jsonrpc":"2.0",
|
1376
|
-
# "usIn":1647675007485,
|
1377
|
-
# "usOut":1647675007494,
|
1378
|
-
# "usDiff":9,
|
1379
|
-
# "result":{
|
1380
|
-
# "order_id":"250979354159153152"
|
1381
|
-
# }
|
1382
|
-
# }
|
1383
|
-
#
|
1384
|
-
return self.parse_order(result)
|
1385
|
-
|
1386
|
-
async def cancel_all_orders(self, symbol: Optional[str] = None, params={}):
|
1387
|
-
if symbol is None:
|
1388
|
-
raise ArgumentsRequired(self.id + ' cancelAllOrders() requires a symbol argument')
|
1389
|
-
await self.sign_in()
|
1390
|
-
await self.load_markets()
|
1391
|
-
market = self.market(symbol)
|
1392
|
-
request = {
|
1393
|
-
'instrument_name': market['id'],
|
1394
|
-
}
|
1395
|
-
response = await self.privatePostCancelAllByInstrument(self.extend(request, params))
|
1396
|
-
#
|
1397
|
-
# {
|
1398
|
-
# "id":"1647686580",
|
1399
|
-
# "jsonrpc":"2.0",
|
1400
|
-
# "usIn":1647686581216,
|
1401
|
-
# "usOut":1647686581224,
|
1402
|
-
# "usDiff":8,
|
1403
|
-
# "result":2
|
1404
|
-
# }
|
1405
|
-
#
|
1406
|
-
return response
|
1407
|
-
|
1408
|
-
async def fetch_open_orders(self, symbol: Optional[str] = None, since: Optional[int] = None, limit: Optional[int] = None, params={}):
|
1409
|
-
if symbol is None:
|
1410
|
-
raise ArgumentsRequired(self.id + ' fetchOpenOrders() requires a symbol argument')
|
1411
|
-
await self.sign_in()
|
1412
|
-
await self.load_markets()
|
1413
|
-
market = self.market(symbol)
|
1414
|
-
request = {
|
1415
|
-
'instrument_name': market['id'],
|
1416
|
-
}
|
1417
|
-
response = await self.privateGetGetOpenOrdersByInstrument(self.extend(request, params))
|
1418
|
-
result = self.safe_value(response, 'result', [])
|
1419
|
-
#
|
1420
|
-
# {
|
1421
|
-
# "jsonrpc":"2.0",
|
1422
|
-
# "usIn":1647667026285,
|
1423
|
-
# "usOut":1647667026291,
|
1424
|
-
# "usDiff":6,
|
1425
|
-
# "result":[{
|
1426
|
-
# "kind":"spot",
|
1427
|
-
# "direction":"sell",
|
1428
|
-
# "amount":"0.02",
|
1429
|
-
# "price":"900",
|
1430
|
-
# "advanced":"usdt",
|
1431
|
-
# "source":"api",
|
1432
|
-
# "mmp":false,
|
1433
|
-
# "version":1,
|
1434
|
-
# "order_id":"250971492850401280",
|
1435
|
-
# "order_state":"open",
|
1436
|
-
# "instrument_name":"BNB-USDT-SPOT",
|
1437
|
-
# "filled_amount":"0",
|
1438
|
-
# "average_price":"0",
|
1439
|
-
# "order_type":"limit",
|
1440
|
-
# "time_in_force":"GTC",
|
1441
|
-
# "post_only":false,
|
1442
|
-
# "reduce_only":false,
|
1443
|
-
# "creation_timestamp":1647666666723,
|
1444
|
-
# "last_update_timestamp":1647666666725
|
1445
|
-
# }]
|
1446
|
-
# }
|
1447
|
-
#
|
1448
|
-
return self.parse_orders(result, market, since, limit)
|
1449
|
-
|
1450
|
-
async def fetch_closed_orders(self, symbol: Optional[str] = None, since: Optional[int] = None, limit: Optional[int] = None, params={}):
|
1451
|
-
if symbol is None:
|
1452
|
-
raise ArgumentsRequired(self.id + ' fetchClosedOrders() requires a symbol argument')
|
1453
|
-
await self.sign_in()
|
1454
|
-
await self.load_markets()
|
1455
|
-
market = self.market(symbol)
|
1456
|
-
request = {
|
1457
|
-
'instrument_name': market['id'],
|
1458
|
-
}
|
1459
|
-
if limit is not None:
|
1460
|
-
request['count'] = limit
|
1461
|
-
response = await self.privateGetGetOrderHistoryByInstrument(self.extend(request, params))
|
1462
|
-
result = self.safe_value(response, 'result', [])
|
1463
|
-
#
|
1464
|
-
# {
|
1465
|
-
# "jsonrpc":"2.0",
|
1466
|
-
# "usIn":1647671721716,
|
1467
|
-
# "usOut":1647671721730,
|
1468
|
-
# "usDiff":14,
|
1469
|
-
# "result":[{
|
1470
|
-
# "currency":"SPOT",
|
1471
|
-
# "kind":"spot",
|
1472
|
-
# "direction":"sell",
|
1473
|
-
# "amount":"0.03",
|
1474
|
-
# "price":"-1",
|
1475
|
-
# "advanced":"usdt",
|
1476
|
-
# "source":"api",
|
1477
|
-
# "mmp":false,
|
1478
|
-
# "version":1,
|
1479
|
-
# "order_id":"250979478947823616",
|
1480
|
-
# "order_state":"filled",
|
1481
|
-
# "instrument_name":"BNB-USDT-SPOT",
|
1482
|
-
# "filled_amount":"0.03",
|
1483
|
-
# "average_price":"397.8",
|
1484
|
-
# "order_type":"market",
|
1485
|
-
# "time_in_force":"GTC",
|
1486
|
-
# "post_only":false,
|
1487
|
-
# "reduce_only":false,
|
1488
|
-
# "creation_timestamp":1647668570759,
|
1489
|
-
# "last_update_timestamp":1647668570761
|
1490
|
-
# }]
|
1491
|
-
# }
|
1492
|
-
#
|
1493
|
-
return self.parse_orders(result, market, since, limit)
|
1494
|
-
|
1495
|
-
async def fetch_order_trades(self, id: str, symbol: Optional[str] = None, since: Optional[int] = None, limit: Optional[int] = None, params={}):
|
1496
|
-
if id is None:
|
1497
|
-
raise ArgumentsRequired(self.id + ' fetchOrderTrades() requires a id argument')
|
1498
|
-
await self.load_markets()
|
1499
|
-
request = {
|
1500
|
-
'order_id': id,
|
1501
|
-
# 'start_id': 0, # The ID number of the first trade to be returned
|
1502
|
-
# 'end_id': 0, # The ID number of the last trade to be returned
|
1503
|
-
# 'sorting': '', # Direction of results sorting,default: desc
|
1504
|
-
}
|
1505
|
-
if limit is not None:
|
1506
|
-
request['count'] = limit # default 20
|
1507
|
-
response = await self.privateGetGetUserTradesByOrder(self.extend(request, params))
|
1508
|
-
result = self.safe_value(response, 'result', {})
|
1509
|
-
#
|
1510
|
-
# {
|
1511
|
-
# "jsonrpc":"2.0",
|
1512
|
-
# "usIn":1647671425457,
|
1513
|
-
# "usOut":1647671425470,
|
1514
|
-
# "usDiff":13,
|
1515
|
-
# "result":{
|
1516
|
-
# "count":1,
|
1517
|
-
# "trades":[{
|
1518
|
-
# "direction":"sell",
|
1519
|
-
# "amount":"0.03",
|
1520
|
-
# "price":"397.8",
|
1521
|
-
# "fee":"0.011934",
|
1522
|
-
# "timestamp":1647668570759,
|
1523
|
-
# "role":"taker",
|
1524
|
-
# "trade_id":"58319385",
|
1525
|
-
# "order_id":"250979478947823616",
|
1526
|
-
# "instrument_name":"BNB-USDT-SPOT",
|
1527
|
-
# "order_type":"market",
|
1528
|
-
# "fee_use_coupon":false,
|
1529
|
-
# "fee_coin_type":"USDT",
|
1530
|
-
# "index_price":"",
|
1531
|
-
# "self_trade":false
|
1532
|
-
# }],
|
1533
|
-
# "has_more":false
|
1534
|
-
# }
|
1535
|
-
# }
|
1536
|
-
#
|
1537
|
-
trades = self.safe_value(result, 'trades', [])
|
1538
|
-
return self.parse_trades(trades, None, since, limit)
|
1539
|
-
|
1540
|
-
async def fetch_my_trades(self, symbol: Optional[str] = None, since: Optional[int] = None, limit: Optional[int] = None, params={}):
|
1541
|
-
if symbol is None:
|
1542
|
-
raise ArgumentsRequired(self.id + ' fetchMyTrades() requires a id argument')
|
1543
|
-
await self.sign_in()
|
1544
|
-
await self.load_markets()
|
1545
|
-
request = {
|
1546
|
-
# 'kind': '', # The order kind, eg. margin, spot, option, future, perpetual. only used when call privateGetGetUserTradesByCurrency
|
1547
|
-
# 'start_id': 0, # The ID number of the first trade to be returned
|
1548
|
-
# 'end_id': 0, # The ID number of the last trade to be returned
|
1549
|
-
# 'sorting': '', # Direction of results sorting,default: desc
|
1550
|
-
# 'self_trade': False, # If not set, query all
|
1551
|
-
# 'start_timestamp': False # The trade time of the first trade to be returned
|
1552
|
-
# 'end_timestamp': False # The trade time of the last trade to be returned
|
1553
|
-
}
|
1554
|
-
market = self.market(symbol)
|
1555
|
-
request['instrument_name'] = market['id']
|
1556
|
-
if limit is not None:
|
1557
|
-
request['count'] = limit # default 20
|
1558
|
-
if since is not None:
|
1559
|
-
request['start_timestamp'] = since
|
1560
|
-
response = await self.privateGetGetUserTradesByInstrument(self.extend(request, params))
|
1561
|
-
result = self.safe_value(response, 'result', {})
|
1562
|
-
#
|
1563
|
-
# {
|
1564
|
-
# "jsonrpc":"2.0",
|
1565
|
-
# "usIn":1647668582167,
|
1566
|
-
# "usOut":1647668582187,
|
1567
|
-
# "usDiff":20,
|
1568
|
-
# "result":{
|
1569
|
-
# "count":1,
|
1570
|
-
# "trades":[{
|
1571
|
-
# "direction":"sell",
|
1572
|
-
# "amount":"0.03",
|
1573
|
-
# "price":"397.8",
|
1574
|
-
# "fee":"0.011934",
|
1575
|
-
# "timestamp":1647668570759,
|
1576
|
-
# "role":"taker",
|
1577
|
-
# "trade_id":"58319385",
|
1578
|
-
# "order_id":"250979478947823616",
|
1579
|
-
# "instrument_name":"BNB-USDT-SPOT",
|
1580
|
-
# "order_type":"market",
|
1581
|
-
# "fee_use_coupon":false,
|
1582
|
-
# "fee_coin_type":"USDT",
|
1583
|
-
# "index_price":"",
|
1584
|
-
# "self_trade":false
|
1585
|
-
# }],
|
1586
|
-
# "has_more":false
|
1587
|
-
# }
|
1588
|
-
# }
|
1589
|
-
#
|
1590
|
-
trades = self.safe_value(result, 'trades', [])
|
1591
|
-
return self.parse_trades(trades, market, since, limit)
|
1592
|
-
|
1593
|
-
def parse_position(self, position, market=None):
|
1594
|
-
#
|
1595
|
-
# {
|
1596
|
-
# "currency":"PERPETUAL",
|
1597
|
-
# "kind":"perpetual",
|
1598
|
-
# "size":"-0.08",
|
1599
|
-
# "direction":"sell",
|
1600
|
-
# "leverage":"3",
|
1601
|
-
# "margin":"10.7724",
|
1602
|
-
# "version":"553",
|
1603
|
-
# "roe":"-0.000483",
|
1604
|
-
# "traceType":0,
|
1605
|
-
# "pos_id":"0",
|
1606
|
-
# "instrument_name":"BNB-USDT-PERPETUAL",
|
1607
|
-
# "average_price":"403.9",
|
1608
|
-
# "mark_price":"403.965",
|
1609
|
-
# "initial_margin":"10.77066668",
|
1610
|
-
# "maintenance_margin":"0.2100618",
|
1611
|
-
# "floating_profit_loss":"-0.0052",
|
1612
|
-
# "liquid_price":"549.15437158",
|
1613
|
-
# "margin_type":"cross",
|
1614
|
-
# "risk_level":"0.017651",
|
1615
|
-
# "available_withdraw_funds":"1.13004332",
|
1616
|
-
# "order_id":"251085320510201856",
|
1617
|
-
# "stop_loss_price":"0",
|
1618
|
-
# "stop_loss_type":1,
|
1619
|
-
# "take_profit_price":"0",
|
1620
|
-
# "take_profit_type":1
|
1621
|
-
# }
|
1622
|
-
#
|
1623
|
-
contract = self.safe_string(position, 'instrument_name')
|
1624
|
-
market = self.safe_market(contract, market)
|
1625
|
-
size = self.safe_string(position, 'size')
|
1626
|
-
side = self.safe_string(position, 'direction')
|
1627
|
-
side = 'long' if (side == 'buy') else 'short'
|
1628
|
-
maintenanceMarginString = self.safe_string(position, 'maintenance_margin')
|
1629
|
-
riskLevel = self.safe_string(position, 'risk_level')
|
1630
|
-
# maint_margin / collateral = risk_level
|
1631
|
-
# collateral = maint_margin / risk_level
|
1632
|
-
collateral = Precise.string_div(maintenanceMarginString, riskLevel)
|
1633
|
-
markPrice = self.safe_string(position, 'mark_price')
|
1634
|
-
notionalString = Precise.string_mul(markPrice, size)
|
1635
|
-
unrealisedPnl = self.safe_string(position, 'floating_profit_loss')
|
1636
|
-
initialMarginString = self.safe_string(position, 'initial_margin')
|
1637
|
-
marginType = self.safe_string(position, 'margin_type')
|
1638
|
-
return self.safe_position({
|
1639
|
-
'info': position,
|
1640
|
-
'id': None,
|
1641
|
-
'symbol': self.safe_string(market, 'symbol'),
|
1642
|
-
'timestamp': None,
|
1643
|
-
'datetime': None,
|
1644
|
-
'lastUpdateTimestamp': None,
|
1645
|
-
'initialMargin': self.parse_number(initialMarginString),
|
1646
|
-
'initialMarginPercentage': self.parse_number(Precise.string_div(initialMarginString, notionalString)),
|
1647
|
-
'maintenanceMargin': self.parse_number(maintenanceMarginString),
|
1648
|
-
'maintenanceMarginPercentage': self.parse_number(Precise.string_div(maintenanceMarginString, notionalString)),
|
1649
|
-
'entryPrice': self.safe_number(position, 'average_price'),
|
1650
|
-
'notional': self.parse_number(notionalString),
|
1651
|
-
'leverage': self.safe_number(position, 'leverage'),
|
1652
|
-
'unrealizedPnl': self.parse_number(unrealisedPnl),
|
1653
|
-
'contracts': self.parse_number(size), # in USD for perpetuals on deribit
|
1654
|
-
'contractSize': self.safe_value(market, 'contractSize'),
|
1655
|
-
'marginRatio': self.parse_number(riskLevel),
|
1656
|
-
'liquidationPrice': self.safe_number(position, 'liquid_price'),
|
1657
|
-
'markPrice': self.parse_number(markPrice),
|
1658
|
-
'lastPrice': None,
|
1659
|
-
'collateral': self.parse_number(collateral),
|
1660
|
-
'marginType': marginType,
|
1661
|
-
'side': side,
|
1662
|
-
'percentage': None,
|
1663
|
-
})
|
1664
|
-
|
1665
|
-
async def fetch_position(self, symbol: str, params={}):
|
1666
|
-
await self.sign_in()
|
1667
|
-
await self.load_markets()
|
1668
|
-
market = self.market(symbol)
|
1669
|
-
request = {
|
1670
|
-
'instrument_name': market['id'],
|
1671
|
-
}
|
1672
|
-
response = await self.privateGetGetPosition(self.extend(request, params))
|
1673
|
-
result = self.safe_value(response, 'result')
|
1674
|
-
#
|
1675
|
-
# {
|
1676
|
-
# "jsonrpc":"2.0",
|
1677
|
-
# "usIn":1647693832273,
|
1678
|
-
# "usOut":1647693832282,
|
1679
|
-
# "usDiff":9,
|
1680
|
-
# "result":{
|
1681
|
-
# "currency":"PERPETUAL",
|
1682
|
-
# "kind":"perpetual",
|
1683
|
-
# "size":"-0.08",
|
1684
|
-
# "direction":"sell",
|
1685
|
-
# "leverage":"3",
|
1686
|
-
# "margin":"10.7724",
|
1687
|
-
# "version":"553",
|
1688
|
-
# "roe":"-0.000483",
|
1689
|
-
# "traceType":0,
|
1690
|
-
# "pos_id":"0",
|
1691
|
-
# "instrument_name":"BNB-USDT-PERPETUAL",
|
1692
|
-
# "average_price":"403.9",
|
1693
|
-
# "mark_price":"403.965",
|
1694
|
-
# "initial_margin":"10.77066668",
|
1695
|
-
# "maintenance_margin":"0.2100618",
|
1696
|
-
# "floating_profit_loss":"-0.0052",
|
1697
|
-
# "liquid_price":"549.15437158",
|
1698
|
-
# "margin_type":"cross",
|
1699
|
-
# "risk_level":"0.017651",
|
1700
|
-
# "available_withdraw_funds":"1.13004332",
|
1701
|
-
# "order_id":"251085320510201856",
|
1702
|
-
# "stop_loss_price":"0",
|
1703
|
-
# "stop_loss_type":1,
|
1704
|
-
# "take_profit_price":"0",
|
1705
|
-
# "take_profit_type":1
|
1706
|
-
# }
|
1707
|
-
# }
|
1708
|
-
#
|
1709
|
-
return self.parse_position(result)
|
1710
|
-
|
1711
|
-
async def fetch_positions(self, symbols: Optional[List[str]] = None, params={}):
|
1712
|
-
await self.sign_in()
|
1713
|
-
await self.load_markets()
|
1714
|
-
request = {
|
1715
|
-
'currency': 'PERPETUAL',
|
1716
|
-
# 'kind' : '', # option, future, spot, margin,perpetual The order kind
|
1717
|
-
}
|
1718
|
-
response = await self.privateGetGetPositions(self.extend(request, params))
|
1719
|
-
result = self.safe_value(response, 'result')
|
1720
|
-
#
|
1721
|
-
# {
|
1722
|
-
# "jsonrpc":"2.0",
|
1723
|
-
# "usIn":1647694531356,
|
1724
|
-
# "usOut":1647694531364,
|
1725
|
-
# "usDiff":8,
|
1726
|
-
# "result":[{
|
1727
|
-
# "currency":"PERPETUAL",
|
1728
|
-
# "kind":"perpetual",
|
1729
|
-
# "size":"-0.08",
|
1730
|
-
# "direction":"sell",
|
1731
|
-
# "leverage":"3",
|
1732
|
-
# "margin":"10.7836",
|
1733
|
-
# "version":"1251",
|
1734
|
-
# "roe":"-0.003602",
|
1735
|
-
# "traceType":0,
|
1736
|
-
# "pos_id":"0",
|
1737
|
-
# "instrument_name":"BNB-USDT-PERPETUAL",
|
1738
|
-
# "average_price":"403.9",
|
1739
|
-
# "mark_price":"404.385",
|
1740
|
-
# "initial_margin":"10.77066668",
|
1741
|
-
# "maintenance_margin":"0.2102802",
|
1742
|
-
# "floating_profit_loss":"-0.0388",
|
1743
|
-
# "liquid_price":"549.15437158",
|
1744
|
-
# "margin_type":"cross",
|
1745
|
-
# "risk_level":"0.01772",
|
1746
|
-
# "available_withdraw_funds":"1.09644332",
|
1747
|
-
# "order_id":"251085320510201856",
|
1748
|
-
# "stop_loss_price":"0",
|
1749
|
-
# "stop_loss_type":1,
|
1750
|
-
# "take_profit_price":"0",
|
1751
|
-
# "take_profit_type":1
|
1752
|
-
# }]
|
1753
|
-
# }
|
1754
|
-
#
|
1755
|
-
return self.parse_positions(result, symbols)
|
1756
|
-
|
1757
|
-
def parse_transaction_status(self, status):
|
1758
|
-
states = {
|
1759
|
-
'deposit_confirmed': 'ok',
|
1760
|
-
'deposit_waiting_confirm': 'pending',
|
1761
|
-
'withdraw_init': 'pending',
|
1762
|
-
'withdraw_noticed_block_chain': 'pending',
|
1763
|
-
'withdraw_waiting_confirm': 'pending',
|
1764
|
-
'withdraw_confirmed': 'ok',
|
1765
|
-
'withdraw_failed': 'failed',
|
1766
|
-
'withdraw_auditing': 'pending',
|
1767
|
-
'withdraw_audit_reject': 'failed',
|
1768
|
-
}
|
1769
|
-
return self.safe_string(states, status, status)
|
1770
|
-
|
1771
|
-
def parse_transaction(self, transaction, currency=None):
|
1772
|
-
#
|
1773
|
-
# fetchDeposits
|
1774
|
-
# {
|
1775
|
-
# "id":"250325458128736256",
|
1776
|
-
# "amount":"0.04",
|
1777
|
-
# "state":"deposit_confirmed",
|
1778
|
-
# "coin_type":"BNB",
|
1779
|
-
# "token_code":"BNB",
|
1780
|
-
# "create_time":"1647512640040",
|
1781
|
-
# "update_time":"1647512640053",
|
1782
|
-
# "tx_hash":"",
|
1783
|
-
# "full_name":"Binance Coin"
|
1784
|
-
# }
|
1785
|
-
#
|
1786
|
-
# fetchWithdrawals or fetchWithdraw
|
1787
|
-
# {
|
1788
|
-
# "id":"251076247882829824",
|
1789
|
-
# "address":"",
|
1790
|
-
# "amount":"0.01",
|
1791
|
-
# "state":"withdraw_auditing",
|
1792
|
-
# "coin_type":"BNB",
|
1793
|
-
# "create_time":"1647691642267",
|
1794
|
-
# "update_time":"1647691650090",
|
1795
|
-
# "full_name":"Binance Coin",
|
1796
|
-
# "token_code":"BNB"
|
1797
|
-
# }
|
1798
|
-
#
|
1799
|
-
currencyId = self.safe_string(transaction, 'coin_type')
|
1800
|
-
code = self.safe_currency_code(currencyId, currency)
|
1801
|
-
id = self.safe_string(transaction, 'id')
|
1802
|
-
txId = self.safe_string(transaction, 'tx_hash')
|
1803
|
-
timestamp = self.safe_integer(transaction, 'create_time')
|
1804
|
-
updated = self.safe_integer(transaction, 'update_time')
|
1805
|
-
amount = self.safe_number(transaction, 'amount')
|
1806
|
-
status = self.safe_string(transaction, 'state')
|
1807
|
-
return {
|
1808
|
-
'info': transaction,
|
1809
|
-
'id': id,
|
1810
|
-
'txid': txId,
|
1811
|
-
'timestamp': timestamp,
|
1812
|
-
'datetime': self.iso8601(timestamp),
|
1813
|
-
'network': None,
|
1814
|
-
'addressFrom': None,
|
1815
|
-
'address': None,
|
1816
|
-
'addressTo': None,
|
1817
|
-
'tagFrom': None,
|
1818
|
-
'tag': None,
|
1819
|
-
'tagTo': None,
|
1820
|
-
'type': None,
|
1821
|
-
'amount': amount,
|
1822
|
-
'currency': code,
|
1823
|
-
'status': self.parse_transaction_status(status),
|
1824
|
-
'updated': updated,
|
1825
|
-
'fee': None,
|
1826
|
-
}
|
1827
|
-
|
1828
|
-
async def fetch_deposits(self, code: Optional[str] = None, since: Optional[int] = None, limit: Optional[int] = None, params={}):
|
1829
|
-
if code is None:
|
1830
|
-
raise ArgumentsRequired(self.id + ' fetchDeposits() requires the code argument')
|
1831
|
-
await self.sign_in()
|
1832
|
-
await self.load_markets()
|
1833
|
-
currency = self.safe_currency(code)
|
1834
|
-
request = {
|
1835
|
-
'coin_type': currency['id'],
|
1836
|
-
}
|
1837
|
-
response = await self.privateGetGetDepositRecord(self.extend(request, params))
|
1838
|
-
result = self.safe_value(response, 'result', [])
|
1839
|
-
#
|
1840
|
-
# {
|
1841
|
-
# "jsonrpc":"2.0",
|
1842
|
-
# "usIn":1647606752447,
|
1843
|
-
# "usOut":1647606752457,
|
1844
|
-
# "usDiff":10,
|
1845
|
-
# "result":[{
|
1846
|
-
# "id":"250325458128736256",
|
1847
|
-
# "amount":"0.04",
|
1848
|
-
# "state":"deposit_confirmed",
|
1849
|
-
# "coin_type":"BNB",
|
1850
|
-
# "token_code":"BNB",
|
1851
|
-
# "create_time":"1647512640040",
|
1852
|
-
# "update_time":"1647512640053",
|
1853
|
-
# "tx_hash":"",
|
1854
|
-
# "full_name":"Binance Coin"
|
1855
|
-
# }]
|
1856
|
-
# }
|
1857
|
-
# }
|
1858
|
-
#
|
1859
|
-
return self.parse_transactions(result, currency, since, limit, {'type': 'deposit'})
|
1860
|
-
|
1861
|
-
async def fetch_withdrawals(self, code: Optional[str] = None, since: Optional[int] = None, limit: Optional[int] = None, params={}):
|
1862
|
-
if code is None:
|
1863
|
-
raise ArgumentsRequired(self.id + ' fetchWithdrawals() requires the code argument')
|
1864
|
-
await self.sign_in()
|
1865
|
-
await self.load_markets()
|
1866
|
-
currency = self.safe_currency(code)
|
1867
|
-
request = {
|
1868
|
-
'coin_type': currency['id'],
|
1869
|
-
# 'withdraw_id': 0,
|
1870
|
-
}
|
1871
|
-
response = await self.privateGetGetWithdrawRecord(self.extend(request, params))
|
1872
|
-
result = self.safe_value(response, 'result', [])
|
1873
|
-
#
|
1874
|
-
# {
|
1875
|
-
# "jsonrpc":"2.0",
|
1876
|
-
# "usIn":1647691750112,
|
1877
|
-
# "usOut":1647691750125,
|
1878
|
-
# "usDiff":13,
|
1879
|
-
# "result":[{
|
1880
|
-
# "id":"251076247882829824",
|
1881
|
-
# "address":"",
|
1882
|
-
# "amount":"0.01",
|
1883
|
-
# "state":"withdraw_auditing",
|
1884
|
-
# "coin_type":"BNB",
|
1885
|
-
# "create_time":"1647691642267",
|
1886
|
-
# "update_time":"1647691650090",
|
1887
|
-
# "full_name":"Binance Coin",
|
1888
|
-
# "token_code":"BNB"
|
1889
|
-
# }]
|
1890
|
-
# }
|
1891
|
-
#
|
1892
|
-
return self.parse_transactions(result, currency, since, limit, {'type': 'withdrawal'})
|
1893
|
-
|
1894
|
-
async def fetch_withdrawal(self, id: str, code: Optional[str] = None, params={}):
|
1895
|
-
if code is None:
|
1896
|
-
raise ArgumentsRequired(self.id + ' fetchWithdrawal() requires the code argument')
|
1897
|
-
await self.sign_in()
|
1898
|
-
await self.load_markets()
|
1899
|
-
currency = self.safe_currency(code)
|
1900
|
-
request = {
|
1901
|
-
'coin_type': currency['id'],
|
1902
|
-
'withdraw_id': id,
|
1903
|
-
}
|
1904
|
-
response = await self.privateGetGetWithdrawRecord(self.extend(request, params))
|
1905
|
-
result = self.safe_value(response, 'result', [])
|
1906
|
-
#
|
1907
|
-
# {
|
1908
|
-
# "jsonrpc":"2.0",
|
1909
|
-
# "usIn":1647691750112,
|
1910
|
-
# "usOut":1647691750125,
|
1911
|
-
# "usDiff":13,
|
1912
|
-
# "result":[{
|
1913
|
-
# "id":"251076247882829824",
|
1914
|
-
# "address":"",
|
1915
|
-
# "amount":"0.01",
|
1916
|
-
# "state":"withdraw_auditing",
|
1917
|
-
# "coin_type":"BNB",
|
1918
|
-
# "create_time":"1647691642267",
|
1919
|
-
# "update_time":"1647691650090",
|
1920
|
-
# "full_name":"Binance Coin",
|
1921
|
-
# "token_code":"BNB"
|
1922
|
-
# }]
|
1923
|
-
# }
|
1924
|
-
#
|
1925
|
-
records = self.filter_by(result, 'id', id)
|
1926
|
-
record = self.safe_value(records, 0)
|
1927
|
-
return self.parse_transaction(record, currency)
|
1928
|
-
|
1929
|
-
async def fetch_leverage(self, symbol: str, params={}):
|
1930
|
-
"""
|
1931
|
-
see https://docs.btcex.com/#get-perpetual-instrument-config
|
1932
|
-
fetch the set leverage for a market
|
1933
|
-
:param str symbol: unified market symbol
|
1934
|
-
:param dict params: extra parameters specific to the btcex api endpoint
|
1935
|
-
:returns dict: a `leverage structure <https://docs.ccxt.com/#/?id=leverage-structure>`
|
1936
|
-
"""
|
1937
|
-
await self.sign_in()
|
1938
|
-
await self.load_markets()
|
1939
|
-
market = self.market(symbol)
|
1940
|
-
request = {
|
1941
|
-
'instrument_name': market['id'],
|
1942
|
-
}
|
1943
|
-
response = await self.privateGetGetPerpetualUserConfig(self.extend(request, params))
|
1944
|
-
#
|
1945
|
-
# {
|
1946
|
-
# "jsonrpc": "2.0",
|
1947
|
-
# "usIn": 1674182494283,
|
1948
|
-
# "usOut": 1674182494294,
|
1949
|
-
# "usDiff": 11,
|
1950
|
-
# "result": {
|
1951
|
-
# "margin_type": "cross",
|
1952
|
-
# "leverage": "20",
|
1953
|
-
# "instrument_name": "BTC-USDT-PERPETUAL",
|
1954
|
-
# "time": "1674182494293"
|
1955
|
-
# }
|
1956
|
-
# }
|
1957
|
-
#
|
1958
|
-
data = self.safe_value(response, 'result', {})
|
1959
|
-
return self.safe_number(data, 'leverage')
|
1960
|
-
|
1961
|
-
async def fetch_market_leverage_tiers(self, symbol: str, params={}):
|
1962
|
-
"""
|
1963
|
-
see https://docs.btcex.com/#get-perpetual-instrument-leverage-config
|
1964
|
-
retrieve information on the maximum leverage, for different trade sizes for a single market
|
1965
|
-
:param str symbol: unified market symbol
|
1966
|
-
:param dict params: extra parameters specific to the btcex api endpoint
|
1967
|
-
:returns dict: a `leverage tiers structure <https://docs.ccxt.com/#/?id=leverage-tiers-structure>`
|
1968
|
-
"""
|
1969
|
-
await self.load_markets()
|
1970
|
-
market = self.market(symbol)
|
1971
|
-
if not market['swap']:
|
1972
|
-
raise BadRequest(self.id + ' fetchMarketLeverageTiers() supports swap markets only')
|
1973
|
-
request = {
|
1974
|
-
'instrument_name': market['id'],
|
1975
|
-
}
|
1976
|
-
response = await self.publicGetGetPerpetualLeverageBracket(self.extend(request, params))
|
1977
|
-
#
|
1978
|
-
# {
|
1979
|
-
# "jsonrpc": "2.0",
|
1980
|
-
# "usIn": 1674184074454,
|
1981
|
-
# "usOut": 1674184074457,
|
1982
|
-
# "usDiff": 3,
|
1983
|
-
# "result": [
|
1984
|
-
# {
|
1985
|
-
# "bracket": 1,
|
1986
|
-
# "initialLeverage": 125,
|
1987
|
-
# "maintenanceMarginRate": "0.004",
|
1988
|
-
# "notionalCap": "50000",
|
1989
|
-
# "notionalFloor": "0",
|
1990
|
-
# "cum": "0"
|
1991
|
-
# },
|
1992
|
-
# ...
|
1993
|
-
# ]
|
1994
|
-
# }
|
1995
|
-
#
|
1996
|
-
data = self.safe_value(response, 'result', [])
|
1997
|
-
return self.parse_market_leverage_tiers(data, market)
|
1998
|
-
|
1999
|
-
def parse_market_leverage_tiers(self, info, market=None):
|
2000
|
-
#
|
2001
|
-
# [
|
2002
|
-
# {
|
2003
|
-
# "bracket": 1,
|
2004
|
-
# "initialLeverage": 125,
|
2005
|
-
# "maintenanceMarginRate": "0.004",
|
2006
|
-
# "notionalCap": "50000",
|
2007
|
-
# "notionalFloor": "0",
|
2008
|
-
# "cum": "0"
|
2009
|
-
# },
|
2010
|
-
# ...
|
2011
|
-
# ]
|
2012
|
-
#
|
2013
|
-
tiers = []
|
2014
|
-
brackets = info
|
2015
|
-
for i in range(0, len(brackets)):
|
2016
|
-
tier = brackets[i]
|
2017
|
-
tiers.append({
|
2018
|
-
'tier': self.safe_integer(tier, 'bracket'),
|
2019
|
-
'currency': market['settle'],
|
2020
|
-
'minNotional': self.safe_number(tier, 'notionalFloor'),
|
2021
|
-
'maxNotional': self.safe_number(tier, 'notionalCap'),
|
2022
|
-
'maintenanceMarginRate': self.safe_number(tier, 'maintenanceMarginRate'),
|
2023
|
-
'maxLeverage': self.safe_number(tier, 'initialLeverage'),
|
2024
|
-
'info': tier,
|
2025
|
-
})
|
2026
|
-
return tiers
|
2027
|
-
|
2028
|
-
async def fetch_leverage_tiers(self, symbols: Optional[List[str]] = None, params={}):
|
2029
|
-
"""
|
2030
|
-
see https://docs.btcex.com/#get-all-perpetual-instrument-leverage-config
|
2031
|
-
retrieve information on the maximum leverage, for different trade sizes
|
2032
|
-
:param [str]|None symbols: a list of unified market symbols
|
2033
|
-
:param dict params: extra parameters specific to the btcex api endpoint
|
2034
|
-
:returns dict: a dictionary of `leverage tiers structures <https://docs.ccxt.com/#/?id=leverage-tiers-structure>`, indexed by market symbols
|
2035
|
-
"""
|
2036
|
-
await self.load_markets()
|
2037
|
-
response = await self.publicGetGetPerpetualLeverageBracketAll(params)
|
2038
|
-
#
|
2039
|
-
# {
|
2040
|
-
# "jsonrpc": "2.0",
|
2041
|
-
# "usIn": 1674183578745,
|
2042
|
-
# "usOut": 1674183578752,
|
2043
|
-
# "usDiff": 7,
|
2044
|
-
# "result": {
|
2045
|
-
# "WAVES-USDT-PERPETUAL": [
|
2046
|
-
# {
|
2047
|
-
# "bracket": 1,
|
2048
|
-
# "initialLeverage": 50,
|
2049
|
-
# "maintenanceMarginRate": "0.01",
|
2050
|
-
# "notionalCap": "50000",
|
2051
|
-
# "notionalFloor": "0",
|
2052
|
-
# "cum": "0"
|
2053
|
-
# },
|
2054
|
-
# ...
|
2055
|
-
# ]
|
2056
|
-
# }
|
2057
|
-
# }
|
2058
|
-
#
|
2059
|
-
data = self.safe_value(response, 'result', {})
|
2060
|
-
symbols = self.market_symbols(symbols)
|
2061
|
-
return self.parse_leverage_tiers(data, symbols, 'symbol')
|
2062
|
-
|
2063
|
-
def parse_leverage_tiers(self, response, symbols: Optional[List[str]] = None, marketIdKey=None):
|
2064
|
-
#
|
2065
|
-
# {
|
2066
|
-
# "WAVES-USDT-PERPETUAL": [
|
2067
|
-
# {
|
2068
|
-
# "bracket": 1,
|
2069
|
-
# "initialLeverage": 50,
|
2070
|
-
# "maintenanceMarginRate": "0.01",
|
2071
|
-
# "notionalCap": "50000",
|
2072
|
-
# "notionalFloor": "0",
|
2073
|
-
# "cum": "0"
|
2074
|
-
# },
|
2075
|
-
# ...
|
2076
|
-
# ]
|
2077
|
-
# }
|
2078
|
-
#
|
2079
|
-
tiers = {}
|
2080
|
-
result = {}
|
2081
|
-
marketIds = list(response.keys())
|
2082
|
-
for i in range(0, len(marketIds)):
|
2083
|
-
marketId = marketIds[i]
|
2084
|
-
entry = response[marketId]
|
2085
|
-
market = self.safe_market(marketId)
|
2086
|
-
symbol = self.safe_symbol(marketId, market)
|
2087
|
-
symbolsLength = 0
|
2088
|
-
tiers[symbol] = self.parse_market_leverage_tiers(entry, market)
|
2089
|
-
if symbols is not None:
|
2090
|
-
symbolsLength = len(symbols)
|
2091
|
-
if self.in_array(symbol, symbols):
|
2092
|
-
result[symbol] = self.parse_market_leverage_tiers(entry, market)
|
2093
|
-
if symbol is not None and (symbolsLength == 0 or self.in_array(symbol, symbols)):
|
2094
|
-
result[symbol] = self.parse_market_leverage_tiers(entry, market)
|
2095
|
-
return result
|
2096
|
-
|
2097
|
-
async def set_margin_mode(self, marginMode, symbol: Optional[str] = None, params={}):
|
2098
|
-
"""
|
2099
|
-
set margin mode to 'cross' or 'isolated'
|
2100
|
-
see https://docs.btcex.com/#modify-perpetual-instrument-margin-type
|
2101
|
-
:param str marginMode: 'cross' or 'isolated'
|
2102
|
-
:param str|None symbol: unified market symbol
|
2103
|
-
:param dict params: extra parameters specific to the btcex api endpoint
|
2104
|
-
:returns dict: response from the exchange
|
2105
|
-
"""
|
2106
|
-
self.check_required_symbol('setMarginMode', symbol)
|
2107
|
-
await self.sign_in()
|
2108
|
-
await self.load_markets()
|
2109
|
-
market = self.market(symbol)
|
2110
|
-
if not market['swap']:
|
2111
|
-
raise BadRequest(self.id + ' setMarginMode() supports swap contracts only')
|
2112
|
-
if (marginMode != 'isolated') and (marginMode != 'isolate') and (marginMode != 'cross'):
|
2113
|
-
raise BadRequest(self.id + ' marginMode must be either isolated or cross')
|
2114
|
-
marginMode = 'isolate' if (marginMode == 'isolated') else 'cross'
|
2115
|
-
request = {
|
2116
|
-
'instrument_name': market['id'],
|
2117
|
-
'margin_type': marginMode,
|
2118
|
-
}
|
2119
|
-
result = await self.privatePostAdjustPerpetualMarginType(self.extend(request, params))
|
2120
|
-
#
|
2121
|
-
# {
|
2122
|
-
# "id": "1674857919",
|
2123
|
-
# "jsonrpc": "2.0",
|
2124
|
-
# "usIn": 1674857920070,
|
2125
|
-
# "usOut": 1674857920079,
|
2126
|
-
# "usDiff": 9,
|
2127
|
-
# "result": "ok"
|
2128
|
-
# }
|
2129
|
-
#
|
2130
|
-
return result
|
2131
|
-
|
2132
|
-
async def set_leverage(self, leverage, symbol: Optional[str] = None, params={}):
|
2133
|
-
"""
|
2134
|
-
set the leverage amount for a market
|
2135
|
-
see https://docs.btcex.com/#modify-perpetual-instrument-leverage
|
2136
|
-
:param float leverage: the rate of leverage
|
2137
|
-
:param str symbol: unified market symbol
|
2138
|
-
:param dict params: extra parameters specific to the btcex api endpoint
|
2139
|
-
:returns dict: response from the exchange
|
2140
|
-
"""
|
2141
|
-
if symbol is None:
|
2142
|
-
raise ArgumentsRequired(self.id + ' setLeverage() requires a symbol argument')
|
2143
|
-
await self.sign_in()
|
2144
|
-
await self.load_markets()
|
2145
|
-
self.check_required_symbol('setLeverage', symbol)
|
2146
|
-
market = self.market(symbol)
|
2147
|
-
if not market['swap']:
|
2148
|
-
raise BadRequest(self.id + ' setLeverage() supports swap contracts only')
|
2149
|
-
if (leverage < 1) or (leverage > 125):
|
2150
|
-
raise BadRequest(self.id + ' leverage should be between 1 and 125')
|
2151
|
-
request = {
|
2152
|
-
'instrument_name': market['id'],
|
2153
|
-
'leverage': leverage,
|
2154
|
-
}
|
2155
|
-
response = await self.privatePostAdjustPerpetualLeverage(self.extend(request, params))
|
2156
|
-
#
|
2157
|
-
# {
|
2158
|
-
# "id": "1674856410",
|
2159
|
-
# "jsonrpc": "2.0",
|
2160
|
-
# "usIn": 1674856410930,
|
2161
|
-
# "usOut": 1674856410988,
|
2162
|
-
# "usDiff": 58,
|
2163
|
-
# "result": "ok"
|
2164
|
-
# }
|
2165
|
-
#
|
2166
|
-
return response
|
2167
|
-
|
2168
|
-
async def fetch_funding_rates(self, symbols: Optional[List[str]] = None, params={}):
|
2169
|
-
"""
|
2170
|
-
fetch the current funding rates
|
2171
|
-
see https://docs.btcex.com/#contracts
|
2172
|
-
:param [str] symbols: unified market symbols
|
2173
|
-
:param dict params: extra parameters specific to the btcex api endpoint
|
2174
|
-
:returns [dict]: an array of `funding rate structures <https://docs.ccxt.com/#/?id=funding-rate-structure>`
|
2175
|
-
"""
|
2176
|
-
await self.load_markets()
|
2177
|
-
symbols = self.market_symbols(symbols)
|
2178
|
-
response = await self.publicGetCoinGeckoContracts(params)
|
2179
|
-
#
|
2180
|
-
# {
|
2181
|
-
# "jsonrpc": "2.0",
|
2182
|
-
# "usIn": 1674803585896,
|
2183
|
-
# "usOut": 1674803585943,
|
2184
|
-
# "usDiff": 47,
|
2185
|
-
# "result": [
|
2186
|
-
# {
|
2187
|
-
# "ticker_id": "BTC-USDT-PERPETUAL",
|
2188
|
-
# "base_currency": "BTC",
|
2189
|
-
# "target_currency": "USDT",
|
2190
|
-
# "last_price": "23685",
|
2191
|
-
# "base_volume": "167011.37199999999999989",
|
2192
|
-
# "target_volume": "3837763191.33800288010388613",
|
2193
|
-
# "bid": "23684.5",
|
2194
|
-
# "ask": "23685",
|
2195
|
-
# "high": "23971.5",
|
2196
|
-
# "low": "23156",
|
2197
|
-
# "product_type": "perpetual",
|
2198
|
-
# "open_interest": "24242.36",
|
2199
|
-
# "index_price": "23686.4",
|
2200
|
-
# "index_name": "BTC-USDT",
|
2201
|
-
# "index_currency": "BTC",
|
2202
|
-
# "start_timestamp": 1631004005882,
|
2203
|
-
# "funding_rate": "0.000187",
|
2204
|
-
# "next_funding_rate_timestamp": 1675065600000,
|
2205
|
-
# "contract_type": "Quanto",
|
2206
|
-
# "contract_price": "23685",
|
2207
|
-
# "contract_price_currency": "USDT"
|
2208
|
-
# },
|
2209
|
-
# ]
|
2210
|
-
# }
|
2211
|
-
#
|
2212
|
-
data = self.safe_value(response, 'result', [])
|
2213
|
-
result = {}
|
2214
|
-
for i in range(0, len(data)):
|
2215
|
-
entry = data[i]
|
2216
|
-
marketId = self.safe_string(entry, 'ticker_id')
|
2217
|
-
market = self.safe_market(marketId)
|
2218
|
-
symbol = market['symbol']
|
2219
|
-
if symbols is not None:
|
2220
|
-
if self.in_array(symbol, symbols):
|
2221
|
-
result[symbol] = self.parse_funding_rate(entry, market)
|
2222
|
-
else:
|
2223
|
-
result[symbol] = self.parse_funding_rate(entry, market)
|
2224
|
-
return self.filter_by_array(result, 'symbol', symbols)
|
2225
|
-
|
2226
|
-
async def fetch_funding_rate(self, symbol: str, params={}):
|
2227
|
-
"""
|
2228
|
-
fetch the current funding rate
|
2229
|
-
see https://docs.btcex.com/#contracts
|
2230
|
-
:param str symbol: unified market symbol
|
2231
|
-
:param dict params: extra parameters specific to the btcex api endpoint
|
2232
|
-
:returns dict: a `funding rate structure <https://docs.ccxt.com/#/?id=funding-rate-structure>`
|
2233
|
-
"""
|
2234
|
-
await self.load_markets()
|
2235
|
-
market = self.market(symbol)
|
2236
|
-
response = await self.publicGetCoinGeckoContracts(params)
|
2237
|
-
#
|
2238
|
-
# {
|
2239
|
-
# "jsonrpc": "2.0",
|
2240
|
-
# "usIn": 1674803585896,
|
2241
|
-
# "usOut": 1674803585943,
|
2242
|
-
# "usDiff": 47,
|
2243
|
-
# "result": [
|
2244
|
-
# {
|
2245
|
-
# "ticker_id": "BTC-USDT-PERPETUAL",
|
2246
|
-
# "base_currency": "BTC",
|
2247
|
-
# "target_currency": "USDT",
|
2248
|
-
# "last_price": "23685",
|
2249
|
-
# "base_volume": "167011.37199999999999989",
|
2250
|
-
# "target_volume": "3837763191.33800288010388613",
|
2251
|
-
# "bid": "23684.5",
|
2252
|
-
# "ask": "23685",
|
2253
|
-
# "high": "23971.5",
|
2254
|
-
# "low": "23156",
|
2255
|
-
# "product_type": "perpetual",
|
2256
|
-
# "open_interest": "24242.36",
|
2257
|
-
# "index_price": "23686.4",
|
2258
|
-
# "index_name": "BTC-USDT",
|
2259
|
-
# "index_currency": "BTC",
|
2260
|
-
# "start_timestamp": 1631004005882,
|
2261
|
-
# "funding_rate": "0.000187",
|
2262
|
-
# "next_funding_rate_timestamp": 1675065600000,
|
2263
|
-
# "contract_type": "Quanto",
|
2264
|
-
# "contract_price": "23685",
|
2265
|
-
# "contract_price_currency": "USDT"
|
2266
|
-
# },
|
2267
|
-
# ]
|
2268
|
-
# }
|
2269
|
-
#
|
2270
|
-
data = self.safe_value(response, 'result', [])
|
2271
|
-
for i in range(0, len(data)):
|
2272
|
-
entry = data[i]
|
2273
|
-
marketId = self.safe_string(entry, 'ticker_id')
|
2274
|
-
if marketId == market['id']:
|
2275
|
-
return self.parse_funding_rate(entry, market)
|
2276
|
-
return self.parse_funding_rate(data, market)
|
2277
|
-
|
2278
|
-
def parse_funding_rate(self, contract, market=None):
|
2279
|
-
#
|
2280
|
-
# {
|
2281
|
-
# "ticker_id": "BTC-USDT-PERPETUAL",
|
2282
|
-
# "base_currency": "BTC",
|
2283
|
-
# "target_currency": "USDT",
|
2284
|
-
# "last_price": "23685",
|
2285
|
-
# "base_volume": "167011.37199999999999989",
|
2286
|
-
# "target_volume": "3837763191.33800288010388613",
|
2287
|
-
# "bid": "23684.5",
|
2288
|
-
# "ask": "23685",
|
2289
|
-
# "high": "23971.5",
|
2290
|
-
# "low": "23156",
|
2291
|
-
# "product_type": "perpetual",
|
2292
|
-
# "open_interest": "24242.36",
|
2293
|
-
# "index_price": "23686.4",
|
2294
|
-
# "index_name": "BTC-USDT",
|
2295
|
-
# "index_currency": "BTC",
|
2296
|
-
# "start_timestamp": 1631004005882,
|
2297
|
-
# "funding_rate": "0.000187",
|
2298
|
-
# "next_funding_rate_timestamp": 1675065600000,
|
2299
|
-
# "contract_type": "Quanto",
|
2300
|
-
# "contract_price": "23685",
|
2301
|
-
# "contract_price_currency": "USDT"
|
2302
|
-
# }
|
2303
|
-
#
|
2304
|
-
marketId = self.safe_string(contract, 'ticker_id')
|
2305
|
-
fundingTimestamp = self.safe_integer(contract, 'next_funding_rate_timestamp')
|
2306
|
-
return {
|
2307
|
-
'info': contract,
|
2308
|
-
'symbol': self.safe_symbol(marketId, market),
|
2309
|
-
'markPrice': None,
|
2310
|
-
'indexPrice': self.safe_number(contract, 'index_price'),
|
2311
|
-
'interestRate': None,
|
2312
|
-
'estimatedSettlePrice': None,
|
2313
|
-
'timestamp': None,
|
2314
|
-
'datetime': None,
|
2315
|
-
'fundingRate': self.safe_number(contract, 'funding_rate'),
|
2316
|
-
'fundingTimestamp': fundingTimestamp,
|
2317
|
-
'fundingDatetime': self.iso8601(fundingTimestamp),
|
2318
|
-
'nextFundingRate': None,
|
2319
|
-
'nextFundingTimestamp': None,
|
2320
|
-
'nextFundingDatetime': None,
|
2321
|
-
'previousFundingRate': None,
|
2322
|
-
'previousFundingTimestamp': None,
|
2323
|
-
'previousFundingDatetime': None,
|
2324
|
-
}
|
2325
|
-
|
2326
|
-
async def transfer(self, code: str, amount, fromAccount, toAccount, params={}):
|
2327
|
-
"""
|
2328
|
-
transfer currency internally between wallets on the same account
|
2329
|
-
see https://docs.btcex.com/#asset-transfer
|
2330
|
-
:param str code: unified currency code
|
2331
|
-
:param float amount: amount to transfer
|
2332
|
-
:param str fromAccount: account to transfer from
|
2333
|
-
:param str toAccount: account to transfer to
|
2334
|
-
:param dict params: extra parameters specific to the btcex api endpoint
|
2335
|
-
:returns dict: a `transfer structure <https://docs.ccxt.com/#/?id=transfer-structure>`
|
2336
|
-
"""
|
2337
|
-
await self.sign_in()
|
2338
|
-
await self.load_markets()
|
2339
|
-
currency = self.currency(code)
|
2340
|
-
accountsByType = self.safe_value(self.options, 'accountsByType', {})
|
2341
|
-
fromId = self.safe_string(accountsByType, fromAccount, fromAccount)
|
2342
|
-
toId = self.safe_string(accountsByType, toAccount, toAccount)
|
2343
|
-
request = {
|
2344
|
-
'coin_type': currency['id'],
|
2345
|
-
'amount': self.currency_to_precision(code, amount),
|
2346
|
-
'from': fromId, # WALLET, SPOT, PERPETUAL
|
2347
|
-
'to': toId, # WALLET, SPOT, PERPETUAL
|
2348
|
-
}
|
2349
|
-
response = await self.privatePostSubmitTransfer(self.extend(request, params))
|
2350
|
-
#
|
2351
|
-
# {
|
2352
|
-
# "id": "1674937273",
|
2353
|
-
# "jsonrpc": "2.0",
|
2354
|
-
# "usIn": 1674937274762,
|
2355
|
-
# "usOut": 1674937274774,
|
2356
|
-
# "usDiff": 12,
|
2357
|
-
# "result": "ok"
|
2358
|
-
# }
|
2359
|
-
#
|
2360
|
-
return self.parse_transfer(response, currency)
|
2361
|
-
|
2362
|
-
def parse_transfer(self, transfer, currency=None):
|
2363
|
-
#
|
2364
|
-
# {
|
2365
|
-
# "id": "1674937273",
|
2366
|
-
# "jsonrpc": "2.0",
|
2367
|
-
# "usIn": 1674937274762,
|
2368
|
-
# "usOut": 1674937274774,
|
2369
|
-
# "usDiff": 12,
|
2370
|
-
# "result": "ok"
|
2371
|
-
# }
|
2372
|
-
#
|
2373
|
-
return {
|
2374
|
-
'info': transfer,
|
2375
|
-
'id': self.safe_string(transfer, 'id'),
|
2376
|
-
'timestamp': None,
|
2377
|
-
'datetime': None,
|
2378
|
-
'currency': None,
|
2379
|
-
'amount': None,
|
2380
|
-
'fromAccount': None,
|
2381
|
-
'toAccount': None,
|
2382
|
-
'status': None,
|
2383
|
-
}
|
2384
|
-
|
2385
|
-
async def fetch_open_interest(self, symbol: str, params={}):
|
2386
|
-
"""
|
2387
|
-
fetch the open interest of a market
|
2388
|
-
see https://docs.btcex.com/#contracts
|
2389
|
-
:param str symbol: unified CCXT market symbol
|
2390
|
-
:param dict params: extra parameters specific to the btcex api endpoint
|
2391
|
-
:returns dict} an open interest structure{@link https://docs.ccxt.com/#/?id=interest-history-structure:
|
2392
|
-
"""
|
2393
|
-
await self.load_markets()
|
2394
|
-
market = self.market(symbol)
|
2395
|
-
if not market['contract']:
|
2396
|
-
raise BadRequest(self.id + ' fetchOpenInterest() supports contract markets only')
|
2397
|
-
response = await self.publicGetCoinGeckoContracts(params)
|
2398
|
-
#
|
2399
|
-
# {
|
2400
|
-
# "jsonrpc": "2.0",
|
2401
|
-
# "usIn": 1674803585896,
|
2402
|
-
# "usOut": 1674803585943,
|
2403
|
-
# "usDiff": 47,
|
2404
|
-
# "result": [
|
2405
|
-
# {
|
2406
|
-
# "ticker_id": "BTC-USDT-PERPETUAL",
|
2407
|
-
# "base_currency": "BTC",
|
2408
|
-
# "target_currency": "USDT",
|
2409
|
-
# "last_price": "23685",
|
2410
|
-
# "base_volume": "167011.37199999999999989",
|
2411
|
-
# "target_volume": "3837763191.33800288010388613",
|
2412
|
-
# "bid": "23684.5",
|
2413
|
-
# "ask": "23685",
|
2414
|
-
# "high": "23971.5",
|
2415
|
-
# "low": "23156",
|
2416
|
-
# "product_type": "perpetual",
|
2417
|
-
# "open_interest": "24242.36",
|
2418
|
-
# "index_price": "23686.4",
|
2419
|
-
# "index_name": "BTC-USDT",
|
2420
|
-
# "index_currency": "BTC",
|
2421
|
-
# "start_timestamp": 1631004005882,
|
2422
|
-
# "funding_rate": "0.000187",
|
2423
|
-
# "next_funding_rate_timestamp": 1675065600000,
|
2424
|
-
# "contract_type": "Quanto",
|
2425
|
-
# "contract_price": "23685",
|
2426
|
-
# "contract_price_currency": "USDT"
|
2427
|
-
# },
|
2428
|
-
# ]
|
2429
|
-
# }
|
2430
|
-
#
|
2431
|
-
data = self.safe_value(response, 'result', [])
|
2432
|
-
for i in range(0, len(data)):
|
2433
|
-
entry = data[i]
|
2434
|
-
marketId = self.safe_string(entry, 'ticker_id')
|
2435
|
-
if marketId == market['id']:
|
2436
|
-
return self.parse_open_interest(entry, market)
|
2437
|
-
return self.parse_open_interest(data, market)
|
2438
|
-
|
2439
|
-
def parse_open_interest(self, interest, market=None):
|
2440
|
-
#
|
2441
|
-
# {
|
2442
|
-
# "ticker_id": "BTC-USDT-PERPETUAL",
|
2443
|
-
# "base_currency": "BTC",
|
2444
|
-
# "target_currency": "USDT",
|
2445
|
-
# "last_price": "23685",
|
2446
|
-
# "base_volume": "167011.37199999999999989",
|
2447
|
-
# "target_volume": "3837763191.33800288010388613",
|
2448
|
-
# "bid": "23684.5",
|
2449
|
-
# "ask": "23685",
|
2450
|
-
# "high": "23971.5",
|
2451
|
-
# "low": "23156",
|
2452
|
-
# "product_type": "perpetual",
|
2453
|
-
# "open_interest": "24242.36",
|
2454
|
-
# "index_price": "23686.4",
|
2455
|
-
# "index_name": "BTC-USDT",
|
2456
|
-
# "index_currency": "BTC",
|
2457
|
-
# "start_timestamp": 1631004005882,
|
2458
|
-
# "funding_rate": "0.000187",
|
2459
|
-
# "next_funding_rate_timestamp": 1675065600000,
|
2460
|
-
# "contract_type": "Quanto",
|
2461
|
-
# "contract_price": "23685",
|
2462
|
-
# "contract_price_currency": "USDT"
|
2463
|
-
# }
|
2464
|
-
#
|
2465
|
-
marketId = self.safe_string(interest, 'ticker_id')
|
2466
|
-
market = self.safe_market(marketId, market)
|
2467
|
-
openInterest = self.safe_number(interest, 'open_interest')
|
2468
|
-
return {
|
2469
|
-
'info': interest,
|
2470
|
-
'symbol': market['symbol'],
|
2471
|
-
'baseVolume': openInterest,
|
2472
|
-
'quoteVolume': None,
|
2473
|
-
'openInterestAmount': openInterest, # in base currency
|
2474
|
-
'openInterestValue': None,
|
2475
|
-
'timestamp': None,
|
2476
|
-
'datetime': None,
|
2477
|
-
}
|
2478
|
-
|
2479
|
-
def sign(self, path, api='public', method='GET', params={}, headers=None, body=None):
|
2480
|
-
request = '/' + 'api/' + self.version + '/' + api + '/' + path
|
2481
|
-
if api == 'public':
|
2482
|
-
if params:
|
2483
|
-
request += '?' + self.urlencode(params)
|
2484
|
-
if api == 'private':
|
2485
|
-
self.check_required_credentials()
|
2486
|
-
if method == 'GET':
|
2487
|
-
if params:
|
2488
|
-
request += '?' + self.urlencode(params)
|
2489
|
-
sessionToken = self.safe_string(self.options, 'accessToken')
|
2490
|
-
if sessionToken is None:
|
2491
|
-
raise AuthenticationError(self.id + ' sign() requires access token')
|
2492
|
-
headers = {
|
2493
|
-
'Authorization': 'bearer ' + sessionToken,
|
2494
|
-
}
|
2495
|
-
if method == 'POST':
|
2496
|
-
headers['Content-Type'] = 'application/json'
|
2497
|
-
if params:
|
2498
|
-
rpcPayload = {
|
2499
|
-
'jsonrpc': '2.0',
|
2500
|
-
'id': self.nonce(),
|
2501
|
-
'method': '/' + api + '/' + path,
|
2502
|
-
'params': params,
|
2503
|
-
}
|
2504
|
-
body = self.json(rpcPayload)
|
2505
|
-
url = self.urls['api']['rest'] + request
|
2506
|
-
return {'url': url, 'method': method, 'body': body, 'headers': headers}
|
2507
|
-
|
2508
|
-
def handle_errors(self, code, reason, url, method, headers, body, response, requestHeaders, requestBody):
|
2509
|
-
if response is None:
|
2510
|
-
return None # fallback to the default error handler
|
2511
|
-
error = self.safe_value(response, 'error')
|
2512
|
-
if error:
|
2513
|
-
feedback = self.id + ' ' + body
|
2514
|
-
codeInner = self.safe_string(error, 'code')
|
2515
|
-
message = self.safe_string(error, 'message')
|
2516
|
-
self.throw_exactly_matched_exception(self.exceptions['exact'], codeInner, feedback)
|
2517
|
-
self.throw_broadly_matched_exception(self.exceptions['broad'], message, feedback)
|
2518
|
-
raise ExchangeError(feedback) # unknown message
|
2519
|
-
return None
|