From 7a4fa53efd11975570d3dea368cc0697a200235f Mon Sep 17 00:00:00 2001 From: "jason.hsu" Date: Tue, 16 Dec 2025 10:26:08 +0800 Subject: [PATCH 1/6] feat: add idxVol and fix wrong params for posBuilder --- okx/Account.py | 8 +++++--- test/__init__.py | 0 2 files changed, 5 insertions(+), 3 deletions(-) create mode 100644 test/__init__.py diff --git a/okx/Account.py b/okx/Account.py index 911cf9b..8de8532 100644 --- a/okx/Account.py +++ b/okx/Account.py @@ -28,20 +28,22 @@ def get_positions(self, instType='', instId='', posId=''): return self._request_with_params(GET, POSITION_INFO, params) def position_builder(self, acctLv=None,inclRealPosAndEq=False, lever=None, greeksType=None, simPos=None, - simAsset=None): + simAsset=None, idxVol=None): params = {} if acctLv is not None: params['acctLv'] = acctLv if inclRealPosAndEq is not None: params['inclRealPosAndEq'] = inclRealPosAndEq if lever is not None: - params['spotOffsetType'] = lever + params['lever'] = lever if greeksType is not None: - params['greksType'] = greeksType + params['greeksType'] = greeksType if simPos is not None: params['simPos'] = simPos if simAsset is not None: params['simAsset'] = simAsset + if idxVol is not None: + params['idxVol'] = idxVol return self._request_with_params(POST, POSITION_BUILDER, params) # Get Bills Details (recent 7 days) diff --git a/test/__init__.py b/test/__init__.py new file mode 100644 index 0000000..e69de29 From f8847a91dd455775bfe9f2497c8c5160da209f8c Mon Sep 17 00:00:00 2001 From: "jason.hsu" Date: Tue, 16 Dec 2025 10:55:37 +0800 Subject: [PATCH 2/6] feat: add unit-testing for the test_account --- okx/Account.py | 2 +- test/unit/__init__.py | 10 + test/unit/okx/__init__.py | 2 + test/unit/okx/test_account.py | 441 ++++++++++++++++++++++++++++++++++ 4 files changed, 454 insertions(+), 1 deletion(-) create mode 100644 test/unit/__init__.py create mode 100644 test/unit/okx/__init__.py create mode 100644 test/unit/okx/test_account.py diff --git a/okx/Account.py b/okx/Account.py index 8de8532..e3952ff 100644 --- a/okx/Account.py +++ b/okx/Account.py @@ -27,7 +27,7 @@ def get_positions(self, instType='', instId='', posId=''): params = {'instType': instType, 'instId': instId, 'posId': posId} return self._request_with_params(GET, POSITION_INFO, params) - def position_builder(self, acctLv=None,inclRealPosAndEq=False, lever=None, greeksType=None, simPos=None, + def position_builder(self, acctLv=None, inclRealPosAndEq=None, lever=None, greeksType=None, simPos=None, simAsset=None, idxVol=None): params = {} if acctLv is not None: diff --git a/test/unit/__init__.py b/test/unit/__init__.py new file mode 100644 index 0000000..940cd5e --- /dev/null +++ b/test/unit/__init__.py @@ -0,0 +1,10 @@ +""" +Unit tests package + +Unit tests mirror the source code structure for easy navigation. + +Example: + okx/Account.py -> test/unit/okx/test_account.py + okx/Trade.py -> test/unit/okx/test_trade.py + okx/Finance/Savings.py -> test/unit/okx/Finance/test_savings.py +""" diff --git a/test/unit/okx/__init__.py b/test/unit/okx/__init__.py new file mode 100644 index 0000000..2b43621 --- /dev/null +++ b/test/unit/okx/__init__.py @@ -0,0 +1,2 @@ +"""Unit tests for okx package""" + diff --git a/test/unit/okx/test_account.py b/test/unit/okx/test_account.py new file mode 100644 index 0000000..6e5f0c4 --- /dev/null +++ b/test/unit/okx/test_account.py @@ -0,0 +1,441 @@ +""" +Unit tests for okx.Account module + +Mirrors the structure: okx/Account.py -> test/unit/okx/test_account.py +""" +import unittest +from unittest.mock import patch +from okx.Account import AccountAPI +from okx import consts as c + + +class TestAccountAPIPositionBuilder(unittest.TestCase): + """Unit tests for the position_builder method""" + + def setUp(self): + """Set up test fixtures""" + self.api_key = 'test_api_key' + self.api_secret = 'test_api_secret' + self.passphrase = 'test_passphrase' + self.account_api = AccountAPI( + api_key=self.api_key, + api_secret_key=self.api_secret, + passphrase=self.passphrase, + flag='0' + ) + + @patch.object(AccountAPI, '_request_with_params') + def test_position_builder_with_all_parameters(self, mock_request): + """Test position_builder with all parameters provided""" + # Arrange + mock_response = { + 'code': '0', + 'msg': '', + 'data': [{ + 'mmr': '1000', + 'imr': '2000', + 'mmrBf': '900', + 'imrBf': '1900' + }] + } + mock_request.return_value = mock_response + + sim_pos = [{'instId': 'BTC-USDT-SWAP', 'pos': '10', 'avgPx': '50000'}] + sim_asset = [{'ccy': 'USDT', 'amt': '10000'}] + + # Act + result = self.account_api.position_builder( + acctLv='2', + inclRealPosAndEq=True, + lever='5', + greeksType='PA', + simPos=sim_pos, + simAsset=sim_asset, + idxVol='0.05' + ) + + # Assert + expected_params = { + 'acctLv': '2', + 'inclRealPosAndEq': True, + 'lever': '5', + 'greeksType': 'PA', + 'simPos': sim_pos, + 'simAsset': sim_asset, + 'idxVol': '0.05' + } + mock_request.assert_called_once_with(c.POST, c.POSITION_BUILDER, expected_params) + self.assertEqual(result, mock_response) + + @patch.object(AccountAPI, '_request_with_params') + def test_position_builder_with_idxVol_only(self, mock_request): + """Test position_builder with only idxVol parameter""" + # Arrange + mock_response = { + 'code': '0', + 'msg': '', + 'data': [] + } + mock_request.return_value = mock_response + + # Act + result = self.account_api.position_builder(idxVol='0.1') + + # Assert + expected_params = { + 'idxVol': '0.1' + } + mock_request.assert_called_once_with(c.POST, c.POSITION_BUILDER, expected_params) + self.assertEqual(result, mock_response) + + @patch.object(AccountAPI, '_request_with_params') + def test_position_builder_negative_idxVol(self, mock_request): + """Test position_builder with negative idxVol (price decrease)""" + # Arrange + mock_response = { + 'code': '0', + 'msg': '', + 'data': [] + } + mock_request.return_value = mock_response + + # Act + result = self.account_api.position_builder(idxVol='-0.05') + + # Assert + expected_params = { + 'idxVol': '-0.05' + } + mock_request.assert_called_once_with(c.POST, c.POSITION_BUILDER, expected_params) + self.assertEqual(result, mock_response) + + @patch.object(AccountAPI, '_request_with_params') + def test_position_builder_with_no_parameters(self, mock_request): + """Test position_builder with no parameters (all None)""" + # Arrange + mock_response = { + 'code': '0', + 'msg': '', + 'data': [] + } + mock_request.return_value = mock_response + + # Act + result = self.account_api.position_builder() + + # Assert + # Should pass empty params dict + mock_request.assert_called_once_with(c.POST, c.POSITION_BUILDER, {}) + self.assertEqual(result, mock_response) + + @patch.object(AccountAPI, '_request_with_params') + def test_position_builder_with_simulated_positions(self, mock_request): + """Test position_builder with simulated positions and assets""" + # Arrange + mock_response = { + 'code': '0', + 'msg': '', + 'data': [{ + 'mmr': '5000', + 'imr': '10000' + }] + } + mock_request.return_value = mock_response + + sim_pos = [ + {'instId': 'BTC-USDT-SWAP', 'pos': '10', 'avgPx': '50000'}, + {'instId': 'ETH-USDT-SWAP', 'pos': '100', 'avgPx': '3000'} + ] + sim_asset = [ + {'ccy': 'USDT', 'amt': '100000'}, + {'ccy': 'BTC', 'amt': '1'} + ] + + # Act + result = self.account_api.position_builder( + inclRealPosAndEq=False, + simPos=sim_pos, + simAsset=sim_asset, + idxVol='0.1' + ) + + # Assert + expected_params = { + 'inclRealPosAndEq': False, + 'simPos': sim_pos, + 'simAsset': sim_asset, + 'idxVol': '0.1' + } + mock_request.assert_called_once_with(c.POST, c.POSITION_BUILDER, expected_params) + self.assertEqual(result, mock_response) + + @patch.object(AccountAPI, '_request_with_params') + def test_position_builder_greeks_type_pa(self, mock_request): + """Test position_builder with greeksType PA""" + # Arrange + mock_response = {'code': '0', 'msg': '', 'data': []} + mock_request.return_value = mock_response + + # Act + result = self.account_api.position_builder(greeksType='PA') + + # Assert + expected_params = {'greeksType': 'PA'} + mock_request.assert_called_once_with(c.POST, c.POSITION_BUILDER, expected_params) + + @patch.object(AccountAPI, '_request_with_params') + def test_position_builder_greeks_type_bs(self, mock_request): + """Test position_builder with greeksType BS""" + # Arrange + mock_response = {'code': '0', 'msg': '', 'data': []} + mock_request.return_value = mock_response + + # Act + result = self.account_api.position_builder(greeksType='BS') + + # Assert + expected_params = {'greeksType': 'BS'} + mock_request.assert_called_once_with(c.POST, c.POSITION_BUILDER, expected_params) + + @patch.object(AccountAPI, '_request_with_params') + def test_position_builder_includes_real_positions(self, mock_request): + """Test position_builder with inclRealPosAndEq=True""" + # Arrange + mock_response = {'code': '0', 'msg': '', 'data': []} + mock_request.return_value = mock_response + + # Act + result = self.account_api.position_builder( + inclRealPosAndEq=True, + idxVol='0.05' + ) + + # Assert + expected_params = { + 'inclRealPosAndEq': True, + 'idxVol': '0.05' + } + mock_request.assert_called_once_with(c.POST, c.POSITION_BUILDER, expected_params) + + @patch.object(AccountAPI, '_request_with_params') + def test_position_builder_excludes_real_positions(self, mock_request): + """Test position_builder with inclRealPosAndEq=False (only virtual positions)""" + # Arrange + mock_response = {'code': '0', 'msg': '', 'data': []} + mock_request.return_value = mock_response + + sim_pos = [{'instId': 'BTC-USDT-SWAP', 'pos': '5', 'avgPx': '60000'}] + + # Act + result = self.account_api.position_builder( + inclRealPosAndEq=False, + simPos=sim_pos + ) + + # Assert + expected_params = { + 'inclRealPosAndEq': False, + 'simPos': sim_pos + } + mock_request.assert_called_once_with(c.POST, c.POSITION_BUILDER, expected_params) + + @patch.object(AccountAPI, '_request_with_params') + def test_position_builder_with_account_level(self, mock_request): + """Test position_builder with specific account level""" + # Arrange + mock_response = {'code': '0', 'msg': '', 'data': []} + mock_request.return_value = mock_response + + # Act + result = self.account_api.position_builder(acctLv='3') + + # Assert + expected_params = {'acctLv': '3'} + mock_request.assert_called_once_with(c.POST, c.POSITION_BUILDER, expected_params) + + @patch.object(AccountAPI, '_request_with_params') + def test_position_builder_with_leverage(self, mock_request): + """Test position_builder with leverage parameter""" + # Arrange + mock_response = {'code': '0', 'msg': '', 'data': []} + mock_request.return_value = mock_response + + # Act + result = self.account_api.position_builder(lever='10') + + # Assert + expected_params = {'lever': '10'} + mock_request.assert_called_once_with(c.POST, c.POSITION_BUILDER, expected_params) + + @patch.object(AccountAPI, '_request_with_params') + def test_position_builder_extreme_volatility_positive(self, mock_request): + """Test position_builder with maximum positive volatility""" + # Arrange + mock_response = {'code': '0', 'msg': '', 'data': []} + mock_request.return_value = mock_response + + # Act + result = self.account_api.position_builder(idxVol='1') + + # Assert + expected_params = {'idxVol': '1'} + mock_request.assert_called_once_with(c.POST, c.POSITION_BUILDER, expected_params) + + @patch.object(AccountAPI, '_request_with_params') + def test_position_builder_extreme_volatility_negative(self, mock_request): + """Test position_builder with maximum negative volatility""" + # Arrange + mock_response = {'code': '0', 'msg': '', 'data': []} + mock_request.return_value = mock_response + + # Act + result = self.account_api.position_builder(idxVol='-0.99') + + # Assert + expected_params = {'idxVol': '-0.99'} + mock_request.assert_called_once_with(c.POST, c.POSITION_BUILDER, expected_params) + + @patch.object(AccountAPI, '_request_with_params') + def test_position_builder_complex_scenario(self, mock_request): + """Test position_builder with a complex realistic scenario""" + # Arrange + mock_response = { + 'code': '0', + 'msg': '', + 'data': [{ + 'mmr': '15000', + 'imr': '30000', + 'mmrBf': '14000', + 'imrBf': '28000', + 'markPxBf': '49500' + }] + } + mock_request.return_value = mock_response + + sim_pos = [ + {'instId': 'BTC-USDT-SWAP', 'pos': '10', 'avgPx': '50000'}, + {'instId': 'ETH-USDT-SWAP', 'pos': '-50', 'avgPx': '3000'} + ] + sim_asset = [{'ccy': 'USDT', 'amt': '50000'}] + + # Act - Simulate a 5% market drop + result = self.account_api.position_builder( + acctLv='2', + inclRealPosAndEq=False, + lever='5', + greeksType='PA', + simPos=sim_pos, + simAsset=sim_asset, + idxVol='-0.05' + ) + + # Assert + expected_params = { + 'acctLv': '2', + 'inclRealPosAndEq': False, + 'lever': '5', + 'greeksType': 'PA', + 'simPos': sim_pos, + 'simAsset': sim_asset, + 'idxVol': '-0.05' + } + mock_request.assert_called_once_with(c.POST, c.POSITION_BUILDER, expected_params) + self.assertEqual(result['code'], '0') + self.assertIn('mmrBf', result['data'][0]) + self.assertIn('imrBf', result['data'][0]) + + +class TestAccountAPIPositionBuilderParameterHandling(unittest.TestCase): + """Test parameter handling and edge cases""" + + def setUp(self): + """Set up test fixtures""" + self.account_api = AccountAPI( + api_key='test_key', + api_secret_key='test_secret', + passphrase='test_pass', + flag='0' + ) + + @patch.object(AccountAPI, '_request_with_params') + def test_none_parameters_are_excluded(self, mock_request): + """Test that None parameters are not included in the request""" + # Arrange + mock_response = {'code': '0', 'msg': '', 'data': []} + mock_request.return_value = mock_response + + # Act + result = self.account_api.position_builder( + acctLv='2', + inclRealPosAndEq=None, # Should be excluded + lever=None, # Should be excluded + greeksType='PA', + simPos=None, # Should be excluded + simAsset=None, # Should be excluded + idxVol='0.05' + ) + + # Assert - Only non-None params should be in the call + expected_params = { + 'acctLv': '2', + 'greeksType': 'PA', + 'idxVol': '0.05' + } + mock_request.assert_called_once_with(c.POST, c.POSITION_BUILDER, expected_params) + + @patch.object(AccountAPI, '_request_with_params') + def test_false_value_for_inclRealPosAndEq_is_included(self, mock_request): + """Test that False value for inclRealPosAndEq is included (not treated as None)""" + # Arrange + mock_response = {'code': '0', 'msg': '', 'data': []} + mock_request.return_value = mock_response + + # Act + result = self.account_api.position_builder(inclRealPosAndEq=False) + + # Assert - False should be included + expected_params = { + 'inclRealPosAndEq': False + } + mock_request.assert_called_once_with(c.POST, c.POSITION_BUILDER, expected_params) + + @patch.object(AccountAPI, '_request_with_params') + def test_empty_lists_are_included(self, mock_request): + """Test that empty lists are included in the request""" + # Arrange + mock_response = {'code': '0', 'msg': '', 'data': []} + mock_request.return_value = mock_response + + # Act + result = self.account_api.position_builder( + simPos=[], + simAsset=[] + ) + + # Assert + expected_params = { + 'simPos': [], + 'simAsset': [] + } + mock_request.assert_called_once_with(c.POST, c.POSITION_BUILDER, expected_params) + + @patch.object(AccountAPI, '_request_with_params') + def test_zero_idxVol_is_included(self, mock_request): + """Test that zero idxVol is included (represents no volatility change)""" + # Arrange + mock_response = {'code': '0', 'msg': '', 'data': []} + mock_request.return_value = mock_response + + # Act + result = self.account_api.position_builder(idxVol='0') + + # Assert + expected_params = { + 'idxVol': '0' + } + mock_request.assert_called_once_with(c.POST, c.POSITION_BUILDER, expected_params) + + +if __name__ == '__main__': + unittest.main() + From e8084271d1b8c7a092a272b47271ca73e2475027 Mon Sep 17 00:00:00 2001 From: "jason.hsu" Date: Fri, 19 Dec 2025 16:56:48 +0800 Subject: [PATCH 3/6] feat: add api changes --- okx/Account.py | 4 +++- okx/Grid.py | 8 ++++++-- okx/Trade.py | 26 +++++++++++++++++++------- 3 files changed, 28 insertions(+), 10 deletions(-) diff --git a/okx/Account.py b/okx/Account.py index e3952ff..d280013 100644 --- a/okx/Account.py +++ b/okx/Account.py @@ -102,8 +102,10 @@ def get_instruments(self, instType='', ugly='', instFamily='', instId=''): return self._request_with_params(GET, GET_INSTRUMENTS, params) # Get the maximum loan of isolated MARGIN - def get_max_loan(self, instId, mgnMode, mgnCcy=''): + def get_max_loan(self, instId, mgnMode, mgnCcy='', tradeQuoteCcy=None): params = {'instId': instId, 'mgnMode': mgnMode, 'mgnCcy': mgnCcy} + if tradeQuoteCcy is not None: + params['tradeQuoteCcy'] = tradeQuoteCcy return self._request_with_params(GET, MAX_LOAN, params) # Get Fee Rates diff --git a/okx/Grid.py b/okx/Grid.py index 74b6a9b..d761708 100644 --- a/okx/Grid.py +++ b/okx/Grid.py @@ -7,11 +7,13 @@ def __init__(self, api_key='-1', api_secret_key='-1', passphrase='-1', use_serve OkxClient.__init__(self, api_key, api_secret_key, passphrase, use_server_time, flag, domain, debug, proxy) def grid_order_algo(self, instId='', algoOrdType='', maxPx='', minPx='', gridNum='', runType='', tpTriggerPx='', - slTriggerPx='', tag='', quoteSz='', baseSz='', sz='', direction='', lever='', basePos=''): + slTriggerPx='', tag='', quoteSz='', baseSz='', sz='', direction='', lever='', basePos='', tradeQuoteCcy=None): params = {'instId': instId, 'algoOrdType': algoOrdType, 'maxPx': maxPx, 'minPx': minPx, 'gridNum': gridNum, 'runType': runType, 'tpTriggerPx': tpTriggerPx, 'slTriggerPx': slTriggerPx, 'tag': tag, 'quoteSz': quoteSz, 'baseSz': baseSz, 'sz': sz, 'direction': direction, 'lever': lever, 'basePos': basePos} + if tradeQuoteCcy is not None: + params['tradeQuoteCcy'] = tradeQuoteCcy return self._request_with_params(POST, GRID_ORDER_ALGO, params) def grid_amend_order_algo(self, algoId='', instId='', slTriggerPx='', tpTriggerPx=''): @@ -79,11 +81,13 @@ def grid_ai_param(self, algoOrdType='', instId='', direction='', duration=''): # - Place recurring buy order def place_recurring_buy_order(self, stgyName='', recurringList=[], period='', recurringDay='', recurringTime='', - timeZone='', amt='', investmentCcy='', tdMode='', algoClOrdId='', tag=''): + timeZone='', amt='', investmentCcy='', tdMode='', algoClOrdId='', tag='', tradeQuoteCcy=None): params = {'stgyName': stgyName, 'recurringList': recurringList, 'period': period, 'recurringDay': recurringDay, 'recurringTime': recurringTime, 'timeZone': timeZone, 'amt': amt, 'investmentCcy': investmentCcy, 'tdMode': tdMode, 'algoClOrdId': algoClOrdId, 'tag': tag} + if tradeQuoteCcy is not None: + params['tradeQuoteCcy'] = tradeQuoteCcy return self._request_with_params(POST, PLACE_RECURRING_BUY_ORDER, params) # - Amend recurring buy order diff --git a/okx/Trade.py b/okx/Trade.py index db994ae..a975dbb 100644 --- a/okx/Trade.py +++ b/okx/Trade.py @@ -12,10 +12,14 @@ def __init__(self, api_key='-1', api_secret_key='-1', passphrase='-1', use_serve # Place Order def place_order(self, instId, tdMode, side, ordType, sz, ccy='', clOrdId='', tag='', posSide='', px='', - reduceOnly='', tgtCcy='', stpMode='', attachAlgoOrds=None, pxUsd='', pxVol='', banAmend='', tradeQuoteCcy=''): + reduceOnly='', tgtCcy='', stpMode='', attachAlgoOrds=None, pxUsd='', pxVol='', banAmend='', tradeQuoteCcy=None, pxAmendType=None): params = {'instId': instId, 'tdMode': tdMode, 'side': side, 'ordType': ordType, 'sz': sz, 'ccy': ccy, 'clOrdId': clOrdId, 'tag': tag, 'posSide': posSide, 'px': px, 'reduceOnly': reduceOnly, - 'tgtCcy': tgtCcy, 'stpMode': stpMode, 'pxUsd': pxUsd, 'pxVol': pxVol, 'banAmend': banAmend, 'tradeQuoteCcy': tradeQuoteCcy} + 'tgtCcy': tgtCcy, 'stpMode': stpMode, 'pxUsd': pxUsd, 'pxVol': pxVol, 'banAmend': banAmend} + if tradeQuoteCcy is not None: + params['tradeQuoteCcy'] = tradeQuoteCcy + if pxAmendType is not None: + params['pxAmendType'] = pxAmendType params['attachAlgoOrds'] = attachAlgoOrds return self._request_with_params(POST, PLACR_ORDER, params) @@ -35,11 +39,13 @@ def cancel_multiple_orders(self, orders_data): # Amend Order def amend_order(self, instId, cxlOnFail='', ordId='', clOrdId='', reqId='', newSz='', newPx='', newTpTriggerPx='', newTpOrdPx='', newSlTriggerPx='', newSlOrdPx='', newTpTriggerPxType='', newSlTriggerPxType='', - attachAlgoOrds='', newTriggerPx='', newOrdPx=''): + attachAlgoOrds='', newTriggerPx='', newOrdPx='', pxAmendType=None): params = {'instId': instId, 'cxlOnFail': cxlOnFail, 'ordId': ordId, 'clOrdId': clOrdId, 'reqId': reqId, 'newSz': newSz, 'newPx': newPx, 'newTpTriggerPx': newTpTriggerPx, 'newTpOrdPx': newTpOrdPx, 'newSlTriggerPx': newSlTriggerPx, 'newSlOrdPx': newSlOrdPx, 'newTpTriggerPxType': newTpTriggerPxType, 'newSlTriggerPxType': newSlTriggerPxType, 'newTriggerPx': newTriggerPx, 'newOrdPx': newOrdPx} + if pxAmendType is not None: + params['pxAmendType'] = pxAmendType params['attachAlgoOrds'] = attachAlgoOrds return self._request_with_params(POST, AMEND_ORDER, params) @@ -95,8 +101,8 @@ def place_algo_order(self, instId='', tdMode='', side='', ordType='', sz='', ccy pxSpread='', szLimit='', pxLimit='', timeInterval='', tpTriggerPxType='', slTriggerPxType='', callbackRatio='', callbackSpread='', activePx='', tag='', triggerPxType='', closeFraction='' - , quickMgnType='', algoClOrdId='', tradeQuoteCcy='', tpOrdKind='', cxlOnClosePos='' - , chaseType='', chaseVal='', maxChaseType='', maxChaseVal='', attachAlgoOrds=[]): + , quickMgnType='', algoClOrdId='', tradeQuoteCcy=None, tpOrdKind='', cxlOnClosePos='' + , chaseType='', chaseVal='', maxChaseType='', maxChaseVal='', attachAlgoOrds=[], pxAmendType=None): params = {'instId': instId, 'tdMode': tdMode, 'side': side, 'ordType': ordType, 'sz': sz, 'ccy': ccy, 'posSide': posSide, 'reduceOnly': reduceOnly, 'tpTriggerPx': tpTriggerPx, 'tpOrdPx': tpOrdPx, 'slTriggerPx': slTriggerPx, 'slOrdPx': slOrdPx, 'triggerPx': triggerPx, 'orderPx': orderPx, @@ -105,9 +111,13 @@ def place_algo_order(self, instId='', tdMode='', side='', ordType='', sz='', ccy 'pxSpread': pxSpread, 'tpTriggerPxType': tpTriggerPxType, 'slTriggerPxType': slTriggerPxType, 'callbackRatio': callbackRatio, 'callbackSpread': callbackSpread, 'activePx': activePx, 'tag': tag, 'triggerPxType': triggerPxType, 'closeFraction': closeFraction, - 'quickMgnType': quickMgnType, 'algoClOrdId': algoClOrdId, 'tradeQuoteCcy': tradeQuoteCcy, + 'quickMgnType': quickMgnType, 'algoClOrdId': algoClOrdId, 'tpOrdKind': tpOrdKind, 'cxlOnClosePos': cxlOnClosePos, 'chaseType': chaseType, 'chaseVal': chaseVal, 'maxChaseType': maxChaseType, 'maxChaseVal': maxChaseVal, 'attachAlgoOrds': attachAlgoOrds} + if tradeQuoteCcy is not None: + params['tradeQuoteCcy'] = tradeQuoteCcy + if pxAmendType is not None: + params['pxAmendType'] = pxAmendType return self._request_with_params(POST, PLACE_ALGO_ORDER, params) # Cancel Algo Order @@ -179,11 +189,13 @@ def get_algo_order_details(self, algoId='', algoClOrdId=''): # Amend algo order def amend_algo_order(self, instId='', algoId='', algoClOrdId='', cxlOnFail='', reqId='', newSz='', newTriggerPx='', newOrdPx='', newTpTriggerPx='', newTpOrdPx='', newSlTriggerPx='', newSlOrdPx='', newTpTriggerPxType='', - newSlTriggerPxType=''): + newSlTriggerPxType='', pxAmendType=None): params = {'instId': instId, 'algoId': algoId, 'algoClOrdId': algoClOrdId, 'cxlOnFail': cxlOnFail, 'reqId': reqId, 'newSz': newSz, 'newTriggerPx': newTriggerPx, 'newOrdPx': newOrdPx, 'newTpTriggerPx': newTpTriggerPx, 'newTpOrdPx': newTpOrdPx, 'newSlTriggerPx': newSlTriggerPx, 'newSlOrdPx': newSlOrdPx, 'newTpTriggerPxType': newTpTriggerPxType, 'newSlTriggerPxType': newSlTriggerPxType} + if pxAmendType is not None: + params['pxAmendType'] = pxAmendType return self._request_with_params(POST, AMEND_ALGO_ORDER, params) def get_oneclick_repay_list_v2(self): From 75a20fc4eb115843420c116b708a8c56c4cdde61 Mon Sep 17 00:00:00 2001 From: "jason.hsu" Date: Fri, 19 Dec 2025 19:05:39 +0800 Subject: [PATCH 4/6] feat: add .env --- .env.example | 10 ++++++ .gitignore | 7 +++- test/config.py | 35 +++++++++++++++++++ test/{AccountTest.py => test_account.py} | 7 ++-- ...ckTradingTest.py => test_block_trading.py} | 9 ++--- test/{ConvertTest.py => test_convert.py} | 11 +++--- ...opyTradingTest.py => test_copy_trading.py} | 8 ++--- ...{EthStakingTest.py => test_eth_staking.py} | 8 ++--- ...xibleLoanTest.py => test_flexible_loan.py} | 8 ++--- test/{FundingTest.py => test_funding.py} | 8 ++--- test/{GridTest.py => test_grid.py} | 8 ++--- test/{MarketTest.py => test_market.py} | 9 ++--- ...{PublicDataTest.py => test_public_data.py} | 9 ++--- test/{SavingsTest.py => test_savings.py} | 8 ++--- ...{SolStakingTest.py => test_sol_staking.py} | 8 ++--- test/{SpreadTest.py => test_spread.py} | 9 ++--- ...takingDefiTest.py => test_staking_defi.py} | 7 ++-- ...{SubAccountTest.py => test_sub_account.py} | 8 ++--- test/{TradeTest.py => test_trade.py} | 7 ++-- ...radingDataTest.py => test_trading_data.py} | 9 +++-- ...eAsyncTest.py => test_ws_private_async.py} | 8 +++-- ...icAsyncTest.py => test_ws_public_async.py} | 0 22 files changed, 127 insertions(+), 74 deletions(-) create mode 100644 .env.example create mode 100644 test/config.py rename test/{AccountTest.py => test_account.py} (98%) rename test/{BlockTradingTest.py => test_block_trading.py} (93%) rename test/{ConvertTest.py => test_convert.py} (83%) rename test/{CopyTradingTest.py => test_copy_trading.py} (88%) rename test/{EthStakingTest.py => test_eth_staking.py} (82%) rename test/{FlexibleLoanTest.py => test_flexible_loan.py} (84%) rename test/{FundingTest.py => test_funding.py} (95%) rename test/{GridTest.py => test_grid.py} (95%) rename test/{MarketTest.py => test_market.py} (93%) rename test/{PublicDataTest.py => test_public_data.py} (95%) rename test/{SavingsTest.py => test_savings.py} (84%) rename test/{SolStakingTest.py => test_sol_staking.py} (82%) rename test/{SpreadTest.py => test_spread.py} (91%) rename test/{StakingDefiTest.py => test_staking_defi.py} (82%) rename test/{SubAccountTest.py => test_sub_account.py} (92%) rename test/{TradeTest.py => test_trade.py} (98%) rename test/{TradingDataTest.py => test_trading_data.py} (86%) rename test/{WsPrivateAsyncTest.py => test_ws_private_async.py} (88%) rename test/{WsPublicAsyncTest.py => test_ws_public_async.py} (100%) diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..0f777f4 --- /dev/null +++ b/.env.example @@ -0,0 +1,10 @@ +# OKX API Credentials +# Copy this file to .env and fill in your actual credentials +# NEVER commit .env to version control! + +OKX_API_KEY=your_api_key_here +OKX_API_SECRET=your_api_secret_here +OKX_PASSPHRASE=your_passphrase_here + +# Optional: Set to '0' for live trading, '1' for demo trading +OKX_FLAG=1 diff --git a/.gitignore b/.gitignore index 10c5a42..41c5c7c 100644 --- a/.gitignore +++ b/.gitignore @@ -32,4 +32,9 @@ build/ ### VS Code ### .vscode/ -id_rsa* \ No newline at end of file +id_rsa* + +# Environment files +.env +.env.local +.env.*.local \ No newline at end of file diff --git a/test/config.py b/test/config.py new file mode 100644 index 0000000..090e7e8 --- /dev/null +++ b/test/config.py @@ -0,0 +1,35 @@ +""" +Test configuration module - loads API credentials from environment variables. + +Usage: + from test.config import get_api_credentials + + api_key, api_secret, passphrase, flag = get_api_credentials() +""" +import os +from pathlib import Path + +# Try to load from .env file if python-dotenv is available +try: + from dotenv import load_dotenv + # Load .env from project root + env_path = Path(__file__).parent.parent / '.env' + load_dotenv(env_path) +except ImportError: + pass # python-dotenv not installed, rely on system environment variables + + +def get_api_credentials(): + """ + Get API credentials from environment variables. + + Returns: + tuple: (api_key, api_secret, passphrase, flag) + """ + api_key = os.getenv('OKX_API_KEY', '') + api_secret = os.getenv('OKX_API_SECRET', '') + passphrase = os.getenv('OKX_PASSPHRASE', '') + flag = os.getenv('OKX_FLAG', '1') # Default to demo trading + + return api_key, api_secret, passphrase, flag + diff --git a/test/AccountTest.py b/test/test_account.py similarity index 98% rename from test/AccountTest.py rename to test/test_account.py index 14793d0..50b5493 100644 --- a/test/AccountTest.py +++ b/test/test_account.py @@ -3,14 +3,13 @@ from loguru import logger from okx import Account +from test.config import get_api_credentials class AccountTest(unittest.TestCase): def setUp(self): - api_key = 'your_apiKey' - api_secret_key = 'your_secretKey' - passphrase = 'your_secretKey' - self.AccountAPI = Account.AccountAPI(api_key, api_secret_key, passphrase, flag='1') + api_key, api_secret_key, passphrase, flag = get_api_credentials() + self.AccountAPI = Account.AccountAPI(api_key, api_secret_key, passphrase, flag=flag) # ''' # POSITIONS_HISTORY = '/api/v5/account/positions-history' #need add diff --git a/test/BlockTradingTest.py b/test/test_block_trading.py similarity index 93% rename from test/BlockTradingTest.py rename to test/test_block_trading.py index e8b0e88..1c02542 100644 --- a/test/BlockTradingTest.py +++ b/test/test_block_trading.py @@ -1,12 +1,13 @@ import unittest from okx import BlockTrading +from test.config import get_api_credentials + + class BlockTradingTest(unittest.TestCase): def setUp(self): - api_key = 'your_apiKey' - api_secret_key = 'your_secretKey' - passphrase = 'your_secretKey' - self.BlockTradingAPI = BlockTrading.BlockTradingAPI(api_key, api_secret_key, passphrase, use_server_time=False, flag='1') + api_key, api_secret_key, passphrase, flag = get_api_credentials() + self.BlockTradingAPI = BlockTrading.BlockTradingAPI(api_key, api_secret_key, passphrase, use_server_time=False, flag=flag) """ def test_get_counter_parties(self): diff --git a/test/ConvertTest.py b/test/test_convert.py similarity index 83% rename from test/ConvertTest.py rename to test/test_convert.py index aa1d175..fc1f048 100644 --- a/test/ConvertTest.py +++ b/test/test_convert.py @@ -1,11 +1,12 @@ import unittest -from ..okx import Convert +from okx import Convert +from test.config import get_api_credentials + + class ConvertTest(unittest.TestCase): def setUp(self): - api_key = 'your_apiKey' - api_secret_key = 'your_secretKey' - passphrase = 'your_secretKey' - self.ConvertAPI = Convert.ConvertAPI(api_key, api_secret_key, passphrase, use_server_time=False, flag='1') + api_key, api_secret_key, passphrase, flag = get_api_credentials() + self.ConvertAPI = Convert.ConvertAPI(api_key, api_secret_key, passphrase, use_server_time=False, flag=flag) ''' def test_get_currencies(self): diff --git a/test/CopyTradingTest.py b/test/test_copy_trading.py similarity index 88% rename from test/CopyTradingTest.py rename to test/test_copy_trading.py index 95c1739..b516bc5 100644 --- a/test/CopyTradingTest.py +++ b/test/test_copy_trading.py @@ -1,13 +1,13 @@ import unittest from okx import CopyTrading +from test.config import get_api_credentials + class CopyTradingTest(unittest.TestCase): def setUp(self): - api_key = 'your_apiKey' - api_secret_key = 'your_secretKey' - passphrase = 'your_secretKey' + api_key, api_secret_key, passphrase, flag = get_api_credentials() self.StackingAPI = CopyTrading.CopyTradingAPI(api_key, api_secret_key, passphrase, use_server_time=False, - flag='0') + flag=flag) # def test_get_existing_leading_positions(self): # print(self.StackingAPI.get_existing_leading_positions(instId='DOGE-USDT-SWAP')) diff --git a/test/EthStakingTest.py b/test/test_eth_staking.py similarity index 82% rename from test/EthStakingTest.py rename to test/test_eth_staking.py index 3be4860..f280d1d 100644 --- a/test/EthStakingTest.py +++ b/test/test_eth_staking.py @@ -1,12 +1,12 @@ import unittest from okx.Finance import EthStaking +from test.config import get_api_credentials + class EthStakingTest(unittest.TestCase): def setUp(self): - api_key = 'your_apiKey' - api_secret_key = 'your_secretKey' - passphrase = 'your_secretKey' - self.StackingAPI = EthStaking.EthStakingAPI(api_key, api_secret_key, passphrase, use_server_time=False, flag='1') + api_key, api_secret_key, passphrase, flag = get_api_credentials() + self.StackingAPI = EthStaking.EthStakingAPI(api_key, api_secret_key, passphrase, use_server_time=False, flag=flag) def test_eth_product_info(self): print(self.StackingAPI.eth_product_info()) diff --git a/test/FlexibleLoanTest.py b/test/test_flexible_loan.py similarity index 84% rename from test/FlexibleLoanTest.py rename to test/test_flexible_loan.py index b4320a5..517b194 100644 --- a/test/FlexibleLoanTest.py +++ b/test/test_flexible_loan.py @@ -1,12 +1,12 @@ import unittest from okx.Finance import FlexibleLoan +from test.config import get_api_credentials + class FlexibleLoanTest(unittest.TestCase): def setUp(self): - api_key = 'your_apiKey' - api_secret_key = 'your_secretKey' - passphrase = 'your_secretKey' - self.FlexibleLoanAPI = FlexibleLoan.FlexibleLoanAPI(api_key, api_secret_key, passphrase, use_server_time=False, flag='1') + api_key, api_secret_key, passphrase, flag = get_api_credentials() + self.FlexibleLoanAPI = FlexibleLoan.FlexibleLoanAPI(api_key, api_secret_key, passphrase, use_server_time=False, flag=flag) def test_borrow_currencies(self): print(self.FlexibleLoanAPI.borrow_currencies()) diff --git a/test/FundingTest.py b/test/test_funding.py similarity index 95% rename from test/FundingTest.py rename to test/test_funding.py index f9fb0c6..3247f65 100644 --- a/test/FundingTest.py +++ b/test/test_funding.py @@ -1,13 +1,13 @@ import unittest from okx import Funding +from test.config import get_api_credentials + class FundingTest(unittest.TestCase): def setUp(self): - api_key = 'your_apiKey' - api_secret_key = 'your_secretKey' - passphrase = 'your_secretKey' - self.FundingAPI = Funding.FundingAPI(api_key, api_secret_key, passphrase, use_server_time=False, flag='0') + api_key, api_secret_key, passphrase, flag = get_api_credentials() + self.FundingAPI = Funding.FundingAPI(api_key, api_secret_key, passphrase, use_server_time=False, flag=flag) """ CANCEL_WITHDRAWAL = '/api/v5/asset/cancel-withdrawal' #need add CONVERT_DUST_ASSETS = '/api/v5/asset/convert-dust-assets' #need add diff --git a/test/GridTest.py b/test/test_grid.py similarity index 95% rename from test/GridTest.py rename to test/test_grid.py index 6e8f7da..92b130c 100644 --- a/test/GridTest.py +++ b/test/test_grid.py @@ -1,13 +1,13 @@ import unittest from okx import Grid +from test.config import get_api_credentials + class GridTest(unittest.TestCase): def setUp(self): - api_key = 'your_apiKey' - api_secret_key = 'your_secretKey' - passphrase = 'your_secretKey' - self.GridAPI = Grid.GridAPI(api_key, api_secret_key, passphrase, use_server_time=False, flag='1', debug=False) + api_key, api_secret_key, passphrase, flag = get_api_credentials() + self.GridAPI = Grid.GridAPI(api_key, api_secret_key, passphrase, use_server_time=False, flag=flag, debug=False) """ GRID_COMPUTE_MARIGIN_BALANCE = '/api/v5/tradingBot/grid/compute-margin-balance' GRID_MARGIN_BALANCE = '/api/v5/tradingBot/grid/margin-balance' diff --git a/test/MarketTest.py b/test/test_market.py similarity index 93% rename from test/MarketTest.py rename to test/test_market.py index 2a45d7f..f3b6acf 100644 --- a/test/MarketTest.py +++ b/test/test_market.py @@ -12,12 +12,13 @@ BLOCK_TRADES = '/api/v5/market/block-trades'#need to add ''' +from test.config import get_api_credentials + + class MarketAPITest(unittest.TestCase): def setUp(self): - api_key = 'your_apiKey' - api_secret_key = 'your_secretKey' - passphrase = 'your_secretKey' - self.MarketApi = MarketData.MarketAPI(api_key, api_secret_key, passphrase, use_server_time=False, flag='1') + api_key, api_secret_key, passphrase, flag = get_api_credentials() + self.MarketApi = MarketData.MarketAPI(api_key, api_secret_key, passphrase, use_server_time=False, flag=flag) ''' def test_index_component(self): diff --git a/test/PublicDataTest.py b/test/test_public_data.py similarity index 95% rename from test/PublicDataTest.py rename to test/test_public_data.py index 56a028b..79e5d35 100644 --- a/test/PublicDataTest.py +++ b/test/test_public_data.py @@ -1,11 +1,12 @@ import unittest from okx import PublicData +from test.config import get_api_credentials + + class publicDataTest(unittest.TestCase): def setUp(self): - api_key = 'your_apiKey' - api_secret_key = 'your_secretKey' - passphrase = 'your_secretKey' - self.publicDataApi = PublicData.PublicAPI(api_key, api_secret_key, passphrase, use_server_time=False, flag='1') + api_key, api_secret_key, passphrase, flag = get_api_credentials() + self.publicDataApi = PublicData.PublicAPI(api_key, api_secret_key, passphrase, use_server_time=False, flag=flag) ''' TestCase For: INTEREST_LOAN = '/api/v5/public/interest-rate-loan-quota' #need to add diff --git a/test/SavingsTest.py b/test/test_savings.py similarity index 84% rename from test/SavingsTest.py rename to test/test_savings.py index 9dac910..9baf663 100644 --- a/test/SavingsTest.py +++ b/test/test_savings.py @@ -1,12 +1,12 @@ import unittest from okx.Finance import Savings +from test.config import get_api_credentials + class SavingsTest(unittest.TestCase): def setUp(self): - api_key = 'your_apiKey' - api_secret_key = 'your_secretKey' - passphrase = 'your_secretKey' - self.StackingAPI = Savings.SavingsAPI(api_key, api_secret_key, passphrase, use_server_time=False, flag='1') + api_key, api_secret_key, passphrase, flag = get_api_credentials() + self.StackingAPI = Savings.SavingsAPI(api_key, api_secret_key, passphrase, use_server_time=False, flag=flag) def test_get_saving_balance(self): diff --git a/test/SolStakingTest.py b/test/test_sol_staking.py similarity index 82% rename from test/SolStakingTest.py rename to test/test_sol_staking.py index c3899d4..110fb67 100644 --- a/test/SolStakingTest.py +++ b/test/test_sol_staking.py @@ -1,12 +1,12 @@ import unittest from okx.Finance import SolStaking +from test.config import get_api_credentials + class SolStakingTest(unittest.TestCase): def setUp(self): - api_key = 'your_apiKey' - api_secret_key = 'your_secretKey' - passphrase = 'your_secretKey' - self.StackingAPI = SolStaking.SolStakingAPI(api_key, api_secret_key, passphrase, use_server_time=False, flag='1') + api_key, api_secret_key, passphrase, flag = get_api_credentials() + self.StackingAPI = SolStaking.SolStakingAPI(api_key, api_secret_key, passphrase, use_server_time=False, flag=flag) def test_sol_purchase(self): print(self.StackingAPI.sol_purchase(amt="1")) diff --git a/test/SpreadTest.py b/test/test_spread.py similarity index 91% rename from test/SpreadTest.py rename to test/test_spread.py index cbaf6e8..25a596b 100644 --- a/test/SpreadTest.py +++ b/test/test_spread.py @@ -1,11 +1,12 @@ import unittest from okx import SpreadTrading +from test.config import get_api_credentials + + class TradeTest(unittest.TestCase): def setUp(self): - api_key = 'your_apiKey' - api_secret_key = 'your_secretKey' - passphrase = 'your_secretKey' - self.tradeApi = SpreadTrading.SpreadTradingAPI(api_key, api_secret_key, passphrase, False, '1') + api_key, api_secret_key, passphrase, flag = get_api_credentials() + self.tradeApi = SpreadTrading.SpreadTradingAPI(api_key, api_secret_key, passphrase, False, flag) # def test_place_order(self): # print(self.tradeApi.place_order(sprdId='BTC-USDT_BTC-USDT-SWAP',clOrdId='b15',side='buy',ordType='limit', diff --git a/test/StakingDefiTest.py b/test/test_staking_defi.py similarity index 82% rename from test/StakingDefiTest.py rename to test/test_staking_defi.py index 29ac045..bfe908a 100644 --- a/test/StakingDefiTest.py +++ b/test/test_staking_defi.py @@ -1,14 +1,13 @@ import unittest from okx.Finance import StakingDefi +from test.config import get_api_credentials class StakingDefiTest(unittest.TestCase): def setUp(self): - api_key = 'your_apiKey' - api_secret_key = 'your_secretKey' - passphrase = 'your_secretKey' + api_key, api_secret_key, passphrase, flag = get_api_credentials() self.StackingAPI = StakingDefi.StakingDefiAPI(api_key, api_secret_key, passphrase, use_server_time=False, - flag='1') + flag=flag) def test_get_offers(self): print(self.StackingAPI.get_offers(ccy="USDT")) diff --git a/test/SubAccountTest.py b/test/test_sub_account.py similarity index 92% rename from test/SubAccountTest.py rename to test/test_sub_account.py index b4281bd..8682194 100644 --- a/test/SubAccountTest.py +++ b/test/test_sub_account.py @@ -1,12 +1,12 @@ import unittest from okx import SubAccount +from test.config import get_api_credentials + class SubAccountTest(unittest.TestCase): def setUp(self): - api_key = 'your_apiKey' - api_secret_key = 'your_secretKey' - passphrase = 'your_secretKey' - self.SubAccountApi = SubAccount.SubAccountAPI(api_key, api_secret_key, passphrase, use_server_time=False, flag='1') + api_key, api_secret_key, passphrase, flag = get_api_credentials() + self.SubAccountApi = SubAccount.SubAccountAPI(api_key, api_secret_key, passphrase, use_server_time=False, flag=flag) ''' ENTRUST_SUBACCOUNT_LIST = '/api/v5/users/entrust-subaccount-list' #need to add SET_TRSNSFER_OUT = '/api/v5/users/subaccount/set-transfer-out' #need to add diff --git a/test/TradeTest.py b/test/test_trade.py similarity index 98% rename from test/TradeTest.py rename to test/test_trade.py index 3f1b601..c460943 100644 --- a/test/TradeTest.py +++ b/test/test_trade.py @@ -1,14 +1,13 @@ import unittest from okx import Trade +from test.config import get_api_credentials class TradeTest(unittest.TestCase): def setUp(self): - api_key = 'your_apiKey' - api_secret_key = 'your_secretKey' - passphrase = 'your_secretKey' - self.tradeApi = Trade.TradeAPI(api_key, api_secret_key, passphrase, False, '1') + api_key, api_secret_key, passphrase, flag = get_api_credentials() + self.tradeApi = Trade.TradeAPI(api_key, api_secret_key, passphrase, False, flag) # # """ # def test_place_order(self): diff --git a/test/TradingDataTest.py b/test/test_trading_data.py similarity index 86% rename from test/TradingDataTest.py rename to test/test_trading_data.py index ac318b6..0872f37 100644 --- a/test/TradingDataTest.py +++ b/test/test_trading_data.py @@ -1,14 +1,13 @@ import unittest -from ..okx import TradingData +from okx import TradingData +from test.config import get_api_credentials class TradingDataTest(unittest.TestCase): def setUp(self): - api_key = 'your_apiKey' - api_secret_key = 'your_secretKey' - passphrase = 'your_secretKey' + api_key, api_secret_key, passphrase, flag = get_api_credentials() self.TradingDataAPI = TradingData.TradingDataAPI(api_key, api_secret_key, passphrase, use_server_time=False, - flag='1') + flag=flag) """ def test_get_support_coins(self): print(self.TradingDataAPI.get_support_coin()) diff --git a/test/WsPrivateAsyncTest.py b/test/test_ws_private_async.py similarity index 88% rename from test/WsPrivateAsyncTest.py rename to test/test_ws_private_async.py index 6130b83..1244387 100644 --- a/test/WsPrivateAsyncTest.py +++ b/test/test_ws_private_async.py @@ -1,6 +1,7 @@ import asyncio from okx.websocket.WsPrivateAsync import WsPrivateAsync +from test.config import get_api_credentials def privateCallback(message): @@ -8,11 +9,12 @@ def privateCallback(message): async def main(): + api_key, api_secret_key, passphrase, _ = get_api_credentials() url = "wss://wspap.okx.com:8443/ws/v5/private?brokerId=9999" ws = WsPrivateAsync( - apiKey="your apiKey", - passphrase="your passphrase", - secretKey="your secretKey", + apiKey=api_key, + passphrase=passphrase, + secretKey=api_secret_key, url=url, useServerTime=False ) diff --git a/test/WsPublicAsyncTest.py b/test/test_ws_public_async.py similarity index 100% rename from test/WsPublicAsyncTest.py rename to test/test_ws_public_async.py From 6cee7dc266cf4237d32ef063b63be5f1d49d5c7c Mon Sep 17 00:00:00 2001 From: "jason.hsu" Date: Fri, 19 Dec 2025 19:30:38 +0800 Subject: [PATCH 5/6] feat: rmv changes --- okx/Trade.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/okx/Trade.py b/okx/Trade.py index a975dbb..9d6d9e5 100644 --- a/okx/Trade.py +++ b/okx/Trade.py @@ -189,13 +189,11 @@ def get_algo_order_details(self, algoId='', algoClOrdId=''): # Amend algo order def amend_algo_order(self, instId='', algoId='', algoClOrdId='', cxlOnFail='', reqId='', newSz='', newTriggerPx='', newOrdPx='', newTpTriggerPx='', newTpOrdPx='', newSlTriggerPx='', newSlOrdPx='', newTpTriggerPxType='', - newSlTriggerPxType='', pxAmendType=None): + newSlTriggerPxType=''): params = {'instId': instId, 'algoId': algoId, 'algoClOrdId': algoClOrdId, 'cxlOnFail': cxlOnFail, 'reqId': reqId, 'newSz': newSz, 'newTriggerPx': newTriggerPx, 'newOrdPx': newOrdPx, 'newTpTriggerPx': newTpTriggerPx, 'newTpOrdPx': newTpOrdPx, 'newSlTriggerPx': newSlTriggerPx, 'newSlOrdPx': newSlOrdPx, 'newTpTriggerPxType': newTpTriggerPxType, 'newSlTriggerPxType': newSlTriggerPxType} - if pxAmendType is not None: - params['pxAmendType'] = pxAmendType return self._request_with_params(POST, AMEND_ALGO_ORDER, params) def get_oneclick_repay_list_v2(self): From 128da2d464134505f354359b08190fc234da58cd Mon Sep 17 00:00:00 2001 From: "jason.hsu" Date: Fri, 19 Dec 2025 21:35:38 +0800 Subject: [PATCH 6/6] fix: add testing files --- test/config.py | 1 - test/test_account.py | 11 ++++++-- test/test_grid.py | 26 ++++++++++++++++- test/test_trade.py | 66 ++++++++++++++++++++++++++++++++++++++++---- 4 files changed, 94 insertions(+), 10 deletions(-) diff --git a/test/config.py b/test/config.py index 090e7e8..37fefdb 100644 --- a/test/config.py +++ b/test/config.py @@ -12,7 +12,6 @@ # Try to load from .env file if python-dotenv is available try: from dotenv import load_dotenv - # Load .env from project root env_path = Path(__file__).parent.parent / '.env' load_dotenv(env_path) except ImportError: diff --git a/test/test_account.py b/test/test_account.py index 50b5493..ef71181 100644 --- a/test/test_account.py +++ b/test/test_account.py @@ -145,8 +145,15 @@ def setUp(self): # logger.info(f'{self.AccountAPI.set_auto_repay(autoRepay=True)}') # def test_spot_borrow_repay_history(self): # logger.debug(self.AccountAPI.spot_borrow_repay_history(ccy="USDT",type="auto_borrow",after="1597026383085")) - def test_set_auto_earn(self): - logger.debug(self.AccountAPI.set_auto_earn(ccy="USDT", action="turn_on", earnType='0')) + # def test_set_auto_earn(self): + # logger.debug(self.AccountAPI.set_auto_earn(ccy="USDT", action="turn_on", earnType='0')) + #def test_get_max_loan_with_trade_quote_ccy(self): + # logger.debug(self.AccountAPI.get_max_loan( + # instId="BTC-USDT", + # mgnMode="isolated", + # mgnCcy="USDT", + # tradeQuoteCcy="USDT" + # )) if __name__ == '__main__': unittest.main() diff --git a/test/test_grid.py b/test/test_grid.py index 92b130c..fb14c95 100644 --- a/test/test_grid.py +++ b/test/test_grid.py @@ -79,7 +79,31 @@ def test_withdrawl_profits(self): # def test_get_recurring_buy_sub_orders(self): # print(self.GridAPI.get_recurring_buy_sub_orders(algoId="581191143417970688")) - #581191143417970688 + #def test_grid_order_algo_with_trade_quote_ccy(self): + # print(self.GridAPI.grid_order_algo( + # instId="BTC-USDT", + # algoOrdType="grid", + # maxPx="45000", + # minPx="20000", + # gridNum="100", + # runType="1", + # quoteSz="50", + # tradeQuoteCcy="USDT" + # )) + + #def test_place_recurring_buy_order_with_trade_quote_ccy(self): + # print(self.GridAPI.place_recurring_buy_order( + # stgyName="test_strategy", + # recurringList=[{'ccy': 'ETH', 'ratio': '1'}], + # period="daily", + # recurringDay='1', + # recurringTime='0', + # timeZone='8', + # amt='100', + # investmentCcy='USDT', + # tdMode='cash', + # tradeQuoteCcy="USDT" + # )) if __name__ == '__main__': unittest.main() \ No newline at end of file diff --git a/test/test_trade.py b/test/test_trade.py index c460943..6da7a54 100644 --- a/test/test_trade.py +++ b/test/test_trade.py @@ -233,12 +233,66 @@ def setUp(self): # def test_close_all_positions(self): # print(self.tradeApi.close_positions(instId="BTC-USDT-SWAP", mgnMode="cross",clOrdId='1213124')) - def test_get_oneclick_repay_list_v2(self): - print(self.tradeApi.get_oneclick_repay_list_v2()) - def test_oneclick_repay_v2(self): - print(self.tradeApi.oneclick_repay_v2('BTC',['USDT'])) - def test_oneclick_repay_history_v2(self): - print(self.tradeApi.oneclick_repay_history_v2()) + #def test_get_oneclick_repay_list_v2(self): + # print(self.tradeApi.get_oneclick_repay_list_v2()) + #def test_oneclick_repay_v2(self): + # print(self.tradeApi.oneclick_repay_v2('BTC',['USDT'])) + #def test_oneclick_repay_history_v2(self): + # print(self.tradeApi.oneclick_repay_history_v2()) + + #def test_place_order_with_trade_quote_ccy(self): + # print(self.tradeApi.place_order( + # instId="BTC-USDT", + # tdMode="cash", + # side="buy", + # ordType="limit", + # sz="0.01", + # px="30000", + # tradeQuoteCcy="USDT" + # )) + + #def test_place_order_with_px_amend_type(self): + # print(self.tradeApi.place_order( + # instId="BTC-USDT-SWAP", + # tdMode="cash", + # side="buy", + # ordType="limit", + # sz="1", + # px="30000", + # pxAmendType="1" + # )) + + #def test_amend_order_with_px_amend_type(self): + # print(self.tradeApi.amend_order( + # instId="BTC-USDT-SWAP", + # ordId="123", + # newPx="30500", + # pxAmendType="1" + # )) + + #def test_place_algo_order_with_trade_quote_ccy(self): + # print(self.tradeApi.place_algo_order( + # instId="BTC-USDT-SWAP", + # tdMode="cash", + # side="buy", + # ordType="trigger", + # sz="1", + # triggerPx="30000", + # orderPx="-1", + # tradeQuoteCcy="USDT" + # )) + + #def test_place_algo_order_with_px_amend_type(self): + # print(self.tradeApi.place_algo_order( + # instId="BTC-USDT-SWAP", + # tdMode="cash", + # side="buy", + # ordType="trigger", + # sz="1", + # triggerPx="30000", + # orderPx="-1", + # pxAmendType="1" + # )) if __name__ == '__main__': unittest.main()