python-okx 0.4.1__py3-none-any.whl → 0.4.3__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.
okx/Account.py CHANGED
@@ -48,9 +48,9 @@ class AccountAPI(OkxClient):
48
48
 
49
49
  # Get Bills Details (recent 7 days)
50
50
  def get_account_bills(self, instType='', ccy='', mgnMode='', ctType='', type='', subType='', after='', before='',
51
- limit=''):
51
+ limit='', begin='', end=''):
52
52
  params = {'instType': instType, 'ccy': ccy, 'mgnMode': mgnMode, 'ctType': ctType, 'type': type,
53
- 'subType': subType, 'after': after, 'before': before, 'limit': limit}
53
+ 'subType': subType, 'after': after, 'before': before, 'limit': limit, 'begin': begin, 'end': end}
54
54
  return self._request_with_params(GET, BILLS_DETAIL, params)
55
55
 
56
56
  # Get Bills Details (recent 3 months)
@@ -113,8 +113,10 @@ class AccountAPI(OkxClient):
113
113
  return self._request_with_params(GET, MAX_LOAN, params)
114
114
 
115
115
  # Get Fee Rates
116
- def get_fee_rates(self, instType, instId='', uly='', category='', instFamily=''):
116
+ def get_fee_rates(self, instType, instId='', uly='', category='', instFamily='', groupId=None):
117
117
  params = {'instType': instType, 'instId': instId, 'uly': uly, 'category': category, 'instFamily': instFamily}
118
+ if groupId is not None:
119
+ params['groupId'] = groupId
118
120
  return self._request_with_params(GET, FEE_RATES, params)
119
121
 
120
122
  # Get interest-accrued
@@ -337,3 +339,30 @@ class AccountAPI(OkxClient):
337
339
  if earnType is not None:
338
340
  params['earnType'] = earnType
339
341
  return self._request_with_params(POST, SET_AUTO_EARN, params)
342
+
343
+ # Set trading config (BROK-1724). type is required (e.g. 'stgyType');
344
+ # stgyType (0=general, 1=delta neutral) applies only when type == 'stgyType'.
345
+ def set_trading_config(self, type='', stgyType=''):
346
+ params = {'type': type}
347
+ if stgyType != '':
348
+ params['stgyType'] = stgyType
349
+ return self._request_with_params(POST, SET_TRADING_CONFIG, params)
350
+
351
+ # Pre-check whether the delta-neutral switch is allowed (BROK-1724)
352
+ def precheck_set_delta_neutral(self, stgyType=''):
353
+ params = {'stgyType': stgyType}
354
+ return self._request_with_params(GET, PRECHECK_SET_DELTA_NEUTRAL, params)
355
+
356
+ # Get the list of supported bill subtypes (BROK-1728)
357
+ def get_bill_type(self, type=''):
358
+ params = {}
359
+ if type != '':
360
+ params['type'] = type
361
+ return self._request_with_params(GET, BILL_TYPE, params)
362
+
363
+ # Apply for an asynchronous bill history archive by year + quarter (BROK-1728)
364
+ def apply_bills(self, year='', quarter='', type=''):
365
+ params = {'year': year, 'quarter': quarter}
366
+ if type != '':
367
+ params['type'] = type
368
+ return self._request_with_params(POST, BILLS_APPLY, params)
okx/Convert.py CHANGED
@@ -10,16 +10,22 @@ class ConvertAPI(OkxClient):
10
10
  params = {}
11
11
  return self._request_with_params(GET, GET_CURRENCIES, params)
12
12
 
13
- def get_currency_pair(self, fromCcy='', toCcy=''):
13
+ def get_currency_pair(self, fromCcy='', toCcy='', convertMode=None):
14
14
  params = {"fromCcy": fromCcy, 'toCcy': toCcy}
15
+ if convertMode is not None:
16
+ params['convertMode'] = convertMode
15
17
  return self._request_with_params(GET, GET_CURRENCY_PAIR, params)
16
18
 
17
- def estimate_quote(self, baseCcy = '', quoteCcy = '', side = '', rfqSz = '', rfqSzCcy = '', clQReqId = '',tag=''):
19
+ def estimate_quote(self, baseCcy = '', quoteCcy = '', side = '', rfqSz = '', rfqSzCcy = '', clQReqId = '',tag='', convertMode=None):
18
20
  params = {'baseCcy': baseCcy, 'quoteCcy': quoteCcy, 'side':side, 'rfqSz':rfqSz, 'rfqSzCcy':rfqSzCcy, 'clQReqId':clQReqId,'tag':tag}
