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/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.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
- def fetch_markets(self, params={}):
351
- response = 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
- def fetch_ticker(self, symbol: str, params={}):
544
- self.load_markets()
545
- market = self.market(symbol)
546
- request = {
547
- 'instrument_name': market['id'],
548
- }
549
- response = 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
- def fetch_order_book(self, symbol: str, limit: Optional[int] = None, params={}):
580
- 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 = 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
- def fetch_ohlcv(self, symbol: str, timeframe='1m', since: Optional[int] = None, limit: Optional[int] = None, params={}):
631
- 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 = 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
- def fetch_trades(self, symbol: str, since: Optional[int] = None, limit: Optional[int] = None, params={}):
740
- 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 = 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
- 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 = 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
- def fetch_balance(self, params={}):
950
- self.sign_in()
951
- 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 = 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
- def fetch_order(self, id: str, symbol: Optional[str] = None, params={}):
1193
- self.sign_in()
1194
- self.load_markets()
1195
- request = {
1196
- 'order_id': id,
1197
- }
1198
- response = 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
- 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
- self.sign_in()
1261
- 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 = 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
- def cancel_order(self, id: str, symbol: Optional[str] = None, params={}):
1365
- self.sign_in()
1366
- self.load_markets()
1367
- request = {
1368
- 'order_id': id,
1369
- }
1370
- response = 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
- 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
- self.sign_in()
1390
- self.load_markets()
1391
- market = self.market(symbol)
1392
- request = {
1393
- 'instrument_name': market['id'],
1394
- }
1395
- response = 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
- 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
- self.sign_in()
1412
- self.load_markets()
1413
- market = self.market(symbol)
1414
- request = {
1415
- 'instrument_name': market['id'],
1416
- }
1417
- response = 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
- 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
- self.sign_in()
1454
- 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 = 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
- 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
- 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 = 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
- 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
- self.sign_in()
1544
- 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 = 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
- def fetch_position(self, symbol: str, params={}):
1666
- self.sign_in()
1667
- self.load_markets()
1668
- market = self.market(symbol)
1669
- request = {
1670
- 'instrument_name': market['id'],
1671
- }
1672
- response = 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
- def fetch_positions(self, symbols: Optional[List[str]] = None, params={}):
1712
- self.sign_in()
1713
- self.load_markets()
1714
- request = {
1715
- 'currency': 'PERPETUAL',
1716
- # 'kind' : '', # option, future, spot, margin,perpetual The order kind
1717
- }
1718
- response = 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
- 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
- self.sign_in()
1832
- self.load_markets()
1833
- currency = self.safe_currency(code)
1834
- request = {
1835
- 'coin_type': currency['id'],
1836
- }
1837
- response = 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
- 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
- self.sign_in()
1865
- self.load_markets()
1866
- currency = self.safe_currency(code)
1867
- request = {
1868
- 'coin_type': currency['id'],
1869
- # 'withdraw_id': 0,
1870
- }
1871
- response = 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
- 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
- self.sign_in()
1898
- self.load_markets()
1899
- currency = self.safe_currency(code)
1900
- request = {
1901
- 'coin_type': currency['id'],
1902
- 'withdraw_id': id,
1903
- }
1904
- response = 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
- 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
- self.sign_in()
1938
- self.load_markets()
1939
- market = self.market(symbol)
1940
- request = {
1941
- 'instrument_name': market['id'],
1942
- }
1943
- response = 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
- 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
- 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 = 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
- 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
- self.load_markets()
2037
- response = 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
- 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
- self.sign_in()
2108
- 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 = 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
- 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
- self.sign_in()
2144
- 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 = 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
- 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
- self.load_markets()
2177
- symbols = self.market_symbols(symbols)
2178
- response = 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
- 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
- self.load_markets()
2235
- market = self.market(symbol)
2236
- response = 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
- 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
- self.sign_in()
2338
- 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 = 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
- 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
- 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 = 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