ccxt 4.4.59__py2.py3-none-any.whl → 4.4.61__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/gate.py CHANGED
@@ -674,23 +674,67 @@ class gate(Exchange, ImplicitAPI):
674
674
  },
675
675
  'createMarketBuyOrderRequiresPrice': True,
676
676
  'networks': {
677
- 'LINEA': 'LINEAETH',
678
- 'KON': 'KONET',
679
- 'AVAXC': 'AVAX_C',
677
+ 'BTC': 'BTC',
678
+ 'BRC20': 'BTCBRC', # for eg: ORDI, RATS, ...
679
+ 'ETH': 'ETH',
680
+ 'ERC20': 'ETH',
681
+ 'TRX': 'TRX',
682
+ 'TRC20': 'TRX',
683
+ 'HECO': 'HT',
684
+ 'HRC20': 'HT',
685
+ 'BSC': 'BSC',
680
686
  'BEP20': 'BSC',
687
+ 'SOL': 'SOL',
688
+ 'POLYGON': 'POL',
689
+ 'MATIC': 'POL',
690
+ 'OP': 'OPETH',
691
+ 'OPTIMISM': 'OPETH',
692
+ 'ADA': 'ADA', # CARDANO
693
+ 'AVAXC': 'AVAX_C',
694
+ 'NEAR': 'NEAR',
695
+ 'ARBONE': 'ARBEVM',
696
+ 'BASE': 'BASEEVM',
697
+ 'SUI': 'SUI',
698
+ 'CRONOS': 'CRO',
699
+ 'CRO': 'CRO',
700
+ 'APT': 'APT',
701
+ 'SCROLL': 'SCROLLETH',
702
+ 'TAIKO': 'TAIKOETH',
703
+ 'HYPE': 'HYPE',
704
+ 'ALGO': 'ALGO',
705
+ # KAVA: ['KAVA', 'KAVAEVM']
706
+ # SEI: ['SEI', 'SEIEVM']
707
+ 'LINEA': 'LINEAETH',
708
+ 'BLAST': 'BLASTETH',
709
+ 'XLM': 'XLM',
710
+ 'RSK': 'RBTC',
711
+ 'TON': 'TON',
712
+ 'MNT': 'MNT',
713
+ # 'RUNE': 'BTCRUNES', probably, cant verify atm
714
+ 'CELO': 'CELO',
715
+ 'HBAR': 'HBAR',
716
+ # 'FTM': SONIC REBRAND, todo
717
+ 'ZKSERA': 'ZKSERA',
718
+ 'KLAY': 'KLAY',
681
719
  'EOS': 'EOS',
682
- 'ERC20': 'ETH',
720
+ 'ACA': 'ACA',
721
+ # TLOS: ['TLOS', 'TLOSEVM']
722
+ # ASTR: ['ASTR', 'ASTREVM']
723
+ # CFX: ['CFX', 'CFXEVM']
724
+ 'XTZ': 'XTZ',
725
+ 'EGLD': 'EGLD',
726
+ 'GLMR': 'GLMR',
727
+ 'AURORA': 'AURORAEVM',
728
+ # others
729
+ 'KON': 'KONET',
683
730
  'GATECHAIN': 'GTEVM',
684
- 'HRC20': 'HT',
685
731
  'KUSAMA': 'KSMSM',
686
- 'NEAR': 'NEAR',
687
732
  'OKC': 'OKT',
688
- 'OPTIMISM': 'OPETH',
689
- 'POLKADOT': 'DOTSM',
690
- 'TRC20': 'TRX',
733
+ 'POLKADOT': 'DOTSM', # todo: DOT for main DOT
691
734
  'LUNA': 'LUNC',
692
- 'BASE': 'BASEEVM',
693
- 'BRC20': 'BTCBRC',
735
+ },
736
+ 'networksById': {
737
+ 'OPETH': 'OP',
694
738
  },