21
+ if convertMode is not None:
22
+ params['convertMode'] = convertMode
19
23
  return self._request_with_params(POST, ESTIMATE_QUOTE, params)
20
24
 
21
- def convert_trade(self, quoteId = '', baseCcy = '', quoteCcy = '', side = '', sz = '', szCcy = '', clTReqId = '',tag=''):
25
+ def convert_trade(self, quoteId = '', baseCcy = '', quoteCcy = '', side = '', sz = '', szCcy = '', clTReqId = '',tag='', convertMode=None):
22
26
  params = {'quoteId': quoteId, 'baseCcy': baseCcy, 'quoteCcy':quoteCcy, 'side':side, 'sz':sz, 'szCcy':szCcy, 'clTReqId':clTReqId,'tag':tag}
27
+ if convertMode is not None:
28
+ params['convertMode'] = convertMode
23
29
  return self._request_with_params(POST, CONVERT_TRADE, params)
24
30
 
25
31
  def get_convert_history(self, after = '', before = '', limit = '',tag=''):
okx/DualInvest.py ADDED
@@ -0,0 +1,59 @@
1
+ from .okxclient import OkxClient
2
+ from .consts import (
3
+ GET,
4
+ POST,
5
+ DUAL_INVEST_CURRENCY_PAIRS,
6
+ DUAL_INVEST_PRODUCT_INFO,
7
+ DUAL_INVEST_REQUEST_QUOTE,
8
+ DUAL_INVEST_TRADE,
9
+ DUAL_INVEST_REQUEST_REDEEM_QUOTE,
10
+ DUAL_INVEST_REDEEM,
11
+ DUAL_INVEST_ORDER_STATE,
12
+ DUAL_INVEST_ORDER_HISTORY,
13
+ )
14
+
15
+
16
+ class DualInvestAPI(OkxClient):
17
+ def __init__(self, api_key='-1', api_secret_key='-1', passphrase='-1', use_server_time=None, flag='1', domain='https://www.okx.com', debug=False, proxy=None): # NOSONAR - '-1' is the SDK-wide "no credential supplied" sentinel (auth is gated on api_key != '-1' in OkxClient), not a hard-coded secret
18
+ OkxClient.__init__(self, api_key, api_secret_key, passphrase, use_server_time, flag, domain, debug, proxy)
19
+
20
+ # GET /api/v5/finance/sfp/dcd/currency-pair
21
+ def get_currency_pairs(self):
22
+ return self._request_without_params(GET, DUAL_INVEST_CURRENCY_PAIRS)
23
+
24
+ # GET /api/v5/finance/sfp/dcd/products
25
+ def get_product_info(self, baseCcy='', quoteCcy='', optType=''):
26
+ params = {'baseCcy': baseCcy, 'quoteCcy': quoteCcy, 'optType': optType}
27
+ return self._request_with_params(GET, DUAL_INVEST_PRODUCT_INFO, params)
28
+
29
+ # POST /api/v5/finance/sfp/dcd/quote
30
+ def request_quote(self, productId='', notionalSz='', notionalCcy=''):
31
+ params = {'productId': productId, 'notionalSz': notionalSz, 'notionalCcy': notionalCcy}
32
+ return self._request_with_params(POST, DUAL_INVEST_REQUEST_QUOTE, params)
33
+
34
+ # POST /api/v5/finance/sfp/dcd/trade
35
+ def trade(self, quoteId=''):
36
+ params = {'quoteId': quoteId}
37
+ return self._request_with_params(POST, DUAL_INVEST_TRADE, params)
38
+
39
+ # POST /api/v5/finance/sfp/dcd/redeem-quote
40
+ def request_redeem_quote(self, ordId=''):
41
+ params = {'ordId': ordId}
42
+ return self._request_with_params(POST, DUAL_INVEST_REQUEST_REDEEM_QUOTE, params)
43
+
44
+ # POST /api/v5/finance/sfp/dcd/redeem
45
+ def redeem(self, ordId='', quoteId=''):
46
+ params = {'ordId': ordId, 'quoteId': quoteId}
47
+ return self._request_with_params(POST, DUAL_INVEST_REDEEM, params)
48
+
49
+ # GET /api/v5/finance/sfp/dcd/order-status
50
+ def get_order_state(self, ordId=''):
51
+ params = {'ordId': ordId}
52
+ return self._request_with_params(GET, DUAL_INVEST_ORDER_STATE, params)
53
+
54
+ # GET /api/v5/finance/sfp/dcd/order-history
55
+ def get_order_history(self, ordId='', productId='', uly='', state='',
56
+ beginId='', endId='', begin='', end='', limit=''):
57
+ params = {'ordId': ordId, 'productId': productId, 'uly': uly, 'state': state,
58
+ 'beginId': beginId, 'endId': endId, 'begin': begin, 'end': end, 'limit': limit}
59
+ return self._request_with_params(GET, DUAL_INVEST_ORDER_HISTORY, params)
okx/Finance/EthStaking.py CHANGED
@@ -24,6 +24,13 @@ class EthStakingAPI(OkxClient):
24
24
  }
