ccxt 4.4.6__py2.py3-none-any.whl → 4.4.7__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/bitmart.py CHANGED
@@ -2206,7 +2206,7 @@ class bitmart(Exchange, ImplicitAPI):
2206
2206
 
2207
2207
  def parse_order(self, order: dict, market: Market = None) -> Order:
2208
2208
  #
2209
- # createOrder
2209
+ # createOrder, editOrder
2210
2210
  #
2211
2211
  # {
2212
2212
  # "order_id": 2707217580
@@ -4466,6 +4466,114 @@ class bitmart(Exchange, ImplicitAPI):
4466
4466
  'datetime': self.iso8601(timestamp),
4467
4467
  })
4468
4468
 
4469
+ def edit_order(self, id: str, symbol: str, type: OrderType, side: OrderSide, amount: Num = None, price: Num = None, params={}) -> Order:
4470
+ """
4471
+ edits an open order
4472
+ :see: https://developer-pro.bitmart.com/en/futuresv2/#modify-plan-order-signed
4473
+ :see: https://developer-pro.bitmart.com/en/futuresv2/#modify-tp-sl-order-signed
4474
+ :see: https://developer-pro.bitmart.com/en/futuresv2/#modify-preset-plan-order-signed
4475
+ :param str id: order id
4476
+ :param str symbol: unified symbol of the market to edit an order in
4477
+ :param str type: 'market' or 'limit'
4478
+ :param str side: 'buy' or 'sell'
4479
+ :param float [amount]: how much you want to trade in units of the base currency
4480
+ :param float [price]: the price to fulfill the order, in units of the quote currency, ignored in market orders
4481
+ :param dict [params]: extra parameters specific to the exchange API endpoint
4482
+ :param str [params.triggerPrice]: *swap only* the price to trigger a stop order
4483
+ :param str [params.stopLossPrice]: *swap only* the price to trigger a stop-loss order
4484
+ :param str [params.takeProfitPrice]: *swap only* the price to trigger a take-profit order
4485
+ :param str [params.stopLoss.triggerPrice]: *swap only* the price to trigger a preset stop-loss order
4486
+ :param str [params.takeProfit.triggerPrice]: *swap only* the price to trigger a preset take-profit order
4487
+ :param str [params.clientOrderId]: client order id of the order
4488
+ :param int [params.price_type]: *swap only* 1: last price, 2: fair price, default is 1
4489
+ :param int [params.plan_category]: *swap tp/sl only* 1: tp/sl, 2: position tp/sl, default is 1
4490
+ :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
4491
+ """
4492
+ self.load_markets()
4493
+ market = self.market(symbol)
4494
+ if not market['swap']:
4495
+ raise NotSupported(self.id + ' editOrder() does not support ' + market['type'] + ' markets, only swap markets are supported')
4496
+ stopLossPrice = self.safe_string(params, 'stopLossPrice')
4497
+ takeProfitPrice = self.safe_string(params, 'takeProfitPrice')
4498
+ triggerPrice = self.safe_string_n(params, ['triggerPrice', 'stopPrice', 'trigger_price'])
4499
+ stopLoss = self.safe_dict(params, 'stopLoss', {})
4500
+ takeProfit = self.safe_dict(params, 'takeProfit', {})
4501
+ presetStopLoss = self.safe_string(stopLoss, 'triggerPrice')
4502
+ presetTakeProfit = self.safe_string(takeProfit, 'triggerPrice')
4503
+ isTriggerOrder = triggerPrice is not None
4504
+ isStopLoss = stopLossPrice is not None
4505
+ isTakeProfit = takeProfitPrice is not None
4506
+ isPresetStopLoss = presetStopLoss is not None
4507
+ isPresetTakeProfit = presetTakeProfit is not None
4508
+ request: dict = {
4509
+ 'symbol': market['id'],
4510
+ }
4511
+ clientOrderId = self.safe_string(params, 'clientOrderId')
4512
+ if clientOrderId is not None:
4513
+ params = self.omit(params, 'clientOrderId')
4514
+ request['client_order_id'] = clientOrderId
4515
+ if id is not None:
4516
+ request['order_id'] = id
4517
+ params = self.omit(params, ['triggerPrice', 'stopPrice', 'stopLossPrice', 'takeProfitPrice', 'stopLoss', 'takeProfit'])
4518
+ response = None
4519
+ if isTriggerOrder or isStopLoss or isTakeProfit:
4520
+ request['price_type'] = self.safe_integer(params, 'price_type', 1)
4521
+ if price is not None:
4522
+ request['executive_price'] = self.price_to_precision(symbol, price)
4523
+ if isTriggerOrder:
4524
+ request['type'] = type
4525
+ request['trigger_price'] = self.price_to_precision(symbol, triggerPrice)
4526
+ response = self.privatePostContractPrivateModifyPlanOrder(self.extend(request, params))
4527
+ #
4528
+ # {
4529
+ # "code": 1000,
4530
+ # "message": "Ok",
4531
+ # "data": {
4532
+ # "order_id": "3000023150003503"
4533
+ # },
4534
+ # "trace": "324523453245.108.1734567125596324575"
4535
+ # }
4536
+ #
4537
+ elif isStopLoss or isTakeProfit:
4538
+ request['category'] = type
4539
+ if isStopLoss:
4540
+ request['trigger_price'] = self.price_to_precision(symbol, stopLossPrice)
4541
+ else:
4542
+ request['trigger_price'] = self.price_to_precision(symbol, takeProfitPrice)
4543
+ response = self.privatePostContractPrivateModifyTpSlOrder(self.extend(request, params))
4544
+ #
4545
+ # {
4546
+ # "code": 1000,
4547
+ # "message": "Ok",
4548
+ # "data": {
4549
+ # "order_id": "3000023150003480"
4550
+ # },
4551
+ # "trace": "23452345.104.1724536582682345459"
4552
+ # }
4553
+ #
4554
+ elif isPresetStopLoss or isPresetTakeProfit:
4555
+ if isPresetStopLoss:
4556
+ request['preset_stop_loss_price_type'] = self.safe_integer(params, 'price_type', 1)
4557
+ request['preset_stop_loss_price'] = self.price_to_precision(symbol, presetStopLoss)
4558
+ else:
4559
+ request['preset_take_profit_price_type'] = self.safe_integer(params, 'price_type', 1)
4560
+ request['preset_take_profit_price'] = self.price_to_precision(symbol, presetTakeProfit)
4561
+ response = self.privatePostContractPrivateModifyPresetPlanOrder(self.extend(request, params))
4562
+ #
4563
+ # {
4564
+ # "code": 1000,
4565
+ # "message": "Ok",
4566
+ # "data": {
4567
+ # "order_id": "3000023150003496"
4568
+ # },
4569
+ # "trace": "a5c3234534534a836bc476a203.123452.172716624359200197"
4570
+ # }
4571
+ #
4572
+ else:
4573
+ raise NotSupported(self.id + ' editOrder() only supports trigger, stop loss and take profit orders')
4574
+ data = self.safe_dict(response, 'data', {})
4575
+ return self.parse_order(data, market)
4576
+
4469
4577
  def nonce(self):
