ccxt 4.3.71__py2.py3-none-any.whl → 4.3.73__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
ccxt/__init__.py CHANGED
@@ -22,7 +22,7 @@
22
22
 
23
23
  # ----------------------------------------------------------------------------
24
24
 
25
- __version__ = '4.3.71'
25
+ __version__ = '4.3.73'
26
26
 
27
27
  # ----------------------------------------------------------------------------
28
28
 
@@ -4,7 +4,7 @@
4
4
 
5
5
  # -----------------------------------------------------------------------------
6
6
 
7
- __version__ = '4.3.71'
7
+ __version__ = '4.3.73'
8
8
 
9
9
  # -----------------------------------------------------------------------------
10
10
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  # -----------------------------------------------------------------------------
4
4
 
5
- __version__ = '4.3.71'
5
+ __version__ = '4.3.73'
6
6
 
7
7
  # -----------------------------------------------------------------------------
8
8
 
@@ -15,7 +15,7 @@ class Client(object):
15
15
  subscriptions = {}
16
16
  rejections = {}
17
17
  message_queue = {}
18
- useMessageQueue = True
18
+ useMessageQueue = False
19
19
  on_message_callback = None
20
20
  on_error_callback = None
21
21
  on_close_callback = None
@@ -130,7 +130,7 @@ class paradex(Exchange, ImplicitAPI):
130
130
  },
131
131
  'hostname': 'paradex.trade',
132
132
  'urls': {
133
- 'logo': 'https://github.com/user-attachments/assets/5dadc09a-74ba-466a-a8f2-3f55c7e4654a',
133
+ 'logo': 'https://github.com/user-attachments/assets/84628770-784e-4ec4-a759-ec2fbb2244ea',
134
134
  'api': {
135
135
  'v1': 'https://api.prod.{hostname}/v1',
136
136
  },
ccxt/base/exchange.py CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  # -----------------------------------------------------------------------------
6
6
 
7
- __version__ = '4.3.71'
7
+ __version__ = '4.3.73'
8
8
 
9
9
  # -----------------------------------------------------------------------------
10
10
 
ccxt/paradex.py CHANGED
@@ -130,7 +130,7 @@ class paradex(Exchange, ImplicitAPI):
130
130
  },
131
131
  'hostname': 'paradex.trade',
