From b6cef36dba0f58cfda5d75f247212c41c8f175a8 Mon Sep 17 00:00:00 2001 From: "shiyao.zhu@okg.com" Date: Wed, 12 Oct 2022 10:53:50 +0800 Subject: [PATCH] first commit --- .DS_Store | Bin 0 -> 6148 bytes .gitignore | 33 ++ Test/AccountTest.py | 80 +++ Test/BlockTradingTest.py | 48 ++ Test/BrokerTest.py | 70 +++ Test/ConvertTest.py | 30 + Test/FundingTest.py | 66 +++ Test/GridTest.py | 55 ++ Test/MarketTest.py | 65 +++ Test/PublicDataTest.py | 57 ++ Test/StackingTest.py | 36 ++ Test/SubAccountTest.py | 40 ++ Test/TradeTest.py | 121 ++++ Test/TradingDataTest.py | 37 ++ http2_example.py | 31 ++ okx/Account.py | 166 ++++++ okx/BlockTrading.py | 71 +++ okx/Convert.py | 27 + okx/Earning.py | 64 +++ okx/FDBroker.py | 15 + okx/Funding.py | 126 +++++ okx/Grid.py | 78 +++ okx/MarketData.py | 122 ++++ okx/NDBroker.py | 150 +++++ okx/PublicData.py | 117 ++++ okx/Status.py | 11 + okx/SubAccount.py | 63 +++ okx/Trade.py | 159 ++++++ okx/TradingData.py | 55 ++ okx/__init__.py | 6 + okx/__pycache__/Broker_api.cpython-38.pyc | Bin 0 -> 4795 bytes okx/__pycache__/Market_api.cpython-38.pyc | Bin 0 -> 4452 bytes okx/__pycache__/Public_api.cpython-38.pyc | Bin 0 -> 4838 bytes okx/__pycache__/Rfq_api.cpython-38.pyc | Bin 0 -> 3788 bytes okx/__pycache__/TradingBot_api.cpython-38.pyc | Bin 0 -> 3312 bytes okx/__pycache__/__init__.cpython-38.pyc | Bin 0 -> 283 bytes okx/__pycache__/__init__.cpython-39.pyc | Bin 0 -> 341 bytes okx/__pycache__/client.cpython-38.pyc | Bin 0 -> 2062 bytes okx/__pycache__/client.cpython-39.pyc | Bin 0 -> 2306 bytes okx/__pycache__/consts.cpython-38.pyc | Bin 0 -> 9637 bytes okx/__pycache__/consts.cpython-39.pyc | Bin 0 -> 10898 bytes okx/__pycache__/exceptions.cpython-38.pyc | Bin 0 -> 1863 bytes okx/__pycache__/exceptions.cpython-39.pyc | Bin 0 -> 1892 bytes okx/__pycache__/status_api.cpython-38.pyc | Bin 0 -> 820 bytes okx/__pycache__/subAccount_api.cpython-38.pyc | Bin 0 -> 2775 bytes okx/__pycache__/utils.cpython-38.pyc | Bin 0 -> 1837 bytes okx/__pycache__/utils.cpython-39.pyc | Bin 0 -> 2180 bytes okx/client.py | 57 ++ okx/consts.py | 235 ++++++++ okx/exceptions.py | 44 ++ okx/utils.py | 63 +++ websocket_example.py | 522 ++++++++++++++++++ 52 files changed, 2920 insertions(+) create mode 100644 .DS_Store create mode 100644 .gitignore create mode 100644 Test/AccountTest.py create mode 100644 Test/BlockTradingTest.py create mode 100644 Test/BrokerTest.py create mode 100644 Test/ConvertTest.py create mode 100644 Test/FundingTest.py create mode 100644 Test/GridTest.py create mode 100644 Test/MarketTest.py create mode 100644 Test/PublicDataTest.py create mode 100644 Test/StackingTest.py create mode 100644 Test/SubAccountTest.py create mode 100644 Test/TradeTest.py create mode 100644 Test/TradingDataTest.py create mode 100644 http2_example.py create mode 100644 okx/Account.py create mode 100644 okx/BlockTrading.py create mode 100644 okx/Convert.py create mode 100644 okx/Earning.py create mode 100644 okx/FDBroker.py create mode 100644 okx/Funding.py create mode 100644 okx/Grid.py create mode 100644 okx/MarketData.py create mode 100644 okx/NDBroker.py create mode 100644 okx/PublicData.py create mode 100644 okx/Status.py create mode 100644 okx/SubAccount.py create mode 100644 okx/Trade.py create mode 100644 okx/TradingData.py create mode 100644 okx/__init__.py create mode 100644 okx/__pycache__/Broker_api.cpython-38.pyc create mode 100644 okx/__pycache__/Market_api.cpython-38.pyc create mode 100644 okx/__pycache__/Public_api.cpython-38.pyc create mode 100644 okx/__pycache__/Rfq_api.cpython-38.pyc create mode 100644 okx/__pycache__/TradingBot_api.cpython-38.pyc create mode 100644 okx/__pycache__/__init__.cpython-38.pyc create mode 100644 okx/__pycache__/__init__.cpython-39.pyc create mode 100644 okx/__pycache__/client.cpython-38.pyc create mode 100644 okx/__pycache__/client.cpython-39.pyc create mode 100644 okx/__pycache__/consts.cpython-38.pyc create mode 100644 okx/__pycache__/consts.cpython-39.pyc create mode 100644 okx/__pycache__/exceptions.cpython-38.pyc create mode 100644 okx/__pycache__/exceptions.cpython-39.pyc create mode 100644 okx/__pycache__/status_api.cpython-38.pyc create mode 100644 okx/__pycache__/subAccount_api.cpython-38.pyc create mode 100644 okx/__pycache__/utils.cpython-38.pyc create mode 100644 okx/__pycache__/utils.cpython-39.pyc create mode 100644 okx/client.py create mode 100644 okx/consts.py create mode 100644 okx/exceptions.py create mode 100644 okx/utils.py create mode 100644 websocket_example.py diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..604430796605da98b8440bdde58c7e05bcf3eff2 GIT binary patch literal 6148 zcmeHKyH3ME5S()?^*iDp2;i7tT5xsWsa}+cK5#9 z^Kn=;RX`O`1^%Q0%-LemzC-O*0aZX1*eD?1hlEWq^Vm4FpAL4m1R#cVTjRCV5)zYm z%se&@`GjU%DA9!)Ut$;+PJiNgna9SV3y1N=hw(ETU!fQ~JI7Bf9VTDxtfGY5>6fj|anNPSSpIZl;lU$py-LQ!XuW`5u;e}1bn*I^6GH9m?{HOw-{={G4 literal 0 HcmV?d00001 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9ec2509 --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +README.md +build/ +dist/ +python_okx.egg-info/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ +setup.py \ No newline at end of file diff --git a/Test/AccountTest.py b/Test/AccountTest.py new file mode 100644 index 0000000..2d08848 --- /dev/null +++ b/Test/AccountTest.py @@ -0,0 +1,80 @@ + +import unittest +from ..okx import Account + +class AccountTest(unittest.TestCase): + def setUp(self): + api_key = 'ef06bf27-6a01-4797-b801-e3897031e45d' + api_secret_key = 'D3620B2660203350EEE80FDF5BE0C960' + passphrase = 'Beijing123' + self.AccountAPI = Account.AccountAPI(api_key, api_secret_key, passphrase, use_server_time=False, flag='1') + ''' + POSITIONS_HISTORY = '/api/v5/account/positions-history' #need add + GET_PM_LIMIT = '/api/v5/account/position-tiers' #need add + ACCOUNT_RISK = '/api/v5/account/risk-state' #need add + def test_account_risk(self): + print(self.AccountAPI.get_account_risk()) + + def test_get_pm_limit(self): + print(self.AccountAPI.get_pm_limit("SWAP","BTC-USDT")) + #positions-history + def test_get_positions_history(self): + print(self.AccountAPI.get_positions_history()) + def test_get_user_config(self): + print(self.AccountAPI.get_account_config()) + def test_get_positions(self): + print(self.AccountAPI.get_positions("SWAP")) + def test_get_balance(self): + print(self.AccountAPI.get_account()) + def test_get_positions_risk(self): + print(self.AccountAPI.get_position_risk("SWAP")) + def test_get_bills(self): + print(self.AccountAPI.get_bills_detail()) + + def test_get_bills_arch(self): + print(self.AccountAPI.get_bills_details()) + def test_set_position_mode(self): + print(self.AccountAPI.set_position_mode("long_short_mode")) + def test_set_leverage(self): + print(self.AccountAPI.set_leverage(instId="BTC-USDT",lever="5",mgnMode="isolated")) + def test_get_max_avaliable_size(self): + print(self.AccountAPI.get_max_avail_size(instId="BTC-USDT",tdMode="cash")) + def test_get_max_size(self): + print(self.AccountAPI.get_maximum_trade_size(instId="BTC-USDT",tdMode="cash")) + def test_get_positions(self): + print(self.AccountAPI.get_positions("MARGIN")) + def test_set_margin_balance(self): + print(self.AccountAPI.Adjustment_margin(instId="BTC-USDT",posSide="net",type="add",amt="1")) + def test_get_lev_info(self): + print(self.AccountAPI.get_leverage("BTC-USDT","cross")); + def test_get_max_loan(self): + print(self.AccountAPI.get_max_loan("BTC-USDT","cross","USDT")) + def test_get_trade_fee(self): + print(self.AccountAPI.get_fee_rates("SPOT")) + def test_get_insterested_accrued(self): + print(self.AccountAPI.get_interest_accrued()) + def test_get_interestred_rate(self): + print(self.AccountAPI.get_interest_rate()) + def test_set_greeks(self): + print(self.AccountAPI.set_greeks("BS")) + + def test_set_isolated_mode(self): + print(self.AccountAPI.set_isolated_mode("automatic","MARGIN")) + def test_set_max_withdraw(self): + print(self.AccountAPI.get_max_withdrawal("USDT")) + def test_borrow_repay(self): + print(self.AccountAPI.borrow_repay("BTC","borrow","1.0")) + def test_borrow_repay_history(self): + print(self.AccountAPI.get_borrow_repay_history()) + def test_get_interest_limits(self): + print(self.AccountAPI.get_interest_limits()) + def test_simulated_margin(self): + print(self.AccountAPI.get_simulated_margin()) + def test_get_greeks(self): + print(self.AccountAPI.get_greeks()) + ''' + def test_simulated_margin(self): + print(self.AccountAPI.get_simulated_margin()) + +if __name__ == '__main__': + unittest.main() \ No newline at end of file diff --git a/Test/BlockTradingTest.py b/Test/BlockTradingTest.py new file mode 100644 index 0000000..8d86974 --- /dev/null +++ b/Test/BlockTradingTest.py @@ -0,0 +1,48 @@ + +import unittest +from ..okx import BlockTrading +class BlockTradingTest(unittest.TestCase): + def setUp(self): + api_key = 'ef06bf27-6a01-4797-b801-e3897031e45d' + api_secret_key = 'D3620B2660203350EEE80FDF5BE0C960' + passphrase = 'Beijing123' + self.BlockTradingAPI = BlockTrading.BlockTradingAPI(use_server_time=False, flag='1') + + """ + def test_get_counter_parties(self): + print(self.BlockTradingAPI.counterparties()) + def test_create_rfqs(self): + counterparties=['HWZ'] + legs =[{ + 'instId':"BTC-USDT", + 'sz':'25', + 'side':'buy' + }] + print(self.BlockTradingAPI.create_rfq(counterparties,legs = legs)) + def test_cancel_rfq(self):###'rfqId': '3I1MK3O' + print(self.BlockTradingAPI.cancel_rfq(rfqId='3I1MK3O')) + def test_cancel_batch_rfqs(self): + #3I1MK40 + #3I1MK48 + print(self.BlockTradingAPI.cancel_batch_rfqs(["3I1MK40","3I1MK48"])) + def test_cancel_all_rfqs(self): + print(self.BlockTradingAPI.cancel_all_rfqs()) + def test_execute_quotes(self): + print(self.BlockTradingAPI.execute_quote("3I1MJE0","AC1233")) + def test_create_quotes(self): + print(self.BlockTradingAPI.create_quote("3I1MJE0",)) + def test_get_rfqs(self): + print(self.BlockTradingAPI.get_rfqs()) + def test_get_quotes(self): + print(self.BlockTradingAPI.get_quotes()) + def test_get_public_trades(self): + print(self.BlockTradingAPI.get_public_trades()) + def test_get_trade(self): + print(self.BlockTradingAPI.get_trades()) + """ + + + def test_get_public_trades(self): + print(self.BlockTradingAPI.get_public_trades()) +if __name__ == '__main__': + unittest.main() \ No newline at end of file diff --git a/Test/BrokerTest.py b/Test/BrokerTest.py new file mode 100644 index 0000000..e4a034c --- /dev/null +++ b/Test/BrokerTest.py @@ -0,0 +1,70 @@ + +import unittest +from ..okx import NDBroker + +class BrokerTest(unittest.TestCase): + def setUp(self): + ''' + + 52c37310-a8b0-454a-8191-3250acff2626 + EC37534156E6B8C32E78FE8D8C1D506B + Hanhao0.0 + ''' + api_key = '52c37310-a8b0-454a-8191-3250acff2626' + api_secret_key = 'EC37534156E6B8C32E78FE8D8C1D506B' + passphrase = 'Hanhao0.0' + self.NDBrokerAPI = NDBroker.NDBrokerAPI(api_key, api_secret_key, passphrase, use_server_time=False, flag='1') + + ''' + def test_get_broker_info(self): + result = self.NDBrokerAPI.get_broker_info() + print(result) + + def test_create_subAccount(self): + print(self.NDBrokerAPI.create_subaccount("","")) + #{'code': '0', 'data': [{'acctLv': '1', 'label': 'unitTest', 'subAcct': 'unitTest1298', 'ts': '1660789737257', 'uid': '346146586377719875'}], 'msg': ''} + + + + def test_get_subaccount_info(self): + print(self.NDBrokerAPI.get_subaccount_info()) + + def test_subaccount_create_apikey(self): + print(self.NDBrokerAPI.create_subaccount_apikey("unitTest1298",'test2222',"114514A.bc","142.112.128.63","trade")) + #{'code': '0', 'data': [{'apiKey': 'faf24bd1-dc25-45ab-9f78-ebfea58614bd', 'ip': '142.112.128.63', 'label': 'test2222', 'passphrase': '114514A.bc', 'perm': 'read_only,trade', 'secretKey': 'DB4F607380AA04313BB0DEDBFE576FF1', 'subAcct': 'unitTest1298', 'ts': '1660793476848'}], 'msg': ''} + + def test_subaccount_get_apikey(self): + print(self.NDBrokerAPI.get_subaccount_apikey("unitTest1298","faf24bd1-dc25-45ab-9f78-ebfea58614bd")) + + def test_delete_subAccount(self): + print(self.NDBrokerAPI.delete_subaccount("hanhaoBras1234")) + + + def test_modifiy_subaccount_apikey(self): + print(self.NDBrokerAPI.reset_subaccount_apikey("unitTest1298","faf24bd1-dc25-45ab-9f78-ebfea58614bd","csuihssssiani",perm="trade",ip = "192.168.1.1")) + + def test_delete_subaccount_apikey(self): + print(self.NDBrokerAPI.delete_subaccount_apikey("unitTest1298","faf24bd1-dc25-45ab-9f78-ebfea58614bd")) + + def test_set_account_lv(self): + print(self.NDBrokerAPI.set_subaccount_level("unitTest1298","4")) + + def test_delete_subaccount_apikey(self): + print(self.NDBrokerAPI.delete_subaccount_apikey("unitTest1298","faf24bd1-dc25-45ab-9f78-ebfea58614bd")) + + def test_set_fee_rate(self): + print(self.NDBrokerAPI.set_subaccount_fee_rate("unitTest1298","SPOT","absolute","90","90")) + def test_create_desposit(self): + print(self.NDBrokerAPI.create_subaccount_deposit_address("unitTest1298","ETH")) + def test_rebate_daily(self): + print(self.NDBrokerAPI.get_rebate_daily()) + + + + def test_create_rebate_per_order(self): + print(self.NDBrokerAPI.generate_rebate_per_orders("20220501","20220801")) + ''' + def test_get_rebate_per_order(self): + print(self.NDBrokerAPI.get_rebate_per_orders("false",begin="20220501",end = "20220801")) +if __name__ == '__main__': + unittest.main() \ No newline at end of file diff --git a/Test/ConvertTest.py b/Test/ConvertTest.py new file mode 100644 index 0000000..d4faa28 --- /dev/null +++ b/Test/ConvertTest.py @@ -0,0 +1,30 @@ +import unittest +from ..okx import Convert +class ConvertTest(unittest.TestCase): + def setUp(self): + api_key = 'ef06bf27-6a01-4797-b801-e3897031e45d' + api_secret_key = 'D3620B2660203350EEE80FDF5BE0C960' + passphrase = 'Beijing123' + self.ConvertAPI = Convert.ConvertAPI(api_key, api_secret_key, passphrase, use_server_time=False, flag='1') + ''' + + def test_get_currencies(self): + print(self.ConvertAPI.get_currencies()) + def test_get_currency_pair(self): + print(self.ConvertAPI.get_currency_pair("USDT","BTC")) + def test_query_estimate(self): + print(self.ConvertAPI.estimate_quote("BTC","USDT","buy","0.1","BTC")) + def test_query_estimate(self): + print(self.ConvertAPI.estimate_quote("BTC", "USDT", "buy", "0.1", "BTC")) + def test_convert_trade(self): + print(self.ConvertAPI.convert_trade('quotersBTC-USDT16618704214351712','BTC',"USDT",'buy','0.1','BTC')) + def test_get_convert_history(self): + print(self.ConvertAPI.get_convert_history()) + ''' + + + #def test_query_estimate(self): + # print(self.ConvertAPI.estimate_quote("BTC", "USDT", "buy", "0.1", "BTC")) + +if __name__ == '__main__': + unittest.main() diff --git a/Test/FundingTest.py b/Test/FundingTest.py new file mode 100644 index 0000000..2cce1e1 --- /dev/null +++ b/Test/FundingTest.py @@ -0,0 +1,66 @@ + +import unittest +from ..okx import Funding + +class FundingTest(unittest.TestCase): + def setUp(self): + api_key = 'ef06bf27-6a01-4797-b801-e3897031e45d' + api_secret_key = 'D3620B2660203350EEE80FDF5BE0C960' + passphrase = 'Beijing123' + self.FundingAPI = Funding.FundingAPI(use_server_time=False, flag='0') + """ + CANCEL_WITHDRAWAL = '/api/v5/asset/cancel-withdrawal' #need add + CONVERT_DUST_ASSETS = '/api/v5/asset/convert-dust-assets' #need add + ASSET_VALUATION = '/api/v5/asset/asset-valuation' #need add + GET_SAVING_BALANCE = '/api/v5/asset/saving-balance' #need to add + def test_asset_evluation(self): + print(self.FundingAPI.get_asset_valuation("USDT")) + def test_dust_convert_asset(self): + print(self.FundingAPI.convert_dust_assets(["USDT"])) + def test_saving_balance(self): + print(self.FundingAPI.get_saving_balance()) + def test_asset_get_currency(self): + print(self.FundingAPI.get_currency()) + def test_get_balance(self): + print(self.FundingAPI.get_balances()) + def test_transfer(self): + print(self.FundingAPI.funds_transfer("USDT","100","6","18")) + def test_transfer_state(self): + print(self.FundingAPI.transfer_state("11")) + def test_get_bills(self): + print(self.FundingAPI.get_bills()) + def test_deposit_lighting(self): + print(self.FundingAPI.get_deposit_lightning("BTC","10")) + def test_get_deposit_address(self): + print(self.FundingAPI.get_deposit_address("BTC")) + def test_get_deposit_history(self): + print(self.FundingAPI.get_deposit_history()) + def test_withdraw(self): + print(self.FundingAPI.coin_withdraw(ccy="USDT",amt = '10.0',dest = '3',toAddr="1391224291",fee="10")) + def test_lighting_withdrawl(self): + print(self.FundingAPI.withdrawal_lightning("BTC","jdsnjvhofhenogvne",memo="222")) + def test_cancel_withdrawl(self): + print(self.FundingAPI.cancel_withdrawal("sdhiadhsfdjknvjdaodns")) + def test_get_withdrawal_history(self): + print(self.FundingAPI.get_withdrawal_history()) + def test_purchase_redempt(self): + print(self.FundingAPI.purchase_redempt("BTC",'1.0','purchase','0.1')) + def test_set_lending_rate(self): + print(self.FundingAPI.set_lending_rate("USDT","0.1")) + def test_get_lending_history(self): + print(self.FundingAPI.get_lending_history(ccy="USDT")) + def test_get_lending_summary(self): + print(self.FundingAPI.get_lending_rate_summary('BTC')) + def test_get_lending_rate_history(self): + print(self.FundingAPI.get_lending_rate_history()) + + def test_get_lending_summary(self): + print(self.FundingAPI.get_lending_rate_summary('BTC')) + """ + + def test_get_lending_summary(self): + print(self.FundingAPI.get_lending_rate_summary('BTC')) + def test_get_lending_rate_history(self): + print(self.FundingAPI.get_lending_rate_history()) +if __name__ == '__main__': + unittest.main() \ No newline at end of file diff --git a/Test/GridTest.py b/Test/GridTest.py new file mode 100644 index 0000000..072e67c --- /dev/null +++ b/Test/GridTest.py @@ -0,0 +1,55 @@ + +import unittest +from ..okx import Grid + +class GridTest(unittest.TestCase): + def setUp(self): + api_key = 'ef06bf27-6a01-4797-b801-e3897031e45d' + api_secret_key = 'D3620B2660203350EEE80FDF5BE0C960' + passphrase = 'Beijing123' + self.GridAPI = Grid.GridAPI(api_key, api_secret_key, passphrase, use_server_time=False, flag='1', debug=False) + """ + GRID_COMPUTE_MARIGIN_BALANCE = '/api/v5/tradingBot/grid/compute-margin-balance' + GRID_MARGIN_BALANCE = '/api/v5/tradingBot/grid/margin-balance' + GRID_AI_PARAM = '/api/v5/tradingBot/grid/ai-param' + + def test_ai_param(self): + print(self.GridAPI.grid_ai_param("grid","BTC-USDT")) + + def test_order_algo(self): + print(self.GridAPI.grid_order_algo("BTC-USDT","grid","45000","20000","100","1",quoteSz="50")) + #479973849967362048 + def test_grid_margin_balance(self): + print(self.GridAPI.grid_adjust_margin_balance()) + def test_compute_margin_balance(self): + print(self.GridAPI.grid_compute_margin_balance("479978879210491904","add","100")) + + def test_pending_grid_order(self): + print(self.GridAPI.grid_orders_algo_pending("grid")) + def test_amend_order_algo(self): + print(self.GridAPI.grid_amend_order_algo('485238792325173248','BTC-USDT-SWAP',tpTriggerPx='50000')) + def test_stop_order_algo(self): + print(self.GridAPI.grid_stop_order_algo('485238792325173248','BTC-USDT-SWAP','contract_grid','1')) + def test_pending_grid_order(self): + print(self.GridAPI.grid_orders_algo_pending("grid")) + def test_algo_history(self): + print(self.GridAPI.grid_orders_algo_history('contract_grid')) + def test_orders_algo_details(self): + print(self.GridAPI.grid_orders_algo_details('contract_grid','485238792325173248')) + def test_get_sub_orders(self): + print(self.GridAPI.grid_sub_orders('485238792325173248','contract_grid','filled')) + def test_order_algo2(self): + print(self.GridAPI.grid_order_algo("BTC-USDT-SWAP","contract_grid","45000","20000","100","1",sz='3000',direction='long',lever='3.0')) + def test_get_positions(self): + print(self.GridAPI.grid_positions('contract_grid','485379848832286720')) + def test_withdrawl_profits(self): + print(self.GridAPI.grid_withdraw_income('11111')) + def test_withdrawl_profits(self): + print(self.GridAPI.grid_withdraw_income('485380442313723904')) + """ + + + def test_order_algo(self): + print(self.GridAPI.grid_order_algo("BTC-USDT","grid","45000","20000","100","1",quoteSz="50")) +if __name__ == '__main__': + unittest.main() \ No newline at end of file diff --git a/Test/MarketTest.py b/Test/MarketTest.py new file mode 100644 index 0000000..fdf8df7 --- /dev/null +++ b/Test/MarketTest.py @@ -0,0 +1,65 @@ + +import unittest +from ..okx import MarketData + +''' +ORACLE = '/api/v5/market/open-oracle' #need to update? if it is open oracle +INDEX_COMPONENTS = '/api/v5/market/index-components' #need to add +EXCHANGE_RATE = '/api/v5/market/exchange-rate' #need to add +HISTORY_TRADES = '/api/v5/market/history-trades' #need to add +BLOCK_TICKERS = '/api/v5/market/block-tickers' #need to add +BLOCK_TICKER = '/api/v5/market/block-ticker'#need to add +BLOCK_TRADES = '/api/v5/market/block-trades'#need to add +''' + +class MarketAPITest(unittest.TestCase): + def setUp(self): + api_key = 'ef06bf27-6a01-4797-b801-e3897031e45d' + api_secret_key = 'D3620B2660203350EEE80FDF5BE0C960' + passphrase = 'Beijing123' + self.MarketApi = MarketData.MarketAPI(api_key, api_secret_key, passphrase, use_server_time=False, flag='1') + ''' + + def test_oracle(self): + print(self.MarketApi.get_oracle()) + def test_index_component(self): + print(self.MarketApi.get_index_components("BTC-USDT")) + def test_exchange_rate(self): + print(self.MarketApi.get_exchange_rate()) + def test_history_trades(self): + print(self.MarketApi.get_history_trades("BTC-USDT")) + def test_block_tickers(self): + print(self.MarketApi.get_block_tickers("SPOT")) + def test_block_ticker(self): + print(self.MarketApi.get_block_ticker("BTC-USD-SWAP")) + def test_block_trades(self): + print(self.MarketApi.get_block_trades("BTC-USDT")) + def test_get_tickers(self): + print(self.MarketApi.get_tickers('SPOT')) + def test_get_ticker(self): + print(self.MarketApi.get_ticker('BTC-USD-SWAP')) + def test_index_ticker(self): + print(self.MarketApi.get_index_ticker('USDT')) + def test_get_books(self): + print(self.MarketApi.get_orderbook('BTC-USDT')) + def test_get_candles(self): + print(self.MarketApi.get_candlesticks('BTC-USDT')) + def test_get_candles_history(self): + print(self.MarketApi.get_history_candlesticks('BTC-USDT')) + def test_get_index_candles(self): + print(self.MarketApi.get_index_candlesticks('BTC-USD')) + def test_get_market_price_candles(self): + print(self.MarketApi.get_mark_price_candlesticks('BTC-USD-SWAP')) + def test_get_trade(self): + print(self.MarketApi.get_trades('BTC-USDT')) + def test_get_history_trades(self): + print(self.MarketApi.get_history_trades('BTC-USDT')) + def test_get_platform_24_volume(self): + print(self.MarketApi.get_volume()) + ''' + + + + +if __name__ == "__main__": + unittest.main() \ No newline at end of file diff --git a/Test/PublicDataTest.py b/Test/PublicDataTest.py new file mode 100644 index 0000000..f0b5138 --- /dev/null +++ b/Test/PublicDataTest.py @@ -0,0 +1,57 @@ +import unittest +from ..okx import PublicData +class publicDataTest(unittest.TestCase): + def setUp(self): + api_key = 'ef06bf27-6a01-4797-b801-e3897031e45d' + api_secret_key = 'D3620B2660203350EEE80FDF5BE0C960' + passphrase = 'Beijing123' + self.publicDataApi = PublicData.PublicAPI(api_key, api_secret_key, passphrase, use_server_time=False, flag='1') + ''' + TestCase For: + INTEREST_LOAN = '/api/v5/public/interest-rate-loan-quota' #need to add + UNDERLYING = '/api/v5/public/underlying' #need to add + VIP_INTEREST_RATE_LOAN_QUOTA = '/api/v5/public/vip-interest-rate-loan-quota' #need to add + INSURANCE_FUND = '/api/v5/public/insurance-fund'#need to add + CONVERT_CONTRACT_COIN = '/api/v5/public/convert-contract-coin' #need to add + def test_interest_loan(self): + print(self.publicDataApi.get_interest_rate_loan_quota()) + def test_get_underlying(self): + print(self.publicDataApi.get_underlying("SWAP")) + def test_get_vip_loan(self): + print(self.publicDataApi.get_vip_interest_rate_loan_quota()) + def test_insurance_fund(self): + print(self.publicDataApi.get_insurance_fund("SWAP",uly= "BTC-USD")) + def test_convert_contract_coin(self): + print(self.publicDataApi.get_convert_contract_coin(instId="BTC-USD-SWAP",sz = "1",px = "27000")) + def test_get_instruments(self): + print(self.publicDataApi.get_instruments("SPOT")) + def test_delivery_exercise_history(self): + print(self.publicDataApi.get_deliver_history("FUTURES","BTC-USD")) + def test_get_open_interest(self): + print(self.publicDataApi.get_open_interest("SWAP")) + def test_get_funding_rate(self): + print(self.publicDataApi.get_funding_rate("BTC-USD-SWAP")) + def test_get_funding_rate_history(self): + print(self.publicDataApi.funding_rate_history('BTC-USD-SWAP')) + def test_get_price_limited(self): + print(self.publicDataApi.get_price_limit("BTC-USD-SWAP")) + def test_get_opt_summary(self): + print(self.publicDataApi.get_opt_summary('BTC-USD')) + + def test_estimate_price(self): + print(self.publicDataApi.get_estimated_price("BTC-USD-220831-17000-P")) + def test_get_discount_rate_interest(self): + print(self.publicDataApi.discount_interest_free_quota(ccy='ETH')) + def test_get_systime(self): + print(self.publicDataApi.get_system_time()) + def test_get_liquid_order(self): + print(self.publicDataApi.get_liquidation_orders("SWAP",uly='BTC-USD',state='filled')) + def test_get_mark_price(self): + print(self.publicDataApi.get_mark_price('SWAP')) + + ''' + def test_position_tier(self): + print(self.publicDataApi.get_position_tiers('SWAP','cross',uly='ETH-USD')) + +if __name__ == '__main__': + unittest.main() \ No newline at end of file diff --git a/Test/StackingTest.py b/Test/StackingTest.py new file mode 100644 index 0000000..1d6a875 --- /dev/null +++ b/Test/StackingTest.py @@ -0,0 +1,36 @@ +import unittest +from ..okx import Status + +class StackingTest(unittest.TestCase): + def setUp(self): + api_key = 'ef06bf27-6a01-4797-b801-e3897031e45d' + api_secret_key = 'D3620B2660203350EEE80FDF5BE0C960' + passphrase = 'Beijing123' + self.StackingAPI = Status.StackingAPI(api_key, api_secret_key, passphrase, use_server_time=False, flag='1') + ''' + STACK_DEFI_OFFERS = '/api/v5/finance/staking-defi/offers' + STACK_DEFI_PURCHASE = '/api/v5/finance/staking-defi/purchase' + STACK_DEFI_REDEEM = '/api/v5/finance/staking-defi/redeem' + STACK_DEFI_CANCEL = '/api/v5/finance/staking-defi/cancel' + STACK_DEFI_ORDERS_ACTIVITY = '/api/v5/finance/staking-defi/orders-active' + STACK_DEFI_ORDERS_HISTORY = '/api/v5/finance/staking-defi/orders-history' + ''' + def test_get_offers(self): + print(self.StackingAPI.get_offers(ccy="USDT")) + + + + def test_purcase(self): + print(self.StackingAPI.purchase(1456,"USDT","100","0")) + def test_redeem(self): + print(self.StackingAPI.redeem()) + def test_cencel(self): + print(self.StackingAPI.cancel()) + def test_order_activity(self): + print(self.StackingAPI.get_activity_orders()) + def test_order_history(self): + print(self.StackingAPI.stack_get_order_history()) + + +if __name__ == "__main__": + unittest.main() \ No newline at end of file diff --git a/Test/SubAccountTest.py b/Test/SubAccountTest.py new file mode 100644 index 0000000..c251c0b --- /dev/null +++ b/Test/SubAccountTest.py @@ -0,0 +1,40 @@ +import unittest +from ..okx import SubAccount + +class SubAccountTest(unittest.TestCase): + def setUp(self): + api_key = '52c37310-a8b0-454a-8191-3250acff2626' + api_secret_key = 'EC37534156E6B8C32E78FE8D8C1D506B' + passphrase = 'Hanhao0.0' + self.SubAccountApi = SubAccount.SubAccountAPI(api_key, api_secret_key, passphrase, use_server_time=False, flag='1') + ''' + 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 + GET_ASSET_SUBACCOUNT_BALANCE = '/api/v5/asset/subaccount/balances' #need to add + + def test_set_permission_transfer_out(self): + print(self.SubAccountApi.set_permission_transfer_out("tst123qwerq", "false")) + def test_entrust_subaccount_list(self): + print(self.SubAccountApi.get_entrust_subaccount_list()) + + def test_subaccount_funding_balance(self): + print(self.SubAccountApi.subaccount_funding_balance("unitTest1298")) + + def test_get_subaccount_list(self): + print(self.SubAccountApi.view_list()) + def test_modified_apiKey(self): + print(self.SubAccountApi.reset('')) + def test_get_subaccount_balance(self): + #zsynoaff02 + print(self.SubAccountApi.balances('zsynoaff02')) + def test_get_subaccount_bills(self): + print(self.SubAccountApi.bills()) + def test_subaccount_transfer(self): + print(self.SubAccountApi.subAccount_transfer()) + def test_subaccount_transfer(self): + print(self.SubAccountApi.subAccount_transfer(ccy = 'BTC', amt = '1.0', froms= '18', to='18', fromSubAccount='zsynoaff02',toSubAccount = 'unitTest1298')) + + ''' + +if __name__ == "__main__": + unittest.main() \ No newline at end of file diff --git a/Test/TradeTest.py b/Test/TradeTest.py new file mode 100644 index 0000000..d963787 --- /dev/null +++ b/Test/TradeTest.py @@ -0,0 +1,121 @@ +import unittest +from ..okx import Trade +class TradeTest(unittest.TestCase): + def setUp(self): + api_key = '35d8f27e-63cc-45bc-a578-45d76363d47f' + api_secret_key = '0B7C968025BC2D4D71CF74771EA0E15C' + passphrase = '123456' + self.tradeApi = Trade.TradeAPI(api_key, api_secret_key, passphrase, False, '1') + """ + def test_place_order(self): + print(self.tradeApi.place_order("BTC-USDT",tdMode="cross",clOrdId="asCai1",side="buy",ordType="limit",sz="0.01",px="18000")) + def test_cancel_order(self): + print(self.tradeApi.cancel_order(instId="ETH-USDT",ordId="480702180748558336")) + + def test_batch_order(self): + orderData = [ { + "instId":"ETH-USDT", + "tdMode":"cross", + "clOrdId":"b151121", + "side":"buy", + "ordType":"limit", + "px":"2.15", + "sz":"2" + }, + { + "instId":"BTC-USDT", + "tdMode":"cross", + "clOrdId":"b152233", + "side":"buy", + "ordType":"limit", + "px":"2.15", + "sz":"2" + }] + print(self.tradeApi.place_multiple_orders(orderData)) + #480702180748558336 + def test_cancel_batch_orders(self): + data=[ + { + 'instId':"ETH-USDT", + 'ordId':"480702885353881600" + }, + { + 'instId':"BTC-USDT", + 'ordId':'480702885353881601' + } + ] + print(self.tradeApi.cancel_multiple_orders(data)) + def test_amend_order(self): + print(self.tradeApi.amend_order("BTC-USDT",ordId="480706017781743616",newSz="0.03")) + def test_amend_order_batch(self): + orderData = [ + { + 'instId':'ETH-USDT', + 'ordId':'480707205436669952', + 'newSz':'0.02' + }, + { + 'instId':'BTC-USDT', + 'ordId':'480707205436669953', + 'newPx':'3.0' + } + ] + print(self.tradeApi.amend_multiple_orders(orderData)) + def test_close_all_positions(self): + print(self.tradeApi.close_positions("BTC-USDT",mgnMode="cross")) + def test_get_order_info(self): + print(self.tradeApi.get_orders("ETH-USDT","480707205436669952")) + def test_get_order_pending(self): + print(self.tradeApi.get_order_list("SPOT")) + def test_get_order_history(self): + print(self.tradeApi.get_orders_history("SPOT")) + def test_get_order_histry_archive(self): + print(self.tradeApi.orders_history_archive("SPOT")) + def test_get_fills(self): + print(self.tradeApi.get_fills("SPOT")) + def test_get_fills_history(self): + print(self.tradeApi.get_fills_history("SPOT")) + def test_get_order_algo_pending(self): + print(self.tradeApi.order_algos_list('oco')) + def test_order_algo(self): + print(self.tradeApi.place_algo_order('BTC-USDT-SWAP', 'cross', side='buy', ordType='trigger', posSide='long', + sz='100', triggerPx='22000', triggerPxType ='index', orderPx='-1')) + def test_cancel_algos(self): + params = [{ + 'algoId': '485903392536264704', + 'instId': 'BTC-USDT-SWAP' + }] + + + print(self.tradeApi.cancel_algo_order(params)) + def test_cancel_adv_algos(self): + params = [{ + 'algoId': '485936482235191296', + 'instId': 'BTC-USDT-SWAP' + }] + + print(self.tradeApi.cancel_advance_algos(params))) + def test_orders_algo_pending(self): + print(self.tradeApi.order_algos_list(ordType='iceberg')) + def test_algo_order_history(self): + print(self.tradeApi.order_algos_history(algoId='485903392536264704',ordType='conditional')) + def test_get_easy_convert_list(self): + print(self.tradeApi.get_easy_convert_currency_list()) + def test_easy_convert(self): + print(self.tradeApi.easy_convert(fromCcy=['BTC'],toCcy='OKB')) + def test_get_convert_history(self): + print(self.tradeApi.get_easy_convert_history()) + def test_get_oneclick_repay_support_list(self): + print(self.tradeApi.get_oneclick_repay_list('cross')) + def test_oneclick_repay(self): + print(self.tradeApi.oneclick_repay(['BTC'],'USDT')) +""" +#485903392536264704 + #485936482235191296 + def test_oneclick_repay_history(self): + print(self.tradeApi.oneclick_repay_history()) + + + +if __name__=='__main__': + unittest.main() diff --git a/Test/TradingDataTest.py b/Test/TradingDataTest.py new file mode 100644 index 0000000..e3083fd --- /dev/null +++ b/Test/TradingDataTest.py @@ -0,0 +1,37 @@ +import unittest +from ..okx import TradingData + + +class TradingDataTest(unittest.TestCase): + def setUp(self): + api_key = '52c37310-a8b0-454a-8191-3250acff2626' + api_secret_key = 'EC37534156E6B8C32E78FE8D8C1D506B' + passphrase = 'Hanhao0.0' + self.TradingDataAPI = TradingData.TradingDataAPI(api_key, api_secret_key, passphrase, use_server_time=False, + flag='1') + """ + def test_get_support_coins(self): + print(self.TradingDataAPI.get_support_coin()) + def test_get_taker_vol(self): + print(self.TradingDataAPI.get_taker_volume(ccy="BTC",instType="SPOT")) + def test_get_loan_ratio(self): + print(self.TradingDataAPI.get_margin_lending_ratio('ETH')) + def test_get_long_short_account(self): + print(self.TradingDataAPI.get_long_short_ratio('BTC')) + def test_get_contracts_vol_open(self): + print(self.TradingDataAPI.get_contracts_interest_volume(ccy="BTC")) + def test_get_option_vol_open(self): + print(self.TradingDataAPI.get_options_interest_volume(ccy="ETH")) + def test_get_option_ratio(self): + print(self.TradingDataAPI.get_put_call_ratio(ccy='BTC')) + def test_get_open_interest_expiry(self): + print(self.TradingDataAPI.get_interest_volume_expiry("BTC")) + def test_open_interest_volume_strike(self): + print(self.TradingDataAPI.get_interest_volume_strike(ccy="BTC",expTime="20220901")) + + """ + def test_taker_block_vol(self): + print(self.TradingDataAPI.get_taker_flow(ccy='BTC')) + +if __name__ == "__main__": + unittest.main() diff --git a/http2_example.py b/http2_example.py new file mode 100644 index 0000000..7663d23 --- /dev/null +++ b/http2_example.py @@ -0,0 +1,31 @@ +import json +import time + +import okx.Account as Account + + +async def http2_request(request, parameters): + while 1: + begin = time.time() + if type(parameters) is list: + result = request(*parameters) + else: + result = request(**parameters) + + end = time.time() + cost = end - begin + print(f'request_cost:{cost}\nresponse_body:{json.dumps(result)}') + + +api_key = "" +secret_key = "" +passphrase = "" +# flag是实盘与模拟盘的切换参数 flag is the key parameter which can help you to change between demo and real trading. +# flag = '1' # 模拟盘 demo trading +flag = '0' # 实盘 real tradiang + +if __name__ == '__main__': + # account api + accountAPI = Account.AccountAPI(api_key, secret_key, passphrase, False, flag) + accountAPI.get_account_config() + accountAPI.get_greeks('BTC') diff --git a/okx/Account.py b/okx/Account.py new file mode 100644 index 0000000..2a087c8 --- /dev/null +++ b/okx/Account.py @@ -0,0 +1,166 @@ +from .client import Client +from .consts import * + + +class AccountAPI(Client): + + def __init__(self, api_key='-1', api_secret_key='-1', passphrase='-1', use_server_time=False, flag='1', domain = 'https://www.okx.com',debug = True): + Client.__init__(self, api_key, api_secret_key, passphrase, use_server_time, flag, domain,debug) + + + # Get Positions + def get_position_risk(self, instType=''): + params = {} + if instType: + params['instType'] = instType + return self._request_with_params(GET, POSITION_RISK, params) + + # Get Balance + def get_account_balance(self, ccy=''): + params = {} + if ccy: + params['ccy'] = ccy + return self._request_with_params(GET, ACCOUNT_INFO, params) + + # Get Positions + def get_positions(self, instType='', instId=''): + params = {'instType': instType, 'instId': instId} + return self._request_with_params(GET, POSITION_INFO, params) + + # Get Bills Details (recent 7 days) + def get_account_bills(self, instType='', ccy='', mgnMode='', ctType='', type='', subType='', after='', before='', + limit=''): + params = {'instType': instType, 'ccy': ccy, 'mgnMode': mgnMode, 'ctType': ctType, 'type': type, + 'subType': subType, 'after': after, 'before': before, 'limit': limit} + return self._request_with_params(GET, BILLS_DETAIL, params) + + # Get Bills Details (recent 3 months) + def get_account_bills_archive(self, instType='', ccy='', mgnMode='', ctType='', type='', subType='', after='', before='', + limit=''): + params = {'instType': instType, 'ccy': ccy, 'mgnMode': mgnMode, 'ctType': ctType, 'type': type, + 'subType': subType, 'after': after, 'before': before, 'limit': limit} + return self._request_with_params(GET, BILLS_ARCHIVE, params) + + # Get Account Configuration + def get_account_config(self): + return self._request_without_params(GET, ACCOUNT_CONFIG) + + # Get Account Configuration + def set_position_mode(self, posMode): + params = {'posMode': posMode} + return self._request_with_params(POST, POSITION_MODE, params) + + # Get Account Configuration + def set_leverage(self, lever, mgnMode, instId='', ccy='', posSide=''): + params = {'lever': lever, 'mgnMode': mgnMode, 'instId': instId, 'ccy': ccy, 'posSide': posSide} + return self._request_with_params(POST, SET_LEVERAGE, params) + + # Get Maximum Tradable Size For Instrument + def get_max_order_size(self, instId, tdMode, ccy='', px=''): + params = {'instId': instId, 'tdMode': tdMode, 'ccy': ccy, 'px': px} + return self._request_with_params(GET, MAX_TRADE_SIZE, params) + + # Get Maximum Available Tradable Amount + def get_max_avail_size(self, instId, tdMode, ccy='', reduceOnly=''): + params = {'instId': instId, 'tdMode': tdMode, 'ccy': ccy, 'reduceOnly': reduceOnly} + return self._request_with_params(GET, MAX_AVAIL_SIZE, params) + + # Increase / Decrease margin + def adjustment_margin(self, instId, posSide, type, amt,loanTrans=''): + params = {'instId': instId, 'posSide': posSide, 'type': type, 'amt': amt,'loanTrans':loanTrans} + return self._request_with_params(POST, ADJUSTMENT_MARGIN, params) + + # Get Leverage + def get_leverage(self, instId, mgnMode): + params = {'instId': instId, 'mgnMode': mgnMode} + return self._request_with_params(GET, GET_LEVERAGE, params) + + # Get the maximum loan of isolated MARGIN + def get_max_loan(self, instId, mgnMode, mgnCcy): + params = {'instId': instId, 'mgnMode': mgnMode, 'mgnCcy': mgnCcy} + return self._request_with_params(GET, MAX_LOAN, params) + + # Get Fee Rates + def get_fee_rates(self, instType, instId='', uly='', category='',instFamily = ''): + params = {'instType': instType, 'instId': instId, 'uly': uly, 'category': category,'instFamily':instFamily} + return self._request_with_params(GET, FEE_RATES, params) + + # Get interest-accrued + def get_interest_accrued(self, instId='', ccy='', mgnMode='', after='', before='', limit=''): + params = {'instId': instId, 'ccy': ccy, 'mgnMode': mgnMode, 'after': after, 'before': before, 'limit': limit} + return self._request_with_params(GET, INTEREST_ACCRUED, params) + + # Get interest-accrued + def get_interest_rate(self, ccy=''): + params = {'ccy': ccy} + return self._request_with_params(GET, INTEREST_RATE, params) + + # Set Greeks (PA/BS) + def set_greeks(self, greeksType): + params = {'greeksType': greeksType} + return self._request_with_params(POST, SET_GREEKS, params) + + # Set Isolated Mode + def set_isolated_mode(self, isoMode,type): + params = {'isoMode': isoMode, 'type':type} + return self._request_with_params(POST, ISOLATED_MODE, params) + + # Get Maximum Withdrawals + def get_max_withdrawal(self, ccy=''): + params = {'ccy': ccy} + return self._request_with_params(GET, MAX_WITHDRAWAL, params) + + # Get borrow repay + def borrow_repay(self, ccy='', side='', amt=''): + params = {'ccy': ccy, 'side': side, 'amt': amt} + return self._request_with_params(POST, BORROW_REPAY, params) + + # Get borrow repay history + def get_borrow_repay_history(self, ccy='', after='', before='', limit=''): + params = {'ccy': ccy, 'after': after, 'before': before, 'limit':limit} + return self._request_with_params(GET, BORROW_REPAY_HISTORY, params) + + # Get Obtain borrowing rate and limit + def get_interest_limits(self, type='',ccy=''): + params = {'type': type, 'ccy': ccy} + return self._request_with_params(GET, INTEREST_LIMITS, params) + + # Get Simulated Margin + def get_simulated_margin(self, instType ='',inclRealPos=True,instId='',pos=''): + params = {'instType': instType, 'inclRealPos': inclRealPos,'instId': instId,'pos': pos,} + return self._request_with_params(POST, SIMULATED_MARGIN, params) + + # Get Greeks + def get_greeks(self, ccy=''): + params = {'ccy': ccy} + return self._request_with_params(GET, GREEKS, params) + + #GET /api/v5/account/risk-state + def get_account_position_risk(self): + return self._request_without_params(GET, ACCOUNT_RISK) + + #GET /api/v5/account/positions-history + def get_positions_history(self,instType = '', instId = '',mgnMode = '',type = '',posId = '',after = '',before ='',limit = ''): + params = { + 'instType':instType, + 'instId':instId, + 'mgnMode':mgnMode, + 'type':type, + 'posId':posId, + 'after':after, + 'before':before, + 'limit':limit + } + return self._request_with_params(GET,POSITIONS_HISTORY,params) + + #GET /api/v5/account/position-tiers + def get_account_position_tiers(self,instType = '', uly = '',instFamily = ''): + params = { + 'instType':instType, + 'uly':uly, + 'instFamily':instFamily + } + return self._request_with_params(GET,GET_PM_LIMIT,params) + + + diff --git a/okx/BlockTrading.py b/okx/BlockTrading.py new file mode 100644 index 0000000..0275555 --- /dev/null +++ b/okx/BlockTrading.py @@ -0,0 +1,71 @@ +from .client import Client +from .consts import * + + +class BlockTradingAPI(Client): + def __init__(self, api_key='-1', api_secret_key='-1', passphrase='-1', use_server_time=False, flag='1', domain = 'https://www.okx.com',debug = True): + Client.__init__(self, api_key, api_secret_key, passphrase, use_server_time, flag, domain,debug) + + def counterparties(self): + params = {} + return self._request_with_params(GET, COUNTERPARTIES, params) + + def create_rfq(self, counterparties=[], anonymous='false', clRfqId='', legs = []): + params = {'counterparties': counterparties, 'anonymous': anonymous, 'clRfqId': clRfqId, 'legs': legs} + return self._request_with_params(POST, CREATE_RFQ, params) + + def cancel_rfq(self, rfqId = '', clRfqId = ''): + params = {'rfqId': rfqId, 'clRfqId': clRfqId} + return self._request_with_params(POST, CANCEL_RFQ, params) + + def cancel_batch_rfqs(self, rfqIds=[], clRfqIds=[]): + params = {'rfqIds': rfqIds, 'clRfqIds': clRfqIds} + return self._request_with_params(POST, CANCEL_BATCH_RFQS, params) + + def cancel_all_rfqs(self): + params = {} + return self._request_with_params(POST, CANCEL_ALL_RSQS, params) + + def execute_quote(self, rfqId='', quoteId=''): + params = {'rfqId': rfqId, 'quoteId': quoteId} + return self._request_with_params(POST, EXECUTE_QUOTE, params) + + def create_quote(self, rfqId='', clQuoteId='', quoteSide = '', legs = [],anonymous=False,expiresIn=''): + params = {'rfqId': rfqId, 'clQuoteId': clQuoteId, 'quoteSide': quoteSide, 'legs': legs, + 'anonymous':anonymous,'expiresIn':expiresIn} + return self._request_with_params(POST, CREATE_QUOTE, params) + + def cancel_quote(self, quoteId = '', clQuoteId = ''): + params = {'quoteId': quoteId, 'clQuoteId': clQuoteId} + return self._request_with_params(POST, CANCEL_QUOTE, params) + + def cancel_batch_quotes(self, quoteIds='', clQuoteIds=''): + params = {'quoteIds': quoteIds, 'clQuoteIds': clQuoteIds} + return self._request_with_params(POST, CANCEL_BATCH_QUOTES, params) + + def cancel_all_quotes(self): + params = {} + return self._request_with_params(POST, CANCEL_ALL_QUOTES, params) + + def get_rfqs(self, rfqId = '', clRfqId = '', state = '', beginId = '', endId = '', limit = ''): + params = {'rfqId': rfqId, 'clRfqId': clRfqId, 'state': state, 'beginId': beginId, 'endId': endId, 'limit':limit} + return self._request_with_params(GET, GET_RFQS, params) + + def get_quotes(self, rfqId = '', clRfqId = '', quoteId = '', clQuoteId = '', state = '', beginId = '', endId = '', limit = ''): + params = {'rfqId': rfqId, 'clRfqId': clRfqId, 'quoteId':quoteId,'clQuoteId':clQuoteId, 'state': state, 'beginId': beginId, 'endId': endId, 'limit':limit} + return self._request_with_params(GET, GET_QUOTES, params) + + def get_trades(self, rfqId = '', clRfqId = '', quoteId = '', clQuoteId = '', state = '', beginId = '', endId = '', limit = ''): + params = {'rfqId': rfqId, 'clRfqId': clRfqId, 'quoteId':quoteId,'clQuoteId':clQuoteId, 'state': state, 'beginId': beginId, 'endId': endId, 'limit':limit} + return self._request_with_params(GET, GET_RFQ_TRADES, params) + + def get_public_trades(self, beginId = '', endId = '', limit = ''): + params = {'beginId': beginId, 'endId': endId, 'limit': limit} + return self._request_with_params(GET, GET_PUBLIC_TRADES, params) + + def reset_mmp(self): + return self._request_without_params(POST, MMP_RESET) + + def set_marker_instrument(self,params = []): + + return self._request_with_params(POST, MARKER_INSTRUMENT_SETTING, params) \ No newline at end of file diff --git a/okx/Convert.py b/okx/Convert.py new file mode 100644 index 0000000..8d04f44 --- /dev/null +++ b/okx/Convert.py @@ -0,0 +1,27 @@ +from .client import Client +from .consts import * + + +class ConvertAPI(Client): + def __init__(self, api_key='-1', api_secret_key='-1', passphrase='-1', use_server_time=False, flag='1', domain = 'https://www.okx.com',debug = True): + Client.__init__(self, api_key, api_secret_key, passphrase, use_server_time, flag, domain,debug) + + def get_currencies(self): + params = {} + return self._request_with_params(GET, GET_CURRENCIES, params) + + def get_currency_pair(self, fromCcy='', toCcy=''): + params = {"fromCcy": fromCcy, 'toCcy': toCcy} + return self._request_with_params(GET, GET_CURRENCY_PAIR, params) + + def estimate_quote(self, baseCcy = '', quoteCcy = '', side = '', rfqSz = '', rfqSzCcy = '', clQReqId = '',tag=''): + params = {'baseCcy': baseCcy, 'quoteCcy': quoteCcy, 'side':side, 'rfqSz':rfqSz, 'rfqSzCcy':rfqSzCcy, 'clQReqId':clQReqId,'tag':tag} + return self._request_with_params(POST, ESTIMATE_QUOTE, params) + + def convert_trade(self, quoteId = '', baseCcy = '', quoteCcy = '', side = '', sz = '', szCcy = '', clTReqId = '',tag=''): + params = {'quoteId': quoteId, 'baseCcy': baseCcy, 'quoteCcy':quoteCcy, 'side':side, 'sz':sz, 'szCcy':szCcy, 'clTReqId':clTReqId,'tag':tag} + return self._request_with_params(POST, CONVERT_TRADE, params) + + def get_convert_history(self, after = '', before = '', limit = '',tag=''): + params = {'after': after, 'before': before, 'limit':limit,'tag':tag} + return self._request_with_params(GET, CONVERT_HISTORY, params) diff --git a/okx/Earning.py b/okx/Earning.py new file mode 100644 index 0000000..0ecb256 --- /dev/null +++ b/okx/Earning.py @@ -0,0 +1,64 @@ +from .client import Client +from .consts import * + + +class EarningAPI(Client): + def __init__(self, api_key='-1', api_secret_key='-1', passphrase='-1', use_server_time=False, flag='1', domain = 'https://www.okx.com',debug = True): + Client.__init__(self, api_key, api_secret_key, passphrase, use_server_time, flag, domain, debug) + + def get_offers(self,productId = '',protocolType = '',ccy = ''): + params = { + 'productId':productId, + 'protocolType':protocolType, + 'ccy':ccy + } + return self._request_with_params(GET,STACK_DEFI_OFFERS,params) + + def purchase(self,productId = '',investData = [],term = ''): + + params = { + 'productId':productId, + 'investData':investData + } + if term != '': + params['term'] = term + return self._request_with_params(POST,STACK_DEFI_PURCHASE,params) + + def redeem(self,ordId = '',protocolType = '',allowEarlyRedeem = ''): + params = { + 'ordId':ordId, + 'protocolType':protocolType, + 'allowEarlyRedeem':allowEarlyRedeem + } + return self._request_with_params(POST,STACK_DEFI_REDEEM,params) + + def cancel(self,ordId = '',protocolType = ''): + params = { + 'ordId':ordId, + 'protocolType':protocolType + } + return self._request_with_params(POST,STACK_DEFI_CANCEL,params) + + def get_activity_orders(self,productId = '',protocolType = '',ccy = '',state = ''): + params = { + 'productId':productId, + 'protocolType':protocolType, + 'ccy':ccy, + 'state':state + } + return self._request_with_params(GET,STACK_DEFI_ORDERS_ACTIVITY,params) + + def get_orders_history(self,productId = '',protocolType = '',ccy = '',after = '',before = '',limit = ''): + params = { + 'productId':productId, + 'protocolType':protocolType, + 'ccy':ccy, + 'after':after, + 'before':before, + 'limit':limit + } + return self._request_with_params(GET,STACK_DEFI_ORDERS_HISTORY,params) + + + + diff --git a/okx/FDBroker.py b/okx/FDBroker.py new file mode 100644 index 0000000..d0c8f57 --- /dev/null +++ b/okx/FDBroker.py @@ -0,0 +1,15 @@ +from .client import Client +from .consts import * + + +class FDBrokerAPI(Client): + def __init__(self, api_key='-1', api_secret_key='-1', passphrase='-1', use_server_time=False, flag='1', domain = 'https://www.okx.com',debug = True): + Client.__init__(self, api_key, api_secret_key, passphrase, use_server_time, flag, domain,debug) + + def generate_rebate_details_download_link(self, begin ='', end = ''): + params = {'begin': begin, 'end': end} + return self._request_with_params(POST, FD_REBATE_PER_ORDERS, params) + + def get_rebate_details_download_link(self, type = '', begin = '', end = ''): + params = {'type': type, 'begin': begin, 'end': end} + return self._request_with_params(GET, FD_GET_REBATE_PER_ORDERS, params) diff --git a/okx/Funding.py b/okx/Funding.py new file mode 100644 index 0000000..a4c3c65 --- /dev/null +++ b/okx/Funding.py @@ -0,0 +1,126 @@ +from .client import Client +from .consts import * + + +class FundingAPI(Client): + + + def __init__(self, api_key='-1', api_secret_key='-1', passphrase='-1', use_server_time=False, flag='1', domain = 'https://www.okx.com',debug = True): + Client.__init__(self, api_key, api_secret_key, passphrase, use_server_time, flag, domain,debug) + + # Get Deposit Address + def get_deposit_address(self, ccy): + params = {'ccy': ccy} + return self._request_with_params(GET, DEPOSIT_ADDRESS, params) + + # Get Transfer State + def transfer_state(self, transId,type=''): + params = {'transId': transId, 'type': type} + return self._request_with_params(GET, TRANSFER_STATE, params) + + # Get Balance + def get_balances(self, ccy=''): + params = {'ccy': ccy} + return self._request_with_params(GET, GET_BALANCES, params) + + # Get Account Configuration + def funds_transfer(self, ccy, amt, from_, to, type='0', subAcct='', instId='', toInstId='',loanTrans=''): + params = {'ccy': ccy, 'amt': amt, 'from': from_, 'to': to, 'type': type, 'subAcct': subAcct, 'instId': instId, + 'toInstId': toInstId,'loanTrans':loanTrans} + return self._request_with_params(POST, FUNDS_TRANSFER, params) + + # Withdrawal + def withdrawal(self, ccy, amt, dest, toAddr, fee,chain = '', clientId = ''): + params = {'ccy': ccy, 'amt': amt, 'dest': dest, 'toAddr': toAddr, 'fee': fee,'chain':chain,'clientId':clientId} + return self._request_with_params(POST, WITHDRAWAL_COIN, params) + + # Get Deposit History + def get_deposit_history(self, ccy='', state='', after='', before='', limit='',txId='',depId=''): + params = {'ccy': ccy, 'state': state, 'after': after, 'before': before, 'limit': limit,'txId':txId,'depId':depId} + return self._request_with_params(GET, DEPOSIT_HISTORIY, params) + + # Get Withdrawal History + def get_withdrawal_history(self, ccy='', state='', after='', before='', limit='',txId=''): + params = {'ccy': ccy, 'state': state, 'after': after, 'before': before, 'limit': limit,'txId':txId} + return self._request_with_params(GET, WITHDRAWAL_HISTORIY, params) + + # Get Currencies + def get_currencies(self, ccy=''): + params = {'ccy': ccy} + return self._request_with_params(GET, CURRENCY_INFO, params) + + # PiggyBank Purchase/Redemption + def purchase_redempt(self, ccy, amt, side, rate): + params = {'ccy': ccy, 'amt': amt, 'side': side,'rate':rate} + return self._request_with_params(POST, PURCHASE_REDEMPT, params) + + # Get Withdrawal History + def get_bills(self, ccy='', type='', after='', before='', limit=''): + params = {'ccy': ccy, 'type': type, 'after': after, 'before': before, 'limit': limit} + return self._request_with_params(GET, BILLS_INFO, params) + + + #Get Deposit Lightning + def get_deposit_lightning(self, ccy,amt,to=""): + params = {'ccy':ccy,'amt':amt} + if to: + params = {'to':to} + return self._request_with_params(GET, DEPOSIT_LIGHTNING, params) + + # Withdrawal Lightning + def withdrawal_lightning(self, ccy,invoice,memo=''): + params = {'ccy':ccy, 'invoice':invoice, 'memo':memo} + return self._request_with_params(POST, WITHDRAWAL_LIGHTNING, params) + + + # POST SET LENDING RATE + def set_lending_rate(self, ccy, rate): + params = {'ccy': ccy, 'rate': rate} + return self._request_with_params(POST, SET_LENDING_RATE, params) + + + # GET LENDING HISTORY + def get_lending_history(self, ccy='', before='', after='', limit='' ): + params = {'ccy': ccy, 'after': after, 'before': before, 'limit': limit } + return self._request_with_params(GET, LENDING_HISTORY, params) + + + # GET LENDING RATE HISTORY + def get_lending_rate_history(self, ccy='',after = '',before = '',limit = '' ): + params = {'ccy': ccy,'after':after,'before':before,'limit':limit} + return self._request_with_params(GET, LENDING_RATE_HISTORY, params) + + + # GET LENDING RATE SUMMARY + def get_lending_rate_summary(self, ccy=''): + params = {'ccy': ccy} + return self._request_with_params(GET, LENDING_RATE_SUMMARY, params) + + + #POST /api/v5/asset/cancel-withdrawal + def cancel_withdrawal(self,wdId = ''): + params = { + 'wdId':wdId + } + return self._request_with_params(POST, CANCEL_WITHDRAWAL, params) + + #POST /api/v5/asset/convert-dust-assets + def convert_dust_assets(self,ccy = []): + params = { + 'ccy':ccy + } + return self._request_with_params(POST, CONVERT_DUST_ASSETS, params) + + #GET /api/v5/asset/asset-valuation + def get_asset_valuation(self,ccy = ''): + params = { + 'ccy':ccy + } + return self._request_with_params(GET, ASSET_VALUATION, params) + + #GET / api / v5 / asset / saving - balance + def get_saving_balance(self,ccy = ''): + params = { + 'ccy':ccy + } + return self._request_with_params(GET, GET_SAVING_BALANCE, params) diff --git a/okx/Grid.py b/okx/Grid.py new file mode 100644 index 0000000..6cf4991 --- /dev/null +++ b/okx/Grid.py @@ -0,0 +1,78 @@ +from .client import Client +from .consts import * + + +class GridAPI(Client): + def __init__(self, api_key='-1', api_secret_key='-1', passphrase='-1', use_server_time=False, flag='1', domain = 'https://www.okx.com',debug = True): + Client.__init__(self, api_key, api_secret_key, passphrase, use_server_time, flag, domain,debug) + + def grid_order_algo(self, instId='', algoOrdType='', maxPx='', minPx='', gridNum='', runType='', tpTriggerPx='', + slTriggerPx='', tag='', quoteSz='', baseSz='', sz='', direction='', lever='', basePos=''): + 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} + return self._request_with_params(POST, GRID_ORDER_ALGO, params) + + def grid_amend_order_algo(self, algoId='', instId='', slTriggerPx='', tpTriggerPx=''): + params = {'algoId': algoId, 'instId': instId, 'slTriggerPx': slTriggerPx, 'tpTriggerPx': tpTriggerPx} + return self._request_with_params(POST, GRID_AMEND_ORDER_ALGO, params) + + def grid_stop_order_algo(self, algoId='', instId='', algoOrdType='', stopType=''): + params = [{'algoId': algoId, 'instId': instId, 'algoOrdType': algoOrdType, 'stopType': stopType}] + return self._request_with_params(POST, GRID_STOP_ORDER_ALGO, params) + + def grid_orders_algo_pending(self, algoOrdType='', algoId='', instId='', instType='', after='', before='', + limit='', instFamily = ''): + params = {'algoOrdType': algoOrdType, 'algoId': algoId, 'instId': instId, 'instType': instType, 'after': after, + 'before': before, 'limit': limit,'instFamily':instFamily} + return self._request_with_params(GET, GRID_ORDERS_ALGO_PENDING, params) + + def grid_orders_algo_history(self, algoOrdType='', algoId='', instId='', instType='', after='', before='', + limit='',instFamily = ''): + params = {'algoOrdType': algoOrdType, 'algoId': algoId, 'instId': instId, 'instType': instType, 'after': after, + 'before': before, 'limit': limit,'instFamily':instFamily} + return self._request_with_params(GET, GRID_ORDERS_ALGO_HISTORY, params) + + def grid_orders_algo_details(self, algoOrdType='', algoId=''): + params = {'algoOrdType': algoOrdType, 'algoId': algoId} + return self._request_with_params(GET, GRID_ORDERS_ALGO_DETAILS, params) + + def grid_sub_orders(self, algoId='', algoOrdType='', type='', groupId='', after='', before='', limit=''): + params = {'algoId': algoId, 'algoOrdType': algoOrdType, 'type': type, 'groupId': groupId, 'after': after, + 'before': before, 'limit': limit} + return self._request_with_params(GET, GRID_SUB_ORDERS, params) + + def grid_positions(self, algoOrdType='', algoId=''): + params = {'algoOrdType': algoOrdType, 'algoId': algoId} + return self._request_with_params(GET, GRID_POSITIONS, params) + + def grid_withdraw_income(self, algoId=''): + params = {'algoId': algoId} + return self._request_with_params(POST, GRID_WITHDRAW_INCOME, params) + + def grid_compute_margin_balance(self, algoId='', type='', amt=''): + params = { + 'algoId': algoId, + 'type': type, + 'amt': amt + } + return self._request_with_params(POST, GRID_COMPUTE_MARIGIN_BALANCE, params) + + def grid_adjust_margin_balance(self, algoId='', type='', amt='', percent=''): + params = { + 'algoId': algoId, + 'type': type, + 'amt': amt, + 'percent': percent + } + return self._request_with_params(POST, GRID_MARGIN_BALANCE, params) + + def grid_ai_param(self, algoOrdType='', instId='', direction='', duration=''): + params = { + 'algoOrdType': algoOrdType, + 'instId': instId, + 'direction': direction, + 'duration':duration + } + return self._request_with_params(GET, GRID_AI_PARAM, params) diff --git a/okx/MarketData.py b/okx/MarketData.py new file mode 100644 index 0000000..1dc2bdf --- /dev/null +++ b/okx/MarketData.py @@ -0,0 +1,122 @@ +from .client import Client +from .consts import * + + +class MarketAPI(Client): + + def __init__(self, api_key='-1', api_secret_key='-1', passphrase='-1', use_server_time=False, flag='1', domain = 'https://www.okx.com',debug = True): + Client.__init__(self, api_key, api_secret_key, passphrase, use_server_time, flag, domain,debug) + + + # Get Tickers + def get_tickers(self, instType, uly='', instFamily =''): + if uly: + params = {'instType': instType, 'uly': uly, 'instFamily': instFamily} + else: + params = {'instType': instType, 'instFamily': instFamily} + return self._request_with_params(GET, TICKERS_INFO, params) + + # Get Ticker + def get_ticker(self, instId): + params = {'instId': instId} + return self._request_with_params(GET, TICKER_INFO, params) + + # Get Index Tickers + def get_index_tickers(self, quoteCcy='', instId=''): + params = {'quoteCcy': quoteCcy, 'instId': instId} + return self._request_with_params(GET, INDEX_TICKERS, params) + + # Get Order Book + def get_orderbook(self, instId, sz=''): + params = {'instId': instId, 'sz': sz} + return self._request_with_params(GET, ORDER_BOOKS, params) + + # Get Candlesticks + def get_candlesticks(self, instId, after='', before='', bar='', limit=''): + params = {'instId': instId, 'after': after, 'before': before, 'bar': bar, 'limit': limit} + return self._request_with_params(GET, MARKET_CANDLES, params) + + # GGet Candlesticks History(top currencies only) + def get_history_candlesticks(self, instId, after='', before='', bar='', limit=''): + params = {'instId': instId, 'after': after, 'before': before, 'bar': bar, 'limit': limit} + return self._request_with_params(GET, HISTORY_CANDLES, params) + + # Get Index Candlesticks + def get_index_candlesticks(self, instId, after='', before='', bar='', limit=''): + params = {'instId': instId, 'after': after, 'before': before, 'bar': bar, 'limit': limit} + return self._request_with_params(GET, INDEX_CANSLES, params) + + # Get Mark Price Candlesticks + def get_mark_price_candlesticks(self, instId, after='', before='', bar='', limit=''): + params = {'instId': instId, 'after': after, 'before': before, 'bar': bar, 'limit': limit} + return self._request_with_params(GET, MARKPRICE_CANDLES, params) + + # Get Index Candlesticks + def get_trades(self, instId, limit=''): + params = {'instId': instId, 'limit': limit} + return self._request_with_params(GET, MARKET_TRADES, params) + + # Get Volume + def get_volume(self): + return self._request_without_params(GET, VOLUMNE) + + # Get Oracle + def get_oracle(self): + return self._request_without_params(GET, ORACLE) + + # Get Tier + def get_tier(self, instType='', tdMode='', uly='', instId='', ccy='', tier=''): + params = {'instType': instType, 'tdMode': tdMode, 'uly': uly, 'instId': instId, 'ccy': ccy, 'tier': tier} + return self._request_with_params(GET, TIER, params) + + #GET /api/v5/market/index-components + def get_index_components(self,index = ''): + param = { + 'index':index + } + return self._request_with_params(GET,INDEX_COMPONENTS,param) + + + #GET /api/v5/market/exchange-rate + def get_exchange_rate(self): + return self._request_without_params(GET, EXCHANGE_RATE) + + #GET /api/v5/market/history-trades + def get_history_trades(self,instId = '',type = '',after = '',before = '',limit = ''): + params = { + 'instId':instId, + 'type':type, + 'after':after, + 'before':before, + 'limit':limit + } + return self._request_with_params(GET,HISTORY_TRADES,params) + + #GET /api/v5/market/block-ticker + def get_block_ticker(self,instId = ''): + params = { + 'instId':instId + } + return self._request_with_params(GET,BLOCK_TICKER,params) + + #GET /api/v5/market/block-tickers + def get_block_tickers(self,instType = '',uly = '', instFamily = ''): + params = { + 'instType':instType, + 'uly':uly, + 'instFamily':instFamily + } + return self._request_with_params(GET, BLOCK_TICKERS, params) + + #GET /api/v5/market/block-trades + def get_block_trades(self,instId = ''): + params = { + 'instId':instId + } + return self._request_with_params(GET, BLOCK_TRADES, params) + + + + + + diff --git a/okx/NDBroker.py b/okx/NDBroker.py new file mode 100644 index 0000000..01dcb33 --- /dev/null +++ b/okx/NDBroker.py @@ -0,0 +1,150 @@ +from .client import Client +from .consts import * +class NDBrokerAPI(Client): + def __init__(self, api_key='-1', api_secret_key='-1', passphrase='-1', use_server_time=False, flag='1', domain = 'https://www.okx.com',debug = True): + Client.__init__(self, api_key, api_secret_key, passphrase, use_server_time, flag, domain,debug) + + #GET /api/v5/broker/nd/info + def get_broker_info(self): + return self._request_without_params(GET, BROKER_INFO) + + #POST /api/v5/broker/nd/create-subaccount + def create_subaccount(self,subAcct = '',label = ''): + params = { + 'subAcct':subAcct, + 'label':label + } + return self._request_with_params(POST,CREATE_SUBACCOUNT,params) + + def delete_subaccount(self,subAcct = ''): + params = { + 'subAcct':subAcct + } + return self._request_with_params(POST,DELETE_SUBACCOUNT,params) + + def get_subaccount_info(self,subAcct = '',page = '',limit = ''): + params = { + 'subAcct':subAcct, + 'page':page, + 'limit':limit + } + return self._request_with_params(GET,SUBACCOUNT_INFO,params) + + def create_subaccount_apikey(self,subAcct = '',label='',passphrase='',ip='',perm=''): + params = { + 'subAcct':subAcct, + 'label':label, + 'passphrase':passphrase, + 'ip':ip, + 'perm':perm + } + return self._request_with_params(POST,ND_CREAET_APIKEY,params) + + def get_subaccount_apikey(self,subAcct = '',apiKey = ''): + params = { + 'subAcct':subAcct, + 'apiKey':apiKey + } + return self._request_with_params(GET,ND_SELECT_APIKEY,params) + + def reset_subaccount_apikey(self,subAcct = '',apiKey = '',label='',perm = '',ip = ''): + params = { + 'subAcct':subAcct, + 'apiKey':apiKey, + 'label':label, + 'perm':perm, + 'ip':ip + } + return self._request_with_params(POST,ND_MODIFY_APIKEY,params) + + def delete_subaccount_apikey(self,subAcct = '',apiKey = ''): + params = { + 'subAcct':subAcct, + 'apiKey':apiKey + } + return self._request_with_params(POST,ND_DELETE_APIKEY,params) + + def set_subaccount_level(self,subAcct = '',acctLv = ''): + params = { + 'subAcct':subAcct, + 'acctLv':acctLv + } + return self._request_with_params(POST,SET_SUBACCOUNT_LEVEL,params) + + def set_subaccount_fee_rate(self,subAcct = '',instType = '',chgType = '',chgTaker = '',chgMaker = '',effDate = ''): + params = { + 'subAcct':subAcct, + 'instType':instType, + 'chgType':chgType, + 'chgTaker':chgTaker, + 'chgMaker':chgMaker, + 'effDate':effDate + } + return self._request_with_params(POST,SET_SUBACCOUNT_FEE_REAT,params) + + def create_subaccount_deposit_address(self,subAcct = '',ccy = '',chain = '',addrType = '', to =''): + params = { + 'subAcct':subAcct, + 'ccy':ccy, + 'chain':chain, + 'addrType':addrType, + 'to':to + } + return self._request_with_params(POST,SUBACCOUNT_DEPOSIT_ADDRESS,params) + + def reset_subaccount_deposit_address(self,subAcct = '',ccy = '',chain = '',addr = '',to = ''): + params = { + 'subAcct':subAcct, + 'ccy':ccy, + 'chain':chain, + 'addr':addr, + 'to':to + } + return self._request_with_params(POST,MODIFY_SUBACCOUNT_DEPOSIT_ADDRESS,params) + + def get_subaccount_deposit_address(self,subAcct = '',ccy = ''): + params = { + 'subAcct':subAcct, + 'ccy':ccy + } + return self._request_with_params(GET,GET_SUBACCOUNT_DEPOSIT,params) + + def get_subaccount_deposit_history(self,subAcct = '',ccy = '',txId = '',state = '',after = '',before = '',limit = ''): + params = { + 'subAcct':subAcct, + 'ccy':ccy, + 'txId':txId, + 'state':state, + 'after':after, + 'before':before, + 'limit':limit + } + return self._request_with_params(GET,SUBACCOUNT_DEPOSIT_HISTORY,params) + + def get_rebate_daily(self,subAcct = '',begin = '',end = '',page = '',limit = ''): + params = { + 'subAcct':subAcct, + 'begin':begin, + 'end':end, + 'page':page, + 'limit':limit + } + return self._request_with_params(GET,REBATE_DAILY,params) + + def get_rebate_details_download_link(self,type ='',begin = '',end = ''): + params ={ + 'type':type, + 'begin':begin, + 'end':end + } + return self._request_with_params(GET,GET_REBATE_PER_ORDERS,params) + + + + def generate_rebate_details_download_link(self,begin = '',end = ''): + params = { + 'begin':begin, + 'end':end + } + return self._request_with_params(POST,REBATE_PER_ORDERS,params) + diff --git a/okx/PublicData.py b/okx/PublicData.py new file mode 100644 index 0000000..10438eb --- /dev/null +++ b/okx/PublicData.py @@ -0,0 +1,117 @@ +from .client import Client +from .consts import * + + +class PublicAPI(Client): + + def __init__(self, api_key='-1', api_secret_key='-1', passphrase='-1', use_server_time=False, flag='1', domain = 'https://www.okx.com',debug = True): + Client.__init__(self, api_key, api_secret_key, passphrase, use_server_time, flag, domain,debug) + + # Get Instruments + def get_instruments(self, instType, uly='', instId='',instFamily = ''): + params = {'instType': instType, 'uly': uly, 'instId': instId,'instFamily':instFamily} + return self._request_with_params(GET, INSTRUMENT_INFO, params) + + # Get Delivery/Exercise History + def get_delivery_exercise_history(self, instType, uly = '', after='', before='', limit='',instFamily = ''): + params = {'instType': instType, 'uly': uly, 'after': after, 'before': before, 'limit': limit,'instFamily':instFamily} + return self._request_with_params(GET, DELIVERY_EXERCISE, params) + + # Get Open Interest + def get_open_interest(self, instType, uly='', instId='' ,instFamily =''): + params = {'instType': instType, 'uly': uly, 'instId': instId,'instFamily':instFamily} + return self._request_with_params(GET, OPEN_INTEREST, params) + + # Get Funding Rate + def get_funding_rate(self, instId): + params = {'instId': instId} + return self._request_with_params(GET, FUNDING_RATE, params) + + # Get Funding Rate History + def funding_rate_history(self, instId, after='', before='', limit=''): + params = {'instId': instId, 'after': after, 'before': before, 'limit': limit} + return self._request_with_params(GET, FUNDING_RATE_HISTORY, params) + + # Get Limit Price + def get_price_limit(self, instId): + params = {'instId': instId} + return self._request_with_params(GET, PRICE_LIMIT, params) + + # Get Option Market Data + def get_opt_summary(self, uly = '', expTime='',instFamily=''): + params = {'uly': uly, 'expTime': expTime,'instFamily':instFamily} + return self._request_with_params(GET, OPT_SUMMARY, params) + + # Get Estimated Delivery/Excercise Price + def get_estimated_price(self, instId): + params = {'instId': instId} + return self._request_with_params(GET, ESTIMATED_PRICE, params) + + # Get Discount Rate And Interest-Free Quota + def discount_interest_free_quota(self, ccy=''): + params = {'ccy': ccy} + return self._request_with_params(GET, DICCOUNT_INTETEST_INFO, params) + + # Get System Time + def get_system_time(self): + return self._request_without_params(GET, SYSTEM_TIME) + + # Get Liquidation Orders + def get_liquidation_orders(self, instType, mgnMode='', instId='', ccy='', uly='', alias='', state='', before='', + after='', limit='',instFamily =''): + params = {'instType': instType, 'mgnMode': mgnMode, 'instId': instId, 'ccy': ccy, 'uly': uly, + 'alias': alias, 'state': state, 'before': before, 'after': after, 'limit': limit,'instFamily':instFamily} + return self._request_with_params(GET, LIQUIDATION_ORDERS, params) + + # Get Mark Price + def get_mark_price(self, instType, uly='', instId='',instFamily = ''): + params = {'instType': instType, 'uly': uly, 'instId': instId,'instFamily':instFamily} + return self._request_with_params(GET, MARK_PRICE, params) + + # Get Tier + def get_position_tiers(self, instType, tdMode, uly='', instId='', ccy='', tier='',instFamily =''): + params = {'instType': instType, 'tdMode': tdMode, 'uly': uly, 'instId': instId, 'ccy': ccy, 'tier': tier,'instFamily':instFamily} + return self._request_with_params(GET, TIER, params) + + #GET /api/v5/public/interest-rate-loan-quota + def get_interest_rate_loan_quota(self): + return self._request_without_params(GET,INTEREST_LOAN) + + #GET /api/v5/public/vip-interest-rate-loan-quota + def get_vip_interest_rate_loan_quota(self): + return self._request_without_params(GET, VIP_INTEREST_RATE_LOAN_QUOTA) + + #GET /api/v5/public/underlying + def get_underlying(self,instType = ''): + params = { + 'instType':instType + } + return self._request_with_params(GET, UNDERLYING, params) + + #GET /api/v5/public/insurance-fund + def get_insurance_fund(self,instType = '',type = '',uly = '',ccy='',before = '',after = '',limit = '',instFamily=''): + params = { + 'instType':instType, + 'type':type, + 'uly':uly, + 'ccy':ccy, + 'before':before, + 'after':after, + 'limit':limit, + 'instFamily':instFamily + } + return self._request_with_params(GET, INSURANCE_FUND, params) + + #GET /api/v5/public/convert-contract-coin + def get_convert_contract_coin(self,type = '',instId = '',sz = '',px = '',unit = ''): + params = { + 'type':type, + 'instId':instId, + 'sz':sz, + 'px':px, + 'unit':unit + } + return self._request_with_params(GET, CONVERT_CONTRACT_COIN, params) + + + diff --git a/okx/Status.py b/okx/Status.py new file mode 100644 index 0000000..ab9cf80 --- /dev/null +++ b/okx/Status.py @@ -0,0 +1,11 @@ +from .client import Client +from .consts import * + + +class StatusAPI(Client): + def __init__(self, api_key='-1', api_secret_key='-1', passphrase='-1', use_server_time=False, flag='1', domain = 'https://www.okx.com',debug = True): + Client.__init__(self, api_key, api_secret_key, passphrase, use_server_time, flag, domain,debug) + + def status(self, state=''): + params = {'state': state} + return self._request_with_params(GET, STATUS, params) diff --git a/okx/SubAccount.py b/okx/SubAccount.py new file mode 100644 index 0000000..ea0428b --- /dev/null +++ b/okx/SubAccount.py @@ -0,0 +1,63 @@ +from .client import Client +from .consts import * + + +class SubAccountAPI(Client): + def __init__(self, api_key='-1', api_secret_key='-1', passphrase='-1', use_server_time=False, flag='1', domain = 'https://www.okx.com',debug = True): + Client.__init__(self, api_key, api_secret_key, passphrase, use_server_time, flag, domain,debug) + + def get_account_balance(self, subAcct): + params = {"subAcct": subAcct} + return self._request_with_params(GET, BALANCE, params) + + def bills(self, ccy='', type='', subAcct='', after='', before='', limit=''): + params = {"ccy": ccy, 'type': type, 'subAcct': subAcct, 'after': after, 'before': before, 'limit': limit} + return self._request_with_params(GET, BILLs, params) + + + def reset_subaccount_apikey(self, subAcct,apiKey, label='', perm='', ip='-1'): + params = {'subAcct': subAcct, 'apiKey': apiKey} + + if ip != '-1': + params['ip'] = ip + if label != '': + params['label'] = label + if perm != '': + params['perm'] = perm + #params = {'subAcct': subAcct, 'label': label, 'apiKey': apiKey, 'perm': perm, 'ip': ip} + return self._request_with_params(POST, RESET, params) + + + def get_subaccount_list(self, enable='', subAcct='', after='', before='', limit=''): + params = {'enable': enable, 'subAcct': subAcct, 'after': after, 'before': before, 'limit': limit} + return self._request_with_params(GET, VIEW_LIST, params) + + def subAccount_transfer(self, ccy, amt, froms, to, fromSubAccount,toSubAccount,loanTrans='false',omitPosRisk = 'false'): + params = {'ccy': ccy, 'amt': amt, 'from': froms, 'to': to, 'fromSubAccount': fromSubAccount, 'toSubAccount': toSubAccount,'loanTrans':loanTrans,'omitPosRisk':omitPosRisk} + return self._request_with_params(POST, SUBACCOUNT_TRANSFER, params) + + #GET /api/v5/users/entrust-subaccount-list + def get_entrust_subaccount_list(self,subAcct = ''): + params = { + 'subAcct':subAcct + } + return self._request_with_params(GET, ENTRUST_SUBACCOUNT_LIST, params) + + #POST /api/v5/users/subaccount/set-transfer-out + def set_permission_transfer_out(self,subAcct = '',canTransOut = ''): + params = { + 'subAcct':subAcct, + 'canTransOut':canTransOut + } + return self._request_with_params(POST, SET_TRSNSFER_OUT, params) + + #GET /api/v5/asset/subaccount/balances + def get_funding_balance(self,subAcct='',ccy=''): + params = { + 'subAcct':subAcct, + 'ccy':ccy + } + return self._request_with_params(GET, GET_ASSET_SUBACCOUNT_BALANCE, params) + + + diff --git a/okx/Trade.py b/okx/Trade.py new file mode 100644 index 0000000..2db2e83 --- /dev/null +++ b/okx/Trade.py @@ -0,0 +1,159 @@ +from .client import Client +from .consts import * + + +class TradeAPI(Client): + + def __init__(self, api_key='-1', api_secret_key='-1', passphrase='-1', use_server_time=False, flag='1', domain = 'https://www.okx.com',debug = True): + Client.__init__(self, api_key, api_secret_key, passphrase, use_server_time, flag, domain,debug) + + # Place Order + def place_order(self, instId, tdMode, side, ordType, sz, ccy='', clOrdId='', tag='', posSide='', px='', + reduceOnly='', tgtCcy=''): + 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} + return self._request_with_params(POST, PLACR_ORDER, params) + + # Place Multiple Orders + def place_multiple_orders(self, orders_data): + return self._request_with_params(POST, BATCH_ORDERS, orders_data) + + # Cancel Order + def cancel_order(self, instId, ordId='', clOrdId=''): + params = {'instId': instId, 'ordId': ordId, 'clOrdId': clOrdId} + return self._request_with_params(POST, CANAEL_ORDER, params) + + # Cancel Multiple Orders + def cancel_multiple_orders(self, orders_data): + return self._request_with_params(POST, CANAEL_BATCH_ORDERS, orders_data) + + # Amend Order + def amend_order(self, instId, cxlOnFail='', ordId='', clOrdId='', reqId='', newSz='', newPx=''): + params = {'instId': instId, 'cxlOnFailc': cxlOnFail, 'ordId': ordId, 'clOrdId': clOrdId, 'reqId': reqId, + 'newSz': newSz, + 'newPx': newPx} + return self._request_with_params(POST, AMEND_ORDER, params) + + # Amend Multiple Orders + def amend_multiple_orders(self, orders_data): + return self._request_with_params(POST, AMEND_BATCH_ORDER, orders_data) + + # Close Positions + def close_positions(self, instId, mgnMode, posSide='', ccy='',autoCxl=''): + params = {'instId': instId, 'mgnMode': mgnMode, 'posSide': posSide, 'ccy': ccy,'autoCxl':autoCxl} + return self._request_with_params(POST, CLOSE_POSITION, params) + + # Get Order Details + def get_order(self, instId, ordId='', clOrdId=''): + params = {'instId': instId, 'ordId': ordId, 'clOrdId': clOrdId} + return self._request_with_params(GET, ORDER_INFO, params) + + # Get Order List + def get_order_list(self, instType='', uly='', instId='', ordType='', state='', after='', before='', limit='',instFamily = ''): + params = {'instType': instType, 'uly': uly, 'instId': instId, 'ordType': ordType, 'state': state, + 'after': after, 'before': before, 'limit': limit,'instFamily':instFamily} + return self._request_with_params(GET, ORDERS_PENDING, params) + + # Get Order History (last 7 days) + def get_orders_history(self, instType, uly='', instId='', ordType='', state='', after='', before='', limit='',instFamily = ''): + params = {'instType': instType, 'uly': uly, 'instId': instId, 'ordType': ordType, 'state': state, + 'after': after, 'before': before, 'limit': limit,'instFamily':instFamily} + return self._request_with_params(GET, ORDERS_HISTORY, params) + + # Get Order History (last 3 months) + def get_orders_history_archive(self, instType, uly='', instId='', ordType='', state='', after='', before='', limit='',instFamily = ''): + params = {'instType': instType, 'uly': uly, 'instId': instId, 'ordType': ordType, 'state': state, + 'after': after, 'before': before, 'limit': limit,'instFamily':instFamily} + return self._request_with_params(GET, ORDERS_HISTORY_ARCHIVE, params) + + # Get Transaction Details + def get_fills(self, instType='', uly='', instId='', ordId='', after='', before='', limit='',instFamily = ''): + params = {'instType': instType, 'uly': uly, 'instId': instId, 'ordId': ordId, 'after': after, 'before': before, + 'limit': limit,'instFamily':instFamily} + return self._request_with_params(GET, ORDER_FILLS, params) + + # Place Algo Order + def place_algo_order(self, instId='', tdMode='', side='', ordType='', sz='', ccy='', + posSide='', reduceOnly='', tpTriggerPx='', + tpOrdPx='', slTriggerPx='', slOrdPx='', + triggerPx='', orderPx='', tgtCcy='', pxVar='', + pxSpread='', + szLimit='', pxLimit='', timeInterval='', tpTriggerPxType='', slTriggerPxType='', + callbackRatio='',callbackSpread='',activePx='',tag='',triggerPxType=''): + 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, + 'tgtCcy': tgtCcy, 'pxVar': pxVar, 'szLimit': szLimit, 'pxLimit': pxLimit, + 'timeInterval': timeInterval, + 'pxSpread': pxSpread, 'tpTriggerPxType': tpTriggerPxType, 'slTriggerPxType': slTriggerPxType, + 'callbackRatio' : callbackRatio, 'callbackSpread':callbackSpread,'activePx':activePx, + 'tag':tag,'triggerPxType':triggerPxType,} + return self._request_with_params(POST, PLACE_ALGO_ORDER, params) + + + + # Cancel Algo Order + def cancel_algo_order(self, params): + return self._request_with_params(POST, CANCEL_ALGOS, params) + + # Cancel Advance Algos + def cancel_advance_algos(self,params): + return self._request_with_params(POST, Cancel_Advance_Algos, params) + + # Get Algo Order List + def order_algos_list(self, ordType ='', algoId='', instType='', instId='', after='', before='', limit=''): + params = {'ordType': ordType, 'algoId': algoId, 'instType': instType, 'instId': instId, 'after': after, + 'before': before, 'limit': limit} + return self._request_with_params(GET, ORDERS_ALGO_OENDING, params) + + # Get Algo Order History + def order_algos_history(self, ordType, state='', algoId='', instType='', instId='', after='', before='', limit=''): + params = {'ordType': ordType, 'state': state, 'algoId': algoId, 'instType': instType, 'instId': instId, + 'after': after, 'before': before, 'limit': limit} + return self._request_with_params(GET, ORDERS_ALGO_HISTORY, params) + + # Get Transaction Details History + def get_fills_history(self, instType, uly='', instId='', ordId='', after='', before='', limit='',instFamily=''): + params = {'instType': instType, 'uly': uly, 'instId': instId, 'ordId': ordId, 'after': after, 'before': before, + 'limit': limit,'instFamily':instFamily} + return self._request_with_params(GET, ORDERS_FILLS_HISTORY, params) + + def get_easy_convert_currency_list(self): + return self._request_without_params(GET, EASY_CONVERT_CURRENCY_LIST) + + def easy_convert(self,fromCcy = [],toCcy = ''): + params = { + 'fromCcy':fromCcy, + 'toCcy':toCcy + } + return self._request_with_params(POST, EASY_CONVERT, params) + + def get_easy_convert_history(self,before = '',after = '',limit = ''): + params = { + 'before':before, + 'after':after, + 'limit':limit + } + return self._request_with_params(GET,CONVERT_EASY_HISTORY,params) + + def get_oneclick_repay_list(self,debtType = ''): + params = { + 'debtType':debtType + } + return self._request_with_params(GET,ONE_CLICK_REPAY_SUPPORT,params) + + def oneclick_repay(self,debtCcy = [] , repayCcy=''): + params = { + 'debtCcy':debtCcy, + 'repayCcy':repayCcy + } + return self._request_with_params(POST,ONE_CLICK_REPAY,params) + + def oneclick_repay_history(self,after = '',before = '',limit = ''): + params = { + 'after':after, + 'before':before, + 'limit':limit + } + return self._request_with_params(GET,ONE_CLICK_REPAY_HISTORY,params) diff --git a/okx/TradingData.py b/okx/TradingData.py new file mode 100644 index 0000000..0d8bf70 --- /dev/null +++ b/okx/TradingData.py @@ -0,0 +1,55 @@ +from .client import Client +from .consts import * + + +class TradingDataAPI(Client): + + def __init__(self, api_key='-1', api_secret_key='-1', passphrase='-1', use_server_time=False, flag='1', domain = 'https://www.okx.com',debug = True): + Client.__init__(self, api_key, api_secret_key, passphrase, use_server_time, flag, domain,debug) + + + def get_support_coin(self): + return self._request_without_params(GET, SUPPORT_COIN) + + def get_taker_volume(self, ccy, instType, begin='', end='', period=''): + params = {'ccy': ccy, 'instType': instType, 'begin': begin, 'end': end, 'period': period} + return self._request_with_params(GET, TAKER_VOLUME, params) + + def get_margin_lending_ratio(self, ccy, begin='', end='', period=''): + params = {'ccy': ccy, 'begin': begin, 'end': end, 'period': period} + return self._request_with_params(GET, MARGIN_LENDING_RATIO, params) + + def get_long_short_ratio(self, ccy, begin='', end='', period=''): + params = {'ccy': ccy, 'begin': begin, 'end': end, 'period': period} + return self._request_with_params(GET, LONG_SHORT_RATIO, params) + + def get_contracts_interest_volume(self, ccy, begin='', end='', period=''): + params = {'ccy': ccy, 'begin': begin, 'end': end, 'period': period} + return self._request_with_params(GET, CONTRACTS_INTEREST_VOLUME, params) + + def get_options_interest_volume(self, ccy, period=''): + params = {'ccy': ccy, 'period': period} + return self._request_with_params(GET, OPTIONS_INTEREST_VOLUME, params) + + def get_put_call_ratio(self, ccy, period=''): + params = {'ccy': ccy, 'period': period} + return self._request_with_params(GET, PUT_CALL_RATIO, params) + + def get_interest_volume_expiry(self, ccy, period=''): + params = {'ccy': ccy, 'period': period} + return self._request_with_params(GET, OPEN_INTEREST_VOLUME_EXPIRY, params) + + def get_interest_volume_strike(self, ccy, expTime, period=''): + params = {'ccy': ccy, 'expTime': expTime, 'period': period} + return self._request_with_params(GET, INTEREST_VOLUME_STRIKE, params) + + def get_taker_block_volume(self, ccy, period=''): + params = {'ccy': ccy, 'period': period} + return self._request_with_params(GET, TAKER_FLOW, params) + + + + + + + diff --git a/okx/__init__.py b/okx/__init__.py new file mode 100644 index 0000000..a79ac7a --- /dev/null +++ b/okx/__init__.py @@ -0,0 +1,6 @@ +"""An unofficial Python wrapper for the OKEx exchange API v3 + +.. moduleauthor:: Sam McHardy + +""" +__version__="0.0.12" \ No newline at end of file diff --git a/okx/__pycache__/Broker_api.cpython-38.pyc b/okx/__pycache__/Broker_api.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f22616ab3fc0292cd72b5fe28a349820d88575e3 GIT binary patch literal 4795 zcmb_gS#R4$5GF;6lCSuPox^Dkw@DKvRhpyenYOVlI(6e%fu$6PVSu1HE1QTcsY^Po z4Ed?~4MmIgAp!c5w?5?8>}!Dn{Q-UN%!;Q?J8hb^IhZA9m-~G)J3G|Fk&!_K+t1zK z)_)pRls~AGY&v%C;N@LH0Sc&1WlLRERnl|KTwS@VfClm_ls`-iKpw9JOJ%1}ESoY9nwR zrr{K7N8kp$1*cIPg`02&&Z0I3AHX@7L2Vpv!Q1c-Y7_7woQDgj9ffxh=SN~-j<+8( zKKo#CL8#Xq1CfM{^desKczGvK_{uZ2r}WfbuBY|%UjDg3G}e?C>T)T^b7&!omgTlw z-?B=E&^^{{h=Sd5t;eh@j*#LphcjRH2RpXsbvC)}F)_OBF?`0KFmCzo7881-X>Ytx z_z|4+??)&qpRRSfYk&UoGUNZp-)oh7Yt;^Gl@Ui7JLPX~t+gM2U+#4M&33Eo!Q(Q% zz5GPpUF$=(@Xpmvmy;I>sz(46b!Q@CVrXuqde2<37MB;QNFMPljJ|;c-4__q ziWpj#E<$1(?E$>uQA{hUuI^05OHJ4a#gP_dg^ku4t#=wbeFuX2tG260>(*)ArQ9;E zy5McE&pM7T@=bf4HHBegXX!~v<6}5l=nty3x)`5dF=y+hReLx$J3n82xLhygB?^8F zjregA6f^uN336is(KrTy?W4!H*KzLlcFP|@g8`<_c+cJth<<6_dd)2ETt9?D3lO8R7y1E}bj2C8;Acr>K^l#HAOmbF2850{89QQ+okP@zjlwN*19_c7 z3j7%8GRoW-InLqyB#J9&gO zWCdyWrB+~#Mg_M(ih<*M7+5e(i*{M5m>}Uiu7_VB@h*vrBYl=M(^#q=OK`CTI-#|X*E_sP*5rz`T#rtP*w(FWj>pPb)L z(J-Be=8B2gX0dL~Rw^rItyU@|n7Bfy-y=~bag{_?h)*XX16Zf+;rT=_XP!5MV*(z= z)SdGQ9-_=-?HS@wbcBu4G4&-CZ=(`Z(KC7lq@%D~jOZwabQJnqfB*>H|9%lf-t*Bd zB5yZ*j1yy>HQJoXT^mv(H+mK|UoF<^)s;u3fxXmR$LaYE5;sYFK;pnWkVVp_>-lZo zrC0NsEhhR$LG*wZ~aC=6%;sqcYG4BbDuj> zhOf6ys!MY`+R-WI$Ab*;0E_ABO2u5Mg*8KDpUL%ju%&U|S#1uCd!MI3Bx=xomjA1k z!;FvR!G1Jye@x-G0iO9XrzH>t_1xFwi^E|}ZD4h?Z^5%MG_2~*#+yFV`VH-w=zJDB z9k=p;PPuL-*fIb4yuVL89C+T(1Uuv4W8aMFz-@IUrsI_(F%B0vmAVLoO66FTRH^U3 zpG(*nv7V*jCscaUxQl1oL671GhmAjE>f{RlrCD;wJ|+&CW0HO$XxUrLvc#ZeA>Z3g z(uXbU+iknqe_AVF0aC*ShBBo;|5k*Jc0 zzd@x&pVmD5aPg>iE2@K9Q6D_yPuee+bYVF1XQBRY9){D#n%|QTv)&?#xBEE1pq~-s KsWq$?wSNG{{{XlE literal 0 HcmV?d00001 diff --git a/okx/__pycache__/Market_api.cpython-38.pyc b/okx/__pycache__/Market_api.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d2d5e4d33fdc2aefa05332774067f7d519a96236 GIT binary patch literal 4452 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 C+~f`b literal 0 HcmV?d00001 diff --git a/okx/__pycache__/__init__.cpython-38.pyc b/okx/__pycache__/__init__.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..56cc821d3516125f535d6a6ec1c1ff7ce39d6acc GIT binary patch literal 283 zcmWIL<>g`k0+!SzNohd(F^Gc<7=auIATH(r5-AK(3@MDk44O<;QI2^ErFr>jX_?8H zi8%@Zl_eSZc?#u4i3J6zMG9&8MG7SusS5tyt`!QY70DTidFiPNjsczuWyV}wdU^`E z`6;D2sfndPT}4(_3c-oF3ckr6iA5=uTwH#djJMe1<5TjJoa&*H?WAd{rbPK@F(=ATP)=ezP)GY&x#>B^G Z=4F<|$LkeT-r}%zz0wN^Nk8;9ybpx3ASJra9XP`wpswSGjqd75I3l;KS!XcMR0a)~xnp=b6$ z9S>>R4ySmEXIC%d{^1OO8wPN=0N4rVrO^PNi5o;mNBRlm&Bq2YrEo+ESxMpx8K}W+ z(Ez8+1FgZ7Tg;3iv)P>78P+JFYfo&5&YXHTu3T4?iMV7x@w_}{dpxO=6KdsTx9F+_ XKx$b7U>gqS*MDc+bdU1=NGGSi&tGLh literal 0 HcmV?d00001 diff --git a/okx/__pycache__/client.cpython-38.pyc b/okx/__pycache__/client.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..aba0e305dae2d8e0d926b6a5f3644f3d2e5f898c GIT binary patch literal 2062 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 literal 0 HcmV?d00001 diff --git a/okx/__pycache__/consts.cpython-39.pyc b/okx/__pycache__/consts.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..23716f33fbbe03e66785590999ef49bc898eb7ab GIT binary patch literal 10898 zcmb7K_kY{Q*;j1Gc5GS0mS>zjodjl_(Kc<81|lH|5tji_ww?|Y;sZ&DD1rt^*2A}#-t}Mb*Z05ZPkrtVcK|`!aqW*p-t#9_ab8rqH zfk*IBcoZLl$4~z37>^$@i}-7pNHr1&G2S?0bW2IbexBIEJ6`WP(lL?Tz~~!ghgC}B{adr z7vV)*hGi^687ol1DpausHLOD&FTzE%z(N~rbig4$HLw9IxB{2(5?sd1u!^ey2=Eqs z3%nKI3U9-=!Q1ie;Gzrfz;}R$9<1RSG_eVY2tN9-j_a_28?cF+5MTf=;Y+ZEThPK5 zY~wbxi5FrUIvBzg>_CK9AjSx~7()-cu!B9giaT%(ufi@~gFf!UJFyS%!gs>E@m=s9 zd^fxo-vjT%_rm+}eeeN%KYS2B059VQ;Y0W`d>B6jAHfg9NAV-@G5jce96tu1z>mWx z@e}YV{3LuDKLww`Ps3;NGw?b3`8<9WzJQ;DFXHFnOZ4+)`~rN1;Scy5_#^%n z{)E4SKjW+L7yLc^75@N#!#~2`@lWs%{4@L${{sJoe}(_Xzrp|D-{F7pANIt#fA%Mf zVY}{`PbZDE4)&8+`?3fk9cJxZUKbI2gx^35&EZsH+ z`}Jni?{o+Ii($AG`27Rru<5n@=lU~Vr_&0WUN;Eag_q*6J=nWwID>uln(g$D6}(PR z*m=6p>8+7ap&M-b{Rbq`Yc|7PyIV*;wN4lZY#A*I;;sJ4yx5x8^4d+me>%^Q^Wy&T zJZmjzwc`FAW67EqH8+DDzkednZiemkV55Ieo*w(%RLSiS{r=f;A}xQ%kGu`Pe=5)2 z_O5Ah(D(ayj^lVcUeFT!hw^-BV`1BiHiEV$oiSpX+*}LV>*06}TA|k-^

j(AU;| zzkhdr^MFz+^5d>Xk&1dgjyhCHL|)hLpUE%49Jdkq{#HERsX-jJXd-IdsbigUHRx_) z=b=sy}O#safPG_k2+Ye&D#uLq5pVpa|~jBAmJgQ{+Tqrb!uGNm0sBO z(&m+{*b1)n0_25FiGZv`)afJ>Iw^AomGfEPDw+KCqVEy$sM)Y@e* z_-M|gouHE%l3zzbjoL8oQCpx|VPQy{Wx|$VN1v3I&92rAgLeNhxntB@3$_ZZ3l~_{ zGB_d6c!jvv>4b!lTv|bJR@x(Mku|0|bVh(&NJpLm_W;=tg#D+-Y%0}?Ns#uAH`%80 zXep*$xZ$*+w3YgtA2TKF@Wbv{`KSIfd6sI|vF8T6PziPd0`YNfxY0B!?qJIw8?t0t zm&ZcDOM-gp49~Hsz|%Y}J3(CYy3I{l0jgXDFKM%4p2FuL-q3WF-9p48G(xd-+Mlzm zp~(u0lJ#35;gqbi6oUmxY71F_jY)xT%9u zW?ju|ZG?FrCw^qCI6dx&S(1l4ynKaB&ew^xjHgV#frzwQwE?k{@5Q@R%Hr6Qoa%Pz zj1_nD`er5b`eu2`6AHT$Pqe9L)1`4soZYqI%@lTx6;AJ%W7%p;)qdnvH14g*uj=Hi z+K4!iW<_{-ACx8Ei>Uz+-l-+%HWRGxYIFzQ@^@4CACcqkQ?VG?hHMaLb#-$VD^Qz` z*ugX1Q3T@LbroW#O}UyD_PS|98`)Huug-#NQAj{tXk&q2EtT(5dNcCbIW*O$KSqeo z5&p1{vOHZWT|(Srm5(zbWJ^Yj-FsVoW%_mH=z=SbTu(?Z3DYwZQ~=h=;A6Za?Uj)_mAT!(tHfQv)jD1frALurA$g$V=ORBnX%0(q2uQ1Mm?@*A z)JPn>j)hT2sLmFxUn%gTq91j_j^oW9WfME0W*#~5c|whG9HEHdq=zzQmf#3gI6rfx%_)YBz_+uI%L0)$>EuyZm$t)!P0jU>9%%5(jZDDz>r zun`3)jxVCW4t2JyOy6VqG=S3Y+B|>nhg=GcDHQ$>Omic*8!svGiQf^>9 zRjMp%1-f~gu%(j~5i0=jC&93O(|2UO>1I zdD|&?t_N+Fxa|J1MUE#RS`P~0Iz8cv)0`PABp*P%##-$0l>b^AisDJpdhCWW7n)u6 z@L2`+MzS&sR8hpcao6AGx2;}WJ@JKhSf3Ib_fM zfu8%zv3l+g^xR(()93!MUoRR)-GTkZT5Z{+_W1-wv#i=B*D~t*D$Hd^?viOcHER{7 z)m~+@VmhRbZB`n|7Q%-8$=9(59&8t^jK6fx(GPsDVmr7)iJ>cwly{uR1wb5W| zp;0Z_%z;&V!LSBX@|#O9iyUJxof_g6Yi4yYBi9qknyZ5&#fD`W)#56T^kAmmpg7Vi zB{H#ORO-&)kO(ge{9sm2FPn=?PSva~4(2jjq}16WQ?Tr&%)znrdtxl@evFcYQo(Uc z6lIs*XBmz?nC74Eie7H;1Rl(YoT-**LmuM6blDK2#OZ@MNnr7n&dgEmMul={b#Rnr zkgcz<)e=|2q+=GB4a*k!eprl>O~tH6c>E46Z?QZ--|m3pm8bwC+wT&56J z7e%_ml-x5};mACJz_QYJGCKr0VkJlFnpNAe8oa!CWmAC5RK(V*Yg{(0qG>a*svA}E zgs3Q(WGN@(0CU-qbUPdt7V;D(f7Qv`!u2psMQK)ewQ(6ZQ8E?KI0hAOf;flmRogKt z9HiiA*}T{=O9IWf`)xSH+~$f!_Bp0uWon$`!6DMqu*$2XE1X?1>&gV4K^!yOi;bG2 z!xVX;K_x^%VdlVbnUoB)DF_r^svSbEM!jC6Toofnr+jgFv<#RdZ3vtQmy~nN8qAby zlw$T0n?!j@l+$uamS_n^B}<$nKM`7wGN$ScmSE*_vc~O00ZBBVc-2h;pA)%d2?#86 znGjE?yHKuOqVSaUqUCZ&QbOoXaY+npn50D2scr@DSTY(CIjmEjm3heW;b^qLaEb19=(4pHZ0wUmP2iQ%y;drDGs3#{!>Clr(TNafrNGsMDf9xa6lj(S^kFi~qn#2V zPL=adQt`S)>dDKZc~D94Y=Y?=14bm}5(gw$-O3<2hFhs47!KUFVj7pIUyvfl?8dxo zzp@p;NdgUv!E1)er8%rRmd$&ITWdIQmLa1+-;A)__VBz_V>vI7qG%ZmYEwC2;6Wvv zB~7PnF^vu%!-~*JpbRH-RNl&Ic{r1qFMChY3di!Kt0paja?)^1bdp$w8Om3tE;Fu9 z)gUM~X-l=8q0j-qTv*Lg5{nX<GM9Ylh9RQ}~P>EdyB%WR5-Rr_=^&1iiQnptc`7+cx~)>Flew&DPV=tIa#=M%B0CI}rWY+U!8eW_ zaGVn|uqViKoJ?oFx<~{;J(bS3IYoipC`ZL-WR5smlRL#8jd_`CQ=A~dm0*pJ<_gIQT3*PwTb(=h-DHewqH# zao;V;|2_P3&p!6KXWw2$m;9UgyxCd%UUT)ES!tZiI9gtFVX2_zHF@p%sRa9$j`F*V NU!VDwakBIF{u|x^6IuWO literal 0 HcmV?d00001 diff --git a/okx/__pycache__/exceptions.cpython-38.pyc b/okx/__pycache__/exceptions.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9f2068bde3888d5b59cadced75b33c231afb3cf6 GIT binary patch literal 1863 zcmbtUOK%%D5GJ{+)mo7qBToHD9cK|B51~~~&BaKH6p2x|Eo37?(?k$JY((0TCG9FC z6pDzrHNw z2>An*)58bl5lsCREZ-7A1bqinl0C0RL1)4P-E%qv-4{8~b58d}P$i{&13bqD1MLw^ zy$p*aH7ZDr2`bn-QuBl-e0V|}@D1$cjn?iro9k=44cRr#G-;soXm}umFdxIzzrkY2 zknT`H7l>gXd3zx3Q3_=a3HJxZA>Gd%khkn7lHBx(30ej9110zq-hLi^4=8*Yz97ki z=g`cM?N1$$R-lF=cOnm&@RtZi1S#jFFe!=vEh3Npm>Ztn5Tg~$r6Coe0LVZq3IdHy zRR-+K=r1Ul4DPHaZ{l`SMBi06Dv?wwRZ&N39dFBMOQoF%AXtrlerx?kDx~!~dfWPy zG?9a1wXcorWIi^pH}H8iy|riJAk$ z-!EW!vRd!<>wmugeZv2j57j5%*EhN{DFeS{P|DBl*VEQ+x!X6d(xj|Ks~mTmWTj0Etie4M#BImDraXWjXKEpf<W60&g4SsI{>jf$9aJb!r8xn4eGz0(0HtJ%sm1XKCp6%7 zcOAnV(cmexd=d>;ppwm4#T|WN78I6}^^7o2g8wcSi%1eWz@E=!`Y810&&T<1@V_`! z$hGqU{s;CEM7WJnjIo1OVKPUcRz^QV40iOz&8~Q{=L2cE{St ztn#sSC0~rBHmyZl8>%!n);IFNSWg>euV@pSk>(geA!^p&(?xC@&*H&IKER|l*e+BS z8(TlkZvDO-Ya1%5hefWXt?x*PVw4IXK+ChfmV<4z1WGT&XdJ#gA!->6f4yu!)l%tp z(U+>7$#jsm^=>+ji_LO(#6_HF9vfctcQ%tEYu~x^b^E6x8D%mzx;-2xyRpii7plKC zh!Y7x4mPytyL~t|yG4%bMm$V6_P<4ITTYLM-W-l?$a$KlhI1^`9Wp}KXh0cl!gGzS z(FSd@fCelCYq@seh;2^Y6AJ#*fifcJ&Kfo?fZaVf2YYmztstwcQ{IH58a=6qh#ai9 z5c2On)2+J^EX;wg-UIg&s;nZ1-g1pg$iii3NkEwyZ*ysvq2N;#=3iV4 zhSPzGKOlEi;P27}Tsi=aLx@!fp?m=**V4yepF(tFPR4)caVB-e0HsunskPY%Z)m`O;YS$elm<_s<(+7_3YBcdD$ev3^ZWayibwga75ZLO!@0;6Gp=L4?mS${F@(>9l;iaE6?_6^;{y XFV7)z#-R=GRX6bav-`BPzO?W+t@@kX literal 0 HcmV?d00001 diff --git a/okx/__pycache__/status_api.cpython-38.pyc b/okx/__pycache__/status_api.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fc7e9dc7ceae5565633501dad1e0dae72e8b3bea GIT binary patch literal 820 zcmZuv&1=*^6rY#LX0x%|7E$r&(FiGc@FF5D{X&FQ*sb8QFvQH%4V%rTGn3ja@nru1 zPhPyV;KiE<|C+f9f`5Q_-%O}h=p*mtedYH)@(%j_h#>jm%bSlt$Pa5=B_EAVWOW|} zCmaeghcSTFy}}!jeZndC&j|Mge4t~>J3|r&zYvSWV1n%;7o|oG9%ShHk0@H3$m$*n zLB_zz*yBBi2Z$8$fOpSe?DG&YZ^1Jkj!L`=;sCdE-LlxFX8J!MrY)44Kqe|Kbp;b?1g zFpR0}B9>f7VS+Zn&EJYu=Wbi?p|0!|5eVUQ{a?dv82`qev<=1}*X*lf|4W(91!E>+ zY`)-iVf7Wpj_R~%BW@A$Hs)WcYWFW~X=%$@OjkFAh&s<8_Dztvdu$IN$QGs2$_1~( RG2xT8{8M|)4r~QN`Uj2#$Ke0~ literal 0 HcmV?d00001 diff --git a/okx/__pycache__/subAccount_api.cpython-38.pyc b/okx/__pycache__/subAccount_api.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..48781463f3f410d5f076fef090ba961b522cf0ed GIT binary patch literal 2775 zcmb_eOK%%D5MJ&}E5)zaj-7X$wkfhLWHe|~pbr$0WjQfoD262`fZ<}XTGI8_t4GL{ zT^aJJ`3=3ahXm-ww;uXycr8$%KcM%{aJ4JTk&B`TB@TwrZ?yW zorInoy-BC&G-wXJMQ7+`(DL*)ouzZ273dv0Pp^P>i7wDZ_;P|?1$0Ytves>sf}q`P z#ih;lHAx->2qrD4J5b9|#Z?fo_L}syKI!Xyqi^=DH#TknOhu}$&ULVmj^~A~F!nsx zmZo6Qp3M23&^ur~IfaT~0cWvl7dpNWoqg^LCa1fC!5BYe+>65|ljdIJe|M_!NtpES zZ$Yenx!dXO{`vFoWBxz=R$G0#`>exSMc`3{M)CQ>-S)u`#ZE8YZ?}qq9u#5q;-Tu@ z6&Y<0dY3yrj#RMUq)$R}qW87eT1;ZSufH*B z+NoZZxn#xIHRQa<*~=~yv3C^4`(DTAep5)}aiuPEE2WK6wOlzhcn+rHGa#g$Sg4Ii z#1wWr4L|Z*0TU3dn!xbXi1QZi)JSRp&X^W-Dz+8!B~XSg?c0?6VxQzP4msrD>Q(Tk z5d=MH#=Quc1I@{5pyo zC~l&-f&$%rhNaaAqex)qfZ{AUo*Q+IvIx`$fEgC_N#++^Bw+`^Y0 zV6!0{p0eJ6gETjv)#}n-t!z~471v5w+<_Sr0!yfkgKbk5v6$gL3~*17os`Oae^)v|#XM z0f#}30SDoxpBP!V8ELrb!`Ml|C#mwHR4+eq&0*>%{ut|pBR>xIZ^23fn1#2}LRpNQ z=9ut!#HpmeJwTb9CtZ$q-gZ8?S7a8)@Gx6iclQQL3Tx!)2gdzDplwe6Ksx%_OqTKDQ(rD|=hvgPK_ z9C{CMB@3q({8P~RXDA+`_#DMJC(nuDEfwREdrXDzV0Y%p@!cUZxb~LE*#DpVicbTg zl%5LB#Y(llwOy-wXK13U`8;AjcVsWZJBN4SdILCq^0rWp#q=9MhkNSYDD(@yfmg*E z$INnVzKCmGBwV6~;1QBpq+Qmq>ztNaOyZ-ZY^6|p?3{Vv zsoXWb>PENktih{1?{$RIgM^oT<8}v8Y@DHZYP`L%7Rvau*T&zAlvrCe`MtGO`!P{= zO>Q8RiaMg1S0a`|?})K+@C%f`Ao4nd{ci)r=I5<+-1_IYKi}~C^^f}IPHQ(6!%DTb zT>+!={hd~F_^gtSbvGGS6hEv)X|M9cdRrsi>#I-Gv2j(eGYl|2m?uI%q5+lff)-=$ z&Ijr^Z64nPMU#viQB9^aqbGEUWDKUWL?B-@EHmRMEsZxyQz7AkdEJ96>S&M}e;^

mHyHIJEqF!C z2&-St8<+QDZD?#3s<56wPly-O8)s2m4LPzNK?A6=wN3{TgP@fiQ0iJo7Q2bB87h_MIkJpNS z54@aCXhx>wglv)@ZnfBiO`MEsiWyxZ9H0QYV|9SUgg!1p!$E`n!fqfy{P2u^c}BlD zqaRB==kz}qfEll+#X#AV0A~C&lF>jJXC(W^feRb&Nz@;St9M$2eM$g~aCciLZ9pD^ zL?NgNb?E|Kp>h@U7#-&W;dFuM6)=Dq0L{?*0GBC4emG%pP0DAec0)rO&ElZf@Asff zlOb1zHp`9)I6wpOZTyjrhsjfu@2O-zk%LHMBcO-st5KJ*5*J-@3(kMpe+4LpTnGC# zkmFr0c&u-u#RPMD$ka0QBI@jr$(!5(?s`LS&h|htJk1V(-7?oQ9s|t-()EA=b36bB z^fQ0zK^Ah_pXRchWx#y+oc%O0ZkP;(ArjLju?1xg1;!@xAj*NQom@u89Eu`}5(;c# zc?|_(4t64NB{GS8AH_`&rZA&Fi|)73iy)PYD3Ana!cs#XSu4^bDG;p+&mnXfioL>s zz?i%bcDXbQ0#7wA=30IRszd}!WDNNs3gkKq7z=z06q|qhjaSaK5zKgL9aw(U7xxgn U3jG1}4L(ID@B=rP3vz+~Kjw9*r~m)} literal 0 HcmV?d00001 diff --git a/okx/__pycache__/utils.cpython-39.pyc b/okx/__pycache__/utils.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a801254bd97258fa00874207dbacad721c775919 GIT binary patch literal 2180 zcmZ8iUvm>T5SMg+d^UCn31Da`rF5npw-^@+lxb;8CS*#WIG);_77rcI<)qk$eLf?} zP^ago&_}+5^O&!s*FNzT^3v|gZURxF)$X1w?Z4kDER_lb#=~+ox|$>89~9ml4hZ*Q zsvRJla5^CE`AXZ=%B;;e1coDcf zFYzVVRp6)jGOVZg8NLE*k<%uroPP^CsRkeGcR-Y@fyEw+_B!ddq7PfhEdAnVfWAjP4%wv zRWH1G`_2KH8h3@#Ny;m}aeGM^8D}V78E<={g);v9v+=h>CGOlZ`RzNm>|vtfnp`53 z3cI46S0a)^KNb_?;0cr;5V;CwAHJ;ps)SUvv@c{W5%D0dsa`w@)9bsvafgSI>V&$J z_Pf`kG^yRV@pbJ%8jTY%)T%a`M7>ZZzooL@7=)34L;kEP-nZ*$qI>BO#cDW;t1oY( zwl>!BKwTeAjH}}A5E4!lhLO-KG@$YvaIMHg#bO|jv9@u(22AF1+Glb_6V5Vck5Qs& zM)s(tGl>2^Et8DFbjk!G?9^Mk{&vbI-(IOW#v93asEwnvG~ReL60+i%ypADAI!s2! zPXw6EO;L&$W6*U*q3#(Me{Vc4w#Qu?vN<^mwwPcfMW+|4UJ0ayBLOW?c^Tx$ItC05 z^b||k`tb}HP4>vt*Yr8dkUIBBMl9z7M=j^wBihf{-dxIo-m&@sI5+b-h1KH>qVc=V zbNGhQ$owWbaO=CPkcl`M4?-v3moeSM?Z>^$ChYL<@0=H^dzSq5*+>anu5`DCNn zT6@wkXOESQwPv&N@RzmbhCC1ZD>;*cs_68^#3o%{#6t?BP^nQ*LM0n_XApMfN2vDa zMxP9Rp(}J}{s}8tVMYk`X%P}opi3|V_=99%*}Ml{OvF(#z5>A}gV|&tohO6Y00W#M zz}K`30cJM9tV!g@@S}<+ufQTdL2?zzr%0@Oj{E|7G+%y+1TB20a8{0O?+nupVgZj- zMIdt@7PePGj<65?KM)K@fOrG~r&9pHjO>#KiL? zIF@(IWJ+JaSMG8DZ*~!+3>#9een@{b)U@}RG9H%EfQr@4Q<6Ag)&T( zamI3B9LS;ZUWS9QIO*jo>{9|@gu6Q${M7PuICbHsOP3)*muZp7yP%C=9u4fZM{XjT zpudtCg$@chnL%ne+h=GtItHe@bwgY2ViFGqG4#50$d#dO0DZs#0f=$qk99OmUzvQY z(w$T$p$5ks)KGoW@)G9fs59Jv`xodgKzYggAivk80#F>i1_KZ@V091Pf<99h7Ce^G zCGNlr03JZU0&kA{)qD@6#nbFLyb;jl@ZDg*L5h&W#|+*PKl5iEL?NgBSuV@jcO+lm zWq(bLTTh43!{K&`k(1auCH5VO=E*#eN?=ncFQ5Y7U3m%#R-MEaCYO+$1_C<~lJWy2 zA0oK~#1!W5h{f$PYR@29L2{zP^H|fN9!v2Jd|hPx0(I$S2CbgSbP z4o|agAV%l#!iT{&RSRZ`sIWC-Q(@0~=YDI+yg%QAXLCFdKVU7}27#~&XweD$f?p^W Jf}jxi{{dou len(bids): + break + bids_l.append(bids[count_bid - 1]) + count_bid += 1 + for j in bids_l: + str_bid = ':'.join(j[0: 2]) + bid_l.append(str_bid) + # 获取ask档str + asks_l = [] + ask_l = [] + count_ask = 1 + while count_ask <= 25: + if count_ask > len(asks): + break + asks_l.append(asks[count_ask - 1]) + count_ask += 1 + for k in asks_l: + str_ask = ':'.join(k[0: 2]) + ask_l.append(str_ask) + # 拼接str + num = '' + if len(bid_l) == len(ask_l): + for m in range(len(bid_l)): + num += bid_l[m] + ':' + ask_l[m] + ':' + elif len(bid_l) > len(ask_l): + # bid档比ask档多 + for n in range(len(ask_l)): + num += bid_l[n] + ':' + ask_l[n] + ':' + for l in range(len(ask_l), len(bid_l)): + num += bid_l[l] + ':' + elif len(bid_l) < len(ask_l): + # ask档比bid档多 + for n in range(len(bid_l)): + num += bid_l[n] + ':' + ask_l[n] + ':' + for l in range(len(bid_l), len(ask_l)): + num += ask_l[l] + ':' + + new_num = num[:-1] + int_checksum = zlib.crc32(new_num.encode()) + fina = change(int_checksum) + return fina + + +def change(num_old): + num = pow(2, 31) - 1 + if num_old > num: + out = num_old - num * 2 - 2 + else: + out = num_old + return out + + +# subscribe channels un_need login +async def subscribe_without_login(url, channels): + l = [] + while True: + try: + async with websockets.connect(url) as ws: + sub_param = {"op": "subscribe", "args": channels} + sub_str = json.dumps(sub_param) + await ws.send(sub_str) + print(f"send: {sub_str}") + + while True: + try: + res = await asyncio.wait_for(ws.recv(), timeout=25) + except (asyncio.TimeoutError, websockets.exceptions.ConnectionClosed) as e: + try: + await ws.send('ping') + res = await ws.recv() + print(res) + continue + except Exception as e: + print("连接关闭,正在重连……") + break + + print(get_timestamp() + res) + res = eval(res) + if 'event' in res: + continue + for i in res['arg']: + if 'books' in res['arg'][i] and 'books5' not in res['arg'][i]: + # 订阅频道是深度频道 + if res['action'] == 'snapshot': + for m in l: + if res['arg']['instId'] == m['instrument_id']: + l.remove(m) + # 获取首次全量深度数据 + bids_p, asks_p, instrument_id = partial(res) + d = {} + d['instrument_id'] = instrument_id + d['bids_p'] = bids_p + d['asks_p'] = asks_p + l.append(d) + + # 校验checksum + checksum = res['data'][0]['checksum'] + # print('推送数据的checksum为:' + str(checksum)) + check_num = check(bids_p, asks_p) + # print('校验后的checksum为:' + str(check_num)) + if check_num == checksum: + print("校验结果为:True") + else: + print("校验结果为:False,正在重新订阅……") + + # 取消订阅 + await unsubscribe_without_login(url, channels) + # 发送订阅 + async with websockets.connect(url) as ws: + sub_param = {"op": "subscribe", "args": channels} + sub_str = json.dumps(sub_param) + await ws.send(sub_str) + print(f"send: {sub_str}") + + elif res['action'] == 'update': + for j in l: + if res['arg']['instId'] == j['instrument_id']: + # 获取全量数据 + bids_p = j['bids_p'] + asks_p = j['asks_p'] + # 获取合并后数据 + bids_p = update_bids(res, bids_p) + asks_p = update_asks(res, asks_p) + + # 校验checksum + checksum = res['data'][0]['checksum'] + # print('推送数据的checksum为:' + str(checksum)) + check_num = check(bids_p, asks_p) + # print('校验后的checksum为:' + str(check_num)) + if check_num == checksum: + print("校验结果为:True") + else: + print("校验结果为:False,正在重新订阅……") + + # 取消订阅 + await unsubscribe_without_login(url, channels) + # 发送订阅 + async with websockets.connect(url) as ws: + sub_param = {"op": "subscribe", "args": channels} + sub_str = json.dumps(sub_param) + await ws.send(sub_str) + print(f"send: {sub_str}") + except Exception as e: + print(e) + print("连接断开,正在重连……") + continue + + +# subscribe channels need login +async def subscribe(url, api_key, passphrase, secret_key, channels): + while True: + try: + async with websockets.connect(url) as ws: + # login + timestamp = str(get_local_timestamp()) + login_str = login_params(timestamp, api_key, passphrase, secret_key) + await ws.send(login_str) + # print(f"send: {login_str}") + res = await ws.recv() + print(res) + + # subscribe + sub_param = {"op": "subscribe", "args": channels} + sub_str = json.dumps(sub_param) + await ws.send(sub_str) + print(f"send: {sub_str}") + + while True: + try: + res = await asyncio.wait_for(ws.recv(), timeout=25) + except (asyncio.TimeoutError, websockets.exceptions.ConnectionClosed) as e: + try: + await ws.send('ping') + res = await ws.recv() + print(res) + continue + except Exception as e: + print("连接关闭,正在重连……") + break + + print(get_timestamp() + res) + + except Exception as e: + print("连接断开,正在重连……") + continue + + +# trade +async def trade(url, api_key, passphrase, secret_key, trade_param): + while True: + try: + async with websockets.connect(url) as ws: + # login + timestamp = str(get_local_timestamp()) + login_str = login_params(timestamp, api_key, passphrase, secret_key) + await ws.send(login_str) + # print(f"send: {login_str}") + res = await ws.recv() + print(res) + + # trade + sub_str = json.dumps(trade_param) + await ws.send(sub_str) + print(f"send: {sub_str}") + + while True: + try: + res = await asyncio.wait_for(ws.recv(), timeout=25) + except (asyncio.TimeoutError, websockets.exceptions.ConnectionClosed) as e: + try: + await ws.send('ping') + res = await ws.recv() + print(res) + continue + except Exception as e: + print("连接关闭,正在重连……") + break + + print(get_timestamp() + res) + + except Exception as e: + print("连接断开,正在重连……") + continue + + +# unsubscribe channels +async def unsubscribe(url, api_key, passphrase, secret_key, channels): + async with websockets.connect(url) as ws: + # login + timestamp = str(get_local_timestamp()) + login_str = login_params(timestamp, api_key, passphrase, secret_key) + await ws.send(login_str) + # print(f"send: {login_str}") + + res = await ws.recv() + print(f"recv: {res}") + + # unsubscribe + sub_param = {"op": "unsubscribe", "args": channels} + sub_str = json.dumps(sub_param) + await ws.send(sub_str) + print(f"send: {sub_str}") + + res = await ws.recv() + print(f"recv: {res}") + + +# unsubscribe channels +async def unsubscribe_without_login(url, channels): + async with websockets.connect(url) as ws: + # unsubscribe + sub_param = {"op": "unsubscribe", "args": channels} + sub_str = json.dumps(sub_param) + await ws.send(sub_str) + print(f"send: {sub_str}") + + res = await ws.recv() + print(f"recv: {res}") + + +api_key = "" +secret_key = "" +passphrase = "" + +# WebSocket公共频道 public channels +# 实盘 real trading +# url = "wss://ws.okx.com:8443/ws/v5/public" +# 模拟盘 demo trading +# url = "wss://wspap.okx.com:8443/ws/v5/public" + +# WebSocket私有频道 private channels +# 实盘 real trading +# url = "wss://ws.okx.com:8443/ws/v5/private" +# 模拟盘 demo trading +# url = "wss://wspap.okx.com:8443/ws/v5/private" + +''' +公共频道 public channel +:param channel: 频道名 +:param instType: 产品类型 +:param instId: 产品ID +:param uly: 合约标的指数 + +''' + +# 产品频道 Instruments Channel +# channels = [{"channel": "instruments", "instType": "FUTURES"}] +# 行情频道 tickers channel +# channels = [{"channel": "tickers", "instId": "BTC-USDT"}, {"channel": "tickers", "instId": "ETH-USDT"}] +# 持仓总量频道 Open interest Channel +# channels = [{"channel": "open-interest", "instId": "BTC-USD-210326"}] +# K线频道 Candlesticks Channel +# channels = [{"channel": "candle1m", "instId": "BTC-USD-210326"}] +# 交易频道 Trades Channel +# channels = [{"channel": "trades", "instId": "BTC-USD-201225"}] +# 预估交割/行权价格频道 Estimated delivery/exercise Price Channel +# channels = [{"channel": "estimated-price", "instType": "FUTURES", "uly": "BTC-USD"}] +# 标记价格频道 Mark Price Channel +# channels = [{"channel": "mark-price", "instId": "BTC-USDT-210326"}] +# 标记价格K线频道 Mark Price Candlesticks Channel +# channels = [{"channel": "mark-price-candle1D", "instId": "BTC-USD-201225"}] +# 限价频道 Price Limit Channel +# channels = [{"channel": "price-limit", "instId": "BTC-USD-201225"}] +# 深度频道 Order Book Channel +# channels = [{"channel": "books", "instId": "BTC-USD-SWAP"}] +# 期权定价频道 OPTION Summary Channel +# channels = [{"channel": "opt-summary", "uly": "BTC-USD"}] +# 资金费率频道 Funding Rate Channel +# channels = [{"channel": "funding-rate", "instId": "BTC-USD-SWAP"}] +# 指数K线频道 Index Candlesticks Channel +# channels = [{"channel": "index-candle1m", "instId": "BTC-USDT"}] +# 指数行情频道 Index Tickers Channel +# channels = [{"channel": "index-tickers", "instId": "BTC-USDT"}] +# status频道 Status Channel +# channels = [{"channel": "status"}] +# 公共大宗交易频道 Public block trading channel +# channels = [{"channel": "public-struc-block-trades"}] +# 大宗交易行情频道 Block trading market channel +# channels = [{"channel": "block-tickers", "instId":"BTC-USDT-SWAP"}] + +''' +私有频道 private channel +:param channel: 频道名 +:param ccy: 币种 +:param instType: 产品类型 +:param uly: 合约标的指数 +:param instId: 产品ID + +''' + +# 账户频道 Account Channel +# channels = [{"channel": "account", "ccy": "BTC"}] +# 持仓频道 Positions Channel +# channels = [{"channel": "positions", "instType": "FUTURES", "uly": "BTC-USDT", "instId": "BTC-USDT-210326"}] +# 余额和持仓频道 Balance and Position Channel +# channels = [{"channel": "balance_and_position"}] +# 订单频道 Order Channel +# channels = [{"channel": "orders", "instType": "FUTURES", "uly": "BTC-USD", "instId": "BTC-USD-201225"}] +# 策略委托订单频道 Algo Orders Channel +# channels = [{"channel": "orders-algo", "instType": "FUTURES", "uly": "BTC-USD", "instId": "BTC-USD-201225"}] +# 高级策略委托订单频道 Cancel Advance Algos +# channels = [{"channel": "algo-advance", "instType": "SPOT","instId": "BTC-USD-201225","algoId":"12345678"}] +# 爆仓风险预警推送频道 +# channels = [{"channel": "liquidation-warning", "instType": "SWAP","instType": "","uly":"","instId":""}] +# 账户greeks频道 +# channels = [{"channel": "account-greeks", "ccy": "BTC"}] +# 询价频道 Inquiry channel +# channels = [{"channel": "rfqs"}] +# 报价频道 Quote channel +# channels = [{"channel": "quotes"}] +# 大宗交易频道 Block trading channel +# channels = [{"channel": "struc-block-trades"}] +# 现货网格策略委托订单频道 Consignment order channel of spot grid strategy +# channels = [{"channel": "grid-orders-spot", "instType": "ANY"}] +# 合约网格策略委托订单频道 Spot grid policy delegated order channel contract grid policy delegated order channel +# channels = [{"channel": "grid-orders-contract", "instType": "ANY"}] +# 合约网格持仓频道 Contract grid position channel +# channels = [{"channel": "grid-positions", "algoId": ""}] +# 网格策略子订单频道 Grid policy suborder channel +# channels = [{"channel": "grid-sub-orders", "algoId": ""}] +''' +交易 trade +''' + +# 下单 Place Order +# trade_param = {"id": "1512", "op": "order", "args": [{"side": "buy", "instId": "BTC-USDT", "tdMode": "isolated", "ordType": "limit", "px": "19777", "sz": "1"}]} +# 批量下单 Place Multiple Orders +# trade_param = {"id": "1512", "op": "batch-orders", "args": [ +# {"side": "buy", "instId": "BTC-USDT", "tdMode": "isolated", "ordType": "limit", "px": "19666", "sz": "1"}, +# {"side": "buy", "instId": "BTC-USDT", "tdMode": "isolated", "ordType": "limit", "px": "19633", "sz": "1"} +# ]} +# 撤单 Cancel Order +# trade_param = {"id": "1512", "op": "cancel-order", "args": [{"instId": "BTC-USDT", "ordId": "259424589042823169"}]} +# 批量撤单 Cancel Multiple Orders +# trade_param = {"id": "1512", "op": "batch-cancel-orders", "args": [ +# {"instId": "BTC-USDT", "ordId": ""}, +# {"instId": "BTC-USDT", "ordId": ""} +# ]} +# 改单 Amend Order +# trade_param = {"id": "1512", "op": "amend-order", "args": [{"instId": "BTC-USDT", "ordId": "259432767558135808", "newSz": "2"}]} +# 批量改单 Amend Multiple Orders +# trade_param = {"id": "1512", "op": "batch-amend-orders", "args": [ +# {"instId": "BTC-USDT", "ordId": "", "newSz": "2"}, +# {"instId": "BTC-USDT", "ordId": "", "newSz": "3"} +# ]} + + +loop = asyncio.get_event_loop() + +# 公共频道 不需要登录(行情,持仓总量,K线,标记价格,深度,资金费率等)subscribe public channel +loop.run_until_complete(subscribe_without_login(url, channels)) + +# 私有频道 需要登录(账户,持仓,订单等)subscribe private channel +# loop.run_until_complete(subscribe(url, api_key, passphrase, secret_key, channels)) + +# 交易(下单,撤单,改单等)trade +# loop.run_until_complete(trade(url, api_key, passphrase, secret_key, trade_param)) + +loop.close()