695
739
  'timeInForce': {
696
740
  'GTC': 'gtc',
@@ -3525,6 +3569,7 @@ class gate(Exchange, ImplicitAPI):
3525
3569
  #
3526
3570
  # public
3527
3571
  #
3572
+ # spot:
3528
3573
  # {
3529
3574
  # "id": "1334253759",
3530
3575
  # "create_time": "1626342738",
@@ -3535,6 +3580,18 @@ class gate(Exchange, ImplicitAPI):
3535
3580
  # "price": "32452.16"
3536
3581
  # }
3537
3582
  #
3583
+ # swap:
3584
+ #
3585
+ # {
3586
+ # "id": "442288327",
3587
+ # "contract": "BTC_USDT",
3588
+ # "create_time": "1739814676.707",
3589
+ # "create_time_ms": "1739814676.707",
3590
+ # "size": "-105",
3591
+ # "price": "95594.8"
3592
+ # }
3593
+ #
3594
+ #
3538
3595
  # public ws
3539
3596
  #
3540
3597
  # {
@@ -3611,8 +3668,14 @@ class gate(Exchange, ImplicitAPI):
3611
3668
  # }
3612
3669
  #
3613
3670
  id = self.safe_string_2(trade, 'id', 'trade_id')
3614
- timestamp = self.safe_timestamp_2(trade, 'time', 'create_time')
3615
- timestamp = self.safe_integer(trade, 'create_time_ms', timestamp)
3671
+ timestamp: Int = None
3672
+ msString = self.safe_string(trade, 'create_time_ms')
3673
+ if msString is not None:
3674
+ msString = Precise.string_mul(msString, '1000')
3675
+ msString = msString[0:13]
3676
+ timestamp = self.parse_to_int(msString)
3677
+ else:
3678
+ timestamp = self.safe_timestamp_2(trade, 'time', 'create_time')
3616
3679
  marketId = self.safe_string_2(trade, 'currency_pair', 'contract')
3617
3680
  marketType = 'contract' if ('contract' in trade) else 'spot'
3618
3681
  market = self.safe_market(marketId, market, '_', marketType)
ccxt/hollaex.py CHANGED
@@ -1882,7 +1882,7 @@ class hollaex(Exchange, ImplicitAPI):
1882
1882
  # "network":"https://api.hollaex.network"
1883
1883
  # }
1884
1884
  #
1885
- coins = self.safe_list(response, 'coins')
1885
+ coins = self.safe_dict(response, 'coins', {})
1886
1886
  return self.parse_deposit_withdraw_fees(coins, codes, 'symbol')
1887
1887
 
1888
1888
  def normalize_number_if_needed(self, number):
ccxt/oxfun.py CHANGED
@@ -2884,7 +2884,7 @@ class oxfun(Exchange, ImplicitAPI):
2884
2884
  'AccessKey': self.apiKey,
2885
2885
  'Timestamp': datetime,
2886
2886
  'Signature': signature,
2887
- 'Nonce': nonce,
2887
+ 'Nonce': str(nonce),
2888
2888
  }
2889
2889
  return {'url': url, 'method': method, 'body': body, 'headers': headers}
2890
2890
 
ccxt/phemex.py CHANGED
@@ -1078,7 +1078,7 @@ class phemex(Exchange, ImplicitAPI):
1078
1078
  for i in range(0, len(products)):
1079
1079
  market = products[i]
1080
1080
  type = self.safe_string_lower(market, 'type')
1081
- if (type == 'perpetual') or (type == 'perpetualv2'):
1081
+ if (type == 'perpetual') or (type == 'perpetualv2') or (type == 'PerpetualPilot'):
1082
1082
  id = self.safe_string(market, 'symbol')
1083
1083
  riskLimitValues = self.safe_value(riskLimitsById, id, {})
1084
1084
  market = self.extend(market, riskLimitValues)
ccxt/pro/__init__.py CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  # ----------------------------------------------------------------------------
6
6
 
7
- __version__ = '4.4.59'
7
+ __version__ = '4.4.61'
8
8
 
9
9
  # ----------------------------------------------------------------------------
10
10
 