4470
4578
  return self.milliseconds()
4471
4579
 
ccxt/bybit.py CHANGED
@@ -5785,13 +5785,17 @@ class bybit(Exchange, ImplicitAPI):
5785
5785
  currencyId = self.safe_string_2(item, 'coin', 'currency')
5786
5786
  code = self.safe_currency_code(currencyId, currency)
5787
5787
  currency = self.safe_currency(currencyId, currency)
5788
- amount = self.safe_string_2(item, 'amount', 'change')
5789
- after = self.safe_string_2(item, 'wallet_balance', 'cashBalance')
5790
- direction = 'out' if Precise.string_lt(amount, '0') else 'in'
5788
+ amountString = self.safe_string_2(item, 'amount', 'change')
5789
+ afterString = self.safe_string_2(item, 'wallet_balance', 'cashBalance')
5790
+ direction = 'out' if Precise.string_lt(amountString, '0') else 'in'
5791
5791
  before = None
5792
- if after is not None and amount is not None:
5793
- difference = amount if (direction == 'out') else Precise.string_neg(amount)
5794
- before = Precise.string_add(after, difference)
5792
+ after = None
5793
+ amount = None
5794
+ if afterString is not None and amountString is not None:
5795
+ difference = amountString if (direction == 'out') else Precise.string_neg(amountString)
5796
+ before = self.parse_to_numeric(Precise.string_add(afterString, difference))
5797
+ after = self.parse_to_numeric(afterString)
5798
+ amount = self.parse_to_numeric(Precise.string_abs(amountString))
5795
5799
  timestamp = self.parse8601(self.safe_string(item, 'exec_time'))
