diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index d3c415a6..00000000 Binary files a/.DS_Store and /dev/null differ diff --git a/.gitignore b/.gitignore index c45a7445..10c5a421 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,9 @@ build/ dist/ python_okx.egg-info/ +*.DS_Store +**/__pycache__ +**/**/__pycache__ ### STS ### .apt_generated @@ -29,4 +32,4 @@ build/ ### VS Code ### .vscode/ -setup.py \ No newline at end of file +id_rsa* \ No newline at end of file diff --git a/README.md b/README.md index e67d4b95..19aac314 100644 --- a/README.md +++ b/README.md @@ -1,143 +1,64 @@ -[TOC] +### Overview +This is an unofficial Python wrapper for the [OKX exchange v5 API](https://www.okx.com/okx-api) -### 如何使用? +If you came here looking to purchase cryptocurrencies from the OKX exchange, please go [here](https://www.okx.com/). -`python版本:>=3.9 +#### Source code +https://github.com/okxapi/python-okx +#### API trading tutorials +- Spot trading: https://www.okx.com/help/how-can-i-do-spot-trading-with-the-jupyter-notebook +- Derivative trading: https://www.okx.com/help/how-can-i-do-derivatives-trading-with-the-jupyter-notebook -`WebSocketAPI:autobahn.twisted>=22.10.0` +Make sure you update often and check the [Changelog](https://www.okx.com/docs-v5/log_en/) for new features and bug fixes. -#### 第一步:下载SDK,安装相关所需库 +### Features +- Implementation of all Rest API endpoints. +- Private and Public Websocket implementation +- Testnet support +- Websocket handling with reconnection and multiplexed connections -1.1 下载`python SDK` - -* 将SDK目录`Clone`或者`Download`到本地,选择使用`okx-python-sdk-api-v5`即可 - -1.2 安装所需库 - -```python -pip install requests -pip install autobahn\[twisted\] -pip install pyOpenSSL -``` - -#### 第二步:配置个人信息 - -2.1 如果还未有API,可[点击](https://www.okx.com/account/users/myApi)前往官网进行申请 - -```python -api_key = "" -secret_key = "" -passphrase = "" -``` - -#### 第三步:调用接口 - -* RestAPI - - * 运行`example.py` - - * 解开相应方法的注释传参调用各接口即可 - -* WebSocketAPI - * 参考Test文件夹下`WsPrivate`和`WsPublic`文件示例; - * 根据`公共频道`/`私有频道`选择对应`url`(如果是私有频道需要设置登陆信息),传入相应参数即可。 - - ```python - # WebSocket公共频道 - url = "wss://ws.okx.com:8443/ws/v5/public" - # WebSocket私有频道 - url = "wss://ws.okx.com:8443/ws/v5/private" - ``` - - ```python - # 公共频道 不需要登录(行情,持仓总量,K线,标记价格,深度,资金费率等) - 参考 WsPublicTest.py - - # 私有频道 需要登录(账户,持仓,订单等) - 参考 WsPrivateTest.py - ``` - -附言: - -* 如果对API尚不了解,建议参考`OKX`官方[API文档](https://www.okx.com/docs-v5/zh/) - -* 使用RestAPI的用户可以通过参考Test文件夹下的示例,设置正确的参数即可 - -* 使用WebSocketAPI的用户可以通过参考Test文件夹下的`WsPublicTest.py`和`WsPrivateTest.py`,设置正确的参数即可 - -* 若使用`WebSocketAPI`遇到问题建议参考相关链接 - - * `asyncio`、`websockets`文档/`github`: - https://docs.python.org/3/library/asyncio-dev.html - https://websockets.readthedocs.io/en/stable/intro.html - https://github.com/aaugustin/websockets - - * 关于`code=1006`: - https://github.com/Rapptz/discord.py/issues/1996 - https://github.com/aaugustin/websockets/issues/587 - - - -### How to use ? +### Quick start +#### Prerequisites `python version:>=3.9` -`WebSocketAPI: autobahn.twisted>=22.10.0` - -#### Step 1: Download the SDK and install the necessary libraries - -1.1 Download python SDK +`WebSocketAPI: websockets package advise version 6.0` -- `Clone` or `Download` the SDK directory to your local directory,choose to use `okx-python-sdk-api-v5` +#### Step 1: register an account on OKX and apply for an API key +- Register for an account: https://www.okx.com/account/register +- Apply for an API key: https://www.okx.com/account/users/myApi -1.2 Install the necessary libraries +#### Step 2: install python-okx ```python -pip install requests -pip install autobahn\[twisted\] -pip install pyOpenSSL +pip install python-okx ``` -#### Step 2: Configure Personal Information - -2.1 If you have no API,[Click here](https://www.okx.com/account/users/myApi) to the official websit to apply for the API - -2.2 Fill out all necessary informatiuon in `example.py(RestAPI)` and `websocket_example.py(WebSocketAPI)` +#### Step 3: Run examples +- Fill in API credentials in the corresponding examples ```python api_key = "" secret_key = "" passphrase = "" ``` - -#### Step 3: Call API - - RestAPI - - Run `example.py` - - Uncomment the corresponding method and then pass the arguments and call the interfaces + - For spot trading: run example/get_started_en.ipynb + - For derivative trading: run example/trade_derivatives_en.ipynb + - Tweak the value of the parameter `flag` (live trading: 0, demo trading: 1 +) to switch between live and demo trading environment - WebSocketAPI - - Open `websocket_example.py` - - According to the `public channel`/`private channel`, select the corresponding `url`, the corresponding start method, and pass in the corresponding parameters - -```python -# WebSocket public channel -url = "wss://ws.okx.com:8443/ws/v5/public?brokerId=9999" - -# WebSocket private channel -url = "wss://ws.okx.com:8443/ws/v5/private?brokerId=9999" -``` + - Run test/WsPrivateTest.py for private websocket channels + - Run test/WsPublicTest.py for public websocket channels + - Use different URLs for different environment + - Live trading URLs: https://www.okx.com/docs-v5/en/#overview-production-trading-services + - Demo trading URLs: https://www.okx.com/docs-v5/en/#overview-demo-trading-services -P.S. +Note -- If you know little about API, advise consulting the offical [API document](https://www.okx.com/docs-v5/en/) +- To learn more about OKX API, visit official [OKX API documentation](https://www.okx.com/docs-v5/en/) -- User with RestAPI can configure parameter `flag` in `example.py` in to choose to access to real trading or demo trading - -- User with WebSocketAPI can ucomment the corresponding `url` to choose to access to real trading or demo trading - -- Rest API support request by http2, you can refer to http2_example - -- If you face any questions when using `WebSocketAPI`,you can consult related link +- If you face any questions when using `WebSocketAPI`,you can consult the following links - `asyncio`、`websockets` document/`github`: @@ -153,6 +74,3 @@ P.S. https://github.com/Rapptz/discord.py/issues/1996 https://github.com/aaugustin/websockets/issues/587 ``` - - - diff --git a/example/.ipynb_checkpoints/get_started_en-checkpoint.ipynb b/example/.ipynb_checkpoints/get_started_en-checkpoint.ipynb new file mode 100644 index 00000000..706e4096 --- /dev/null +++ b/example/.ipynb_checkpoints/get_started_en-checkpoint.ipynb @@ -0,0 +1,1109 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "# Get Started\n", + "## Install python package\n", + "You can install `python-okx` from PyPi server." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "! pip install python-okx --upgrade" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "## Sign up as an OKX user\n", + "Please refer to [Create account](https://www.okx.com/account/register)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "## Create API Key\n", + "Please refer to [Create API Key](https://www.okx.com/account/my-api)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "## Import API modules\n", + "The following modules are available\n", + "- Trade\n", + "- BlockTrading\n", + "- Funding\n", + "- Account\n", + "- Convert\n", + "- Earning\n", + "- SubAccount\n", + "- MarketData\n", + "- PublicData\n", + "- TradingData\n", + "- Status\n", + "- NDBroker\n", + "- FDBroker" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "import okx.Trade as Trade" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "## Fill in your API key details" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "api_key = \"xxxxx\"\n", + "secret_key = \"xxxxx\"\n", + "passphrase = \"xxxxxx\"" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "## Get available funds" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "import okx.Funding as Funding\n", + "\n", + "flag = \"1\" # live trading: 0, demo trading: 1\n", + "\n", + "fundingAPI = Funding.FundingAPI(api_key, secret_key, passphrase, False, flag)\n", + "\n", + "result = fundingAPI.get_currencies()\n", + "print(result)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "## Get market data" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "import okx.MarketData as MarketData\n", + "\n", + "flag = \"1\" # live trading: 0, demo trading: 1\n", + "\n", + "marketDataAPI = MarketData.MarketAPI(flag=flag)\n", + "\n", + "result = marketDataAPI.get_tickers(instType=\"SPOT\")\n", + "print(result)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "## Handle errors" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "You will the error code `51000` when. you run the following code. More details about the error code can be found in `msg`.\n", + "Please refer to [error code](https://www.okx.com/docs-v5/en/#error-code) for addtional information." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "pycharm": { + "name": "#%%\n" + }, + "scrolled": true + }, + "outputs": [], + "source": [ + "import okx.MarketData as MarketData\n", + "\n", + "flag = \"1\" # live trading: 0, demo trading: 1\n", + "\n", + "marketDataAPI = MarketData.MarketAPI(flag=flag)\n", + "\n", + "result = marketDataAPI.get_tickers( instType=\"SPOT\")\n", + "print(result)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "# Prepare for trading\n", + "- Make sure you understand the basic trading rules. Please refer to [Basic Trading Rules](https://www.okx.com/support/hc/en-us/sections/360011507312)\n", + "- Make sure you have enough funds in your trading account。Please refer to [Get balance](https://www.okx.com/docs-v5/en/#rest-api-account-get-balance)." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "## Get account balance. Please refer to [Get balance](https://www.okx.com/docs-v5/en/#rest-api-account-get-balance)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "pycharm": { + "name": "#%%\n" + }, + "scrolled": true + }, + "outputs": [], + "source": [ + "import okx.Account as Account\n", + "flag = \"1\" # live trading: 0, demo trading: 1\n", + "\n", + "accountAPI = Account.AccountAPI(api_key, secret_key, passphrase, False, flag)\n", + "\n", + "result = accountAPI.get_account_balance()\n", + "print(result)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "## Get available trading pairs from [Get instruments](https://www.okx.com/docs-v5/en/#rest-api-public-data-get-instruments)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "pycharm": { + "name": "#%%\n" + }, + "scrolled": true + }, + "outputs": [], + "source": [ + "import okx.PublicData as PublicData\n", + "\n", + "flag = \"1\" # live trading: 0, demo trading: 1\n", + "\n", + "PublicDataAPI = PublicData.PublicAPI(flag=flag)\n", + "\n", + "result = PublicDataAPI.get_instruments(\n", + " instType=\"SPOT\"\n", + ")\n", + "print(result)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "## Make sure you have enough funds to trade a certain pair. Please refer to [Get maximum tradable amount](https://www.okx.com/docs-v5/en/#rest-api-account-get-maximum-available-tradable-amount)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "import okx.Account as Account\n", + "\n", + "flag = \"1\" # live trading: 0, demo trading: 1\n", + "\n", + "accountAPI = Account.AccountAPI(api_key, secret_key, passphrase, False, flag)\n", + "\n", + "result = accountAPI.get_max_avail_size(\n", + " instId=\"BTC-USDT\",\n", + " tdMode=\"cash\"\n", + ")\n", + "print(result)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "import okx.Account as Account\n", + "\n", + "flag = \"1\" # live trading: 0, demo trading: 1\n", + "\n", + "accountAPI = Account.AccountAPI(api_key, secret_key, passphrase, False, flag)\n", + "\n", + "result = accountAPI.get_max_avail_size(\n", + " instId=\"BTC-USDT\",\n", + " tdMode=\"cash\"\n", + ")\n", + "print(result)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "## In unified account, you can trade Spot under simple, single currency, multi currency and portfolio margin account mode. Please refer to [Introduction on Unified Account](https://www.okx.com/support/hc/en-us/articles/360054690791-1-统一交易账户介绍)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "## Get the current account configuration from the `acctLv` parameter in [Get account configuration](https://www.okx.com/docs-v5/en/#rest-api-account-get-account-configuration)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "import okx.Account as Account\n", + "\n", + "flag = \"1\" # live trading: 0, demo trading: 1\n", + "\n", + "accountAPI = Account.AccountAPI(api_key, secret_key, passphrase, False, flag)\n", + "result = accountAPI.get_account_config()\n", + "print(result)\n", + "\n", + "if result['code'] == \"0\":\n", + " acctLv = result[\"data\"][0][\"acctLv\"]\n", + " if acctLv == \"1\":\n", + " print(\"Simple mode\")\n", + " elif acctLv == \"2\":\n", + " print(\"Single-currency margin mode\")\n", + " elif acctLv == \"3\":\n", + " print(\"Multi-currency margin mode\")\n", + " elif acctLv == \"4\":\n", + " print(\"Portfolio margin mode\")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "# Start Spot Trading" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "### Spot trading under simple/single-currency margin mode" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "import okx.Trade as Trade\n", + "\n", + "flag = \"1\" # live trading: 0, demo trading: 1\n", + "\n", + "tradeAPI = Trade.TradeAPI(api_key, secret_key, passphrase, False, flag)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "#### place a limit order" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "# limit order\n", + "result = tradeAPI.place_order(\n", + " instId=\"BTC-USDT\",\n", + " tdMode=\"cash\",\n", + " side=\"buy\",\n", + " ordType=\"limit\",\n", + " px=\"19000\",\n", + " sz=\"0.01\"\n", + ")\n", + "print(result)\n", + "\n", + "if result[\"code\"] == \"0\":\n", + " print(\"Successful order request,order_id = \",result[\"data\"][0][\"ordId\"])\n", + "else:\n", + " print(\"Unsuccessful order request,error_code = \",result[\"data\"][0][\"sCode\"], \", Error_message = \", result[\"data\"][0][\"sMsg\"])" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "#### place a market order" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "# market order\n", + "result = tradeAPI.place_order(\n", + " instId=\"BTC-USDT\",\n", + " tdMode=\"cash\",\n", + " side=\"buy\",\n", + " ordType=\"market\",\n", + " sz=\"100\",\n", + ")\n", + "print(result)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "#### place an order with tgtCcy=quote_ccy (only applicable to spot)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "# market order\n", + "result = tradeAPI.place_order(\n", + " instId=\"BTC-USDT\",\n", + " tdMode=\"cash\",\n", + " side=\"buy\",\n", + " ordType=\"market\",\n", + " sz=\"100\",\n", + " tgtCcy=\"quote_ccy\" # this determines the unit of the sz parameter. base_ccy is the default value\n", + ")\n", + "print(result)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "#### place an order with your own clOrdId" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "# market order\n", + "result = tradeAPI.place_order(\n", + " instId=\"BTC-USDT\",\n", + " tdMode=\"cash\",\n", + " side=\"buy\",\n", + " ordType=\"market\",\n", + " sz=\"100\",\n", + " clOrdId=\"003\" # you can define your own client defined order ID\n", + ")\n", + "print(result)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "### Spot trading under multi-currency/porfolio margin mode" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "# cross-margin spot trading\n", + "result = tradeAPI.place_order(\n", + " instId=\"BTC-USDT\",\n", + " tdMode=\"cross\",\n", + " side=\"buy\",\n", + " ordType=\"limit\",\n", + " px=\"1000\",\n", + " sz=\"0.01\"\n", + ")\n", + "print(result)\n", + "\n", + "if result[\"code\"] == \"0\":\n", + " print(\"Successful order request,order_id = \",result[\"data\"][0][\"ordId\"])\n", + "else:\n", + " print(\"Unsuccessful order request,error_code = \",result[\"data\"][0][\"sCode\"], \", Error_message = \", result[\"data\"][0][\"sMsg\"])" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "### For additional information on the place order endpoint,please refer to [Place order](https://www.okx.com/docs-v5/en/#rest-api-trade-place-order)\n", + "\n", + "### To place orders in a batch, please refer to [Get account configuration](https://www.okx.com/docs-v5/en/#rest-api-trade-place-multiple-orders)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "place_orders = [\n", + " {\"instId\":\"BTC-USDT\", \"tdMode\":\"cash\", \"side\":\"buy\", \"ordType\" : \"limit\",\"px\":\"1000\",\"sz\":\"0.01\"},\n", + " {\"instId\": \"BTC-USDT\", \"tdMode\": \"cash\", \"side\": \"buy\", \"ordType\": \"limit\", \"px\": \"1000\", \"sz\": \"0.02\"}\n", + "]\n", + "\n", + "result = tradeAPI.place_multiple_orders(place_orders)\n", + "print(result)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "### To amend pending orders,please refer to [Amend order](https://www.okx.com/docs-v5/en/#rest-api-trade-amend-order)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "result = tradeAPI.amend_order(\n", + " instId=\"BTC-USDT\",\n", + " ordId=\"489103565508685824\",\n", + " newSz=\"0.012\"\n", + ")\n", + "print(result)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "### To amend orders in a batch, please refer to [Amend multiple orders](https://www.okx.com/docs-v5/en/#rest-api-trade-amend-multiple-orders)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "amend_orders = [\n", + " {\"instId\": \"BTC-USDT\", \"ordId\": \"489106394289909760\",\"newSz\":\"0.001\"},\n", + " {\"instId\": \"BTC-USDT\", \"ordId\": \"489106394289909761\",\"newSz\":\"0.001\"},\n", + "]\n", + "\n", + "result = tradeAPI.amend_multiple_orders(amend_orders)\n", + "print(result)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "### To cancel pending orders,please refer to [Cancel order](https://www.okx.com/docs-v5/en/#rest-api-trade-cancel-order)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "result = tradeAPI.cancel_order(instId=\"BTC-USDT\", ordId = \"489093931993509888\")\n", + "print(result)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "### To cancel orders in a batch,please refer to [Cancel multiple orders](https://www.okx.com/docs-v5/zh/#rest-api-trade-cancel-multiple-orders)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "cancel_orders = [\n", + " {\"instId\": \"BTC-USDT\", \"ordId\": \"489102222534488064\"},\n", + " {\"instId\": \"BTC-USDT\", \"ordId\": \"489102222534488065\"},\n", + "]\n", + "\n", + "result = tradeAPI.cancel_multiple_orders(cancel_orders)\n", + "print(result)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "## Get details of a certain order, please refer to [Get order details](https://www.okx.com/docs-v5/en/#rest-api-trade-get-order-details)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "result = tradeAPI.get_order(instId=\"BTC-USDT\", clOrdId=\"002\")\n", + "print(result)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "result = tradeAPI.get_order(instId=\"BTC-USDT\", ordId=\"497819823594909696\")\n", + "print(result)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "## To get the list of open orders,please refer to [Get order List](https://www.okx.com/docs-v5/en/#rest-api-trade-get-order-list)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "result = tradeAPI.get_order_list()\n", + "print(result)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "### To get past orders,please refer to [Get order history (last 7 days)](https://www.okx.com/docs-v5/en/#rest-api-trade-get-order-history-last-7-days) and [Get order history (last 3 months)](https://www.okx.com/docs-v5/en/#rest-api-trade-get-order-history-last-3-months)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "result = tradeAPI.get_orders_history(\n", + " instType=\"SPOT\"\n", + ")\n", + "print(result)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "result = tradeAPI.get_orders_history_archive(\n", + " instType=\"SPOT\"\n", + ")\n", + "print(result)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "### To get past trades,please refer to [Get transaction details (last 3 days)](https://www.okx.com/docs-v5/en/#rest-api-trade-get-transaction-details-last-3-days) and [Get transaction details (last 3 months) ](https://www.okx.com/docs-v5/en/#rest-api-trade-get-transaction-details-last-3-months)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "result = tradeAPI.get_fills(\n", + " instType=\"SPOT\"\n", + ")\n", + "print(result)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "result = tradeAPI.get_fills_history(\n", + " instType=\"SPOT\"\n", + ")\n", + "print(result)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "### If you wish to place orders when the price reaches a certain level, you can place an algo order" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "result = tradeAPI.place_algo_order(\n", + " instId=\"BTC-USDT\",\n", + " tdMode=\"cash\",\n", + " side=\"buy\", # buy\n", + " ordType=\"trigger\", # order type\n", + " sz=\"100\", # order amount: 100USDT\n", + " triggerPx=\"10000\", # trigger price\n", + " orderPx=\"-1\", # order price. When orderPx=-1, the order will be placed as an market order\n", + " triggerPxType=\"last\" # trigger price type。last:last trade price\n", + ")\n", + "print(result)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "## You can also use Stop Loss or Take Profit order to sell the currencies in your account" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "result = tradeAPI.place_algo_order(\n", + " instId=\"BTC-USDT\",\n", + " tdMode=\"cash\",\n", + " side=\"sell\", # sell\n", + " ordType=\"conditional\", # one-way take profit or stop loss\n", + " sz=\"0.01\", # order amount: 0.01BTC\n", + " tpTriggerPx=\"30000\", # take profit trigger price\n", + " tpOrdPx=\"-1\", # taker profit order price。When it is set to -1,the order will be placed as an market order\n", + " tpTriggerPxType=\"last\" # take profit trigger price type。last:last trade price\n", + ")\n", + "print(result)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "### For additional information, please refer to [Place algo order](https://www.okx.com/docs-v5/en/#rest-api-trade-place-algo-order)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "### Cancel pending algo orders (not including Iceberg order, TWAP order, Trailing Stop order),please refer to [Cancel algo order](https://www.okx.com/docs-v5/en/#rest-api-trade-cancel-algo-order)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "algo_orders = [\n", + " {\"instId\": \"BTC-USDT\", \"algoId\": \"495001187587043328\"},\n", + "]\n", + "\n", + "result = tradeAPI.cancel_algo_order(algo_orders)\n", + "print(result)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "### To get list of currently pending algo orders,please refer to [Get algo order list](https://www.okx.com/docs-v5/en/#rest-api-trade-get-algo-order-list)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "result = tradeAPI.order_algos_list(\n", + " ordType=\"trigger\" # order type\n", + ")\n", + "print(result)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "### To get the past algo orders (last three months),please refer to [Get algo order history](https://www.okx.com/docs-v5/en/#rest-api-trade-get-algo-order-history)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "result = tradeAPI.order_algos_history(\n", + " ordType=\"conditional\", # order type\n", + " state=\"canceled\" # state of the orders\n", + ")\n", + "print(result)\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.12" + }, + "vscode": { + "interpreter": { + "hash": "31f2aee4e71d21fbe5cf8b01ff0e069b9275f58929596ceb00d14d90e3e16cd6" + } + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/example/get_started_en.ipynb b/example/get_started_en.ipynb index de8db080..d75dcb65 100644 --- a/example/get_started_en.ipynb +++ b/example/get_started_en.ipynb @@ -2,56 +2,29 @@ "cells": [ { "cell_type": "markdown", - "metadata": { - "pycharm": { - "name": "#%% md\n" - } - }, "source": [ "# Get Started\n", "## Install python package\n", "You can install `python-okx` from PyPi server." - ] + ], + "metadata": { + "collapsed": false + } }, { "cell_type": "code", - "execution_count": 1, - "metadata": { - "pycharm": { - "name": "#%%\n" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Requirement already satisfied: python-okx in /Users/skylerfeng/opt/anaconda3/lib/python3.9/site-packages (0.0.12)\n", - "Requirement already satisfied: h2 in /Users/skylerfeng/opt/anaconda3/lib/python3.9/site-packages (from python-okx) (4.1.0)\n", - "Requirement already satisfied: httpx in /Users/skylerfeng/opt/anaconda3/lib/python3.9/site-packages (from python-okx) (0.23.0)\n", - "Requirement already satisfied: hyperframe<7,>=6.0 in /Users/skylerfeng/opt/anaconda3/lib/python3.9/site-packages (from h2->python-okx) (6.0.1)\n", - "Requirement already satisfied: hpack<5,>=4.0 in /Users/skylerfeng/opt/anaconda3/lib/python3.9/site-packages (from h2->python-okx) (4.0.0)\n", - "Requirement already satisfied: rfc3986[idna2008]<2,>=1.3 in /Users/skylerfeng/opt/anaconda3/lib/python3.9/site-packages (from httpx->python-okx) (1.5.0)\n", - "Requirement already satisfied: certifi in /Users/skylerfeng/opt/anaconda3/lib/python3.9/site-packages (from httpx->python-okx) (2021.10.8)\n", - "Requirement already satisfied: httpcore<0.16.0,>=0.15.0 in /Users/skylerfeng/opt/anaconda3/lib/python3.9/site-packages (from httpx->python-okx) (0.15.0)\n", - "Requirement already satisfied: sniffio in /Users/skylerfeng/opt/anaconda3/lib/python3.9/site-packages (from httpx->python-okx) (1.2.0)\n", - "Requirement already satisfied: h11<0.13,>=0.11 in /Users/skylerfeng/opt/anaconda3/lib/python3.9/site-packages (from httpcore<0.16.0,>=0.15.0->httpx->python-okx) (0.12.0)\n", - "Requirement already satisfied: anyio==3.* in /Users/skylerfeng/opt/anaconda3/lib/python3.9/site-packages (from httpcore<0.16.0,>=0.15.0->httpx->python-okx) (3.5.0)\n", - "Requirement already satisfied: idna>=2.8 in /Users/skylerfeng/opt/anaconda3/lib/python3.9/site-packages (from anyio==3.*->httpcore<0.16.0,>=0.15.0->httpx->python-okx) (3.3)\n" - ] - } - ], + "execution_count": null, + "outputs": [], "source": [ "! pip install python-okx --upgrade" - ] + ], + "metadata": { + "collapsed": false + } }, { "cell_type": "markdown", - "metadata": { - "pycharm": { - "name": "#%% md\n" - } - }, + "metadata": {}, "source": [ "## Sign up as an OKX user\n", "Please refer to [Create account](https://www.okx.com/account/register)" @@ -59,11 +32,7 @@ }, { "cell_type": "markdown", - "metadata": { - "pycharm": { - "name": "#%% md\n" - } - }, + "metadata": {}, "source": [ "## Create API Key\n", "Please refer to [Create API Key](https://www.okx.com/account/my-api)" @@ -71,11 +40,7 @@ }, { "cell_type": "markdown", - "metadata": { - "pycharm": { - "name": "#%% md\n" - } - }, + "metadata": {}, "source": [ "## Import API modules\n", "The following modules are available\n", @@ -96,36 +61,20 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "metadata": { "pycharm": { - "name": "#%%\n" + "is_executing": true } }, - "outputs": [ - { - "ename": "ModuleNotFoundError", - "evalue": "No module named 'okx'", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mModuleNotFoundError\u001b[0m Traceback (most recent call last)", - "Cell \u001b[0;32mIn [2], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[38;5;28;01mimport\u001b[39;00m \u001b[38;5;21;01mokx\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mTrade\u001b[39;00m \u001b[38;5;28;01mas\u001b[39;00m \u001b[38;5;21;01mTrade\u001b[39;00m\n", - "\u001b[0;31mModuleNotFoundError\u001b[0m: No module named 'okx'" - ] - } - ], + "outputs": [], "source": [ "import okx.Trade as Trade" ] }, { "cell_type": "markdown", - "metadata": { - "pycharm": { - "name": "#%% md\n" - } - }, + "metadata": {}, "source": [ "## Fill in your API key details" ] @@ -133,11 +82,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "pycharm": { - "name": "#%%\n" - } - }, + "metadata": {}, "outputs": [], "source": [ "api_key = \"xxxxx\"\n", @@ -147,11 +92,7 @@ }, { "cell_type": "markdown", - "metadata": { - "pycharm": { - "name": "#%% md\n" - } - }, + "metadata": {}, "source": [ "## Get available funds" ] @@ -161,7 +102,7 @@ "execution_count": null, "metadata": { "pycharm": { - "name": "#%%\n" + "is_executing": true } }, "outputs": [], @@ -178,11 +119,7 @@ }, { "cell_type": "markdown", - "metadata": { - "pycharm": { - "name": "#%% md\n" - } - }, + "metadata": {}, "source": [ "## Get market data" ] @@ -192,7 +129,7 @@ "execution_count": null, "metadata": { "pycharm": { - "name": "#%%\n" + "is_executing": true } }, "outputs": [], @@ -209,22 +146,14 @@ }, { "cell_type": "markdown", - "metadata": { - "pycharm": { - "name": "#%% md\n" - } - }, + "metadata": {}, "source": [ "## Handle errors" ] }, { "cell_type": "markdown", - "metadata": { - "pycharm": { - "name": "#%% md\n" - } - }, + "metadata": {}, "source": [ "You will the error code `51000` when. you run the following code. More details about the error code can be found in `msg`.\n", "Please refer to [error code](https://www.okx.com/docs-v5/en/#error-code) for addtional information." @@ -234,10 +163,10 @@ "cell_type": "code", "execution_count": null, "metadata": { + "scrolled": true, "pycharm": { - "name": "#%%\n" - }, - "scrolled": true + "is_executing": true + } }, "outputs": [], "source": [ @@ -247,17 +176,13 @@ "\n", "marketDataAPI = MarketData.MarketAPI(flag=flag)\n", "\n", - "result = marketDataAPI.get_tickers( instType=\"SPO\")\n", + "result = marketDataAPI.get_tickers( instType=\"SPOT\")\n", "print(result)" ] }, { "cell_type": "markdown", - "metadata": { - "pycharm": { - "name": "#%% md\n" - } - }, + "metadata": {}, "source": [ "# Prepare for trading\n", "- Make sure you understand the basic trading rules. Please refer to [Basic Trading Rules](https://www.okx.com/support/hc/en-us/sections/360011507312)\n", @@ -266,11 +191,7 @@ }, { "cell_type": "markdown", - "metadata": { - "pycharm": { - "name": "#%% md\n" - } - }, + "metadata": {}, "source": [ "## Get account balance. Please refer to [Get balance](https://www.okx.com/docs-v5/en/#rest-api-account-get-balance)." ] @@ -279,9 +200,6 @@ "cell_type": "code", "execution_count": null, "metadata": { - "pycharm": { - "name": "#%%\n" - }, "scrolled": true }, "outputs": [], @@ -297,11 +215,7 @@ }, { "cell_type": "markdown", - "metadata": { - "pycharm": { - "name": "#%% md\n" - } - }, + "metadata": {}, "source": [ "## Get available trading pairs from [Get instruments](https://www.okx.com/docs-v5/en/#rest-api-public-data-get-instruments)." ] @@ -310,20 +224,17 @@ "cell_type": "code", "execution_count": null, "metadata": { - "pycharm": { - "name": "#%%\n" - }, "scrolled": true }, "outputs": [], "source": [ - "import okx.MarketData as MarketData\n", + "import okx.PublicData as PublicData\n", "\n", "flag = \"1\" # live trading: 0, demo trading: 1\n", "\n", - "marketDataAPI = MarketData.MarketAPI(flag=flag)\n", + "PublicDataAPI = PublicData.PublicAPI(flag=flag)\n", "\n", - "result = marketDataAPI.get_instruments(\n", + "result = PublicDataAPI.get_instruments(\n", " instType=\"SPOT\"\n", ")\n", "print(result)" @@ -331,11 +242,7 @@ }, { "cell_type": "markdown", - "metadata": { - "pycharm": { - "name": "#%% md\n" - } - }, + "metadata": {}, "source": [ "## Make sure you have enough funds to trade a certain pair. Please refer to [Get maximum tradable amount](https://www.okx.com/docs-v5/en/#rest-api-account-get-maximum-available-tradable-amount)" ] @@ -343,11 +250,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "pycharm": { - "name": "#%%\n" - } - }, + "metadata": {}, "outputs": [], "source": [ "import okx.Account as Account\n", @@ -366,11 +269,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "pycharm": { - "name": "#%%\n" - } - }, + "metadata": {}, "outputs": [], "source": [ "import okx.Account as Account\n", @@ -388,22 +287,14 @@ }, { "cell_type": "markdown", - "metadata": { - "pycharm": { - "name": "#%% md\n" - } - }, + "metadata": {}, "source": [ "## In unified account, you can trade Spot under simple, single currency, multi currency and portfolio margin account mode. Please refer to [Introduction on Unified Account](https://www.okx.com/support/hc/en-us/articles/360054690791-1-统一交易账户介绍)" ] }, { "cell_type": "markdown", - "metadata": { - "pycharm": { - "name": "#%% md\n" - } - }, + "metadata": {}, "source": [ "## Get the current account configuration from the `acctLv` parameter in [Get account configuration](https://www.okx.com/docs-v5/en/#rest-api-account-get-account-configuration)." ] @@ -411,11 +302,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "pycharm": { - "name": "#%%\n" - } - }, + "metadata": {}, "outputs": [], "source": [ "import okx.Account as Account\n", @@ -440,22 +327,14 @@ }, { "cell_type": "markdown", - "metadata": { - "pycharm": { - "name": "#%% md\n" - } - }, + "metadata": {}, "source": [ "# Start Spot Trading" ] }, { "cell_type": "markdown", - "metadata": { - "pycharm": { - "name": "#%% md\n" - } - }, + "metadata": {}, "source": [ "### Spot trading under simple/single-currency margin mode" ] @@ -463,11 +342,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "pycharm": { - "name": "#%%\n" - } - }, + "metadata": {}, "outputs": [], "source": [ "import okx.Trade as Trade\n", @@ -479,11 +354,7 @@ }, { "cell_type": "markdown", - "metadata": { - "pycharm": { - "name": "#%% md\n" - } - }, + "metadata": {}, "source": [ "#### place a limit order" ] @@ -491,11 +362,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "pycharm": { - "name": "#%%\n" - } - }, + "metadata": {}, "outputs": [], "source": [ "# limit order\n", @@ -517,11 +384,7 @@ }, { "cell_type": "markdown", - "metadata": { - "pycharm": { - "name": "#%% md\n" - } - }, + "metadata": {}, "source": [ "#### place a market order" ] @@ -529,11 +392,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "pycharm": { - "name": "#%%\n" - } - }, + "metadata": {}, "outputs": [], "source": [ "# market order\n", @@ -549,11 +408,7 @@ }, { "cell_type": "markdown", - "metadata": { - "pycharm": { - "name": "#%% md\n" - } - }, + "metadata": {}, "source": [ "#### place an order with tgtCcy=quote_ccy (only applicable to spot)" ] @@ -561,11 +416,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "pycharm": { - "name": "#%%\n" - } - }, + "metadata": {}, "outputs": [], "source": [ "# market order\n", @@ -582,11 +433,7 @@ }, { "cell_type": "markdown", - "metadata": { - "pycharm": { - "name": "#%% md\n" - } - }, + "metadata": {}, "source": [ "#### place an order with your own clOrdId" ] @@ -594,11 +441,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "pycharm": { - "name": "#%%\n" - } - }, + "metadata": {}, "outputs": [], "source": [ "# market order\n", @@ -615,11 +458,7 @@ }, { "cell_type": "markdown", - "metadata": { - "pycharm": { - "name": "#%% md\n" - } - }, + "metadata": {}, "source": [ "### Spot trading under multi-currency/porfolio margin mode" ] @@ -627,11 +466,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "pycharm": { - "name": "#%%\n" - } - }, + "metadata": {}, "outputs": [], "source": [ "# cross-margin spot trading\n", @@ -653,11 +488,7 @@ }, { "cell_type": "markdown", - "metadata": { - "pycharm": { - "name": "#%% md\n" - } - }, + "metadata": {}, "source": [ "### For additional information on the place order endpoint,please refer to [Place order](https://www.okx.com/docs-v5/en/#rest-api-trade-place-order)\n", "\n", @@ -667,11 +498,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "pycharm": { - "name": "#%%\n" - } - }, + "metadata": {}, "outputs": [], "source": [ "place_orders = [\n", @@ -685,11 +512,7 @@ }, { "cell_type": "markdown", - "metadata": { - "pycharm": { - "name": "#%% md\n" - } - }, + "metadata": {}, "source": [ "### To amend pending orders,please refer to [Amend order](https://www.okx.com/docs-v5/en/#rest-api-trade-amend-order)" ] @@ -697,11 +520,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "pycharm": { - "name": "#%%\n" - } - }, + "metadata": {}, "outputs": [], "source": [ "result = tradeAPI.amend_order(\n", @@ -714,11 +533,7 @@ }, { "cell_type": "markdown", - "metadata": { - "pycharm": { - "name": "#%% md\n" - } - }, + "metadata": {}, "source": [ "### To amend orders in a batch, please refer to [Amend multiple orders](https://www.okx.com/docs-v5/en/#rest-api-trade-amend-multiple-orders)" ] @@ -726,11 +541,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "pycharm": { - "name": "#%%\n" - } - }, + "metadata": {}, "outputs": [], "source": [ "amend_orders = [\n", @@ -744,11 +555,7 @@ }, { "cell_type": "markdown", - "metadata": { - "pycharm": { - "name": "#%% md\n" - } - }, + "metadata": {}, "source": [ "### To cancel pending orders,please refer to [Cancel order](https://www.okx.com/docs-v5/en/#rest-api-trade-cancel-order)" ] @@ -756,11 +563,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "pycharm": { - "name": "#%%\n" - } - }, + "metadata": {}, "outputs": [], "source": [ "result = tradeAPI.cancel_order(instId=\"BTC-USDT\", ordId = \"489093931993509888\")\n", @@ -769,11 +572,7 @@ }, { "cell_type": "markdown", - "metadata": { - "pycharm": { - "name": "#%% md\n" - } - }, + "metadata": {}, "source": [ "### To cancel orders in a batch,please refer to [Cancel multiple orders](https://www.okx.com/docs-v5/zh/#rest-api-trade-cancel-multiple-orders)" ] @@ -781,11 +580,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "pycharm": { - "name": "#%%\n" - } - }, + "metadata": {}, "outputs": [], "source": [ "cancel_orders = [\n", @@ -799,11 +594,7 @@ }, { "cell_type": "markdown", - "metadata": { - "pycharm": { - "name": "#%% md\n" - } - }, + "metadata": {}, "source": [ "## Get details of a certain order, please refer to [Get order details](https://www.okx.com/docs-v5/en/#rest-api-trade-get-order-details)" ] @@ -811,11 +602,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "pycharm": { - "name": "#%%\n" - } - }, + "metadata": {}, "outputs": [], "source": [ "result = tradeAPI.get_order(instId=\"BTC-USDT\", clOrdId=\"002\")\n", @@ -825,11 +612,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "pycharm": { - "name": "#%%\n" - } - }, + "metadata": {}, "outputs": [], "source": [ "result = tradeAPI.get_order(instId=\"BTC-USDT\", ordId=\"497819823594909696\")\n", @@ -838,11 +621,7 @@ }, { "cell_type": "markdown", - "metadata": { - "pycharm": { - "name": "#%% md\n" - } - }, + "metadata": {}, "source": [ "## To get the list of open orders,please refer to [Get order List](https://www.okx.com/docs-v5/en/#rest-api-trade-get-order-list)" ] @@ -850,11 +629,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "pycharm": { - "name": "#%%\n" - } - }, + "metadata": {}, "outputs": [], "source": [ "result = tradeAPI.get_order_list()\n", @@ -863,11 +638,7 @@ }, { "cell_type": "markdown", - "metadata": { - "pycharm": { - "name": "#%% md\n" - } - }, + "metadata": {}, "source": [ "### To get past orders,please refer to [Get order history (last 7 days)](https://www.okx.com/docs-v5/en/#rest-api-trade-get-order-history-last-7-days) and [Get order history (last 3 months)](https://www.okx.com/docs-v5/en/#rest-api-trade-get-order-history-last-3-months)" ] @@ -875,11 +646,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "pycharm": { - "name": "#%%\n" - } - }, + "metadata": {}, "outputs": [], "source": [ "result = tradeAPI.get_orders_history(\n", @@ -891,11 +658,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "pycharm": { - "name": "#%%\n" - } - }, + "metadata": {}, "outputs": [], "source": [ "result = tradeAPI.get_orders_history_archive(\n", @@ -906,11 +669,7 @@ }, { "cell_type": "markdown", - "metadata": { - "pycharm": { - "name": "#%% md\n" - } - }, + "metadata": {}, "source": [ "### To get past trades,please refer to [Get transaction details (last 3 days)](https://www.okx.com/docs-v5/en/#rest-api-trade-get-transaction-details-last-3-days) and [Get transaction details (last 3 months) ](https://www.okx.com/docs-v5/en/#rest-api-trade-get-transaction-details-last-3-months)" ] @@ -918,11 +677,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "pycharm": { - "name": "#%%\n" - } - }, + "metadata": {}, "outputs": [], "source": [ "result = tradeAPI.get_fills(\n", @@ -934,11 +689,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "pycharm": { - "name": "#%%\n" - } - }, + "metadata": {}, "outputs": [], "source": [ "result = tradeAPI.get_fills_history(\n", @@ -949,11 +700,7 @@ }, { "cell_type": "markdown", - "metadata": { - "pycharm": { - "name": "#%% md\n" - } - }, + "metadata": {}, "source": [ "### If you wish to place orders when the price reaches a certain level, you can place an algo order" ] @@ -961,11 +708,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "pycharm": { - "name": "#%%\n" - } - }, + "metadata": {}, "outputs": [], "source": [ "result = tradeAPI.place_algo_order(\n", @@ -983,11 +726,7 @@ }, { "cell_type": "markdown", - "metadata": { - "pycharm": { - "name": "#%% md\n" - } - }, + "metadata": {}, "source": [ "## You can also use Stop Loss or Take Profit order to sell the currencies in your account" ] @@ -995,11 +734,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "pycharm": { - "name": "#%%\n" - } - }, + "metadata": {}, "outputs": [], "source": [ "result = tradeAPI.place_algo_order(\n", @@ -1017,22 +752,14 @@ }, { "cell_type": "markdown", - "metadata": { - "pycharm": { - "name": "#%% md\n" - } - }, + "metadata": {}, "source": [ "### For additional information, please refer to [Place algo order](https://www.okx.com/docs-v5/en/#rest-api-trade-place-algo-order)" ] }, { "cell_type": "markdown", - "metadata": { - "pycharm": { - "name": "#%% md\n" - } - }, + "metadata": {}, "source": [ "### Cancel pending algo orders (not including Iceberg order, TWAP order, Trailing Stop order),please refer to [Cancel algo order](https://www.okx.com/docs-v5/en/#rest-api-trade-cancel-algo-order)" ] @@ -1040,11 +767,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "pycharm": { - "name": "#%%\n" - } - }, + "metadata": {}, "outputs": [], "source": [ "algo_orders = [\n", @@ -1057,11 +780,7 @@ }, { "cell_type": "markdown", - "metadata": { - "pycharm": { - "name": "#%% md\n" - } - }, + "metadata": {}, "source": [ "### To get list of currently pending algo orders,please refer to [Get algo order list](https://www.okx.com/docs-v5/en/#rest-api-trade-get-algo-order-list)" ] @@ -1069,11 +788,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "pycharm": { - "name": "#%%\n" - } - }, + "metadata": {}, "outputs": [], "source": [ "result = tradeAPI.order_algos_list(\n", @@ -1084,11 +799,7 @@ }, { "cell_type": "markdown", - "metadata": { - "pycharm": { - "name": "#%% md\n" - } - }, + "metadata": {}, "source": [ "### To get the past algo orders (last three months),please refer to [Get algo order history](https://www.okx.com/docs-v5/en/#rest-api-trade-get-algo-order-history)" ] @@ -1096,11 +807,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "pycharm": { - "name": "#%%\n" - } - }, + "metadata": {}, "outputs": [], "source": [ "result = tradeAPI.order_algos_history(\n", @@ -1113,7 +820,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3.8.9 64-bit", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, @@ -1127,7 +834,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.9" + "version": "3.9.12" }, "vscode": { "interpreter": { diff --git a/example/trade_derivatives_en.ipynb b/example/trade_derivatives_en.ipynb index bb43a24d..db5438a0 100644 --- a/example/trade_derivatives_en.ipynb +++ b/example/trade_derivatives_en.ipynb @@ -46,25 +46,13 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": null, "metadata": { "pycharm": { "name": "#%%\n" } }, - "outputs": [ - { - "ename": "ModuleNotFoundError", - "evalue": "No module named 'okx'", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mModuleNotFoundError\u001b[0m Traceback (most recent call last)", - "Cell \u001b[0;32mIn [1], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[38;5;28;01mimport\u001b[39;00m \u001b[38;5;21;01mokx\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mTrade\u001b[39;00m \u001b[38;5;28;01mas\u001b[39;00m \u001b[38;5;21;01mTrade\u001b[39;00m\n", - "\u001b[0;31mModuleNotFoundError\u001b[0m: No module named 'okx'" - ] - } - ], + "outputs": [], "source": [ "import okx.Trade as Trade" ] diff --git a/http2_example.py b/http2_example.py deleted file mode 100644 index 7663d235..00000000 --- a/http2_example.py +++ /dev/null @@ -1,31 +0,0 @@ -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 index 2a087c89..911cf9b8 100644 --- a/okx/Account.py +++ b/okx/Account.py @@ -1,12 +1,12 @@ -from .client import Client from .consts import * +from .okxclient import OkxClient -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) +class AccountAPI(OkxClient): + def __init__(self, api_key='-1', api_secret_key='-1', passphrase='-1', use_server_time=None, flag='1', + domain='https://www.okx.com', debug=False, proxy=None): + OkxClient.__init__(self, api_key, api_secret_key, passphrase, use_server_time, flag, domain, debug, proxy) # Get Positions def get_position_risk(self, instType=''): @@ -23,22 +23,40 @@ def get_account_balance(self, ccy=''): return self._request_with_params(GET, ACCOUNT_INFO, params) # Get Positions - def get_positions(self, instType='', instId=''): - params = {'instType': instType, 'instId': instId} + def get_positions(self, instType='', instId='', posId=''): + params = {'instType': instType, 'instId': instId, 'posId': posId} return self._request_with_params(GET, POSITION_INFO, params) + def position_builder(self, acctLv=None,inclRealPosAndEq=False, lever=None, greeksType=None, simPos=None, + simAsset=None): + params = {} + if acctLv is not None: + params['acctLv'] = acctLv + if inclRealPosAndEq is not None: + params['inclRealPosAndEq'] = inclRealPosAndEq + if lever is not None: + params['spotOffsetType'] = lever + if greeksType is not None: + params['greksType'] = greeksType + if simPos is not None: + params['simPos'] = simPos + if simAsset is not None: + params['simAsset'] = simAsset + return self._request_with_params(POST, POSITION_BUILDER, params) + # Get Bills Details (recent 7 days) def get_account_bills(self, instType='', ccy='', mgnMode='', ctType='', type='', subType='', after='', before='', - limit=''): + 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=''): + def get_account_bills_archive(self, instType='', ccy='', mgnMode='', ctType='', type='', subType='', after='', + before='', + limit='', begin='', end=''): params = {'instType': instType, 'ccy': ccy, 'mgnMode': mgnMode, 'ctType': ctType, 'type': type, - 'subType': subType, 'after': after, 'before': before, 'limit': limit} + 'subType': subType, 'after': after, 'before': before, 'limit': limit, 'begin': begin, 'end': end} return self._request_with_params(GET, BILLS_ARCHIVE, params) # Get Account Configuration @@ -61,28 +79,34 @@ def get_max_order_size(self, instId, tdMode, ccy='', 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} + def get_max_avail_size(self, instId, tdMode, ccy='', reduceOnly='', unSpotOffset='', quickMgnType=''): + params = {'instId': instId, 'tdMode': tdMode, 'ccy': ccy, 'reduceOnly': reduceOnly, + 'unSpotOffset': unSpotOffset, 'quickMgnType': quickMgnType} 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} + 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} + def get_leverage(self, mgnMode, ccy='', instId=''): + params = {'instId': instId, 'mgnMode': mgnMode, 'ccy': ccy} return self._request_with_params(GET, GET_LEVERAGE, params) + # Get instruments + def get_instruments(self, instType='', ugly='', instFamily='', instId=''): + params = {'instType': instType, 'ugly': ugly, 'instFamily': instFamily, 'instId': instId} + return self._request_with_params(GET, GET_INSTRUMENTS, params) + # Get the maximum loan of isolated MARGIN - def get_max_loan(self, instId, mgnMode, mgnCcy): + def get_max_loan(self, instId, mgnMode, mgnCcy=''): 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} + 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 @@ -101,8 +125,8 @@ def set_greeks(self, 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} + def set_isolated_mode(self, isoMode, type): + params = {'isoMode': isoMode, 'type': type} return self._request_with_params(POST, ISOLATED_MODE, params) # Get Maximum Withdrawals @@ -111,23 +135,23 @@ def get_max_withdrawal(self, 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} + def borrow_repay(self, ccy='', side='', amt='', ordId=''): + params = {'ccy': ccy, 'side': side, 'amt': amt, 'ordId': ordId} 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} + 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=''): + 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,} + def get_simulated_margin(self, instType='', inclRealPos=True, spotOffsetType='', simPos=[]): + params = {'instType': instType, 'inclRealPos': inclRealPos, 'spotOffsetType': spotOffsetType, 'simPos': simPos} return self._request_with_params(POST, SIMULATED_MARGIN, params) # Get Greeks @@ -135,32 +159,167 @@ def get_greeks(self, ccy=''): params = {'ccy': ccy} return self._request_with_params(GET, GREEKS, params) - #GET /api/v5/account/risk-state + # 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 = ''): + # 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) + + # - Get VIP interest accrued data + def get_VIP_interest_accrued_data(self, ccy='', ordId='', after='', before='', limit=''): + params = {'ccy': ccy, 'ordId': ordId, 'after': after, 'before': before, 'limit': limit} + return self._request_with_params(GET, GET_VIP_INTEREST_ACCRUED_DATA, params) + + # - Get VIP interest deducted data + def get_VIP_interest_deducted_data(self, ccy='', ordId='', after='', before='', limit=''): + params = {'ccy': ccy, 'ordId': ordId, 'after': after, 'before': before, 'limit': limit} + return self._request_with_params(GET, GET_VIP_INTEREST_DEDUCTED_DATA, params) + + # - Get VIP loan order list + def get_VIP_loan_order_list(self, ordId='', state='', ccy='', after='', before='', limit=''): + params = {'ordId': ordId, 'state': state, 'ccy': ccy, 'after': after, 'before': before, 'limit': limit} + return self._request_with_params(GET, GET_VIP_LOAN_ORDER_LIST, params) + + # - Get VIP loan order detail + def get_VIP_loan_order_detail(self, ccy='', ordId='', after='', before='', limit=''): + params = {'ccy': ccy, 'ordId': ordId, 'after': after, 'before': before, 'limit': limit} + return self._request_with_params(GET, GET_VIP_LOAN_ORDER_DETAIL, params) + + # - Set risk offset type + def set_risk_offset_typel(self, type=''): + params = {'type': type} + return self._request_with_params(POST, SET_RISK_OFFSET_TYPE, params) + + # - Set auto loan + def set_auto_loan(self, autoLoan=''): params = { - 'instType':instType, - 'instId':instId, - 'mgnMode':mgnMode, - 'type':type, - 'posId':posId, - 'after':after, - 'before':before, - 'limit':limit + 'autoLoan': autoLoan } - return self._request_with_params(GET,POSITIONS_HISTORY,params) + return self._request_with_params(POST, SET_AUTO_LOAN, params) - #GET /api/v5/account/position-tiers - def get_account_position_tiers(self,instType = '', uly = '',instFamily = ''): + # - Set auto loan + def set_account_level(self, acctLv): params = { - 'instType':instType, - 'uly':uly, - 'instFamily':instFamily + 'acctLv': acctLv } - return self._request_with_params(GET,GET_PM_LIMIT,params) + return self._request_with_params(POST, SET_ACCOUNT_LEVEL, params) + # - Activate option + def activate_option(self): + return self._request_without_params(POST, ACTIVSTE_OPTION) + def get_fix_loan_borrowing_limit(self): + return self._request_without_params(GET, BORROWING_LIMIT) + + def get_fix_loan_borrowing_quote(self, type=None, ccy=None, amt=None, maxRate=None, term=None, ordId=None): + params = {} + if type is not None: + params['type'] = type + if ccy is not None: + params['ccy'] =ccy + if amt is not None: + params['amt'] = amt + if maxRate is not None: + params['maxRate'] = maxRate + if term is not None: + params['term'] = term + if ordId is not None: + params['ordId'] = ordId + return self._request_with_params(GET, BORROWING_QUOTE, params) + + def place_fix_loan_borrowing_order(self, ccy=None, amt=None, maxRate=None, term=None, reborrow=False, reborrowRate=None): + params = {} + if ccy is not None: + params['ccy'] =ccy + if amt is not None: + params['amt'] = amt + if maxRate is not None: + params['maxRate'] = maxRate + if term is not None: + params['term'] = term + if reborrow is not None: + params['reborrow'] = reborrow + if reborrowRate is not None: + params['reborrowRate'] = reborrowRate + return self._request_with_params(POST, PLACE_BORROWING_ORDER, params) + + def amend_fix_loan_borrowing_order(self, ordId=None, reborrow=None, renewMaxRate=None): + params = {} + if ordId is not None: + params['ordId'] = ordId + if reborrow is not None: + params['reborrow'] = reborrow + if renewMaxRate is not None: + params['renewMaxRate'] = renewMaxRate + return self._request_with_params(POST, AMEND_BORROWING_ORDER, params) + + def fix_loan_manual_reborrow(self, ordId=None, maxRate=None): + params = {} + if ordId is not None: + params['ordId'] = ordId + if maxRate is not None: + params['maxRate'] = maxRate + return self._request_with_params(POST, MANUAL_REBORROW, params) + + def repay_fix_loan_borrowing_order(self, ordId=None): + params = {} + if ordId is not None: + params['ordId'] = ordId + return self._request_with_params(POST, REPAY_BORROWING_ORDER, params) + def get_fix_loan_borrowing_orders_list(self, ordId=None, ccy=None, state=None, after=None, before=None, limit=None): + params = {} + if ordId is not None: + params['ordId'] = ordId + if ccy is not None: + params['ccy'] =ccy + if state is not None: + params['state'] = state + if after is not None: + params['after'] = after + if before is not None: + params['before'] = before + if limit is not None: + params['limit'] = limit + return self._request_with_params(GET, BORROWING_ORDERS_LIST, params) + + def spot_manual_borrow_repay(self, ccy=None, side=None, amt=None): + params = {} + if ccy is not None: + params['ccy'] = ccy + if side is not None: + params['side'] = side + if amt is not None: + params['amt'] = amt + return self._request_with_params(POST, MANUAL_REBORROW_REPAY, params) + + def set_auto_repay(self, autoRepay=False): + params = {} + if autoRepay is not None: + params['autoRepay'] = autoRepay + return self._request_with_params(POST, SET_AUTO_REPAY, params) + def spot_borrow_repay_history(self, ccy='', type='', after='', before='', limit=''): + params = {'ccy': ccy, 'type': type, 'after': after, 'before': before, 'limit': limit} + return self._request_with_params(GET, GET_BORROW_REPAY_HISTORY, params) diff --git a/okx/BlockTrading.py b/okx/BlockTrading.py index 0275555e..75c6b539 100644 --- a/okx/BlockTrading.py +++ b/okx/BlockTrading.py @@ -1,17 +1,19 @@ -from .client import Client +from .okxclient import OkxClient 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) +class BlockTradingAPI(OkxClient): + def __init__(self, api_key='-1', api_secret_key='-1', passphrase='-1', use_server_time=None, flag='1', domain = 'https://www.okx.com',debug = False, proxy=None): + OkxClient.__init__(self, api_key, api_secret_key, passphrase, use_server_time, flag, domain, debug, proxy) 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} + def create_rfq(self, counterparties=[], anonymous='false', clRfqId='', tag='', allowPartialExecution='false', + legs=[]): + params = {'counterparties': counterparties, 'anonymous': anonymous, 'clRfqId': clRfqId, 'tag': tag, + 'allowPartialExecution': allowPartialExecution, 'legs': legs} return self._request_with_params(POST, CREATE_RFQ, params) def cancel_rfq(self, rfqId = '', clRfqId = ''): @@ -26,13 +28,13 @@ 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} + def execute_quote(self, rfqId='', quoteId='', legs=[]): + params = {'rfqId': rfqId, 'quoteId': quoteId, 'legs': legs} 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} + def create_quote(self, rfqId='', clQuoteId='', tag='', quoteSide='', legs=[], anonymous=False, expiresIn=''): + params = {'rfqId': rfqId, 'clQuoteId': clQuoteId, 'tag': tag, 'quoteSide': quoteSide, 'legs': legs, + 'anonymous': anonymous, 'expiresIn': expiresIn} return self._request_with_params(POST, CREATE_QUOTE, params) def cancel_quote(self, quoteId = '', clQuoteId = ''): @@ -55,8 +57,10 @@ def get_quotes(self, rfqId = '', clRfqId = '', quoteId = '', clQuoteId = '', sta 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} + def get_trades(self, rfqId='', clRfqId='', quoteId='', clQuoteId='', state='', beginId='', endId='', beginTs='', + endTs='', limit=''): + params = {'rfqId': rfqId, 'clRfqId': clRfqId, 'quoteId': quoteId, 'clQuoteId': clQuoteId, 'state': state, + 'beginId': beginId, 'endId': endId, 'beginTs': beginTs, 'endTs': endTs, 'limit': limit} return self._request_with_params(GET, GET_RFQ_TRADES, params) def get_public_trades(self, beginId = '', endId = '', limit = ''): @@ -68,4 +72,8 @@ def reset_mmp(self): def set_marker_instrument(self,params = []): - return self._request_with_params(POST, MARKER_INSTRUMENT_SETTING, params) \ No newline at end of file + return self._request_with_params(POST, MARKER_INSTRUMENT_SETTING, params) + + #Get Quote products + def get_quote_products(self): + return self._request_without_params(GET, MARKER_INSTRUMENT_SETTING) diff --git a/okx/Convert.py b/okx/Convert.py index 8d04f446..075607b8 100644 --- a/okx/Convert.py +++ b/okx/Convert.py @@ -1,10 +1,10 @@ -from .client import Client +from .okxclient import OkxClient 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) +class ConvertAPI(OkxClient): + def __init__(self, api_key='-1', api_secret_key='-1', passphrase='-1', use_server_time=None, flag='1', domain = 'https://www.okx.com',debug = False,proxy = None): + OkxClient.__init__(self, api_key, api_secret_key, passphrase, use_server_time, flag, domain, debug, proxy) def get_currencies(self): params = {} diff --git a/okx/CopyTrading.py b/okx/CopyTrading.py new file mode 100644 index 00000000..331b6cfa --- /dev/null +++ b/okx/CopyTrading.py @@ -0,0 +1,73 @@ +from .okxclient import OkxClient +from .consts import * + + +class CopyTradingAPI(OkxClient): + def __init__(self, api_key='-1', api_secret_key='-1', passphrase='-1', use_server_time=False, flag='1', + domain='https://www.okx.com', debug=False, proxy=None): + OkxClient.__init__(self, api_key, api_secret_key, passphrase, use_server_time, flag, domain, debug, + proxy=proxy) + + # Get existing leading positions + def get_existing_leading_positions(self, instId=''): + params = { + 'instId': instId + } + return self._request_with_params(GET, GET_EXISTING_LEADING_POSITIONS, params) + + # Get leading position history + def get_leading_position_history(self, instId='', after='', before='', limit=''): + params = { + 'instId': instId, + 'after': after, + 'before': before, + 'limit': limit + } + return self._request_with_params(GET, GET_LEADING_POSITIONS_HISTORY, params) + + # Place leading stop order + def place_leading_stop_order(self, subPosId='', tpTriggerPx='', slTriggerPx='', tpTriggerPxType='', + slTriggerPxType=''): + params = { + 'subPosId': subPosId, + 'tpTriggerPx': tpTriggerPx, + 'slTriggerPx': slTriggerPx, + 'tpTriggerPxType': tpTriggerPxType, + 'slTriggerPxType': slTriggerPxType + } + return self._request_with_params(POST, PLACE_LEADING_STOP_ORDER, params) + + # Close leading position + def close_leading_position(self, subPosId=''): + params = { + 'subPosId': subPosId + } + return self._request_with_params(POST, CLOSE_LEADING_POSITIONS, params) + + # Get leading instruments + def get_leading_instruments(self): + return self._request_without_params(GET, GET_LEADING_POSITIONS) + + # Amend leading instruments + def amend_leading_instruments(self, instId=''): + params = { + 'instId': instId + } + return self._request_with_params(POST, AMEND_EXISTING_LEADING_POSITIONS, params) + + # Get profit sharing details + def get_profit_sharing_details(self, after='', before='', limit=''): + params = { + 'after': after, + 'before': before, + 'limit': limit + } + return self._request_with_params(GET, GET_PROFIT_SHARING_DETAILS, params) + + # Get total profit sharing + def get_total_profit_sharing(self): + return self._request_without_params(GET, GET_TOTAL_PROFIT_SHARING) + + # Get unrealized profit sharing details + def get_unrealized_profit_sharing_details(self): + return self._request_without_params(GET, GET_UNREALIZED_PROFIT_SHARING_DETAILS) diff --git a/okx/Earning.py b/okx/Earning.py deleted file mode 100644 index 0ecb2566..00000000 --- a/okx/Earning.py +++ /dev/null @@ -1,64 +0,0 @@ -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 index d0c8f57c..31185644 100644 --- a/okx/FDBroker.py +++ b/okx/FDBroker.py @@ -1,10 +1,10 @@ -from .client import Client +from .okxclient import OkxClient 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) +class FDBrokerAPI(OkxClient): + def __init__(self, api_key='-1', api_secret_key='-1', passphrase='-1', use_server_time=None, flag='1', domain = 'https://www.okx.com',debug = False, proxy=None): + OkxClient.__init__(self, api_key, api_secret_key, passphrase, use_server_time, flag, domain, debug, proxy) def generate_rebate_details_download_link(self, begin ='', end = ''): params = {'begin': begin, 'end': end} diff --git a/okx/Finance/EthStaking.py b/okx/Finance/EthStaking.py new file mode 100644 index 00000000..c7d008dd --- /dev/null +++ b/okx/Finance/EthStaking.py @@ -0,0 +1,52 @@ +from okx.okxclient import OkxClient +from okx.consts import * + + +class EthStakingAPI(OkxClient): + def __init__(self, api_key='-1', api_secret_key='-1', passphrase='-1', use_server_time=None, flag='1', domain = 'https://www.okx.com',debug = False, proxy=None): + OkxClient.__init__(self, api_key, api_secret_key, passphrase, use_server_time, flag, domain, debug, proxy) + + def eth_product_info(self): + + return self._request_without_params(GET, STACK_ETH_PRODUCT_INFO) + + def eth_purchase(self, amt=''): + + params = { + 'amt': amt, + } + return self._request_with_params(POST, STACK_ETH_PURCHASE, params) + + def eth_redeem(self, amt=''): + + params = { + 'amt': amt, + } + return self._request_with_params(POST, STACK_ETH_REDEEM, params) + + def eth_balance(self): + + params = {} + return self._request_with_params(GET, STACK_ETH_BALANCE, params) + + def eth_purchase_redeem_history(self, type='', status='', after='', before='', limit=''): + + params = {} + if type != '': + params['type'] = type + if status != '': + params['status'] = status + if after != '': + params['after'] = after + if before != '': + params['before'] = before + if limit != '': + params['limit'] = limit + return self._request_with_params(GET, STACK_ETH_PURCHASE_REDEEM_HISTORY, params) + + def eth_apy_history(self, days): + + params = { + 'days': days, + } + return self._request_with_params(GET, STACK_ETH_APY_HISTORY, params) diff --git a/okx/Finance/FlexibleLoan.py b/okx/Finance/FlexibleLoan.py new file mode 100644 index 00000000..44ce4e80 --- /dev/null +++ b/okx/Finance/FlexibleLoan.py @@ -0,0 +1,65 @@ +from okx.okxclient import OkxClient +from okx.consts import * + + +class FlexibleLoanAPI(OkxClient): + def __init__(self, api_key='-1', api_secret_key='-1', passphrase='-1', use_server_time=None, flag='1', + domain='https://www.okx.com', debug=False, proxy=None): + OkxClient.__init__(self, api_key, api_secret_key, passphrase, use_server_time, flag, domain, debug, proxy) + + def borrow_currencies(self): + return self._request_without_params(GET, FINANCE_BORROW_CURRENCIES) + + def collateral_assets(self, ccy=''): + params = {} + if ccy != '': + params['ccy'] = ccy + return self._request_with_params(GET, FINANCE_COLLATERAL_ASSETS, params) + + def max_loan(self, borrowCcy='', supCollateral=[]): + params = { + 'borrowCcy': borrowCcy, + 'supCollateral': supCollateral, + } + return self._request_with_params(POST, FINANCE_MAX_LOAN, params) + + def max_collateral_redeem_amount(self, ccy=''): + params = {} + if ccy != '': + params['ccy'] = ccy + return self._request_with_params(GET, FINANCE_MAX_REDEEM, params) + + def adjust_collateral(self, type='', collateralCcy='', collateralAmt=''): + params = { + 'type': type, + 'collateralCcy': collateralCcy, + 'collateralAmt': collateralAmt, + } + return self._request_with_params(POST, FINANCE_ADJUST_COLLATERAL, params) + + def loan_info(self): + return self._request_without_params(GET, FINANCE_LOAN_INFO) + + def loan_history(self, type='', after='', before='', limit=''): + params = {} + if type != '': + params['type'] = type + if after != '': + params['after'] = after + if before != '': + params['before'] = before + if limit != '': + params['limit'] = limit + return self._request_with_params(GET, FINANCE_LOAN_HISTORY, params) + + def interest_accrued(self, ccy='', after='', before='', limit=''): + params = {} + if ccy != '': + params['ccy'] = ccy + if after != '': + params['after'] = after + if before != '': + params['before'] = before + if limit != '': + params['limit'] = limit + return self._request_with_params(GET, FINANCE_INTEREST_ACCRUED, params) diff --git a/okx/Finance/Savings.py b/okx/Finance/Savings.py new file mode 100644 index 00000000..3fbb3933 --- /dev/null +++ b/okx/Finance/Savings.py @@ -0,0 +1,62 @@ +from okx.okxclient import OkxClient +from okx.consts import * + + +class SavingsAPI(OkxClient): + def __init__(self, api_key='-1', api_secret_key='-1', passphrase='-1', use_server_time=None, flag='1', domain = 'https://www.okx.com',debug = False, proxy=None): + OkxClient.__init__(self, api_key, api_secret_key, passphrase, use_server_time, flag, domain, debug, proxy) + + # - Get saving balance + def get_saving_balance(self, ccy=''): + params = { + 'ccy': ccy + } + return self._request_with_params(GET, GET_SAVING_BALANCE, params) + + # - Savings purchase/redemption + def savings_purchase_redemption(self, ccy='', amt='', side='', rate=''): + + params = { + 'ccy': ccy, + 'amt': amt, + 'side': side, + 'rate': rate + } + return self._request_with_params(POST, SAVING_PURCHASE_REDEMPTION, params) + + # - 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='', after='', before='', limit=''): + params = { + 'ccy': ccy, + 'after': after, + 'before': before, + 'limit': limit + } + return self._request_with_params(GET, GET_LENDING_HISTORY, params) + + # - Get public borrow history (public) + def get_public_borrow_history(self, ccy='', after='', before='', limit=''): + params = { + 'ccy': ccy, + 'after': after, + 'before': before, + 'limit': limit + } + return self._request_with_params(GET, GET_PUBLIC_BORROW_HISTORY, params) + + # GET / Public borrow info (public) + def get_public_borrow_info(self, ccy=''): + params = { + 'ccy': ccy + } + return self._request_with_params(GET, GET_PUBLIC_BORROW_INFO, params) + + diff --git a/okx/Finance/SolStaking.py b/okx/Finance/SolStaking.py new file mode 100644 index 00000000..dc1151f0 --- /dev/null +++ b/okx/Finance/SolStaking.py @@ -0,0 +1,51 @@ +from okx.okxclient import OkxClient +from okx.consts import * + + +class SolStakingAPI(OkxClient): + def __init__(self, api_key='-1', api_secret_key='-1', passphrase='-1', use_server_time=None, flag='1', domain = 'https://www.okx.com',debug = False, proxy=None): + OkxClient.__init__(self, api_key, api_secret_key, passphrase, use_server_time, flag, domain, debug, proxy) + + def sol_purchase(self, amt): + + params = { + 'amt': amt, + } + return self._request_with_params(POST, STACK_SOL_PURCHASE, params) + + def sol_redeem(self, amt=''): + + params = { + 'amt': amt, + } + return self._request_with_params(POST, STACK_SOL_REDEEM, params) + + def sol_balance(self): + + params = {} + return self._request_with_params(GET, STACK_SOL_BALANCE, params) + + def sol_purchase_redeem_history(self, type='', status='', after='', before='', limit=''): + + params = {} + if type != '': + params['type'] = type + if status != '': + params['status'] = status + if after != '': + params['after'] = after + if before != '': + params['before'] = before + if limit != '': + params['limit'] = limit + return self._request_with_params(GET, STACK_SOL_PURCHASE_REDEEM_HISTORY, params) + + def sol_apy_history(self, days): + + params = { + 'days': days, + } + return self._request_with_params(GET, STACK_SOL_APY_HISTORY, params) + + def sol_product_info(self): + return self._request_without_params(GET, STACK_SOL_PRODUCT_INFO) diff --git a/okx/Finance/StakingDefi.py b/okx/Finance/StakingDefi.py new file mode 100644 index 00000000..65d7f47e --- /dev/null +++ b/okx/Finance/StakingDefi.py @@ -0,0 +1,63 @@ +from okx.okxclient import OkxClient +from okx.consts import * + + +class StakingDefiAPI(OkxClient): + def __init__(self, api_key='-1', api_secret_key='-1', passphrase='-1', use_server_time=None, flag='1', domain = 'https://www.okx.com',debug = False, proxy=None): + OkxClient.__init__(self, api_key, api_secret_key, passphrase, use_server_time, flag, domain, debug, proxy) + + 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='', tag=''): + + params = { + 'productId': productId, + 'investData': investData + } + if term != '': + params['term'] = term + if tag != '': + params['tag'] = tag + 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/Finance/__init__.py b/okx/Finance/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/okx/Funding.py b/okx/Funding.py index a4c3c659..6ca0344d 100644 --- a/okx/Funding.py +++ b/okx/Funding.py @@ -1,12 +1,17 @@ -from .client import Client +from .okxclient import OkxClient from .consts import * -class FundingAPI(Client): +class FundingAPI(OkxClient): - 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 __init__(self, api_key='-1', api_secret_key='-1', passphrase='-1', use_server_time=None, flag='1', domain = 'https://www.okx.com',debug = False, proxy=None): + OkxClient.__init__(self, api_key, api_secret_key, passphrase, use_server_time, flag, domain, debug, proxy) + + # Get Non Tradable Assets + def get_non_tradable_assets(self, ccy: str = ''): + params = {'ccy': ccy} + return self._request_with_params(GET, NON_TRADABLE_ASSETS, params) # Get Deposit Address def get_deposit_address(self, ccy): @@ -30,19 +35,21 @@ def funds_transfer(self, ccy, amt, from_, to, type='0', subAcct='', instId='', t 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} + def withdrawal(self, ccy, amt, dest, toAddr, chain='', areaCode='', clientId=''): + params = {'ccy': ccy, 'amt': amt, 'dest': dest, 'toAddr': toAddr, 'chain': chain, + 'areaCode': areaCode, '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) + def get_deposit_history(self, ccy='', type='', state='', after='', before='', limit='', txId='', depId='', fromWdId=''): + params = {'ccy': ccy, 'type': type, 'state': state, 'after': after, 'before': before, 'limit': limit, 'txId': txId, + 'depId': depId, 'fromWdId': fromWdId} + return self._request_with_params(GET, DEPOSIT_HISTORY, 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) + def get_withdrawal_history(self, ccy='', wdId='', state='', after='', before='', limit='',txId=''): + params = {'ccy': ccy, 'wdId': wdId, 'state': state, 'after': after, 'before': before, 'limit': limit,'txId':txId} + return self._request_with_params(GET, WITHDRAWAL_HISTORY, params) # Get Currencies def get_currencies(self, ccy=''): @@ -72,31 +79,6 @@ 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 = { @@ -118,9 +100,20 @@ def get_asset_valuation(self,ccy = ''): } return self._request_with_params(GET, ASSET_VALUATION, params) - #GET / api / v5 / asset / saving - balance - def get_saving_balance(self,ccy = ''): + #Get non-tradable assets + def get_non_tradable_assets(self, ccy=''): params = { - 'ccy':ccy + 'ccy': ccy } - return self._request_with_params(GET, GET_SAVING_BALANCE, params) + return self._request_with_params(GET, GET_NON_TRADABLE_ASSETS, params) + + #Get deposit withdraw status + def get_deposit_withdraw_status(self, wdId='', txId='', ccy='', to='', chain=''): + params = {'wdId': wdId, 'txId': txId, 'ccy': ccy, 'to': to, 'chain': chain} + return self._request_with_params(GET, GET_DEPOSIT_WITHDrAW_STATUS, params) + + #Get withdrawal history + def get_withdrawal_history(self, ccy='', wdId='', clientId='', txId='', type='', state='', after='', before ='', limit=''): + params = {'ccy': ccy, 'wdId': wdId, 'clientId': clientId, 'txId': txId, 'type': type, 'state': state, 'after': after, 'before': before, 'limit': limit} + return self._request_with_params(GET, GET_WITHDRAWAL_HISTORY, params) + diff --git a/okx/Grid.py b/okx/Grid.py index 6cf49914..74b6a9b5 100644 --- a/okx/Grid.py +++ b/okx/Grid.py @@ -1,10 +1,10 @@ -from .client import Client +from .okxclient import OkxClient 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) +class GridAPI(OkxClient): + def __init__(self, api_key='-1', api_secret_key='-1', passphrase='-1', use_server_time=None, flag='1', domain = 'https://www.okx.com',debug = False, proxy=None): + OkxClient.__init__(self, api_key, api_secret_key, passphrase, use_server_time, flag, domain, debug, proxy) def grid_order_algo(self, instId='', algoOrdType='', maxPx='', minPx='', gridNum='', runType='', tpTriggerPx='', slTriggerPx='', tag='', quoteSz='', baseSz='', sz='', direction='', lever='', basePos=''): @@ -76,3 +76,57 @@ def grid_ai_param(self, algoOrdType='', instId='', direction='', duration=''): 'duration':duration } return self._request_with_params(GET, GRID_AI_PARAM, params) + + # - Place recurring buy order + def place_recurring_buy_order(self, stgyName='', recurringList=[], period='', recurringDay='', recurringTime='', + timeZone='', amt='', investmentCcy='', tdMode='', algoClOrdId='', tag=''): + params = {'stgyName': stgyName, 'recurringList': recurringList, 'period': period, 'recurringDay': recurringDay, + 'recurringTime': recurringTime, + 'timeZone': timeZone, 'amt': amt, 'investmentCcy': investmentCcy, 'tdMode': tdMode, + 'algoClOrdId': algoClOrdId, 'tag': tag} + return self._request_with_params(POST, PLACE_RECURRING_BUY_ORDER, params) + + # - Amend recurring buy order + def amend_recurring_buy_order(self, algoId='', stgyName=''): + params = {'algoId': algoId, 'stgyName': stgyName} + return self._request_with_params(POST, AMEND_RECURRING_BUY_ORDER, params) + + # - Stop recurring buy order + def stop_recurring_buy_order(self, orders_data): + return self._request_with_params(POST, STOP_RECURRING_BUY_ORDER, orders_data) + + # - Get recurring buy order list + def get_recurring_buy_order_list(self, algoId='', after='', before='', limit=''): + params = { + 'algoId': algoId, + 'after': after, + 'before': before, + 'limit': limit + } + return self._request_with_params(GET, GET_RECURRING_BUY_ORDER_LIST, params) + + # - Get recurring buy order history + def get_recurring_buy_order_history(self, algoId='', after='', before='', limit=''): + params = { + 'algoId': algoId, + 'after': after, + 'before': before, + 'limit': limit + } + return self._request_with_params(GET, GET_RECURRING_BUY_ORDER_HISTORY, params) + + # - Get recurring buy order details + def get_recurring_buy_order_details(self, algoId=''): + params = {'algoId': algoId} + return self._request_with_params(GET, GET_RECURRING_BUY_ORDER_DETAILS, params) + + # - Get recurring buy sub orders + def get_recurring_buy_sub_orders(self, algoId='', ordId='', after='', before='', limit=''): + params = { + 'algoId': algoId, + 'ordId': ordId, + 'after': after, + 'before': before, + 'limit': limit + } + return self._request_with_params(GET, GET_RECURRING_BUY_SUB_ORDERS, params) diff --git a/okx/MarketData.py b/okx/MarketData.py index 1dc2bdf0..35f4891e 100644 --- a/okx/MarketData.py +++ b/okx/MarketData.py @@ -1,11 +1,11 @@ -from .client import Client +from .okxclient import OkxClient from .consts import * -class MarketAPI(Client): +class MarketAPI(OkxClient): - 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 __init__(self, api_key='-1', api_secret_key='-1', passphrase='-1', use_server_time=None, flag='1', domain = 'https://www.okx.com',debug = False, proxy=None): + OkxClient.__init__(self, api_key, api_secret_key, passphrase, use_server_time, flag, domain, debug, proxy) # Get Tickers @@ -60,10 +60,6 @@ def get_trades(self, instId, limit=''): 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} @@ -115,6 +111,20 @@ def get_block_trades(self,instId = ''): } return self._request_with_params(GET, BLOCK_TRADES, params) + #- Get order lite book + def get_order_lite_book(self,instId = ''): + params = { + 'instId':instId + } + return self._request_with_params(GET, GET_ORDER_LITE_BOOK, params) + + #- Get option trades + def get_option_trades(self,instFamily = ''): + params = { + 'instFamily':instFamily + } + return self._request_with_params(GET, GET_OPTION_TRADES, params) + diff --git a/okx/NDBroker.py b/okx/NDBroker.py deleted file mode 100644 index 01dcb339..00000000 --- a/okx/NDBroker.py +++ /dev/null @@ -1,150 +0,0 @@ -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 index 10438ebc..b3bb9614 100644 --- a/okx/PublicData.py +++ b/okx/PublicData.py @@ -1,11 +1,11 @@ -from .client import Client +from .okxclient import OkxClient from .consts import * -class PublicAPI(Client): +class PublicAPI(OkxClient): - 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 __init__(self, api_key='-1', api_secret_key='-1', passphrase='-1', use_server_time=None, flag='1', domain = 'https://www.okx.com',debug = False, proxy=None): + OkxClient.__init__(self, api_key, api_secret_key, passphrase, use_server_time, flag, domain, debug, proxy) # Get Instruments def get_instruments(self, instType, uly='', instId='',instFamily = ''): @@ -56,13 +56,6 @@ def discount_interest_free_quota(self, ccy=''): 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} @@ -113,5 +106,19 @@ def get_convert_contract_coin(self,type = '',instId = '',sz = '',px = '',unit = } return self._request_with_params(GET, CONVERT_CONTRACT_COIN, params) + # Get option tickBands + def get_option_tickBands(self, instType='', instFamily=''): + params = { + 'instType': instType, + 'instFamily': instFamily + } + return self._request_with_params(GET, GET_OPTION_TICKBANDS, params) - + # Get option trades + def get_option_trades(self, instId='', instFamily='', optType=''): + params = { + 'instId': instId, + 'instFamily': instFamily, + 'optType': optType + } + return self._request_with_params(GET, GET_OPTION_TRADES, params) diff --git a/okx/SpreadTrading.py b/okx/SpreadTrading.py new file mode 100644 index 00000000..46b0b8be --- /dev/null +++ b/okx/SpreadTrading.py @@ -0,0 +1,67 @@ +from .okxclient import OkxClient +from .consts import * + + +class SpreadTradingAPI(OkxClient): + + def __init__(self, api_key='-1', api_secret_key='-1', passphrase='-1', use_server_time=None, flag='1', domain = 'https://www.okx.com',debug = False, proxy=None): + OkxClient.__init__(self, api_key, api_secret_key, passphrase, use_server_time, flag, domain, debug, proxy) + + # Place Order + def place_order(self, sprdId='', clOrdId='', tag='', side='', ordType='', sz='', px=''): + params = {'sprdId': sprdId, 'clOrdId': clOrdId, 'tag': tag, 'side': side, 'ordType': ordType, 'sz': sz, + 'px': px} + return self._request_with_params(POST, SPREAD_PLACE_ORDER, params) + + # Cancel Order + def cancel_order(self,ordId='', clOrdId=''): + params = {'ordId': ordId, 'clOrdId': clOrdId} + return self._request_with_params(POST, SPREAD_CANCEL_ORDER, params) + + # Cancel All orders + def cancel_all_orders(self, sprdId=''): + params = {'sprdId': sprdId} + return self._request_with_params(POST, SPREAD_CANCEL_ALL_ORDERS, params) + + # Get order details + def get_order_details(self, ordId='', clOrdId=''): + params = {'ordId': ordId, 'clOrdId': clOrdId} + return self._request_with_params(GET, SPREAD_GET_ORDER_DETAILS, params) + + # Get active orders + def get_active_orders(self, sprdId='', ordType='', state='', beginId='', endId='', limit=''): + params = {'sprdId': sprdId, 'ordType': ordType, 'state': state, 'beginId': beginId, 'endId': endId, 'limit': limit} + return self._request_with_params(GET, SPREAD_GET_ACTIVE_ORDERS, params) + + # Get orders (last 7 days) + def get_orders(self, sprdId='', ordType='', state='', beginId='', endId='', begin='', end='', limit=''): + params = {'sprdId': sprdId, 'ordType': ordType, 'state': state, 'beginId': beginId, 'endId': endId, + 'begin': begin, 'end': end, 'limit': limit} + return self._request_with_params(GET, SPREAD_GET_ORDERS, params) + + # Get trades (last 7 days) + def get_trades(self, sprdId='', tradeId='', ordId='', beginId='', endId='', begin='', end='', limit=''): + params = {'sprdId': sprdId, 'tradeId': tradeId, 'ordId': ordId, 'beginId': beginId, 'endId': endId, + 'begin': begin, 'end': end, 'limit': limit} + return self._request_with_params(GET, SPREAD_GET_TRADES, params) + + # Get Spreads (Public) + def get_spreads(self, baseCcy='',instId='', sprdId='', state=''): + params = {'baseCcy': baseCcy, 'instId': instId, 'sprdId': sprdId, 'state': state} + return self._request_with_params(GET, SPREAD_GET_SPREADS, params) + + # Get order book (Public) + def get_order_book(self, sprdId='', sz=''): + params = {'sprdId': sprdId, 'sz': sz} + return self._request_with_params(GET, SPREAD_GET_ORDER_BOOK, params) + + # Get ticker (Public) + def get_ticker(self, sprdId=''): + params = {'sprdId': sprdId} + return self._request_with_params(GET, SPREAD_GET_TICKER, params) + + # Get public trades (Public) + def get_public_trades(self, sprdId=''): + params = {'sprdId': sprdId} + return self._request_with_params(GET, SPREAD_GET_PUBLIC_TRADES, params) + diff --git a/okx/Status.py b/okx/Status.py index ab9cf803..2304fb60 100644 --- a/okx/Status.py +++ b/okx/Status.py @@ -1,10 +1,10 @@ -from .client import Client +from .okxclient import OkxClient 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) +class StatusAPI(OkxClient): + def __init__(self, api_key='-1', api_secret_key='-1', passphrase='-1', use_server_time=None, flag='1', domain = 'https://www.okx.com',debug = False, proxy=None): + OkxClient.__init__(self, api_key, api_secret_key, passphrase, use_server_time, flag, domain, debug, proxy) def status(self, state=''): params = {'state': state} diff --git a/okx/SubAccount.py b/okx/SubAccount.py index ea0428b4..abd128ab 100644 --- a/okx/SubAccount.py +++ b/okx/SubAccount.py @@ -1,10 +1,10 @@ -from .client import Client +from .okxclient import OkxClient 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) +class SubAccountAPI(OkxClient): + def __init__(self, api_key='-1', api_secret_key='-1', passphrase='-1', use_server_time=None, flag='1', domain = 'https://www.okx.com',debug = False, proxy=None): + OkxClient.__init__(self, api_key, api_secret_key, passphrase, use_server_time, flag, domain, debug, proxy) def get_account_balance(self, subAcct): params = {"subAcct": subAcct} @@ -59,5 +59,18 @@ def get_funding_balance(self,subAcct='',ccy=''): } return self._request_with_params(GET, GET_ASSET_SUBACCOUNT_BALANCE, params) + # - Set sub_accounts VIP loan% + def set_sub_accounts_VIP_loan(self, enable='', alloc=[]): + params = { + 'enable': enable, + 'alloc': alloc + } + return self._request_with_params(POST, SET_SUB_ACCOUNTS_VIP_LOAN, params) - + # - Get sub_account borrow interest and limit + def get_sub_account_borrow_interest_and_limit(self, subAcct='', ccy=''): + params = { + 'subAcct': subAcct, + 'ccy': ccy + } + return self._request_with_params(GET, GET_SUB_ACCOUNT_BORROW_INTEREST_AND_LIMIT, params) diff --git a/okx/Trade.py b/okx/Trade.py index 2db2e833..5e6c6176 100644 --- a/okx/Trade.py +++ b/okx/Trade.py @@ -1,18 +1,22 @@ -from .client import Client +import json + +from .okxclient import OkxClient from .consts import * -class TradeAPI(Client): +class TradeAPI(OkxClient): - 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 __init__(self, api_key='-1', api_secret_key='-1', passphrase='-1', use_server_time=None, flag='1', + domain='https://www.okx.com', debug=False, proxy=None): + OkxClient.__init__(self, api_key, api_secret_key, passphrase, use_server_time, flag, domain, debug, proxy) # Place Order def place_order(self, instId, tdMode, side, ordType, sz, ccy='', clOrdId='', tag='', posSide='', px='', - reduceOnly='', tgtCcy=''): + reduceOnly='', tgtCcy='', stpMode='', attachAlgoOrds=None, pxUsd='', pxVol='', banAmend=''): 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} + 'tgtCcy': tgtCcy, 'stpMode': stpMode, 'pxUsd': pxUsd, 'pxVol': pxVol, 'banAmend': banAmend} + params['attachAlgoOrds'] = attachAlgoOrds return self._request_with_params(POST, PLACR_ORDER, params) # Place Multiple Orders @@ -22,17 +26,21 @@ def place_multiple_orders(self, 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) + return self._request_with_params(POST, CANCEL_ORDER, params) # Cancel Multiple Orders def cancel_multiple_orders(self, orders_data): - return self._request_with_params(POST, CANAEL_BATCH_ORDERS, orders_data) + return self._request_with_params(POST, CANCEL_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} + def amend_order(self, instId, cxlOnFail='', ordId='', clOrdId='', reqId='', newSz='', newPx='', newTpTriggerPx='', + newTpOrdPx='', newSlTriggerPx='', newSlOrdPx='', newTpTriggerPxType='', newSlTriggerPxType='', + attachAlgoOrds='', newTriggerPx='', newOrdPx=''): + params = {'instId': instId, 'cxlOnFail': cxlOnFail, 'ordId': ordId, 'clOrdId': clOrdId, 'reqId': reqId, + 'newSz': newSz, 'newPx': newPx, 'newTpTriggerPx': newTpTriggerPx, 'newTpOrdPx': newTpOrdPx, + 'newSlTriggerPx': newSlTriggerPx, 'newSlOrdPx': newSlOrdPx, 'newTpTriggerPxType': newTpTriggerPxType, + 'newSlTriggerPxType': newSlTriggerPxType, 'newTriggerPx': newTriggerPx, 'newOrdPx': newOrdPx} + params['attachAlgoOrds'] = attachAlgoOrds return self._request_with_params(POST, AMEND_ORDER, params) # Amend Multiple Orders @@ -40,8 +48,9 @@ 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} + def close_positions(self, instId, mgnMode, posSide='', ccy='', autoCxl='', clOrdId='', tag=''): + params = {'instId': instId, 'mgnMode': mgnMode, 'posSide': posSide, 'ccy': ccy, 'autoCxl': autoCxl, + 'clOrdId': clOrdId, 'tag': tag} return self._request_with_params(POST, CLOSE_POSITION, params) # Get Order Details @@ -50,27 +59,32 @@ def get_order(self, instId, ordId='', 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 = ''): + 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} + '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 = ''): + def get_orders_history(self, instType, uly='', instId='', ordType='', state='', after='', before='', begin='', + end='', limit='', instFamily=''): params = {'instType': instType, 'uly': uly, 'instId': instId, 'ordType': ordType, 'state': state, - 'after': after, 'before': before, 'limit': limit,'instFamily':instFamily} + 'after': after, 'before': before, 'begin': begin, 'end': end, '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 = ''): + def get_orders_history_archive(self, instType, uly='', instId='', ordType='', state='', after='', before='', + begin='', end='', limit='', instFamily=''): params = {'instType': instType, 'uly': uly, 'instId': instId, 'ordType': ordType, 'state': state, - 'after': after, 'before': before, 'limit': limit,'instFamily':instFamily} + 'after': after, 'before': before, 'begin': begin, 'end': end, '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 = ''): + def get_fills(self, instType='', uly='', instId='', ordId='', after='', before='', limit='', instFamily='',begin='',end=''): params = {'instType': instType, 'uly': uly, 'instId': instId, 'ordId': ordId, 'after': after, 'before': before, - 'limit': limit,'instFamily':instFamily} + 'limit': limit, 'instFamily': instFamily,'begin': begin, 'end' :end} return self._request_with_params(GET, ORDER_FILLS, params) # Place Algo Order @@ -80,32 +94,31 @@ def place_algo_order(self, instId='', tdMode='', side='', ordType='', sz='', ccy triggerPx='', orderPx='', tgtCcy='', pxVar='', pxSpread='', szLimit='', pxLimit='', timeInterval='', tpTriggerPxType='', slTriggerPxType='', - callbackRatio='',callbackSpread='',activePx='',tag='',triggerPxType=''): + callbackRatio='', callbackSpread='', activePx='', tag='', triggerPxType='', closeFraction='' + , quickMgnType='', algoClOrdId='', tradeQuoteCcy='', tpOrdKind='', cxlOnClosePos='' + , chaseType='', chaseVal='', maxChaseType='', maxChaseVal='', attachAlgoOrds=[]): 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,} + 'callbackRatio': callbackRatio, 'callbackSpread': callbackSpread, 'activePx': activePx, + 'tag': tag, 'triggerPxType': triggerPxType, 'closeFraction': closeFraction, + 'quickMgnType': quickMgnType, 'algoClOrdId': algoClOrdId, 'tradeQuoteCcy': tradeQuoteCcy, + 'tpOrdKind': tpOrdKind, 'cxlOnClosePos': cxlOnClosePos, 'chaseType': chaseType, 'chaseVal': chaseVal, + 'maxChaseType': maxChaseType, 'maxChaseVal': maxChaseVal, 'attachAlgoOrds': attachAlgoOrds} 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=''): + 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) + return self._request_with_params(GET, ORDERS_ALGO_PENDING, params) # Get Algo Order History def order_algos_history(self, ordType, state='', algoId='', instType='', instId='', after='', before='', limit=''): @@ -114,46 +127,79 @@ def order_algos_history(self, ordType, state='', algoId='', instType='', instId= 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=''): + def get_fills_history(self, instType, uly='', instId='', ordId='', after='', before='', limit='', instFamily='', begin='', end=''): params = {'instType': instType, 'uly': uly, 'instId': instId, 'ordId': ordId, 'after': after, 'before': before, - 'limit': limit,'instFamily':instFamily} + 'limit': limit, 'instFamily': instFamily, 'begin': begin, 'end': end} 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 = ''): + def easy_convert(self, fromCcy=[], toCcy=''): params = { - 'fromCcy':fromCcy, - 'toCcy':toCcy + 'fromCcy': fromCcy, + 'toCcy': toCcy } return self._request_with_params(POST, EASY_CONVERT, params) - def get_easy_convert_history(self,before = '',after = '',limit = ''): + def get_easy_convert_history(self, before='', after='', limit=''): params = { - 'before':before, - 'after':after, - 'limit':limit + 'before': before, + 'after': after, + 'limit': limit } - return self._request_with_params(GET,CONVERT_EASY_HISTORY,params) + return self._request_with_params(GET, CONVERT_EASY_HISTORY, params) - def get_oneclick_repay_list(self,debtType = ''): + def get_oneclick_repay_list(self, debtType=''): params = { - 'debtType':debtType + 'debtType': debtType } - return self._request_with_params(GET,ONE_CLICK_REPAY_SUPPORT,params) + return self._request_with_params(GET, ONE_CLICK_REPAY_SUPPORT, params) - def oneclick_repay(self,debtCcy = [] , repayCcy=''): + 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) + + # Get algo order details + def get_algo_order_details(self, algoId='', algoClOrdId=''): + params = {'algoId': algoId, 'algoClOrdId': algoClOrdId} + return self._request_with_params(GET, GET_ALGO_ORDER_DETAILS, params) + + # Amend algo order + def amend_algo_order(self, instId='', algoId='', algoClOrdId='', cxlOnFail='', reqId='', newSz='', newTriggerPx='', newOrdPx='', + newTpTriggerPx='', newTpOrdPx='', newSlTriggerPx='', newSlOrdPx='', newTpTriggerPxType='', + newSlTriggerPxType=''): + params = {'instId': instId, 'algoId': algoId, 'algoClOrdId': algoClOrdId, 'cxlOnFail': cxlOnFail, + 'reqId': reqId, 'newSz': newSz, 'newTriggerPx': newTriggerPx, 'newOrdPx': newOrdPx, 'newTpTriggerPx': newTpTriggerPx, 'newTpOrdPx': newTpOrdPx, + 'newSlTriggerPx': newSlTriggerPx, 'newSlOrdPx': newSlOrdPx, + 'newTpTriggerPxType': newTpTriggerPxType, 'newSlTriggerPxType': newSlTriggerPxType} + return self._request_with_params(POST, AMEND_ALGO_ORDER, params) + + def get_oneclick_repay_list_v2(self): + return self._request_without_params(GET, ONE_CLICK_REPAY_SUPPORT_V2) + + def oneclick_repay_v2(self, debtCcy='', repayCcyList=[]): params = { - 'debtCcy':debtCcy, - 'repayCcy':repayCcy + 'debtCcy': debtCcy, + 'repayCcyList': repayCcyList } - return self._request_with_params(POST,ONE_CLICK_REPAY,params) + return self._request_with_params(POST, ONE_CLICK_REPAY_V2, params) - def oneclick_repay_history(self,after = '',before = '',limit = ''): + def oneclick_repay_history_v2(self, after='', before='', limit=''): params = { - 'after':after, - 'before':before, - 'limit':limit + 'after': after, + 'before': before, + 'limit': limit } - return self._request_with_params(GET,ONE_CLICK_REPAY_HISTORY,params) + return self._request_with_params(GET, ONE_CLICK_REPAY_HISTORY_V2, params) diff --git a/okx/TradingData.py b/okx/TradingData.py index 0d8bf70c..7100ef49 100644 --- a/okx/TradingData.py +++ b/okx/TradingData.py @@ -1,11 +1,11 @@ -from .client import Client +from .okxclient import OkxClient from .consts import * -class TradingDataAPI(Client): +class TradingDataAPI(OkxClient): - 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 __init__(self, api_key='-1', api_secret_key='-1', passphrase='-1', use_server_time=None, flag='1', domain = 'https://www.okx.com',debug = False, proxy=None): + OkxClient.__init__(self, api_key, api_secret_key, passphrase, use_server_time, flag, domain, debug, proxy) def get_support_coin(self): diff --git a/okx/__init__.py b/okx/__init__.py index 71c25d8f..2dbeeb8b 100644 --- a/okx/__init__.py +++ b/okx/__init__.py @@ -2,4 +2,4 @@ Python SDK for the OKX API v5 """ -__version__="0.1.0" \ No newline at end of file +__version__="0.4.0" \ No newline at end of file diff --git a/okx/__pycache__/Broker_api.cpython-38.pyc b/okx/__pycache__/Broker_api.cpython-38.pyc deleted file mode 100644 index f22616ab..00000000 Binary files a/okx/__pycache__/Broker_api.cpython-38.pyc and /dev/null differ diff --git a/okx/__pycache__/Market_api.cpython-38.pyc b/okx/__pycache__/Market_api.cpython-38.pyc deleted file mode 100644 index d2d5e4d3..00000000 Binary files a/okx/__pycache__/Market_api.cpython-38.pyc and /dev/null differ diff --git a/okx/__pycache__/Public_api.cpython-38.pyc b/okx/__pycache__/Public_api.cpython-38.pyc deleted file mode 100644 index 229588cd..00000000 Binary files a/okx/__pycache__/Public_api.cpython-38.pyc and /dev/null differ diff --git a/okx/__pycache__/Rfq_api.cpython-38.pyc b/okx/__pycache__/Rfq_api.cpython-38.pyc deleted file mode 100644 index 84090aa2..00000000 Binary files a/okx/__pycache__/Rfq_api.cpython-38.pyc and /dev/null differ diff --git a/okx/__pycache__/TradingBot_api.cpython-38.pyc b/okx/__pycache__/TradingBot_api.cpython-38.pyc deleted file mode 100644 index 77cbb32b..00000000 Binary files a/okx/__pycache__/TradingBot_api.cpython-38.pyc and /dev/null differ diff --git a/okx/__pycache__/__init__.cpython-38.pyc b/okx/__pycache__/__init__.cpython-38.pyc deleted file mode 100644 index 56cc821d..00000000 Binary files a/okx/__pycache__/__init__.cpython-38.pyc and /dev/null differ diff --git a/okx/__pycache__/__init__.cpython-39.pyc b/okx/__pycache__/__init__.cpython-39.pyc deleted file mode 100644 index b8c662ba..00000000 Binary files a/okx/__pycache__/__init__.cpython-39.pyc and /dev/null differ diff --git a/okx/__pycache__/client.cpython-38.pyc b/okx/__pycache__/client.cpython-38.pyc deleted file mode 100644 index aba0e305..00000000 Binary files a/okx/__pycache__/client.cpython-38.pyc and /dev/null differ diff --git a/okx/__pycache__/client.cpython-39.pyc b/okx/__pycache__/client.cpython-39.pyc deleted file mode 100644 index 353bc601..00000000 Binary files a/okx/__pycache__/client.cpython-39.pyc and /dev/null differ diff --git a/okx/__pycache__/consts.cpython-38.pyc b/okx/__pycache__/consts.cpython-38.pyc deleted file mode 100644 index e0d7f968..00000000 Binary files a/okx/__pycache__/consts.cpython-38.pyc and /dev/null differ diff --git a/okx/__pycache__/consts.cpython-39.pyc b/okx/__pycache__/consts.cpython-39.pyc deleted file mode 100644 index 23716f33..00000000 Binary files a/okx/__pycache__/consts.cpython-39.pyc and /dev/null differ diff --git a/okx/__pycache__/exceptions.cpython-38.pyc b/okx/__pycache__/exceptions.cpython-38.pyc deleted file mode 100644 index 9f2068bd..00000000 Binary files a/okx/__pycache__/exceptions.cpython-38.pyc and /dev/null differ diff --git a/okx/__pycache__/exceptions.cpython-39.pyc b/okx/__pycache__/exceptions.cpython-39.pyc deleted file mode 100644 index 02bfc270..00000000 Binary files a/okx/__pycache__/exceptions.cpython-39.pyc and /dev/null differ diff --git a/okx/__pycache__/status_api.cpython-38.pyc b/okx/__pycache__/status_api.cpython-38.pyc deleted file mode 100644 index fc7e9dc7..00000000 Binary files a/okx/__pycache__/status_api.cpython-38.pyc and /dev/null differ diff --git a/okx/__pycache__/subAccount_api.cpython-38.pyc b/okx/__pycache__/subAccount_api.cpython-38.pyc deleted file mode 100644 index 48781463..00000000 Binary files a/okx/__pycache__/subAccount_api.cpython-38.pyc and /dev/null differ diff --git a/okx/__pycache__/utils.cpython-38.pyc b/okx/__pycache__/utils.cpython-38.pyc deleted file mode 100644 index 675772ed..00000000 Binary files a/okx/__pycache__/utils.cpython-38.pyc and /dev/null differ diff --git a/okx/__pycache__/utils.cpython-39.pyc b/okx/__pycache__/utils.cpython-39.pyc deleted file mode 100644 index a801254b..00000000 Binary files a/okx/__pycache__/utils.cpython-39.pyc and /dev/null differ diff --git a/okx/consts.py b/okx/consts.py index 833e44f5..aae07780 100644 --- a/okx/consts.py +++ b/okx/consts.py @@ -1,5 +1,5 @@ -# http header -#API_URL = 'https://www.okx.com' +# Http header +API_URL = 'https://www.okx.com' CONTENT_TYPE = 'Content-Type' OK_ACCESS_KEY = 'OK-ACCESS-KEY' @@ -18,7 +18,7 @@ SERVER_TIMESTAMP_URL = '/api/v5/public/time' -# account-complete-testcomplete +# Account POSITION_RISK='/api/v5/account/account-position-risk' ACCOUNT_INFO = '/api/v5/account/balance' POSITION_INFO = '/api/v5/account/positions' @@ -44,33 +44,52 @@ 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 +POSITIONS_HISTORY = '/api/v5/account/positions-history' +GET_PM_LIMIT = '/api/v5/account/position-tiers' +GET_VIP_INTEREST_ACCRUED_DATA = '/api/v5/account/vip-interest-accrued' +GET_VIP_INTEREST_DEDUCTED_DATA = '/api/v5/account/vip-interest-deducted' +GET_VIP_LOAN_ORDER_LIST= '/api/v5/account/vip-loan-order-list' +GET_VIP_LOAN_ORDER_DETAIL= '/api/v5/account/vip-loan-order-detail' +SET_RISK_OFFSET_TYPE = '/api/v5/account/set-riskOffset-type' +SET_AUTO_LOAN = '/api/v5/account/set-auto-loan' +SET_ACCOUNT_LEVEL = '/api/v5/account/set-account-level' +ACTIVSTE_OPTION = '/api/v5/account/activate-option' +POSITION_BUILDER = '/api/v5/account/position-builder' +GET_INSTRUMENTS = '/api/v5/account/instruments' +BORROWING_LIMIT = '/api/v5/account/fixed-loan/borrowing-limit' +BORROWING_QUOTE = '/api/v5/account/fixed-loan/borrowing-quote' +PLACE_BORROWING_ORDER= '/api/v5/account/fixed-loan/borrowing-order' +AMEND_BORROWING_ORDER='/api/v5/account/fixed-loan/amend-borrowing-order' +MANUAL_REBORROW = '/api/v5/account/fixed-loan/manual-reborrow' +REPAY_BORROWING_ORDER='/api/v5/account/fixed-loan/repay-borrowing-order' +BORROWING_ORDERS_LIST='/api/v5/account/fixed-loan/borrowing-orders-list' +MANUAL_REBORROW_REPAY = '/api/v5/account/spot-manual-borrow-repay' +SET_AUTO_REPAY='/api/v5/account/set-auto-repay' +GET_BORROW_REPAY_HISTORY='/api/v5/account/spot-borrow-repay-history' -# funding-complete-testcomplete +# Funding +NON_TRADABLE_ASSETS = '/api/v5/asset/non-tradable-assets' 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' +DEPOSIT_HISTORY = '/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 +CANCEL_WITHDRAWAL = '/api/v5/asset/cancel-withdrawal' +WITHDRAWAL_HISTORY = '/api/v5/asset/withdrawal-history' +CONVERT_DUST_ASSETS = '/api/v5/asset/convert-dust-assets' +ASSET_VALUATION = '/api/v5/asset/asset-valuation' +GET_WITHDRAWAL_HISTORY = '/api/v5/asset/withdrawal-history' +GET_NON_TRADABLE_ASSETS = '/api/v5/asset/non-tradable-assets' +GET_DEPOSIT_WITHDrAW_STATUS = '/api/v5/asset/deposit-withdraw-status' + + +# Market Data TICKERS_INFO = '/api/v5/market/tickers' TICKER_INFO = '/api/v5/market/ticker' INDEX_TICKERS = '/api/v5/market/index-tickers' @@ -81,15 +100,16 @@ 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 +INDEX_COMPONENTS = '/api/v5/market/index-components' +EXCHANGE_RATE = '/api/v5/market/exchange-rate' +HISTORY_TRADES = '/api/v5/market/history-trades' +BLOCK_TICKERS = '/api/v5/market/block-tickers' +BLOCK_TICKER = '/api/v5/market/block-ticker' +BLOCK_TRADES = '/api/v5/market/block-trades' +GET_ORDER_LITE_BOOK = '/api/v5/market/books-lite' +GET_OPTION_TRADES = '/api/v5/market/option/instrument-family-trades' + +# Public Data INSTRUMENT_INFO = '/api/v5/public/instruments' DELIVERY_EXERCISE = '/api/v5/public/delivery-exercise-history' OPEN_INTEREST = '/api/v5/public/open-interest' @@ -103,13 +123,15 @@ 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 +INTEREST_LOAN = '/api/v5/public/interest-rate-loan-quota' +UNDERLYING = '/api/v5/public/underlying' +VIP_INTEREST_RATE_LOAN_QUOTA = '/api/v5/public/vip-interest-rate-loan-quota' +INSURANCE_FUND = '/api/v5/public/insurance-fund' +CONVERT_CONTRACT_COIN = '/api/v5/public/convert-contract-coin' +GET_OPTION_TICKBANDS = '/api/v5/public/instrument-tick-bands' +GET_OPTION_TRADES = '/api/v5/public/option-trades' -# TRADING DATA-COMPLETE +# Trading data 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' @@ -121,11 +143,11 @@ INTEREST_VOLUME_STRIKE = '/api/v5/rubik/stat/option/open-interest-volume-strike' TAKER_FLOW = '/api/v5/rubik/stat/option/taker-block-volume' -# TRADE-Complete +# Trade 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' +CANCEL_ORDER = '/api/v5/trade/cancel-order' +CANCEL_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' @@ -137,59 +159,45 @@ 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_PENDING = '/api/v5/trade/orders-algo-pending' ORDERS_ALGO_HISTORY = '/api/v5/trade/orders-algo-history' - +GET_ALGO_ORDER_DETAILS = '/api/v5/trade/order-algo' +AMEND_ALGO_ORDER = '/api/v5/trade/amend-algos' 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' +ONE_CLICK_REPAY_SUPPORT_V2 = '/api/v5/trade/one-click-repay-currency-list-v2' +ONE_CLICK_REPAY_V2 = '/api/v5/trade/one-click-repay-v2' +ONE_CLICK_REPAY_HISTORY_V2 = '/api/v5/trade/one-click-repay-history-v2' -# SubAccount-complete-testwriteComplete +# SubAccount 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 +ENTRUST_SUBACCOUNT_LIST = '/api/v5/users/entrust-subaccount-list' +SET_TRSNSFER_OUT = '/api/v5/users/subaccount/set-transfer-out' +GET_ASSET_SUBACCOUNT_BALANCE = '/api/v5/asset/subaccount/balances' +SET_SUB_ACCOUNTS_VIP_LOAN = '/api/v5/account/subaccount/set-loan-allocation' +GET_SUB_ACCOUNT_BORROW_INTEREST_AND_LIMIT = '/api/v5/account/subaccount/interest-limits' + +# Convert 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 Broker 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 +# BlockTrading COUNTERPARTIES = '/api/v5/rfq/counterparties' CREATE_RFQ = '/api/v5/rfq/create-rfq' CANCEL_RFQ = '/api/v5/rfq/cancel-rfq' @@ -208,7 +216,7 @@ MARKER_INSTRUMENT_SETTING = '/api/v5/rfq/maker-instrument-settings' -# tradingBot-Grid-complete-testcomplete +# Trading Bot 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' @@ -218,18 +226,78 @@ 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' +PLACE_RECURRING_BUY_ORDER = '/api/v5/tradingBot/recurring/order-algo' +AMEND_RECURRING_BUY_ORDER = '/api/v5/tradingBot/recurring/amend-order-algo' +STOP_RECURRING_BUY_ORDER = '/api/v5/tradingBot/recurring/stop-order-algo' +GET_RECURRING_BUY_ORDER_LIST = '/api/v5/tradingBot/recurring/orders-algo-pending' +GET_RECURRING_BUY_ORDER_HISTORY = '/api/v5/tradingBot/recurring/orders-algo-history' +GET_RECURRING_BUY_ORDER_DETAILS = '/api/v5/tradingBot/recurring/orders-algo-details' +GET_RECURRING_BUY_SUB_ORDERS = '/api/v5/tradingBot/recurring/sub-orders' -#stacking - all need to implement-testcomplete +# Stacking 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' +GET_SAVING_BALANCE = '/api/v5/finance/savings/balance' +SAVING_PURCHASE_REDEMPTION = '/api/v5/finance/savings/purchase-redempt' +SET_LENDING_RATE = '/api/v5/finance/savings/set-lending-rate' +GET_LENDING_HISTORY = '/api/v5/finance/savings/lending-history' +GET_PUBLIC_BORROW_INFO = '/api/v5/finance/savings/lending-rate-summary' +GET_PUBLIC_BORROW_HISTORY = '/api/v5/finance/savings/lending-rate-history' +STACK_ETH_PRODUCT_INFO = '/api/v5/finance/staking-defi/eth/product-info' +STACK_ETH_PURCHASE = '/api/v5/finance/staking-defi/eth/purchase' +STACK_ETH_REDEEM = '/api/v5/finance/staking-defi/eth/redeem' +STACK_ETH_BALANCE = '/api/v5/finance/staking-defi/eth/balance' +STACK_ETH_PURCHASE_REDEEM_HISTORY = '/api/v5/finance/staking-defi/eth/purchase-redeem-history' +STACK_ETH_APY_HISTORY = '/api/v5/finance/staking-defi/eth/apy-history' +STACK_SOL_PURCHASE = '/api/v5/finance/staking-defi/sol/purchase' +STACK_SOL_REDEEM = '/api/v5/finance/staking-defi/sol/redeem' +STACK_SOL_BALANCE = '/api/v5/finance/staking-defi/sol/balance' +STACK_SOL_PURCHASE_REDEEM_HISTORY = '/api/v5/finance/staking-defi/sol/purchase-redeem-history' +STACK_SOL_APY_HISTORY = '/api/v5/finance/staking-defi/sol/apy-history' +STACK_SOL_PRODUCT_INFO = '/api/v5/finance/staking-defi/sol/product-info' -# status-complete +# Status STATUS = '/api/v5/system/status' + +# Copy Trading +GET_EXISTING_LEADING_POSITIONS = '/api/v5/copytrading/current-subpositions' +GET_LEADING_POSITIONS_HISTORY = '/api/v5/copytrading/subpositions-history' +PLACE_LEADING_STOP_ORDER = '/api/v5/copytrading/algo-order' +CLOSE_LEADING_POSITIONS = '/api/v5/copytrading/close-subposition' +GET_LEADING_POSITIONS = '/api/v5/copytrading/instruments' +AMEND_EXISTING_LEADING_POSITIONS = '/api/v5/copytrading/set-instruments' +GET_PROFIT_SHARING_DETAILS = '/api/v5/copytrading/profit-sharing-details' +GET_TOTAL_PROFIT_SHARING = '/api/v5/copytrading/total-profit-sharing' +GET_UNREALIZED_PROFIT_SHARING_DETAILS = '/api/v5/copytrading/unrealized-profit-sharing-details' + +# Spread Trading˚ +SPREAD_PLACE_ORDER= '/api/v5/sprd/order' +SPREAD_CANCEL_ORDER = '/api/v5/sprd/cancel-order' +SPREAD_CANCEL_ALL_ORDERS = '/api/v5/sprd/mass-cancel' +SPREAD_GET_ORDER_DETAILS = '/api/v5/sprd/order' +SPREAD_GET_ACTIVE_ORDERS = '/api/v5/sprd/orders-pending' +SPREAD_GET_ORDERS = '/api/v5/sprd/orders-history' +SPREAD_GET_TRADES = '/api/v5/sprd/trades' +SPREAD_GET_SPREADS = '/api/v5/sprd/spreads' +SPREAD_GET_ORDER_BOOK = '/api/v5/sprd/books' +SPREAD_GET_TICKER = '/api/v5/sprd/ticker' +SPREAD_GET_PUBLIC_TRADES = '/api/v5/sprd/public-trades' + +# Flexible loan +FINANCE_BORROW_CURRENCIES = '/api/v5/finance/flexible-loan/borrow-currencies' +FINANCE_COLLATERAL_ASSETS = '/api/v5/finance/flexible-loan/collateral-assets' +FINANCE_MAX_LOAN = '/api/v5/finance/flexible-loan/max-loan' +FINANCE_MAX_REDEEM = '/api/v5/finance/flexible-loan/max-collateral-redeem-amount' +FINANCE_ADJUST_COLLATERAL = '/api/v5/finance/flexible-loan/adjust-collateral' +FINANCE_LOAN_INFO = '/api/v5/finance/flexible-loan/loan-info' +FINANCE_LOAN_HISTORY = '/api/v5/finance/flexible-loan/loan-history' +FINANCE_INTEREST_ACCRUED = '/api/v5/finance/flexible-loan/interest-accrued' + + diff --git a/okx/exceptions.py b/okx/exceptions.py index e3dd1831..ee8e1803 100644 --- a/okx/exceptions.py +++ b/okx/exceptions.py @@ -4,7 +4,6 @@ class OkxAPIException(Exception): def __init__(self, response): - print(response.text + ', ' + str(response.status_code)) self.code = 0 try: json_res = response.json() diff --git a/okx/client.py b/okx/okxclient.py similarity index 58% rename from okx/client.py rename to okx/okxclient.py index 26ae6033..e88e3a7d 100644 --- a/okx/client.py +++ b/okx/okxclient.py @@ -1,22 +1,29 @@ import json +import warnings +from datetime import datetime, timezone import httpx +from httpx import Client +from datetime import datetime, timezone -from . import consts as c, utils, exceptions +from loguru import logger +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'): +class OkxClient(Client): + def __init__(self, api_key='-1', api_secret_key='-1', passphrase='-1', use_server_time=None, flag='1',base_api=c.API_URL, debug=False, proxy=None): + super().__init__(base_url=base_api, http2=True, proxy=proxy) self.API_KEY = api_key self.API_SECRET_KEY = api_secret_key self.PASSPHRASE = passphrase - self.use_server_time = use_server_time + self.use_server_time = False self.flag = flag self.domain = base_api self.debug = debug - self.client = httpx.Client(base_url=base_api, http2=True) + if use_server_time is not None: + warnings.warn("use_server_time parameter is deprecated. Please remove it.", DeprecationWarning) def _request(self, method, request_path, params): if method == c.GET: @@ -32,14 +39,13 @@ def _request(self, method, request_path, params): header = utils.get_header_no_sign(self.flag, self.debug) response = None if self.debug == True: - print('domain:',self.domain) - print('url:',request_path) + logger.debug(f'domain: {self.domain}') + logger.debug(f'url: {request_path}') + logger.debug(f'body:{body}') if method == c.GET: - response = self.client.get(request_path, headers=header) + response = self.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) + response = self.post(request_path, data=body, headers=header) return response.json() def _request_without_params(self, method, request_path): @@ -50,8 +56,9 @@ def _request_with_params(self, method, request_path, params): def _get_timestamp(self): request_path = c.API_URL + c.SERVER_TIMESTAMP_URL - response = self.client.get(request_path) + response = self.get(request_path) if response.status_code == 200: - return response.json()['ts'] + ts = datetime.fromtimestamp(int(response.json()['data'][0]['ts']) / 1000.0, tz=timezone.utc) + return ts.isoformat(timespec='milliseconds').replace('+00:00', 'Z') else: return "" diff --git a/okx/utils.py b/okx/utils.py index f130a9b5..a32b50a2 100644 --- a/okx/utils.py +++ b/okx/utils.py @@ -1,6 +1,9 @@ import hmac import base64 import datetime + +from loguru import logger + from . import consts as c @@ -12,7 +15,7 @@ def sign(message, secretKey): def pre_hash(timestamp, method, request_path, body,debug = True): if debug == True: - print('body: ',body) + logger.debug(f'body: {body}') return str(timestamp) + str.upper(method) + request_path + body @@ -25,7 +28,7 @@ def get_header(api_key, sign, timestamp, passphrase, flag,debug = True): header[c.OK_ACCESS_PASSPHRASE] = passphrase header['x-simulated-trading'] = flag if debug == True: - print('header: ',header) + logger.debug(f'header: {header}') return header def get_header_no_sign(flag,debug = True): @@ -33,16 +36,15 @@ def get_header_no_sign(flag,debug = True): header[c.CONTENT_TYPE] = c.APPLICATION_JSON header['x-simulated-trading'] = flag if debug == True: - print('header: ',header) + logger.debug(f'header: {header}') return header def parse_params_to_str(params): url = '?' for key, value in params.items(): - if(value != ''): + if value is not None and value != '': url = url + str(key) + '=' + str(value) + '&' url = url[0:-1] - #print('url:',url) return url diff --git a/okx/websocket/WebSocketFactory.py b/okx/websocket/WebSocketFactory.py new file mode 100644 index 00000000..ff983e6b --- /dev/null +++ b/okx/websocket/WebSocketFactory.py @@ -0,0 +1,32 @@ +import asyncio +import logging +import ssl + +import certifi +import websockets + +logger = logging.getLogger(__name__) + + +class WebSocketFactory: + + def __init__(self, url): + self.url = url + self.websocket = None + self.loop = asyncio.get_event_loop() + + async def connect(self): + ssl_context = ssl.create_default_context() + ssl_context.load_verify_locations(certifi.where()) + try: + self.websocket = await websockets.connect(self.url, ssl=ssl_context) + logger.info("WebSocket connection established.") + return self.websocket + except Exception as e: + logger.error(f"Error connecting to WebSocket: {e}") + return None + + async def close(self): + if self.websocket: + await self.websocket.close() + self.websocket = None diff --git a/okx/websocket/WsClientFactory.py b/okx/websocket/WsClientFactory.py deleted file mode 100644 index c016222b..00000000 --- a/okx/websocket/WsClientFactory.py +++ /dev/null @@ -1,49 +0,0 @@ -from autobahn.twisted.websocket import WebSocketClientFactory -from twisted.internet.protocol import ReconnectingClientFactory - -from .WsClientProtocol import * - - -class WsReconnectingClientFactory(ReconnectingClientFactory): - """ - @ivar maxDelay: Maximum number of seconds between connection attempts. - @ivar initialDelay: Delay for the first reconnection attempt. - @ivar maxRetries: Maximum number of consecutive unsuccessful connection - attempts, after which no further connection attempts will be made. If - this is not explicitly set, no maximum is applied. - """ - initialDelay = 0.1 - maxDelay = 2 - maxRetries = 5 - - -class WsClientFactory(WebSocketClientFactory, WsReconnectingClientFactory): - reachMaxRetriesError = {"e": "error", "m": "reached max connect retries"} - - def __init__(self, *args, payload=None, **kwargs): - WebSocketClientFactory.__init__(self, *args, **kwargs) - self.instance = None - self.subscribeSet = set() - self.payload = payload - self.logger = logging.getLogger(__name__) - - def startedConnecting(self, connector): - self.logger.info("WsClientFactory execute startedConnecting") - - def clientConnectionFailed(self, connector, reason): - self.logger.error( - "Can't connect to server. Reason: {}. Retrying: {}".format(reason, self.retries + 1)) - self.retry(connector) - if self.retries > self.maxRetries: - self.callback(self.reachMaxRetriesError) - - def clientConnectionLost(self, connector, reason): - self.logger.error("WsClientFactory execute clientConnectionLost. Reason: {},retried {} times".format(reason, - self.retries + 1)) - self.retry(connector) - if self.retries > self.maxRetries: - self.callback(self.reachMaxRetriesError) - - def buildProtocol(self, addr): - protocol = WsClientProtocol(self, payload=self.payload) - return protocol diff --git a/okx/websocket/WsClientProtocol.py b/okx/websocket/WsClientProtocol.py deleted file mode 100644 index b753215b..00000000 --- a/okx/websocket/WsClientProtocol.py +++ /dev/null @@ -1,46 +0,0 @@ -import json -import logging - -from autobahn.twisted.websocket import WebSocketClientProtocol - - -class WsClientProtocol(WebSocketClientProtocol): - def __init__(self, factory, payload=None): - super().__init__() - self.autoPingInterval = 5 - self.factory = factory - self.payload = payload - self.logger = logging.getLogger(__name__) - - def onOpen(self): - self.factory.instance = self - - def onConnect(self, response): - self.logger.info("WsClientProtocol execute onConnect") - if self.payload: - self.logger.info("WsClientProtocol will Send message to OKX Server") - self.sendMessage(self.payload, isBinary=False) - self.factory.resetDelay() - - def onMessage(self, payload, isBinary): - self.logger.info("WsClientProtocol execute onMessage begin") - if not isBinary: - try: - payload_obj = json.loads(payload.decode("utf8")) - except Exception as e: - self.logger.error("WsClientProtocol onMessage error;e:{}".format(e)) - else: - self.factory.callback(payload_obj) - - def onClose(self, wasClean, code, reason): - self.logger.info( - "WsClientProtocol WS connection will be closed; wasClean={0}, code={1}, reason: {2}".format(wasClean, code, - reason)) - - def onPing(self, payload): - self.logger.info("WsClientProtocol execute onPing") - self.sendPong() - self.logger.info("WsClientProtocol execute onPing finish") - - def onPong(self, payload): - self.logger.info("WsClientProtocol execute onPong") diff --git a/okx/websocket/WsConnectManager.py b/okx/websocket/WsConnectManager.py deleted file mode 100644 index cd71edad..00000000 --- a/okx/websocket/WsConnectManager.py +++ /dev/null @@ -1,136 +0,0 @@ -import threading -import time - -from autobahn.twisted.websocket import connectWS -from twisted.internet import reactor -from twisted.internet.error import ReactorAlreadyRunning - -from . import WsUtils -from .WsClientFactory import * - - -class WsConnectManager(threading.Thread): - - def __init__(self, url, isPrivate): - threading.Thread.__init__(self) - self.factories = {} - self.isPrivate = isPrivate - self._connected_event = threading.Event() - self.url = url - self.conns = {} - self.callback = None - self.logger = logging.getLogger(__name__) - - def subscribeSocket(self, args: list, callback): - channelArgs = {} - channelParamMap = {} - WsUtils.checkSocketParams(args, channelArgs, channelParamMap) - if len(channelArgs) < 1: - return False - for channel in channelArgs: - subSet = channelParamMap.get(channel, set()) - if self.isPrivate: - privateKey = self.getPrivateKey(channel) - if privateKey not in self.factories: - reactor.callFromThread(self.loginSocket, channel) - time.sleep(2) - newFactory = self.initSubscribeFactory(args=channelArgs[channel], subSet=subSet, callback=callback) - reactor.callFromThread(self.resetConnection, newFactory, channel) - continue - factory = self.initSubscribeFactory(args=channelArgs[channel], subSet=subSet, callback=callback) - self.factories[channel] = factory - reactor.callFromThread(self.addConnection, channel) - - def unsubscribeSocket(self, args: list, callback): - channelArgs = {} - channelParamMap = {} - WsUtils.checkSocketParams(args, channelArgs, channelParamMap) - if len(channelArgs) < 1: - return False - for channel in channelArgs: - if self.isPrivate: - privateKey = self.getPrivateKey(channel) - else: - privateKey = channel - if privateKey not in self.factories: - continue - factory = self.factories[privateKey] - ifFiledParams = factory.subscribeSet - channelParamMap[channel] - if len(ifFiledParams) < 1: - self.disconnect(channel) - else: - payload = json.dumps({"op": "unsubscribe", "args": channelArgs[channel]}, ensure_ascii=False).encode( - "utf8") - factory = WsClientFactory(self.url, payload=payload) - factory.client = self - factory.protocol = WsClientProtocol - factory.callback = callback - factory.subscribeSet = ifFiledParams - reactor.callFromThread(self.resetConnection, factory, channel) - - def addConnection(self, channel): - self.conns[channel] = connectWS(self.factories[channel]) - - def disconnect(self, channel): - if channel not in self.conns: - self.logger.error("WsConnectManager disconnect error,channel is not able".format(channel)) - return - self.conns[channel].factory = WebSocketClientFactory(self.url) - self.conns[channel].disconnect() - del self.conns[channel] - privateKey = channel - if self.isPrivate: - privateKey = self.getPrivateKey(channel) - del self.factories[privateKey] - - def initSubscribeFactory(self, args, subSet: set, callback): - payload = json.dumps({"op": "subscribe", "args": args}, ensure_ascii=False).encode( - "utf8") - factory = WsClientFactory(self.url, payload=payload) - factory.payload = payload - factory.protocol = WsClientProtocol - factory.callback = callback - factory.subscribeSet = factory.subscribeSet | subSet - return factory - - def loginSocket(self, channel: str): - payload = WsUtils.initLoginParams(useServerTime=self.useServerTime, apiKey=self.apiKey, - passphrase=self.passphrase, secretKey=self.secretKey) - factory = WsClientFactory(self.url, payload=payload) - factory.protocol = WsClientProtocol - factory.callback = loginSocketCallBack - privateKey = self.getPrivateKey(channel) - self.factories[privateKey] = factory - self.conns[channel] = connectWS(factory) - - def resetConnection(self, newFactory, channel): - if self.isPrivate: - privateKey = self.getPrivateKey(channel) - preFactory = self.factories[privateKey] - else: - preFactory = self.factories[channel] - instance = preFactory.instance - if instance is None: - raise ValueError("instance must not none") - instance.factory = newFactory - instance.payload = newFactory.payload - instance.onConnect(None) - - def getPrivateKey(self, channel) -> str: - return str(self.apiKey) + "@" + channel - - def run(self): - try: - reactor.run(installSignalHandlers=False) - except ReactorAlreadyRunning as e: - self.logger.error("WsConnectManager reactor.run error;e:{}".format(e)) - - def close(self): - keys = set(self.conns.keys()) - for key in keys: - self.closeConnection(key) - self.conns = {} - - -def loginSocketCallBack(message): - print("loginSocket callback:", message) diff --git a/okx/websocket/WsLoginFactory.py b/okx/websocket/WsLoginFactory.py deleted file mode 100644 index e00ac844..00000000 --- a/okx/websocket/WsLoginFactory.py +++ /dev/null @@ -1,59 +0,0 @@ -# import time -# -# import WsUtils -# from WsClientProtocol import * -# from autobahn.twisted.websocket import WebSocketClientFactory -# from twisted.internet.protocol import ReconnectingClientFactory -# -# -# class WsReconnectingClientFactory(ReconnectingClientFactory): -# """ -# @ivar maxDelay: Maximum number of seconds between connection attempts. -# @ivar initialDelay: Delay for the first reconnection attempt. -# @ivar maxRetries: Maximum number of consecutive unsuccessful connection -# attempts, after which no further connection attempts will be made. If -# this is not explicitly set, no maximum is applied. -# """ -# initialDelay = 0.1 -# maxDelay = 1 -# maxRetries = 4 -# -# -# class WsLoginFactory(WebSocketClientFactory, WsReconnectingClientFactory): -# reachMaxRetriesError = {"e": "error", "m": "reached max connect retries"} -# -# def __init__(self, *args, useServerTime: str, apiKey: str, passphrase: str, secretKey: str, **kwargs): -# WebSocketClientFactory.__init__(self, *args, **kwargs) -# self.apiKey = apiKey -# self.passphrase = passphrase -# self.secretKey = secretKey -# self.useServerTime = useServerTime -# self.instance = None -# self.preTime = time.time() -# self.logger = logging.getLogger(__name__) -# -# def startedConnecting(self, connector): -# self.logger.info("WsClientFactory execute startedConnecting") -# -# def clientConnectionFailed(self, connector, reason): -# self.logger.error( -# "Can't connect to server. Reason: {}. Retrying: {}".format(reason, self.retries + 1)) -# self.retry(connector) -# if self.retries > self.maxRetries: -# self.callback(self.reachMaxRetriesError) -# -# def clientConnectionLost(self, connector, reason): -# cur = time.time() -# print("WsClientFactory,pre team=", cur - self.preTime) -# self.preTime = cur -# self.logger.error("WsClientFactory execute clientConnectionLost. Reason: {},retried {} times".format(reason, -# self.retries + 1)) -# self.retry(connector) -# if self.retries > self.maxRetries: -# self.callback(self.reachMaxRetriesError) -# -# def buildProtocol(self, addr): -# payload = WsUtils.initLoginParams(useServerTime=self.useServerTime, apiKey=self.apiKey, -# passphrase=self.passphrase, secretKey=self.secretKey) -# protocol = WsClientProtocol(self, payload=payload) -# return protocol diff --git a/okx/websocket/WsPrivate.py b/okx/websocket/WsPrivate.py deleted file mode 100644 index b1bb189c..00000000 --- a/okx/websocket/WsPrivate.py +++ /dev/null @@ -1,30 +0,0 @@ - -from twisted.internet import reactor - -from . import WsUtils -from .WsConnectManager import WsConnectManager - - -class WsPrivate(WsConnectManager): - def __init__(self, apiKey: str, passphrase: str, secretKey: str, url: str, useServerTime: False): - if ~WsUtils.isNotBlankStr(apiKey) or ~WsUtils.isNotBlankStr(passphrase) or ~WsUtils.isNotBlankStr( - secretKey) or ~WsUtils.isNotBlankStr(url): - return - super().__init__(url, isPrivate=True) - self.apiKey = apiKey - self.passphrase = passphrase - self.secretKey = secretKey - self.useServerTime = useServerTime - - def subscribe(self, params: list, callback): - self.subscribeSocket(params, callback) - - def unsubscribe(self, params: list, callback): - self.unsubscribeSocket(params, callback) - - def stop(self): - try: - self.close() - finally: - reactor.stop() - diff --git a/okx/websocket/WsPrivateAsync.py b/okx/websocket/WsPrivateAsync.py new file mode 100644 index 00000000..c5359aa2 --- /dev/null +++ b/okx/websocket/WsPrivateAsync.py @@ -0,0 +1,77 @@ +import asyncio +import json +import logging + +from okx.websocket import WsUtils +from okx.websocket.WebSocketFactory import WebSocketFactory + +logger = logging.getLogger(__name__) + + +class WsPrivateAsync: + def __init__(self, apiKey, passphrase, secretKey, url, useServerTime): + self.url = url + self.subscriptions = set() + self.callback = None + self.loop = asyncio.get_event_loop() + self.factory = WebSocketFactory(url) + self.apiKey = apiKey + self.passphrase = passphrase + self.secretKey = secretKey + self.useServerTime = useServerTime + self.websocket = None + + async def connect(self): + self.websocket = await self.factory.connect() + + async def consume(self): + async for message in self.websocket: + logger.debug("Received message: {%s}", message) + if self.callback: + self.callback(message) + + async def subscribe(self, params: list, callback): + self.callback = callback + + logRes = await self.login() + await asyncio.sleep(5) + if logRes: + payload = json.dumps({ + "op": "subscribe", + "args": params + }) + await self.websocket.send(payload) + # await self.consume() + + async def login(self): + loginPayload = WsUtils.initLoginParams( + useServerTime=self.useServerTime, + apiKey=self.apiKey, + passphrase=self.passphrase, + secretKey=self.secretKey + ) + await self.websocket.send(loginPayload) + return True + + async def unsubscribe(self, params: list, callback): + self.callback = callback + payload = json.dumps({ + "op": "unsubscribe", + "args": params + }) + logger.info(f"unsubscribe: {payload}") + await self.websocket.send(payload) + # for param in params: + # self.subscriptions.discard(param) + + async def stop(self): + await self.factory.close() + self.loop.stop() + + async def start(self): + logger.info("Connecting to WebSocket...") + await self.connect() + self.loop.create_task(self.consume()) + + def stop_sync(self): + self.loop.run_until_complete(self.stop()) diff --git a/okx/websocket/WsPublic.py b/okx/websocket/WsPublic.py deleted file mode 100644 index c38e9d7e..00000000 --- a/okx/websocket/WsPublic.py +++ /dev/null @@ -1,20 +0,0 @@ -from twisted.internet import reactor - -from .WsConnectManager import WsConnectManager - - -class WsPublic(WsConnectManager): - def __init__(self, url): - super().__init__(url, isPrivate=False) - - def subscribe(self, params: list, callback): - self.subscribeSocket(params, callback) - - def unsubscribe(self, params: list, callback): - self.unsubscribeSocket(params, callback) - - def stop(self): - try: - self.close() - finally: - reactor.stop() diff --git a/okx/websocket/WsPublicAsync.py b/okx/websocket/WsPublicAsync.py new file mode 100644 index 00000000..e576d658 --- /dev/null +++ b/okx/websocket/WsPublicAsync.py @@ -0,0 +1,56 @@ +import asyncio +import json +import logging + +from okx.websocket.WebSocketFactory import WebSocketFactory + +logger = logging.getLogger(__name__) + + +class WsPublicAsync: + def __init__(self, url): + self.url = url + self.subscriptions = set() + self.callback = None + self.loop = asyncio.get_event_loop() + self.factory = WebSocketFactory(url) + self.websocket = None + + async def connect(self): + self.websocket = await self.factory.connect() + + async def consume(self): + async for message in self.websocket: + logger.debug("Received message: {%s}", message) + if self.callback: + self.callback(message) + + async def subscribe(self, params: list, callback): + self.callback = callback + payload = json.dumps({ + "op": "subscribe", + "args": params + }) + await self.websocket.send(payload) + # await self.consume() + + async def unsubscribe(self, params: list, callback): + self.callback = callback + payload = json.dumps({ + "op": "unsubscribe", + "args": params + }) + logger.info(f"unsubscribe: {payload}") + await self.websocket.send(payload) + + async def stop(self): + await self.factory.close() + self.loop.stop() + + async def start(self): + logger.info("Connecting to WebSocket...") + await self.connect() + self.loop.create_task(self.consume()) + + def stop_sync(self): + self.loop.run_until_complete(self.stop()) diff --git a/okx/websocket/WsUtils.py b/okx/websocket/WsUtils.py index 28aa2b91..fcb0db26 100644 --- a/okx/websocket/WsUtils.py +++ b/okx/websocket/WsUtils.py @@ -16,7 +16,7 @@ def initLoginParams(useServerTime: bool, apiKey, passphrase, secretKey): sign = base64.b64encode(d) arg = {"apiKey": apiKey, "passphrase": passphrase, "timestamp": timestamp, "sign": sign.decode("utf-8")} payload = {"op": "login", "args": [arg]} - return json.dumps(payload, ensure_ascii=False).encode("utf8") + return json.dumps(payload) def isNotBlankStr(param: str) -> bool: diff --git a/setup.py b/setup.py new file mode 100644 index 00000000..b91e2374 --- /dev/null +++ b/setup.py @@ -0,0 +1,30 @@ +import setuptools +import okx +with open("README.md", "r",encoding="utf-8") as fh: + long_description = fh.read() + +setuptools.setup( + name="python-okx", + version=okx.__version__, + author="okxv5api", + author_email="api@okg.com", + description="Python SDK for OKX", + long_description=long_description, + long_description_content_type="text/markdown", + url="https://okx.com/docs-v5/", + packages=setuptools.find_packages(), + classifiers=[ + "Programming Language :: Python :: 3", + "License :: OSI Approved :: MIT License", + "Operating System :: OS Independent", + ], + install_requires=[ + "importlib-metadata", + "httpx[http2]", + "keyring", + "loguru", + "requests", + "Twisted", + "pyOpenSSL" + ] +) \ No newline at end of file diff --git a/test/AccountTest.py b/test/AccountTest.py index 2d088487..724112b8 100644 --- a/test/AccountTest.py +++ b/test/AccountTest.py @@ -1,80 +1,151 @@ - import unittest -from ..okx import Account + +from loguru import logger + +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()) + api_key = 'your_apiKey' + api_secret_key = 'your_secretKey' + passphrase = 'your_secretKey' + self.AccountAPI = Account.AccountAPI(api_key, api_secret_key, passphrase, 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_instruments(self): + # print(self.AccountAPI.get_instruments(instType='SPOT')) + # def test_get_account_bills_archive(self): + # print(self.AccountAPI.get_account_bills_archive(begin='1715780962300',end='1716998400000')) + # def test_positions_builder(self): + # print("Both real and virtual positions and assets are calculated") + # sim_pos = [{'instId': 'BTC-USDT-SWAP', 'pos': '10','avgPx': '1'}] + # sim_asset = [{'ccy': 'USDT', 'amt': '100'}] + # print(self.AccountAPI.position_builder(inclRealPosAndEq=False, greeksType='CASH', + # simPos=sim_pos, simAsset=sim_asset)) + # + # print("Only existing real positions are calculated") + # print(self.AccountAPI.position_builder(inclRealPosAndEq=True, greeksType='CASH')) + # + # print("Only virtual positions are calculated") + # print(self.AccountAPI.position_builder(inclRealPosAndEq=False, simPos=sim_pos)) + + # 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()) + + # def test_get_VIP_interest_accrued_data(self): + # print(self.AccountAPI.get_VIP_interest_accrued_data()) + + # def test_get_VIP_interest_deducted_data(self): + # print(self.AccountAPI.get_VIP_interest_deducted_data()) + + # def test_get_VIP_loan_order_list(self): + # print(self.AccountAPI.get_VIP_loan_order_list()) + + # def test_get_VIP_loan_order_detail(self): + # print(self.AccountAPI.get_VIP_loan_order_detail(ordId='1')) + + # def test_set_risk_offset_typel(self): + # print(self.AccountAPI.set_risk_offset_typel(type='1')) + # + # def test_set_auto_loan(self): + # print(self.AccountAPI.set_auto_loan()) + # + # def test_activate_option(self): + # print(self.AccountAPI.activate_option()) - 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_max_avaliable_size(self): + # print(self.AccountAPI.get_max_avail_size(instId="BTC-USDT",tdMode="cash",quickMgnType='manual')) + # def test_borrow_repay(self): + # print(self.AccountAPI.borrow_repay("BTC", "borrow", "1.0")) - 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_simulated_margin(self): + # print(self.AccountAPI.get_simulated_margin(spotOffsetType='3')) + # def test_get_fix_loan_borrowing_limit(self): + # logger.debug(f'{self.AccountAPI.get_fix_loan_borrowing_limit()}') + # def test_get_fix_loan_borrowing_quote(self): + # logger.debug(f'{self.AccountAPI.get_fix_loan_borrowing_quote(type="normal")}') + # def test_place_fix_loan_borrowing_order(self): + # logger.debug(f'{self.AccountAPI.place_fix_loan_borrowing_order(ccy="BTC", amt="0.1515", maxRate="0.001", term="30D", reborrow=True, reborrowRate="0.01")}') + # def test_amend_fix_loan_borrowing_order(self): + # logger.debug(f'{self.AccountAPI.amend_fix_loan_borrowing_order(ordId="2407301043344857",reborrow=True,renewMaxRate="0.01")}') + # def test_fix_loan_manual_reborrow(self): + # logger.debug(f'{self.AccountAPI.fix_loan_manual_reborrow(ordId="2407301043344857",maxRate="0.1")}') + # def test_repay_fix_loan_borrowing_order(self): + # logger.info(f'{self.AccountAPI.repay_fix_loan_borrowing_order(ordId="2407301054407907")}') + # def test_get_fix_loan_borrowing_orders_list(self): + # logger.debug(self.AccountAPI.get_fix_loan_borrowing_orders_list(ordId="2407301054407907")) - 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()) + # def test_spot_manual_borrow_repay(self): + # logger.debug(f'{self.AccountAPI.spot_manual_borrow_repay(ccy="USDT",side="borrow",amt=1)}') + # def test_set_auto_repay(self): + # logger.info(f'{self.AccountAPI.set_auto_repay(autoRepay=True)}') + # def test_spot_borrow_repay_history(self): + # logger.debug(self.AccountAPI.spot_borrow_repay_history(ccy="USDT",type="auto_borrow",after="1597026383085")) if __name__ == '__main__': - unittest.main() \ No newline at end of file + unittest.main() diff --git a/test/BlockTradingTest.py b/test/BlockTradingTest.py index 8d86974c..e8b0e88d 100644 --- a/test/BlockTradingTest.py +++ b/test/BlockTradingTest.py @@ -1,12 +1,12 @@ import unittest -from ..okx import BlockTrading +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') + api_key = 'your_apiKey' + api_secret_key = 'your_secretKey' + passphrase = 'your_secretKey' + self.BlockTradingAPI = BlockTrading.BlockTradingAPI(api_key, api_secret_key, passphrase, use_server_time=False, flag='1') """ def test_get_counter_parties(self): @@ -42,7 +42,46 @@ def test_get_trade(self): """ - def test_get_public_trades(self): - print(self.BlockTradingAPI.get_public_trades()) + # def test_get_public_trades(self): + # print(self.BlockTradingAPI.get_public_trades()) + + # def test_get_quote_products(self): + # print(self.BlockTradingAPI.get_quote_products()) + + def test_create_rfqs(self): + counterparties=['8924'] + legs =[{ + 'instId':"BTC-USDT", + 'sz':'25', + 'side':'buy', + 'posSide':'net', + 'tdMode':'cross', + 'ccy':'USDT' + }] + print(self.BlockTradingAPI.create_rfq(counterparties,allowPartialExecution='true',tag='1234',legs = legs)) + + # def test_execute_quotes(self): + # legs = [{ + # 'instId':"BTC-USDT", + # 'sz':'0.0001', + # }] + # print(self.BlockTradingAPI.execute_quote("3IR9E68","3IR9E80",legs)) + + # def test_create_quotes(self): + # legs = [{ + # 'instId': "BTC-USDT", + # 'sz': '25', + # 'side': 'buy', + # 'posSide': 'net', + # 'tdMode': 'cross', + # 'ccy': 'USDT' + # }] + # print(self.BlockTradingAPI.create_quote(rfqId='3IR9BT8',quoteSide='buy',legs=legs)) + + # def test_get_trade(self): + # print(self.BlockTradingAPI.get_trades()) + + + if __name__ == '__main__': unittest.main() \ No newline at end of file diff --git a/test/BrokerTest.py b/test/BrokerTest.py deleted file mode 100644 index e4a034cd..00000000 --- a/test/BrokerTest.py +++ /dev/null @@ -1,70 +0,0 @@ - -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 index d4faa28f..aa1d175c 100644 --- a/test/ConvertTest.py +++ b/test/ConvertTest.py @@ -2,9 +2,9 @@ from ..okx import Convert class ConvertTest(unittest.TestCase): def setUp(self): - api_key = 'ef06bf27-6a01-4797-b801-e3897031e45d' - api_secret_key = 'D3620B2660203350EEE80FDF5BE0C960' - passphrase = 'Beijing123' + api_key = 'your_apiKey' + api_secret_key = 'your_secretKey' + passphrase = 'your_secretKey' self.ConvertAPI = Convert.ConvertAPI(api_key, api_secret_key, passphrase, use_server_time=False, flag='1') ''' diff --git a/test/CopyTradingTest.py b/test/CopyTradingTest.py new file mode 100644 index 00000000..95c17396 --- /dev/null +++ b/test/CopyTradingTest.py @@ -0,0 +1,40 @@ +import unittest +from okx import CopyTrading + +class CopyTradingTest(unittest.TestCase): + def setUp(self): + api_key = 'your_apiKey' + api_secret_key = 'your_secretKey' + passphrase = 'your_secretKey' + self.StackingAPI = CopyTrading.CopyTradingAPI(api_key, api_secret_key, passphrase, use_server_time=False, + flag='0') + + # def test_get_existing_leading_positions(self): + # print(self.StackingAPI.get_existing_leading_positions(instId='DOGE-USDT-SWAP')) + + # def test_get_leading_position_history(self): + # print(self.StackingAPI.get_leading_position_history()) + + # def test_place_leading_stop_order(self): + # print(self.StackingAPI.place_leading_stop_order(subPosId='581247467976732672',tpTriggerPx='1')) + # + # def test_close_leading_position(self): + # print(self.StackingAPI.close_leading_position(subPosId='581247467976732672')) + + # def test_get_leading_instruments(self): + # print(self.StackingAPI.get_leading_instruments()) + + # def test_amend_leading_instruments(self): + # print(self.StackingAPI.amend_leading_instruments(instId='AAVE-USDT-SWAP')) + # + # def test_get_profit_sharing_details(self): + # print(self.StackingAPI.get_profit_sharing_details()) + # + # def test_get_total_profit_sharing(self): + # print(self.StackingAPI.get_total_profit_sharing()) + # + def test_get_unrealized_profit_sharing_details(self): + print(self.StackingAPI.get_unrealized_profit_sharing_details()) + +if __name__ == "__main__": + unittest.main() \ No newline at end of file diff --git a/test/EthStakingTest.py b/test/EthStakingTest.py new file mode 100644 index 00000000..3be48603 --- /dev/null +++ b/test/EthStakingTest.py @@ -0,0 +1,30 @@ +import unittest +from okx.Finance import EthStaking + +class EthStakingTest(unittest.TestCase): + def setUp(self): + api_key = 'your_apiKey' + api_secret_key = 'your_secretKey' + passphrase = 'your_secretKey' + self.StackingAPI = EthStaking.EthStakingAPI(api_key, api_secret_key, passphrase, use_server_time=False, flag='1') + + def test_eth_product_info(self): + print(self.StackingAPI.eth_product_info()) + + def test_eth_purchase(self): + print(self.StackingAPI.eth_purchase(amt="1")) + + def test_eth_redeem(self): + print(self.StackingAPI.eth_redeem(amt="1")) + + def test_eth_balance(self): + print(self.StackingAPI.eth_balance()) + + def test_eth_purchase_redeem_history(self): + print(self.StackingAPI.eth_purchase_redeem_history(type="", status="", after="", before="", limit="")) + + def test_eth_apy_history(self): + print(self.StackingAPI.eth_apy_history(days="7")) + +if __name__ == "__main__": + unittest.main() \ No newline at end of file diff --git a/test/FlexibleLoanTest.py b/test/FlexibleLoanTest.py new file mode 100644 index 00000000..b4320a5c --- /dev/null +++ b/test/FlexibleLoanTest.py @@ -0,0 +1,36 @@ +import unittest +from okx.Finance import FlexibleLoan + +class FlexibleLoanTest(unittest.TestCase): + def setUp(self): + api_key = 'your_apiKey' + api_secret_key = 'your_secretKey' + passphrase = 'your_secretKey' + self.FlexibleLoanAPI = FlexibleLoan.FlexibleLoanAPI(api_key, api_secret_key, passphrase, use_server_time=False, flag='1') + + def test_borrow_currencies(self): + print(self.FlexibleLoanAPI.borrow_currencies()) + + def test_collateral_assets(self): + print(self.FlexibleLoanAPI.collateral_assets()) + + def test_max_loan(self): + print(self.FlexibleLoanAPI.max_loan(borrowCcy='USDT')) + + def test_max_collateral_redeem_amount(self): + print(self.FlexibleLoanAPI.max_collateral_redeem_amount(ccy='USDT')) + + def test_adjust_collateral(self): + print(self.FlexibleLoanAPI.adjust_collateral(type="add", collateralCcy="USDT", collateralAmt="1")) + + def test_loan_info(self): + print(self.FlexibleLoanAPI.loan_info()) + + def test_loan_history(self): + print(self.FlexibleLoanAPI.loan_history()) + + def test_interest_accrued(self): + print(self.FlexibleLoanAPI.interest_accrued()) + +if __name__ == "__main__": + unittest.main() \ No newline at end of file diff --git a/test/FundingTest.py b/test/FundingTest.py index 2cce1e1e..e87bb76d 100644 --- a/test/FundingTest.py +++ b/test/FundingTest.py @@ -1,13 +1,13 @@ import unittest -from ..okx import Funding +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') + api_key = 'your_apiKey' + api_secret_key = 'your_secretKey' + passphrase = 'your_secretKey' + self.FundingAPI = Funding.FundingAPI(api_key, api_secret_key, passphrase, use_server_time=False, flag='0') """ CANCEL_WITHDRAWAL = '/api/v5/asset/cancel-withdrawal' #need add CONVERT_DUST_ASSETS = '/api/v5/asset/convert-dust-assets' #need add @@ -58,9 +58,27 @@ 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()) + # def test_get_non_tradable_assets(self): + # print(self.FundingAPI.get_non_tradable_assets()) + # 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_non_tradable_assets(self): + # print(self.FundingAPI.get_non_tradable_assets()) + + # def test_get_deposit_withdraw_status(self): + # print(self.FundingAPI.get_deposit_withdraw_status(wdId='84804812')) + + # def test_get_withdrawal_history(self): + # print(self.FundingAPI.get_withdrawal_history()) + + # def test_get_deposit_history(self): + # print(self.FundingAPI.get_deposit_history()) + + def test_withdrawal(self): + print(self.FundingAPI.withdrawal(ccy='USDT',amt='1',dest='3',toAddr='18740405107',areaCode='86')) + if __name__ == '__main__': unittest.main() \ No newline at end of file diff --git a/test/GridTest.py b/test/GridTest.py index 072e67cb..6e8f7da1 100644 --- a/test/GridTest.py +++ b/test/GridTest.py @@ -1,12 +1,12 @@ import unittest -from ..okx import Grid +from okx import Grid class GridTest(unittest.TestCase): def setUp(self): - api_key = 'ef06bf27-6a01-4797-b801-e3897031e45d' - api_secret_key = 'D3620B2660203350EEE80FDF5BE0C960' - passphrase = 'Beijing123' + api_key = 'your_apiKey' + api_secret_key = 'your_secretKey' + passphrase = 'your_secretKey' self.GridAPI = Grid.GridAPI(api_key, api_secret_key, passphrase, use_server_time=False, flag='1', debug=False) """ GRID_COMPUTE_MARIGIN_BALANCE = '/api/v5/tradingBot/grid/compute-margin-balance' @@ -49,7 +49,37 @@ def test_withdrawl_profits(self): """ - def test_order_algo(self): - print(self.GridAPI.grid_order_algo("BTC-USDT","grid","45000","20000","100","1",quoteSz="50")) + # def test_order_algo(self): + # print(self.GridAPI.grid_order_algo("BTC-USDT","grid","45000","20000","100","1",quoteSz="50")) + + # def test_place_recurring_buy_order(self): + # print(self.GridAPI.place_recurring_buy_order(stgyName="jzhtest",recurringList=[{ + # 'ccy':"ETH", + # 'ratio':'1' + # }],period="daily",recurringDay='1',recurringTime='0',timeZone='8',amt='100',investmentCcy='USDT',tdMode='cross')) + + # def test_amend_recurring_buy_order(self): + # print(self.GridAPI.amend_recurring_buy_order(algoId="581185292170952704",stgyName="changtest")) + + # def test_stop_recurring_buy_order(self): + # orderData = [{ + # "algoId": "581190894481838080" + # }] + # print(self.GridAPI.stop_recurring_buy_order(orderData)) + + # def test_get_recurring_buy_order_list(self): + # print(self.GridAPI.get_recurring_buy_order_list()) + + # def test_get_recurring_buy_order_history(self): + # print(self.GridAPI.get_recurring_buy_order_history()) + + # def test_get_recurring_buy_order_details(self): + # print(self.GridAPI.get_recurring_buy_order_details(algoId="581191143417970688")) + + # def test_get_recurring_buy_sub_orders(self): + # print(self.GridAPI.get_recurring_buy_sub_orders(algoId="581191143417970688")) + + #581191143417970688 + if __name__ == '__main__': unittest.main() \ No newline at end of file diff --git a/test/MarketTest.py b/test/MarketTest.py index fdf8df77..2a45d7f9 100644 --- a/test/MarketTest.py +++ b/test/MarketTest.py @@ -1,6 +1,6 @@ import unittest -from ..okx import MarketData +from okx import MarketData ''' ORACLE = '/api/v5/market/open-oracle' #need to update? if it is open oracle @@ -14,14 +14,12 @@ class MarketAPITest(unittest.TestCase): def setUp(self): - api_key = 'ef06bf27-6a01-4797-b801-e3897031e45d' - api_secret_key = 'D3620B2660203350EEE80FDF5BE0C960' - passphrase = 'Beijing123' + api_key = 'your_apiKey' + api_secret_key = 'your_secretKey' + passphrase = 'your_secretKey' self.MarketApi = MarketData.MarketAPI(api_key, api_secret_key, passphrase, use_server_time=False, flag='1') ''' - 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): @@ -58,7 +56,11 @@ def test_get_platform_24_volume(self): print(self.MarketApi.get_volume()) ''' + # def test_get_order_lite_book(self): + # print(self.MarketApi.get_order_lite_book(instId='BTC-USDT')) + def test_get_option_trades(self): + print(self.MarketApi.get_option_trades(instFamily='BTC-USD')) if __name__ == "__main__": diff --git a/test/PublicDataTest.py b/test/PublicDataTest.py index f0b51389..7d7449dd 100644 --- a/test/PublicDataTest.py +++ b/test/PublicDataTest.py @@ -1,10 +1,10 @@ import unittest -from ..okx import PublicData +from okx import PublicData class publicDataTest(unittest.TestCase): def setUp(self): - api_key = 'ef06bf27-6a01-4797-b801-e3897031e45d' - api_secret_key = 'D3620B2660203350EEE80FDF5BE0C960' - passphrase = 'Beijing123' + api_key = 'your_apiKey' + api_secret_key = 'your_secretKey' + passphrase = 'your_secretKey' self.publicDataApi = PublicData.PublicAPI(api_key, api_secret_key, passphrase, use_server_time=False, flag='1') ''' TestCase For: @@ -50,8 +50,14 @@ 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')) + # def test_position_tier(self): + # print(self.publicDataApi.get_position_tiers('SWAP','cross',uly='ETH-USD')) + + # def test_get_option_tickBands(self): + # print(self.publicDataApi.get_option_tick_bands(instType='OPTION')) + + def test_get_option_trades(self): + print(self.publicDataApi.get_option_trades(instFamily='BTC-USD')) if __name__ == '__main__': unittest.main() \ No newline at end of file diff --git a/test/SavingsTest.py b/test/SavingsTest.py new file mode 100644 index 00000000..9dac910a --- /dev/null +++ b/test/SavingsTest.py @@ -0,0 +1,31 @@ +import unittest +from okx.Finance import Savings + +class SavingsTest(unittest.TestCase): + def setUp(self): + api_key = 'your_apiKey' + api_secret_key = 'your_secretKey' + passphrase = 'your_secretKey' + self.StackingAPI = Savings.SavingsAPI(api_key, api_secret_key, passphrase, use_server_time=False, flag='1') + + + def test_get_saving_balance(self): + print(self.StackingAPI.get_saving_balance(ccy='USDT')) + + def test_savings_purchase_redemption(self): + print(self.StackingAPI.savings_purchase_redemption(ccy='USDT',amt="0.1",side="redempt",rate="1")) + + def test_set_lending_rate(self): + print(self.StackingAPI.set_lending_rate(ccy='USDT',rate="1")) + + def test_get_lending_history(self): + print(self.StackingAPI.get_lending_history(ccy='USDT')) + + def test_get_public_borrow_history(self): + print(self.StackingAPI.get_public_borrow_history(ccy='USDT')) + + def test_get_public_borrow_info(self): + print(self.StackingAPI.get_public_borrow_info(ccy='BTC')) + +if __name__ == "__main__": + unittest.main() \ No newline at end of file diff --git a/test/SolStakingTest.py b/test/SolStakingTest.py new file mode 100644 index 00000000..c3899d43 --- /dev/null +++ b/test/SolStakingTest.py @@ -0,0 +1,30 @@ +import unittest +from okx.Finance import SolStaking + +class SolStakingTest(unittest.TestCase): + def setUp(self): + api_key = 'your_apiKey' + api_secret_key = 'your_secretKey' + passphrase = 'your_secretKey' + self.StackingAPI = SolStaking.SolStakingAPI(api_key, api_secret_key, passphrase, use_server_time=False, flag='1') + + def test_sol_purchase(self): + print(self.StackingAPI.sol_purchase(amt="1")) + + def test_sol_redeem(self): + print(self.StackingAPI.sol_redeem(amt="1")) + + def test_sol_balance(self): + print(self.StackingAPI.sol_balance()) + + def test_sol_purchase_redeem_history(self): + print(self.StackingAPI.sol_purchase_redeem_history(type="purchase", status="", after="", before="", limit="")) + + def test_sol_apy_history(self): + print(self.StackingAPI.sol_apy_history(days="7")) + + def test_sol_product_info(self): + print(self.StackingAPI.sol_product_info()) + +if __name__ == "__main__": + unittest.main() \ No newline at end of file diff --git a/test/SpreadTest.py b/test/SpreadTest.py new file mode 100644 index 00000000..cbaf6e8e --- /dev/null +++ b/test/SpreadTest.py @@ -0,0 +1,46 @@ +import unittest +from okx import SpreadTrading +class TradeTest(unittest.TestCase): + def setUp(self): + api_key = 'your_apiKey' + api_secret_key = 'your_secretKey' + passphrase = 'your_secretKey' + self.tradeApi = SpreadTrading.SpreadTradingAPI(api_key, api_secret_key, passphrase, False, '1') + + # def test_place_order(self): + # print(self.tradeApi.place_order(sprdId='BTC-USDT_BTC-USDT-SWAP',clOrdId='b15',side='buy',ordType='limit', + # px='2',sz='2')) + #{'code': '0', 'msg': '', 'data': [{'ordId': '1899422086260064256', 'clOrdId': 'b15', 'tag': '', 'sCode': '0', 'sMsg': ''}]} + + # def test_cancel_order(self): + # print(self.tradeApi.cancel_order(ordId='1899422086260064256')) + + # def test_cancel_all_orders(self): + # print(self.tradeApi.cancel_all_orders(sprdId='BTC-USDT_BTC-USDT-SWAP')) + + + #{'code': '0', 'msg': '','data': [{'ordId': '1899453539647750144', 'clOrdId': 'b15', 'tag': '', 'sCode': '0', + # 'sMsg': ''}]} + # def test_get_order_details(self): + # print(self.tradeApi.get_order_details(ordId='1899453539647750144')) + + # def test_get_active_orders(self): + # print(self.tradeApi.get_active_orders()) + + # def test_get_orders(self): + # print(self.tradeApi.get_orders()) + + # def test_get_spreads(self): + # print(self.tradeApi.get_spreads()) + + # def test_get_order_book(self): + # print(self.tradeApi.get_order_book(sprdId='ETH-USDT-SWAP_ETH-USDT-230929')) + # + # def test_get_ticker(self): + # print(self.tradeApi.get_ticker(sprdId='ETH-USDT-SWAP_ETH-USDT-230929')) + # + def test_get_public_trades(self): + print(self.tradeApi.get_public_trades(sprdId='ETH-USDT-SWAP_ETH-USDT-230929')) + +if __name__=='__main__': + unittest.main() diff --git a/test/StackingTest.py b/test/StackingTest.py deleted file mode 100644 index 1d6a8755..00000000 --- a/test/StackingTest.py +++ /dev/null @@ -1,36 +0,0 @@ -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/StakingDefiTest.py b/test/StakingDefiTest.py new file mode 100644 index 00000000..29ac0453 --- /dev/null +++ b/test/StakingDefiTest.py @@ -0,0 +1,36 @@ +import unittest +from okx.Finance import StakingDefi + + +class StakingDefiTest(unittest.TestCase): + def setUp(self): + api_key = 'your_apiKey' + api_secret_key = 'your_secretKey' + passphrase = 'your_secretKey' + self.StackingAPI = StakingDefi.StakingDefiAPI(api_key, api_secret_key, passphrase, use_server_time=False, + flag='1') + + def test_get_offers(self): + print(self.StackingAPI.get_offers(ccy="USDT")) + + def test_purcase(self): + print(self.StackingAPI.purchase(1456, [{ + "ccy":"USDT", + "amt":"100" + }], "100", "0")) + + def test_redeem(self): + print(self.StackingAPI.redeem(1456,"defi")) + + def test_cancel(self): + print(self.StackingAPI.cancel(1456,"defi")) + + def test_get_activity_orders(self): + print(self.StackingAPI.get_activity_orders()) + + def test_get_orders_history(self): + print(self.StackingAPI.get_orders_history()) + + +if __name__ == "__main__": + unittest.main() diff --git a/test/SubAccountTest.py b/test/SubAccountTest.py index c251c0b8..b4281bd4 100644 --- a/test/SubAccountTest.py +++ b/test/SubAccountTest.py @@ -1,11 +1,11 @@ import unittest -from ..okx import SubAccount +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' + api_key = 'your_apiKey' + api_secret_key = 'your_secretKey' + passphrase = 'your_secretKey' self.SubAccountApi = SubAccount.SubAccountAPI(api_key, api_secret_key, passphrase, use_server_time=False, flag='1') ''' ENTRUST_SUBACCOUNT_LIST = '/api/v5/users/entrust-subaccount-list' #need to add @@ -36,5 +36,15 @@ def test_subaccount_transfer(self): ''' + # def test_set_sub_accounts_VIP_loan(self): + # print(self.SubAccountApi.set_sub_accounts_VIP_loan(enable='true',alloc=[{'subAcct':'coretrading7', + # 'loanAlloc':'1'}])) + + def test_get_sub_account_borrow_interest_and_limit(self): + print(self.SubAccountApi.get_sub_account_borrow_interest_and_limit(subAcct='coretrading7')) + + # def test_get_history_of_managed_subAccount_transfer(self): + # print(self.SubAccountApi.get_history_of_managed_subAccount_transfer()) + if __name__ == "__main__": unittest.main() \ No newline at end of file diff --git a/test/TradeTest.py b/test/TradeTest.py index d963787c..3f1b601c 100644 --- a/test/TradeTest.py +++ b/test/TradeTest.py @@ -1,121 +1,245 @@ import unittest -from ..okx import Trade + +from okx import Trade + + class TradeTest(unittest.TestCase): def setUp(self): - api_key = '35d8f27e-63cc-45bc-a578-45d76363d47f' - api_secret_key = '0B7C968025BC2D4D71CF74771EA0E15C' - passphrase = '123456' + api_key = 'your_apiKey' + api_secret_key = 'your_secretKey' + passphrase = 'your_secretKey' 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__': + + # # """ + # def test_place_order(self): + # attachAlgoOrds = [{'tpTriggerPx': '49000.0', 'tpOrdPx': '-1', 'sz': '1', 'tpTriggerPxType': 'last'}]; + # print(self.tradeApi.place_order( + # "BTC-USDT-SWAP", tdMode="isolated", clOrdId="asCai1234", side='buy', posSide="long", ordType="limit", + # sz="1", + # px="30000.0", + # attachAlgoOrds=attachAlgoOrds) + # ); + # + # attachAlgoOrds = [{'slTriggerPx': '25000.0', 'slOrdPx': '-1', 'sz': '1', 'slTriggerPxType': 'last'}]; + # print(self.tradeApi.place_order( + # "BTC-USDT-SWAP", tdMode="isolated", clOrdId="asCai1234", side='buy', posSide="long", ordType="limit", + # sz="1", + # px="30000.0", + # attachAlgoOrds=attachAlgoOrds) + # ); + # + # attachAlgoOrds = [ + # { + # "tpTriggerPxType": "last", + # "tpOrdPx": "-1", + # "tpTriggerPx": "34000", + # "sz": "1" + # }, + # { + # "tpTriggerPxType": "last", + # "tpOrdPx": "-1", + # "tpTriggerPx": "35000", + # "sz": "1" + # }, + # { + # "slTriggerPxType": "last", + # "slOrdPx": "-1", + # "slTriggerPx": "20000", + # "sz": "3" + # } + # ] + # print(self.tradeApi.place_order( + # "BTC-USDT-SWAP", tdMode="isolated", clOrdId="asCai1234", side='buy', posSide="long", ordType="limit", + # sz="1", + # px="30000.0", + # attachAlgoOrds=attachAlgoOrds) + # ); + + # def test_cancel_order(self): + # print(self.tradeApi.cancel_order(instId="ETH-USDT",ordId="480702180748558336")) + + # def test_batch_order(self): + # orderData = [{ + # "instId": "BTC-USDT-SWAP", + # "tdMode": "isolated", + # "clOrdId": "b15112122", + # "side": "buy", + # "posSide": "long", + # "ordType": "limit", + # "px": "30000.0", + # "sz": "2", + # "attachAlgoOrds": [{'tpTriggerPx': '50000.0', 'tpOrdPx': '-1', 'sz': '1', 'tpTriggerPxType': 'last'}] + # }, + # { + # "instId": "BTC-USDT-SWAP", + # "tdMode": "isolated", + # "clOrdId": "b15112111", + # "side": "buy", + # "posSide": "long", + # "ordType": "limit", + # "px": "31000.0", + # "sz": "2", + # "attachAlgoOrds": [{'tpTriggerPx': '51000.0', 'tpOrdPx': '-1', 'sz': '1', 'tpTriggerPxType': 'last'}] + # } + # ] + # + # 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): + # attachAlgoOrds = [{'attachAlgoId': '672081789170569217', 'newTpTriggerPx': '55000.0'}]; + # print(self.tradeApi.amend_order("BTC-USDT-SWAP", ordId="672081789170569216", newSz="1", + # attachAlgoOrds=attachAlgoOrds)) + + # def test_amend_order_batch(self): + # orderData = [ + # { + # 'instId': 'BTC-USDT-SWAP', + # 'ordId': '672081789170569216', + # 'newSz': '1', + # "attachAlgoOrds": [{'attachAlgoId': '672081789170569217', 'newTpTriggerPx': '53000.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(begin='1717045609000',end='1717045609100')) + # 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_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()) + # def test_order_algo(self): + # print(self.tradeApi.place_algo_order(instId='BTC-USDT-SWAP', tdMode='cross', side='buy', ordType='conditional', \ + # tpTriggerPx='15', tpOrdPx='18',sz='2')) + + # 581628185981308928 + # def test_get_algo_order_details(self): + # print(self.tradeApi.get_algo_order_details(algoId='581628185981308928')) + + # 581628185981308928 + # def test_amend_algo_order(self): + # print(self.tradeApi.amend_algo_order(instId='BTC-USDT-SWAP', algoId='581628185981308928',newSz='3')) + + # def test_get_order_history(self): + # print(self.tradeApi.get_orders_history(instType="SPOT",begin='1684857629313',end='1684857629313')) + + # def test_get_order_histry_archive(self): + # print(self.tradeApi.get_orders_history_archive(instType="SPOT",begin='1684857629313',end='1684857629313')) + # 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_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)) + + # 581616258865516544 + # 581616258865516545 + # def test_amend_order(self): + # print(self.tradeApi.amend_order("BTC-USDT", ordId="581616258865516544", newSz="0.03")) + # def test_amend_order_batch(self): + # orderData = [ + # { + # 'instId': 'ETH-USDT', + # 'ordId': '581616258865516544', + # 'newSz': '0.02' + # }, + # { + # 'instId': 'BTC-USDT', + # 'ordId': '581616258865516545', + # 'newPx': '3.0' + # } + # ] + # print(self.tradeApi.amend_multiple_orders(orderData)) + + # def test_order_algo(self): + # + # print(self.tradeApi.place_algo_order(instId='BTC-USDT-SWAP', tdMode='cross', side='buy', ordType='conditional', \ + # tpTriggerPx='15', tpOrdPx='18', sz='2',algoClOrdId='7678687',quickMgnType='manual')) + + # def test_order_algos_list(self): + # print(self.tradeApi.order_algos_list(ordType='conditional')) + + # def test_order_algo(self): + # print(self.tradeApi.place_order(instId='BTC-USDT-SWAP', tdMode='cross', side='buy',px='121',sz='2', + # clOrdId='234234565535',ordType='market')) + # def test_close_all_positions(self): + # print(self.tradeApi.close_positions(instId="BTC-USDT-SWAP", mgnMode="cross",clOrdId='1213124')) + + def test_get_oneclick_repay_list_v2(self): + print(self.tradeApi.get_oneclick_repay_list_v2()) + def test_oneclick_repay_v2(self): + print(self.tradeApi.oneclick_repay_v2('BTC',['USDT'])) + def test_oneclick_repay_history_v2(self): + print(self.tradeApi.oneclick_repay_history_v2()) + +if __name__ == '__main__': unittest.main() diff --git a/test/TradingDataTest.py b/test/TradingDataTest.py index e3083fdf..ac318b60 100644 --- a/test/TradingDataTest.py +++ b/test/TradingDataTest.py @@ -4,9 +4,9 @@ class TradingDataTest(unittest.TestCase): def setUp(self): - api_key = '52c37310-a8b0-454a-8191-3250acff2626' - api_secret_key = 'EC37534156E6B8C32E78FE8D8C1D506B' - passphrase = 'Hanhao0.0' + api_key = 'your_apiKey' + api_secret_key = 'your_secretKey' + passphrase = 'your_secretKey' self.TradingDataAPI = TradingData.TradingDataAPI(api_key, api_secret_key, passphrase, use_server_time=False, flag='1') """ diff --git a/test/WsPrivateAsyncTest.py b/test/WsPrivateAsyncTest.py new file mode 100644 index 00000000..ba7fcff0 --- /dev/null +++ b/test/WsPrivateAsyncTest.py @@ -0,0 +1,39 @@ +import asyncio + +from okx.websocket.WsPrivateAsync import WsPrivateAsync + + +def privateCallback(message): + print("privateCallback", message) + + +async def main(): + url = "wss://wspap.okx.com:8443/ws/v5/private?brokerId=9999" + ws = WsPrivateAsync( + apiKey="your apiKey", + passphrase="your passphrase", + secretKey="your secretKey", + url=url, + useServerTime=False + ) + await ws.start() + args = [] + arg1 = {"channel": "account", "ccy": "BTC"} + arg2 = {"channel": "orders", "instType": "ANY"} + arg3 = {"channel": "balance_and_position"} + args.append(arg1) + args.append(arg2) + args.append(arg3) + await ws.subscribe(args, callback=privateCallback) + await asyncio.sleep(30) + print("-----------------------------------------unsubscribe--------------------------------------------") + args2 = [arg2] + await ws.unsubscribe(args2, callback=privateCallback) + await asyncio.sleep(30) + print("-----------------------------------------unsubscribe all--------------------------------------------") + args3 = [arg1, arg3] + await ws.unsubscribe(args3, callback=privateCallback) + + +if __name__ == '__main__': + asyncio.run(main()) diff --git a/test/WsPrivateTest.py b/test/WsPrivateTest.py deleted file mode 100644 index af12427b..00000000 --- a/test/WsPrivateTest.py +++ /dev/null @@ -1,32 +0,0 @@ -import time - -from okx.websocket.WsPrivate import WsPrivate - -def privateCallback(message): - print("WsPrivate subscribe callback:", message) - - -if __name__ == '__main__': - url = "wss://ws.okx.com:8443/ws/v5/private" - ws = WsPrivate(apiKey="your_apiKey", - passphrase="your_passphrase", - secretKey="your_secretKey", - url=url, - useServerTime=False) - ws.start() - args = [] - arg1 = {"channel": "account", "instType": "BTC"} - arg2 = {"channel": "orders", "instType": "ANY"} - arg3 = {"channel": "balance_and_position"} - args.append(arg1) - args.append(arg2) - args.append(arg3) - ws.subscribe(args, callback=privateCallback) - time.sleep(30) - print("-----------------------------------------unsubscribe--------------------------------------------") - args2 = [arg2] - ws.unsubscribe(args2, callback=privateCallback) - time.sleep(30) - print("-----------------------------------------unsubscribe all--------------------------------------------") - args3 = [arg1, arg3] - ws.unsubscribe(args3, callback=privateCallback) diff --git a/test/WsPublicTest.py b/test/WsPublicAsyncTest.py similarity index 53% rename from test/WsPublicTest.py rename to test/WsPublicAsyncTest.py index 6a56990e..14276a06 100644 --- a/test/WsPublicTest.py +++ b/test/WsPublicAsyncTest.py @@ -1,29 +1,37 @@ -import time -from okx.websocket.WsPublic import WsPublic +import asyncio + +from okx.websocket.WsPublicAsync import WsPublicAsync + def publicCallback(message): print("publicCallback", message) -if __name__ == '__main__': - url = "wss://wspri.coinall.ltd:8443/ws/v5/public?brokerId=9999" - ws = WsPublic(url=url) - ws.start() +async def main(): + + # url = "wss://wspap.okex.com:8443/ws/v5/public?brokerId=9999" + url = "wss://wspap.okx.com:8443/ws/v5/public?brokerId=9999" + ws = WsPublicAsync(url=url) + await ws.start() args = [] arg1 = {"channel": "instruments", "instType": "FUTURES"} arg2 = {"channel": "instruments", "instType": "SPOT"} - arg3 = {"channel": "tickers", "instId": "BTC-USDT"} + arg3 = {"channel": "tickers", "instId": "BTC-USDT-SWAP"} arg4 = {"channel": "tickers", "instId": "ETH-USDT"} args.append(arg1) args.append(arg2) args.append(arg3) args.append(arg4) - ws.subscribe(args, publicCallback) - time.sleep(10) + await ws.subscribe(args, publicCallback) + await asyncio.sleep(5) print("-----------------------------------------unsubscribe--------------------------------------------") args2 = [arg4] - ws.unsubscribe(args2, publicCallback) - time.sleep(10) + await ws.unsubscribe(args2, publicCallback) + await asyncio.sleep(5) print("-----------------------------------------unsubscribe all--------------------------------------------") args3 = [arg1, arg2, arg3] - ws.unsubscribe(args3, publicCallback) + await ws.unsubscribe(args3, publicCallback) + + +if __name__ == '__main__': + asyncio.run(main()) diff --git a/websocket_example.py b/websocket_example.py deleted file mode 100644 index 2b83cb07..00000000 --- a/websocket_example.py +++ /dev/null @@ -1,522 +0,0 @@ -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()