ccxt/pro/gate.py CHANGED
@@ -1493,6 +1493,27 @@ class gate(ccxt.async_support.gate):
1493
1493
  # data: {errs: {label: 'AUTHENTICATION_FAILED', message: 'Not login'}},
1494
1494
  # request_id: '10406147'
1495
1495
  # }
1496
+ # {
1497
+ # "time": 1739853211,
1498
+ # "time_ms": 1739853211201,
1499
+ # "id": 1,
1500
+ # "conn_id": "62f2c1dabbe186d7",
1501
+ # "trace_id": "cdb02a8c0b61086b2fe6f8fad2f98c54",
1502
+ # "channel": "spot.trades",
1503
+ # "event": "subscribe",
1504
+ # "payload": [
1505
+ # "LUNARLENS_USDT",
1506
+ # "ETH_USDT"
1507
+ # ],
1508
+ # "error": {
1509
+ # "code": 2,
1510
+ # "message": "unknown currency pair: LUNARLENS_USDT"
1511
+ # },
1512
+ # "result": {
1513
+ # "status": "fail"
1514
+ # },
1515
+ # "requestId": "cdb02a8c0b61086b2fe6f8fad2f98c54"
1516
+ # }
1496
1517
  #
1497
1518
  data = self.safe_dict(message, 'data')
1498
1519
  errs = self.safe_dict(data, 'errs')
@@ -1511,6 +1532,17 @@ class gate(ccxt.async_support.gate):
1511
1532
  client.reject(e, messageHash)
1512
1533
  if (messageHash is not None) and (messageHash in client.subscriptions):
1513
1534
  del client.subscriptions[messageHash]
1535
+ # remove subscriptions for watchSymbols
1536
+ channel = self.safe_string(message, 'channel')
1537
+ if (channel is not None) and (channel.find('.') > 0):
1538
+ parsedChannel = channel.split('.')
1539
+ payload = self.safe_list(message, 'payload', [])
1540
+ for i in range(0, len(payload)):
1541
+ marketType = parsedChannel[0] == 'swap' if 'futures' else parsedChannel[0]
1542
+ symbol = self.safe_symbol(payload[i], None, '_', marketType)
1543
+ messageHashSymbol = parsedChannel[1] + ':' + symbol
1544
+ if (messageHashSymbol is not None) and (messageHashSymbol in client.subscriptions):
1545
+ del client.subscriptions[messageHashSymbol]
1514
1546
  if (id is not None) and (id in client.subscriptions):
1515
1547
  del client.subscriptions[id]
1516
1548
  return True
ccxt/pro/xt.py CHANGED
@@ -4,8 +4,8 @@
4
4
  # https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
5
5
 
6
6
  import ccxt.async_support
7
- from ccxt.async_support.base.ws.cache import ArrayCache, ArrayCacheBySymbolById, ArrayCacheByTimestamp
8
- from ccxt.base.types import Any, Balances, Int, Market, Order, OrderBook, Str, Strings, Ticker, Tickers, Trade
7
+ from ccxt.async_support.base.ws.cache import ArrayCache, ArrayCacheBySymbolById, ArrayCacheBySymbolBySide, ArrayCacheByTimestamp
8
+ from ccxt.base.types import Any, Balances, Int, Market, Order, OrderBook, Position, Str, Strings, Ticker, Tickers, Trade
9
9
  from ccxt.async_support.base.ws.client import Client
10
10
  from typing import List
11
11
 
@@ -25,7 +25,7 @@ class xt(ccxt.async_support.xt):
25
25
  'watchBalance': True,
26
26
  'watchOrders': True,
27
27
  'watchMyTrades': True,
28
- 'watchPositions': None, # TODO https://doc.xt.com/#futures_user_websocket_v2position
28
+ 'watchPositions': True,
29
29
  },