25
25
  return self._request_with_params(POST, STACK_ETH_REDEEM, params)
26
26
 
27
+ def eth_cancel_redeem(self, ordId=''):
28
+
29
+ params = {
30
+ 'ordId': ordId,
31
+ }
32
+ return self._request_with_params(POST, STACK_ETH_CANCEL_REDEEM, params)
33
+
27
34
  def eth_balance(self):
28
35
 
29
36
  params = {}
okx/PublicData.py CHANGED
@@ -137,3 +137,8 @@ class PublicAPI(OkxClient):
137
137
  if instFamilyList is not None:
138
138
  params['instFamilyList'] = instFamilyList
139
139
  return self._request_with_params(GET, MARKET_DATA_HISTORY, params)
140
+
141
+ # Get announcements (BROK-1730)
142
+ def get_announcements(self, annType='', page=''):
143
+ params = {'annType': annType, 'page': page}
144
+ return self._request_with_params(GET, ANNOUNCEMENTS, params)
okx/Trade.py CHANGED
@@ -11,8 +11,9 @@ class TradeAPI(OkxClient):
11
11
  OkxClient.__init__(self, api_key, api_secret_key, passphrase, use_server_time, flag, domain, debug, proxy)
12
12
 
13
13
  # Place Order
14
- def place_order(self, instId, tdMode, side, ordType, sz, ccy='', clOrdId='', tag='', posSide='', px='',
15
- reduceOnly='', tgtCcy='', stpMode='', attachAlgoOrds=None, pxUsd='', pxVol='', banAmend='', tradeQuoteCcy=None, pxAmendType=None):
14
+ def place_order(self, instId, tdMode, side, ordType, sz, ccy='', clOrdId='', tag='', posSide='', px='', # NOSONAR - public OKX v5 place-order API surface; the parameter list mirrors the REST endpoint 1:1 and cannot be reduced without breaking backward compatibility
15
+ reduceOnly='', tgtCcy='', stpMode='', attachAlgoOrds=None, pxUsd='', pxVol='', banAmend='', tradeQuoteCcy=None, pxAmendType=None,
16
+ isElpTakerAccess=None, instIdCode=None):
16
17
  params = {'instId': instId, 'tdMode': tdMode, 'side': side, 'ordType': ordType, 'sz': sz, 'ccy': ccy,
17
18
  'clOrdId': clOrdId, 'tag': tag, 'posSide': posSide, 'px': px, 'reduceOnly': reduceOnly,
18
19
  'tgtCcy': tgtCcy, 'stpMode': stpMode, 'pxUsd': pxUsd, 'pxVol': pxVol, 'banAmend': banAmend}
@@ -20,6 +21,10 @@ class TradeAPI(OkxClient):
20
21
  params['tradeQuoteCcy'] = tradeQuoteCcy
21
22
  if pxAmendType is not None:
22
23
  params['pxAmendType'] = pxAmendType
24
+ if isElpTakerAccess is not None:
25
+ params['isElpTakerAccess'] = isElpTakerAccess
26
+ if instIdCode is not None:
27
+ params['instIdCode'] = instIdCode
23
28
  params['attachAlgoOrds'] = attachAlgoOrds
24
29
  return self._request_with_params(POST, PLACR_ORDER, params)
25
30
 
@@ -37,15 +42,20 @@ class TradeAPI(OkxClient):
37
42
  return self._request_with_params(POST, CANCEL_BATCH_ORDERS, orders_data)
38
43
 
39
44
  # Amend Order
40
- def amend_order(self, instId, cxlOnFail='', ordId='', clOrdId='', reqId='', newSz='', newPx='', newTpTriggerPx='',
45
+ def amend_order(self, instId, cxlOnFail='', ordId='', clOrdId='', reqId='', newSz='', newPx='', newTpTriggerPx='', # NOSONAR - public OKX v5 amend-order API surface; the parameter list mirrors the REST endpoint 1:1 and cannot be reduced without breaking backward compatibility
41
46
  newTpOrdPx='', newSlTriggerPx='', newSlOrdPx='', newTpTriggerPxType='', newSlTriggerPxType='',
42
- attachAlgoOrds='', newTriggerPx='', newOrdPx='', pxAmendType=None):
47
+ attachAlgoOrds='', newTriggerPx='', newOrdPx='', pxAmendType=None,
48
+ newTpTriggerRatio=None, newSlTriggerRatio=None):
43
49
  params = {'instId': instId, 'cxlOnFail': cxlOnFail, 'ordId': ordId, 'clOrdId': clOrdId, 'reqId': reqId,
44
50
  'newSz': newSz, 'newPx': newPx, 'newTpTriggerPx': newTpTriggerPx, 'newTpOrdPx': newTpOrdPx,
45
51
  'newSlTriggerPx': newSlTriggerPx, 'newSlOrdPx': newSlOrdPx, 'newTpTriggerPxType': newTpTriggerPxType,
46
52
  'newSlTriggerPxType': newSlTriggerPxType, 'newTriggerPx': newTriggerPx, 'newOrdPx': newOrdPx}
47
53
  if pxAmendType is not None:
48
54
  params['pxAmendType'] = pxAmendType
55
+ if newTpTriggerRatio is not None:
56
+ params['newTpTriggerRatio'] = newTpTriggerRatio
57
+ if newSlTriggerRatio is not None:
58
+ params['newSlTriggerRatio'] = newSlTriggerRatio
49
59
  params['attachAlgoOrds'] = attachAlgoOrds
50
60
  return self._request_with_params(POST, AMEND_ORDER, params)
51
61
 
@@ -94,7 +104,7 @@ class TradeAPI(OkxClient):
94
104
  return self._request_with_params(GET, ORDER_FILLS, params)
95
105
 
96
106
  # Place Algo Order
97
- def place_algo_order(self, instId='', tdMode='', side='', ordType='', sz='', ccy='',
107
+ def place_algo_order(self, instId='', tdMode='', side='', ordType='', sz='', ccy='', # NOSONAR - public OKX v5 place-algo-order API surface; the parameter list mirrors the REST endpoint 1:1 and cannot be reduced without breaking backward compatibility
98
108
  posSide='', reduceOnly='', tpTriggerPx='',
99
109
  tpOrdPx='', slTriggerPx='', slOrdPx='',
100
110
  triggerPx='', orderPx='', tgtCcy='', pxVar='',
@@ -102,7 +112,8 @@ class TradeAPI(OkxClient):
102
112
  szLimit='', pxLimit='', timeInterval='', tpTriggerPxType='', slTriggerPxType='',
103
113
  callbackRatio='', callbackSpread='', activePx='', tag='', triggerPxType='', closeFraction=''
104
114
  , quickMgnType='', algoClOrdId='', tradeQuoteCcy=None, tpOrdKind='', cxlOnClosePos=''
105
- , chaseType='', chaseVal='', maxChaseType='', maxChaseVal='', attachAlgoOrds=[], pxAmendType=None):
115
+ , chaseType='', chaseVal='', maxChaseType='', maxChaseVal='', attachAlgoOrds=[], pxAmendType=None
116
+ , advanceOrdType=None, tpTriggerRatio=None, slTriggerRatio=None):
106
117
  params = {'instId': instId, 'tdMode': tdMode, 'side': side, 'ordType': ordType, 'sz': sz, 'ccy': ccy,
107
118
  'posSide': posSide, 'reduceOnly': reduceOnly, 'tpTriggerPx': tpTriggerPx, 'tpOrdPx': tpOrdPx,
108
119
  'slTriggerPx': slTriggerPx, 'slOrdPx': slOrdPx, 'triggerPx': triggerPx, 'orderPx': orderPx,
@@ -118,11 +129,27 @@ class TradeAPI(OkxClient):
118
129
  params['tradeQuoteCcy'] = tradeQuoteCcy
119
130
  if pxAmendType is not None:
120
131
  params['pxAmendType'] = pxAmendType
132
+ if advanceOrdType is not None:
133
+ params['advanceOrdType'] = advanceOrdType
134
+ if tpTriggerRatio is not None:
135
+ params['tpTriggerRatio'] = tpTriggerRatio
136
+ if slTriggerRatio is not None:
137
+ params['slTriggerRatio'] = slTriggerRatio
121
138
  return self._request_with_params(POST, PLACE_ALGO_ORDER, params)
122
139
 
123
140
  # Cancel Algo Order
124
- def cancel_algo_order(self, params):
125
- return self._request_with_params(POST, CANCEL_ALGOS, params)
141
+ def cancel_algo_order(self, orders_data=None, params=None):
142
+ """
143
+ Cancel algo orders — POST /api/v5/trade/cancel-algos.
144
+
145
+ :param orders_data: list of {'instId': str, 'algoId': str},
146
+ e.g. [{'instId': 'BTC-USDT', 'algoId': '590xxxx'}]
147
+ :param params: DEPRECATED alias for orders_data (kept for backward compatibility).
148
+ """
149
+ data = orders_data if orders_data is not None else params
150
+ if data is None:
151
+ raise ValueError("orders_data is required: list of {'instId', 'algoId'}")
152
+ return self._request_with_params(POST, CANCEL_ALGOS, data)
126
153
 
127
154
  # Get Algo Order List
128
155
  def order_algos_list(self, ordType='', algoId='', instType='', instId='', after='', before='', limit=''):
okx/__init__.py CHANGED
@@ -2,4 +2,4 @@
2
2
  Python SDK for the OKX API v5
3
3
 
4
4
  """
5
- __version__="0.4.1"
5
+ __version__="0.4.3"
okx/consts.py CHANGED
@@ -67,6 +67,10 @@ MANUAL_REBORROW_REPAY = '/api/v5/account/spot-manual-borrow-repay'
67
67
  SET_AUTO_REPAY='/api/v5/account/set-auto-repay'
68
68
  GET_BORROW_REPAY_HISTORY='/api/v5/account/spot-borrow-repay-history'
69
69
  SET_AUTO_EARN='/api/v5/account/set-auto-earn'
70
+ SET_TRADING_CONFIG = '/api/v5/account/set-trading-config'
71
+ PRECHECK_SET_DELTA_NEUTRAL = '/api/v5/account/precheck-set-delta-neutral'
72
+ BILL_TYPE = '/api/v5/account/subtypes'
73
+ BILLS_APPLY = '/api/v5/account/bills-history-archive'
70
74
 
71
75
  # Funding
72
76
  NON_TRADABLE_ASSETS = '/api/v5/asset/non-tradable-assets'
@@ -144,6 +148,7 @@ OPEN_INTEREST_VOLUME_EXPIRY = '/api/v5/rubik/stat/option/open-interest-volume-ex
144
148
  INTEREST_VOLUME_STRIKE = '/api/v5/rubik/stat/option/open-interest-volume-strike'
145
149
  TAKER_FLOW = '/api/v5/rubik/stat/option/taker-block-volume'
146
150
  CONTRACTS_OPEN_INTEREST_HISTORY = '/api/v5/rubik/stat/contracts/open-interest-history'
151
+ ANNOUNCEMENTS = '/api/v5/support/announcements'
147
152
 
148
153
  # Trade
149
154
  PLACR_ORDER = '/api/v5/trade/order'
@@ -255,6 +260,7 @@ GET_PUBLIC_BORROW_HISTORY = '/api/v5/finance/savings/lending-rate-history'
255
260
  STACK_ETH_PRODUCT_INFO = '/api/v5/finance/staking-defi/eth/product-info'
256
261
  STACK_ETH_PURCHASE = '/api/v5/finance/staking-defi/eth/purchase'
257
262
  STACK_ETH_REDEEM = '/api/v5/finance/staking-defi/eth/redeem'
263
+ STACK_ETH_CANCEL_REDEEM = '/api/v5/finance/staking-defi/eth/cancel-redeem'
258
264
  STACK_ETH_BALANCE = '/api/v5/finance/staking-defi/eth/balance'
259
265
  STACK_ETH_PURCHASE_REDEEM_HISTORY = '/api/v5/finance/staking-defi/eth/purchase-redeem-history'
260
266
  STACK_ETH_APY_HISTORY = '/api/v5/finance/staking-defi/eth/apy-history'
@@ -302,4 +308,15 @@ FINANCE_LOAN_INFO = '/api/v5/finance/flexible-loan/loan-info'
302
308
  FINANCE_LOAN_HISTORY = '/api/v5/finance/flexible-loan/loan-history'
303
309
  FINANCE_INTEREST_ACCRUED = '/api/v5/finance/flexible-loan/interest-accrued'
304
310
 
311
+ # Dual Investment (DCD) — under /api/v5/finance/sfp/dcd/
312
+ DUAL_INVEST_CURRENCY_PAIRS = '/api/v5/finance/sfp/dcd/currency-pair'
313
+ DUAL_INVEST_PRODUCT_INFO = '/api/v5/finance/sfp/dcd/products'
314
+ DUAL_INVEST_REQUEST_QUOTE = '/api/v5/finance/sfp/dcd/quote'
315
+ DUAL_INVEST_TRADE = '/api/v5/finance/sfp/dcd/trade'
316
+ DUAL_INVEST_REQUEST_REDEEM_QUOTE = '/api/v5/finance/sfp/dcd/redeem-quote'
317
+ DUAL_INVEST_REDEEM = '/api/v5/finance/sfp/dcd/redeem'
318
+ DUAL_INVEST_ORDER_STATE = '/api/v5/finance/sfp/dcd/order-status'
319
+ DUAL_INVEST_ORDER_HISTORY = '/api/v5/finance/sfp/dcd/order-history'
320
+
321
+
305
322
 
@@ -3,6 +3,8 @@ import json
3
3
  import logging
4
4
  import warnings
5
5
 
6
+ from websockets.exceptions import ConnectionClosedError
7
+
6
8
  from okx.websocket import WsUtils
7
9
  from okx.websocket.WebSocketFactory import WebSocketFactory
8
10
 
@@ -35,11 +37,17 @@ class WsPrivateAsync:
35
37
  self.websocket = await self.factory.connect()
36
38
 
37
39
  async def consume(self):
38
- async for message in self.websocket:
39
- if self.debug:
40
- logger.debug("Received message: {%s}", message)
40
+ try:
41
+ async for message in self.websocket:
42
+ if self.debug:
43
+ logger.debug("Received message: {%s}", message)
44
+ if self.callback:
45
+ self.callback(message)
46
+ except ConnectionClosedError as e:
47
+ logger.error(f"WebSocket connection closed: {e}")
41
48
  if self.callback:
42
- self.callback(message)
49
+ self.callback(json.dumps({"event": "error", "code": "ConnClosed", "msg": str(e)}))
50
+ raise
43
51
 
44
52
  async def subscribe(self, params: list, callback, id: str = None):
45
53
  self.callback = callback
@@ -194,7 +202,7 @@ class WsPrivateAsync:
194
202
  else:
195
203
  logger.info("Connecting to WebSocket...")
196
204
  await self.connect()
197
- self.loop.create_task(self.consume())
205
+ return self.loop.create_task(self.consume())
198
206
 
199
207
  def stop_sync(self):
200
208
  if self.loop.is_running():
@@ -2,6 +2,8 @@ import asyncio
2
2
  import json
3
3
  import logging
4
4
 
5
+ from websockets.exceptions import ConnectionClosedError
6
+
5
7
  from okx.websocket import WsUtils
6
8
  from okx.websocket.WebSocketFactory import WebSocketFactory
7
9
 
@@ -31,11 +33,17 @@ class WsPublicAsync:
31
33
  self.websocket = await self.factory.connect()
32
34
 
33
35
  async def consume(self):
34
- async for message in self.websocket:
35
- if self.debug:
36
- logger.debug("Received message: {%s}", message)
36
+ try:
37
+ async for message in self.websocket:
38
+ if self.debug:
39
+ logger.debug("Received message: {%s}", message)
40
+ if self.callback:
41
+ self.callback(message)
42
+ except ConnectionClosedError as e:
43
+ logger.error(f"WebSocket connection closed: {e}")
37
44
  if self.callback:
38
- self.callback(message)
45
+ self.callback(json.dumps({"event": "error", "code": "ConnClosed", "msg": str(e)}))
46
+ raise
39
47
 
40
48
  async def login(self):
41
49
  """
@@ -115,7 +123,7 @@ class WsPublicAsync:
115
123
  else:
116
124
  logger.info("Connecting to WebSocket...")
117
125
  await self.connect()
118
- self.loop.create_task(self.consume())
126
+ return self.loop.create_task(self.consume())
119
127
 
120
128
  def stop_sync(self):
121
129
  if self.loop.is_running():
@@ -1,12 +1,10 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: python-okx
3
- Version: 0.4.1
3
+ Version: 0.4.3
4
4
  Summary: Python SDK for OKX
5
5
  Home-page: https://okx.com/docs-v5/
6
6
  Author: okxv5api
7
7
  Author-email: api@okg.com
8
- License: UNKNOWN
9
- Platform: UNKNOWN
10
8
  Classifier: Programming Language :: Python :: 3
11
9
  Classifier: Programming Language :: Python :: 3.7
12
10
  Classifier: Programming Language :: Python :: 3.8
@@ -23,13 +21,15 @@ Requires-Dist: requests>=2.25.0
23
21
  Requires-Dist: websockets>=10.0
24
22
  Requires-Dist: certifi>=2021.0.0
25
23
  Requires-Dist: loguru>=0.7.0
26
- Requires-Dist: python-dotenv>=1.0.0
27
- Requires-Dist: pytest>=7.0.0
28
- Requires-Dist: pytest-asyncio>=0.21.0
29
- Requires-Dist: pytest-cov>=4.0.0
30
- Requires-Dist: ruff>=0.1.0
31
- Requires-Dist: build>=1.0.0
32
- Requires-Dist: twine>=4.0.0
24
+ Dynamic: author
25
+ Dynamic: author-email
26
+ Dynamic: classifier
27
+ Dynamic: description
28
+ Dynamic: description-content-type
29
+ Dynamic: home-page
30
+ Dynamic: requires-dist
31
+ Dynamic: requires-python
32
+ Dynamic: summary
33
33
 
34
34
  ### Overview
35
35
  This is an unofficial Python wrapper for the [OKX exchange v5 API](https://www.okx.com/okx-api)
@@ -51,6 +51,7 @@ Make sure you update often and check the [Changelog](https://www.okx.com/docs-v5
51
51
  - Websocket handling with reconnection and multiplexed connections
52
52
 
53
53
  ### Quick start
54
+
54
55
  #### Prerequisites
55
56
 
56
57
  `python version:>=3.7`
@@ -120,7 +121,7 @@ git clone https://github.com/okxapi/python-okx.git
120
121
  cd python-okx
121
122
 
122
123
  # Install dependencies
123
- pip install -r requirements.txt
124
+ pip install -r dev_requirements.txt
124
125
  pip install -e .
125
126
 
126
127
  # Run tests
@@ -167,5 +168,3 @@ Note
167
168
  https://github.com/Rapptz/discord.py/issues/1996
168
169
  https://github.com/aaugustin/websockets/issues/587
169
170
  ```
170
-
171
-
@@ -1,34 +1,35 @@
1
- okx/Account.py,sha256=ms9eNwuKHmYi2Oun4X6LQJ9OcazUPdEn8NfoLtYyFoA,14815
1
+ okx/Account.py,sha256=mK_q3P1ZcPI8iuZuZ5TrMIV4eOLQUP3O3Ts3vasLQMI,16143
2
2
  okx/BlockTrading.py,sha256=A4OcuLuEHucAIhc8doPGr2o6dsCjVbv-a6YiTlzwdEw,4128
3
- okx/Convert.py,sha256=xEB2pwEUpc-k23hA3mYIe3EKB5szIXlEe96JFiRSPpc,1575
3
+ okx/Convert.py,sha256=AlFKMOnn6UPpFvak6iQSpRq6UtrBSBNaYwwZTRRBk6E,1881
4
4
  okx/CopyTrading.py,sha256=Mso5GE9UQTJVrL4V3jIyU1QWBtzr-m32edrGDoRHk84,2751
5
+ okx/DualInvest.py,sha256=CTuvjI6KDgkB4trfjFZLiBNB9FO0r3gampPx3JkioE8,2782
5
6
  okx/FDBroker.py,sha256=nUpcR_XtUcKa1Jk_B1OUZCjiv9ifQnxGRsLNHDxdGno,788
6
7
  okx/Funding.py,sha256=lQcx1JUyebhbQGd978K_LuJUTi52Wi1GjrnI40i9Xrc,5040
7
8
  okx/Grid.py,sha256=8rPEjojbyZ_kJdzvHMHVkVTp-xrdUC0SCQ2rmY35rPA,6911
8
9
  okx/MarketData.py,sha256=4GO8Vdkh02GQFJeqC0k4ej3w49wkZroEOoVJ407_ju4,4827
9
- okx/PublicData.py,sha256=UIBX9fQRRsOpEa7OMoZbSGy9bPEHCMI3YhGk7pzYlt4,5726
10
+ okx/PublicData.py,sha256=SkiHA3AiXhPHjZ4OK_k7YyAX6A5i3gbEWZDk5swibHE,5938
10
11
  okx/SpreadTrading.py,sha256=Dy7VZ8WK4HyxhMvLY1G5RukRHI_T3d0fnrHZifv9Uyw,3227
11
12
  okx/Status.py,sha256=hGnn-tw302xXCDWly7LssaG3-29HcHZRhrBFUuGrSS0,495
12
13
  okx/SubAccount.py,sha256=BcwEzi_Y63k-rS9IffFKAJ2ywVl7o9J0U9sBzg87Lpw,3264
13
- okx/Trade.py,sha256=FHNxkHWf046YuDpXS94DgA8OWXMJgdPMOEHYxB7GFOE,11981
14
+ okx/Trade.py,sha256=nw93Zar92U5lIJ5WhPK6v-W8l_J_-sAY4ZvIx8Njp_U,13880
14
15
  okx/TradingData.py,sha256=T_55BXEcEXj7Ti5eO1hfRo6fgdg5i2VxXYl4G3acgnE,3498
15
- okx/__init__.py,sha256=UP-NPa-t7tXwbtG7kEnTlQZu2HPH1DKmRM_hiYP1mvo,58
16
- okx/consts.py,sha256=KrI7d7wEmJ0VkVeVQiB_iqNf9bebbBP37_LXJ0MsvSI,14841
16
+ okx/__init__.py,sha256=X0xFnw59xovb4eAHErwrskpMxsvR7vgzAtyRD9Yy-f0,58
17
+ okx/consts.py,sha256=XNxojpnVOl72V3EuNTiIEuFvWrPdOFXul9srHoaO9Xc,15820
17
18
  okx/exceptions.py,sha256=ERuCnvnudJNBNACh3LNE3km5GJy0BGC5C3OKjgHXFaU,1182
18
19
  okx/okxclient.py,sha256=wywtgB73QelIlsQHFkOcRQsichdpm1n8AlYizB9S_rI,3040
19
20
  okx/utils.py,sha256=yMlqB3OF6NDBrz7P6rEmD8PWe2xeqh0Gw8lceUFWy0A,1879
20
- okx/Finance/EthStaking.py,sha256=hOl_i4VOBjejeyBboG1-37rhVnlSoOZ44e-Jzger-bQ,1612
21
+ okx/Finance/EthStaking.py,sha256=SGI9nP_l9wQOjr7P6Ct1v75JUbjdX7z4CWL11hYU1AQ,1794
21
22
  okx/Finance/FlexibleLoan.py,sha256=L-j1O73fEIIiM_h8NvCT6NocUv6KAx2WEQU6F9GRzIw,2351
22
23
  okx/Finance/Savings.py,sha256=qZbv-KzgGt_me8RZePDSUiRCI1mbz692EK2ZhfYiH8c,1999
23
24
  okx/Finance/SolStaking.py,sha256=VcEU4ukbU5bO8qe00DDfFJ0DUIZZS9ZO_-A2evJz5e0,1608
24
25
  okx/Finance/StakingDefi.py,sha256=eWyAAmMDht4B4N5VWf3bj3FxSBETMXaay-Luu4GN3ls,2250
25
26
  okx/Finance/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
26
27
  okx/websocket/WebSocketFactory.py,sha256=ba0ZNUggghZ_YlWYB7g8UCv6MewqVr9wn75YOtIU5kE,845
27
- okx/websocket/WsPrivateAsync.py,sha256=jq5Imy3hiM3pA7i-uUisGi2R_t9J4h_UOu78mWCv6do,6643
28
- okx/websocket/WsPublicAsync.py,sha256=e5UXLP0y5ypcdV9YXk39FZqDVvA76H-VS1xWAKXREDs,3920
28
+ okx/websocket/WsPrivateAsync.py,sha256=yssG16oniViPQhIUb52kPj_TmNhrulXY7GknkkjAZ7Q,6992
29
+ okx/websocket/WsPublicAsync.py,sha256=rOBVvO1Hm0SeIKGJYanom0Vs4FjH8wZHFNjsaXCJWJA,4269
29
30
  okx/websocket/WsUtils.py,sha256=ynkCtfvkrwBUiCi-_yqp1xTn3hhVd_o5ITIhD1xLdBo,2199
30
31
  okx/websocket/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
31
- python_okx-0.4.1.dist-info/METADATA,sha256=Cu772omzS6r2A7RbtDJMPGXTJU8hgcTcbQgbDHqswrY,4751
32
- python_okx-0.4.1.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
33
- python_okx-0.4.1.dist-info/top_level.txt,sha256=rrbhHZwiw4YlhG1LWWaAODvRxyZr3onxFnqwsHdikDc,4
34
- python_okx-0.4.1.dist-info/RECORD,,
32
+ python_okx-0.4.3.dist-info/METADATA,sha256=iFiDChj4NsWcOeWc96PEjs1G9Zfq3SzdOO3A7mlIGJ8,4697
33
+ python_okx-0.4.3.dist-info/WHEEL,sha256=K260EYznzXsJYBQGqmI8VTxEdiZYNvDZwW9cBh9-_MA,91
34
+ python_okx-0.4.3.dist-info/top_level.txt,sha256=rrbhHZwiw4YlhG1LWWaAODvRxyZr3onxFnqwsHdikDc,4
35
+ python_okx-0.4.3.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: bdist_wheel (0.45.1)
2
+ Generator: setuptools (83.0.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5