132
132
  'urls': {
133
- 'logo': 'https://github.com/user-attachments/assets/5dadc09a-74ba-466a-a8f2-3f55c7e4654a',
133
+ 'logo': 'https://github.com/user-attachments/assets/84628770-784e-4ec4-a759-ec2fbb2244ea',
134
134
  'api': {
135
135
  'v1': 'https://api.prod.{hostname}/v1',
136
136
  },
ccxt/pro/__init__.py CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  # ----------------------------------------------------------------------------
6
6
 
7
- __version__ = '4.3.71'
7
+ __version__ = '4.3.73'
8
8
 
9
9
  # ----------------------------------------------------------------------------
10
10
 
ccxt/pro/binance.py CHANGED
@@ -1098,11 +1098,15 @@ class binance(ccxt.async_support.binance):
1098
1098
  async def watch_ohlcv(self, symbol: str, timeframe='1m', since: Int = None, limit: Int = None, params={}) -> List[list]:
1099
1099
  """
1100
1100
  watches historical candlestick data containing the open, high, low, and close price, and the volume of a market
1101
+ :see: https://binance-docs.github.io/apidocs/spot/en/#kline-candlestick-data
1102
+ :see: https://binance-docs.github.io/apidocs/futures/en/#kline-candlestick-data
1103
+ :see: https://binance-docs.github.io/apidocs/delivery/en/#kline-candlestick-data
1101
1104
  :param str symbol: unified symbol of the market to fetch OHLCV data for
1102
1105
  :param str timeframe: the length of time each candle represents
1103
1106
  :param int [since]: timestamp in ms of the earliest candle to fetch
1104
1107
  :param int [limit]: the maximum amount of candles to fetch
1105
1108
  :param dict [params]: extra parameters specific to the exchange API endpoint
1109
+ :param dict [params.timezone]: if provided, kline intervals are interpreted in that timezone instead of UTC, example '+08:00'
1106
1110
  :returns int[][]: A list of candles ordered, open, high, low, close, volume
1107
1111
  """
1108
1112
  params['callerMethodName'] = 'watchOHLCV'
@@ -1112,10 +1116,14 @@ class binance(ccxt.async_support.binance):
1112
1116
  async def watch_ohlcv_for_symbols(self, symbolsAndTimeframes: List[List[str]], since: Int = None, limit: Int = None, params={}):
1113
1117
  """
1114
1118
  watches historical candlestick data containing the open, high, low, and close price, and the volume of a market
1119
+ :see: https://binance-docs.github.io/apidocs/spot/en/#kline-candlestick-data
1120
+ :see: https://binance-docs.github.io/apidocs/futures/en/#kline-candlestick-data
1121
+ :see: https://binance-docs.github.io/apidocs/delivery/en/#kline-candlestick-data
1115
1122
  :param str[][] symbolsAndTimeframes: array of arrays containing unified symbols and timeframes to fetch OHLCV data for, example [['BTC/USDT', '1m'], ['LTC/USDT', '5m']]
1116
1123
  :param int [since]: timestamp in ms of the earliest candle to fetch
1117
1124
  :param int [limit]: the maximum amount of candles to fetch
1118
1125
  :param dict [params]: extra parameters specific to the exchange API endpoint
1126
+ :param dict [params.timezone]: if provided, kline intervals are interpreted in that timezone instead of UTC, example '+08:00'
1119
1127
  :returns int[][]: A list of candles ordered, open, high, low, close, volume
1120
1128
  """
1121
1129
  await self.load_markets()
@@ -1127,6 +1135,10 @@ class binance(ccxt.async_support.binance):
1127
1135
  type = firstMarket['type']
1128
1136
  if firstMarket['contract']:
1129
1137
  type = 'future' if firstMarket['linear'] else 'delivery'
1138
+ isSpot = (type == 'spot')
1139
+ timezone = None
1140
+ timezone, params = self.handle_param_string(params, 'timezone', None)
1141
+ isUtc8 = (timezone is not None) and ((timezone == '+08:00') or Precise.string_eq(timezone, '8'))
1130
1142
  rawHashes = []
1131
1143
  messageHashes = []
1132
1144
  for i in range(0, len(symbolsAndTimeframes)):
@@ -1139,7 +1151,10 @@ class binance(ccxt.async_support.binance):
1139
1151
  if klineType == 'indexPriceKline':
1140
1152
  # weird behavior for index price kline we can't use the perp suffix
1141
1153
  marketId = marketId.replace('_perp', '')
1142
- rawHashes.append(marketId + '@' + klineType + '_' + interval)
1154
+ shouldUseUTC8 = (isUtc8 and isSpot)
1155
+ suffix = '@+08:00'
1156
+ utcSuffix = suffix if shouldUseUTC8 else ''
1157
+ rawHashes.append(marketId + '@' + klineType + '_' + interval + utcSuffix)
1143
1158
  messageHashes.append('ohlcv::' + symbolString + '::' + timeframeString)
1144
1159
  url = self.urls['api']['ws'][type] + '/' + self.stream(type, 'multipleOHLCV')
1145
1160
  requestId = self.request_id(url)
ccxt/pro/kucoin.py CHANGED
@@ -1024,6 +1024,10 @@ class kucoin(ccxt.async_support.kucoin):
1024
1024
  tradeId = self.safe_string(trade, 'tradeId')
1025
1025
  price = self.safe_string(trade, 'matchPrice')
1026
1026
  amount = self.safe_string(trade, 'matchSize')
1027
+ if price is None:
1028
+ # /spot/tradeFills
1029
+ price = self.safe_string(trade, 'price')
1030
+ amount = self.safe_string(trade, 'size')
1027
1031
  order = self.safe_string(trade, 'orderId')
1028
1032
  timestamp = self.safe_integer_product_2(trade, 'ts', 'time', 0.000001)
1029
1033
  feeCurrency = market['quote']
ccxt/pro/woo.py CHANGED
@@ -90,32 +90,48 @@ class woo(ccxt.async_support.woo):
90
90
 
91
91
  async def watch_order_book(self, symbol: str, limit: Int = None, params={}) -> OrderBook:
92
92
  """
93
+ :see: https://docs.woo.org/#orderbookupdate
93
94
  :see: https://docs.woo.org/#orderbook
94
95
  watches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
95
96
  :param str symbol: unified symbol of the market to fetch the order book for
96
97
  :param int [limit]: the maximum amount of order book entries to return.
97
98
  :param dict [params]: extra parameters specific to the exchange API endpoint
99
+ :param str [params.method]: either(default) 'orderbook' or 'orderbookupdate', default is 'orderbook'
98
100
  :returns dict: A dictionary of `order book structures <https://docs.ccxt.com/#/?id=order-book-structure>` indexed by market symbols
99
101
  """
100
102
  await self.load_markets()
101
- name = 'orderbook'
103
+ method = None
104
+ method, params = self.handle_option_and_params(params, 'watchOrderBook', 'method', 'orderbook')
102
105
  market = self.market(symbol)
103
- topic = market['id'] + '@' + name
106
+ topic = market['id'] + '@' + method
107
+ urlUid = '/' + self.uid if (self.uid) else ''
108
+ url = self.urls['api']['ws']['public'] + urlUid
109
+ requestId = self.request_id(url)
104
110
  request: dict = {
105
111
  'event': 'subscribe',
106
112
  'topic': topic,
113
+ 'id': requestId,
107
114
  }
108
- message = self.extend(request, params)
109
- orderbook = await self.watch_public(topic, message)
115
+ subscription: dict = {
116
+ 'id': str(requestId),
117
+ 'name': method,
118
+ 'symbol': symbol,
119
+ 'limit': limit,
120
+ 'params': params,
121
+ }
122
+ if method == 'orderbookupdate':
123
+ subscription['method'] = self.handle_order_book_subscription
124
+ orderbook = await self.watch(url, topic, self.extend(request, params), topic, subscription)
110
125
  return orderbook.limit()
111
126
 
112
127
  def handle_order_book(self, client: Client, message):
113
128
  #
114
129
  # {
115
- # "topic": "PERP_BTC_USDT@orderbook",
116
- # "ts": 1650121915308,
130
+ # "topic": "PERP_BTC_USDT@orderbookupdate",
131
+ # "ts": 1722500373999,
117
132
  # "data": {
118
133
  # "symbol": "PERP_BTC_USDT",
134
+ # "prevTs": 1722500373799,
119
135
  # "bids": [
120
136
  # [
121
137
  # 0.30891,
@@ -136,13 +152,89 @@ class woo(ccxt.async_support.woo):
136
152
  market = self.safe_market(marketId)
137
153
  symbol = market['symbol']
138
154
  topic = self.safe_string(message, 'topic')
139
- if not (symbol in self.orderbooks):
140
- self.orderbooks[symbol] = self.order_book({})
141
- orderbook = self.orderbooks[symbol]
155
+ method = self.safe_string(topic.split('@'), 1)
156
+ if method == 'orderbookupdate':
157
+ if not (symbol in self.orderbooks):
158
+ return
159
+ orderbook = self.orderbooks[symbol]
160
+ timestamp = self.safe_integer(orderbook, 'timestamp')
161
+ if timestamp is None:
162
+ orderbook.cache.append(message)
163
+ else:
164
+ try:
165
+ ts = self.safe_integer(message, 'ts')
166
+ if ts > timestamp:
167
+ self.handle_order_book_message(client, message, orderbook)
168
+ client.resolve(orderbook, topic)
169
+ except Exception as e:
170
+ del self.orderbooks[symbol]
171
+ del client.subscriptions[topic]
172
+ client.reject(e, topic)
173
+ else:
174
+ if not (symbol in self.orderbooks):
175
+ defaultLimit = self.safe_integer(self.options, 'watchOrderBookLimit', 1000)
176
+ subscription = client.subscriptions[topic]
177
+ limit = self.safe_integer(subscription, 'limit', defaultLimit)
178
+ self.orderbooks[symbol] = self.order_book({}, limit)
179
+ orderbook = self.orderbooks[symbol]
180
+ timestamp = self.safe_integer(message, 'ts')
181
+ snapshot = self.parse_order_book(data, symbol, timestamp, 'bids', 'asks')
182
+ orderbook.reset(snapshot)
183
+ client.resolve(orderbook, topic)
184
+
185
+ def handle_order_book_subscription(self, client: Client, message, subscription):
186
+ defaultLimit = self.safe_integer(self.options, 'watchOrderBookLimit', 1000)
187
+ limit = self.safe_integer(subscription, 'limit', defaultLimit)
188
+ symbol = self.safe_string(subscription, 'symbol') # watchOrderBook
189
+ if symbol in self.orderbooks:
190
+ del self.orderbooks[symbol]
191
+ self.orderbooks[symbol] = self.order_book({}, limit)
192
+ self.spawn(self.fetch_order_book_snapshot, client, message, subscription)
193
+
194
+ async def fetch_order_book_snapshot(self, client, message, subscription):
195
+ symbol = self.safe_string(subscription, 'symbol')
196
+ messageHash = self.safe_string(message, 'topic')
197
+ try:
198
+ defaultLimit = self.safe_integer(self.options, 'watchOrderBookLimit', 1000)
199
+ limit = self.safe_integer(subscription, 'limit', defaultLimit)
200
+ params = self.safe_value(subscription, 'params')
201
+ snapshot = await self.fetch_rest_order_book_safe(symbol, limit, params)
202
+ if self.safe_value(self.orderbooks, symbol) is None:
203
+ # if the orderbook is dropped before the snapshot is received
204
+ return
205
+ orderbook = self.orderbooks[symbol]
206
+ orderbook.reset(snapshot)
207
+ messages = orderbook.cache
208
+ for i in range(0, len(messages)):
209
+ messageItem = messages[i]
210
+ ts = self.safe_integer(messageItem, 'ts')
211
+ if ts < orderbook['timestamp']:
212
+ continue
213
+ else:
214
+ self.handle_order_book_message(client, messageItem, orderbook)
215
+ self.orderbooks[symbol] = orderbook
216
+ client.resolve(orderbook, messageHash)
217
+ except Exception as e:
218
+ del client.subscriptions[messageHash]
219
+ client.reject(e, messageHash)
220
+
221
+ def handle_order_book_message(self, client: Client, message, orderbook):
222
+ data = self.safe_dict(message, 'data')
223
+ self.handle_deltas(orderbook['asks'], self.safe_value(data, 'asks', []))
224
+ self.handle_deltas(orderbook['bids'], self.safe_value(data, 'bids', []))
142
225
  timestamp = self.safe_integer(message, 'ts')
143
- snapshot = self.parse_order_book(data, symbol, timestamp, 'bids', 'asks')
144
- orderbook.reset(snapshot)
145
- client.resolve(orderbook, topic)
226
+ orderbook['timestamp'] = timestamp
227
+ orderbook['datetime'] = self.iso8601(timestamp)
228
+ return orderbook
229
+
230
+ def handle_delta(self, bookside, delta):
231
+ price = self.safe_float_2(delta, 'price', 0)
232
+ amount = self.safe_float_2(delta, 'quantity', 1)
233
+ bookside.store(price, amount)
234
+
235
+ def handle_deltas(self, bookside, deltas):
236
+ for i in range(0, len(deltas)):
237
+ self.handle_delta(bookside, deltas[i])
146
238
 
147
239
  async def watch_ticker(self, symbol: str, params={}) -> Ticker:
148
240
  """
@@ -998,6 +1090,7 @@ class woo(ccxt.async_support.woo):
998
1090
  'pong': self.handle_pong,
999
1091
  'subscribe': self.handle_subscribe,
1000
1092
  'orderbook': self.handle_order_book,
1093
+ 'orderbookupdate': self.handle_order_book,
1001
1094
  'ticker': self.handle_ticker,
1002
1095
  'tickers': self.handle_tickers,
1003
1096
  'kline': self.handle_ohlcv,
@@ -1056,6 +1149,12 @@ class woo(ccxt.async_support.woo):
1056
1149
  # "ts": 1657117712212
1057
1150
  # }
1058
1151
  #
1152
+ id = self.safe_string(message, 'id')
1153
+ subscriptionsById = self.index_by(client.subscriptions, 'id')
1154
+ subscription = self.safe_value(subscriptionsById, id, {})
1155
+ method = self.safe_value(subscription, 'method')
1156
+ if method is not None:
1157
+ method(client, message, subscription)
1059
1158
  return message
1060
1159
 
1061
1160
  def handle_auth(self, client: Client, message):
File without changes
@@ -0,0 +1,45 @@
1
+ """
2
+ TypedDict structures for TypedData
3
+ """
4
+
5
+ from enum import Enum
6
+ from typing import Any, Dict, List, Optional, TypedDict
7
+
8
+ class Revision(Enum):
9
+ """
10
+ Enum representing the revision of the specification to be used.
11
+ """
12
+
13
+ V0 = 0
14
+ V1 = 1
15
+
16
+
17
+ class ParameterDict(TypedDict):
18
+ """
19
+ TypedDict representing a Parameter object
20
+ """
21
+
22
+ name: str
23
+ type: str
24
+
25
+
26
+ class StarkNetDomainDict(TypedDict):
27
+ """
28
+ TypedDict representing a domain object (both StarkNetDomain, StarknetDomain).
29
+ """
30
+
31
+ name: str
32
+ version: str
33
+ chainId: str
34
+ revision: Optional[Revision]
35
+
36
+
37
+ class TypedDataDict(TypedDict):
38
+ """
39
+ TypedDict representing a TypedData object
40
+ """
41
+
42
+ types: Dict[str, List[ParameterDict]]
43
+ primaryType: str
44
+ domain: StarkNetDomainDict
45
+ message: Dict[str, Any]
File without changes
File without changes
@@ -0,0 +1,50 @@
1
+ from ...ecdsa.curves import Curve
2
+ from ...ecdsa.ellipticcurve import CurveFp, Point
3
+
4
+ from .signature import (
5
+ ALPHA,
6
+ BETA,
7
+ CONSTANT_POINTS,
8
+ EC_ORDER,
9
+ FIELD_PRIME,
10
+ N_ELEMENT_BITS_HASH,
11
+ SHIFT_POINT,
12
+ )
13
+ from .utils import from_bytes, to_bytes
14
+
15
+ curve_stark = CurveFp(FIELD_PRIME, ALPHA, BETA)
16
+ LOW_PART_BITS = 248
17
+ LOW_PART_MASK = 2**248 - 1
18
+ HASH_SHIFT_POINT = Point(curve_stark, SHIFT_POINT[0], SHIFT_POINT[1], EC_ORDER)
19
+ P_0 = Point(curve_stark, CONSTANT_POINTS[2][0], CONSTANT_POINTS[2][1], EC_ORDER)
20
+ P_1 = Point(curve_stark, CONSTANT_POINTS[2 + LOW_PART_BITS][0], CONSTANT_POINTS[2 + LOW_PART_BITS][1], EC_ORDER)
21
+ P_2 = Point(curve_stark, CONSTANT_POINTS[2 + N_ELEMENT_BITS_HASH][0], CONSTANT_POINTS[2 + N_ELEMENT_BITS_HASH][1], EC_ORDER)
22
+ P_3 = Point(curve_stark, CONSTANT_POINTS[2 + N_ELEMENT_BITS_HASH + LOW_PART_BITS][0], CONSTANT_POINTS[2 + N_ELEMENT_BITS_HASH + LOW_PART_BITS][1], EC_ORDER)
23
+
24
+ def process_single_element(element: int, p1, p2) -> Point:
25
+ assert 0 <= element < FIELD_PRIME, "Element integer value is out of range"
26
+
27
+ high_nibble = element >> LOW_PART_BITS
28
+ low_part = element & LOW_PART_MASK
29
+ return low_part * p1 + high_nibble * p2
30
+
31
+
32
+ def pedersen_hash(x: int, y: int) -> int:
33
+ """
34
+ Computes the Starkware version of the Pedersen hash of x and y.
35
+ The hash is defined by:
36
+ shift_point + x_low * P_0 + x_high * P1 + y_low * P2 + y_high * P3
37
+ where x_low is the 248 low bits of x, x_high is the 4 high bits of x and similarly for y.
38
+ shift_point, P_0, P_1, P_2, P_3 are constant points generated from the digits of pi.
39
+ """
40
+ return (
41
+ HASH_SHIFT_POINT + process_single_element(x, P_0, P_1) + process_single_element(y, P_2, P_3)
42
+ ).x()
43
+
44
+
45
+ def pedersen_hash_func(x: bytes, y: bytes) -> bytes:
46
+ """
47
+ A variant of 'pedersen_hash', where the elements and their resulting hash are in bytes.
48
+ """
49
+ assert len(x) == len(y) == 32, "Unexpected element length."
50
+ return to_bytes(pedersen_hash(*(from_bytes(element) for element in (x, y))))
@@ -0,0 +1,78 @@
1
+ ###############################################################################
2
+ # Copyright 2019 StarkWare Industries Ltd. #
3
+ # #
4
+ # Licensed under the Apache License, Version 2.0 (the "License"). #
5
+ # You may not use this file except in compliance with the License. #
6
+ # You may obtain a copy of the License at #
7
+ # #
8
+ # https://www.starkware.co/open-source-license/ #
9
+ # #
10
+ # Unless required by applicable law or agreed to in writing, #
11
+ # software distributed under the License is distributed on an "AS IS" BASIS, #
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
13
+ # See the License for the specific language governing permissions #
14
+ # and limitations under the License. #
15
+ ###############################################################################
16
+
17
+
18
+ from typing import Tuple
19
+
20
+ from ...sympy.core.intfunc import igcdex
21
+
22
+ # A type that represents a point (x,y) on an elliptic curve.
23
+ ECPoint = Tuple[int, int]
24
+
25
+ def div_mod(n: int, m: int, p: int) -> int:
26
+ """
27
+ Finds a nonnegative integer 0 <= x < p such that (m * x) % p == n
28
+ """
29
+ a, b, c = igcdex(m, p)
30
+ assert c == 1
31
+ return (n * a) % p
32
+
33
+ def div_ceil(x, y):
34
+ assert isinstance(x, int) and isinstance(y, int)
35
+ return -((-x) // y)
36
+
37
+ def ec_add(point1: ECPoint, point2: ECPoint, p: int) -> ECPoint:
38
+ """
39
+ Gets two points on an elliptic curve mod p and returns their sum.
40
+ Assumes the points are given in affine form (x, y) and have different x coordinates.
41
+ """
42
+ assert (point1[0] - point2[0]) % p != 0
43
+ m = div_mod(point1[1] - point2[1], point1[0] - point2[0], p)
44
+ x = (m * m - point1[0] - point2[0]) % p
45
+ y = (m * (point1[0] - x) - point1[1]) % p
46
+ return x, y
47
+
48
+
49
+ def ec_neg(point: ECPoint, p: int) -> ECPoint:
50
+ """
51
+ Given a point (x,y) return (x, -y)
52
+ """
53
+ x, y = point
54
+ return (x, (-y) % p)
55
+
56
+
57
+ def ec_double(point: ECPoint, alpha: int, p: int) -> ECPoint:
58
+ """
59
+ Doubles a point on an elliptic curve with the equation y^2 = x^3 + alpha*x + beta mod p.
60
+ Assumes the point is given in affine form (x, y) and has y != 0.
61
+ """
62
+ assert point[1] % p != 0
63
+ m = div_mod(3 * point[0] * point[0] + alpha, 2 * point[1], p)
64
+ x = (m * m - 2 * point[0]) % p
65
+ y = (m * (point[0] - x) - point[1]) % p
66
+ return x, y
67
+
68
+
69
+ def ec_mult(m: int, point: ECPoint, alpha: int, p: int) -> ECPoint:
70
+ """
71
+ Multiplies by m a point on the elliptic curve with equation y^2 = x^3 + alpha*x + beta mod p.
72
+ Assumes the point is given in affine form (x, y) and that 0 < m < order(point).
73
+ """
74
+ if m == 1:
75
+ return point
76
+ if m % 2 == 0:
77
+ return ec_mult(m // 2, ec_double(point, alpha, p), alpha, p)
78
+ return ec_add(ec_mult(m - 1, point, alpha, p), point, p)