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 +23 -9
- okx/Finance/SolStaking.py +3 -0
- okx/Funding.py +7 -6
- okx/Grid.py +6 -2
- okx/PublicData.py +15 -0
- okx/Trade.py +19 -6
- okx/TradingData.py +25 -0
- okx/__init__.py +1 -1
- okx/consts.py +4 -1
- okx/okxclient.py +10 -1
- okx/utils.py +1 -1
- okx/websocket/WsPrivateAsync.py +143 -15
- okx/websocket/WsPublicAsync.py +82 -12
- {python_okx-0.3.9.dist-info → python_okx-0.4.1.dist-info}/METADATA +90 -16
- {python_okx-0.3.9.dist-info → python_okx-0.4.1.dist-info}/RECORD +17 -17
- {python_okx-0.3.9.dist-info → python_okx-0.4.1.dist-info}/WHEEL +1 -1
- {python_okx-0.3.9.dist-info → python_okx-0.4.1.dist-info}/top_level.txt +0 -0
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=
|
|
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['
|
|
38
|
+
params['lever'] = lever
|
|
39
39
|
if greeksType is not None:
|
|
40
|
-
params['
|
|
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
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
|
-
|
|
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
|
|
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
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
|
-
|
|
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
|
|
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
|
okx/websocket/WsPrivateAsync.py
CHANGED
|
@@ -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 =
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
76
|
+
payload_dict = {
|
|
58
77
|
"op": "unsubscribe",
|
|
59
78
|
"args": params
|
|
60
|
-
}
|
|
61
|
-
|
|
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
|
-
|
|
64
|
-
|
|
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
|
-
|
|
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.
|
|
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())
|
okx/websocket/WsPublicAsync.py
CHANGED
|
@@ -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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
75
|
+
payload_dict = {
|
|
39
76
|
"op": "unsubscribe",
|
|
40
77
|
"args": params
|
|
41
|
-
}
|
|
42
|
-
|
|
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
|
-
|
|
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.
|
|
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
|
+
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:
|
|
13
|
-
Requires-Dist:
|
|
14
|
-
Requires-Dist:
|
|
15
|
-
Requires-Dist:
|
|
16
|
-
Requires-Dist:
|
|
17
|
-
Requires-Dist:
|
|
18
|
-
Requires-Dist:
|
|
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.
|
|
56
|
+
`python version:>=3.7`
|
|
45
57
|
|
|
46
|
-
|
|
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:
|
|
62
|
+
#### Step 2: Install python-okx
|
|
53
63
|
|
|
54
|
-
```
|
|
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=
|
|
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=
|
|
7
|
-
okx/Grid.py,sha256=
|
|
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=
|
|
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=
|
|
14
|
-
okx/TradingData.py,sha256=
|
|
15
|
-
okx/__init__.py,sha256=
|
|
16
|
-
okx/consts.py,sha256=
|
|
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=
|
|
19
|
-
okx/utils.py,sha256=
|
|
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=
|
|
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=
|
|
28
|
-
okx/websocket/WsPublicAsync.py,sha256=
|
|
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.
|
|
32
|
-
python_okx-0.
|
|
33
|
-
python_okx-0.
|
|
34
|
-
python_okx-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,,
|
|
File without changes
|