5796
5800
  if timestamp is None:
5797
5801
  timestamp = self.safe_integer(item, 'transactionTime')
@@ -5804,15 +5808,15 @@ class bybit(Exchange, ImplicitAPI):
5804
5808
  'referenceAccount': None,
5805
5809
  'type': self.parse_ledger_entry_type(self.safe_string(item, 'type')),
5806
5810
  'currency': code,
5807
- 'amount': self.parse_to_numeric(Precise.string_abs(amount)),
5811
+ 'amount': amount,
5808
5812
  'timestamp': timestamp,
5809
5813
  'datetime': self.iso8601(timestamp),
5810
- 'before': self.parse_to_numeric(before),
5811
- 'after': self.parse_to_numeric(after),
5814
+ 'before': before,
5815
+ 'after': after,
5812
5816
  'status': 'ok',
5813
5817
  'fee': {
5814
5818
  'currency': code,
5815
- 'cost': self.parse_to_numeric(self.safe_string(item, 'fee')),
5819
+ 'cost': self.safe_number(item, 'fee'),
5816
5820
  },
5817
5821
  }, currency)
5818
5822
 
ccxt/gate.py CHANGED
@@ -657,6 +657,9 @@ class gate(Exchange, ImplicitAPI):
657
657
  'OPTIMISM': 'OPETH',
658
658
  'POLKADOT': 'DOTSM',
659
659
  'TRC20': 'TRX',
660
+ 'LUNA': 'LUNC',
661
+ 'BASE': 'BASEEVM',
662
+ 'BRC20': 'BTCBRC',
660
663
  },
661
664
  'timeInForce': {
662
665
  'GTC': 'gtc',
ccxt/kucoin.py CHANGED
@@ -777,7 +777,7 @@ class kucoin(Exchange, ImplicitAPI):
777
777
  'hf': 'trade_hf',
778
778
  },