30
30
  'urls': {
31
31
  'api': {
@@ -45,6 +45,11 @@ class xt(ccxt.async_support.xt):
45
45
  'watchTickers': {
46
46
  'method': 'tickers', # agg_tickers(contract only)
47
47
  },
48
+ 'watchPositions': {
49
+ 'type': 'swap',
50
+ 'fetchPositionsSnapshot': True,
51
+ 'awaitPositionsSnapshot': True,
52
+ },
48
53
  },
49
54
  'streaming': {
50
55
  'keepAlive': 20000,
@@ -352,6 +357,106 @@ class xt(ccxt.async_support.xt):
352
357
  name = 'balance'
353
358
  return await self.subscribe(name, 'private', 'watchBalance', None, None, params)
354
359
 
360
+ async def watch_positions(self, symbols: Strings = None, since: Int = None, limit: Int = None, params={}) -> List[Position]:
361
+ """
362
+
363
+ https://doc.xt.com/#futures_user_websocket_v2position
364
+
365
+ watch all open positions
366
+ :param str[]|None symbols: list of unified market symbols
367
+ :param number [since]: since timestamp
368
+ :param number [limit]: limit
369
+ :param dict params: extra parameters specific to the exchange API endpoint
370
+ :returns dict[]: a list of `position structure <https://docs.ccxt.com/en/latest/manual.html#position-structure>`
371
+ """
372
+ await self.load_markets()
373
+ url = self.urls['api']['ws']['contract'] + '/' + 'user'
374
+ client = self.client(url)
375
+ self.set_positions_cache(client)
376
+ fetchPositionsSnapshot = self.handle_option('watchPositions', 'fetchPositionsSnapshot', True)
377
+ awaitPositionsSnapshot = self.handle_option('watchPositions', 'awaitPositionsSnapshot', True)
378
+ cache = self.positions
379
+ if fetchPositionsSnapshot and awaitPositionsSnapshot and self.is_empty(cache):
380
+ snapshot = await client.future('fetchPositionsSnapshot')
381
+ return self.filter_by_symbols_since_limit(snapshot, symbols, since, limit, True)
382
+ name = 'position'
383
+ newPositions = await self.subscribe(name, 'private', 'watchPositions', None, None, params)
384
+ if self.newUpdates:
385
+ return newPositions
386
+ return self.filter_by_symbols_since_limit(cache, symbols, since, limit, True)
387
+
388
+ def set_positions_cache(self, client: Client):
389
+ if self.positions is None:
390
+ self.positions = ArrayCacheBySymbolBySide()
391
+ fetchPositionsSnapshot = self.handle_option('watchPositions', 'fetchPositionsSnapshot')
392
+ if fetchPositionsSnapshot:
393
+ messageHash = 'fetchPositionsSnapshot'
394
+ if not (messageHash in client.futures):
395
+ client.future(messageHash)
396
+ self.spawn(self.load_positions_snapshot, client, messageHash)
397
+
398
+ async def load_positions_snapshot(self, client, messageHash):
399
+ positions = await self.fetch_positions(None)
400
+ self.positions = ArrayCacheBySymbolBySide()
401
+ cache = self.positions
402
+ for i in range(0, len(positions)):
403
+ position = positions[i]
404
+ contracts = self.safe_number(position, 'contracts', 0)
405
+ if contracts > 0:
406
+ cache.append(position)
407
+ # don't remove the future from the .futures cache
408
+ future = client.futures[messageHash]
409
+ future.resolve(cache)
410
+ client.resolve(cache, 'position::contract')
411
+
412
+ def handle_position(self, client, message):
413
+ #
414
+ # {
415
+ # topic: 'position',
416
+ # event: 'position',
417
+ # data: {
418
+ # accountId: 245296,
419
+ # accountType: 0,
420
+ # symbol: 'eth_usdt',
421
+ # contractType: 'PERPETUAL',
422
+ # positionType: 'CROSSED',
423
+ # positionSide: 'LONG',
424
+ # positionSize: '1',
425
+ # closeOrderSize: '0',
426
+ # availableCloseSize: '1',
427
+ # realizedProfit: '-0.0121',
428
+ # entryPrice: '2637.87',
429
+ # openOrderSize: '1',
430
+ # isolatedMargin: '2.63787',
431
+ # openOrderMarginFrozen: '2.78832014',
432
+ # underlyingType: 'U_BASED',
433
+ # leverage: 10,
434
+ # welfareAccount: False,
435
+ # profitFixedLatest: {},
436
+ # closeProfit: '0.0000',
437
+ # totalFee: '-0.0158',
438
+ # totalFundFee: '0.0037',
439
+ # markPrice: '2690.96'
440
+ # }
441
+ # }
442
+ #
443
+ if self.positions is None:
444
+ self.positions = ArrayCacheBySymbolBySide()
445
+ cache = self.positions
446
+ data = self.safe_dict(message, 'data', {})
447
+ position = self.parse_position(data)
448
+ cache.append(position)
449
+ messageHashes = self.find_message_hashes(client, 'position::contract')
450
+ for i in range(0, len(messageHashes)):
451
+ messageHash = messageHashes[i]
452
+ parts = messageHash.split('::')
453
+ symbolsString = parts[1]
454
+ symbols = symbolsString.split(',')
455
+ positions = self.filter_by_array([position], 'symbol', symbols, False)
456
+ if not self.is_empty(positions):
457
+ client.resolve(positions, messageHash)
458
+ client.resolve([position], 'position::contract')
459
+
355
460
  def handle_ticker(self, client: Client, message: dict):
356
461
  #
357
462
  # spot
@@ -1036,6 +1141,7 @@ class xt(ccxt.async_support.xt):
1036
1141
  'agg_tickers': self.handle_tickers,
1037
1142
  'balance': self.handle_balance,
1038
1143
  'order': self.handle_order,
1144
+ 'position': self.handle_position,
1039
1145
  }
1040
1146
  method = self.safe_value(methods, topic)
1041
1147
  if topic == 'trade':
ccxt/test/tests_async.py CHANGED
@@ -620,10 +620,21 @@ class testMainClass:
620
620
  dump('[TEST_WARNING]' + error_message)
621
621
  return True
622
622
 
623
+ def check_constructor(self, exchange):
624
+ # todo: this might be moved in base tests later
625
+ if exchange.id == 'binance':
626
+ assert exchange.hostname is None, 'binance.com hostname should be empty'
627
+ assert exchange.urls['api']['public'] == 'https://api.binance.com/api/v3', 'https://api.binance.com/api/v3 does not match: ' + exchange.urls['api']['public']
628
+ assert ('lending/union/account' in exchange.api['sapi']['get']), 'SAPI should contain the endpoint lending/union/account, ' + json_stringify(exchange.api['sapi']['get'])
629
+ elif exchange.id == 'binanceus':
630
+ assert exchange.hostname == 'binance.us', 'binance.us hostname does not match ' + exchange.hostname
631
+ assert exchange.urls['api']['public'] == 'https://api.binance.us/api/v3', 'https://api.binance.us/api/v3 does not match: ' + exchange.urls['api']['public']
632
+
623
633
  async def start_test(self, exchange, symbol):
624
634
  # we do not need to test aliases
625
635
  if exchange.alias:
626
636
  return True
637
+ self.check_constructor(exchange)
627
638
  if self.sandbox or get_exchange_prop(exchange, 'sandbox'):
628
639
  exchange.set_sandbox_mode(True)
629
640
  try:
ccxt/test/tests_sync.py CHANGED
@@ -617,10 +617,21 @@ class testMainClass:
617
617
  dump('[TEST_WARNING]' + error_message)
618
618
  return True
619
619
 
620
+ def check_constructor(self, exchange):
621
+ # todo: this might be moved in base tests later
622
+ if exchange.id == 'binance':
623
+ assert exchange.hostname is None, 'binance.com hostname should be empty'
624
+ assert exchange.urls['api']['public'] == 'https://api.binance.com/api/v3', 'https://api.binance.com/api/v3 does not match: ' + exchange.urls['api']['public']
625
+ assert ('lending/union/account' in exchange.api['sapi']['get']), 'SAPI should contain the endpoint lending/union/account, ' + json_stringify(exchange.api['sapi']['get'])
626
+ elif exchange.id == 'binanceus':
627
+ assert exchange.hostname == 'binance.us', 'binance.us hostname does not match ' + exchange.hostname
628
+ assert exchange.urls['api']['public'] == 'https://api.binance.us/api/v3', 'https://api.binance.us/api/v3 does not match: ' + exchange.urls['api']['public']
629
+
620
630
  def start_test(self, exchange, symbol):
621
631
  # we do not need to test aliases
622
632
  if exchange.alias:
623
633
  return True
634
+ self.check_constructor(exchange)
624
635
  if self.sandbox or get_exchange_prop(exchange, 'sandbox'):
625
636
  exchange.set_sandbox_mode(True)
626
637
  try:
ccxt/xt.py CHANGED
@@ -1393,9 +1393,15 @@ class xt(Exchange, ImplicitAPI):
1393
1393
  :param int [since]: timestamp in ms of the earliest candle to fetch
1394
1394
  :param int [limit]: the maximum amount of candles to fetch
1395
1395
  :param dict params: extra parameters specific to the xt api endpoint
1396
+ :param int [params.until]: timestamp in ms of the latest candle to fetch
1397
+ :param boolean [params.paginate]: default False, when True will automatically paginate by calling self endpoint multiple times. See in the docs all the [available parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
1396
1398
  :returns int[][]: A list of candles ordered, open, high, low, close, volume
1397
1399
  """
1398
1400
  self.load_markets()
1401
+ paginate = False
1402
+ paginate, params = self.handle_option_and_params(params, 'fetchOHLCV', 'paginate', False)
1403
+ if paginate:
1404
+ return self.fetch_paginated_call_deterministic('fetchOHLCV', symbol, since, limit, timeframe, params, 1000)
1399
1405
  market = self.market(symbol)
1400
1406
  request = {
1401
1407
  'symbol': market['id'],
@@ -1405,6 +1411,12 @@ class xt(Exchange, ImplicitAPI):
1405
1411
  request['startTime'] = since
1406
1412
  if limit is not None:
1407
1413
  request['limit'] = limit
1414
+ else:
1415
+ request['limit'] = 1000
1416
+ until = self.safe_integer(params, 'until')
1417
+ params = self.omit(params, ['until'])
1418
+ if until is not None:
1419
+ request['endTime'] = until
1408
1420
  response = None
1409
1421
  if market['linear']:
1410
1422
  response = self.publicLinearGetFutureMarketV1PublicQKline(self.extend(request, params))
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ccxt
3
- Version: 4.4.59
3
+ Version: 4.4.61
4
4
  Summary: A JavaScript / TypeScript / Python / C# / PHP cryptocurrency trading library with support for 100+ exchanges
5
5
  Home-page: https://ccxt.com
6
6
  Author: Igor Kroitor
@@ -277,13 +277,13 @@ console.log(version, Object.keys(exchanges));
277
277
 
278
278
  All-in-one browser bundle (dependencies included), served from a CDN of your choice:
279
279
 
280
- * jsDelivr: https://cdn.jsdelivr.net/npm/ccxt@4.4.59/dist/ccxt.browser.min.js
281
- * unpkg: https://unpkg.com/ccxt@4.4.59/dist/ccxt.browser.min.js
280
+ * jsDelivr: https://cdn.jsdelivr.net/npm/ccxt@4.4.61/dist/ccxt.browser.min.js
281
+ * unpkg: https://unpkg.com/ccxt@4.4.61/dist/ccxt.browser.min.js
282
282
 
283
283
  CDNs are not updated in real-time and may have delays. Defaulting to the most recent version without specifying the version number is not recommended. Please, keep in mind that we are not responsible for the correct operation of those CDN servers.
284
284
 
285
285
  ```HTML
286
- <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/ccxt@4.4.59/dist/ccxt.browser.min.js"></script>
286
+ <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/ccxt@4.4.61/dist/ccxt.browser.min.js"></script>
287
287
  ```
288
288
 
289
289
  Creates a global `ccxt` object: