python-okx 0.3.9__py3-none-any.whl → 0.4.1__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
@@ -23,25 +23,27 @@ class AccountAPI(OkxClient):
23
23
  return self._request_with_params(GET, ACCOUNT_INFO, params)
24
24
 
25
25
  # Get Positions
26
- def get_positions(self, instType='', instId=''):
27
- params = {'instType': instType, 'instId': instId}
26
+ def get_positions(self, instType='', instId='', posId=''):
27
+ params = {'instType': instType, 'instId': instId, 'posId': posId}
28
28
  return self._request_with_params(GET, POSITION_INFO, params)
29
29
 
30
- def position_builder(self, acctLv=None,inclRealPosAndEq=False, lever=None, greeksType=None, simPos=None,
31
- simAsset=None):
30
+ def position_builder(self, acctLv=None, inclRealPosAndEq=None, lever=None, greeksType=None, simPos=None,
31
+ simAsset=None, idxVol=None):
32
32
  params = {}
33
33
  if acctLv is not None:
34
34
  params['acctLv'] = acctLv
35
35
  if inclRealPosAndEq is not None:
36
36
  params['inclRealPosAndEq'] = inclRealPosAndEq
37
37
  if lever is not None:
38
- params['spotOffsetType'] = lever
38
+ params['lever'] = lever
39
39
  if greeksType is not None:
40
- params['greksType'] = greeksType
40
+ params['greeksType'] = greeksType
41
41
  if simPos is not None:
42
42
  params['simPos'] = simPos
43
43
  if simAsset is not None:
44
44
  params['simAsset'] = simAsset
45
+ if idxVol is not None:
46
+ params['idxVol'] = idxVol
45
47
  return self._request_with_params(POST, POSITION_BUILDER, params)
46
48
 
47
49
  # Get Bills Details (recent 7 days)
@@ -74,14 +76,18 @@ class AccountAPI(OkxClient):
74
76
  return self._request_with_params(POST, SET_LEVERAGE, params)
75
77
 
76
78
  # Get Maximum Tradable Size For Instrument
77
- def get_max_order_size(self, instId, tdMode, ccy='', px=''):
79
+ def get_max_order_size(self, instId, tdMode, ccy='', px='', tradeQuoteCcy=None):
78
80
  params = {'instId': instId, 'tdMode': tdMode, 'ccy': ccy, 'px': px}
81
+ if tradeQuoteCcy is not None:
82
+ params['tradeQuoteCcy'] = tradeQuoteCcy
79
83
  return self._request_with_params(GET, MAX_TRADE_SIZE, params)
80
84
 
81
85
  # Get Maximum Available Tradable Amount
82
- def get_max_avail_size(self, instId, tdMode, ccy='', reduceOnly='', unSpotOffset='', quickMgnType=''):
86
+ def get_max_avail_size(self, instId, tdMode, ccy='', reduceOnly='', unSpotOffset='', quickMgnType='', tradeQuoteCcy=None):
83
87
  params = {'instId': instId, 'tdMode': tdMode, 'ccy': ccy, 'reduceOnly': reduceOnly,
84
88
  'unSpotOffset': unSpotOffset, 'quickMgnType': quickMgnType}
89
+ if tradeQuoteCcy is not None:
90
+ params['tradeQuoteCcy'] = tradeQuoteCcy
85
91
  return self._request_with_params(GET, MAX_AVAIL_SIZE, params)
86
92
 
87
93
  # Increase / Decrease margin
@@ -100,8 +106,10 @@ class AccountAPI(OkxClient):
100
106
  return self._request_with_params(GET, GET_INSTRUMENTS, params)
101
107
 
102
108
  # Get the maximum loan of isolated MARGIN
103
- def get_max_loan(self, instId, mgnMode, mgnCcy=''):
109
+ def get_max_loan(self, instId, mgnMode, mgnCcy='', tradeQuoteCcy=None):
104
110
  params = {'instId': instId, 'mgnMode': mgnMode, 'mgnCcy': mgnCcy}
111
+ if tradeQuoteCcy is not None:
112
+ params['tradeQuoteCcy'] = tradeQuoteCcy
105
113
  return self._request_with_params(GET, MAX_LOAN, params)
106
114
 
107
115
  # Get Fee Rates
@@ -323,3 +331,9 @@ class AccountAPI(OkxClient):
323
331
  def spot_borrow_repay_history(self, ccy='', type='', after='', before='', limit=''):
324
332
  params = {'ccy': ccy, 'type': type, 'after': after, 'before': before, 'limit': limit}
325
333
  return self._request_with_params(GET, GET_BORROW_REPAY_HISTORY, params)
334
+
335
+ def set_auto_earn(self, ccy, action, earnType=None):
336
+ params = {'ccy': ccy, 'action': action}
337
+ if earnType is not None:
338
+ params['earnType'] = earnType
339
+ return self._request_with_params(POST, SET_AUTO_EARN, params)
okx/Finance/SolStaking.py CHANGED
@@ -46,3 +46,6 @@ class SolStakingAPI(OkxClient):
46
46
  'days': days,
47
47
  }
48
48
  return self._request_with_params(GET, STACK_SOL_APY_HISTORY, params)
49
+
50
+ def sol_product_info(self):
51
+ return self._request_without_params(GET, STACK_SOL_PRODUCT_INFO)
okx/Funding.py CHANGED
@@ -35,9 +35,11 @@ class FundingAPI(OkxClient):
35
35
  return self._request_with_params(POST, FUNDS_TRANSFER, params)
36
36
 
37
37
  # Withdrawal
38
- def withdrawal(self, ccy, amt, dest, toAddr, chain='', areaCode='', clientId=''):
38
+ def withdrawal(self, ccy, amt, dest, toAddr, chain='', areaCode='', clientId='', toAddrType=None):
39
39
  params = {'ccy': ccy, 'amt': amt, 'dest': dest, 'toAddr': toAddr, 'chain': chain,
40
40
  'areaCode': areaCode, 'clientId': clientId}
41
+ if toAddrType is not None:
42
+ params['toAddrType'] = toAddrType
41
43
  return self._request_with_params(POST, WITHDRAWAL_COIN, params)
42
44
 
43
45
  # Get Deposit History
@@ -46,10 +48,7 @@ class FundingAPI(OkxClient):
46
48
  'depId': depId, 'fromWdId': fromWdId}
47
49
  return self._request_with_params(GET, DEPOSIT_HISTORY, params)
48
50
 
49
- # Get Withdrawal History
50
- def get_withdrawal_history(self, ccy='', wdId='', state='', after='', before='', limit='',txId=''):
51
- params = {'ccy': ccy, 'wdId': wdId, 'state': state, 'after': after, 'before': before, 'limit': limit,'txId':txId}
52
- return self._request_with_params(GET, WITHDRAWAL_HISTORY, params)
51
+
53
52
 
54
53
  # Get Currencies
55
54
  def get_currencies(self, ccy=''):
@@ -113,7 +112,9 @@ class FundingAPI(OkxClient):
113
112
  return self._request_with_params(GET, GET_DEPOSIT_WITHDrAW_STATUS, params)
114
113
 
115
114
  #Get withdrawal history
116
- def get_withdrawal_history(self, ccy='', wdId='', clientId='', txId='', type='', state='', after='', before ='', limit=''):
115
+ def get_withdrawal_history(self, ccy='', wdId='', clientId='', txId='', type='', state='', after='', before='', limit='', toAddrType=None):
117
116
  params = {'ccy': ccy, 'wdId': wdId, 'clientId': clientId, 'txId': txId, 'type': type, 'state': state, 'after': after, 'before': before, 'limit': limit}
117
+ if toAddrType is not None:
118
+ params['toAddrType'] = toAddrType
118
119
  return self._request_with_params(GET, GET_WITHDRAWAL_HISTORY, params)
119
120
 
okx/Grid.py CHANGED
@@ -7,11 +7,13 @@ class GridAPI(OkxClient):
7
7
  OkxClient.__init__(self, api_key, api_secret_key, passphrase, use_server_time, flag, domain, debug, proxy)
8
8
 
9
9
  def grid_order_algo(self, instId='', algoOrdType='', maxPx='', minPx='', gridNum='', runType='', tpTriggerPx='',
10
- slTriggerPx='', tag='', quoteSz='', baseSz='', sz='', direction='', lever='', basePos=''):
10
+ slTriggerPx='', tag='', quoteSz='', baseSz='', sz='', direction='', lever='', basePos='', tradeQuoteCcy=None):
11
11
  params = {'instId': instId, 'algoOrdType': algoOrdType, 'maxPx': maxPx, 'minPx': minPx, 'gridNum': gridNum,
12
12
  'runType': runType, 'tpTriggerPx': tpTriggerPx, 'slTriggerPx': slTriggerPx, 'tag': tag,
13
13
  'quoteSz': quoteSz, 'baseSz': baseSz, 'sz': sz, 'direction': direction, 'lever': lever,
14
14
  'basePos': basePos}
15
+ if tradeQuoteCcy is not None:
16
+ params['tradeQuoteCcy'] = tradeQuoteCcy
15
17
  return self._request_with_params(POST, GRID_ORDER_ALGO, params)
16
18
 
17
19
  def grid_amend_order_algo(self, algoId='', instId='', slTriggerPx='', tpTriggerPx=''):
@@ -79,11 +81,13 @@ class GridAPI(OkxClient):
79
81
 
80
82
  # - Place recurring buy order
81
83
  def place_recurring_buy_order(self, stgyName='', recurringList=[], period='', recurringDay='', recurringTime='',
82
- timeZone='', amt='', investmentCcy='', tdMode='', algoClOrdId='', tag=''):
84
+ timeZone='', amt='', investmentCcy='', tdMode='', algoClOrdId='', tag='', tradeQuoteCcy=None):
83
85
  params = {'stgyName': stgyName, 'recurringList': recurringList, 'period': period, 'recurringDay': recurringDay,
84
86
  'recurringTime': recurringTime,
85
87
  'timeZone': timeZone, 'amt': amt, 'investmentCcy': investmentCcy, 'tdMode': tdMode,
86
88
  'algoClOrdId': algoClOrdId, 'tag': tag}
89
+ if tradeQuoteCcy is not None:
90
+ params['tradeQuoteCcy'] = tradeQuoteCcy
87
91
  return self._request_with_params(POST, PLACE_RECURRING_BUY_ORDER, params)
88
92
 
89
93
  # - Amend recurring buy order
okx/PublicData.py CHANGED
@@ -122,3 +122,18 @@ class PublicAPI(OkxClient):
122
122
  'optType': optType
123
123
  }
124
124
  return self._request_with_params(GET, GET_OPTION_TRADES, params)
125
+
126
+ # Get historical market data
127
+ def get_market_data_history(self, module, instType, dateAggrType, begin, end, instIdList=None, instFamilyList=None):
128
+ params = {
129
+ 'module': module,
130
+ 'instType': instType,
131
+ 'dateAggrType': dateAggrType,
132
+ 'begin': begin,
133
+ 'end': end
134
+ }
135
+ if instIdList is not None:
136
+ params['instIdList'] = instIdList
137
+ if instFamilyList is not None:
138
+ params['instFamilyList'] = instFamilyList
139
+ return self._request_with_params(GET, MARKET_DATA_HISTORY, params)
okx/Trade.py CHANGED
@@ -12,10 +12,14 @@ class TradeAPI(OkxClient):
12
12
 
13
13
  # Place Order
14
14
  def place_order(self, instId, tdMode, side, ordType, sz, ccy='', clOrdId='', tag='', posSide='', px='',
15
- reduceOnly='', tgtCcy='', stpMode='', attachAlgoOrds=None, pxUsd='', pxVol='', banAmend=''):
15
+ reduceOnly='', tgtCcy='', stpMode='', attachAlgoOrds=None, pxUsd='', pxVol='', banAmend='', tradeQuoteCcy=None, pxAmendType=None):
16
16
  params = {'instId': instId, 'tdMode': tdMode, 'side': side, 'ordType': ordType, 'sz': sz, 'ccy': ccy,
17
17
  'clOrdId': clOrdId, 'tag': tag, 'posSide': posSide, 'px': px, 'reduceOnly': reduceOnly,
18
18
  'tgtCcy': tgtCcy, 'stpMode': stpMode, 'pxUsd': pxUsd, 'pxVol': pxVol, 'banAmend': banAmend}
19
+ if tradeQuoteCcy is not None:
20
+ params['tradeQuoteCcy'] = tradeQuoteCcy
21
+ if pxAmendType is not None:
22
+ params['pxAmendType'] = pxAmendType
19
23
  params['attachAlgoOrds'] = attachAlgoOrds
20
24
  return self._request_with_params(POST, PLACR_ORDER, params)
21
25
 
@@ -35,11 +39,13 @@ class TradeAPI(OkxClient):
35
39
  # Amend Order
36
40
  def amend_order(self, instId, cxlOnFail='', ordId='', clOrdId='', reqId='', newSz='', newPx='', newTpTriggerPx='',
37
41
  newTpOrdPx='', newSlTriggerPx='', newSlOrdPx='', newTpTriggerPxType='', newSlTriggerPxType='',
38
- attachAlgoOrds='', newTriggerPx='', newOrdPx=''):
42
+ attachAlgoOrds='', newTriggerPx='', newOrdPx='', pxAmendType=None):
39
43
  params = {'instId': instId, 'cxlOnFail': cxlOnFail, 'ordId': ordId, 'clOrdId': clOrdId, 'reqId': reqId,
40
44
  'newSz': newSz, 'newPx': newPx, 'newTpTriggerPx': newTpTriggerPx, 'newTpOrdPx': newTpOrdPx,
41
45
  'newSlTriggerPx': newSlTriggerPx, 'newSlOrdPx': newSlOrdPx, 'newTpTriggerPxType': newTpTriggerPxType,
42
46
  'newSlTriggerPxType': newSlTriggerPxType, 'newTriggerPx': newTriggerPx, 'newOrdPx': newOrdPx}
47
+ if pxAmendType is not None:
48
+ params['pxAmendType'] = pxAmendType
43
49
  params['attachAlgoOrds'] = attachAlgoOrds
44
50
  return self._request_with_params(POST, AMEND_ORDER, params)
45
51
 
@@ -95,7 +101,8 @@ class TradeAPI(OkxClient):
95
101
  pxSpread='',
96
102
  szLimit='', pxLimit='', timeInterval='', tpTriggerPxType='', slTriggerPxType='',
97
103
  callbackRatio='', callbackSpread='', activePx='', tag='', triggerPxType='', closeFraction=''
98
- , quickMgnType='', algoClOrdId=''):
104
+ , quickMgnType='', algoClOrdId='', tradeQuoteCcy=None, tpOrdKind='', cxlOnClosePos=''
105
+ , chaseType='', chaseVal='', maxChaseType='', maxChaseVal='', attachAlgoOrds=[], pxAmendType=None):
99
106
  params = {'instId': instId, 'tdMode': tdMode, 'side': side, 'ordType': ordType, 'sz': sz, 'ccy': ccy,
100
107
  'posSide': posSide, 'reduceOnly': reduceOnly, 'tpTriggerPx': tpTriggerPx, 'tpOrdPx': tpOrdPx,
101
108
  'slTriggerPx': slTriggerPx, 'slOrdPx': slOrdPx, 'triggerPx': triggerPx, 'orderPx': orderPx,
@@ -104,7 +111,13 @@ class TradeAPI(OkxClient):
104
111
  'pxSpread': pxSpread, 'tpTriggerPxType': tpTriggerPxType, 'slTriggerPxType': slTriggerPxType,
105
112
  'callbackRatio': callbackRatio, 'callbackSpread': callbackSpread, 'activePx': activePx,
106
113
  'tag': tag, 'triggerPxType': triggerPxType, 'closeFraction': closeFraction,
107
- 'quickMgnType': quickMgnType, 'algoClOrdId': algoClOrdId}
114
+ 'quickMgnType': quickMgnType, 'algoClOrdId': algoClOrdId,
115
+ 'tpOrdKind': tpOrdKind, 'cxlOnClosePos': cxlOnClosePos, 'chaseType': chaseType, 'chaseVal': chaseVal,
116
+ 'maxChaseType': maxChaseType, 'maxChaseVal': maxChaseVal, 'attachAlgoOrds': attachAlgoOrds}
117
+ if tradeQuoteCcy is not None:
118
+ params['tradeQuoteCcy'] = tradeQuoteCcy
119
+ if pxAmendType is not None:
120
+ params['pxAmendType'] = pxAmendType
108
121
  return self._request_with_params(POST, PLACE_ALGO_ORDER, params)
109
122
 
110
123
  # Cancel Algo Order
@@ -174,11 +187,11 @@ class TradeAPI(OkxClient):
174
187
  return self._request_with_params(GET, GET_ALGO_ORDER_DETAILS, params)
175
188
 
176
189
  # Amend algo order
177
- def amend_algo_order(self, instId='', algoId='', algoClOrdId='', cxlOnFail='', reqId='', newSz='',
190
+ def amend_algo_order(self, instId='', algoId='', algoClOrdId='', cxlOnFail='', reqId='', newSz='', newTriggerPx='', newOrdPx='',
178
191
  newTpTriggerPx='', newTpOrdPx='', newSlTriggerPx='', newSlOrdPx='', newTpTriggerPxType='',
179
192
  newSlTriggerPxType=''):
180
193
  params = {'instId': instId, 'algoId': algoId, 'algoClOrdId': algoClOrdId, 'cxlOnFail': cxlOnFail,
181
- 'reqId': reqId, 'newSz': newSz, 'newTpTriggerPx': newTpTriggerPx, 'newTpOrdPx': newTpOrdPx,
194
+ 'reqId': reqId, 'newSz': newSz, 'newTriggerPx': newTriggerPx, 'newOrdPx': newOrdPx, 'newTpTriggerPx': newTpTriggerPx, 'newTpOrdPx': newTpOrdPx,
182
195
  'newSlTriggerPx': newSlTriggerPx, 'newSlOrdPx': newSlOrdPx,
183
196
  'newTpTriggerPxType': newTpTriggerPxType, 'newSlTriggerPxType': newSlTriggerPxType}
184
197
  return self._request_with_params(POST, AMEND_ALGO_ORDER, params)
okx/TradingData.py CHANGED
@@ -47,6 +47,31 @@ class TradingDataAPI(OkxClient):
47
47
  params = {'ccy': ccy, 'period': period}
48
48
  return self._request_with_params(GET, TAKER_FLOW, params)
49
49
 
50
+ def get_open_interest_history(self, instId, period=None, begin=None, end=None, limit=None):
51
+ """
52
+ Get contract open interest history
53
+ Retrieve the contract open interest statistics of futures and perp.
54
+ Rate limit: 10 requests per 2 seconds
55
+ Rate limit rule: IP + Instrument ID
56
+
57
+ :param instId: Instrument ID, e.g. BTC-USDT-SWAP. Only applicable to FUTURES, SWAP
58
+ :param period: Bar size, the default is 5m, e.g. [5m/15m/30m/1H/2H/4H]
59
+ :param begin: Return records newer than the requested ts
60
+ :param end: Pagination of data to return records earlier than the requested ts
61
+ :param limit: Number of results per request. The maximum is 100. The default is 100
62
+ :return: API response
63
+ """
64
+ params = {'instId': instId}
65
+ if period is not None:
66
+ params['period'] = period
67
+ if begin is not None:
68
+ params['begin'] = begin
69
+ if end is not None:
70
+ params['end'] = end
71
+ if limit is not None:
72
+ params['limit'] = limit
73
+ return self._request_with_params(GET, CONTRACTS_OPEN_INTEREST_HISTORY, params)
74
+
50
75
 
51
76
 
52
77
 
okx/__init__.py CHANGED
@@ -2,4 +2,4 @@
2
2
  Python SDK for the OKX API v5
3
3
 
4
4
  """
5
- __version__="0.3.9"
5
+ __version__="0.4.1"
okx/consts.py CHANGED
@@ -66,6 +66,7 @@ BORROWING_ORDERS_LIST='/api/v5/account/fixed-loan/borrowing-orders-list'
66
66
  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
+ SET_AUTO_EARN='/api/v5/account/set-auto-earn'
69
70
 
70
71
  # Funding
71
72
  NON_TRADABLE_ASSETS = '/api/v5/asset/non-tradable-assets'
@@ -81,7 +82,6 @@ BILLS_INFO = '/api/v5/asset/bills'
81
82
  DEPOSIT_LIGHTNING = '/api/v5/asset/deposit-lightning'
82
83
  WITHDRAWAL_LIGHTNING = '/api/v5/asset/withdrawal-lightning'
83
84
  CANCEL_WITHDRAWAL = '/api/v5/asset/cancel-withdrawal'
84
- WITHDRAWAL_HISTORY = '/api/v5/asset/withdrawal-history'
85
85
  CONVERT_DUST_ASSETS = '/api/v5/asset/convert-dust-assets'
86
86
  ASSET_VALUATION = '/api/v5/asset/asset-valuation'
87
87
  GET_WITHDRAWAL_HISTORY = '/api/v5/asset/withdrawal-history'
@@ -130,6 +130,7 @@ INSURANCE_FUND = '/api/v5/public/insurance-fund'
130
130
  CONVERT_CONTRACT_COIN = '/api/v5/public/convert-contract-coin'
131
131
  GET_OPTION_TICKBANDS = '/api/v5/public/instrument-tick-bands'
132
132
  GET_OPTION_TRADES = '/api/v5/public/option-trades'
133
+ MARKET_DATA_HISTORY = '/api/v5/public/market-data-history'
133
134
 
134
135
  # Trading data
135
136
  SUPPORT_COIN = '/api/v5/rubik/stat/trading-data/support-coin'
@@ -142,6 +143,7 @@ PUT_CALL_RATIO = '/api/v5/rubik/stat/option/open-interest-volume-ratio'
142
143
  OPEN_INTEREST_VOLUME_EXPIRY = '/api/v5/rubik/stat/option/open-interest-volume-expiry'
143
144
  INTEREST_VOLUME_STRIKE = '/api/v5/rubik/stat/option/open-interest-volume-strike'
144
145
  TAKER_FLOW = '/api/v5/rubik/stat/option/taker-block-volume'
146
+ CONTRACTS_OPEN_INTEREST_HISTORY = '/api/v5/rubik/stat/contracts/open-interest-history'
145
147
 
146
148
  # Trade
147
149
  PLACR_ORDER = '/api/v5/trade/order'
@@ -261,6 +263,7 @@ STACK_SOL_REDEEM = '/api/v5/finance/staking-defi/sol/redeem'
261
263
  STACK_SOL_BALANCE = '/api/v5/finance/staking-defi/sol/balance'
262
264
  STACK_SOL_PURCHASE_REDEEM_HISTORY = '/api/v5/finance/staking-defi/sol/purchase-redeem-history'
263
265
  STACK_SOL_APY_HISTORY = '/api/v5/finance/staking-defi/sol/apy-history'
266
+ STACK_SOL_PRODUCT_INFO = '/api/v5/finance/staking-defi/sol/product-info'
264
267
 
265
268
  # Status
266
269
  STATUS = '/api/v5/system/status'
okx/okxclient.py CHANGED
@@ -14,7 +14,16 @@ from . import consts as c, utils, exceptions
14
14
  class OkxClient(Client):
15
15
 
16
16
  def __init__(self, api_key='-1', api_secret_key='-1', passphrase='-1', use_server_time=None, flag='1',base_api=c.API_URL, debug=False, proxy=None):
17
- super().__init__(base_url=base_api, http2=True, proxy=proxy)
17
+ # Compatible with different versions of httpx
18
+ # New versions (0.24.0+) use proxy, older versions use proxies
19
+ try:
20
+ super().__init__(base_url=base_api, http2=True, proxy=proxy)
21
+ except TypeError:
22
+ # Older versions of httpx use proxies parameter
23
+ if proxy:
24
+ super().__init__(base_url=base_api, http2=True, proxies={'http://': proxy, 'https://': proxy})
25
+ else:
26
+ super().__init__(base_url=base_api, http2=True)
18
27
  self.API_KEY = api_key
19
28
  self.API_SECRET_KEY = api_secret_key
20
29
  self.PASSPHRASE = passphrase
okx/utils.py CHANGED
@@ -42,7 +42,7 @@ def get_header_no_sign(flag,debug = True):
42
42
  def parse_params_to_str(params):
43
43
  url = '?'
44
44
  for key, value in params.items():
45
- if(value != ''):
45
+ if value is not None and value != '':
46
46
  url = url + str(key) + '=' + str(value) + '&'
47
47
  url = url[0:-1]
48
48
  return url
@@ -1,6 +1,7 @@
1
1
  import asyncio
2
2
  import json
3
3
  import logging
4
+ import warnings
4
5
 
5
6
  from okx.websocket import WsUtils
6
7
  from okx.websocket.WebSocketFactory import WebSocketFactory
@@ -9,7 +10,7 @@ logger = logging.getLogger(__name__)
9
10
 
10
11
 
11
12
  class WsPrivateAsync:
12
- def __init__(self, apiKey, passphrase, secretKey, url, useServerTime):
13
+ def __init__(self, apiKey, passphrase, secretKey, url, useServerTime=None, debug=False):
13
14
  self.url = url
14
15
  self.subscriptions = set()
15
16
  self.callback = None
@@ -18,27 +19,43 @@ class WsPrivateAsync:
18
19
  self.apiKey = apiKey
19
20
  self.passphrase = passphrase
20
21
  self.secretKey = secretKey
21
- self.useServerTime = useServerTime
22
+ self.useServerTime = False
23
+ self.websocket = None
24
+ self.debug = debug
25
+
26
+ # Set log level
27
+ if debug:
28
+ logger.setLevel(logging.DEBUG)
29
+
30
+ # Deprecation warning for useServerTime parameter
31
+ if useServerTime is not None:
32
+ warnings.warn("useServerTime parameter is deprecated. Please remove it.", DeprecationWarning)
22
33
 
23
34
  async def connect(self):
24
35
  self.websocket = await self.factory.connect()
25
36
 
26
37
  async def consume(self):
27
38
  async for message in self.websocket:
28
- logger.debug("Received message: {%s}", message)
39
+ if self.debug:
40
+ logger.debug("Received message: {%s}", message)
29
41
  if self.callback:
30
42
  self.callback(message)
31
43
 
32
- async def subscribe(self, params: list, callback):
44
+ async def subscribe(self, params: list, callback, id: str = None):
33
45
  self.callback = callback
34
46
 
35
47
  logRes = await self.login()
36
48
  await asyncio.sleep(5)
37
49
  if logRes:
38
- payload = json.dumps({
50
+ payload_dict = {
39
51
  "op": "subscribe",
40
52
  "args": params
41
- })
53
+ }
54
+ if id is not None:
55
+ payload_dict["id"] = id
56
+ payload = json.dumps(payload_dict)
57
+ if self.debug:
58
+ logger.debug(f"subscribe: {payload}")
42
59
  await self.websocket.send(payload)
43
60
  # await self.consume()
44
61
 
@@ -49,28 +66,139 @@ class WsPrivateAsync:
49
66
  passphrase=self.passphrase,
50
67
  secretKey=self.secretKey
51
68
  )
69
+ if self.debug:
70
+ logger.debug(f"login: {loginPayload}")
52
71
  await self.websocket.send(loginPayload)
53
72
  return True
54
73
 
55
- async def unsubscribe(self, params: list, callback):
74
+ async def unsubscribe(self, params: list, callback, id: str = None):
56
75
  self.callback = callback
57
- payload = json.dumps({
76
+ payload_dict = {
58
77
  "op": "unsubscribe",
59
78
  "args": params
60
- })
61
- logger.info(f"unsubscribe: {payload}")
79
+ }
80
+ if id is not None:
81
+ payload_dict["id"] = id
82
+ payload = json.dumps(payload_dict)
83
+ if self.debug:
84
+ logger.debug(f"unsubscribe: {payload}")
85
+ else:
86
+ logger.info(f"unsubscribe: {payload}")
87
+ await self.websocket.send(payload)
88
+
89
+ async def send(self, op: str, args: list, callback=None, id: str = None):
90
+ """
91
+ Generic send method
92
+ :param op: Operation type
93
+ :param args: Parameter list
94
+ :param callback: Callback function
95
+ :param id: Optional request ID
96
+ """
97
+ if callback:
98
+ self.callback = callback
99
+ payload_dict = {
100
+ "op": op,
101
+ "args": args
102
+ }
103
+ if id is not None:
104
+ payload_dict["id"] = id
105
+ payload = json.dumps(payload_dict)
106
+ if self.debug:
107
+ logger.debug(f"send: {payload}")
62
108
  await self.websocket.send(payload)
63
- # for param in params:
64
- # self.subscriptions.discard(param)
109
+
110
+ async def place_order(self, args: list, callback=None, id: str = None):
111
+ """
112
+ Place order
113
+ :param args: Order parameter list
114
+ :param callback: Callback function
115
+ :param id: Optional request ID
116
+ """
117
+ if callback:
118
+ self.callback = callback
119
+ await self.send("order", args, id=id)
120
+
121
+ async def batch_orders(self, args: list, callback=None, id: str = None):
122
+ """
123
+ Batch place orders
124
+ :param args: Batch order parameter list
125
+ :param callback: Callback function
126
+ :param id: Optional request ID
127
+ """
128
+ if callback:
129
+ self.callback = callback
130
+ await self.send("batch-orders", args, id=id)
131
+
132
+ async def cancel_order(self, args: list, callback=None, id: str = None):
133
+ """
134
+ Cancel order
135
+ :param args: Cancel order parameter list
136
+ :param callback: Callback function
137
+ :param id: Optional request ID
138
+ """
139
+ if callback:
140
+ self.callback = callback
141
+ await self.send("cancel-order", args, id=id)
142
+
143
+ async def batch_cancel_orders(self, args: list, callback=None, id: str = None):
144
+ """
145
+ Batch cancel orders
146
+ :param args: Batch cancel order parameter list
147
+ :param callback: Callback function
148
+ :param id: Optional request ID
149
+ """
150
+ if callback:
151
+ self.callback = callback
152
+ await self.send("batch-cancel-orders", args, id=id)
153
+
154
+ async def amend_order(self, args: list, callback=None, id: str = None):
155
+ """
156
+ Amend order
157
+ :param args: Amend order parameter list
158
+ :param callback: Callback function
159
+ :param id: Optional request ID
160
+ """
161
+ if callback:
162
+ self.callback = callback
163
+ await self.send("amend-order", args, id=id)
164
+
165
+ async def batch_amend_orders(self, args: list, callback=None, id: str = None):
166
+ """
167
+ Batch amend orders
168
+ :param args: Batch amend order parameter list
169
+ :param callback: Callback function
170
+ :param id: Optional request ID
171
+ """
172
+ if callback:
173
+ self.callback = callback
174
+ await self.send("batch-amend-orders", args, id=id)
175
+
176
+ async def mass_cancel(self, args: list, callback=None, id: str = None):
177
+ """
178
+ Mass cancel orders
179
+ Note: This method is for /ws/v5/business channel, rate limit: 1 request/second
180
+ :param args: Cancel parameter list, contains instType and instFamily
181
+ :param callback: Callback function
182
+ :param id: Optional request ID
183
+ """
184
+ if callback:
185
+ self.callback = callback
186
+ await self.send("mass-cancel", args, id=id)
65
187
 
66
188
  async def stop(self):
67
189
  await self.factory.close()
68
- self.loop.stop()
69
190
 
70
191
  async def start(self):
71
- logger.info("Connecting to WebSocket...")
192
+ if self.debug:
193
+ logger.debug("Connecting to WebSocket...")
194
+ else:
195
+ logger.info("Connecting to WebSocket...")
72
196
  await self.connect()
73
197
  self.loop.create_task(self.consume())
74
198
 
75
199
  def stop_sync(self):
76
- self.loop.run_until_complete(self.stop())
200
+ if self.loop.is_running():
201
+ future = asyncio.run_coroutine_threadsafe(self.stop(), self.loop)
202
+ future.result(timeout=10)
203
+ else:
204
+ self.loop.run_until_complete(self.stop())
@@ -2,54 +2,124 @@ import asyncio
2
2
  import json
3
3
  import logging
4
4
 
5
+ from okx.websocket import WsUtils
5
6
  from okx.websocket.WebSocketFactory import WebSocketFactory
6
7
 
7
8
  logger = logging.getLogger(__name__)
8
9
 
9
10
 
10
11
  class WsPublicAsync:
11
- def __init__(self, url):
12
+ def __init__(self, url, apiKey='', passphrase='', secretKey='', debug=False):
12
13
  self.url = url
13
14
  self.subscriptions = set()
14
15
  self.callback = None
15
16
  self.loop = asyncio.get_event_loop()
16
17
  self.factory = WebSocketFactory(url)
18
+ self.websocket = None
19
+ self.debug = debug
20
+ # Credentials for business channel login
21
+ self.apiKey = apiKey
22
+ self.passphrase = passphrase
23
+ self.secretKey = secretKey
24
+ self.isLoggedIn = False
25
+
26
+ # Set log level
27
+ if debug:
28
+ logger.setLevel(logging.DEBUG)
17
29
 
18
30
  async def connect(self):
19
31
  self.websocket = await self.factory.connect()
20
32
 
21
33
  async def consume(self):
22
34
  async for message in self.websocket:
23
- logger.debug("Received message: {%s}", message)
35
+ if self.debug:
36
+ logger.debug("Received message: {%s}", message)
24
37
  if self.callback:
25
38
  self.callback(message)
26
39
 
27
- async def subscribe(self, params: list, callback):
40
+ async def login(self):
41
+ """
42
+ Login method for business channel that requires authentication (e.g. /ws/v5/business)
43
+ """
44
+ if not self.apiKey or not self.secretKey or not self.passphrase:
45
+ raise ValueError("apiKey, secretKey and passphrase are required for login")
46
+
47
+ loginPayload = WsUtils.initLoginParams(
48
+ useServerTime=False,
49
+ apiKey=self.apiKey,
50
+ passphrase=self.passphrase,
51
+ secretKey=self.secretKey
52
+ )
53
+ if self.debug:
54
+ logger.debug(f"login: {loginPayload}")
55
+ await self.websocket.send(loginPayload)
56
+ self.isLoggedIn = True
57
+ return True
58
+
59
+ async def subscribe(self, params: list, callback, id: str = None):
28
60
  self.callback = callback
29
- payload = json.dumps({
61
+ payload_dict = {
30
62
  "op": "subscribe",
31
63
  "args": params
32
- })
64
+ }
65
+ if id is not None:
66
+ payload_dict["id"] = id
67
+ payload = json.dumps(payload_dict)
68
+ if self.debug:
69
+ logger.debug(f"subscribe: {payload}")
33
70
  await self.websocket.send(payload)
34
71
  # await self.consume()
35
72
 
36
- async def unsubscribe(self, params: list, callback):
73
+ async def unsubscribe(self, params: list, callback, id: str = None):
37
74
  self.callback = callback
38
- payload = json.dumps({
75
+ payload_dict = {
39
76
  "op": "unsubscribe",
40
77
  "args": params
41
- })
42
- logger.info(f"unsubscribe: {payload}")
78
+ }
79
+ if id is not None:
80
+ payload_dict["id"] = id
81
+ payload = json.dumps(payload_dict)
82
+ if self.debug:
83
+ logger.debug(f"unsubscribe: {payload}")
84
+ else:
85
+ logger.info(f"unsubscribe: {payload}")
86
+ await self.websocket.send(payload)
87
+
88
+ async def send(self, op: str, args: list, callback=None, id: str = None):
89
+ """
90
+ Generic send method
91
+ :param op: Operation type
92
+ :param args: Parameter list
93
+ :param callback: Callback function
94
+ :param id: Optional request ID
95
+ """
96
+ if callback:
97
+ self.callback = callback
98
+ payload_dict = {
99
+ "op": op,
100
+ "args": args
101
+ }
102
+ if id is not None:
103
+ payload_dict["id"] = id
104
+ payload = json.dumps(payload_dict)
105
+ if self.debug:
106
+ logger.debug(f"send: {payload}")
43
107
  await self.websocket.send(payload)
44
108
 
45
109
  async def stop(self):
46
110
  await self.factory.close()
47
- self.loop.stop()
48
111
 
49
112
  async def start(self):
50
- logger.info("Connecting to WebSocket...")
113
+ if self.debug:
114
+ logger.debug("Connecting to WebSocket...")
115
+ else:
116
+ logger.info("Connecting to WebSocket...")
51
117
  await self.connect()
52
118
  self.loop.create_task(self.consume())
53
119
 
54
120
  def stop_sync(self):
55
- self.loop.run_until_complete(self.stop())
121
+ if self.loop.is_running():
122
+ future = asyncio.run_coroutine_threadsafe(self.stop(), self.loop)
123
+ future.result(timeout=10)
124
+ else:
125
+ self.loop.run_until_complete(self.stop())
@@ -1,21 +1,35 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: python-okx
3
- Version: 0.3.9
3
+ Version: 0.4.1
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
8
10
  Classifier: Programming Language :: Python :: 3
11
+ Classifier: Programming Language :: Python :: 3.7
12
+ Classifier: Programming Language :: Python :: 3.8
13
+ Classifier: Programming Language :: Python :: 3.9
14
+ Classifier: Programming Language :: Python :: 3.10
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
9
17
  Classifier: License :: OSI Approved :: MIT License
10
18
  Classifier: Operating System :: OS Independent
19
+ Requires-Python: >=3.7
11
20
  Description-Content-Type: text/markdown
12
- Requires-Dist: importlib-metadata
13
- Requires-Dist: httpx[http2]
14
- Requires-Dist: keyring
15
- Requires-Dist: loguru
16
- Requires-Dist: requests
17
- Requires-Dist: Twisted
18
- Requires-Dist: pyOpenSSL
21
+ Requires-Dist: httpx[http2]>=0.24.0
22
+ Requires-Dist: requests>=2.25.0
23
+ Requires-Dist: websockets>=10.0
24
+ Requires-Dist: certifi>=2021.0.0
25
+ 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
19
33
 
20
34
  ### Overview
21
35
  This is an unofficial Python wrapper for the [OKX exchange v5 API](https://www.okx.com/okx-api)
@@ -24,8 +38,6 @@ If you came here looking to purchase cryptocurrencies from the OKX exchange, ple
24
38
 
25
39
  #### Source code
26
40
  https://github.com/okxapi/python-okx
27
- #### OKX API Telegram
28
- https://t.me/OKXAPI
29
41
  #### API trading tutorials
30
42
  - Spot trading: https://www.okx.com/help/how-can-i-do-spot-trading-with-the-jupyter-notebook
31
43
  - Derivative trading: https://www.okx.com/help/how-can-i-do-derivatives-trading-with-the-jupyter-notebook
@@ -41,20 +53,80 @@ Make sure you update often and check the [Changelog](https://www.okx.com/docs-v5
41
53
  ### Quick start
42
54
  #### Prerequisites
43
55
 
44
- `python version:>=3.9`
56
+ `python version:>=3.7`
45
57
 
46
- `WebSocketAPI: websockets package advise version 6.0`
47
-
48
- #### Step 1: register an account on OKX and apply for an API key
58
+ #### Step 1: Register an account on OKX and apply for an API key
49
59
  - Register for an account: https://www.okx.com/account/register
50
60
  - Apply for an API key: https://www.okx.com/account/users/myApi
51
61
 
52
- #### Step 2: install python-okx
62
+ #### Step 2: Install python-okx
53
63
 
54
- ```python
64
+ ```bash
55
65
  pip install python-okx
56
66
  ```
57
67
 
68
+ ### API Credentials
69
+
70
+ #### Option 1: Hardcoded credentials
71
+
72
+ ```python
73
+ from okx import Account
74
+
75
+ account = Account.AccountAPI(
76
+ api_key="your-api-key-here",
77
+ api_secret_key="your-api-secret-here",
78
+ passphrase="your-passphrase-here",
79
+ flag="1", # 0 = live trading, 1 = demo trading
80
+ debug=False
81
+ )
82
+ ```
83
+
84
+ #### Option 2: Using `.env` file (recommended)
85
+
86
+ Create a `.env` file in your project root:
87
+
88
+ ```bash
89
+ OKX_API_KEY=your-api-key-here
90
+ OKX_API_SECRET=your-api-secret-here
91
+ OKX_PASSPHRASE=your-passphrase-here
92
+ OKX_FLAG=1
93
+ ```
94
+
95
+ Then load it in your code:
96
+
97
+ ```python
98
+ import os
99
+ from dotenv import load_dotenv
100
+ from okx import Account
101
+
102
+ load_dotenv()
103
+
104
+ account = Account.AccountAPI(
105
+ api_key=os.getenv('OKX_API_KEY'),
106
+ api_secret_key=os.getenv('OKX_API_SECRET'),
107
+ passphrase=os.getenv('OKX_PASSPHRASE'),
108
+ flag=os.getenv('OKX_FLAG', '1'),
109
+ debug=False
110
+ )
111
+ ```
112
+
113
+ ### Development Setup
114
+
115
+ For contributors or local development:
116
+
117
+ ```bash
118
+ # Clone the repository
119
+ git clone https://github.com/okxapi/python-okx.git
120
+ cd python-okx
121
+
122
+ # Install dependencies
123
+ pip install -r requirements.txt
124
+ pip install -e .
125
+
126
+ # Run tests
127
+ pytest test/unit/ -v
128
+ ```
129
+
58
130
  #### Step 3: Run examples
59
131
 
60
132
  - Fill in API credentials in the corresponding examples
@@ -95,3 +167,5 @@ Note
95
167
  https://github.com/Rapptz/discord.py/issues/1996
96
168
  https://github.com/aaugustin/websockets/issues/587
97
169
  ```
170
+
171
+
@@ -1,34 +1,34 @@
1
- okx/Account.py,sha256=GK31nIOcVfjskr1QT4FM3b3dMuPp8NbKkQViHtJ0ekI,14134
1
+ okx/Account.py,sha256=ms9eNwuKHmYi2Oun4X6LQJ9OcazUPdEn8NfoLtYyFoA,14815
2
2
  okx/BlockTrading.py,sha256=A4OcuLuEHucAIhc8doPGr2o6dsCjVbv-a6YiTlzwdEw,4128
3
3
  okx/Convert.py,sha256=xEB2pwEUpc-k23hA3mYIe3EKB5szIXlEe96JFiRSPpc,1575
4
4
  okx/CopyTrading.py,sha256=Mso5GE9UQTJVrL4V3jIyU1QWBtzr-m32edrGDoRHk84,2751
5
5
  okx/FDBroker.py,sha256=nUpcR_XtUcKa1Jk_B1OUZCjiv9ifQnxGRsLNHDxdGno,788
6
- okx/Funding.py,sha256=JN6A7-uUJ83Y-AtqmBr7JUVHOa0lJtABQTS_lQ-6H7g,5173
7
- okx/Grid.py,sha256=r8cZidY2okqrb-zpyTsFJrecPzw2s25ySH3tOBDnDtA,6691
6
+ okx/Funding.py,sha256=lQcx1JUyebhbQGd978K_LuJUTi52Wi1GjrnI40i9Xrc,5040
7
+ okx/Grid.py,sha256=8rPEjojbyZ_kJdzvHMHVkVTp-xrdUC0SCQ2rmY35rPA,6911
8
8
  okx/MarketData.py,sha256=4GO8Vdkh02GQFJeqC0k4ej3w49wkZroEOoVJ407_ju4,4827
9
- okx/PublicData.py,sha256=HEq4cNCk5P1mhLaMewJhVJTvHm0I2bdrL8Z6pH3yYn0,5136
9
+ okx/PublicData.py,sha256=UIBX9fQRRsOpEa7OMoZbSGy9bPEHCMI3YhGk7pzYlt4,5726
10
10
  okx/SpreadTrading.py,sha256=Dy7VZ8WK4HyxhMvLY1G5RukRHI_T3d0fnrHZifv9Uyw,3227
11
11
  okx/Status.py,sha256=hGnn-tw302xXCDWly7LssaG3-29HcHZRhrBFUuGrSS0,495
12
12
  okx/SubAccount.py,sha256=BcwEzi_Y63k-rS9IffFKAJ2ywVl7o9J0U9sBzg87Lpw,3264
13
- okx/Trade.py,sha256=p1vJcwHZvuYfgKXmaTYZKwtJQ9YtvSZ0arOd8GGAufI,11006
14
- okx/TradingData.py,sha256=ig9Y3f-CH_nyBvoZCF4M9z2_wQXF-r0On7p9EMMuDMo,2331
15
- okx/__init__.py,sha256=aCopTb9QU6OqHWoGo05pHw8Qe-kOja2kjDzFeuEeWg8,58
16
- okx/consts.py,sha256=gUTC2PkhH34Ekct-HA428hJAARPLvcVa5JnAiHkjUGQ,14632
13
+ okx/Trade.py,sha256=FHNxkHWf046YuDpXS94DgA8OWXMJgdPMOEHYxB7GFOE,11981
14
+ 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
17
17
  okx/exceptions.py,sha256=ERuCnvnudJNBNACh3LNE3km5GJy0BGC5C3OKjgHXFaU,1182
18
- okx/okxclient.py,sha256=wJD8gTyHs92WjLffANbWLCgfX4Mnxh-IKnnJ2nUYHsI,2597
19
- okx/utils.py,sha256=FTXSW73yXV6Hc4-9O22WFmkhayASYo7WQHIc_bTyc6g,1858
18
+ okx/okxclient.py,sha256=wywtgB73QelIlsQHFkOcRQsichdpm1n8AlYizB9S_rI,3040
19
+ okx/utils.py,sha256=yMlqB3OF6NDBrz7P6rEmD8PWe2xeqh0Gw8lceUFWy0A,1879
20
20
  okx/Finance/EthStaking.py,sha256=hOl_i4VOBjejeyBboG1-37rhVnlSoOZ44e-Jzger-bQ,1612
21
21
  okx/Finance/FlexibleLoan.py,sha256=L-j1O73fEIIiM_h8NvCT6NocUv6KAx2WEQU6F9GRzIw,2351
22
22
  okx/Finance/Savings.py,sha256=qZbv-KzgGt_me8RZePDSUiRCI1mbz692EK2ZhfYiH8c,1999
23
- okx/Finance/SolStaking.py,sha256=XuGFFonpRpMQkrhNlpyOb644EApb3joQ74PRabN0PTs,1502
23
+ okx/Finance/SolStaking.py,sha256=VcEU4ukbU5bO8qe00DDfFJ0DUIZZS9ZO_-A2evJz5e0,1608
24
24
  okx/Finance/StakingDefi.py,sha256=eWyAAmMDht4B4N5VWf3bj3FxSBETMXaay-Luu4GN3ls,2250
25
25
  okx/Finance/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
26
26
  okx/websocket/WebSocketFactory.py,sha256=ba0ZNUggghZ_YlWYB7g8UCv6MewqVr9wn75YOtIU5kE,845
27
- okx/websocket/WsPrivateAsync.py,sha256=zmZuInowW9_YWpQoZoicbbff-UwWvWxOluKclomNcXA,2240
28
- okx/websocket/WsPublicAsync.py,sha256=yDk_2jkgM4M_sq6zSL6i-KfdoSOaSd5KsmA1wqbIx3E,1520
27
+ okx/websocket/WsPrivateAsync.py,sha256=jq5Imy3hiM3pA7i-uUisGi2R_t9J4h_UOu78mWCv6do,6643
28
+ okx/websocket/WsPublicAsync.py,sha256=e5UXLP0y5ypcdV9YXk39FZqDVvA76H-VS1xWAKXREDs,3920
29
29
  okx/websocket/WsUtils.py,sha256=ynkCtfvkrwBUiCi-_yqp1xTn3hhVd_o5ITIhD1xLdBo,2199
30
30
  okx/websocket/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
31
- python_okx-0.3.9.dist-info/METADATA,sha256=6JjQsztHk5jx5GuNQPngvWPs7J_3jbZUKYcBTtctSbU,3145
32
- python_okx-0.3.9.dist-info/WHEEL,sha256=OVMc5UfuAQiSplgO0_WdW7vXVGAt9Hdd6qtN4HotdyA,91
33
- python_okx-0.3.9.dist-info/top_level.txt,sha256=rrbhHZwiw4YlhG1LWWaAODvRxyZr3onxFnqwsHdikDc,4
34
- python_okx-0.3.9.dist-info/RECORD,,
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,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.2.0)
2
+ Generator: bdist_wheel (0.45.1)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5