779
779
  'networks': {
780
- 'BTC': 'btc',
780
+ 'BRC20': 'btc',
781
781
  'BTCNATIVESEGWIT': 'bech32',
782
782
  'ERC20': 'eth',
783
783
  'TRC20': 'trx',
@@ -1343,7 +1343,7 @@ class kucoin(Exchange, ImplicitAPI):
1343
1343
  for j in range(0, chainsLength):
1344
1344
  chain = chains[j]
1345
1345
  chainId = self.safe_string(chain, 'chainId')
1346
- networkCode = self.network_id_to_code(chainId)
1346
+ networkCode = self.network_id_to_code(chainId, code)
1347
1347
  chainWithdrawEnabled = self.safe_bool(chain, 'isWithdrawEnabled', False)
1348
1348
  if isWithdrawEnabled is None:
1349
1349
  isWithdrawEnabled = chainWithdrawEnabled
ccxt/mexc.py CHANGED
@@ -54,8 +54,8 @@ class mexc(Exchange, ImplicitAPI):
54
54
  'closePosition': False,
55
55
  'createDepositAddress': True,
56
56
  'createMarketBuyOrderWithCost': True,
57
- 'createMarketOrderWithCost': False,
58
- 'createMarketSellOrderWithCost': False,
57
+ 'createMarketOrderWithCost': True,
58
+ 'createMarketSellOrderWithCost': True,
59
59
  'createOrder': True,
60
60
  'createOrders': True,
61
61
  'createPostOnlyOrder': True,
@@ -144,7 +144,7 @@ class mexc(Exchange, ImplicitAPI):
144
144
  'repayCrossMargin': False,
145
145
  'repayIsolatedMargin': False,
146
146
  'setLeverage': True,
147
- 'setMarginMode': None,
147
+ 'setMarginMode': True,
148
148
  'setPositionMode': True,
149
149
  'signIn': None,
150
150
  'transfer': None,
@@ -430,7 +430,6 @@ class mexc(Exchange, ImplicitAPI):
430
430
  'options': {
431
431
  'adjustForTimeDifference': False,
432
432
  'timeDifference': 0,
433
- 'createMarketBuyOrderRequiresPrice': True,
434
433
  'unavailableContracts': {
435
434
  'BTC/USDT:USDT': True,
436
435
  'LTC/USDT:USDT': True,
@@ -479,12 +478,14 @@ class mexc(Exchange, ImplicitAPI):
479
478
  'LTC': 'LTC',
480
479
  },
481
480
  'networks': {
481
+ 'ZKSYNC': 'ZKSYNCERA',
482
482
  'TRC20': 'TRX',
483
483
  'TON': 'TONCOIN',
484
484
  'AVAXC': 'AVAX_CCHAIN',
485
485
  'ERC20': 'ETH',
486
486
  'ACA': 'ACALA',
487
487
  'BEP20': 'BSC',
488
+ 'OPTIMISM': 'OP',
488
489
  # 'ADA': 'Cardano(ADA)',
489
490
  # 'AE': 'AE',
490
491
  # 'ALGO': 'Algorand(ALGO)',
@@ -2018,8 +2019,24 @@ class mexc(Exchange, ImplicitAPI):
2018
2019
  market = self.market(symbol)
2019
2020
  if not market['spot']:
2020
2021
  raise NotSupported(self.id + ' createMarketBuyOrderWithCost() supports spot orders only')
2021
- params['createMarketBuyOrderRequiresPrice'] = False
2022
- return self.create_order(symbol, 'market', 'buy', cost, None, params)
2022
+ params['cost'] = cost
2023
+ return self.create_order(symbol, 'market', 'buy', 0, None, params)
2024
+
2025
+ def create_market_sell_order_with_cost(self, symbol: str, cost: float, params={}):
2026
+ """
2027
+ create a market sell order by providing the symbol and cost
2028
+ :see: https://mexcdevelop.github.io/apidocs/spot_v3_en/#new-order
2029
+ :param str symbol: unified symbol of the market to create an order in
2030
+ :param float cost: how much you want to trade in units of the quote currency
2031
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2032
+ :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
2033
+ """
2034
+ self.load_markets()
2035
+ market = self.market(symbol)
2036
+ if not market['spot']:
2037
+ raise NotSupported(self.id + ' createMarketBuyOrderWithCost() supports spot orders only')
2038
+ params['cost'] = cost
2039
+ return self.create_order(symbol, 'market', 'sell', 0, None, params)
2023
2040
 
2024
2041
  def create_order(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}):
2025
2042
  """
@@ -2043,6 +2060,7 @@ class mexc(Exchange, ImplicitAPI):
2043
2060
  :param long [params.positionId]: *contract only* it is recommended to hasattr(self, fill) parameter when closing a position
2044
2061
  :param str [params.externalOid]: *contract only* external order ID
2045
2062
  :param int [params.positionMode]: *contract only* 1:hedge, 2:one-way, default: the user's current config
2063
+ :param boolean [params.test]: *spot only* whether to use the test endpoint or not, default is False
2046
2064
  :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
2047
2065
  """
2048
2066
  self.load_markets()
@@ -2061,22 +2079,21 @@ class mexc(Exchange, ImplicitAPI):
2061
2079
  'side': orderSide,
2062
2080
  'type': type.upper(),
2063
2081
  }
2064
- if orderSide == 'BUY' and type == 'market':
2065
- createMarketBuyOrderRequiresPrice = True
2066
- createMarketBuyOrderRequiresPrice, params = self.handle_option_and_params(params, 'createOrder', 'createMarketBuyOrderRequiresPrice', True)
2082
+ if type == 'market':
2067
2083
  cost = self.safe_number_2(params, 'cost', 'quoteOrderQty')
2068
2084
  params = self.omit(params, 'cost')
2069
2085
  if cost is not None:
2070
2086
  amount = cost
2071
- elif createMarketBuyOrderRequiresPrice:
2087
+ request['quoteOrderQty'] = self.cost_to_precision(symbol, amount)
2088
+ else:
2072
2089
  if price is None:
2073
- raise InvalidOrder(self.id + ' createOrder() requires the price argument for market buy orders to calculate the total cost to spend(amount * price), alternatively set the createMarketBuyOrderRequiresPrice option or param to False and pass the cost to spend in the amount argument')
2090
+ request['quantity'] = self.amount_to_precision(symbol, amount)
2074
2091
  else:
2075
2092
  amountString = self.number_to_string(amount)
2076
2093
  priceString = self.number_to_string(price)
2077
2094
  quoteAmount = Precise.string_mul(amountString, priceString)
2078
2095
  amount = quoteAmount
2079
- request['quoteOrderQty'] = self.cost_to_precision(symbol, amount)
2096
+ request['quoteOrderQty'] = self.cost_to_precision(symbol, amount)
2080
2097
  else:
2081
2098
  request['quantity'] = self.amount_to_precision(symbol, amount)
2082
2099
  if price is not None:
@@ -2111,8 +2128,14 @@ class mexc(Exchange, ImplicitAPI):
2111
2128
  :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
2112
2129
  """
2113
2130
  self.load_markets()
2131
+ test = self.safe_bool(params, 'test', False)
2132
+ params = self.omit(params, 'test')
2114
2133
  request = self.create_spot_order_request(market, type, side, amount, price, marginMode, params)
2115
- response = self.spotPrivatePostOrder(self.extend(request, params))
2134
+ response = None
2135
+ if test:
2136
+ response = self.spotPrivatePostOrderTest(request)
2137
+ else:
2138
+ response = self.spotPrivatePostOrder(request)
2116
2139
  #
2117
2140
  # spot
2118
2141
  #
@@ -2426,6 +2449,9 @@ class mexc(Exchange, ImplicitAPI):
2426
2449
  def fetch_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
2427
2450
  """
2428
2451
  fetches information on multiple orders made by the user
2452
+ :see: https://mexcdevelop.github.io/apidocs/spot_v3_en/#all-orders
2453
+ :see: https://mexcdevelop.github.io/apidocs/contract_v1_en/#get-all-of-the-user-39-s-historical-orders
2454
+ :see: https://mexcdevelop.github.io/apidocs/contract_v1_en/#gets-the-trigger-order-list
2429
2455
  :param str symbol: unified market symbol of the market orders were made in
2430
2456
  :param int [since]: the earliest time in ms to fetch orders for
2431
2457
  :param int [limit]: the maximum number of order structures to retrieve
@@ -2639,6 +2665,9 @@ class mexc(Exchange, ImplicitAPI):
2639
2665
  def fetch_open_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
2640
2666
  """
2641
2667
  fetch all unfilled currently open orders
2668
+ :see: https://mexcdevelop.github.io/apidocs/spot_v3_en/#current-open-orders
2669
+ :see: https://mexcdevelop.github.io/apidocs/contract_v1_en/#get-all-of-the-user-39-s-historical-orders
2670
+ :see: https://mexcdevelop.github.io/apidocs/contract_v1_en/#gets-the-trigger-order-list
2642
2671
  :param str symbol: unified market symbol
2643
2672
  :param int [since]: the earliest time in ms to fetch open orders for
2644
2673
  :param int [limit]: the maximum number of open orders structures to retrieve
@@ -2721,6 +2750,9 @@ class mexc(Exchange, ImplicitAPI):
2721
2750
  def fetch_closed_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
2722
2751
  """
2723
2752
  fetches information on multiple closed orders made by the user
2753
+ :see: https://mexcdevelop.github.io/apidocs/spot_v3_en/#all-orders
2754
+ :see: https://mexcdevelop.github.io/apidocs/contract_v1_en/#get-all-of-the-user-39-s-historical-orders
2755
+ :see: https://mexcdevelop.github.io/apidocs/contract_v1_en/#gets-the-trigger-order-list
2724
2756
  :param str symbol: unified market symbol of the market orders were made in
2725
2757
  :param int [since]: the earliest time in ms to fetch orders for
2726
2758
  :param int [limit]: the maximum number of order structures to retrieve
@@ -2732,6 +2764,9 @@ class mexc(Exchange, ImplicitAPI):
2732
2764
  def fetch_canceled_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
2733
2765
  """
2734
2766
  fetches information on multiple canceled orders made by the user
2767
+ :see: https://mexcdevelop.github.io/apidocs/spot_v3_en/#all-orders
2768
+ :see: https://mexcdevelop.github.io/apidocs/contract_v1_en/#get-all-of-the-user-39-s-historical-orders
2769
+ :see: https://mexcdevelop.github.io/apidocs/contract_v1_en/#gets-the-trigger-order-list
2735
2770
  :param str symbol: unified market symbol of the market orders were made in
2736
2771
  :param int [since]: timestamp in ms of the earliest order, default is None
2737
2772
  :param int [limit]: max number of orders to return, default is None
@@ -5285,6 +5320,43 @@ class mexc(Exchange, ImplicitAPI):
5285
5320
  positions = self.parse_positions(data, symbols, params)
5286
5321
  return self.filter_by_since_limit(positions, since, limit)
5287
5322
 
5323
+ def set_margin_mode(self, marginMode: str, symbol: Str = None, params={}):
5324
+ """
5325
+ set margin mode to 'cross' or 'isolated'
5326
+ :see: https://mexcdevelop.github.io/apidocs/contract_v1_en/#switch-leverage
5327
+ :param str marginMode: 'cross' or 'isolated'
5328
+ :param str [symbol]: required when there is no position, else provide params["positionId"]
5329
+ :param dict [params]: extra parameters specific to the exchange API endpoint
5330
+ :param str [params.positionId]: required when a position is set
5331
+ :param str [params.direction]: "long" or "short" required when there is no position
5332
+ :returns dict: response from the exchange
5333
+ """
5334
+ self.load_markets()
5335
+ market = self.market(symbol)
5336
+ if market['spot']:
5337
+ raise BadSymbol(self.id + ' setMarginMode() supports contract markets only')
5338
+ marginMode = marginMode.lower()
5339
+ if marginMode != 'isolated' and marginMode != 'cross':
5340
+ raise BadRequest(self.id + ' setMarginMode() marginMode argument should be isolated or cross')
5341
+ leverage = self.safe_integer(params, 'leverage')
5342
+ if leverage is None:
5343
+ raise ArgumentsRequired(self.id + ' setMarginMode() requires a leverage parameter')
5344
+ direction = self.safe_string_lower_2(params, 'direction', 'positionId')
5345
+ request: dict = {
5346
+ 'leverage': leverage,
5347
+ 'openType': 1 if (marginMode == 'isolated') else 2,
5348
+ }
5349
+ if symbol is not None:
5350
+ request['symbol'] = market['id']
5351
+ if direction is not None:
5352
+ request['positionType'] = 2 if (direction == 'short') else 1
5353
+ params = self.omit(params, 'direction')
5354
+ response = self.contractPrivatePostPositionChangeLeverage(self.extend(request, params))
5355
+ #
5356
+ # {success: True, code: '0'}
5357
+ #
5358
+ return self.parse_leverage(response, market)
5359
+
5288
5360
  def nonce(self):
5289
5361
  return self.milliseconds() - self.safe_integer(self.options, 'timeDifference', 0)
5290
5362
 
ccxt/pro/__init__.py CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  # ----------------------------------------------------------------------------
6
6
 
7
- __version__ = '4.4.6'
7
+ __version__ = '4.4.7'
8
8
 
9
9
  # ----------------------------------------------------------------------------
10
10
 
ccxt/pro/bitget.py CHANGED
@@ -42,6 +42,7 @@ class bitget(ccxt.async_support.bitget):
42
42
  'watchOrders': True,
43
43
  'watchTicker': True,
44
44
  'watchTickers': True,
45
+ 'watchBidsAsks': True,
45
46
  'watchTrades': True,
46
47
  'watchTradesForSymbols': True,
47
48
  'watchPositions': True,
@@ -209,6 +210,7 @@ class bitget(ccxt.async_support.bitget):
209
210
  # "ts": 1701842994341
210
211
  # }
211
212
  #
213
+ self.handle_bid_ask(client, message)
212
214
  ticker = self.parse_ws_ticker(message)
213
215
  symbol = ticker['symbol']
214
216
  self.tickers[symbol] = ticker
@@ -320,6 +322,66 @@ class bitget(ccxt.async_support.bitget):
320
322
  'info': ticker,
321
323
  }, market)
322
324
 
325
+ async def watch_bids_asks(self, symbols: Strings = None, params={}) -> Tickers:
326
+ """
327
+ :see: https://www.bitget.com/api-doc/spot/websocket/public/Tickers-Channel
328
+ :see: https://www.bitget.com/api-doc/contract/websocket/public/Tickers-Channel
329
+ watches best bid & ask for symbols
330
+ :param str[] symbols: unified symbol of the market to fetch the ticker for
331
+ :param dict [params]: extra parameters specific to the exchange API endpoint
332
+ :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
333
+ """
334
+ await self.load_markets()
335
+ symbols = self.market_symbols(symbols, None, False)
336
+ market = self.market(symbols[0])
337
+ instType = None
338
+ instType, params = self.get_inst_type(market, params)
339
+ topics = []
340
+ messageHashes = []
341
+ for i in range(0, len(symbols)):
342
+ symbol = symbols[i]
343
+ marketInner = self.market(symbol)
344
+ args: dict = {
345
+ 'instType': instType,
346
+ 'channel': 'ticker',
347
+ 'instId': marketInner['id'],
348
+ }
349
+ topics.append(args)
350
+ messageHashes.append('bidask:' + symbol)
351
+ tickers = await self.watch_public_multiple(messageHashes, topics, params)
352
+ if self.newUpdates:
353
+ result: dict = {}
354
+ result[tickers['symbol']] = tickers
355
+ return result
356
+ return self.filter_by_array(self.bidsasks, 'symbol', symbols)
357
+
358
+ def handle_bid_ask(self, client: Client, message):
359
+ ticker = self.parse_ws_bid_ask(message)
360
+ symbol = ticker['symbol']
361
+ self.bidsasks[symbol] = ticker
362
+ messageHash = 'bidask:' + symbol
363
+ client.resolve(ticker, messageHash)
364
+
365
+ def parse_ws_bid_ask(self, message, market=None):
366
+ arg = self.safe_value(message, 'arg', {})
367
+ data = self.safe_value(message, 'data', [])
368
+ ticker = self.safe_value(data, 0, {})
369
+ timestamp = self.safe_integer(ticker, 'ts')
370
+ instType = self.safe_string(arg, 'instType')
371
+ marketType = 'spot' if (instType == 'SPOT') else 'contract'
372
+ marketId = self.safe_string(ticker, 'instId')
373
+ market = self.safe_market(marketId, market, None, marketType)
374
+ return self.safe_ticker({
375
+ 'symbol': market['symbol'],
376
+ 'timestamp': timestamp,
377
+ 'datetime': self.iso8601(timestamp),
378
+ 'ask': self.safe_string(ticker, 'askPr'),
379
+ 'askVolume': self.safe_string(ticker, 'askSz'),
380
+ 'bid': self.safe_string(ticker, 'bidPr'),
381
+ 'bidVolume': self.safe_string(ticker, 'bidSz'),
382
+ 'info': ticker,
383
+ }, market)
384
+
323
385
  async def watch_ohlcv(self, symbol: str, timeframe='1m', since: Int = None, limit: Int = None, params={}) -> List[list]:
324
386
  """
325
387
  watches historical candlestick data containing the open, high, low, close price, and the volume of a market
ccxt/pro/okx.py CHANGED
@@ -1815,6 +1815,12 @@ class okx(ccxt.async_support.okx):
1815
1815
  symbolMessageHash = messageHash + '::' + tradeSymbols[i]
1816
1816
  client.resolve(self.orders, symbolMessageHash)
1817
1817
 
1818
+ def request_id(self):
1819
+ ts = str(self.milliseconds())
1820
+ randomNumber = self.rand_number(4)
1821
+ randomPart = str(randomNumber)
1822
+ return ts + randomPart
1823
+
1818
1824
  async def create_order_ws(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}) -> Order:
1819
1825
  """
1820
1826
  :see: https://www.okx.com/docs-v5/en/#websocket-api-trade-place-order
@@ -1831,7 +1837,7 @@ class okx(ccxt.async_support.okx):
1831
1837
  await self.load_markets()
1832
1838
  await self.authenticate()
1833
1839
  url = self.get_url('private', 'private')
1834
- messageHash = str(self.milliseconds())
1840
+ messageHash = self.request_id()
1835
1841
  op = None
1836
1842
  op, params = self.handle_option_and_params(params, 'createOrderWs', 'op', 'batch-orders')
1837
1843
  args = self.create_order_request(symbol, type, side, amount, price, params)
@@ -1896,7 +1902,7 @@ class okx(ccxt.async_support.okx):
1896
1902
  await self.load_markets()
1897
1903
  await self.authenticate()
1898
1904
  url = self.get_url('private', 'private')
1899
- messageHash = str(self.milliseconds())
1905
+ messageHash = self.request_id()
1900
1906
  op = None
1901
1907
  op, params = self.handle_option_and_params(params, 'editOrderWs', 'op', 'amend-order')
1902
1908
  args = self.edit_order_request(id, symbol, type, side, amount, price, params)
@@ -1922,7 +1928,7 @@ class okx(ccxt.async_support.okx):
1922
1928
  await self.load_markets()
1923
1929
  await self.authenticate()
1924
1930
  url = self.get_url('private', 'private')
1925
- messageHash = str(self.milliseconds())
1931
+ messageHash = self.request_id()
1926
1932
  clientOrderId = self.safe_string_2(params, 'clOrdId', 'clientOrderId')
1927
1933
  params = self.omit(params, ['clientOrderId', 'clOrdId'])
1928
1934
  arg: dict = {
@@ -1956,7 +1962,7 @@ class okx(ccxt.async_support.okx):
1956
1962
  await self.load_markets()
1957
1963
  await self.authenticate()
1958
1964
  url = self.get_url('private', 'private')
1959
- messageHash = str(self.milliseconds())
1965
+ messageHash = self.request_id()
1960
1966
  args = []
1961
1967
  for i in range(0, idsLength):
1962
1968
  arg: dict = {
@@ -1987,7 +1993,7 @@ class okx(ccxt.async_support.okx):
1987
1993
  if market['type'] != 'option':
1988
1994
  raise BadRequest(self.id + 'cancelAllOrdersWs is only applicable to Option in Portfolio Margin mode, and MMP privilege is required.')
1989
1995
  url = self.get_url('private', 'private')
1990
- messageHash = str(self.milliseconds())
1996
+ messageHash = self.request_id()
1991
1997
  request: dict = {
1992
1998
  'id': messageHash,
1993
1999
  'op': 'mass-cancel',
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ccxt
3
- Version: 4.4.6
3
+ Version: 4.4.7
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
@@ -272,13 +272,13 @@ console.log(version, Object.keys(exchanges));
272
272
 
273
273
  All-in-one browser bundle (dependencies included), served from a CDN of your choice:
274
274
 
275
- * jsDelivr: https://cdn.jsdelivr.net/npm/ccxt@4.4.6/dist/ccxt.browser.min.js
276
- * unpkg: https://unpkg.com/ccxt@4.4.6/dist/ccxt.browser.min.js
275
+ * jsDelivr: https://cdn.jsdelivr.net/npm/ccxt@4.4.7/dist/ccxt.browser.min.js
276
+ * unpkg: https://unpkg.com/ccxt@4.4.7/dist/ccxt.browser.min.js
277
277
 
278
278
  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.
279
279
 
280
280
  ```HTML
281
- <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/ccxt@4.4.6/dist/ccxt.browser.min.js"></script>
281
+ <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/ccxt@4.4.7/dist/ccxt.browser.min.js"></script>
282
282
  ```
283
283
 
284
284
  Creates a global `ccxt` object: