commit b6cef36dba0f58cfda5d75f247212c41c8f175a8 Author: shiyao.zhu@okg.com Date: Wed Oct 12 10:53:50 2022 +0800 first commit diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..6044307 Binary files /dev/null and b/.DS_Store differ 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 0000000..f22616a Binary files /dev/null and b/okx/__pycache__/Broker_api.cpython-38.pyc differ diff --git a/okx/__pycache__/Market_api.cpython-38.pyc b/okx/__pycache__/Market_api.cpython-38.pyc new file mode 100644 index 0000000..d2d5e4d Binary files /dev/null and b/okx/__pycache__/Market_api.cpython-38.pyc differ diff --git a/okx/__pycache__/Public_api.cpython-38.pyc b/okx/__pycache__/Public_api.cpython-38.pyc new file mode 100644 index 0000000..229588c Binary files /dev/null and b/okx/__pycache__/Public_api.cpython-38.pyc differ diff --git a/okx/__pycache__/Rfq_api.cpython-38.pyc b/okx/__pycache__/Rfq_api.cpython-38.pyc new file mode 100644 index 0000000..84090aa Binary files /dev/null and b/okx/__pycache__/Rfq_api.cpython-38.pyc differ diff --git a/okx/__pycache__/TradingBot_api.cpython-38.pyc b/okx/__pycache__/TradingBot_api.cpython-38.pyc new file mode 100644 index 0000000..77cbb32 Binary files /dev/null and b/okx/__pycache__/TradingBot_api.cpython-38.pyc differ diff --git a/okx/__pycache__/__init__.cpython-38.pyc b/okx/__pycache__/__init__.cpython-38.pyc new file mode 100644 index 0000000..56cc821 Binary files /dev/null and b/okx/__pycache__/__init__.cpython-38.pyc differ diff --git a/okx/__pycache__/__init__.cpython-39.pyc b/okx/__pycache__/__init__.cpython-39.pyc new file mode 100644 index 0000000..b8c662b Binary files /dev/null and b/okx/__pycache__/__init__.cpython-39.pyc differ diff --git a/okx/__pycache__/client.cpython-38.pyc b/okx/__pycache__/client.cpython-38.pyc new file mode 100644 index 0000000..aba0e30 Binary files /dev/null and b/okx/__pycache__/client.cpython-38.pyc differ diff --git a/okx/__pycache__/client.cpython-39.pyc b/okx/__pycache__/client.cpython-39.pyc new file mode 100644 index 0000000..353bc60 Binary files /dev/null and b/okx/__pycache__/client.cpython-39.pyc differ diff --git a/okx/__pycache__/consts.cpython-38.pyc b/okx/__pycache__/consts.cpython-38.pyc new file mode 100644 index 0000000..e0d7f96 Binary files /dev/null and b/okx/__pycache__/consts.cpython-38.pyc differ diff --git a/okx/__pycache__/consts.cpython-39.pyc b/okx/__pycache__/consts.cpython-39.pyc new file mode 100644 index 0000000..23716f3 Binary files /dev/null and b/okx/__pycache__/consts.cpython-39.pyc differ diff --git a/okx/__pycache__/exceptions.cpython-38.pyc b/okx/__pycache__/exceptions.cpython-38.pyc new file mode 100644 index 0000000..9f2068b Binary files /dev/null and b/okx/__pycache__/exceptions.cpython-38.pyc differ diff --git a/okx/__pycache__/exceptions.cpython-39.pyc b/okx/__pycache__/exceptions.cpython-39.pyc new file mode 100644 index 0000000..02bfc27 Binary files /dev/null and b/okx/__pycache__/exceptions.cpython-39.pyc differ diff --git a/okx/__pycache__/status_api.cpython-38.pyc b/okx/__pycache__/status_api.cpython-38.pyc new file mode 100644 index 0000000..fc7e9dc Binary files /dev/null and b/okx/__pycache__/status_api.cpython-38.pyc differ diff --git a/okx/__pycache__/subAccount_api.cpython-38.pyc b/okx/__pycache__/subAccount_api.cpython-38.pyc new file mode 100644 index 0000000..4878146 Binary files /dev/null and b/okx/__pycache__/subAccount_api.cpython-38.pyc differ diff --git a/okx/__pycache__/utils.cpython-38.pyc b/okx/__pycache__/utils.cpython-38.pyc new file mode 100644 index 0000000..675772e Binary files /dev/null and b/okx/__pycache__/utils.cpython-38.pyc differ diff --git a/okx/__pycache__/utils.cpython-39.pyc b/okx/__pycache__/utils.cpython-39.pyc new file mode 100644 index 0000000..a801254 Binary files /dev/null and b/okx/__pycache__/utils.cpython-39.pyc differ diff --git a/okx/client.py b/okx/client.py new file mode 100644 index 0000000..26ae603 --- /dev/null +++ b/okx/client.py @@ -0,0 +1,57 @@ +import json + +import httpx + +from . import consts as c, utils, exceptions + + +class Client(object): + + def __init__(self, api_key = '-1', api_secret_key = '-1', passphrase = '-1', use_server_time=False, flag='1', base_api = 'https://www.okx.com',debug = 'True'): + + self.API_KEY = api_key + self.API_SECRET_KEY = api_secret_key + self.PASSPHRASE = passphrase + self.use_server_time = use_server_time + self.flag = flag + self.domain = base_api + self.debug = debug + self.client = httpx.Client(base_url=base_api, http2=True) + + def _request(self, method, request_path, params): + if method == c.GET: + request_path = request_path + utils.parse_params_to_str(params) + timestamp = utils.get_timestamp() + if self.use_server_time: + timestamp = self._get_timestamp() + body = json.dumps(params) if method == c.POST else "" + if self.API_KEY != '-1': + sign = utils.sign(utils.pre_hash(timestamp, method, request_path, str(body), self.debug), self.API_SECRET_KEY) + header = utils.get_header(self.API_KEY, sign, timestamp, self.PASSPHRASE, self.flag, self.debug) + else: + header = utils.get_header_no_sign(self.flag, self.debug) + response = None + if self.debug == True: + print('domain:',self.domain) + print('url:',request_path) + if method == c.GET: + response = self.client.get(request_path, headers=header) + elif method == c.POST: + response = self.client.post(request_path, data=body, headers=header) + if not str(response.status_code).startswith('2'): + raise exceptions.OkxAPIException(response) + return response.json() + + def _request_without_params(self, method, request_path): + return self._request(method, request_path, {}) + + def _request_with_params(self, method, request_path, params): + return self._request(method, request_path, params) + + def _get_timestamp(self): + request_path = c.API_URL + c.SERVER_TIMESTAMP_URL + response = self.client.get(request_path) + if response.status_code == 200: + return response.json()['ts'] + else: + return "" diff --git a/okx/consts.py b/okx/consts.py new file mode 100644 index 0000000..833e44f --- /dev/null +++ b/okx/consts.py @@ -0,0 +1,235 @@ +# http header +#API_URL = 'https://www.okx.com' + +CONTENT_TYPE = 'Content-Type' +OK_ACCESS_KEY = 'OK-ACCESS-KEY' +OK_ACCESS_SIGN = 'OK-ACCESS-SIGN' +OK_ACCESS_TIMESTAMP = 'OK-ACCESS-TIMESTAMP' +OK_ACCESS_PASSPHRASE = 'OK-ACCESS-PASSPHRASE' + +ACEEPT = 'Accept' +COOKIE = 'Cookie' +LOCALE = 'Locale=' + +APPLICATION_JSON = 'application/json' + +GET = "GET" +POST = "POST" + +SERVER_TIMESTAMP_URL = '/api/v5/public/time' + +# account-complete-testcomplete +POSITION_RISK='/api/v5/account/account-position-risk' +ACCOUNT_INFO = '/api/v5/account/balance' +POSITION_INFO = '/api/v5/account/positions' +BILLS_DETAIL = '/api/v5/account/bills' +BILLS_ARCHIVE = '/api/v5/account/bills-archive' +ACCOUNT_CONFIG = '/api/v5/account/config' +POSITION_MODE = '/api/v5/account/set-position-mode' +SET_LEVERAGE = '/api/v5/account/set-leverage' +MAX_TRADE_SIZE = '/api/v5/account/max-size' +MAX_AVAIL_SIZE = '/api/v5/account/max-avail-size' +ADJUSTMENT_MARGIN = '/api/v5/account/position/margin-balance' +GET_LEVERAGE = '/api/v5/account/leverage-info' +MAX_LOAN = '/api/v5/account/max-loan' +FEE_RATES = '/api/v5/account/trade-fee' +INTEREST_ACCRUED = '/api/v5/account/interest-accrued' +INTEREST_RATE = '/api/v5/account/interest-rate' +SET_GREEKS = '/api/v5/account/set-greeks' +ISOLATED_MODE = '/api/v5/account/set-isolated-mode' +MAX_WITHDRAWAL = '/api/v5/account/max-withdrawal' +ACCOUNT_RISK = '/api/v5/account/risk-state' #need add +BORROW_REPAY = '/api/v5/account/borrow-repay' +BORROW_REPAY_HISTORY = '/api/v5/account/borrow-repay-history' +INTEREST_LIMITS = '/api/v5/account/interest-limits' +SIMULATED_MARGIN = '/api/v5/account/simulated_margin' +GREEKS = '/api/v5/account/greeks' +POSITIONS_HISTORY = '/api/v5/account/positions-history' #need add +GET_PM_LIMIT = '/api/v5/account/position-tiers' #need add + +# funding-complete-testcomplete +DEPOSIT_ADDRESS = '/api/v5/asset/deposit-address' +GET_BALANCES = '/api/v5/asset/balances' +FUNDS_TRANSFER = '/api/v5/asset/transfer' +TRANSFER_STATE = '/api/v5/asset/transfer-state' +WITHDRAWAL_COIN = '/api/v5/asset/withdrawal' +DEPOSIT_HISTORIY = '/api/v5/asset/deposit-history' +CURRENCY_INFO = '/api/v5/asset/currencies' +PURCHASE_REDEMPT = '/api/v5/asset/purchase_redempt' +BILLS_INFO = '/api/v5/asset/bills' +DEPOSIT_LIGHTNING = '/api/v5/asset/deposit-lightning' +WITHDRAWAL_LIGHTNING = '/api/v5/asset/withdrawal-lightning' +CANCEL_WITHDRAWAL = '/api/v5/asset/cancel-withdrawal' #need add +WITHDRAWAL_HISTORIY = '/api/v5/asset/withdrawal-history' +CONVERT_DUST_ASSETS = '/api/v5/asset/convert-dust-assets' #need add +ASSET_VALUATION = '/api/v5/asset/asset-valuation' #need add +SET_LENDING_RATE = '/api/v5/asset/set-lending-rate' +LENDING_HISTORY = '/api/v5/asset/lending-history' +LENDING_RATE_HISTORY = '/api/v5/asset/lending-rate-history' +LENDING_RATE_SUMMARY = '/api/v5/asset/lending-rate-summary' +GET_SAVING_BALANCE = '/api/v5/asset/saving-balance' #need to add + + +# Market Data-Complete-testComplete +TICKERS_INFO = '/api/v5/market/tickers' +TICKER_INFO = '/api/v5/market/ticker' +INDEX_TICKERS = '/api/v5/market/index-tickers' +ORDER_BOOKS = '/api/v5/market/books' +MARKET_CANDLES = '/api/v5/market/candles' +HISTORY_CANDLES = '/api/v5/market/history-candles' +INDEX_CANSLES = '/api/v5/market/index-candles' +MARKPRICE_CANDLES = '/api/v5/market/mark-price-candles' +MARKET_TRADES = '/api/v5/market/trades' +VOLUMNE = '/api/v5/market/platform-24-volume' +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 + +# Public Data-Complete-testComplete +INSTRUMENT_INFO = '/api/v5/public/instruments' +DELIVERY_EXERCISE = '/api/v5/public/delivery-exercise-history' +OPEN_INTEREST = '/api/v5/public/open-interest' +FUNDING_RATE = '/api/v5/public/funding-rate' +FUNDING_RATE_HISTORY = '/api/v5/public/funding-rate-history' +PRICE_LIMIT = '/api/v5/public/price-limit' +OPT_SUMMARY = '/api/v5/public/opt-summary' +ESTIMATED_PRICE = '/api/v5/public/estimated-price' +DICCOUNT_INTETEST_INFO = '/api/v5/public/discount-rate-interest-free-quota' +SYSTEM_TIME = '/api/v5/public/time' +LIQUIDATION_ORDERS = '/api/v5/public/liquidation-orders' +MARK_PRICE = '/api/v5/public/mark-price' +TIER = '/api/v5/public/position-tiers' +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 + +# TRADING DATA-COMPLETE +SUPPORT_COIN = '/api/v5/rubik/stat/trading-data/support-coin' +TAKER_VOLUME = '/api/v5/rubik/stat/taker-volume' +MARGIN_LENDING_RATIO = '/api/v5/rubik/stat/margin/loan-ratio' +LONG_SHORT_RATIO = '/api/v5/rubik/stat/contracts/long-short-account-ratio' +CONTRACTS_INTEREST_VOLUME = '/api/v5/rubik/stat/contracts/open-interest-volume' +OPTIONS_INTEREST_VOLUME = '/api/v5/rubik/stat/option/open-interest-volume' +PUT_CALL_RATIO = '/api/v5/rubik/stat/option/open-interest-volume-ratio' +OPEN_INTEREST_VOLUME_EXPIRY = '/api/v5/rubik/stat/option/open-interest-volume-expiry' +INTEREST_VOLUME_STRIKE = '/api/v5/rubik/stat/option/open-interest-volume-strike' +TAKER_FLOW = '/api/v5/rubik/stat/option/taker-block-volume' + +# TRADE-Complete +PLACR_ORDER = '/api/v5/trade/order' +BATCH_ORDERS = '/api/v5/trade/batch-orders' +CANAEL_ORDER = '/api/v5/trade/cancel-order' +CANAEL_BATCH_ORDERS = '/api/v5/trade/cancel-batch-orders' +AMEND_ORDER = '/api/v5/trade/amend-order' +AMEND_BATCH_ORDER = '/api/v5/trade/amend-batch-orders' +CLOSE_POSITION = '/api/v5/trade/close-position' +ORDER_INFO = '/api/v5/trade/order' +ORDERS_PENDING = '/api/v5/trade/orders-pending' +ORDERS_HISTORY = '/api/v5/trade/orders-history' +ORDERS_HISTORY_ARCHIVE = '/api/v5/trade/orders-history-archive' +ORDER_FILLS = '/api/v5/trade/fills' +ORDERS_FILLS_HISTORY = '/api/v5/trade/fills-history' +PLACE_ALGO_ORDER = '/api/v5/trade/order-algo' +CANCEL_ALGOS = '/api/v5/trade/cancel-algos' +Cancel_Advance_Algos = '/api/v5/trade/cancel-advance-algos' +ORDERS_ALGO_OENDING = '/api/v5/trade/orders-algo-pending' +ORDERS_ALGO_HISTORY = '/api/v5/trade/orders-algo-history' + +EASY_CONVERT_CURRENCY_LIST = '/api/v5/trade/easy-convert-currency-list' +EASY_CONVERT = '/api/v5/trade/easy-convert' +CONVERT_EASY_HISTORY = '/api/v5/trade/easy-convert-history' +ONE_CLICK_REPAY_SUPPORT = '/api/v5/trade/one-click-repay-currency-list' +ONE_CLICK_REPAY = '/api/v5/trade/one-click-repay' +ONE_CLICK_REPAY_HISTORY = '/api/v5/trade/one-click-repay-history' + + +# SubAccount-complete-testwriteComplete +BALANCE = '/api/v5/account/subaccount/balances' +BILLs = '/api/v5/asset/subaccount/bills' +RESET = '/api/v5/users/subaccount/modify-apikey' +VIEW_LIST = '/api/v5/users/subaccount/list' +SUBACCOUNT_TRANSFER = '/api/v5/asset/subaccount/transfer' +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 + +# Broker-all need to implmented-completed +BROKER_INFO = '/api/v5/broker/nd/info' +CREATE_SUBACCOUNT = '/api/v5/broker/nd/create-subaccount' +DELETE_SUBACCOUNT = '/api/v5/broker/nd/delete-subaccount' +SUBACCOUNT_INFO = '/api/v5/broker/nd/subaccount-info' +SET_SUBACCOUNT_LEVEL = '/api/v5/broker/nd/set-subaccount-level' +SET_SUBACCOUNT_FEE_REAT = '/api/v5/broker/nd/set-subaccount-fee-rate' +SUBACCOUNT_DEPOSIT_ADDRESS = '/api/v5/asset/broker/nd/subaccount-deposit-address' +SUBACCOUNT_DEPOSIT_HISTORY = '/api/v5/asset/broker/nd/subaccount-deposit-history' +REBATE_DAILY = '/api/v5/broker/nd/rebate-daily' +ND_CREAET_APIKEY = '/api/v5/broker/nd/subaccount/apikey' +ND_SELECT_APIKEY = '/api/v5/broker/nd/subaccount/apikey' +ND_MODIFY_APIKEY = '/api/v5/broker/nd/subaccount/modify-apikey' +ND_DELETE_APIKEY = '/api/v5/broker/nd/subaccount/delete-apikey' +GET_REBATE_PER_ORDERS = '/api/v5/broker/nd/rebate-per-orders' +REBATE_PER_ORDERS = '/api/v5/broker/nd/rebate-per-orders' +MODIFY_SUBACCOUNT_DEPOSIT_ADDRESS = '/api/v5/asset/broker/nd/modify-subaccount-deposit-address' +GET_SUBACCOUNT_DEPOSIT='/api/v5/asset/broker/nd/subaccount-deposit-address' + +# Convert-Complete +GET_CURRENCIES = '/api/v5/asset/convert/currencies' +GET_CURRENCY_PAIR = '/api/v5/asset/convert/currency-pair' +ESTIMATE_QUOTE = '/api/v5/asset/convert/estimate-quote' +CONVERT_TRADE = '/api/v5/asset/convert/trade' +CONVERT_HISTORY = '/api/v5/asset/convert/history' + +# FDBroker -completed +FD_GET_REBATE_PER_ORDERS = '/api/v5/broker/fd/rebate-per-orders' +FD_REBATE_PER_ORDERS = '/api/v5/broker/fd/rebate-per-orders' + +# Rfq/BlcokTrading-completed +COUNTERPARTIES = '/api/v5/rfq/counterparties' +CREATE_RFQ = '/api/v5/rfq/create-rfq' +CANCEL_RFQ = '/api/v5/rfq/cancel-rfq' +CANCEL_BATCH_RFQS = '/api/v5/rfq/cancel-batch-rfqs' +CANCEL_ALL_RSQS = '/api/v5/rfq/cancel-all-rfqs' +EXECUTE_QUOTE = '/api/v5/rfq/execute-quote' +CREATE_QUOTE = '/api/v5/rfq/create-quote' +CANCEL_QUOTE = '/api/v5/rfq/cancel-quote' +CANCEL_BATCH_QUOTES = '/api/v5/rfq/cancel-batch-quotes' +CANCEL_ALL_QUOTES = '/api/v5/rfq/cancel-all-quotes' +GET_RFQS = '/api/v5/rfq/rfqs' +GET_QUOTES = '/api/v5/rfq/quotes' +GET_RFQ_TRADES = '/api/v5/rfq/trades' +GET_PUBLIC_TRADES = '/api/v5/rfq/public-trades' +MMP_RESET = '/api/v5/rfq/mmp-reset' +MARKER_INSTRUMENT_SETTING = '/api/v5/rfq/maker-instrument-settings' + + +# tradingBot-Grid-complete-testcomplete +GRID_ORDER_ALGO = '/api/v5/tradingBot/grid/order-algo' +GRID_AMEND_ORDER_ALGO = '/api/v5/tradingBot/grid/amend-order-algo' +GRID_STOP_ORDER_ALGO = '/api/v5/tradingBot/grid/stop-order-algo' +GRID_ORDERS_ALGO_PENDING = '/api/v5/tradingBot/grid/orders-algo-pending' +GRID_ORDERS_ALGO_HISTORY = '/api/v5/tradingBot/grid/orders-algo-history' +GRID_ORDERS_ALGO_DETAILS = '/api/v5/tradingBot/grid/orders-algo-details' +GRID_SUB_ORDERS = '/api/v5/tradingBot/grid/sub-orders' +GRID_POSITIONS = '/api/v5/tradingBot/grid/positions' +GRID_WITHDRAW_INCOME = '/api/v5/tradingBot/grid/withdraw-income' +#--------need to add: +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' + +#stacking - all need to implement-testcomplete +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' + +# status-complete +STATUS = '/api/v5/system/status' diff --git a/okx/exceptions.py b/okx/exceptions.py new file mode 100644 index 0000000..e3dd183 --- /dev/null +++ b/okx/exceptions.py @@ -0,0 +1,44 @@ +# coding=utf-8 + + +class OkxAPIException(Exception): + + def __init__(self, response): + print(response.text + ', ' + str(response.status_code)) + self.code = 0 + try: + json_res = response.json() + except ValueError: + self.message = 'Invalid JSON error message from Okx: {}'.format(response.text) + else: + if "code" in json_res.keys() and "msg" in json_res.keys(): + self.code = json_res['code'] + self.message = json_res['msg'] + else: + self.code = 'None' + self.message = 'System error' + + self.status_code = response.status_code + self.response = response + self.request = getattr(response, 'request', None) + + def __str__(self): # pragma: no cover + return 'API Request Error(code=%s): %s' % (self.code, self.message) + + +class OkxRequestException(Exception): + + def __init__(self, message): + self.message = message + + def __str__(self): + return 'OkxRequestException: %s' % self.message + + +class OkxParamsException(Exception): + + def __init__(self, message): + self.message = message + + def __str__(self): + return 'OkxParamsException: %s' % self.message diff --git a/okx/utils.py b/okx/utils.py new file mode 100644 index 0000000..f130a9b --- /dev/null +++ b/okx/utils.py @@ -0,0 +1,63 @@ +import hmac +import base64 +import datetime +from . import consts as c + + +def sign(message, secretKey): + mac = hmac.new(bytes(secretKey, encoding='utf8'), bytes(message, encoding='utf-8'), digestmod='sha256') + d = mac.digest() + return base64.b64encode(d) + + +def pre_hash(timestamp, method, request_path, body,debug = True): + if debug == True: + print('body: ',body) + return str(timestamp) + str.upper(method) + request_path + body + + +def get_header(api_key, sign, timestamp, passphrase, flag,debug = True): + header = dict() + header[c.CONTENT_TYPE] = c.APPLICATION_JSON + header[c.OK_ACCESS_KEY] = api_key + header[c.OK_ACCESS_SIGN] = sign + header[c.OK_ACCESS_TIMESTAMP] = str(timestamp) + header[c.OK_ACCESS_PASSPHRASE] = passphrase + header['x-simulated-trading'] = flag + if debug == True: + print('header: ',header) + return header + +def get_header_no_sign(flag,debug = True): + header = dict() + header[c.CONTENT_TYPE] = c.APPLICATION_JSON + header['x-simulated-trading'] = flag + if debug == True: + print('header: ',header) + return header + +def parse_params_to_str(params): + url = '?' + for key, value in params.items(): + if(value != ''): + url = url + str(key) + '=' + str(value) + '&' + url = url[0:-1] + #print('url:',url) + return url + + +def get_timestamp(): + now = datetime.datetime.utcnow() + t = now.isoformat("T", "milliseconds") + return t + "Z" + + +def signature(timestamp, method, request_path, body, secret_key): + if str(body) == '{}' or str(body) == 'None': + body = '' + message = str(timestamp) + str.upper(method) + request_path + str(body) + + mac = hmac.new(bytes(secret_key, encoding='utf8'), bytes(message, encoding='utf-8'), digestmod='sha256') + d = mac.digest() + + return base64.b64encode(d) diff --git a/websocket_example.py b/websocket_example.py new file mode 100644 index 0000000..2b83cb0 --- /dev/null +++ b/websocket_example.py @@ -0,0 +1,522 @@ +import asyncio +import base64 +import datetime +import hmac +import json +import time +import zlib + +import requests +import websockets + + +def get_timestamp(): + now = datetime.datetime.now() + t = now.isoformat("T", "milliseconds") + return t + "Z" + + +def get_server_time(): + url = "https://www.okx.com/api/v5/public/time" + response = requests.get(url) + if response.status_code == 200: + return response.json()['data'][0]['ts'] + else: + return "" + + +def get_local_timestamp(): + return int(time.time()) + + +def login_params(timestamp, api_key, passphrase, secret_key): + message = timestamp + 'GET' + '/users/self/verify' + + mac = hmac.new(bytes(secret_key, encoding='utf8'), bytes(message, encoding='utf-8'), digestmod='sha256') + d = mac.digest() + sign = base64.b64encode(d) + + login_param = {"op": "login", "args": [{"apiKey": api_key, + "passphrase": passphrase, + "timestamp": timestamp, + "sign": sign.decode("utf-8")}]} + login_str = json.dumps(login_param) + return login_str + + +def partial(res): + data_obj = res['data'][0] + bids = data_obj['bids'] + asks = data_obj['asks'] + instrument_id = res['arg']['instId'] + # print('全量数据bids为:' + str(bids)) + # print('档数为:' + str(len(bids))) + # print('全量数据asks为:' + str(asks)) + # print('档数为:' + str(len(asks))) + return bids, asks, instrument_id + + +def update_bids(res, bids_p): + # 获取增量bids数据 + bids_u = res['data'][0]['bids'] + # print('增量数据bids为:' + str(bids_u)) + # print('档数为:' + str(len(bids_u))) + # bids合并 + for i in bids_u: + bid_price = i[0] + for j in bids_p: + if bid_price == j[0]: + if i[1] == '0': + bids_p.remove(j) + break + else: + del j[1] + j.insert(1, i[1]) + break + else: + if i[1] != "0": + bids_p.append(i) + else: + bids_p.sort(key=lambda price: sort_num(price[0]), reverse=True) + # print('合并后的bids为:' + str(bids_p) + ',档数为:' + str(len(bids_p))) + return bids_p + + +def update_asks(res, asks_p): + # 获取增量asks数据 + asks_u = res['data'][0]['asks'] + # print('增量数据asks为:' + str(asks_u)) + # print('档数为:' + str(len(asks_u))) + # asks合并 + for i in asks_u: + ask_price = i[0] + for j in asks_p: + if ask_price == j[0]: + if i[1] == '0': + asks_p.remove(j) + break + else: + del j[1] + j.insert(1, i[1]) + break + else: + if i[1] != "0": + asks_p.append(i) + else: + asks_p.sort(key=lambda price: sort_num(price[0])) + # print('合并后的asks为:' + str(asks_p) + ',档数为:' + str(len(asks_p))) + return asks_p + + +def sort_num(n): + if n.isdigit(): + return int(n) + else: + return float(n) + + +def check(bids, asks): + # 获取bid档str + bids_l = [] + bid_l = [] + count_bid = 1 + while count_bid <= 25: + if count_bid > 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()