├── .gitignore
├── .idea
├── .gitignore
├── buou_trail.iml
├── encodings.xml
├── inspectionProfiles
│ ├── Project_Default.xml
│ └── profiles_settings.xml
├── misc.xml
├── modules.xml
└── vcs.xml
├── README.md
├── chua_bitget.py
├── chua_bn.py
├── chua_ok.py
├── chua_ok_all.py
├── chua_ok_bot.py
├── config.json
├── config.template.json
├── okx
├── Account_api.py
├── Affiliate_api.py
├── Broker_api.py
├── Convert_api.py
├── Copytrading_api.py
├── FDBroker_api.py
├── Finance_api.py
├── Funding_api.py
├── Market_api.py
├── Public_api.py
├── Recurring_api.py
├── Rfq_api.py
├── SprdApi_api.py
├── Trade_api.py
├── TradingBot_api.py
├── TradingData_api.py
├── __init__.py
├── __pycache__
│ ├── Account_api.cpython-310.pyc
│ ├── Trade_api.cpython-310.pyc
│ ├── TradingBot_api.cpython-310.pyc
│ ├── __init__.cpython-310.pyc
│ ├── client.cpython-310.pyc
│ ├── consts.cpython-310.pyc
│ ├── exceptions.cpython-310.pyc
│ └── utils.cpython-310.pyc
├── client.py
├── consts.py
├── exceptions.py
├── status_api.py
├── subAccount_api.py
└── utils.py
└── requirements.txt
/.gitignore:
--------------------------------------------------------------------------------
1 | #config.json
2 |
--------------------------------------------------------------------------------
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # 默认忽略的文件
2 | /shelf/
3 | /workspace.xml
4 |
--------------------------------------------------------------------------------
/.idea/buou_trail.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/inspectionProfiles/Project_Default.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
51 |
52 |
53 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
--------------------------------------------------------------------------------
/.idea/inspectionProfiles/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # buou_trail
2 | 分档移动止盈
3 |
4 | 本工具极大提高了胜率,特别是管住你的双手,纪律性拉满。
5 |
6 |
7 | 注意CCXT版本不一致大概率会导致bug,建议requirements.txt安装
8 |
9 | bn交易所需设置**单向持仓**
10 | OKx交易所**单向持仓双向都支持**
11 | bitget交易所需设置**双向持仓**
12 |
13 | 相关视频:
14 | - [视频1](https://www.youtube.com/watch?v=1ujgGsMQbqA)
15 | - [视频2](https://www.youtube.com/watch?v=f4T0tKZTVrM)
16 | - [视频3](https://www.youtube.com/watch?v=S8ICwu9u-dk)
17 |
18 | ### 安装环境
19 | 推荐使用 `python3.9`。
20 |
21 | > 注意:很多朋友报错基本是由于 Windows 系统时间问题或代理问题。请确保电脑时间同步,若有代理问题,将 `proxy = {}` 改为你的代理端口。
22 |
23 | 服务器推荐使用阿里云轻量级服务器,我个人使用的是每月 34 人民币的那台。
24 |
25 | 如果了解 Python 基础知识,大多数情况下都能解决环境问题。如需帮助,建议找身边朋友协助,或联系我有偿代劳。
26 |
27 | 电报:[联系我](https://t.me/buouqukuairiji)
28 |
29 | > 注意 :配置文件改好参数之后重命名:config.template.json 改成 config.json
30 |
31 | ### 更新日志
32 | - **20241028**: 修复已平仓品种再次下单会秒平仓的 bug。
33 | - **20241028**: 修复全仓模式平仓会反向开单的 bug。
34 | - **20241029**: 新增黑名单功能。
35 | - **20241029**: 重新整理变量参数。
36 | - **20241105**: 新增bitget版本。
37 | - **20241105**: 改为按日切割日志。
38 | - **20241105**: 修复bitget因为ccxt版本过高导致的bug。
39 | - **20241105**: 更新后支持okx的策略信号监控了 (https://youtu.be/ugyQDrIw8-I)
40 | - **20241106**: okx不再区分单向持仓还是双向,都支持了
41 | - **20241108**: okx bitget 支持浮盈加仓了 (https://youtu.be/GOYzgskAjvs)
42 | - **20241112**: okx 新增全仓统一监控 (https://www.youtube.com/watch?v=99mCa_UiHiE)
43 |
44 | ### 配置说明
45 |
46 |
47 | #### Binance 配置
48 |
49 | - **apiKey**: 你的 Binance API 密钥,用于身份验证。
50 | - **secret**: 你的 Binance API 密钥的秘密,用于签名请求。
51 | - **leverage**: 杠杆倍数,默认为 1.0。
52 | - **stop_loss_pct**: 止损百分比,表示当亏损达到该百分比时平仓,例如 2 表示亏损 2% 时平仓。
53 | - **low_trail_stop_loss_pct**: 低档保护止盈回撤百分比,表示在低档保护止盈时允许的最大回撤位置,例如 0.3 表示 0.3% 固定平仓。
54 | - **trail_stop_loss_pct**: 第一档移动止盈回撤百分比,表示在第一档移动止盈时允许的最大回撤百分比,例如 0.2 表示 20% 回撤固定平仓。
55 | - **higher_trail_stop_loss_pct**: 第二档移动止盈回撤百分比,表示在第二档移动止盈时允许的最大回撤百分比,例如 0.25 表示 25% 回撤固定平仓。
56 | - **low_trail_profit_threshold**: 低档保护止盈触发阈值,表示达到该盈利百分比时进入低档保护止盈,例如 0.4 表示开仓价 0.4% 时触发。
57 | - **first_trail_profit_threshold**: 第一档移动止盈触发阈值,表示达到该盈利百分比时进入第一档移动止盈,例如 1.0 表示开仓价 1% 时触发。
58 | - **second_trail_profit_threshold**: 第二档移动止盈触发阈值,表示达到该盈利百分比时进入第二档移动止盈,例如 3.0 表示开仓价 3% 时触发。
59 | - **blacklist**: 黑名单列表,包含不需要监控的交易对,例如 ["ETH/USDT:USDT"]。
60 |
61 | #### OKX 配置
62 |
63 | - **apiKey**: 你的 OKX API 密钥,用于身份验证。
64 | - **secret**: 你的 OKX API 密钥的秘密,用于签名请求。
65 | - **password**: 你的 OKX API 密码,用于身份验证。
66 | - **leverage**: 杠杆倍数,默认为 1.0。(暂时没用,反正都是全平,布欧习惯保留这个参数而已)
67 | - **stop_loss_pct**: 止损百分比,表示当亏损达到该百分比时平仓,例如 2 表示亏损 2% 时平仓。
68 | - **low_trail_stop_loss_pct**: 低档保护止盈回撤百分比,表示在低档保护止盈时允许的最大回撤位置,例如 0.3 表示 0.3% 固定平仓。
69 | - **trail_stop_loss_pct**: 第一档移动止盈回撤百分比,表示在第一档移动止盈时允许的最大回撤百分比,例如 0.2 表示 20% 回撤固定平仓。
70 | - **higher_trail_stop_loss_pct**: 第二档移动止盈回撤百分比,表示在第二档移动止盈时允许的最大回撤百分比,例如 0.25 表示 25% 回撤固定平仓。
71 | - **low_trail_profit_threshold**: 低档保护止盈触发阈值,表示达到该盈利百分比时进入低档保护止盈,例如 0.4 表示开仓价 0.4% 时触发。
72 | - **first_trail_profit_threshold**: 第一档移动止盈触发阈值,表示达到该盈利百分比时进入第一档移动止盈,例如 1.0 表示开仓价 1% 时触发。
73 | - **second_trail_profit_threshold**: 第二档移动止盈触发阈值,表示达到该盈利百分比时进入第二档移动止盈,例如 3.0 表示开仓价 3% 时触发。
74 | - **blacklist**: 黑名单列表,包含不需要监控的交易对,例如 ["ETH-USDT-SWAP"]。
75 |
76 | #### BITGET 配置
77 |
78 | - **apiKey**: 你的 OKX API 密钥,用于身份验证。
79 | - **secret**: 你的 OKX API 密钥的秘密,用于签名请求。
80 | - **password**: 你的 OKX API 密码,用于身份验证。
81 | - **leverage**: 杠杆倍数,默认为 1.0。(暂时没用,反正都是全平,布欧习惯保留这个参数而已)
82 | - **stop_loss_pct**: 止损百分比,表示当亏损达到该百分比时平仓,例如 2 表示亏损 2% 时平仓。
83 | - **low_trail_stop_loss_pct**: 低档保护止盈回撤百分比,表示在低档保护止盈时允许的最大回撤位置,例如 0.3 表示 0.3% 固定平仓。
84 | - **trail_stop_loss_pct**: 第一档移动止盈回撤百分比,表示在第一档移动止盈时允许的最大回撤百分比,例如 0.2 表示 20% 回撤固定平仓。
85 | - **higher_trail_stop_loss_pct**: 第二档移动止盈回撤百分比,表示在第二档移动止盈时允许的最大回撤百分比,例如 0.25 表示 25% 回撤固定平仓。
86 | - **low_trail_profit_threshold**: 低档保护止盈触发阈值,表示达到该盈利百分比时进入低档保护止盈,例如 0.4 表示开仓价 0.4% 时触发。
87 | - **first_trail_profit_threshold**: 第一档移动止盈触发阈值,表示达到该盈利百分比时进入第一档移动止盈,例如 1.0 表示开仓价 1% 时触发。
88 | - **second_trail_profit_threshold**: 第二档移动止盈触发阈值,表示达到该盈利百分比时进入第二档移动止盈,例如 3.0 表示开仓价 3% 时触发。
89 | - **blacklist**: 黑名单列表,包含不需要监控的交易对,例如 ["ETH-USDT-SWAP"]。
90 |
91 | ##### 飞书 Webhook
92 |
93 | - **feishu_webhook**: 飞书 Webhook URL,用于接收通知。例如 `https://open.feishu.cn/open-apis/bot/v2/hook/655821a2-8`。
94 |
95 | ##### 监控间隔
96 |
97 | - **monitor_interval**: 监控循环的时间间隔(以秒为单位),默认为 4 秒。
98 |
99 | 打赏地址trc20: TUunBuqQ1ZDYt9WrA3ZarndFPQgefXqZAM
100 |
--------------------------------------------------------------------------------
/chua_bitget.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | import ccxt
3 | import time
4 | import logging
5 | import requests
6 | import json
7 | from logging.handlers import TimedRotatingFileHandler
8 |
9 |
10 | class CustomBitget(ccxt.bitget):
11 | def fetch(self, url, method='GET', headers=None, body=None):
12 | if headers is None:
13 | headers = {}
14 | headers['X-CHANNEL-API-CODE'] = 'tu3hz'
15 | return super().fetch(url, method, headers, body)
16 |
17 |
18 | class MultiAssetTradingBot:
19 | def __init__(self, config, feishu_webhook=None, monitor_interval=4):
20 | self.leverage = float(config["leverage"])
21 | self.stop_loss_pct = config["stop_loss_pct"]
22 | self.low_trail_stop_loss_pct = config["low_trail_stop_loss_pct"]
23 | self.trail_stop_loss_pct = config["trail_stop_loss_pct"]
24 | self.higher_trail_stop_loss_pct = config["higher_trail_stop_loss_pct"]
25 | self.low_trail_profit_threshold = config["low_trail_profit_threshold"]
26 | self.first_trail_profit_threshold = config["first_trail_profit_threshold"]
27 | self.second_trail_profit_threshold = config["second_trail_profit_threshold"]
28 | self.feishu_webhook = feishu_webhook
29 | self.blacklist = set(config.get("blacklist", []))
30 | self.monitor_interval = monitor_interval # 从配置文件读取的监控循环时间
31 |
32 | # 配置交易所
33 | self.exchange = CustomBitget({
34 | 'apiKey': config["apiKey"],
35 | 'secret': config["secret"],
36 | 'password': config.get("password", ""), # 如果 Bitget 需要 password,可以配置进去
37 | 'timeout': 3000,
38 | 'rateLimit': 50,
39 | 'options': {'defaultType': 'swap'},
40 | # 'proxies': {'http': 'http://127.0.0.1:10100', 'https': 'http://127.0.0.1:10100'},
41 | })
42 |
43 | # 配置日志
44 | log_file = "log/multi_asset_bot.log"
45 | logger = logging.getLogger(__name__)
46 | logger.setLevel(logging.INFO)
47 |
48 | # 使用 TimedRotatingFileHandler 以天为单位进行日志分割
49 | file_handler = TimedRotatingFileHandler(log_file, when='midnight', interval=1, backupCount=7, encoding='utf-8')
50 | file_handler.suffix = "%Y-%m-%d" # 设置日志文件名的后缀格式,例如 multi_asset_bot.log.2024-11-05
51 | formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
52 | file_handler.setFormatter(formatter)
53 | logger.addHandler(file_handler)
54 |
55 | console_handler = logging.StreamHandler()
56 | console_handler.setFormatter(formatter)
57 | logger.addHandler(console_handler)
58 |
59 | self.logger = logger
60 |
61 | # 用于记录每个持仓的最高盈利值和当前档位
62 | self.highest_profits = {}
63 | self.current_tiers = {}
64 | self.detected_positions = {}
65 | # 检查持仓模式
66 | if not self.is_single_position_mode():
67 | self.logger.error("持仓模式无法双向持仓,可能是因为手上有持仓单子导致,请先平仓更改双向持仓后再运行程序。")
68 | self.send_feishu_notification("持仓模式无法双向持仓,可能是因为手上有持仓单子导致,请先平仓更改双向持仓后再运行程序。")
69 | raise SystemExit("持仓模式无法双向持仓,可能是因为手上有持仓单子导致,请先平仓更改双向持仓后再运行程序。")
70 |
71 | def is_single_position_mode(self):
72 | try:
73 | # 设置为双向持仓模式
74 | account_info = self.exchange.set_position_mode(hedged=True)
75 |
76 | # 获取 posMode 字段的值
77 | self.logger.info(f"程序启动,更改持仓模式为双向持仓")
78 | self.send_feishu_notification(f"程序启动,更改持仓模式为双向持仓")
79 | pos_mode = account_info.get('data', {}).get('posMode', None)
80 |
81 | # 如果 pos_mode 为 'single_mode',则表示为单向持仓模式
82 | return pos_mode == 'hedge_mode'
83 | except Exception as e:
84 | self.logger.error(f"获取账户信息时出错: {e}")
85 | return False
86 |
87 | def send_feishu_notification(self, message):
88 | if self.feishu_webhook:
89 | try:
90 | headers = {'Content-Type': 'application/json'}
91 | payload = {"msg_type": "text", "content": {"text": message}}
92 | response = requests.post(self.feishu_webhook, json=payload, headers=headers)
93 | if response.status_code == 200:
94 | self.logger.info("飞书通知发送成功")
95 | else:
96 | self.logger.error("飞书通知发送失败,状态码: %s", response.status_code)
97 | except Exception as e:
98 | self.logger.error("发送飞书通知时出现异常: %s", str(e))
99 |
100 | def schedule_task(self):
101 | self.logger.info("启动主循环,开始执行任务调度...")
102 | try:
103 | while True:
104 | self.monitor_positions()
105 | time.sleep(self.monitor_interval)
106 | except KeyboardInterrupt:
107 | self.logger.info("程序收到中断信号,开始退出...")
108 | except Exception as e:
109 | error_message = f"程序异常退出: {str(e)}"
110 | self.logger.error(error_message)
111 | self.send_feishu_notification(error_message)
112 |
113 | def fetch_positions(self):
114 | try:
115 | positions = self.exchange.fetch_positions()
116 | return positions
117 | except Exception as e:
118 | self.logger.error(f"Error fetching positions: {e}")
119 | return []
120 |
121 | def close_position(self, symbol, side):
122 | try:
123 | # 获取当前持仓数量
124 | position = next((pos for pos in self.fetch_positions() if pos['symbol'] == symbol), None)
125 | if position is None or float(position['contracts']) == 0:
126 | self.logger.info(f"{symbol} 仓位已平,无需继续平仓")
127 | return True
128 |
129 | amount = float(position['contracts']) # 使用当前持仓数量进行一次性清仓
130 |
131 | # 创建平仓订单,并加上 reduceOnly 参数
132 |
133 | bg_symbol = symbol.replace("/", "").replace(":USDT", "")
134 |
135 | # order = self.exchange.create_order(symbol, 'market', side, amount)
136 | order = self.exchange.privateMixPostV2MixOrderClosePositions({'symbol': bg_symbol, 'holdSide': side, 'productType': 'USDT-FUTURES'})
137 |
138 | if order['code'] == '00000' and order['data']['successList']:
139 | self.logger.info(f"Closed position for {symbol} with size {amount}, side: {side}")
140 | self.send_feishu_notification(f"Closed position for {symbol} with size {amount}, side: {side}")
141 | self.detected_positions.pop(symbol, None)
142 | self.highest_profits.pop(symbol, None)
143 | self.current_tiers.pop(symbol, None)
144 | return True
145 | else:
146 | self.logger.error(f"Failed to close position for {symbol}: {order}")
147 | return False
148 | except Exception as e:
149 | self.logger.error(f"Error closing position for {symbol}: {e}")
150 | return False
151 |
152 | def monitor_positions(self):
153 | positions = self.fetch_positions()
154 | current_symbols = set(position['symbol'] for position in positions if float(position['contracts']) != 0)
155 |
156 | closed_symbols = set(self.detected_positions.keys()) - current_symbols
157 | for symbol in closed_symbols:
158 | self.logger.info(f"手动平仓检测:{symbol} 已平仓,从监控中移除")
159 | self.send_feishu_notification(f"手动平仓检测:{symbol} 已平仓,从监控中移除")
160 | self.detected_positions.pop(symbol, None)
161 |
162 | for position in positions:
163 | symbol = position['symbol']
164 | position_amt = float(position['contracts'])
165 | entry_price = float(position['entryPrice'])
166 | current_price = float(position['markPrice'])
167 | side = position['side']
168 | td_mode = position['marginMode']
169 |
170 | if position_amt == 0:
171 | continue
172 |
173 | if symbol in self.blacklist:
174 | if symbol not in self.detected_positions:
175 | self.send_feishu_notification(f"检测到黑名单品种:{symbol},跳过监控")
176 | self.detected_positions[symbol] = position_amt # 临时存储持仓数量
177 | continue
178 |
179 | if symbol not in self.detected_positions:
180 | self.detected_positions[symbol] = position_amt
181 | self.highest_profits[symbol] = 0
182 | self.current_tiers[symbol] = "无"
183 | self.logger.info(
184 | f"首次检测到仓位:{symbol}, 仓位数量: {position_amt}, 开仓价格: {entry_price}, 方向: {side}")
185 | self.send_feishu_notification(
186 | f"首次检测到仓位:{symbol}, 仓位数量: {position_amt}, 开仓价格: {entry_price}, 方向: {side}")
187 |
188 | # 检测是否有新加仓
189 | if position_amt > self.detected_positions[symbol]:
190 | self.highest_profits[symbol] = 0 # 重置最高盈利
191 | self.current_tiers[symbol] = "无" # 重置档位
192 | self.detected_positions[symbol] = position_amt
193 | self.logger.info(f"{symbol} 新仓检测到,重置最高盈利和档位。")
194 | continue # 跳出当前循环
195 |
196 | if side == 'long':
197 | profit_pct = (current_price - entry_price) / entry_price * 100
198 | elif side == 'short':
199 | profit_pct = (entry_price - current_price) / entry_price * 100
200 | else:
201 | continue
202 |
203 | highest_profit = self.highest_profits.get(symbol, 0)
204 | if profit_pct > highest_profit:
205 | highest_profit = profit_pct
206 | self.highest_profits[symbol] = highest_profit
207 |
208 | current_tier = self.current_tiers.get(symbol, "无")
209 | if highest_profit >= self.second_trail_profit_threshold:
210 | current_tier = "第二档移动止盈"
211 | elif highest_profit >= self.first_trail_profit_threshold:
212 | current_tier = "第一档移动止盈"
213 | elif highest_profit >= self.low_trail_profit_threshold:
214 | current_tier = "低档保护止盈"
215 | else:
216 | current_tier = "无"
217 |
218 | self.current_tiers[symbol] = current_tier
219 |
220 | self.logger.info(
221 | f"监控 {symbol},仓位: {position_amt},方向: {side},开仓价格: {entry_price},当前价格: {current_price},浮动盈亏: {profit_pct:.2f}%,最高盈亏: {highest_profit:.2f}%,当前档位: {current_tier}")
222 |
223 | if current_tier == "低档保护止盈":
224 | self.logger.info(f"回撤到{self.low_trail_stop_loss_pct:.2f}% 止盈")
225 | if profit_pct <= self.low_trail_stop_loss_pct:
226 | self.logger.info(f"{symbol} 触发低档保护止盈,当前盈亏回撤到: {profit_pct:.2f}%,执行平仓")
227 | self.close_position(symbol, side)
228 | continue
229 |
230 | elif current_tier == "第一档移动止盈":
231 | trail_stop_loss = highest_profit * (1 - self.trail_stop_loss_pct)
232 | self.logger.info(f"回撤到 {trail_stop_loss:.2f}% 止盈")
233 | if profit_pct <= trail_stop_loss:
234 | self.logger.info(
235 | f"{symbol} 达到利润回撤阈值,当前档位:第一档移动止盈,最高盈亏: {highest_profit:.2f}%,当前盈亏: {profit_pct:.2f}%,执行平仓")
236 | self.close_position(symbol, side)
237 | continue
238 |
239 | elif current_tier == "第二档移动止盈":
240 | trail_stop_loss = highest_profit * (1 - self.higher_trail_stop_loss_pct)
241 | self.logger.info(f"回撤到 {trail_stop_loss:.2f}% 止盈")
242 | if profit_pct <= trail_stop_loss:
243 | self.logger.info(
244 | f"{symbol} 达到利润回撤阈值,当前档位:第二档移动止盈,最高盈亏: {highest_profit:.2f}%,当前盈亏: {profit_pct:.2f}%,执行平仓")
245 | self.close_position(symbol, side)
246 | continue
247 |
248 | if profit_pct <= -self.stop_loss_pct:
249 | self.logger.info(f"{symbol} 触发止损,当前盈亏: {profit_pct:.2f}%,执行平仓")
250 | self.close_position(symbol, side)
251 |
252 |
253 | if __name__ == '__main__':
254 | with open('config.json', 'r') as f:
255 | config_data = json.load(f)
256 |
257 | # 选择交易平台,假设这里选择 Bitget
258 | platform_config = config_data['bitget']
259 | feishu_webhook_url = config_data['feishu_webhook']
260 | monitor_interval = config_data.get("monitor_interval", 4) # 默认值为4秒
261 |
262 | bot = MultiAssetTradingBot(platform_config, feishu_webhook=feishu_webhook_url, monitor_interval=monitor_interval)
263 | bot.schedule_task()
264 |
--------------------------------------------------------------------------------
/chua_bn.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | import ccxt
3 | import time
4 | import logging
5 | import requests
6 | import json
7 | from logging.handlers import TimedRotatingFileHandler
8 |
9 | class MultiAssetTradingBot:
10 | def __init__(self, config, feishu_webhook=None, monitor_interval=4):
11 | self.leverage = float(config["leverage"])
12 | self.stop_loss_pct = config["stop_loss_pct"]
13 | self.low_trail_stop_loss_pct = config["low_trail_stop_loss_pct"]
14 | self.trail_stop_loss_pct = config["trail_stop_loss_pct"]
15 | self.higher_trail_stop_loss_pct = config["higher_trail_stop_loss_pct"]
16 | self.low_trail_profit_threshold = config["low_trail_profit_threshold"]
17 | self.first_trail_profit_threshold = config["first_trail_profit_threshold"]
18 | self.second_trail_profit_threshold = config["second_trail_profit_threshold"]
19 | self.feishu_webhook = feishu_webhook
20 | self.blacklist = set(config.get("blacklist", []))
21 | self.monitor_interval = monitor_interval # 从配置文件读取的监控循环时间
22 |
23 | # 配置交易所
24 | self.exchange = ccxt.binance({
25 | 'apiKey': config["apiKey"],
26 | 'secret': config["secret"],
27 | 'timeout': 3000,
28 | 'rateLimit': 50,
29 | 'options': {
30 | 'defaultType': 'future',
31 | },
32 | # 'proxies': {'http': 'http://127.0.0.1:10100', 'https': 'http://127.0.0.1:10100'},
33 | })
34 |
35 | # 配置日志
36 | log_file = "log/multi_asset_bot.log"
37 | logger = logging.getLogger(__name__)
38 | logger.setLevel(logging.INFO)
39 |
40 | # 使用 TimedRotatingFileHandler 以天为单位进行日志分割
41 | file_handler = TimedRotatingFileHandler(log_file, when='midnight', interval=1, backupCount=7, encoding='utf-8')
42 | file_handler.suffix = "%Y-%m-%d" # 设置日志文件名的后缀格式,例如 multi_asset_bot.log.2024-11-05
43 | formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
44 | file_handler.setFormatter(formatter)
45 | logger.addHandler(file_handler)
46 |
47 | console_handler = logging.StreamHandler()
48 | console_handler.setFormatter(formatter)
49 | logger.addHandler(console_handler)
50 |
51 | self.logger = logger
52 |
53 | # 用于记录每个持仓的最高盈利值和当前档位
54 | self.highest_profits = {}
55 | self.current_tiers = {}
56 | self.detected_positions = set()
57 |
58 | def send_feishu_notification(self, message):
59 | """发送飞书通知"""
60 | if self.feishu_webhook:
61 | try:
62 | headers = {'Content-Type': 'application/json'}
63 | payload = {
64 | "msg_type": "text",
65 | "content": {
66 | "text": message
67 | }
68 | }
69 | response = requests.post(self.feishu_webhook, json=payload, headers=headers)
70 | if response.status_code == 200:
71 | self.logger.info("飞书通知发送成功")
72 | else:
73 | self.logger.error("飞书通知发送失败,状态码: %s", response.status_code)
74 | except Exception as e:
75 | self.logger.error("发送飞书通知时出现异常: %s", str(e))
76 |
77 | def schedule_task(self):
78 | """主循环,控制执行时间"""
79 | self.logger.info("启动主循环,开始执行任务调度...")
80 | try:
81 | while True:
82 | self.monitor_positions()
83 | time.sleep(monitor_interval) # 每5秒检查一次持仓
84 | except KeyboardInterrupt:
85 | self.logger.info("程序收到中断信号,开始退出...")
86 | except Exception as e:
87 | error_message = f"程序异常退出: {str(e)}"
88 | self.logger.error(error_message)
89 | self.send_feishu_notification(error_message)
90 |
91 | def fetch_positions(self):
92 | try:
93 | positions = self.exchange.fetch_positions()
94 | return positions
95 | except Exception as e:
96 | self.logger.error(f"Error fetching positions: {e}")
97 | return []
98 |
99 | def close_position(self, symbol, amount, side):
100 | try:
101 | order = self.exchange.create_order(symbol, 'market', side, amount, None, {'type': 'future'})
102 | self.logger.info(f"Closed position for {symbol} with size {amount}, side: {side}")
103 | self.send_feishu_notification(f"Closed position for {symbol} with size {amount}, side: {side}")
104 | # 清除检测过的仓位及相关数据
105 | self.detected_positions.discard(symbol)
106 | self.highest_profits.pop(symbol, None) # 清除最高盈利值
107 | self.current_tiers.pop(symbol, None) # 清除当前档位
108 | return True
109 | except Exception as e:
110 | self.logger.error(f"Error closing position for {symbol}: {e}")
111 | return False
112 |
113 | def monitor_positions(self):
114 | print() # 输出一个空行,便于阅读日志
115 | positions = self.fetch_positions()
116 | for position in positions:
117 | symbol = position['symbol']
118 | position_amt = float(position['info']['positionAmt']) # 使用 positionAmt 来获取仓位数量
119 | entry_price = float(position['info']['entryPrice'])
120 | current_price = float(position['info']['markPrice'])
121 | side = position['side'] # 获取仓位方向 ('long' 或 'short')
122 |
123 | if position_amt == 0:
124 | continue
125 | # 检查是否在黑名单中
126 | if symbol in self.blacklist:
127 | if symbol not in self.detected_positions: # 仅在首次检测时发送通知
128 | self.send_feishu_notification(f"检测到黑名单品种:{symbol},跳过监控")
129 | self.detected_positions.add(symbol) # 避免重复通知
130 | continue # 跳过黑名单中的品种
131 |
132 | # 检查是否是首次检测到该仓位
133 | if symbol not in self.detected_positions:
134 | self.detected_positions.add(symbol)
135 | self.highest_profits[symbol] = 0 # 重置最高盈利值
136 | self.current_tiers[symbol] = "无" # 重置档位
137 | self.logger.info(f"首次检测到仓位:{symbol}, 仓位数量: {position_amt}, 开仓价格: {entry_price}, 方向: {side}")
138 | self.send_feishu_notification(f"首次检测到仓位:{symbol}, 仓位数量: {position_amt}, 开仓价格: {entry_price}, 方向: {side},已重置档位跟最高盈利记录, 开始监控...")
139 |
140 | # 根据方向计算浮动盈亏百分比
141 | if side == 'long': # 多头
142 | profit_pct = (current_price - entry_price) / entry_price * 100
143 | elif side == 'short': # 空头
144 | profit_pct = (entry_price - current_price) / entry_price * 100
145 | else:
146 | continue
147 |
148 | # 初始化或更新最高盈利值
149 | highest_profit = self.highest_profits.get(symbol, 0)
150 | if profit_pct > highest_profit:
151 | highest_profit = profit_pct
152 | self.highest_profits[symbol] = highest_profit
153 |
154 | # 更新当前档位
155 | current_tier = self.current_tiers.get(symbol, "无")
156 | if highest_profit >= self.second_trail_profit_threshold:
157 | current_tier = "第二档移动止盈"
158 | elif highest_profit >= self.first_trail_profit_threshold:
159 | current_tier = "第一档移动止盈"
160 | elif highest_profit >= self.low_trail_profit_threshold:
161 | current_tier = "低档保护止盈"
162 | else:
163 | current_tier = "无"
164 |
165 | self.current_tiers[symbol] = current_tier # 保存档位状态
166 |
167 | self.logger.info(
168 | f"监控 {symbol},仓位: {position_amt},方向: {side},开仓价格: {entry_price},当前价格: {current_price},浮动盈亏: {profit_pct:.2f}%,最高盈亏: {highest_profit:.2f}%,当前档位: {current_tier}")
169 |
170 | # 根据档位执行止盈或止损策略
171 | if current_tier == "低档保护止盈":
172 | self.logger.info(f"回撤到{self.low_trail_stop_loss_pct:.2f}% 止盈")
173 | if profit_pct <= self.low_trail_stop_loss_pct:
174 | self.logger.info(f"{symbol} 触发低档保护止盈,当前盈亏回撤到: {profit_pct:.2f}%,执行平仓")
175 | self.close_position(symbol, abs(position_amt), 'sell' if side == 'long' else 'buy')
176 | continue # 一旦平仓,跳过后续逻辑
177 |
178 | elif current_tier == "第一档移动止盈":
179 | trail_stop_loss = highest_profit * (1 - self.trail_stop_loss_pct)
180 | self.logger.info(f"回撤到 {trail_stop_loss:.2f}% 止盈")
181 | if profit_pct <= trail_stop_loss:
182 | self.logger.info(
183 | f"{symbol} 达到利润回撤阈值,当前档位:第一档移动止盈,最高盈亏: {highest_profit:.2f}%,当前盈亏: {profit_pct:.2f}%,执行平仓")
184 | self.close_position(symbol, abs(position_amt), 'sell' if side == 'long' else 'buy')
185 | continue # 一旦平仓,跳过后续逻辑
186 |
187 | elif current_tier == "第二档移动止盈":
188 | trail_stop_loss = highest_profit * (1 - self.higher_trail_stop_loss_pct)
189 | self.logger.info(f"回撤到 {trail_stop_loss:.2f}% 止盈")
190 | if profit_pct <= trail_stop_loss:
191 | self.logger.info(
192 | f"{symbol} 达到利润回撤阈值,当前档位:第二档移动止盈,最高盈亏: {highest_profit:.2f}%,当前盈亏: {profit_pct:.2f}%,执行平仓")
193 | self.close_position(symbol, abs(position_amt), 'sell' if side == 'long' else 'buy')
194 | continue # 一旦平仓,跳过后续逻辑
195 |
196 | # 止损逻辑
197 | if profit_pct <= -self.stop_loss_pct:
198 | self.logger.info(f"{symbol} 触发止损,当前盈亏: {profit_pct:.2f}%,执行平仓")
199 | self.close_position(symbol, abs(position_amt), 'sell' if side == 'long' else 'buy')
200 |
201 | if __name__ == '__main__':
202 | with open('config.json', 'r') as f:
203 | config_data = json.load(f)
204 | # 选择交易平台,假设这里选择 OKX
205 | platform_config = config_data['binance']
206 | feishu_webhook_url = config_data['feishu_webhook']
207 | monitor_interval = config_data.get("monitor_interval", 4) # 默认值为4秒
208 |
209 | bot = MultiAssetTradingBot(platform_config, feishu_webhook=feishu_webhook_url, monitor_interval=monitor_interval)
210 | bot.schedule_task()
211 |
--------------------------------------------------------------------------------
/chua_ok.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | import ccxt
3 | import time
4 | import logging
5 | import requests
6 | import json
7 | import okx.Trade_api as TradeAPI
8 | from logging.handlers import TimedRotatingFileHandler
9 |
10 | class MultiAssetTradingBot:
11 | def __init__(self, config, feishu_webhook=None, monitor_interval=4):
12 | self.leverage = float(config["leverage"])
13 | self.stop_loss_pct = config["stop_loss_pct"]
14 | self.low_trail_stop_loss_pct = config["low_trail_stop_loss_pct"]
15 | self.trail_stop_loss_pct = config["trail_stop_loss_pct"]
16 | self.higher_trail_stop_loss_pct = config["higher_trail_stop_loss_pct"]
17 | self.low_trail_profit_threshold = config["low_trail_profit_threshold"]
18 | self.first_trail_profit_threshold = config["first_trail_profit_threshold"]
19 | self.second_trail_profit_threshold = config["second_trail_profit_threshold"]
20 | self.feishu_webhook = feishu_webhook
21 | self.blacklist = set(config.get("blacklist", []))
22 | self.monitor_interval = monitor_interval # 从配置文件读取的监控循环时间
23 |
24 |
25 | # 配置交易所
26 | self.exchange = ccxt.okx({
27 | 'apiKey': config["apiKey"],
28 | 'secret': config["secret"],
29 | 'password': config["password"],
30 | 'timeout': 3000,
31 | 'rateLimit': 50,
32 | 'options': {'defaultType': 'future'},
33 | # 'proxies': {'http': 'http://127.0.0.1:10100', 'https': 'http://127.0.0.1:10100'},
34 | })
35 | # 配置 OKX 第三方库
36 | self.trading_bot = TradeAPI.TradeAPI(config["apiKey"], config["secret"], config["password"], False, '0')
37 | # 配置日志
38 | log_file = "log/okx.log"
39 | logger = logging.getLogger(__name__)
40 | logger.setLevel(logging.INFO)
41 |
42 | # 使用 TimedRotatingFileHandler 以天为单位进行日志分割
43 | file_handler = TimedRotatingFileHandler(log_file, when='midnight', interval=1, backupCount=7, encoding='utf-8')
44 | file_handler.suffix = "%Y-%m-%d" # 设置日志文件名的后缀格式,例如 multi_asset_bot.log.2024-11-05
45 | formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
46 | file_handler.setFormatter(formatter)
47 | logger.addHandler(file_handler)
48 |
49 | console_handler = logging.StreamHandler()
50 | console_handler.setFormatter(formatter)
51 | logger.addHandler(console_handler)
52 |
53 | self.logger = logger
54 |
55 | # 用于记录每个持仓的最高盈利值和当前档位
56 | self.highest_profits = {}
57 | self.current_tiers = {}
58 | self.detected_positions = {}
59 | # 获取持仓模式
60 | self.position_mode = self.get_position_mode()
61 |
62 | def get_position_mode(self):
63 | try:
64 | # 假设该端点用于获取账户持仓模式
65 | response = self.exchange.private_get_account_config()
66 | data = response.get('data', [])
67 | if data and isinstance(data, list):
68 | # 取列表的第一个元素(假设它是一个字典),然后获取 'posMode'
69 | position_mode = data[0].get('posMode', 'single') # 默认值为单向
70 | self.logger.info(f"当前持仓模式: {position_mode}")
71 | return position_mode
72 | else:
73 | self.logger.error("无法检测持仓模式: 'data' 字段为空或格式不正确")
74 | return 'single' # 返回默认值
75 | except Exception as e:
76 | self.logger.error(f"无法检测持仓模式: {e}")
77 | return None
78 |
79 | def send_feishu_notification(self, message):
80 | if self.feishu_webhook:
81 | try:
82 | headers = {'Content-Type': 'application/json'}
83 | payload = {"msg_type": "text", "content": {"text": message}}
84 | response = requests.post(self.feishu_webhook, json=payload, headers=headers)
85 | if response.status_code == 200:
86 | self.logger.info("飞书通知发送成功")
87 | else:
88 | self.logger.error("飞书通知发送失败,状态码: %s", response.status_code)
89 | except Exception as e:
90 | self.logger.error("发送飞书通知时出现异常: %s", str(e))
91 |
92 | def schedule_task(self):
93 | self.logger.info("启动主循环,开始执行任务调度...")
94 | try:
95 | while True:
96 | self.monitor_positions()
97 | time.sleep(self.monitor_interval)
98 | except KeyboardInterrupt:
99 | self.logger.info("程序收到中断信号,开始退出...")
100 | except Exception as e:
101 | error_message = f"程序异常退出: {str(e)}"
102 | self.logger.error(error_message)
103 | self.send_feishu_notification(error_message)
104 |
105 | def fetch_positions(self):
106 | try:
107 | positions = self.exchange.fetch_positions()
108 | return positions
109 | except Exception as e:
110 | self.logger.error(f"Error fetching positions: {e}")
111 | return []
112 |
113 | def close_position(self, symbol, amount, side, td_mode):
114 | try:
115 | market_symbol = symbol.replace('/', '-').replace(':USDT', '-SWAP')
116 |
117 | # 根据 position_mode 选择平仓方向
118 | if self.position_mode == 'long_short_mode':
119 | # 在双向持仓模式下,确保指定平仓方向 posSide 指定方向
120 | pos_side = 'long' if side == 'long' else 'short'
121 | else:
122 | # 在 net_mode 模式下,不区分方向,系统会自动平仓
123 | pos_side = 'net'
124 |
125 | order = self.trading_bot.close_positions(instId=market_symbol, mgnMode=td_mode, posSide=pos_side, autoCxl='true')
126 |
127 | if order['code'] == '0':
128 | self.logger.info(f"Closed position for {symbol} with size {amount}, side: {pos_side}")
129 | self.send_feishu_notification(f"Closed position for {symbol} with size {amount}, side: {side}")
130 | self.detected_positions.pop(symbol, None)
131 | self.highest_profits.pop(symbol, None)
132 | self.current_tiers.pop(symbol, None)
133 | return True
134 | else:
135 | self.logger.error(f"Failed to close position for {symbol}: {order}")
136 | return False
137 | except Exception as e:
138 | self.logger.error(f"Error closing position for {symbol}: {e}")
139 | return False
140 |
141 | def monitor_positions(self):
142 | positions = self.fetch_positions()
143 | current_symbols = set(position['symbol'] for position in positions if float(position['contracts']) != 0)
144 |
145 | closed_symbols = set(self.detected_positions.keys()) - current_symbols
146 |
147 | for symbol in closed_symbols:
148 | self.logger.info(f"手动平仓检测:{symbol} 已平仓,从监控中移除")
149 | self.send_feishu_notification(f"手动平仓检测:{symbol} 已平仓,从监控中移除")
150 | self.detected_positions.pop(symbol, None)
151 |
152 | for position in positions:
153 | symbol = position['symbol']
154 | # print(position)
155 | position_amt = float(position['contracts'])
156 | entry_price = float(position['entryPrice'])
157 | current_price = float(position['markPrice'])
158 | side = position['side']
159 | td_mode = position['marginMode']
160 |
161 | if position_amt == 0:
162 | continue
163 |
164 | if symbol in self.blacklist:
165 | if symbol not in self.detected_positions:
166 | self.send_feishu_notification(f"检测到黑名单品种:{symbol},跳过监控")
167 | self.detected_positions[symbol] = position_amt
168 | continue
169 |
170 | # 首次检测仓位
171 | if symbol not in self.detected_positions:
172 | self.detected_positions[symbol] = position_amt # 存储仓位数量
173 | self.highest_profits[symbol] = 0
174 | self.current_tiers[symbol] = "无"
175 | self.logger.info(
176 | f"首次检测到仓位:{symbol}, 仓位数量: {position_amt}, 开仓价格: {entry_price}, 方向: {side}")
177 | self.send_feishu_notification(
178 | f"首次检测到仓位:{symbol}, 仓位数量: {position_amt}, 开仓价格: {entry_price}, 方向: {side}")
179 |
180 | # 检测是否有加仓
181 | elif position_amt > self.detected_positions[symbol]:
182 | self.highest_profits[symbol] = 0 # 重置最高盈利
183 | self.current_tiers[symbol] = "无" # 重置档位
184 | self.detected_positions[symbol] = position_amt # 更新持仓数量
185 | self.logger.info(f"{symbol} 检测到加仓,重置最高盈利和档位。")
186 | continue # 跳出当前循环,进入下一个仓位检测
187 |
188 | # 计算盈亏
189 | if side == 'long':
190 | profit_pct = (current_price - entry_price) / entry_price * 100
191 | elif side == 'short':
192 | profit_pct = (entry_price - current_price) / entry_price * 100
193 | else:
194 | continue
195 |
196 |
197 | highest_profit = self.highest_profits.get(symbol, 0)
198 | if profit_pct > highest_profit:
199 | highest_profit = profit_pct
200 | self.highest_profits[symbol] = highest_profit
201 |
202 | current_tier = self.current_tiers.get(symbol, "无")
203 | if highest_profit >= self.second_trail_profit_threshold:
204 | current_tier = "第二档移动止盈"
205 | elif highest_profit >= self.first_trail_profit_threshold:
206 | current_tier = "第一档移动止盈"
207 | elif highest_profit >= self.low_trail_profit_threshold:
208 | current_tier = "低档保护止盈"
209 | else:
210 | current_tier = "无"
211 |
212 | self.current_tiers[symbol] = current_tier
213 |
214 | self.logger.info(
215 | f"监控 {symbol},仓位: {position_amt},方向: {side},开仓价格: {entry_price},当前价格: {current_price},浮动盈亏: {profit_pct:.2f}%,最高盈亏: {highest_profit:.2f}%,当前档位: {current_tier}")
216 |
217 | if current_tier == "低档保护止盈":
218 | self.logger.info(f"回撤到{self.low_trail_stop_loss_pct:.2f}% 止盈")
219 | if profit_pct <= self.low_trail_stop_loss_pct:
220 | self.logger.info(f"{symbol} 触发低档保护止盈,当前盈亏回撤到: {profit_pct:.2f}%,执行平仓")
221 | self.close_position(symbol, abs(position_amt), side, td_mode)
222 | continue
223 |
224 | elif current_tier == "第一档移动止盈":
225 | trail_stop_loss = highest_profit * (1 - self.trail_stop_loss_pct)
226 | self.logger.info(f"回撤到 {trail_stop_loss:.2f}% 止盈")
227 | if profit_pct <= trail_stop_loss:
228 | self.logger.info(
229 | f"{symbol} 达到利润回撤阈值,当前档位:第一档移动止盈,最高盈亏: {highest_profit:.2f}%,当前盈亏: {profit_pct:.2f}%,执行平仓")
230 | self.close_position(symbol, abs(position_amt), side, td_mode)
231 | continue
232 |
233 | elif current_tier == "第二档移动止盈":
234 | trail_stop_loss = highest_profit * (1 - self.higher_trail_stop_loss_pct)
235 | self.logger.info(f"回撤到 {trail_stop_loss:.2f}% 止盈")
236 | if profit_pct <= trail_stop_loss:
237 | self.logger.info(
238 | f"{symbol} 达到利润回撤阈值,当前档位:第二档移动止盈,最高盈亏: {highest_profit:.2f}%,当前盈亏: {profit_pct:.2f}%,执行平仓")
239 | self.close_position(symbol, abs(position_amt), side, td_mode)
240 | continue
241 |
242 | if profit_pct <= -self.stop_loss_pct:
243 | self.logger.info(f"{symbol} 触发止损,当前盈亏: {profit_pct:.2f}%,执行平仓")
244 | self.close_position(symbol, abs(position_amt), side, td_mode)
245 |
246 |
247 | if __name__ == '__main__':
248 | with open('config.json', 'r') as f:
249 | config_data = json.load(f)
250 |
251 | # 选择交易平台,假设这里选择 OKX
252 | platform_config = config_data['okx']
253 | feishu_webhook_url = config_data['feishu_webhook']
254 | monitor_interval = config_data.get("monitor_interval", 4) # 默认值为4秒
255 |
256 | bot = MultiAssetTradingBot(platform_config, feishu_webhook=feishu_webhook_url, monitor_interval=monitor_interval)
257 | bot.schedule_task()
258 |
--------------------------------------------------------------------------------
/chua_ok_all.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | import ccxt
3 | import time
4 | import logging
5 | import requests
6 | import json
7 | import okx.Trade_api as TradeAPI
8 | from logging.handlers import TimedRotatingFileHandler
9 |
10 |
11 | class MultiAssetTradingBot:
12 | def __init__(self, config, feishu_webhook=None, monitor_interval=4):
13 | self.stop_loss_pct = config["all_stop_loss_pct"] # 全局止损百分比
14 | self.low_trail_stop_loss_pct = config["all_low_trail_stop_loss_pct"]
15 | self.trail_stop_loss_pct = config["all_trail_stop_loss_pct"]
16 | self.higher_trail_stop_loss_pct = config["all_higher_trail_stop_loss_pct"]
17 | self.low_trail_profit_threshold = config["all_low_trail_profit_threshold"]
18 | self.first_trail_profit_threshold = config["all_first_trail_profit_threshold"]
19 | self.second_trail_profit_threshold = config["all_second_trail_profit_threshold"]
20 | self.feishu_webhook = feishu_webhook
21 | self.monitor_interval = monitor_interval # 监控循环时间是分仓监控的3倍
22 | self.highest_total_profit = 0 # 记录最高总盈利
23 |
24 | # 配置交易所
25 | self.exchange = ccxt.okx({
26 | 'apiKey': config["apiKey"],
27 | 'secret': config["secret"],
28 | 'password': config["password"],
29 | 'timeout': 3000,
30 | 'rateLimit': 50,
31 | 'options': {'defaultType': 'future'}
32 | })
33 |
34 | # 配置 OKX 第三方库
35 | self.trading_bot = TradeAPI.TradeAPI(config["apiKey"], config["secret"], config["password"], False, '0')
36 |
37 | # 配置日志
38 | log_file = "log/okx_all.log"
39 | logger = logging.getLogger(__name__)
40 | logger.setLevel(logging.INFO)
41 |
42 | file_handler = TimedRotatingFileHandler(log_file, when='midnight', interval=1, backupCount=7, encoding='utf-8')
43 | file_handler.suffix = "%Y-%m-%d"
44 | formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
45 | file_handler.setFormatter(formatter)
46 | logger.addHandler(file_handler)
47 |
48 | console_handler = logging.StreamHandler()
49 | console_handler.setFormatter(formatter)
50 | logger.addHandler(console_handler)
51 |
52 | self.logger = logger
53 | self.position_mode = self.get_position_mode() # 获取持仓模式
54 |
55 | def get_position_mode(self):
56 | try:
57 | # 假设获取账户持仓模式的 API
58 | response = self.exchange.private_get_account_config()
59 | data = response.get('data', [])
60 | if data and isinstance(data, list):
61 | # 取列表的第一个元素(假设它是一个字典),然后获取 'posMode'
62 | position_mode = data[0].get('posMode', 'single') # 默认值为单向
63 | self.logger.info(f"当前持仓模式: {position_mode}")
64 | return position_mode
65 | else:
66 | self.logger.error("无法检测持仓模式: 'data' 字段为空或格式不正确")
67 | return 'single' # 返回默认值
68 | except Exception as e:
69 | self.logger.error(f"无法检测持仓模式: {e}")
70 | return None
71 |
72 | def send_feishu_notification(self, message):
73 | if self.feishu_webhook:
74 | try:
75 | headers = {'Content-Type': 'application/json'}
76 | payload = {"msg_type": "text", "content": {"text": message}}
77 | response = requests.post(self.feishu_webhook, json=payload, headers=headers)
78 | if response.status_code == 200:
79 | self.logger.info("飞书通知发送成功")
80 | else:
81 | self.logger.error("飞书通知发送失败,状态码: %s", response.status_code)
82 | except Exception as e:
83 | self.logger.error("发送飞书通知时出现异常: %s", str(e))
84 |
85 | def fetch_positions(self):
86 | try:
87 | positions = self.exchange.fetch_positions()
88 | return positions
89 | except Exception as e:
90 | self.logger.error(f"Error fetching positions: {e}")
91 | return []
92 |
93 | def fetch_open_orders(self):
94 | try:
95 | orders = self.exchange.fetch_open_orders()
96 | return orders
97 | except Exception as e:
98 | self.logger.error(f"Error fetching open orders: {e}")
99 | return []
100 |
101 | def cancel_all_orders(self):
102 | orders = self.fetch_open_orders()
103 | for order in orders:
104 | try:
105 | self.exchange.cancel_order(order['id'])
106 | self.logger.info(f"Order {order['id']} cancelled.")
107 | except Exception as e:
108 | self.logger.error(f"Error cancelling order {order['id']}: {e}")
109 |
110 | def close_all_positions(self):
111 | positions = self.fetch_positions()
112 | for position in positions:
113 | symbol = position['symbol']
114 | amount = abs(float(position['contracts']))
115 | side = position['side']
116 | td_mode = position['marginMode']
117 | if amount > 0:
118 | try:
119 | self.logger.info(f"Preparing to close position for {symbol}, side: {side}, amount: {amount}")
120 |
121 | if self.position_mode == 'long_short_mode':
122 | # 在双向持仓模式下,指定平仓方向
123 | pos_side = 'long' if side == 'long' else 'short'
124 | else:
125 | # 在单向模式下,不指定方向
126 | pos_side = 'net'
127 |
128 | # 将 symbol 转换为 API 需要的格式
129 | inst_id = symbol.replace('/', '-').replace(':USDT', '')
130 | if 'SWAP' not in inst_id: # 确保是永续合约标识
131 | inst_id += '-SWAP'
132 | # print(f'{inst_id}处理平仓')
133 |
134 | # 发送平仓请求并获取返回值
135 | response = self.trading_bot.close_positions(
136 | instId=inst_id,
137 | mgnMode=td_mode,
138 | posSide=pos_side,
139 | autoCxl='true'
140 | )
141 | self.logger.info(f"Close position response for {symbol}: {response}")
142 | time.sleep(0.1) # 短暂延迟后再试
143 | # 检查平仓结果
144 | if response.get('code') == '0': # 确认成功状态
145 | self.logger.info(f"Successfully closed position for {symbol}, side: {side}, amount: {amount}")
146 | self.send_feishu_notification(
147 | f"Successfully closed position for {symbol}, side: {side}, amount: {amount}")
148 | else:
149 | self.logger.error(f"Failed to close position for {symbol}: {response}")
150 | self.send_feishu_notification(f"Failed to close position for {symbol}: {response}")
151 |
152 | except Exception as e:
153 | self.logger.error(f"Error closing position for {symbol}: {e}")
154 |
155 | def calculate_average_profit(self):
156 | positions = self.fetch_positions()
157 | total_profit_pct = 0.0
158 | num_positions = 0
159 |
160 | for position in positions:
161 | symbol = position['symbol']
162 | entry_price = float(position['entryPrice'])
163 | current_price = float(position['markPrice'])
164 | side = position['side']
165 |
166 | # 计算单个仓位的浮动盈利百分比
167 | if side == 'long':
168 | profit_pct = (current_price - entry_price) / entry_price * 100
169 | elif side == 'short':
170 | profit_pct = (entry_price - current_price) / entry_price * 100
171 | else:
172 | continue
173 |
174 | # 累加总盈利百分比
175 | total_profit_pct += profit_pct
176 | num_positions += 1
177 |
178 | # 记录单个仓位的盈利情况
179 | self.logger.info(f"仓位 {symbol},方向: {side},开仓价格: {entry_price},当前价格: {current_price},"
180 | f"浮动盈亏: {profit_pct:.2f}%")
181 |
182 | # 计算平均浮动盈利百分比
183 | average_profit_pct = total_profit_pct / num_positions if num_positions > 0 else 0
184 | return average_profit_pct
185 |
186 | def reset_highest_profit_and_tier(self):
187 | """重置最高总盈利和当前档位状态"""
188 | self.highest_total_profit = 0
189 | self.current_tier = "无"
190 | self.logger.info("已重置最高总盈利和档位状态")
191 |
192 | def monitor_total_profit(self):
193 | self.logger.info("启动主循环,开始监控总盈利...")
194 | previous_position_size = sum(
195 | abs(float(position['contracts'])) for position in self.fetch_positions()) # 初始总仓位大小
196 | try:
197 | while True:
198 | # 检查仓位总规模变化
199 | current_position_size = sum(abs(float(position['contracts'])) for position in self.fetch_positions())
200 | if current_position_size > previous_position_size:
201 | self.send_feishu_notification(f"检测到仓位变化操作,重置最高盈利和档位状态")
202 | self.logger.info("检测到新增仓位操作,重置最高盈利和档位状态")
203 | self.reset_highest_profit_and_tier()
204 | previous_position_size = current_position_size
205 | continue # 跳过本次循环
206 |
207 | total_profit = self.calculate_average_profit()
208 | self.logger.info(f"当前总盈利: {total_profit:.2f}%")
209 | if total_profit > self.highest_total_profit:
210 | self.highest_total_profit = total_profit
211 | # 确定当前盈利档位
212 | if self.highest_total_profit >= self.second_trail_profit_threshold:
213 | self.current_tier = "第二档移动止盈"
214 | elif self.highest_total_profit >= self.first_trail_profit_threshold:
215 | self.current_tier = "第一档移动止盈"
216 | elif self.highest_total_profit >= self.low_trail_profit_threshold:
217 | self.current_tier = "低档保护止盈"
218 | else:
219 | self.current_tier = "无"
220 |
221 | self.logger.info(
222 | f"当前总盈利: {total_profit:.2f}%,最高总盈利: {self.highest_total_profit:.2f}%,当前档位: {self.current_tier}")
223 |
224 | # 各档止盈逻辑
225 | if self.current_tier == "低档保护止盈":
226 | self.logger.info(f"低档回撤止盈阈值: {self.low_trail_stop_loss_pct:.2f}%")
227 | if total_profit <= self.low_trail_stop_loss_pct:
228 | self.send_feishu_notification(f"总盈利触发低档保护止盈,当前回撤到: {total_profit:.2f}%,执行全部平仓")
229 | self.logger.info(f"总盈利触发低档保护止盈,当前回撤到: {total_profit:.2f}%,执行全部平仓")
230 | self.close_all_positions()
231 | self.reset_highest_profit_and_tier()
232 | continue
233 | elif self.current_tier == "第一档移动止盈":
234 | trail_stop_loss = self.highest_total_profit * (1 - self.trail_stop_loss_pct)
235 | self.logger.info(f"第一档回撤止盈阈值: {trail_stop_loss:.2f}%")
236 | if total_profit <= trail_stop_loss:
237 | self.send_feishu_notification(
238 | f"总盈利达到第一档回撤阈值,最高总盈利: {self.highest_total_profit:.2f}%,当前回撤到: {total_profit:.2f}%,执行全部平仓")
239 | self.logger.info(
240 | f"总盈利达到第一档回撤阈值,最高总盈利: {self.highest_total_profit:.2f}%,当前回撤到: {total_profit:.2f}%,执行全部平仓")
241 | self.close_all_positions()
242 | self.reset_highest_profit_and_tier()
243 | continue
244 |
245 | elif self.current_tier == "第二档移动止盈":
246 | trail_stop_loss = self.highest_total_profit * (1 - self.higher_trail_stop_loss_pct)
247 | self.logger.info(f"第二档回撤止盈阈值: {trail_stop_loss:.2f}%")
248 | if total_profit <= trail_stop_loss:
249 | self.logger.info(f"总盈利达到第二档回撤阈值,最高总盈利: {self.highest_total_profit:.2f}%,当前回撤到: {total_profit:.2f}%,执行全部平仓")
250 | self.send_feishu_notification(f"总盈利达到第二档回撤阈值,最高总盈利: {self.highest_total_profit:.2f}%,当前回撤到: {total_profit:.2f}%,执行全部平仓")
251 | self.close_all_positions()
252 | self.reset_highest_profit_and_tier()
253 | continue
254 | # 全局止损
255 | if total_profit <= -self.stop_loss_pct:
256 | self.logger.info(f"总盈利触发全局止损,当前回撤到: {total_profit:.2f}%,执行全部平仓")
257 | self.send_feishu_notification(f"总盈利触发全局止损,当前回撤到: {total_profit:.2f}%,执行全部平仓")
258 | self.close_all_positions()
259 | self.reset_highest_profit_and_tier()
260 | continue
261 |
262 |
263 | time.sleep(self.monitor_interval)
264 |
265 | except KeyboardInterrupt:
266 | self.logger.info("程序收到中断信号,开始退出...")
267 | except Exception as e:
268 | error_message = f"程序异常退出: {str(e)}"
269 | self.logger.error(error_message)
270 | self.send_feishu_notification(error_message)
271 |
272 |
273 | if __name__ == '__main__':
274 | with open('config.json', 'r') as f:
275 | config_data = json.load(f)
276 |
277 | # 指定具体平台配置,例如 OKX
278 | platform_config = config_data['okx']
279 | feishu_webhook_url = config_data['feishu_webhook']
280 | monitor_interval = config_data.get("monitor_interval", 4) # 默认值为4秒
281 |
282 | bot = MultiAssetTradingBot(platform_config, feishu_webhook=feishu_webhook_url, monitor_interval=monitor_interval)
283 | bot.monitor_total_profit()
284 |
--------------------------------------------------------------------------------
/chua_ok_bot.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | import ccxt
3 | import time
4 | import logging
5 | import requests
6 | import json
7 | import okx.TradingBot_api as TradingBot
8 | from logging.handlers import TimedRotatingFileHandler
9 |
10 | class MultiAssetTradingBot:
11 | def __init__(self, config, feishu_webhook=None, monitor_interval=4):
12 | self.leverage = float(config["leverage"])
13 | self.stop_loss_pct = config["stop_loss_pct"]
14 | self.low_trail_stop_loss_pct = config["low_trail_stop_loss_pct"]
15 | self.trail_stop_loss_pct = config["trail_stop_loss_pct"]
16 | self.higher_trail_stop_loss_pct = config["higher_trail_stop_loss_pct"]
17 | self.low_trail_profit_threshold = config["low_trail_profit_threshold"]
18 | self.first_trail_profit_threshold = config["first_trail_profit_threshold"]
19 | self.second_trail_profit_threshold = config["second_trail_profit_threshold"]
20 | self.feishu_webhook = feishu_webhook
21 | self.blacklist = set(config.get("blacklist", []))
22 | self.monitor_interval = monitor_interval # 从配置文件读取的监控循环时间
23 |
24 | # 配置交易所
25 | self.exchange = ccxt.okx({
26 | 'apiKey': config["apiKey"],
27 | 'secret': config["secret"],
28 | 'password': config["password"],
29 | 'timeout': 3000,
30 | 'rateLimit': 50,
31 | 'options': {'defaultType': 'future'},
32 | # 'proxies': {'http': 'http://127.0.0.1:10100', 'https': 'http://127.0.0.1:10100'},
33 | })
34 | # 配置 OKX 第三方库
35 | self.trading_bot = TradingBot.TradingBotAPI(config["apiKey"], config["secret"], config["password"], False, '0')
36 | # 配置日志
37 | log_file = "log/ok_bot.log"
38 | logger = logging.getLogger(__name__)
39 | logger.setLevel(logging.INFO)
40 |
41 | # 使用 TimedRotatingFileHandler 以天为单位进行日志分割
42 | file_handler = TimedRotatingFileHandler(log_file, when='midnight', interval=1, backupCount=7, encoding='utf-8')
43 | file_handler.suffix = "%Y-%m-%d" # 设置日志文件名的后缀格式,例如 multi_asset_bot.log.2024-11-05
44 | formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
45 | file_handler.setFormatter(formatter)
46 | logger.addHandler(file_handler)
47 |
48 | console_handler = logging.StreamHandler()
49 | console_handler.setFormatter(formatter)
50 | logger.addHandler(console_handler)
51 |
52 | self.logger = logger
53 |
54 | # 用于记录每个持仓的最高盈利值和当前档位
55 | self.highest_profits = {}
56 | self.current_tiers = {}
57 | self.detected_positions = {}
58 |
59 | def send_feishu_notification(self, message):
60 | if self.feishu_webhook:
61 | try:
62 | headers = {'Content-Type': 'application/json'}
63 | payload = {"msg_type": "text", "content": {"text": message}}
64 | response = requests.post(self.feishu_webhook, json=payload, headers=headers)
65 | if response.status_code == 200:
66 | self.logger.info("飞书通知发送成功")
67 | else:
68 | self.logger.error("飞书通知发送失败,状态码: %s", response.status_code)
69 | except Exception as e:
70 | self.logger.error("发送飞书通知时出现异常: %s", str(e))
71 |
72 | def schedule_task(self):
73 | self.logger.info("启动主循环,开始执行任务调度...")
74 | try:
75 | while True:
76 | self.monitor_positions()
77 | time.sleep(self.monitor_interval)
78 | except KeyboardInterrupt:
79 | self.logger.info("程序收到中断信号,开始退出...")
80 | except Exception as e:
81 | error_message = f"程序异常退出: {str(e)}"
82 | self.logger.error(error_message)
83 | self.send_feishu_notification(error_message)
84 |
85 | def fetch_signals(self):
86 | try:
87 |
88 | # 使用 `signalBotTrade` 模块获取信号数据
89 | details = self.trading_bot.signal_orders_algo_pending(algoOrdType = "contract")
90 | # 提取所有的 `algoId`
91 | algo_ids = [item['algoId'] for item in details.get('data', [])]
92 | return algo_ids
93 |
94 | except Exception as e:
95 | self.logger.error(f"Error fetching signals: {e}")
96 | return []
97 |
98 | def fetch_positions(self):
99 | try:
100 | # 获取所有的 signalChanId
101 | signal_ids = self.fetch_signals() # 获取自己创建的信号
102 | all_positions = []
103 | for signal_id in signal_ids:
104 | # 调用 OKX 信号策略接口获取每个信号策略的持仓数据
105 | positions_data = self.exchange.privateGetTradingBotSignalPositions({
106 | 'algoOrdType': 'contract',
107 | 'algoId': signal_id
108 | })
109 |
110 | if positions_data['code'] != '0':
111 | self.logger.error(f"获取信号策略 {signal_id} 的持仓失败: {positions_data['msg']}")
112 | continue
113 |
114 | for item in positions_data['data']:
115 | position = {
116 | 'symbol': item['instId'].replace('-', '/'),
117 | 'contracts': float(item['pos']),
118 | 'entryPrice': float(item['avgPx']),
119 | 'markPrice': float(item['markPx']),
120 | 'side': 'long' if float(item['pos']) > 0 else 'short',
121 | 'marginMode': item['mgnMode'],
122 | 'algoId': signal_id # 包含 `algoId` 方便平仓时使用
123 | }
124 | all_positions.append(position)
125 |
126 | return all_positions
127 | except Exception as e:
128 | self.logger.error(f"Error fetching positions: {e}")
129 | return []
130 |
131 | def close_position(self, symbol, amount, side, td_mode, algo_id):
132 | try:
133 | market_symbol = symbol.replace('/', '-').replace(':USDT', '-SWAP')
134 |
135 | # 使用带 algoId 的平仓方法
136 | order = self.trading_bot.signal_close_position(instId=market_symbol, algoId=algo_id)
137 | # 更新后的成功判断逻辑
138 | if order['code'] == '0' and 'data' in order and order['data']:
139 | self.logger.info(f"Closed position for {symbol} with size {amount}, side: {side}")
140 | self.send_feishu_notification(f"Closed position for {symbol} with size {amount}, side: {side}")
141 | self.detected_positions.pop(symbol, None)
142 | self.highest_profits.pop(symbol, None)
143 | self.current_tiers.pop(symbol, None)
144 | return True
145 | else:
146 | self.logger.error(f"Failed to close position for {symbol}: {order}")
147 | return False
148 | except Exception as e:
149 | self.logger.error(f"Error closing position for {symbol}: {e}")
150 | return False
151 |
152 | def monitor_positions(self):
153 |
154 | positions = self.fetch_positions()
155 | current_symbols = set(position['symbol'] for position in positions if float(position['contracts']) != 0)
156 |
157 | closed_symbols = set(self.detected_positions.keys()) - current_symbols
158 |
159 | for symbol in closed_symbols:
160 | self.logger.info(f"手动平仓检测:{symbol} 已平仓,从监控中移除")
161 | self.send_feishu_notification(f"手动平仓检测:{symbol} 已平仓,从监控中移除")
162 | self.detected_positions.pop(symbol, None)
163 |
164 | for position in positions:
165 | symbol = position['symbol']
166 | position_amt = float(position['contracts'])
167 | entry_price = float(position['entryPrice'])
168 | current_price = float(position['markPrice'])
169 | side = position['side']
170 | td_mode = position['marginMode']
171 | algo_id = position['algoId'] # 获取 algoId
172 |
173 | if position_amt == 0:
174 | continue
175 |
176 | if symbol in self.blacklist:
177 | if symbol not in self.detected_positions:
178 | self.send_feishu_notification(f"检测到黑名单品种:{symbol},跳过监控")
179 | self.detected_positions[symbol] = position_amt
180 | continue
181 |
182 | # 首次检测仓位
183 | if symbol not in self.detected_positions:
184 | self.detected_positions[symbol] = position_amt # 存储仓位数量
185 | self.highest_profits[symbol] = 0
186 | self.current_tiers[symbol] = "无"
187 | self.logger.info(
188 | f"首次检测到仓位:{symbol}, 仓位数量: {position_amt}, 开仓价格: {entry_price}, 方向: {side}")
189 | self.send_feishu_notification(
190 | f"首次检测到仓位:{symbol}, 仓位数量: {position_amt}, 开仓价格: {entry_price}, 方向: {side}")
191 |
192 | # 检测是否有加仓
193 | elif position_amt > self.detected_positions[symbol]:
194 | self.highest_profits[symbol] = 0 # 重置最高盈利
195 | self.current_tiers[symbol] = "无" # 重置档位
196 | self.detected_positions[symbol] = position_amt # 更新持仓数量
197 | self.logger.info(f"{symbol} 检测到加仓,重置最高盈利和档位。")
198 | continue # 跳出当前循环,进入下一个仓位检测
199 |
200 | if side == 'long':
201 | profit_pct = (current_price - entry_price) / entry_price * 100
202 | elif side == 'short':
203 | profit_pct = (entry_price - current_price) / entry_price * 100
204 | else:
205 | continue
206 |
207 | highest_profit = self.highest_profits.get(symbol, 0)
208 | if profit_pct > highest_profit:
209 | highest_profit = profit_pct
210 | self.highest_profits[symbol] = highest_profit
211 |
212 | current_tier = self.current_tiers.get(symbol, "无")
213 | if highest_profit >= self.second_trail_profit_threshold:
214 | current_tier = "第二档移动止盈"
215 | elif highest_profit >= self.first_trail_profit_threshold:
216 | current_tier = "第一档移动止盈"
217 | elif highest_profit >= self.low_trail_profit_threshold:
218 | current_tier = "低档保护止盈"
219 | else:
220 | current_tier = "无"
221 |
222 | self.current_tiers[symbol] = current_tier
223 |
224 | self.logger.info(
225 | f"监控 {symbol},仓位: {position_amt},方向: {side},开仓价格: {entry_price},当前价格: {current_price},浮动盈亏: {profit_pct:.2f}%,最高盈亏: {highest_profit:.2f}%,当前档位: {current_tier}")
226 |
227 | if current_tier == "低档保护止盈":
228 | self.logger.info(f"回撤到{self.low_trail_stop_loss_pct:.2f}% 止盈")
229 | if profit_pct <= self.low_trail_stop_loss_pct:
230 | self.logger.info(f"{symbol} 触发低档保护止盈,当前盈亏回撤到: {profit_pct:.2f}%,执行平仓")
231 | self.close_position(symbol, abs(position_amt), 'sell' if side == 'long' else 'buy', td_mode, algo_id)
232 | continue
233 |
234 | elif current_tier == "第一档移动止盈":
235 | trail_stop_loss = highest_profit * (1 - self.trail_stop_loss_pct)
236 | self.logger.info(f"回撤到 {trail_stop_loss:.2f}% 止盈")
237 | if profit_pct <= trail_stop_loss:
238 | self.logger.info(
239 | f"{symbol} 达到利润回撤阈值,当前档位:第一档移动止盈,最高盈亏: {highest_profit:.2f}%,当前盈亏: {profit_pct:.2f}%,执行平仓")
240 | self.close_position(symbol, abs(position_amt), 'sell' if side == 'long' else 'buy', td_mode, algo_id)
241 | continue
242 |
243 | elif current_tier == "第二档移动止盈":
244 | trail_stop_loss = highest_profit * (1 - self.higher_trail_stop_loss_pct)
245 | self.logger.info(f"回撤到 {trail_stop_loss:.2f}% 止盈")
246 | if profit_pct <= trail_stop_loss:
247 | self.logger.info(
248 | f"{symbol} 达到利润回撤阈值,当前档位:第二档移动止盈,最高盈亏: {highest_profit:.2f}%,当前盈亏: {profit_pct:.2f}%,执行平仓")
249 | self.close_position(symbol, abs(position_amt), 'sell' if side == 'long' else 'buy', td_mode, algo_id)
250 | continue
251 |
252 | if profit_pct <= -self.stop_loss_pct:
253 | self.logger.info(f"{symbol} 触发止损,当前盈亏: {profit_pct:.2f}%,执行平仓")
254 | self.close_position(symbol, abs(position_amt), 'sell' if side == 'long' else 'buy', td_mode, algo_id)
255 |
256 |
257 | if __name__ == '__main__':
258 | with open('config.json', 'r') as f:
259 | config_data = json.load(f)
260 |
261 | # 选择交易平台,假设这里选择 OKX
262 | platform_config = config_data['okx']
263 | feishu_webhook_url = config_data['feishu_webhook']
264 | monitor_interval = config_data.get("monitor_interval", 4) # 默认值为4秒
265 |
266 | bot = MultiAssetTradingBot(platform_config, feishu_webhook=feishu_webhook_url, monitor_interval=monitor_interval)
267 | bot.schedule_task()
268 |
--------------------------------------------------------------------------------
/config.json:
--------------------------------------------------------------------------------
1 | {
2 | "binance": {
3 | "apiKey": "",
4 | "secret": "",
5 | "leverage": 1.0,
6 | "stop_loss_pct": 2,
7 | "low_trail_stop_loss_pct": 0.3,
8 | "trail_stop_loss_pct": 0.2,
9 | "higher_trail_stop_loss_pct": 0.25,
10 | "low_trail_profit_threshold": 0.4,
11 | "first_trail_profit_threshold": 1.0,
12 | "second_trail_profit_threshold": 3.0,
13 | "blacklist": ["ETH/USDT:USDT","ETH/USDT:USDT"]
14 | },
15 | "okx": {
16 | "apiKey": "",
17 | "secret": "",
18 | "password": "",
19 | "leverage": 1.0,
20 | "stop_loss_pct": 2,
21 | "low_trail_stop_loss_pct": 0.2,
22 | "trail_stop_loss_pct": 0.2,
23 | "higher_trail_stop_loss_pct": 0.25,
24 | "low_trail_profit_threshold": 0.3,
25 | "first_trail_profit_threshold": 1.0,
26 | "second_trail_profit_threshold": 3.0,
27 | "blacklist": ["ETH/USDT:USDT","BTC/USDT:USDT"],
28 | "all_stop_loss_pct": 0.2,
29 | "all_low_trail_stop_loss_pct": 0.1,
30 | "all_trail_stop_loss_pct": 0.2,
31 | "all_higher_trail_stop_loss_pct": 0.25,
32 | "all_low_trail_profit_threshold": 0.1,
33 | "all_first_trail_profit_threshold": 1.0,
34 | "all_second_trail_profit_threshold": 3.0
35 | },
36 | "bitget": {
37 | "apiKey": "",
38 | "secret": "",
39 | "password": "",
40 | "leverage": 1.0,
41 | "stop_loss_pct": 2,
42 | "low_trail_stop_loss_pct": 0.2,
43 | "trail_stop_loss_pct": 0.2,
44 | "higher_trail_stop_loss_pct": 0.25,
45 | "low_trail_profit_threshold": 0.3,
46 | "first_trail_profit_threshold": 1.0,
47 | "second_trail_profit_threshold": 3.0,
48 | "blacklist": ["ETH-USDT-SWAP"]
49 | },
50 | "feishu_webhook": "https://open.feishu.cn/open-apis/bot/v2/hook/655821a2",
51 | "monitor_interval": 4
52 | }
53 |
--------------------------------------------------------------------------------
/config.template.json:
--------------------------------------------------------------------------------
1 | {
2 | "binance": {
3 | "apiKey": "",
4 | "secret": "",
5 | "leverage": 1.0,
6 | "stop_loss_pct": 2,
7 | "low_trail_stop_loss_pct": 0.3,
8 | "trail_stop_loss_pct": 0.2,
9 | "higher_trail_stop_loss_pct": 0.25,
10 | "low_trail_profit_threshold": 0.4,
11 | "first_trail_profit_threshold": 1.0,
12 | "second_trail_profit_threshold": 3.0,
13 | "blacklist": ["ETH/USDT:USDT","ETH/USDT:USDT"]
14 | },
15 | "okx": {
16 | "apiKey": "",
17 | "secret": "",
18 | "password": "",
19 | "leverage": 1.0,
20 | "stop_loss_pct": 2,
21 | "low_trail_stop_loss_pct": 0.2,
22 | "trail_stop_loss_pct": 0.2,
23 | "higher_trail_stop_loss_pct": 0.25,
24 | "low_trail_profit_threshold": 0.3,
25 | "first_trail_profit_threshold": 1.0,
26 | "second_trail_profit_threshold": 3.0,
27 | "blacklist": ["ETH/USDT:USDT","BTC/USDT:USDT"],
28 | "all_stop_loss_pct": 0.2,
29 | "all_low_trail_stop_loss_pct": 0.1,
30 | "all_trail_stop_loss_pct": 0.2,
31 | "all_higher_trail_stop_loss_pct": 0.25,
32 | "all_low_trail_profit_threshold": 0.1,
33 | "all_first_trail_profit_threshold": 1.0,
34 | "all_second_trail_profit_threshold": 3.0
35 | },
36 | "bitget": {
37 | "apiKey": "",
38 | "secret": "",
39 | "password": "",
40 | "leverage": 1.0,
41 | "stop_loss_pct": 2,
42 | "low_trail_stop_loss_pct": 0.2,
43 | "trail_stop_loss_pct": 0.2,
44 | "higher_trail_stop_loss_pct": 0.25,
45 | "low_trail_profit_threshold": 0.3,
46 | "first_trail_profit_threshold": 1.0,
47 | "second_trail_profit_threshold": 3.0,
48 | "blacklist": ["ETH-USDT-SWAP"]
49 | },
50 | "feishu_webhook": "https://open.feishu.cn/open-apis/bot/v2/hook/655821a2",
51 | "monitor_interval": 4
52 | }
--------------------------------------------------------------------------------
/okx/Account_api.py:
--------------------------------------------------------------------------------
1 | from .client import Client
2 | from .consts import *
3 |
4 |
5 | class AccountAPI(Client):
6 |
7 | def __init__(self, api_key, api_secret_key, passphrase, use_server_time=False, flag='1'):
8 | Client.__init__(self, api_key, api_secret_key, passphrase, use_server_time, flag)
9 |
10 | # Get Positions
11 | def get_position_risk(self, instType=''):
12 | params = {}
13 | if instType:
14 | params['instType'] = instType
15 | return self._request_with_params(GET, POSITION_RISK, params)
16 |
17 | # Get Balance
18 | def get_account(self, ccy=''):
19 | params = {}
20 | if ccy:
21 | params['ccy'] = ccy
22 | return self._request_with_params(GET, ACCOUNT_INFO, params)
23 |
24 | # Get Positions
25 | def get_positions(self, instType='', instId=''):
26 | params = {'instType': instType, 'instId': instId}
27 | return self._request_with_params(GET, POSITION_INFO, params)
28 |
29 | # Get Bills Details (recent 7 days)
30 | def get_bills_detail(self, instType='', instId='', ccy='', mgnMode='', ctType='', type='', subType='', after='', before='',begin='',end='',
31 | limit=''):
32 | params = {'instType': instType, 'ccy': ccy, 'mgnMode': mgnMode, 'ctType': ctType, 'type': type,
33 | 'subType': subType, 'after': after, 'before': before, 'limit': limit, 'instId':instId, 'begin':begin, 'end':end}
34 | return self._request_with_params(GET, BILLS_DETAIL, params)
35 |
36 | # Get Bills Details (recent 3 months)
37 | def get_bills_details(self, instType='', instId = '', ccy='', mgnMode='', ctType='', type='', subType='', after='', before='',begin='',end='',
38 | limit=''):
39 | params = {'instType': instType, 'ccy': ccy, 'mgnMode': mgnMode, 'ctType': ctType, 'type': type,
40 | 'subType': subType, 'after': after, 'before': before, 'limit': limit, 'instId':instId, 'begin':begin, 'end':end}
41 | return self._request_with_params(GET, BILLS_ARCHIVE, params)
42 |
43 | # Get Account Configuration
44 | def get_account_config(self):
45 | return self._request_without_params(GET, ACCOUNT_CONFIG)
46 |
47 | # Get Account Configuration
48 | def get_position_mode(self, posMode):
49 | params = {'posMode': posMode}
50 | return self._request_with_params(POST, POSITION_MODE, params)
51 |
52 | # Get Account Configuration
53 | def set_leverage(self, lever, mgnMode, instId='', ccy='', posSide=''):
54 | params = {'lever': lever, 'mgnMode': mgnMode, 'instId': instId, 'ccy': ccy, 'posSide': posSide}
55 | return self._request_with_params(POST, SET_LEVERAGE, params)
56 |
57 | # Get Maximum Tradable Size For Instrument
58 | def get_maximum_trade_size(self, instId, tdMode, ccy='', px='', leverage='',unSpotOffset=''):
59 | params = {'instId': instId, 'tdMode': tdMode, 'ccy': ccy, 'px': px, 'leverage':leverage,'unSpotOffset':unSpotOffset}
60 | return self._request_with_params(GET, MAX_TRADE_SIZE, params)
61 |
62 | # Get Maximum Available Tradable Amount
63 | def get_max_avail_size(self, instId, tdMode, ccy='', reduceOnly='', unSpotOffset='',quickMgnType='',px=''):
64 | params = {'instId': instId, 'tdMode': tdMode, 'ccy': ccy, 'reduceOnly': reduceOnly,
65 | 'unSpotOffset':unSpotOffset,'quickMgnType':quickMgnType,'px': px}
66 | return self._request_with_params(GET, MAX_AVAIL_SIZE, params)
67 |
68 | # Increase / Decrease margin
69 | def Adjustment_margin(self, instId, posSide, type, amt,loanTrans=''):
70 | params = {'instId': instId, 'posSide': posSide, 'type': type, 'amt': amt,'loanTrans':loanTrans}
71 | return self._request_with_params(POST, ADJUSTMENT_MARGIN, params)
72 |
73 | # Get Leverage
74 | def get_leverage(self, instId, mgnMode, ccy):
75 | params = {'instId': instId, 'mgnMode': mgnMode, 'ccy':ccy}
76 | return self._request_with_params(GET, GET_LEVERAGE, params)
77 |
78 | # Get the maximum loan of isolated MARGIN
79 | def get_max_load(self, instId, mgnMode, mgnCcy):
80 | params = {'instId': instId, 'mgnMode': mgnMode, 'mgnCcy': mgnCcy}
81 | return self._request_with_params(GET, MAX_LOAN, params)
82 |
83 | # Get Fee Rates
84 | def get_fee_rates(self, instType = '', instId='', uly='', category='', instFamily='',ruleType = ''):
85 | params = {'instType': instType, 'instId': instId, 'uly': uly, 'category': category,'instFamily':instFamily,'ruleType':ruleType}
86 | return self._request_with_params(GET, FEE_RATES, params)
87 |
88 | # Get interest-accrued
89 | def get_interest_accrued(self, instId='', ccy='', mgnMode='', after='', before='', limit='', type=''):
90 | params = {'instId': instId, 'ccy': ccy, 'mgnMode': mgnMode, 'after': after, 'before': before, 'limit': limit, 'type':type}
91 | return self._request_with_params(GET, INTEREST_ACCRUED, params)
92 |
93 | # Get interest-accrued
94 | def get_interest_rate(self, ccy=''):
95 | params = {'ccy': ccy}
96 | return self._request_with_params(GET, INTEREST_RATE, params)
97 |
98 | # Set Greeks (PA/BS)
99 | def set_greeks(self, greeksType):
100 | params = {'greeksType': greeksType}
101 | return self._request_with_params(POST, SET_GREEKS, params)
102 |
103 | # Set Isolated Mode
104 | def set_isolated_mode(self, isoMode,type):
105 | params = {'isoMode': isoMode, 'type':type}
106 | return self._request_with_params(POST, ISOLATED_MODE, params)
107 |
108 | # Get Maximum Withdrawals
109 | def get_max_withdrawal(self, ccy=''):
110 | params = {'ccy': ccy}
111 | return self._request_with_params(GET, MAX_WITHDRAWAL, params)
112 |
113 | # Get account risk state
114 | def get_account_risk(self):
115 | return self._request_without_params(GET, ACCOUNT_RISK)
116 |
117 | # Get borrow repay
118 | def borrow_repay(self, ccy='', side='', amt='', ordId = ''):
119 | params = {'ccy': ccy, 'side': side, 'amt': amt, 'ordId':ordId}
120 | return self._request_with_params(POST, BORROW_REPAY, params)
121 |
122 | # Get borrow repay history
123 | def get_borrow_repay_history(self, ccy='', after='', before='', limit=''):
124 | params = {'ccy': ccy, 'after': after, 'before': before, 'limit':limit}
125 | return self._request_with_params(GET, BORROW_REPAY_HISTORY, params)
126 |
127 | # Get Obtain borrowing rate and limit
128 | def get_interest_limits(self, type='',ccy=''):
129 | params = {'type': type, 'ccy': ccy}
130 | return self._request_with_params(GET, INTEREST_LIMITS, params)
131 |
132 | # Get Simulated Margin
133 | def get_simulated_margin(self, instType ='',inclRealPos='',spotOffsetType='',simPos=[]):
134 | params = {'instType': instType, 'inclRealPos': inclRealPos,'spotOffsetType':spotOffsetType,'simPos': simPos}
135 | return self._request_with_params(POST, SIMULATED_MARGIN, params)
136 |
137 | # Get Greeks
138 | def get_greeks(self, ccy=''):
139 | params = {'ccy': ccy,}
140 | return self._request_with_params(GET, GREEKS, params)
141 |
142 | def get_positions_history(self, instType='', instId = '', mgnMode = '', type = '', after = '', before = '', limit = '', posId = ''):
143 | params = {'instType': instType, 'instId':instId, 'mgnMode':mgnMode, 'type':type, 'after':after, 'before':before, 'limit':limit, 'posId':posId}
144 | return self._request_with_params(GET, POSITIONS_HISTORY, params)
145 |
146 | def position_tiers(self, instType='',uly=''):
147 | params = {'instType': instType, 'uly': uly}
148 | return self._request_with_params(GET, POSITION_TIRES, params)
149 |
150 | def activate_option(self):
151 | params = {}
152 | return self._request_with_params(POST, ACTIVATE_OPTION, params)
153 |
154 | def set_auto_loan(self,autoLoan = ''):
155 | params = {'autoLoan':autoLoan}
156 | return self._request_with_params(POST, SET_AUTO_LOAN, params)
157 |
158 | def quick_margin_borrow_repay(self, instId='', ccy='', side='', amt=''):
159 | params = {'instId':instId, 'ccy':ccy, 'side':side, 'amt':amt}
160 | return self._request_with_params(POST, QUICK_MARGIN_BRROW_REPAY, params)
161 |
162 | def quick_margin_borrow_repay_history(self, instId='', ccy='', side='', after='', before='', begin='', end='', limit=''):
163 | params = {'instId': instId, 'ccy': ccy, 'side': side, 'after': after, 'before': before, 'begin': begin, 'end': end, 'limit': limit}
164 | return self._request_with_params(GET, QUICK_MARGIN_BORROW_REPAY_HISTORY, params)
165 |
166 | # GET /api/v5/account/vip-interest-accrued
167 | def vip_interest_accrued(self, ccy = '', ordId = '', after = '', before = '', limit = ''):
168 | params = {'ccy': ccy, 'ordId': ordId, 'after': after, 'before': before, 'limit': limit}
169 | return self._request_with_params(GET, VIP_INTEREST_ACCRUED, params)
170 |
171 | # GET /api/v5/account/vip-interest-deducted
172 | def vip_interest_deducted(self, ccy = '', ordId = '', after = '', before = '', limit = ''):
173 | params = {'ccy': ccy, 'ordId': ordId, 'after': after, 'before': before, 'limit': limit}
174 | return self._request_with_params(GET, VIP_INTEREST_DEDUCTED, params)
175 |
176 | # GET /api/v5/account/vip-loan-order-list
177 | def vip_loan_order_list(self, ordId = '', state = '', ccy = '', after = '', before = '', limit = ''):
178 | params = {'ordId': ordId, 'state': state, 'ccy': ccy, 'after': after, 'before': before, 'limit': limit}
179 | return self._request_with_params(GET, VIP_LOAN_ORDER_LIST, params)
180 |
181 | # GET /api/v5/account/vip-loan-order-detail
182 | def vip_loan_order_detail(self, ccy = '', ordId = '', after = '', before = '', limit = ''):
183 | params = {'ccy': ccy, 'ordId': ordId, 'after': after, 'before': before, 'limit': limit}
184 | return self._request_with_params(GET, VIP_LOAN_ORDER_DETAIL, params)
185 |
186 | # POST /api/v5/account/subaccount/set-loan-allocation
187 | def set_loan_allocation(self, enable, alloc:[]):
188 | params = {'enable': enable, 'alloc': alloc}
189 | return self._request_with_params(POST, SET_LOAN_ALLOCATION, params)
190 |
191 | # GET /api/v5/account/subaccount/interest-limits
192 | def interest_limits(self, subAcct = '', ccy = ''):
193 | params = {'subAcct': subAcct, 'ccy': ccy}
194 | return self._request_with_params(GET, INTEREST_LIMITS, params)
195 |
196 | # POST /api/v5/account/set-riskOffset-type
197 | def set_riskOffset_type(self, type = ''):
198 | params = {'type':type}
199 | return self._request_with_params(POST, SET_RISKOFFSET_TYPE, params)
200 |
201 | # POST /api/v5/account/mmp-reset
202 | def mmp_reset(self,instType,instFamily):
203 | params = {'instType': instType,'instFamily':instFamily}
204 | return self._request_with_params(POST, MMP_RESET, params)
205 |
206 | # POST /api/v5/account/mmp-config
207 | def mmp_config(self,instFamily,timeInterval,frozenInterval,qtyLimit):
208 | params = {'instFamily': instFamily,'timeInterval': timeInterval,'frozenInterval': frozenInterval,'qtyLimit': qtyLimit,}
209 | return self._request_with_params(POST, MMP_CONFIG, params)
210 |
211 | # GET /api/v5/account/mmp-config
212 | def mmp(self,instFamily):
213 | params = {'instFamily': instFamily}
214 | return self._request_with_params(GET, MMP, params)
215 |
216 | # POST /api/v5/account/set-account-level
217 | def set_account_level(self,acctLv):
218 | params = {'acctLv': acctLv}
219 | return self._request_with_params(POST, SET_ACCOUNT_LEVEL, params)
220 |
221 |
222 | def position_builder(self,inclRealPosAndEq='',spotOffsetType='',simPos='',simAsset='',
223 | greeksType='',):
224 | params = {'acctLv': acctLv, 'spotOffsetType': spotOffsetType, 'simPos': simPos, 'simAsset': simAsset,
225 | 'greeksType': greeksType, }
226 | return self._request_with_params(POST, POSITION_BUILDER, params)
227 |
228 |
229 | # POST /api/v5/account/set-riskOffset-amt
230 | def set_riskOffset_amt(self,ccy = '', clSpotInUseAmt = ''):
231 | params = {'ccy': ccy, 'clSpotInUseAmt': clSpotInUseAmt}
232 | return self._request_with_params(POST, SET_RISKOFFSET_AMT, params)
233 |
234 | # GET /api/v5/account/fixed-loan/borrowing-limit
235 | def get_fixed_loan_borrowing_limit(self):
236 | params = {}
237 | return self._request_with_params(GET, GET_FIXED_LOAN_BORROWING_LIMIT, params)
238 |
239 | # GET /api/v5/account/fixed-loan/borrowing-quote
240 | def get_fixed_loan_borrowing_quote(self,type = '', ccy = '', amt = '', maxRate = '', term = '', ordId = ''):
241 | params = {'type':type, 'ccy':ccy, 'amt':amt, 'maxRate':maxRate, 'maxRate':maxRate, 'term':term, 'ordId':ordId}
242 | return self._request_with_params(GET, GET_FIXED_LOAN_BORROWING_QUOTE, params)
243 |
244 |
245 | # POST /api/v5/account/fixed-loan/borrowing-order
246 | def fixed_loan_borrowing_order(self,ccy = '', amt = '', maxRate = '', term = '', reborrow = '', reborrowRate = ''):
247 | params = {'ccy':ccy, 'amt':amt, 'maxRate':maxRate, 'term':term, 'reborrow':reborrow, 'reborrowRate':reborrowRate}
248 | return self._request_with_params(POST, FIXED_LOAN_BORROWING_ORDER, params)
249 |
250 |
251 | # POST /api/v5/account/fixed-loan/amend-borrowing-order
252 | def fixed_loan_amend_borrowing_order(self,ordId = '', reborrow = '', renewMaxRate = ''):
253 | params = {'ordId':ordId, 'reborrow':reborrow, 'renewMaxRate':renewMaxRate}
254 | return self._request_with_params(POST, FIXED_LOAN_AMEND_BORROWING_ORDER, params)
255 |
256 |
257 | # POST /api/v5/account/fixed-loan/manual-reborrow
258 | def fixed_loan_manual_reborrow(self,ordId = '', maxRate = ''):
259 | params = {'ordId':ordId, 'maxRate':maxRate}
260 | return self._request_with_params(POST, FIXED_LOAN_MANUAL_BORROWING, params)
261 |
262 | # POST /api/v5/account/fixed-loan/repay-borrowing-order
263 | def fixed_loan_repay_borrowing_order(self,ordId = ''):
264 | params = {'ordId':ordId}
265 | return self._request_with_params(POST, FIXED_LOAN_REPAY_BORROWING_ORDER, params)
266 |
267 |
268 | # GET /api/v5/account/fixed-loan/borrowing-orders-list
269 | def get_fixed_loan_borrowing_orders_list(self,ordId = '', ccy = '', state = '', after = '', before = '',limit = '',term = ''):
270 | params = {'ordId':ordId, 'ccy':ccy, 'state':state, 'after':after, 'before':before, 'limit':limit, 'term':term}
271 | return self._request_with_params(GET, GET_FIXED_LOAN_BORROWING_ORDERS_LIST, params)
272 |
273 | # GET /api/v5/account/instruments
274 | def get_account_instruments(self,instType = '', uly = '', instFamily = '', instId = ''):
275 | params = {'instType':instType, 'uly':uly, 'instFamily':instFamily, 'instId':instId}
276 | return self._request_with_params(GET, GET_ACCOUNT_INSTRUMENTS, params)
277 |
278 |
279 | # POST /api/v5/account/spot-manual-borrow-repay
280 | def spot_manual_borrow_repay(self,ccy = '', side = '', amt = ''):
281 | params = {'ccy':ccy, 'side':side, 'amt':amt}
282 | return self._request_with_params(POST, SPOT_MANUAL_BORROW_REPAY, params)
283 |
284 |
285 | # POST /api/v5/account/set-auto-repay
286 | def set_auto_repay(self,autoRepay = ''):
287 | params = {'autoRepay':autoRepay}
288 | return self._request_with_params(POST, SET_AUTO_REPAY, params)
289 |
290 |
291 | # GET /api/v5/account/spot-borrow-repay-history
292 | def get_spot_borrow_repay_history(self,ccy = '', type = '', after = '', before = '', limit = ''):
293 | params = {'ccy':ccy, 'type':type, 'after':after, 'before':before, 'limit':limit}
294 | return self._request_with_params(GET, GET_SPOT_BORROW_REPAY_HISTORY, params)
295 |
296 | # POST /api/v5/account/fixed-loan/convert-to-market-loan
297 | def convert_to_market_loan(self,ordId = ''):
298 | params = {'ordId':ordId}
299 | return self._request_with_params(POST, CONVERT_TO_MARKET_LOAN, params)
300 |
301 | # POST /api/v5/account/fixed-loan/reduce-liabilities
302 | def reduce_liabilities(self,ordId = '',pendingRepay = ''):
303 | params = {'ordId':ordId,'pendingRepay':pendingRepay}
304 | return self._request_with_params(POST, REDYCE_LIABILITIES, params)
305 |
306 | # GET /api/v5/trade/account-rate-limit
307 | def account_rate_limit(self,):
308 | params = {}
309 | return self._request_with_params(GET, ACC_RATE_LIMIT, params)
310 |
311 | # POST /api/v5/account/bills-history-archive
312 | def bills_history_archive(self,year = '', quarter = ''):
313 | params = {'year':year, 'quarter':quarter}
314 | return self._request_with_params(POST, BILLS_HISTORY_ARCHIVE, params)
315 |
316 | # GET /api/v5/account/bills-history-archive
317 | def get_bills_history_archive(self, year = '', quarter = ''):
318 | params = {'year':year, 'quarter':quarter}
319 | return self._request_with_params(GET, GET_BILLS_HISTORY_ARCHIVE, params)
320 |
321 |
--------------------------------------------------------------------------------
/okx/Affiliate_api.py:
--------------------------------------------------------------------------------
1 | from .client import Client
2 | from .consts import *
3 |
4 |
5 | class AffiliateAPI(Client):
6 |
7 | def __init__(self, api_key, api_secret_key, passphrase, use_server_time=False, flag='1'):
8 | Client.__init__(self, api_key, api_secret_key, passphrase, use_server_time, flag)
--------------------------------------------------------------------------------
/okx/Broker_api.py:
--------------------------------------------------------------------------------
1 | from .client import Client
2 | from .consts import *
3 |
4 |
5 | class BrokerAPI(Client):
6 | def __init__(self, api_key, api_secret_key, passphrase, use_server_time=False, flag='1'):
7 | Client.__init__(self, api_key, api_secret_key, passphrase, use_server_time, flag)
8 |
9 | def broker_info(self):
10 | params = {}
11 | return self._request_with_params(GET, BROKER_INFO, params)
12 |
13 | def create_subaccount(self, subAcct='', label='', clientIP='',mainAcct=''):
14 | params = {'subAcct': subAcct, 'label': label, 'clientIP':clientIP,'mainAcct':mainAcct}
15 | return self._request_with_params(POST, CREATE_SUBACCOUNT, params)
16 |
17 | def delete_subaccount(self, subAcct=''):
18 | params = {'subAcct': subAcct}
19 | return self._request_with_params(POST, DELETE_SUBACCOUNT, params)
20 |
21 | def subaccount_info(self, subAcct='', page='', limit=''):
22 | params = {'subAcct': subAcct, 'page': page, 'limit': limit}
23 | return self._request_with_params(GET, SUBACCOUNT_INFO, params)
24 |
25 | def set_subaccount_level(self, subAcct='', acctLv=''):
26 | params = {'subAcct': subAcct, 'acctLv': acctLv}
27 | return self._request_with_params(POST, SET_SUBACCOUNT_LEVEL, params)
28 |
29 | def set_subaccount_fee_rate(self, subAcct='', instType='', chgType='', chgTaker='',
30 | chgMaker='', effDate='', mgnType='',quoteCcyType = ''):
31 | params = {'subAcct': subAcct, 'instType': instType, 'chgType': chgType, 'chgTaker': chgTaker,
32 | 'chgMaker':chgMaker, 'effDate':effDate, 'mgnType':mgnType, 'quoteCcyType':quoteCcyType}
33 | return self._request_with_params(POST, SET_SUBACCOUNT_FEE_REAT, params)
34 |
35 | def subaccount_deposit_address(self, subAcct='', ccy='', chain='', addrType='', to=''):
36 | params = {'subAcct': subAcct, 'ccy': ccy, 'chain': chain, 'addrType': addrType, 'to': to}
37 | return self._request_with_params(POST, SUBACCOUNT_DEPOSIT_ADDRESS, params)
38 |
39 | def subaccount_deposit_history(self, subAcct = '', ccy = '', txId = '', state = '', after = '', before = '', limit = ''):
40 | params = {'subAcct': subAcct, 'ccy': ccy, 'txId': txId, 'state': state, 'after': after, 'before': before, 'limit':limit}
41 | return self._request_with_params(GET, SUBACCOUNT_DEPOSIT_HISTORY, params)
42 |
43 | def rebate_daily(self, subAcct = '', begin = '', end = '', page = '', limit = '',
44 | beginTime = '', endTime = ''):
45 | params = {'subAcct': subAcct, 'begin': begin, 'end': end, 'page': page, 'limit': limit,
46 | 'beginTime':beginTime, 'endTime': endTime}
47 | return self._request_with_params(GET, REBATE_DAILY, params)
48 |
49 | def nd_create_apikey(self, subAcct = '', label = '', passphrase = '', ip = '', perm = ''):
50 | params = {'subAcct': subAcct, 'label': label, 'passphrase': passphrase, 'ip': ip, 'perm': perm}
51 | return self._request_with_params(POST, ND_CREAET_APIKEY, params)
52 |
53 | def nd_select_apikey(self, subAcct = '', apiKey = ''):
54 | params = {'subAcct': subAcct, 'apiKey': apiKey}
55 | return self._request_with_params(GET, ND_SELECT_APIKEY, params)
56 |
57 | def nd_modify_apikey(self, subAcct = '', apiKey = '', label = '', perm = '', ip = ''):
58 | params = {'subAcct': subAcct, 'apiKey': apiKey, 'label': label, 'perm': perm, 'ip': ip}
59 | return self._request_with_params(POST, ND_MODIFY_APIKEY, params)
60 |
61 | def nd_delete_apikey(self, subAcct = '', apiKey = ''):
62 | params = {'subAcct': subAcct, 'apiKey': apiKey}
63 | return self._request_with_params(POST, ND_DELETE_APIKEY, params)
64 |
65 | def rebate_per_orders(self, begin = '', end = ''):
66 | params = {'begin': begin, 'end': end}
67 | return self._request_with_params(POST, REBATE_PER_ORDERS, params)
68 |
69 | def get_rebate_per_orders(self, type = '', begin = '', end = ''):
70 | params = {'type': type, 'begin': begin, 'end': end}
71 | return self._request_with_params(GET, GET_REBATE_PER_ORDERS, params)
72 |
73 | def modify_subaccount_deposit_address(self, subAcct = '', ccy = '', chain = '', addr = '', to = ''):
74 | params = {'subAcct': subAcct, 'ccy': ccy, 'chain': chain, 'addr': addr, 'to': to}
75 | return self._request_with_params(POST, MODIFY_SUBACCOUNT_DEPOSIT_ADDRESS, params)
76 |
77 | def nd_subaccount_withdrawal_history(self, subAcct = '', ccy = '', wdId = '', clientId = '', txId = '', type = '', state = '', after = '', before = '', limit = ''):
78 | params = {'subAcct': subAcct, 'ccy': ccy, 'wdId': wdId, 'clientId': clientId, 'txId': txId, 'type': type, 'state': state, 'after': after, 'before': before, 'limit': limit}
79 | return self._request_with_params(GET, ND_SUBACCOUNT_WITHDRAWAL_HISTORY, params)
80 |
81 | # POST /api/v5/broker/nd/set-subaccount-assets
82 | def set_subaccount_assets(self, subAcct = '', ccy = ''):
83 | params = {'subAcct': subAcct, 'ccy': ccy,}
84 | return self._request_with_params(POST, SET_SUBACCOUNT_ASSETS, params)
85 |
86 | # POST /api/v5/broker/nd/set-subaccount-assets
87 | def report_subaccount_ip(self, subAcct, clientIP):
88 | params = {'subAcct': subAcct, 'clientIP': clientIP,}
89 | return self._request_with_params(POST, R_SACCOUNT_IP, params)
90 |
91 |
92 | def if_rebate(self, apiKey='',uid='',subAcct='',):
93 | params = {'subAcct': subAcct, 'apiKey': apiKey,'uid': uid,}
94 | return self._request_with_params(GET, IF_REBATE, params)
95 |
96 |
--------------------------------------------------------------------------------
/okx/Convert_api.py:
--------------------------------------------------------------------------------
1 | from .client import Client
2 | from .consts import *
3 |
4 |
5 | class ConvertAPI(Client):
6 | def __init__(self, api_key, api_secret_key, passphrase, use_server_time=False, flag='1'):
7 | Client.__init__(self, api_key, api_secret_key, passphrase, use_server_time, flag)
8 |
9 | def get_currencies(self):
10 | params = {}
11 | return self._request_with_params(GET, GET_CURRENCIES, params)
12 |
13 | def get_currency_pair(self, fromCcy='', toCcy=''):
14 | params = {"fromCcy": fromCcy, 'toCcy': toCcy}
15 | return self._request_with_params(GET, GET_CURRENCY_PAIR, params)
16 |
17 | def estimate_quote(self, baseCcy = '', quoteCcy = '', side = '', rfqSz = '', rfqSzCcy = '', clQReqId = '',tag=''):
18 | params = {'baseCcy': baseCcy, 'quoteCcy': quoteCcy, 'side':side, 'rfqSz':rfqSz, 'rfqSzCcy':rfqSzCcy, 'clQReqId':clQReqId,'tag':tag}
19 | return self._request_with_params(POST, ESTIMATE_QUOTE, params)
20 |
21 | def convert_trade(self, quoteId = '', baseCcy = '', quoteCcy = '', side = '', sz = '', szCcy = '', clTReqId = '',tag=''):
22 | params = {'quoteId': quoteId, 'baseCcy': baseCcy, 'quoteCcy':quoteCcy, 'side':side, 'sz':sz, 'szCcy':szCcy, 'clTReqId':clTReqId,'tag':tag}
23 | return self._request_with_params(POST, CONVERT_TRADE, params)
24 |
25 | def get_convert_history(self, after = '', before = '', limit = '',tag=''):
26 | params = {'after': after, 'before': before, 'limit':limit,'tag':tag}
27 | return self._request_with_params(GET, CONVERT_HISTORY, params)
28 |
--------------------------------------------------------------------------------
/okx/Copytrading_api.py:
--------------------------------------------------------------------------------
1 | from .client import Client
2 | from .consts import *
3 |
4 |
5 | class CopytradingAPI(Client):
6 |
7 | def __init__(self, api_key, api_secret_key, passphrase, use_server_time=False, flag='1'):
8 | Client.__init__(self, api_key, api_secret_key, passphrase, use_server_time, flag)
9 |
10 | # GET /api/v5/copytrading/current-subpositions
11 | def current_subpositions(self, instId='',after='', before='', limit='',uniqueCode='',subPosType=''):
12 | params = {'instId': instId, 'after': after, 'before': before, 'limit': limit,'uniqueCode': uniqueCode,'subPosType': subPosType, }
13 | return self._request_with_params(GET, CURRENT_SUBPOSITIONS, params)
14 |
15 | # GET /api/v5/copytrading/subpositions-history
16 | def subpositions_history(self, instId='', after='', before='', limit='',subPosType=''):
17 | params = {'instId': instId, 'after': after, 'before': before, 'limit': limit,'subPosType':subPosType}
18 | return self._request_with_params(GET, SUBPOSITIONS_HISTORY, params)
19 |
20 | # POST /api/v5/copytrading/algo-order
21 | def copytrading_algo_order(self, subPosId='', tpTriggerPx='', slTriggerPx='', tpTriggerPxType='',
22 | slTriggerPxType='', tag='',subPosType='',tpOrdPx='',slOrdPx=''):
23 | params = {'subPosId': subPosId, 'tpTriggerPx': tpTriggerPx,'tpOrdPx': tpOrdPx,'slOrdPx': slOrdPx,
24 | 'slTriggerPx': slTriggerPx, 'tpTriggerPxType': tpTriggerPxType,
25 | 'slTriggerPxType': slTriggerPxType,'tag':tag,'subPosType':subPosType}
26 | return self._request_with_params(POST, COPYTRADING_ALGO_ORDER, params)
27 |
28 | # POST /api/v5/copytrading/close-subposition
29 | def copytrading_close_subposition(self, subPosId='',tag='',subPosType='',ordType='',px=''):
30 | params = {'subPosId': subPosId,'tag':tag,"subPosType":subPosType,"ordType":ordType,'px':px}
31 | return self._request_with_params(POST, COPYTRADING_CLOSE_POS, params)
32 |
33 | # GET /api/v5/copytrading/instruments
34 | def copytrading_instruments(self):
35 | params = {}
36 | return self._request_with_params(GET, COPYTRADING_INSTRUMENTS, params)
37 |
38 | # POST /api/v5/copytrading/set-instruments
39 | def copytrading_set_instruments(self, instId=''):
40 | params = {'instId': instId}
41 | return self._request_with_params(POST, COPYTRADING_SET_INSTRUMENTS, params)
42 |
43 | # GET /api/v5/copytrading/profit-sharing-details
44 | def profit_sharing_details(self, after='', before='', limit=''):
45 | params = {'after': after, 'before': before, 'limit': limit}
46 | return self._request_with_params(GET, PROFIT_SHARING_DETAILS, params)
47 |
48 | # GET /api/v5/copytrading/total-profit-sharing
49 | def total_profit_sharing(self):
50 | params = {}
51 | return self._request_with_params(GET, TOTAL_PROFIT_SHARING, params)
52 |
53 | # GET /api/v5/copytrading/unrealized-profit-sharing-details
54 | def unrealized_profit_sharing_details(self):
55 | params = {}
56 | return self._request_with_params(GET, UNREALIZED_PROFIT_SHARING_DETAILS, params)
57 |
58 | # POST / api / v5 / copytrading / first - copy - settings
59 | def first_copy_settings(self,instType='',uniqueCode='',copyMgnMode='',copyInstIdType='',instId='',copyMode='',
60 | copyTotalAmt='',copyAmt='',copyRatio='',tpRatio='',slRatio='',slTotalAmt='',
61 | subPosCloseType=''):
62 | params = {'instType':instType,'uniqueCode':uniqueCode,'copyMgnMode':copyMgnMode,'copyInstIdType':copyInstIdType,'instId':instId,'copyMode':copyMode,
63 | 'copyTotalAmt':copyTotalAmt,'copyAmt':copyAmt,'copyRatio':copyRatio,'tpRatio':tpRatio,'slRatio':slRatio,
64 | 'slTotalAmt':slTotalAmt,'subPosCloseType':subPosCloseType,}
65 | return self._request_with_params(POST, FIRST_COPY_SETTINGS, params)
66 |
67 | # POST /api/v5/copytrading/amend-copy-settings
68 | def amend_copy_settings(self,instType='',uniqueCode='',copyMgnMode='',copyInstIdType='',instId='',copyMode='',
69 | copyTotalAmt='',copyAmt='',copyRatio='',tpRatio='',slRatio='',slTotalAmt='',
70 | subPosCloseType=''):
71 | params = {'instType':instType,'uniqueCode':uniqueCode,'copyMgnMode':copyMgnMode,'copyInstIdType':copyInstIdType,'instId':instId,'copyMode':copyMode,
72 | 'copyTotalAmt':copyTotalAmt,'copyAmt':copyAmt,'copyRatio':copyRatio,'tpRatio':tpRatio,'slRatio':slRatio,
73 | 'slTotalAmt':slTotalAmt,'subPosCloseType':subPosCloseType,}
74 | return self._request_with_params(POST, AMEND_COPY_SETTINGS, params)
75 |
76 | # POST /api/v5/copytrading/stop-copy-trading
77 | def stop_copy_trading(self,instType='',uniqueCode='',subPosCloseType=''):
78 | params = {'instType':instType,'uniqueCode':uniqueCode,'subPosCloseType':subPosCloseType,}
79 | return self._request_with_params(POST, STOP_COPY_SETTINGS, params)
80 |
81 | # GET /api/v5/copytrading/copy-trading
82 | def copy_settings(self,instType='',uniqueCode=''):
83 | params = {'instType':instType,'uniqueCode':uniqueCode,}
84 | return self._request_with_params(GET, COPY_SETTINGS, params)
85 |
86 | # GET /api/v5/copytrading/batch-leverage-info
87 | def batch_leverage_inf(self,mgnMode='',uniqueCode='',instId=''):
88 | params = {'mgnMode':mgnMode,'uniqueCode':uniqueCode,'instId':instId,}
89 | return self._request_with_params(GET, BATCH_LEVERAGE_INF, params)
90 |
91 | # POST /api/v5/copytrading/batch-set-leverage
92 | def batch_set_leverage(self,mgnMode='',lever='',instId=''):
93 | params = {'mgnMode':mgnMode,'lever':lever,'instId':instId,}
94 | return self._request_with_params(POST, BATCH_SET_LEVERAGE, params)
95 |
96 | # GET /api/v5/copytrading/current-lead-traders
97 | def current_lead_traders(self,instType='',):
98 | params = {'instType':instType,}
99 | return self._request_with_params(GET, CURRENT_LEAD_TRADERS, params)
100 |
101 | # GET /api/v5/copytrading/lead-traders-history
102 | def lead_traders_history(self, instType='',after='',before='',limit='', ):
103 | params = {'instType': instType,'after': after,'before': before,'limit': limit, }
104 | return self._request_with_params(GET, LEAD_TRADERS_HISTORY, params)
105 |
106 | # GET /api/v5/copytrading/public-lead-traders
107 | def public_lead_traders(instType='',sortType='',state='',minLeadDays='',minAssets='',maxAssets='',
108 | minAum='',maxAum='',dataVer='',page='',limit=''):
109 | params = {'instType': sortType, 'sortType': sortType, 'state': state, 'minLeadDays': minLeadDays,
110 | 'minAssets': minAssets, 'maxAssets': maxAssets, 'minAum': minAum, 'maxAum': maxAum,
111 | 'dataVer': dataVer, 'page': page, 'limit': limit,
112 | }
113 | return self._request_with_params(GET, PUBLIC_LEAD_TRADERS, params)
114 |
115 | # GET /api/v5/copytrading/public-weekly-pnl
116 | def public_weekly_pnl(self, instType='', uniqueCode=''):
117 | params = {'instType': instType, 'uniqueCode': uniqueCode, }
118 | return self._request_with_params(GET, PUBLIC_WEEKLY_PNL, params)
119 |
120 | # GET /api/v5/copytrading/public-pnl
121 | def public_pnl(self, instType='', uniqueCode='',lastDays=''):
122 | params = {'instType': instType, 'uniqueCode': uniqueCode, 'lastDays': lastDays}
123 | return self._request_with_params(GET, PUBLIC_PNL, params)
124 |
125 | # GET /api/v5/copytrading/public-stats
126 | def public_stats(self, instType='', uniqueCode='', lastDays=''):
127 | params = {'instType': instType, 'uniqueCode': uniqueCode, 'lastDays': lastDays}
128 | return self._request_with_params(GET, PUBLIC_STATS, params)
129 |
130 | # GET /api/v5/copytrading/public-preference-currency
131 | def public_preference_currency(self, instType='', uniqueCode=''):
132 | params = {'instType': instType, 'uniqueCode': uniqueCode, }
133 | return self._request_with_params(GET, PUBLIC_PRE_CURR, params)
134 |
135 |
136 | # GET /api/v5/copytrading/public-current-subpositions
137 | def public_current_subpositions(self, after='', before='', limit='', instType='', uniqueCode=''):
138 | params = {'instType': instType,'after': after,'before': before,'limit': limit, 'uniqueCode':uniqueCode}
139 | return self._request_with_params(GET, PUBLIC_CURR_SUBPOS, params)
140 |
141 | # GET /api/v5/copytrading/public-subpositions-history
142 | def public_subpositions_history(self, after='', before='', limit='', instType='', uniqueCode=''):
143 | params = {'instType': instType, 'after': after, 'before': before, 'limit': limit, 'uniqueCode': uniqueCode}
144 | return self._request_with_params(GET, PUBLIC_SUBPOS_HIS, params)
145 |
146 | def apply_lead_trading(self, instType='',instId='', ):
147 | params = {'instType': instType, 'instId': instId,}
148 | return self._request_with_params(POST, APP_LEA_TRAD, params)
149 |
150 | def stop_lead_trading(self, instType='',):
151 | params = {'instType': instType,}
152 | return self._request_with_params(POST, STOP_LEA_TRAD, params)
153 |
154 |
155 | def amend_profit_sharing_ratio(self, instType='',profitSharingRatio=''):
156 | params = {'instType': instType,'profitSharingRatio': profitSharingRatio}
157 | return self._request_with_params(POST, AMEDN_PRO_SHAR_RATIO, params)
158 |
159 |
160 | def lead_traders(self, instType='',sortType='',state='',minLeadDays='',minAssets='',maxAssets='',
161 | minAum='',maxAum='',dataVer='',page='',limit='',):
162 | params = {'instType': instType,'sortType': sortType,'state': state,'minLeadDays': minLeadDays,
163 | 'minAssets': minAssets,'maxAssets': maxAssets,'minAum': minAum,'maxAum': maxAum,
164 | 'dataVer': dataVer,'page': page,'limit': limit,}
165 | return self._request_with_params(GET, LEAD_TRADERS, params)
166 |
167 |
168 | def weekly_pnl(self, instType='',uniqueCode=''):
169 | params = {'instType': instType,'uniqueCode': uniqueCode,}
170 | return self._request_with_params(GET, WEEKLY_PNL, params)
171 |
172 |
173 | def pnl(self, instType='',uniqueCode='',lastDays = ''):
174 | params = {'instType': instType,'uniqueCode': uniqueCode,'lastDays': lastDays,}
175 | return self._request_with_params(GET, PNL, params)
176 |
177 |
178 | def stats(self, instType='',uniqueCode='',lastDays = ''):
179 | params = {'instType': instType,'uniqueCode': uniqueCode,'lastDays': lastDays,}
180 | return self._request_with_params(GET, STATS, params)
181 |
182 |
183 | def preference_currency(self, instType='',uniqueCode=''):
184 | params = {'instType': instType,'uniqueCode': uniqueCode,}
185 | return self._request_with_params(GET, PRE_CURR, params)
186 |
187 |
188 | def performance_current_subpositions(self, instType='',uniqueCode='', after='', before='', limit='', ):
189 | params = {'instType': instType,'uniqueCode': uniqueCode,'after': after,'before': before,'limit': limit, }
190 | return self._request_with_params(GET, PRE_CURR_SUNPOSITION, params)
191 |
192 |
193 | def performance_subpositions_history(self, instType='',uniqueCode='', after='', before='', limit='', ):
194 | params = {'instType': instType,'uniqueCode': uniqueCode,'after': after,'before': before,'limit': limit, }
195 | return self._request_with_params(GET, PRE_SUNPOSITION_HISTORY, params)
196 |
197 |
198 | def copy_traders(self, instType='',uniqueCode='', limit='', ):
199 | params = {'instType': instType,'uniqueCode': uniqueCode,'limit': limit, }
200 | return self._request_with_params(GET, COPY_TRADERS, params)
201 |
202 |
203 | def public_copy_traders(self, instType='',uniqueCode='', limit='', ):
204 | params = {'instType': instType,'uniqueCode': uniqueCode,'limit': limit, }
205 | return self._request_with_params(GET, PUB_COPY_TRADERS, params)
206 |
207 |
208 | def config(self, ):
209 | params = {}
210 | return self._request_with_params(GET, CONFIG, params)
211 |
212 |
213 | def total_unrealized_profit_sharing(self, instType = ''):
214 | params = {'instType':instType}
215 | return self._request_with_params(GET, TOTAL_UNREA_PRO_SHAR, params)
216 |
217 |
218 |
--------------------------------------------------------------------------------
/okx/FDBroker_api.py:
--------------------------------------------------------------------------------
1 | from .client import Client
2 | from .consts import *
3 |
4 |
5 | class FDBrokerAPI(Client):
6 | def __init__(self, api_key, api_secret_key, passphrase, use_server_time=False, flag='1'):
7 | Client.__init__(self, api_key, api_secret_key, passphrase, use_server_time, flag)
8 |
9 | def fd_rebate_per_orders(self, begin = '', end = '', brokerType = ''):
10 | params = {'begin': begin, 'end': end, 'brokerType':brokerType}
11 | return self._request_with_params(POST, FD_REBATE_PER_ORDERS, params)
12 |
13 | def fd_get_rebate_per_orders(self, type = '', begin = '', end = '', brokerType = ''):
14 | params = {'type': type, 'begin': begin, 'end': end, 'brokerType':brokerType}
15 | return self._request_with_params(GET, FD_GET_REBATE_PER_ORDERS, params)
16 |
17 | def fd_if_rebate(self, apiKey = '', brokerType = ''):
18 | params = {'apiKey': apiKey, 'brokerType':brokerType}
19 | return self._request_with_params(GET, FD_IF_REBATE, params)
--------------------------------------------------------------------------------
/okx/Finance_api.py:
--------------------------------------------------------------------------------
1 | from .client import Client
2 | from .consts import *
3 |
4 |
5 | class FinanceAPI(Client):
6 |
7 | def __init__(self, api_key, api_secret_key, passphrase, use_server_time=False, flag='1'):
8 | Client.__init__(self, api_key, api_secret_key, passphrase, use_server_time, flag)
9 |
10 | # View items
11 | def staking_defi_offers(self, productId = '', protocolType = '', ccy = ''):
12 | params = {'productId': productId, 'protocolType': protocolType, 'ccy': ccy}
13 | return self._request_with_params(GET, STAKING_DEFI_OFFERS, params)
14 |
15 | # Subscription items
16 | def staking_defi_purchase(self, productId = '', investData = [], term= '',tag=''):
17 | params = {'productId': productId, 'investData': investData, 'term': term,'tag':tag}
18 | return self._request_with_params(POST, STAKING_DEFI_PURCHASE, params)
19 |
20 | # Redemption items
21 | def staking_defi_redeem(self, ordId = '', protocolType = '', allowEarlyRedeem= ''):
22 | params = {'ordId': ordId, 'protocolType': protocolType, 'allowEarlyRedeem': allowEarlyRedeem}
23 | return self._request_with_params(POST, STAKING_DEFI_REDEEM, params)
24 |
25 | # Cancellation of project subscription / redemption
26 | def staking_defi_cancel(self, ordId = '', protocolType = ''):
27 | params = {'ordId': ordId, 'protocolType': protocolType}
28 | return self._request_with_params(POST, STAKING_DEFI_CANCEL, params)
29 |
30 | # View active orders
31 | def staking_defi_orders_active(self, productId = '', protocolType = '', ccy = '', state = ''):
32 | params = {'productId': productId, 'protocolType': protocolType, 'ccy': ccy, 'state':state}
33 | return self._request_with_params(GET, STAKING_DEFI_ORDERS_ACTIVE, params)
34 |
35 | # View active orders
36 | def staking_defi_orders_history(self, productId = '', protocolType = '', ccy = '', after = '', before = '', limit = ''):
37 | params = {'productId': productId, 'protocolType': protocolType, 'ccy': ccy, 'after':after, 'before':before, 'limit':limit}
38 | return self._request_with_params(GET, STAKING_DEFI_ORDERS_HISTORY, params)
39 |
40 |
41 | def staking_defi_eth_purcase(self, amt = ''):
42 | params = {}
43 | return self._request_with_params(POST, STAKING_DEFI_ETH_PURCASE, params)
44 |
45 |
46 | def staking_defi_eth_redeem(self, amt = ''):
47 | params = {}
48 | return self._request_with_params(POST, STAKING_DEFI_ETH_REDEEM, params)
49 |
50 |
51 | def staking_defi_eth_balance(self, ):
52 | params = {}
53 | return self._request_with_params(GET, STAKING_DEFI_ETH_BALANCE, params)
54 |
55 |
56 | def staking_defi_eth_p_r_history(self,type='',status='',after='',before='',limit='', ):
57 | params = {'type': type,'status': status,'after': after,'before': before,'limit': limit,}
58 | return self._request_with_params(GET, STAKING_DEFI_ETH_P_R_HISTORY, params)
59 |
60 | def staking_defi_eth_apy_history(self,days='',):
61 | params = {'days': days,}
62 | return self._request_with_params(GET, STAKING_DEFI_ETH_APY_HISTORY, params)
63 |
64 | def staking_defi_eth_product_info(self):
65 | params = {}
66 | return self._request_with_params(GET, STAKING_DEFI_ETH_PRODUCT_INFO, params)
67 |
68 | def savings_lending_rate_summary(self,ccy='',):
69 | params = {'ccy': ccy,}
70 | return self._request_with_params(GET, SAVINGS_LENDING_RATE_SUM, params)
71 |
72 |
73 | def savings_lending_rate_his(self,ccy='',after='',before='',limit='',):
74 | params = {'ccy': ccy,'after': after,'before': before,'limit': limit,}
75 | return self._request_with_params(GET, SAVINGS_LENDING_RATE_HIS, params)
76 |
77 |
78 | def fixed_loan_lending_offers(self, ccy='', term='', ):
79 | params = {'ccy': ccy, 'term': term, }
80 | return self._request_with_params(GET, FIXED_LOAN_LENDING_OFFERS, params)
81 |
82 |
83 | def fixed_loan_lending_apy_history(self, ccy='', term='', ):
84 | params = {'ccy': ccy, 'term': term, }
85 | return self._request_with_params(GET, FIXED_LOAN_LENDING_APY_HIS, params)
86 |
87 |
88 | def fixed_loan_pending_lending_vol(self, ccy='', term='', ):
89 | params = {'ccy': ccy, 'term': term, }
90 | return self._request_with_params(GET, FIXED_LOAN_PENDING_LENDING_VOL, params)
91 |
92 | # POST /api/v5/finance/fixed-loan/lending-order
93 | def fixed_loan_lending_order(self, ccy = '', amt = '', rate = '', term = '', autoRenewal = ''):
94 | params = {'ccy':ccy,'amt':amt,'rate':rate,'term':term,'autoRenewal':autoRenewal}
95 | return self._request_with_params(POST, FIXED_LOAN_LENDING_ORDER, params)
96 |
97 | # POST /api/v5/finance/fixed-loan/amend-lending-order
98 | def fixed_loan_amend_lending_order(self, ordId = '', changeAmt = '', rate = '', autoRenewal = ''):
99 | params = {'ordId':ordId,'changeAmt':changeAmt,'rate':rate,'autoRenewal':autoRenewal}
100 | return self._request_with_params(POST, FIXED_LOAN_AMEND_LENDING_ORDER, params)
101 |
102 | # GET /api/v5/finance/fixed-loan/lending-orders-list
103 | def fixed_loan_lending_orders_list(self, ordId='', ccy='', state='', after='', before='', limit=''):
104 | params = {'ordId': ordId, 'ccy': ccy, 'state':state, 'after':after, 'before':before, 'limit':limit}
105 | return self._request_with_params(GET, FIXED_LOAN_LENDING_ORDERS_LIST, params)
106 |
107 | # GET /api/v5/finance/fixed-loan/lending-sub-orders
108 | def fixed_loan_lending_sub_orders(self, ordId='', state='', after='', before='', limit=''):
109 | params = {'ordId': ordId, 'state':state, 'after':after, 'before':before, 'limit':limit}
110 | return self._request_with_params(GET, FIXED_LOAN_LENDING_SUB_ORDERS, params)
--------------------------------------------------------------------------------
/okx/Funding_api.py:
--------------------------------------------------------------------------------
1 | from .client import Client
2 | from .consts import *
3 |
4 |
5 | class FundingAPI(Client):
6 |
7 | def __init__(self, api_key, api_secret_key, passphrase, use_server_time=False, flag='1'):
8 | Client.__init__(self, api_key, api_secret_key, passphrase, use_server_time, flag)
9 |
10 | # Get Deposit Address
11 | def get_deposit_address(self, ccy):
12 | params = {'ccy': ccy}
13 | return self._request_with_params(GET, DEPOSIT_ADDRESS, params)
14 |
15 | # Get Balance
16 | def get_balances(self, ccy=''):
17 | params = {'ccy': ccy}
18 | return self._request_with_params(GET, GET_BALANCES, params)
19 |
20 | # POST Account Configuration
21 | def funds_transfer(self, ccy, amt, froms, to, type='0', subAcct='', clientId='',loanTrans='',omitPosRisk=''):
22 | params = {'ccy': ccy, 'amt': amt, 'from': froms, 'to': to, 'type': type, 'subAcct': subAcct,'clientId': clientId,'loanTrans':loanTrans,'omitPosRisk':omitPosRisk}
23 | return self._request_with_params(POST, FUNDS_TRANSFER, params)
24 |
25 | # Get Transfer State
26 | def transfer_state(self, transId,type=''):
27 | params = {'transId': transId, 'type': type}
28 | return self._request_with_params(POST, TRANSFER_STATE, params)
29 |
30 | # Withdrawal
31 | def coin_withdraw(self, ccy, amt, dest, toAddr, fee,chain='',areaCode='',clientId=''):
32 | params = {'ccy': ccy, 'amt': amt, 'dest': dest, 'toAddr': toAddr, 'fee': fee,'chain': chain,'areaCode':areaCode,'clientId':clientId}
33 | return self._request_with_params(POST, WITHDRAWAL_COIN, params)
34 |
35 | # Get Deposit History
36 | def get_deposit_history(self, ccy='', state='', after='', before='', limit='',txId='',depId='',fromWdId=''):
37 | params = {'ccy': ccy, 'state': state, 'after': after, 'before': before, 'limit': limit,'txId':txId,'depId':depId,'fromWdId':fromWdId}
38 | return self._request_with_params(GET, DEPOSIT_HISTORIY, params)
39 |
40 | # Get Withdrawal History
41 | def get_withdrawal_history(self, ccy='', state='', after='', before='', limit='',txId='',depId='',wdId=''):
42 | params = {'ccy': ccy, 'state': state, 'after': after, 'before': before, 'limit': limit,'txId':txId,'depId':depId,'wdId':wdId}
43 | return self._request_with_params(GET, WITHDRAWAL_HISTORIY, params)
44 |
45 | # Get Convert Dust Assets
46 | def convert_dust_assets(self, ccy):
47 | params = {'ccy': ccy}
48 | return self._request_with_params(POST, CONVERT_DUST_ASSETS, params)
49 |
50 | # Get Currencies
51 | def get_currency(self,ccy=''):
52 | params = {'ccy':ccy}
53 | return self._request_with_params(GET, CURRENCY_INFO,params)
54 |
55 | # PiggyBank Purchase/Redemption
56 | def purchase_redempt(self, ccy, amt, side,rate):
57 | params = {'ccy': ccy, 'amt': amt, 'side': side,'rate': rate}
58 | return self._request_with_params(POST, PURCHASE_REDEMPT, params)
59 |
60 | # Get Withdrawal History
61 | def get_bills(self, ccy='', type='', after='', before='', limit=''):
62 | params = {'ccy': ccy, 'type': type, 'after': after, 'before': before, 'limit': limit}
63 | return self._request_with_params(GET, BILLS_INFO, params)
64 |
65 |
66 | #Get Piggy Balance
67 | def get_piggy_balance(self, ccy=''):
68 | params = {}
69 | if ccy:
70 | params = {'ccy':ccy}
71 | return self._request_with_params(GET, PIGGY_BALANCE, params)
72 |
73 |
74 | #Get Deposit Lightning
75 | def get_deposit_lightning(self, ccy,amt,to=""):
76 | params = {'ccy':ccy,'amt':amt}
77 | if to:
78 | params = {'to':to}
79 | return self._request_with_params(GET, DEPOSIT_LIGHTNING, params)
80 |
81 | # Withdrawal Lightning
82 | def withdrawal_lightning(self, ccy,invoice,memo):
83 | params = {'ccy':ccy, 'invoice':invoice,'memo':memo}
84 | return self._request_with_params(POST, WITHDRAWAL_LIGHTNING, params)
85 |
86 | # Withdrawal Lightning
87 | def cancel_withdrawal(self, wdId):
88 | params = {'wdId':wdId,}
89 | return self._request_with_params(POST , CANCEL_WITHDRAWAL, params)
90 |
91 | # GET Obtain account asset valuation
92 | def get_asset_valuation(self, ccy):
93 | params = {'ccy':ccy}
94 | return self._request_with_params(GET, ASSET_VALUATION, params)
95 |
96 | # POST SET LENDING RATE
97 | def set_lending_rate(self, ccy,rate):
98 | params = {'ccy':ccy,'rate':rate}
99 | return self._request_with_params(POST, SET_LENDING_RATE, params)
100 |
101 |
102 | # GET LENDING HISTORY
103 | def get_lending_rate(self, ccy='',before='',after='',limit='',):
104 | params = {'ccy': ccy, 'after': after, 'before': before, 'limit': limit,}
105 | return self._request_with_params(GET, LENDING_HISTORY, params)
106 |
107 |
108 | # GET LENDING RATE HISTORY
109 | def get_lending_rate_history(self, ccy='',):
110 | params = {'ccy': ccy,}
111 | return self._request_with_params(GET, LENDING_RATE_HISTORY, params)
112 |
113 | # GET LENDING RATE SUMMARY
114 | def get_lending_rate_summary(self, ccy='',before='',after='',limit='',):
115 | params = {'ccy': ccy, 'after': after, 'before': before, 'limit': limit,}
116 | return self._request_with_params(GET,LENDING_RATE_SUMMARY, params)
117 |
118 | # GET LENDING RATE SUMMARY
119 | def deposit_withdraw_status(self, wdId = '', txId = '', ccy = '', to = '', chain = ''):
120 | params = {'wdId': wdId, 'txId': txId, 'ccy': ccy, 'to': to, 'chain':chain}
121 | return self._request_with_params(GET,DEPOSIT_WITHDRAW_STATUS, params)
122 |
123 | # GET /api/v5/asset/exchange-list
124 | def exchange_list(self):
125 | return self._request_without_params(GET,EXCHANGE_LIST)
126 |
127 | # POST /api/v5/asset/monthly-statement
128 | def monthly_statement(self,month=''):
129 | params = {'month':month}
130 | return self._request_with_params(POST, MONTHLY_STATEMENT,params)
131 |
132 | # GET /api/v5/asset/monthly-statement
133 | def monthly_statement(self,month=''):
134 | params = {'month':month}
135 | return self._request_with_params(GET, MONTHLY_STATEMENTS,params)
136 |
137 |
--------------------------------------------------------------------------------
/okx/Market_api.py:
--------------------------------------------------------------------------------
1 | from .client import Client
2 | from .consts import *
3 |
4 |
5 | class MarketAPI(Client):
6 |
7 | def __init__(self, api_key, api_secret_key, passphrase, use_server_time=False, flag='1'):
8 | Client.__init__(self, api_key, api_secret_key, passphrase, use_server_time, flag)
9 |
10 | # Get Tickers
11 | def get_tickers(self, instType, uly='',instFamily=''):
12 | if uly:
13 | params = {'instType': instType, 'uly': uly}
14 | else:
15 | params = {'instType': instType}
16 | return self._request_with_params(GET, TICKERS_INFO, params)
17 |
18 | # Get Ticker
19 | def get_ticker(self, instId):
20 | params = {'instId': instId}
21 | return self._request_with_params(GET, TICKER_INFO, params)
22 |
23 | # Get Index Tickers
24 | def get_index_ticker(self, quoteCcy='', instId=''):
25 | params = {'quoteCcy': quoteCcy, 'instId': instId}
26 | return self._request_with_params(GET, INDEX_TICKERS, params)
27 |
28 | # Get Order Book
29 | def get_orderbook(self, instId, sz=''):
30 | params = {'instId': instId, 'sz': sz}
31 | return self._request_with_params(GET, ORDER_BOOKS, params)
32 |
33 | # Get Candlesticks
34 | def get_candlesticks(self, instId, after='', before='', bar='', limit=''):
35 | params = {'instId': instId, 'after': after, 'before': before, 'bar': bar, 'limit': limit}
36 | return self._request_with_params(GET, MARKET_CANDLES, params)
37 |
38 | # GGet Candlesticks History(top currencies only)
39 | def get_history_candlesticks(self, instId, after='', before='', bar='', limit=''):
40 | params = {'instId': instId, 'after': after, 'before': before, 'bar': bar, 'limit': limit}
41 | return self._request_with_params(GET, HISTORY_CANDLES, params)
42 |
43 | # Get Index Candlesticks
44 | def get_index_candlesticks(self, instId, after='', before='', bar='', limit=''):
45 | params = {'instId': instId, 'after': after, 'before': before, 'bar': bar, 'limit': limit}
46 | return self._request_with_params(GET, INDEX_CANSLES, params)
47 |
48 | # Get Mark Price Candlesticks
49 | def get_markprice_candlesticks(self, instId, after='', before='', bar='', limit=''):
50 | params = {'instId': instId, 'after': after, 'before': before, 'bar': bar, 'limit': limit}
51 | return self._request_with_params(GET, MARKPRICE_CANDLES, params)
52 |
53 | # Get Index Candlesticks
54 | def get_trades(self, instId, limit=''):
55 | params = {'instId': instId, 'limit': limit}
56 | return self._request_with_params(GET, MARKET_TRADES, params)
57 |
58 | # Get Volume
59 | def get_volume(self):
60 | return self._request_without_params(GET, VOLUMNE)
61 |
62 | # Get Oracle
63 | def get_oracle(self):
64 | return self._request_without_params(GET, ORACLE)
65 |
66 | # Get Index Components
67 | def get_index_components(self, index):
68 | params = {'index': index}
69 | return self._request_with_params(GET, Components, params)
70 |
71 | # Get Tier
72 | def get_tier(self, instType='', tdMode='', uly='', instId='', ccy='', tier=''):
73 | params = {'instType': instType, 'tdMode': tdMode, 'uly': uly, 'instId': instId, 'ccy': ccy, 'tier': tier}
74 | return self._request_with_params(GET, TIER, params)
75 |
76 | # Get exchange rate
77 | def get_exchange_rate(self):
78 | params = {}
79 | return self._request_with_params(GET, BORROW_REPAY, params)
80 |
81 | # Get history trades
82 | def get_history_trades(self, instId = '', after = '', before = '', limit = ''):
83 | params = {'instId':instId, 'after':after, 'before':before, 'limit':limit}
84 | return self._request_with_params(GET, HISTORY_TRADES, params)
85 |
86 | # Get block history tickers
87 | def get_block_tickers(self, instType = '', uly = '',instFamily =''):
88 | params = {'instType':instType, 'uly':uly,'instFamily':instFamily}
89 | return self._request_with_params(GET, BLOCK_TICKERS, params)
90 |
91 | # Get block history ticker
92 | def get_block_ticker(self, instId = ''):
93 | params = {'instId':instId}
94 | return self._request_with_params(GET, BLOCK_TICKER, params)
95 |
96 | # Get block trades
97 | def get_block_trades(self, instId = ''):
98 | params = {'instId':instId}
99 | return self._request_with_params(GET, BLOCK_TRADES, params)
100 |
101 | # Get history index candlesticks
102 | def get_history_index_candlesticks(self, instId ='', after='', before='', bar='', limit=''):
103 | params = {'instId': instId, 'after': after, 'before': before, 'bar': bar, 'limit': limit}
104 | return self._request_with_params(GET, HISTORY_INDEX_CANDLES, params)
105 |
106 | # Get history mark price candlesticks
107 | def get_history_markprice_candlesticks(self, instId ='', after='', before='', bar='', limit=''):
108 | params = {'instId': instId, 'after': after, 'before': before, 'bar': bar, 'limit': limit}
109 | return self._request_with_params(GET, HISTORY_MARK_PRICE_CANDLES, params)
110 |
111 | # GET /api/v5/market/option/instrument-family-trades
112 | def instrument_family_trades(self, instFamily = ''):
113 | params = {'instFamily':instFamily}
114 | return self._request_with_params(GET, INSTRUMENT_FAMILY_TRADES, params)
115 |
116 | # GET /api/v5/market/books-lite
117 | def get_books_lite(self, instId=''):
118 | params = {'instId': instId}
119 | return self._request_with_params(GET, GET_BOOKS_LITE, params)
120 |
121 |
122 | def books_full(self, instId='',sz=''):
123 | params = {'instId': instId,'sz':sz}
124 | return self._request_with_params(GET, BOOKS_FULL, params)
125 |
126 | # GET /api/v5/market/call-auction-details
127 | def get_call_auction_details(self, instId=''):
128 | params = {'instId': instId}
129 | return self._request_with_params(GET, GET_CALL_AUCTION_DETAILS, params)
130 |
131 |
132 |
133 |
134 |
--------------------------------------------------------------------------------
/okx/Public_api.py:
--------------------------------------------------------------------------------
1 | from .client import Client
2 | from .consts import *
3 |
4 |
5 | class PublicAPI(Client):
6 |
7 | def __init__(self, api_key, api_secret_key, passphrase, use_server_time=False, flag='1'):
8 | Client.__init__(self, api_key, api_secret_key, passphrase, use_server_time, flag)
9 |
10 | # Get Instruments
11 | def get_instruments(self, instType = 'FUTURES', uly = 'BTC-USDT', instFamily = '', instId = ''):
12 | params = {'instType': instType, 'uly': uly, 'instId': instId, 'instFamily':instFamily}
13 | return self._request_with_params(GET, INSTRUMENT_INFO, params)
14 |
15 | # Get Delivery/Exercise History
16 | def get_deliver_history(self, instType, uly, after='', before='', limit=''):
17 | params = {'instType': instType, 'uly': uly, 'after': after, 'before': before, 'limit': limit}
18 | return self._request_with_params(GET, DELIVERY_EXERCISE, params)
19 |
20 | # Get Open Interest
21 | def get_open_interest(self, instType, uly='', instId='',instFamily=''):
22 | params = {'instType': instType, 'uly': uly, 'instId': instId,'instFamily':instFamily}
23 | return self._request_with_params(GET, OPEN_INTEREST, params)
24 |
25 | # Get Funding Rate
26 | def get_funding_rate(self, instId):
27 | params = {'instId': instId}
28 | return self._request_with_params(GET, FUNDING_RATE, params)
29 |
30 | # Get Funding Rate History
31 | def funding_rate_history(self, instId, after='', before='', limit=''):
32 | params = {'instId': instId, 'after': after, 'before': before, 'limit': limit}
33 | return self._request_with_params(GET, FUNDING_RATE_HISTORY, params)
34 |
35 | # Get Limit Price
36 | def get_price_limit(self, instId):
37 | params = {'instId': instId}
38 | return self._request_with_params(GET, PRICE_LIMIT, params)
39 |
40 | # Get Option Market Data
41 | def get_opt_summary(self, uly, expTime=''):
42 | params = {'uly': uly, 'expTime': expTime}
43 | return self._request_with_params(GET, OPT_SUMMARY, params)
44 |
45 | # Get Estimated Delivery/Excercise Price
46 | def get_estimated_price(self, instId):
47 | params = {'instId': instId}
48 | return self._request_with_params(GET, ESTIMATED_PRICE, params)
49 |
50 | # Get Discount Rate And Interest-Free Quota
51 | def discount_interest_free_quota(self, ccy=''):
52 | params = {'ccy': ccy}
53 | return self._request_with_params(GET, DICCOUNT_INTETEST_INFO, params)
54 |
55 | # Get System Time
56 | def get_system_time(self):
57 | return self._request_without_params(GET, SYSTEM_TIME)
58 |
59 | # Get Liquidation Orders
60 | def get_liquidation_orders(self, instType, mgnMode='', instId='', ccy='', uly='', alias='', state='', before='',
61 | after='', limit='',instFamily = ''):
62 | params = {'instType': instType, 'mgnMode': mgnMode, 'instId': instId, 'ccy': ccy, 'uly': uly,
63 | 'alias': alias, 'state': state, 'before': before, 'after': after, 'limit': limit,'instFamily':instFamily}
64 | return self._request_with_params(GET, LIQUIDATION_ORDERS, params)
65 |
66 | # Get Mark Price
67 | def get_mark_price(self, instType, uly='', instId='',instFamily=''):
68 | params = {'instType': instType, 'uly': uly, 'instId': instId,'instFamily':instFamily}
69 | return self._request_with_params(GET, MARK_PRICE, params)
70 |
71 | # Get Tier
72 | def get_tier(self, instType, tdMode, uly='', instId='', ccy='', tier='',instFamily=''):
73 | params = {'instType': instType, 'tdMode': tdMode, 'uly': uly, 'instId': instId, 'ccy': ccy, 'tier': tier,'instFamily':instFamily}
74 | return self._request_with_params(GET, TIER, params)
75 |
76 | # Get Interest Rate and Loan Quota
77 | def get_interest_loan(self):
78 | return self._request_without_params(GET, INTEREST_LOAN)
79 |
80 | # Get underlying
81 |
82 | def get_underlying(self, instType):
83 | params = {'instType': instType}
84 | return self._request_with_params(GET, UNDERLYING, params)
85 |
86 | # GET Obtain the privileged currency borrowing leverage rate and currency borrowing limit
87 | def get_vip_interest_rate_loan_quota(self):
88 | params = {}
89 | return self._request_with_params(GET, VIP_INTEREST_RATE_LOAN_QUOTA, params)
90 |
91 | def get_insurance_fund(self,instType = '', type = '', uly = '', ccy = '', before = '', after = '', limit = '',instFamily=''):
92 | params = {'instType':instType, 'type':type, 'uly':uly, 'ccy':ccy, 'before':before, 'after':after, 'limit':limit,'instFamily':instFamily}
93 | return self._request_with_params(GET, INSURANCE_FUND, params)
94 |
95 | def convert_contract_coin(self, type = '', instId = '', sz = '', px = '', unit = '', opType=''):
96 | params = {'type':type, 'instId':instId, 'sz':sz, 'px':px, 'unit':unit, 'opType':opType}
97 | return self._request_with_params(GET, CONVERT_CONTRACT_COIN, params)
98 |
99 | # GET /api/v5/public/instrument-tick-bands
100 | def instrument_tick_bands(self, instType = '', instFamily = ''):
101 | params = {'instType':instType, 'instFamily':instFamily}
102 | return self._request_with_params(GET, INSTRUMENT_TICK_BANDS, params)
103 |
104 | # GET /api/v5/public/option-trades
105 | def option_trades(self, instId = '', instFamily = '', optType = ''):
106 | params = {'instId':instId, 'instFamily':instFamily, 'optType':optType}
107 | return self._request_with_params(GET, OPTION_TRADES, params)
108 |
--------------------------------------------------------------------------------
/okx/Recurring_api.py:
--------------------------------------------------------------------------------
1 | from .client import Client
2 | from .consts import *
3 |
4 |
5 | class RecurringAPI(Client):
6 | def __init__(self, api_key, api_secret_key, passphrase, use_server_time=False, flag='1'):
7 | Client.__init__(self, api_key, api_secret_key, passphrase, use_server_time, flag)
8 |
9 | # POST /api/v5/tradingBot/recurring/order-algo
10 | def recurring_order_algo(self, stgyName = '', recurringList = [], period = '', recurringDay = '', recurringTime = '', timeZone = '', amt = '', investmentCcy = '', tdMode = '', algoClOrdId = '', tag = ''):
11 | params = {'stgyName': stgyName, 'recurringList': recurringList, 'period': period, 'recurringDay':recurringDay, 'recurringTime': recurringTime,
12 | 'timeZone': timeZone,'amt': amt,'investmentCcy': investmentCcy,'tdMode': tdMode,'algoClOrdId': algoClOrdId,'tag': tag}
13 | return self._request_with_params(POST, RECURRING_ORDER_ALGO, params)
14 |
15 | # POST /api/v5/tradingBot/recurring/amend-order-algo
16 | def recurring_amend_order_algo(self, algoId = '', stgyName = ''):
17 | params = {'algoId': algoId, 'stgyName': stgyName}
18 | return self._request_with_params(POST, RECURRING_AMEND_ORDER_ALGO, params)
19 |
20 | # POST /api/v5/tradingBot/recurring/stop-order-algo
21 | def recurring_stop_order_algo(self, orders_data):
22 | return self._request_with_params(POST, RECURRING_STOP_ORDER_ALGO, orders_data)
23 |
24 | # GET /api/v5/tradingBot/recurring/orders-algo-pending
25 | def recurring_orders_algo_pending(self, algoId = '', after = '', before = '', limit = ''):
26 | params = {'algoId': algoId, 'after': after, 'before': before, 'limit': limit}
27 | return self._request_with_params(GET, RECURRING_ORDER_ALGO_PENDING, params)
28 |
29 | # GET /api/v5/tradingBot/recurring/orders-algo-history
30 | def recurring_orders_algo_history(self, algoId = '', after = '', before = '', limit = ''):
31 | params = {'algoId': algoId, 'after': after, 'before': before, 'limit': limit}
32 | return self._request_with_params(GET, RECURRING_ORDER_ALGO_HISTORY, params)
33 |
34 | # GET /api/v5/tradingBot/recurring/orders-algo-details
35 | def recurring_orders_algo_details(self, algoId = ''):
36 | params = {'algoId': algoId}
37 | return self._request_with_params(GET, RECURRING_ORDER_ALGO_DETAILS, params)
38 |
39 | # GET /api/v5/tradingBot/recurring/sub-orders
40 | def recurring_sub_orders(self, algoId = '', ordId = '', after = '', before = '', limit = ''):
41 | params = {'algoId': algoId, 'ordId': ordId, 'after': after, 'before': before, 'limit': limit}
42 | return self._request_with_params(GET, RECURRING_SUB_ORDERS, params)
43 |
--------------------------------------------------------------------------------
/okx/Rfq_api.py:
--------------------------------------------------------------------------------
1 | from .client import Client
2 | from .consts import *
3 |
4 |
5 | class RfqAPI(Client):
6 | def __init__(self, api_key, api_secret_key, passphrase, use_server_time=False, flag='1'):
7 | Client.__init__(self, api_key, api_secret_key, passphrase, use_server_time, flag)
8 |
9 | def counterparties(self):
10 | params = {}
11 | return self._request_with_params(GET, COUNTERPARTIES, params)
12 |
13 | def create_rfq(self, counterparties='', anonymous='', clRfqId='', allowPartialExecution = '', tag='', legs = []):
14 | params = {'counterparties': counterparties, 'anonymous': anonymous, 'clRfqId': clRfqId, 'tag':tag, 'legs': legs}
15 | return self._request_with_params(POST, CREATE_RFQ, params)
16 |
17 | def cancel_rfq(self, rfqId = '', clRfqId = ''):
18 | params = {'rfqId': rfqId, 'clRfqId': clRfqId}
19 | return self._request_with_params(POST, CANCEL_RFQ, params)
20 |
21 | def cancel_batch_rfqs(self, rfqIds='', clRfqIds=''):
22 | params = {'rfqIds': rfqIds, 'clRfqIds': clRfqIds}
23 | return self._request_with_params(POST, CANCEL_BATCH_RFQS, params)
24 |
25 | def cancel_all_rfqs(self):
26 | params = {}
27 | return self._request_with_params(POST, CANCEL_ALL_RSQS, params)
28 |
29 | def execute_quote(self, rfqId='', quoteId=''):
30 | params = {'rfqId': rfqId, 'quoteId': quoteId}
31 | return self._request_with_params(POST, EXECUTE_QUOTE, params)
32 |
33 | def create_quote(self, rfqId='', clQuoteId='', tag = '', quoteSide = '', legs = [], expiresIn = '',anonymous = ''):
34 | params = {'rfqId': rfqId, 'clQuoteId': clQuoteId, 'tag':tag, 'quoteSide': quoteSide, 'legs': legs, 'expiresIn':expiresIn, 'anonymous':anonymous}
35 | return self._request_with_params(POST, CREATE_QUOTE, params)
36 |
37 | def cancel_quote(self, quoteId = '', clQuoteId = '', rfqId = ''):
38 | params = {'quoteId': quoteId, 'clQuoteId': clQuoteId, 'rfqId':rfqId}
39 | return self._request_with_params(POST, CANCEL_QUOTE, params)
40 |
41 | def cancel_batch_quotes(self, quoteIds='', clQuoteIds=''):
42 | params = {'quoteIds': quoteIds, 'clQuoteIds': clQuoteIds}
43 | return self._request_with_params(POST, CANCEL_BATCH_QUOTES, params)
44 |
45 | def cancel_all_quotes(self):
46 | params = {}
47 | return self._request_with_params(POST, CANCEL_ALL_QUOTES, params)
48 |
49 | def get_rfqs(self, rfqId = '', clRfqId = '', state = '', beginId = '', endId = '', limit = ''):
50 | params = {'rfqId': rfqId, 'clRfqId': clRfqId, 'state': state, 'beginId': beginId, 'endId': endId, 'limit':limit}
51 | return self._request_with_params(GET, GET_RFQS, params)
52 |
53 | def get_quotes(self, rfqId = '', clRfqId = '', quoteId = '', clQuoteId = '', state = '', beginId = '', endId = '', limit = ''):
54 | params = {'rfqId': rfqId, 'clRfqId': clRfqId, 'quoteId':quoteId,'clQuoteId':clQuoteId, 'state': state, 'beginId': beginId, 'endId': endId, 'limit':limit}
55 | return self._request_with_params(GET, GET_QUOTES, params)
56 |
57 | def get_rfq_trades(self, rfqId = '', clRfqId = '', quoteId = '', blockTdId = '', clQuoteId = '', state = '', beginId = '', endId = '', limit = '', beginTs ='', endTs = ''):
58 | params = {'rfqId': rfqId, 'clRfqId': clRfqId, 'quoteId':quoteId,'clQuoteId':clQuoteId, 'state': state, 'beginId': beginId, 'endId': endId, 'limit':limit,'blockTdId':blockTdId,'beginTs':beginTs,'endTs':endTs}
59 | return self._request_with_params(GET, GET_RFQ_TRADES, params)
60 |
61 | def get_public_trades(self, beginId = '', endId = '', limit = ''):
62 | params = {'beginId': beginId, 'endId': endId, 'limit': limit}
63 | return self._request_with_params(GET, GET_PUBLIC_TRADES, params)
64 |
65 |
66 | def rfq_cancel_all_after(self, timeOut = ''):
67 | params = {'timeOut': timeOut}
68 | return self._request_with_params(POST, RFQ_CANCEL_ALL_AFTER, params)
69 |
70 | def maker_instrument_settings(self, instType='', data=[]):
71 | params = [{'instType': instType, 'data': data}]
72 | return self._request_with_params(POST, MARKET_INSTRUMENT_SETTINGS, params)
73 |
74 | def mmp_reset(self):
75 | params = {}
76 | return self._request_with_params(POST, MMP_RESET, params)
77 |
78 | # POST /api/v5/rfq/mmp-config
79 | def mmp_config(self,timeInterval='',frozenInterval='',countLimit=''):
80 | params = {'timeInterval':timeInterval,'frozenInterval':frozenInterval,'countLimit':countLimit,}
81 | return self._request_with_params(POST, MMP_CONFIG, params)
82 |
83 | # GET /api/v5/rfq/maker-instrument-settings
84 | def get_maker_instrument_settings(self):
85 | params = {}
86 | return self._request_with_params(GET, GET_MAKER_INSTRUMENT_SETTINGS, params)
87 |
88 |
89 | # GET /api/v5/rfq/maker-instrument-settings
90 | def mmp_configs(self,timeInterval='', frozenInterval='', countLimit='',mmpFrozen='',mmpFrozenUntil='',):
91 | params = {'timeInterval':timeInterval,'frozenInterval':frozenInterval,'countLimit':countLimit,
92 | 'mmpFrozen':mmpFrozen,'mmpFrozenUntil':mmpFrozenUntil,}
93 | return self._request_with_params(GET, MMP_CONF, params)
--------------------------------------------------------------------------------
/okx/SprdApi_api.py:
--------------------------------------------------------------------------------
1 | from .client import Client
2 | from .consts import *
3 |
4 |
5 | class SprdAPI(Client):
6 | def __init__(self, api_key, api_secret_key, passphrase, use_server_time=False, flag='1'):
7 | Client.__init__(self, api_key, api_secret_key, passphrase, use_server_time, flag)
8 |
9 | # 下单 POST /api/v5/sprd/order
10 | def place(self,sprdId,side,ordType,sz,px='',clOrdId='',tag='',):
11 | params = {'sprdId':sprdId,'clOrdId':clOrdId,'tag':tag,'side':side,'ordType':ordType,
12 | 'sz':sz,'px':px,}
13 | return self._request_with_params(POST, SPRD_PLACE_ORDER, params)
14 |
15 | # 撤单 POST /api/v5/sprd/cancel-order
16 | def cancel_order(self,ordId='',clOrdId=''):
17 | params = {'ordId':ordId,'clOrdId':clOrdId}
18 | return self._request_with_params(POST, SPRD_CANCEL_ORDER, params)
19 |
20 | # 全部撤单 POST /api/v5/sprd/mass-cancel
21 | def mass_cancel(self,sprdId):
22 | params = {'sprdId':sprdId}
23 | return self._request_with_params(POST, SPRD_MASS_CANCELS, params)
24 |
25 | # 修改订单 POST /api/v5/sprd/amend-order
26 | def amend_cancel(self,reqId='',ordId='', clOrdId='', newSz='', newPx=''):
27 | params = {'reqId':reqId, 'ordId':ordId, 'clOrdId':clOrdId, 'newSz':newSz, 'newPx':newPx, }
28 | return self._request_with_params(POST, SPRD_AMEND_CANCELS, params)
29 |
30 | # 获取订单信息 GET /api/v5/sprd/order
31 | def order(self, ordId='', clOrdId=''):
32 | params = {'ordId': ordId, 'clOrdId': clOrdId}
33 | return self._request_with_params(GET, SPRD_ORDER, params)
34 |
35 | # 获取未成交订单列表 GET /api/v5/sprd/orders-pending
36 | def orders_pending(self,sprdId='', ordType='', state='', beginId='', endId='', limit=''):
37 | params = {'sprdId': sprdId, 'ordType': ordType,
38 | 'state': state,
39 | 'endId': endId,
40 | 'beginId': beginId,'limit': limit,
41 | }
42 | return self._request_with_params(GET, SPRD_ORDERS_PENDING, params)
43 |
44 | # 获取历史订单记录(近21天) GET /api/v5/sprd/orders-history
45 | def orders_history(self,sprdId='',ordType='',state='',beginId='',endId='',limit='',
46 | begin='',end='',):
47 | params = {'sprdId': sprdId, 'ordType': ordType,
48 | 'state': state,'begin': state,
49 | 'endId': endId,'end': endId,
50 | 'beginId': beginId, 'limit': limit,
51 | }
52 | return self._request_with_params(GET, SPRD_ORDERS_HISTORY, params)
53 |
54 |
55 | # 获取历史订单记录(近3个月) GET /api/v5/sprd/orders-history-archive
56 | def orders_history_archive(self, sprdId='', ordType='', state='', beginId='', endId='', limit='',
57 | begin='', end='', ):
58 | params = {'sprdId': sprdId, 'ordType': ordType,
59 | 'state': state, 'begin': state,
60 | 'endId': endId, 'end': endId,
61 | 'beginId': beginId, 'limit': limit,
62 | }
63 | return self._request_with_params(GET, SPRD_ORDERS_HISTORY_ARCHIVE, params)
64 |
65 | # 获取历史成交数据(近七天)GET /api/v5/sprd/trades
66 | def trades(self,sprdId='',tradeId='',ordId='',beginId='',endId='',limit='',begin='',end='',):
67 | params = {'sprdId': sprdId, 'ordId': ordId,'tradeId': tradeId,'begin': state,'endId': endId,'end': endId,
68 | 'beginId': beginId, 'limit': limit,}
69 | return self._request_with_params(GET, SPRD_TRADES, params)
70 |
71 | # 获取Spreads(公共)GET /api/v5/sprd/spreads
72 | def spreads(self,baseCcy='',instId='',sprdId='',state='',):
73 | params = {'sprdId': sprdId, 'baseCcy': baseCcy, 'instId': instId,'state': state,}
74 | return self._request_with_params(GET, SPRD_SPREADS, params)
75 |
76 | # 获取Spread产品深度(公共)GET /api/v5/sprd/books
77 | def books(self,sprdId='',sz='',):
78 | params = {'sprdId': sprdId, 'sz': sz,}
79 | return self._request_with_params(GET, SPRD_BOOKS, params)
80 |
81 | # 获取单个Spread产品行情信息(公共) GET /api/v5/sprd/ticker
82 | def ticker(self,sprdId=''):
83 | params = {'sprdId': sprdId}
84 | return self._request_with_params(GET, SPRD_TICKER, params)
85 |
86 | # 获取公共成交数据(公共)GET /api/v5/sprd/public-trades
87 | def public_trades(self,sprdId=''):
88 | params = {'sprdId': sprdId}
89 | return self._request_with_params(GET, SPRD_PUBLIC_TRADES, params)
90 |
91 | # POST /api/v5/sprd/cancel-all-after
92 | def sprd_cancel_all_after(self,timeOut=''):
93 | params = {'timeOut':timeOut }
94 | return self._request_with_params(POST, SPRD_CANCEL_ALL_AFTER, params)
95 |
96 |
97 | # GET /api/v5/market/sprd-candles
98 | def get_sprd_candles(self,sprdId='', bar='', after='', before='', limit=''):
99 | params = {'sprdId': sprdId, 'bar': bar, 'after': after, 'before': before, 'limit': limit}
100 | return self._request_with_params(GET, GET_SPRD_CANDLES, params)
101 |
102 | # GET /api/v5/market/sprd-history-candles
103 | def get_sprd_history_candles(self,sprdId='', bar='', after='', before='', limit=''):
104 | params = {'sprdId': sprdId, 'bar': bar, 'after': after, 'before': before, 'limit': limit}
105 | return self._request_with_params(GET, GET_SPRD_HISTORY_CANDLES, params)
106 |
107 |
108 |
--------------------------------------------------------------------------------
/okx/Trade_api.py:
--------------------------------------------------------------------------------
1 | from .client import Client
2 | from .consts import *
3 |
4 |
5 | class TradeAPI(Client):
6 |
7 | def __init__(self, api_key, api_secret_key, passphrase, use_server_time=False, flag='1'):
8 | Client.__init__(self, api_key, api_secret_key, passphrase, use_server_time, flag)
9 |
10 | # Place Order
11 | def place_order(self, instId, tdMode, side, ordType, sz, ccy='', clOrdId='', tag='', posSide='', px='',
12 | reduceOnly='', tgtCcy='', banAmend='',quickMgnType='',tpTriggerPx = '', tpOrdPx = '',
13 | slTriggerPx = '', slOrdPx = '', tpTriggerPxType = '', slTriggerPxType = '',stpId='',
14 | stpMode='',attachAlgoClOrdId=''):
15 | params = {'instId': instId, 'tdMode': tdMode, 'side': side, 'ordType': ordType, 'sz': sz, 'ccy': ccy,
16 | 'clOrdId': clOrdId, 'tag': '60bb4a8d3416BCDE', 'posSide': posSide, 'px': px, 'reduceOnly': reduceOnly,
17 | 'tgtCcy': tgtCcy, 'banAmend': banAmend,'quickMgnType':quickMgnType,'tpTriggerPx':tpTriggerPx,'tpOrdPx':tpOrdPx,'slTriggerPx':slTriggerPx
18 | ,'slOrdPx':slOrdPx,'tpTriggerPxType':tpTriggerPxType,'slTriggerPxType':slTriggerPxType,
19 | 'stpId':stpId,'stpMode':stpMode,'attachAlgoClOrdId':attachAlgoClOrdId}
20 | return self._request_with_params(POST, PLACR_ORDER, params)
21 |
22 | # Place Multiple Orders
23 | def place_multiple_orders(self, orders_data):
24 | return self._request_with_params(POST, BATCH_ORDERS, orders_data)
25 |
26 | # Cancel Order
27 | def cancel_order(self, instId, ordId='', clOrdId=''):
28 | params = {'instId': instId, 'ordId': ordId, 'clOrdId': clOrdId}
29 | return self._request_with_params(POST, CANAEL_ORDER, params)
30 |
31 | # Cancel Multiple Orders
32 | def cancel_multiple_orders(self, orders_data):
33 | return self._request_with_params(POST, CANAEL_BATCH_ORDERS, orders_data)
34 |
35 | # Amend Order
36 | def amend_order(self, instId, cxlOnFail='', ordId='', clOrdId='', reqId='', newSz='',
37 | newPx = '', newTpTriggerPx='', newTpOrdPx='',newSlTriggerPx='', newSlOrdPx='',
38 | newTpTriggerPxType='', newSlTriggerPxType=''):
39 | params = {'instId': instId, 'cxlOnFailc': cxlOnFail, 'ordId': ordId, 'clOrdId': clOrdId, 'reqId': reqId,
40 | 'newSz': newSz,'newPx': newPx,'newTpTriggerPx': newTpTriggerPx,'newTpOrdPx': newTpOrdPx,
41 | 'newSlTriggerPx': newSlTriggerPx,'newSlOrdPx': newSlOrdPx,'newTpTriggerPxType': newTpTriggerPxType,
42 | 'newSlTriggerPxType': newSlTriggerPxType}
43 | return self._request_with_params(POST, AMEND_ORDER, params)
44 |
45 | # Amend Multiple Orders
46 | def amend_multiple_orders(self, orders_data):
47 | return self._request_with_params(POST, AMEND_BATCH_ORDER, orders_data)
48 |
49 | # Close Positions
50 | def close_positions(self, instId, mgnMode, posSide='', ccy='',autoCxl='',clOrdId='',tag=''):
51 | params = {'instId': instId, 'mgnMode': mgnMode, 'posSide': posSide, 'ccy': ccy, 'autoCxl':autoCxl, 'clOrdId':clOrdId, 'tag':'f1ee03b510d5SUDE'}
52 | return self._request_with_params(POST, CLOSE_POSITION, params)
53 |
54 | # Get Order Details
55 | def get_orders(self, instId, ordId='', clOrdId=''):
56 | params = {'instId': instId, 'ordId': ordId, 'clOrdId': clOrdId}
57 | return self._request_with_params(GET, ORDER_INFO, params)
58 |
59 | # Get Order List
60 | def get_order_list(self, instType='', uly='', instId='', ordType='', state='', after='', before='', limit='', instFamily = ''):
61 | params = {'instType': instType, 'uly': uly, 'instId': instId, 'ordType': ordType, 'state': state,
62 | 'after': after, 'before': before, 'limit': limit, 'instFamily':instFamily}
63 | return self._request_with_params(GET, ORDERS_PENDING, params)
64 |
65 | # Get Order History (last 7 days)
66 | def get_orders_history(self, instType='', uly='', instId='', ordType='', state='', after='', before='', limit='', instFamily ='', category = '', begin = '', end = ''):
67 | params = {'instType': instType, 'uly': uly, 'instId': instId, 'ordType': ordType, 'state': state,
68 | 'after': after, 'before': before, 'limit': limit, 'instFamily': instFamily, 'category': category, 'begin': begin, 'end': end}
69 | return self._request_with_params(GET, ORDERS_HISTORY, params)
70 |
71 | # Get Order History (last 3 months)
72 | def orders_history_archive(self, instType, uly='', instId='', ordType='', state='', after='', before='', limit='', instFamily ='', category = '', begin = '', end = ''):
73 | params = {'instType': instType, 'uly': uly, 'instId': instId, 'ordType': ordType, 'state': state,
74 | 'after': after, 'before': before, 'limit': limit, 'instFamily': instFamily, 'category': category, 'begin': begin, 'end': end}
75 | return self._request_with_params(GET, ORDERS_HISTORY_ARCHIVE, params)
76 |
77 | # Get Transaction Details
78 | def get_fills(self, instType='', uly='', instId='', ordId='', after='', before='',
79 | limit='', instFamily = '', begin = '', end = '',subType=''):
80 | params = {'instType': instType, 'uly': uly, 'instId': instId, 'ordId': ordId, 'after': after, 'before': before,
81 | 'limit': limit, 'instFamily': instFamily, 'begin': begin, 'end': end,'subType':subType}
82 | return self._request_with_params(GET, ORDER_FILLS, params)
83 |
84 | # Place Algo Order
85 | def place_algo_order(self, instId='', tdMode='', side='', ordType='', sz='', ccy='',
86 | posSide='', reduceOnly='', tpTriggerPx='',
87 | tpOrdPx='', slTriggerPx='', slOrdPx='',
88 | triggerPx='', orderPx='', tgtCcy='', pxVar='',
89 | pxSpread='', cxlOnClosePos='',
90 | szLimit='', pxLimit='', timeInterval='', tpTriggerPxType='', slTriggerPxType='',
91 | callbackRatio='',callbackSpread='',activePx='',tag='',triggerPxType='',
92 | algoClOrdId='',quickMgnType='',closeFraction='', attachAlgoClOrdId=''):
93 | params = {'instId': instId, 'tdMode': tdMode, 'side': side, 'ordType': ordType, 'sz': sz, 'ccy': ccy,
94 | 'posSide': posSide, 'reduceOnly': reduceOnly, 'tpTriggerPx': tpTriggerPx, 'tpOrdPx': tpOrdPx,
95 | 'slTriggerPx': slTriggerPx, 'slOrdPx': slOrdPx, 'triggerPx': triggerPx, 'orderPx': orderPx,
96 | 'tgtCcy': tgtCcy, 'pxVar': pxVar, 'szLimit': szLimit, 'pxLimit': pxLimit,
97 | 'timeInterval': timeInterval, 'cxlOnClosePos': cxlOnClosePos,
98 | 'pxSpread': pxSpread, 'tpTriggerPxType': tpTriggerPxType, 'slTriggerPxType': slTriggerPxType,
99 | 'callbackRatio' : callbackRatio, 'callbackSpread':callbackSpread,'activePx':activePx,
100 | 'tag':tag,'triggerPxType':triggerPxType,'algoClOrdId':algoClOrdId,'quickMgnType':quickMgnType,
101 | 'closeFraction':closeFraction, 'attachAlgoClOrdId':attachAlgoClOrdId}
102 | return self._request_with_params(POST, PLACE_ALGO_ORDER, params)
103 |
104 | # Cancel Algo Order
105 | def cancel_algo_order(self, params):
106 | return self._request_with_params(POST, CANCEL_ALGOS, params)
107 |
108 | # POST /api/v5/trade/amend-algos
109 | def amend_algos(self, instId='', algoId='', algoClOrdId='', cxlOnFail = '',reqId = '',newSz = '',
110 | newTpTriggerPx = '',newTpOrdPx = '',newSlTriggerPx = '',
111 | newSlOrdPx = '',newTpTriggerPxType = '',newSlTriggerPxType='',
112 | newTriggerPx='',newOrdPx='',newTriggerPxType='',attachAlgoOrds=[]):
113 | params = {'instId':instId,'algoId':algoId,'algoClOrdId':algoClOrdId,'cxlOnFail':cxlOnFail,
114 | 'reqId':reqId,'newSz':newSz,'newTpTriggerPx':newTpTriggerPx,'newTpOrdPx':newTpOrdPx,
115 | 'newSlTriggerPx':newSlTriggerPx,'newSlOrdPx':newSlOrdPx,'newTpTriggerPxType':newTpTriggerPxType,
116 | 'newSlTriggerPxType':newSlTriggerPxType,'newTriggerPx':newTriggerPx, 'newOrdPx':newOrdPx, 'newTriggerPxType':newTriggerPxType,
117 | 'attachAlgoOrds':attachAlgoOrds}
118 | return self._request_with_params(POST, AMEND_ALGOS, params)
119 |
120 | # Cancel Advance Algos
121 | def cancel_advance_algos(self, params):
122 | return self._request_with_params(POST, Cancel_Advance_Algos, params)
123 |
124 | # Get Algo Order List
125 | def order_algos_list(self, ordType, algoId='', instType='', instId='', after='', before='', limit='',algoClOrdId=''):
126 | params = {'ordType': ordType, 'algoId': algoId, 'instType': instType, 'instId': instId, 'after': after,
127 | 'before': before, 'limit': limit,'algoClOrdId':algoClOrdId}
128 | return self._request_with_params(GET, ORDERS_ALGO_OENDING, params)
129 |
130 | # Get Algo Order History
131 | def order_algos_history(self, ordType, state='', algoId='', instType='', instId='', after='', before='', limit=''):
132 | params = {'ordType': ordType, 'state': state, 'algoId': algoId, 'instType': instType, 'instId': instId,
133 | 'after': after, 'before': before, 'limit': limit}
134 | return self._request_with_params(GET, ORDERS_ALGO_HISTORY, params)
135 |
136 | # Get Transaction Details History
137 | def get_fills_history(self, instType, uly='', instId='', ordId='', after='', before='', limit='',subType=''):
138 | params = {'instType': instType, 'uly': uly, 'instId': instId, 'ordId': ordId, 'after': after, 'before': before,
139 | 'limit': limit,'subType':subType}
140 | return self._request_with_params(GET, ORDERS_FILLS_HISTORY, params)
141 |
142 | def easy_convert_currency_list(self, source = ''):
143 | params = {'source':source}
144 | return self._request_with_params(GET, EASY_CONVERT_CURRENCY_LIST, params)
145 |
146 | def easy_convert(self, fromCcy = '', toCcy = '', source = ''):
147 | params = {'fromCcy':fromCcy, 'toCcy':toCcy, 'source':source}
148 | return self._request_with_params(POST, EASY_CONVERT, params)
149 |
150 | def easy_convert_history(self, after = '', before = '', limit = ''):
151 | params = {'after':after, 'before':before, 'limit':limit}
152 | return self._request_with_params(GET, EASY_CONVERT_HISTORY, params)
153 |
154 | def one_click_repay_currency_list(self, debtType = ''):
155 | params = {'debtType':debtType}
156 | return self._request_with_params(GET, ONE_CLICK_REPAY_CURRENCY_LIST, params)
157 |
158 | def one_click_repay(self, debtCcy = '', repayCcy = ''):
159 | params = {'debtCcy':debtCcy, 'repayCcy':repayCcy}
160 | return self._request_with_params(POST, ONE_CLICK_REPAY, params)
161 |
162 | def one_click_repay_history(self, after = '', before = '', limit = ''):
163 | params = {'after':after, 'before':before, 'limit':limit}
164 | return self._request_with_params(GET, ONE_CLICK_REPAY_HISTORY, params)
165 |
166 | # GET /api/v5/trade/order-algo
167 | def get_order_algo(self, algoId = '', algoClOrdId = ''):
168 | params = {'algoId':algoId, 'algoClOrdId':algoClOrdId}
169 | return self._request_with_params(GET, GET_ORDER_ALGO, params)
170 |
171 | # POST /api/v5/trade/mass-cancel
172 | def mass_cancel(self,instType= '',instFamily = '',lockInterval = ''):
173 | params = {'instType':instType, 'instFamily':instFamily, 'lockInterval':lockInterval}
174 | return self._request_with_params(POST, MASS_CANCEL, params)
175 |
176 | def cancel_all_after(self,timeOut= '', tag = ''):
177 | params = {'timeOut': timeOut, 'tag': tag}
178 | return self._request_with_params(POST, CANCEL_ALL_AFTER, params)
179 |
180 | # POST / api / v5 / trade / fills - archive
181 | def fills_archive(self,year, quarter):
182 | params = {'year': year, 'quarter':quarter}
183 | return self._request_with_params(POST, FILLS_ARCHIVE, params)
184 |
185 | # GET / api / v5 / trade / fills - archive
186 | def fills_archives(self,year, quarter):
187 | params = {'year': year, 'quarter':quarter}
188 | return self._request_with_params(GET, FILLS_ARCHIVES, params)
189 |
190 | # POST /api/v5/trade/order-precheck
191 | def order_precheck(self,instid = '', tdMode = '', side = '', posSide = '', ordType = '', sz = '', px = '',
192 | reduceOnly = '', tgtCcy = '', attachAlgoOrds = []):
193 | params = {'instid': instid, 'tdMode':tdMode, 'side':side, 'posSide':posSide, 'ordType':ordType,
194 | 'sz':sz, 'px':px, 'reduceOnly':reduceOnly, 'tgtCcy':tgtCcy, 'attachAlgoOrds':attachAlgoOrds}
195 | return self._request_with_params(POST, ORDER_PRECHECK, params)
196 |
197 |
198 |
--------------------------------------------------------------------------------
/okx/TradingBot_api.py:
--------------------------------------------------------------------------------
1 | from .client import Client
2 | from .consts import *
3 |
4 |
5 | class TradingBotAPI(Client):
6 | def __init__(self, api_key, api_secret_key, passphrase, use_server_time=False, flag='1'):
7 | Client.__init__(self, api_key, api_secret_key, passphrase, use_server_time, flag)
8 |
9 | def grid_order_algo(self, instId = '', algoOrdType = '', maxPx= '', minPx = '', gridNum ='', runType = '', tpTriggerPx = '', slTriggerPx = '', tag = '', quoteSz = '',algoClOrdId='',
10 | baseSz = '', sz = '', direction = '', lever = '', basePos = '',tpRatio = '',slRatio='',profitSharingRatio='',triggerParams =[]):
11 | params = {'instId': instId, 'algoOrdType': algoOrdType, 'maxPx': maxPx, 'minPx': minPx, 'gridNum': gridNum, 'runType': runType, 'tpTriggerPx': tpTriggerPx, 'slTriggerPx': slTriggerPx, 'tag': tag, 'quoteSz': quoteSz, 'baseSz': baseSz, 'sz': sz, 'direction': direction, 'lever': lever, 'basePos':basePos,
12 | 'tpRatio': tpRatio,'slRatio': slRatio,'algoClOrdId':algoClOrdId,'profitSharingRatio':profitSharingRatio,'triggerParams':triggerParams}
13 | return self._request_with_params(POST, GRID_ORDER_ALGO, params)
14 |
15 | def grid_amend_order_algo(self, algoId = '', instId = '', slTriggerPx= '', tpTriggerPx ='',tpRatio = '',slRatio=''):
16 | params = {'algoId': algoId, 'instId': instId, 'slTriggerPx': slTriggerPx, 'tpTriggerPx': tpTriggerPx,'tpRatio': tpRatio,'slRatio': slRatio,}
17 | return self._request_with_params(POST, GRID_AMEND_ORDER_ALGO, params)
18 |
19 | def grid_stop_order_algo(self, algoId = '', instId = '', algoOrdType= '', stopType =''):
20 | params = [{'algoId': algoId, 'instId': instId, 'algoOrdType': algoOrdType, 'stopType': stopType}]
21 | return self._request_with_params(POST, GRID_STOP_ORDER_ALGO, params)
22 |
23 | def grid_orders_algo_pending(self, algoOrdType = '', algoId = '', instId = '', instType = '', after = '', before = '', limit = ''):
24 | params = {'algoOrdType': algoOrdType, 'algoId': algoId, 'instId': instId, 'instType': instType, 'after': after, 'before': before, 'limit': limit}
25 | return self._request_with_params(GET, GRID_ORDERS_ALGO_PENDING, params)
26 |
27 | def grid_orders_algo_history(self, algoOrdType = '', algoId = '', instId = '', instType = '', after = '', before = '', limit = ''):
28 | params = {'algoOrdType': algoOrdType, 'algoId': algoId, 'instId': instId, 'instType': instType, 'after': after, 'before': before, 'limit': limit}
29 | return self._request_with_params(GET, GRID_ORDERS_ALGO_HISTORY, params)
30 |
31 | def grid_orders_algo_details(self, algoOrdType = '', algoId = ''):
32 | params = {'algoOrdType': algoOrdType, 'algoId': algoId}
33 | return self._request_with_params(GET, GRID_ORDERS_ALGO_DETAILS, params)
34 |
35 | def grid_sub_orders(self, algoId = '', algoOrdType = '', type = '', groupId = '', after = '', before = '', limit = ''):
36 | params = {'algoId': algoId, 'algoOrdType': algoOrdType, 'type': type, 'groupId': groupId, 'after': after, 'before': before, 'limit': limit}
37 | return self._request_with_params(GET, GRID_SUB_ORDERS, params)
38 |
39 | def grid_positions(self, algoOrdType = '', algoId = ''):
40 | params = {'algoOrdType': algoOrdType, 'algoId': algoId}
41 | return self._request_with_params(GET, GRID_POSITIONS, params)
42 |
43 | def grid_withdraw_income(self, algoId = ''):
44 | params = {'algoId': algoId}
45 | return self._request_with_params(POST, GRID_WITHDRAW_INCOME, params)
46 |
47 | def grid_compute_margin_balance(self, algoId = '', type = '', amt = ''):
48 | params = {'algoId': algoId, 'type':type, 'amt':amt}
49 | return self._request_with_params(POST, GRID_COMPUTE_MARGIN_BALANCE, params)
50 |
51 | def grid_margin_balance(self, algoId = '', type = '', amt = '', percent = ''):
52 | params = {'algoId': algoId, 'type':type, 'amt':amt, 'percent':percent}
53 | return self._request_with_params(POST, GRID_MARGIN_BALANCE, params)
54 |
55 | def grid_ai_param(self, algoOrdType = '', instId = '', direction = '', duration = ''):
56 | params = {'algoOrdType': algoOrdType, 'instId':instId, 'direction':direction, 'duration':duration}
57 | return self._request_with_params(GET, GRID_AI_PARAM, params)
58 |
59 | # POST /api/v5/tradingBot/grid/adjust-investment
60 | def grid_adjust_investment(self, algoId = '', amt = ''):
61 | params = {'algoId': algoId, 'amt':amt}
62 | return self._request_with_params(POST, GRID_ADJUST_INVESTMETN, params)
63 |
64 | # GET /api/v5/tradingBot/grid/grid-quantity
65 | def grid_quantity(self, instId = '', runType = '', algoOrdType = '', maxPx = '', minPx = '', lever = ''):
66 | params = {'instId': instId, 'runType': runType, 'algoOrdType': algoOrdType, 'maxPx': maxPx, 'minPx': minPx, 'lever': lever}
67 | return self._request_with_params(GET, GRID_QUANTITY, params)
68 |
69 | # GET /api/v5/tradingBot/signal/orders-algo-pending
70 | def signal_orders_algo_pending(self, algoOrdType = 'contract'):
71 | params = {'algoOrdType': algoOrdType}
72 | return self._request_with_params(GET, SIGNAL_ORDERS_ALGO_PENDING, params)
73 |
74 | # GET /api/v5/tradingBot/signal/close-position
75 | def signal_close_position(self, instId = '', algoId = ''):
76 | params = {'instId': instId, 'algoId': algoId, 'tag': '60bb4a8d3416BCDE'}
77 | return self._request_with_params(POST, SIGNAL_CLOSE_POSITION, params)
--------------------------------------------------------------------------------
/okx/TradingData_api.py:
--------------------------------------------------------------------------------
1 | from .client import Client
2 | from .consts import *
3 |
4 |
5 | class TradingDataAPI(Client):
6 |
7 | def __init__(self, api_key, api_secret_key, passphrase, use_server_time=False, flag='1'):
8 | Client.__init__(self, api_key, api_secret_key, passphrase, use_server_time, flag)
9 |
10 | def get_support_coin(self):
11 | return self._request_without_params(GET, SUPPORT_COIN)
12 |
13 | # GET /api/v5/rubik/stat/contracts/open-interest-history
14 | def get_open_interest_history(self, instId = '', period = '', end = '', begin = '', limit = ''):
15 | params = {'instId': instId, 'period': period, 'end': end, 'begin': begin, 'limit': limit}
16 | return self._request_with_params(GET, GET_OPEN_INTEREST_HISTORY, params)
17 |
18 | def get_taker_volume(self, ccy, instType, begin='', end='', period=''):
19 | params = {'ccy': ccy, 'instType': instType, 'begin': begin, 'end': end, 'period': period}
20 | return self._request_with_params(GET, TAKER_VOLUME, params)
21 |
22 | # GET /api/v5/rubik/stat/taker-volume-contract
23 | def get_taker_volume_contract(self, instId, period = '', unit='', end='', begin='', limit = ''):
24 | params = {'instId': instId, 'period': period, 'unit': unit, 'end': end, 'begin': begin,'limit':limit}
25 | return self._request_with_params(GET, GET_TAKER_VOLUME_CONTRACT, params)
26 |
27 | def get_margin_lending_ratio(self, ccy, begin='', end='', period=''):
28 | params = {'ccy': ccy, 'begin': begin, 'end': end, 'period': period}
29 | return self._request_with_params(GET, MARGIN_LENDING_RATIO, params)
30 |
31 | # GET /api/v5/rubik/stat/contracts/long-short-account-ratio-contract-top-trader
32 | def get_long_short_account_ratio_contract_top_trader(self, instId = '', period = '', end = '', begin = '', limit = ''):
33 | params = {'instId': instId, 'period': period, 'end': end, 'begin': begin,'limit':limit}
34 | return self._request_with_params(GET, GET_LONG_SHORT_ACCOUNT_RADIO_CONTRACT_TOP_TRADER, params)
35 |
36 | # GET /api/v5/rubik/stat/contracts/long-short-position-ratio-contract-top-trader
37 | def get_long_short_position_ratio_contract_top_trader(self, instId = '', period = '', end = '', begin = '', limit = ''):
38 | params = {'instId': instId, 'period': period, 'end': end, 'begin': begin,'limit':limit}
39 | return self._request_with_params(GET, GET_LONG_SHORT_POSTION_RADIO_CONTRACT_TOP_TRADER, params)
40 |
41 | # GET /api/v5/rubik/stat/contracts/long-short-account-ratio-contract
42 | def get_long_short_account_ratio_contract(self, instId = '', period = '', end = '', begin = '', limit = ''):
43 | params = {'instId': instId, 'period': period, 'end': end, 'begin': begin,'limit':limit}
44 | return self._request_with_params(GET, GET_LONG_SHORT_ACCOUNT_RADIO_CONTRACT, params)
45 |
46 | def get_long_short_ratio(self, ccy, begin='', end='', period=''):
47 | params = {'ccy': ccy, 'begin': begin, 'end': end, 'period': period}
48 | return self._request_with_params(GET, LONG_SHORT_RATIO, params)
49 |
50 | def get_contracts_interest_volume(self, ccy, begin='', end='', period=''):
51 | params = {'ccy': ccy, 'begin': begin, 'end': end, 'period': period}
52 | return self._request_with_params(GET, CONTRACTS_INTEREST_VOLUME, params)
53 |
54 | def get_options_interest_volume(self, ccy, period=''):
55 | params = {'ccy': ccy, 'period': period}
56 | return self._request_with_params(GET, OPTIONS_INTEREST_VOLUME, params)
57 |
58 | def get_put_call_ratio(self, ccy, period=''):
59 | params = {'ccy': ccy, 'period': period}
60 | return self._request_with_params(GET, PUT_CALL_RATIO, params)
61 |
62 | def get_interest_volume_expiry(self, ccy, period=''):
63 | params = {'ccy': ccy, 'period': period}
64 | return self._request_with_params(GET, OPEN_INTEREST_VOLUME_EXPIRY, params)
65 |
66 | def get_interest_volume_strike(self, ccy, expTime, period=''):
67 | params = {'ccy': ccy, 'expTime': expTime, 'period': period}
68 | return self._request_with_params(GET, INTEREST_VOLUME_STRIKE, params)
69 |
70 | def get_taker_flow(self, ccy, period=''):
71 | params = {'ccy': ccy, 'period': period}
72 | return self._request_with_params(GET, TAKER_FLOW, params)
73 |
74 |
75 |
76 |
77 |
78 |
--------------------------------------------------------------------------------
/okx/__init__.py:
--------------------------------------------------------------------------------
1 | """An unofficial Python wrapper for the OKEx exchange API v3
2 |
3 | .. moduleauthor:: Sam McHardy
4 |
5 | """
6 |
--------------------------------------------------------------------------------
/okx/__pycache__/Account_api.cpython-310.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huojichuanqi/buou_trail/2299ed13751c3714176c24915a298532c17ca99b/okx/__pycache__/Account_api.cpython-310.pyc
--------------------------------------------------------------------------------
/okx/__pycache__/Trade_api.cpython-310.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huojichuanqi/buou_trail/2299ed13751c3714176c24915a298532c17ca99b/okx/__pycache__/Trade_api.cpython-310.pyc
--------------------------------------------------------------------------------
/okx/__pycache__/TradingBot_api.cpython-310.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huojichuanqi/buou_trail/2299ed13751c3714176c24915a298532c17ca99b/okx/__pycache__/TradingBot_api.cpython-310.pyc
--------------------------------------------------------------------------------
/okx/__pycache__/__init__.cpython-310.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huojichuanqi/buou_trail/2299ed13751c3714176c24915a298532c17ca99b/okx/__pycache__/__init__.cpython-310.pyc
--------------------------------------------------------------------------------
/okx/__pycache__/client.cpython-310.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huojichuanqi/buou_trail/2299ed13751c3714176c24915a298532c17ca99b/okx/__pycache__/client.cpython-310.pyc
--------------------------------------------------------------------------------
/okx/__pycache__/consts.cpython-310.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huojichuanqi/buou_trail/2299ed13751c3714176c24915a298532c17ca99b/okx/__pycache__/consts.cpython-310.pyc
--------------------------------------------------------------------------------
/okx/__pycache__/exceptions.cpython-310.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huojichuanqi/buou_trail/2299ed13751c3714176c24915a298532c17ca99b/okx/__pycache__/exceptions.cpython-310.pyc
--------------------------------------------------------------------------------
/okx/__pycache__/utils.cpython-310.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huojichuanqi/buou_trail/2299ed13751c3714176c24915a298532c17ca99b/okx/__pycache__/utils.cpython-310.pyc
--------------------------------------------------------------------------------
/okx/client.py:
--------------------------------------------------------------------------------
1 | import requests
2 | import json
3 | from . import consts as c, utils, exceptions
4 |
5 |
6 | class Client(object):
7 |
8 | def __init__(self, api_key, api_secret_key, passphrase, use_server_time=False, flag='1'):
9 |
10 | self.API_KEY = api_key
11 | self.API_SECRET_KEY = api_secret_key
12 | self.PASSPHRASE = passphrase
13 | self.use_server_time = use_server_time
14 | self.flag = flag
15 |
16 | def _request(self, method, request_path, params):
17 |
18 | if method == c.GET:
19 | request_path = request_path + utils.parse_params_to_str(params)
20 | # url
21 | url = c.API_URL + request_path
22 |
23 | timestamp = utils.get_timestamp()
24 |
25 | # sign & header
26 | if self.use_server_time:
27 | timestamp = self._get_timestamp()
28 |
29 | body = json.dumps(params) if method == c.POST else ""
30 |
31 | sign = utils.sign(utils.pre_hash(timestamp, method, request_path, str(body)), self.API_SECRET_KEY)
32 | header = utils.get_header(self.API_KEY, sign, timestamp, self.PASSPHRASE, self.flag)
33 |
34 | # send request
35 | response = None
36 |
37 | # print("url:", url)
38 | # print("headers:", header)
39 | # print("body:", body)
40 |
41 | if method == c.GET:
42 | response = requests.get(url, headers=header)
43 | elif method == c.POST:
44 | response = requests.post(url, data=body, headers=header)
45 |
46 | # exception handle
47 | # print(response.headers)
48 |
49 | if not str(response.status_code).startswith('2'):
50 | raise exceptions.OkxAPIException(response)
51 |
52 | return response.json()
53 |
54 | def _request_without_params(self, method, request_path):
55 | return self._request(method, request_path, {})
56 |
57 | def _request_with_params(self, method, request_path, params):
58 | return self._request(method, request_path, params)
59 |
60 | def _get_timestamp(self):
61 | url = c.API_URL + c.SERVER_TIMESTAMP_URL
62 | response = requests.get(url)
63 | if response.status_code == 200:
64 | return response.json()['data'][0]['ts']
65 | else:
66 | return ""
67 |
--------------------------------------------------------------------------------
/okx/consts.py:
--------------------------------------------------------------------------------
1 | # http header
2 | API_URL = 'https://www.okx.com'
3 |
4 | CONTENT_TYPE = 'Content-Type'
5 | OK_ACCESS_KEY = 'OK-ACCESS-KEY'
6 | OK_ACCESS_SIGN = 'OK-ACCESS-SIGN'
7 | OK_ACCESS_TIMESTAMP = 'OK-ACCESS-TIMESTAMP'
8 | OK_ACCESS_PASSPHRASE = 'OK-ACCESS-PASSPHRASE'
9 |
10 | ACEEPT = 'Accept'
11 | COOKIE = 'Cookie'
12 | LOCALE = 'Locale='
13 |
14 | APPLICATION_JSON = 'application/json'
15 |
16 | GET = "GET"
17 | POST = "POST"
18 |
19 | SERVER_TIMESTAMP_URL = '/api/v5/public/time'
20 |
21 | # account
22 | POSITION_RISK='/api/v5/account/account-position-risk'
23 | ACCOUNT_INFO = '/api/v5/account/balance'
24 | POSITION_INFO = '/api/v5/account/positions'
25 | BILLS_DETAIL = '/api/v5/account/bills'
26 | BILLS_ARCHIVE = '/api/v5/account/bills-archive'
27 | ACCOUNT_CONFIG = '/api/v5/account/config'
28 | POSITION_MODE = '/api/v5/account/set-position-mode'
29 | SET_LEVERAGE = '/api/v5/account/set-leverage'
30 | MAX_TRADE_SIZE = '/api/v5/account/max-size'
31 | MAX_AVAIL_SIZE = '/api/v5/account/max-avail-size'
32 | ADJUSTMENT_MARGIN = '/api/v5/account/position/margin-balance'
33 | GET_LEVERAGE = '/api/v5/account/leverage-info'
34 | MAX_LOAN = '/api/v5/account/max-loan'
35 | FEE_RATES = '/api/v5/account/trade-fee'
36 | INTEREST_ACCRUED = '/api/v5/account/interest-accrued'
37 | INTEREST_RATE = '/api/v5/account/interest-rate'
38 | SET_GREEKS = '/api/v5/account/set-greeks'
39 | ISOLATED_MODE = '/api/v5/account/set-isolated-mode'
40 | MAX_WITHDRAWAL = '/api/v5/account/max-withdrawal'
41 | ACCOUNT_RISK = '/api/v5/account/risk-state'
42 | BORROW_REPAY = '/api/v5/account/borrow-repay'
43 | BORROW_REPAY_HISTORY = '/api/v5/account/borrow-repay-history'
44 | INTEREST_LIMITS = '/api/v5/account/interest-limits'
45 | SIMULATED_MARGIN = '/api/v5/account/simulated_margin'
46 | GREEKS = '/api/v5/account/greeks'
47 | POSITIONS_HISTORY = '/api/v5/account/positions-history'
48 | POSITION_TIRES = '/api/v5/account/position-tiers'
49 | ACTIVATE_OPTION = '/api/v5/account/activate-option'
50 | QUICK_MARGIN_BRROW_REPAY = '/api/v5/account/quick-margin-borrow-repay'
51 | QUICK_MARGIN_BORROW_REPAY_HISTORY = '/api/v5/account/quick-margin-borrow-repay-history'
52 | VIP_INTEREST_ACCRUED = '/api/v5/account/vip-interest-accrued'
53 | VIP_INTEREST_DEDUCTED = '/api/v5/account/vip-interest-deducted'
54 | VIP_LOAN_ORDER_LIST = '/api/v5/account/vip-loan-order-list'
55 | VIP_LOAN_ORDER_DETAIL = '/api/v5/account/vip-loan-order-detail'
56 | SET_LOAN_ALLOCATION = '/api/v5/account/subaccount/set-loan-allocation'
57 | INTEREST_LIMITS = '/api/v5/account/subaccount/interest-limits'
58 | SET_RISKOFFSET_TYPE = '/api/v5/account/set-riskOffset-type'
59 | SET_AUTO_LOAN = '/api/v5/account/set-auto-loan'
60 | MMP_RESET = '/api/v5/account/mmp-reset'
61 | SET_RISKOFFSET_AMT = '/api/v5/account/set-riskOffset-amt'
62 | GET_FIXED_LOAN_BORROWING_LIMIT = '/api/v5/account/fixed-loan/borrowing-limit'
63 | GET_FIXED_LOAN_BORROWING_QUOTE = '/api/v5/account/fixed-loan/borrowing-quote'
64 | FIXED_LOAN_BORROWING_ORDER = '/api/v5/account/fixed-loan/borrowing-order'
65 | FIXED_LOAN_AMEND_BORROWING_ORDER = '/api/v5/account/fixed-loan/amend-borrowing-order'
66 | FIXED_LOAN_MANUAL_BORROWING = '/api/v5/account/fixed-loan/manual-reborrow'
67 | FIXED_LOAN_REPAY_BORROWING_ORDER = '/api/v5/account/fixed-loan/repay-borrowing-order'
68 | GET_FIXED_LOAN_BORROWING_ORDERS_LIST = '/api/v5/account/fixed-loan/borrowing-orders-list'
69 | GET_ACCOUNT_INSTRUMENTS = '/api/v5/account/instruments'
70 | SPOT_MANUAL_BORROW_REPAY = '/api/v5/account/spot-manual-borrow-repay'
71 | SET_AUTO_REPAY = '/api/v5/account/set-auto-repay'
72 | GET_SPOT_BORROW_REPAY_HISTORY = '/api/v5/account/spot-borrow-repay-history'
73 | CONVERT_TO_MARKET_LOAN = '/api/v5/account/fixed-loan/convert-to-market-loan'
74 | REDYCE_LIABILITIES = '/api/v5/account/fixed-loan/reduce-liabilities'
75 | ACC_RATE_LIMIT = '/api/v5/trade/account-rate-limit'
76 | BILLS_HISTORY_ARCHIVE = '/api/v5/account/bills-history-archive'
77 | GET_BILLS_HISTORY_ARCHIVE = '/api/v5/account/bills-history-archive'
78 |
79 | # funding
80 | DEPOSIT_ADDRESS = '/api/v5/asset/deposit-address'
81 | GET_BALANCES = '/api/v5/asset/balances'
82 | FUNDS_TRANSFER = '/api/v5/asset/transfer'
83 | TRANSFER_STATE = '/api/v5/asset/transfer-state'
84 | WITHDRAWAL_COIN = '/api/v5/asset/withdrawal'
85 | DEPOSIT_HISTORIY = '/api/v5/asset/deposit-history'
86 | CURRENCY_INFO = '/api/v5/asset/currencies'
87 | PURCHASE_REDEMPT = '/api/v5/finance/savings/purchase-redempt'
88 | BILLS_INFO = '/api/v5/asset/bills'
89 | PIGGY_BALANCE = '/api/v5/finance/savings/balance'
90 | DEPOSIT_LIGHTNING = '/api/v5/asset/deposit-lightning'
91 | WITHDRAWAL_LIGHTNING = '/api/v5/asset/withdrawal-lightning'
92 | CANCEL_WITHDRAWAL = '/api/v5/asset/cancel-withdrawal'
93 | WITHDRAWAL_HISTORIY = '/api/v5/asset/withdrawal-history'
94 | CONVERT_DUST_ASSETS = '/api/v5/asset/convert-dust-assets'
95 | ASSET_VALUATION = '/api/v5/asset/asset-valuation'
96 | SET_LENDING_RATE = '/api/v5/finance/savings/set-lending-rate'
97 | LENDING_HISTORY = '/api/v5/finance/savings/lending-history'
98 | LENDING_RATE_HISTORY = '/api/v5/asset/lending-rate-history'
99 | LENDING_RATE_SUMMARY = '/api/v5/asset/lending-rate-summary'
100 | DEPOSIT_WITHDRAW_STATUS = '/api/v5/asset/deposit-withdraw-status'
101 | EXCHANGE_LIST = '/api/v5/asset/exchange-list'
102 | MONTHLY_STATEMENT = '/api/v5/asset/monthly-statement'
103 | MONTHLY_STATEMENTS = '/api/v5/asset/monthly-statement'
104 |
105 | # Market Data
106 | TICKERS_INFO = '/api/v5/market/tickers'
107 | TICKER_INFO = '/api/v5/market/ticker'
108 | INDEX_TICKERS = '/api/v5/market/index-tickers'
109 | ORDER_BOOKS = '/api/v5/market/books'
110 | MARKET_CANDLES = '/api/v5/market/candles'
111 | HISTORY_CANDLES = '/api/v5/market/history-candles'
112 | INDEX_CANSLES = '/api/v5/market/index-candles'
113 | MARKPRICE_CANDLES = '/api/v5/market/mark-price-candles'
114 | MARKET_TRADES = '/api/v5/market/trades'
115 | VOLUMNE = '/api/v5/market/platform-24-volume'
116 | ORACLE = '/api/v5/market/oracle'
117 | Components = '/api/v5/market/index-components'
118 | EXCHANGE_RATE = '/api/v5/market/exchange-rate'
119 | HISTORY_TRADES = '/api/v5/market/history-trades'
120 | BLOCK_TICKERS = '/api/v5/market/block-tickers'
121 | BLOCK_TICKER = '/api/v5/market/block-ticker'
122 | BLOCK_TRADES = '/api/v5/market/trades'
123 | HISTORY_INDEX_CANDLES = '/api/v5/market/history-index-candles'
124 | HISTORY_MARK_PRICE_CANDLES = '/api/v5/market/history-mark-price-candles'
125 | INSTRUMENT_FAMILY_TRADES = '/api/v5/market/option/instrument-family-trades'
126 | GET_BOOKS_LITE = '/api/v5/market/books-lite'
127 | BOOKS_FULL = '/api/v5/market/books-full'
128 | GET_CALL_AUCTION_DETAILS = '/api/v5/market/call-auction-details'
129 |
130 | # Public Data
131 | INSTRUMENT_INFO = '/api/v5/public/instruments'
132 | DELIVERY_EXERCISE = '/api/v5/public/delivery-exercise-history'
133 | OPEN_INTEREST = '/api/v5/public/open-interest'
134 | FUNDING_RATE = '/api/v5/public/funding-rate'
135 | FUNDING_RATE_HISTORY = '/api/v5/public/funding-rate-history'
136 | PRICE_LIMIT = '/api/v5/public/price-limit'
137 | OPT_SUMMARY = '/api/v5/public/opt-summary'
138 | ESTIMATED_PRICE = '/api/v5/public/estimated-price'
139 | DICCOUNT_INTETEST_INFO = '/api/v5/public/discount-rate-interest-free-quota'
140 | SYSTEM_TIME = '/api/v5/public/time'
141 | LIQUIDATION_ORDERS = '/api/v5/public/liquidation-orders'
142 | MARK_PRICE = '/api/v5/public/mark-price'
143 | TIER = '/api/v5/public/position-tiers'
144 | INTEREST_LOAN = '/api/v5/public/interest-rate-loan-quota'
145 | UNDERLYING = '/api/v5/public/underlying'
146 | VIP_INTEREST_RATE_LOAN_QUOTA = '/api/v5/public/vip-interest-rate-loan-quota'
147 | INSURANCE_FUND = '/api/v5/public/insurance-fund'
148 | CONVERT_CONTRACT_COIN = '/api/v5/public/convert-contract-coin'
149 | INSTRUMENT_TICK_BANDS = '/api/v5/public/instrument-tick-bands'
150 | OPTION_TRADES = '/api/v5/public/option-trades'
151 |
152 | # TRADING DATA
153 | SUPPORT_COIN = '/api/v5/rubik/stat/trading-data/support-coin'
154 | TAKER_VOLUME = '/api/v5/rubik/stat/taker-volume'
155 | MARGIN_LENDING_RATIO = '/api/v5/rubik/stat/margin/loan-ratio'
156 | LONG_SHORT_RATIO = '/api/v5/rubik/stat/contracts/long-short-account-ratio'
157 | CONTRACTS_INTEREST_VOLUME = '/api/v5/rubik/stat/contracts/open-interest-volume'
158 | OPTIONS_INTEREST_VOLUME = '/api/v5/rubik/stat/option/open-interest-volume'
159 | PUT_CALL_RATIO = '/api/v5/rubik/stat/option/open-interest-volume-ratio'
160 | OPEN_INTEREST_VOLUME_EXPIRY = '/api/v5/rubik/stat/option/open-interest-volume-expiry'
161 | INTEREST_VOLUME_STRIKE = '/api/v5/rubik/stat/option/open-interest-volume-strike'
162 | TAKER_FLOW = '/api/v5/rubik/stat/option/taker-block-volume'
163 | GET_OPEN_INTEREST_HISTORY = '/api/v5/rubik/stat/contracts/open-interest-history'
164 | GET_TAKER_VOLUME_CONTRACT = '/api/v5/rubik/stat/taker-volume-contract'
165 | GET_LONG_SHORT_ACCOUNT_RADIO_CONTRACT_TOP_TRADER = '/api/v5/rubik/stat/contracts/long-short-account-ratio-contract-top-trader'
166 | GET_LONG_SHORT_POSTION_RADIO_CONTRACT_TOP_TRADER = '/api/v5/rubik/stat/contracts/long-short-position-ratio-contract-top-trader'
167 | GET_LONG_SHORT_ACCOUNT_RADIO_CONTRACT = '/api/v5/rubik/stat/contracts/long-short-account-ratio-contract'
168 |
169 | # TRADE
170 | PLACR_ORDER = '/api/v5/trade/order'
171 | BATCH_ORDERS = '/api/v5/trade/batch-orders'
172 | CANAEL_ORDER = '/api/v5/trade/cancel-order'
173 | CANAEL_BATCH_ORDERS = '/api/v5/trade/cancel-batch-orders'
174 | AMEND_ORDER = '/api/v5/trade/amend-order'
175 | AMEND_BATCH_ORDER = '/api/v5/trade/amend-batch-orders'
176 | CLOSE_POSITION = '/api/v5/trade/close-position'
177 | ORDER_INFO = '/api/v5/trade/order'
178 | ORDERS_PENDING = '/api/v5/trade/orders-pending'
179 | ORDERS_HISTORY = '/api/v5/trade/orders-history'
180 | ORDERS_HISTORY_ARCHIVE = '/api/v5/trade/orders-history-archive'
181 | ORDER_FILLS = '/api/v5/trade/fills'
182 | ORDERS_FILLS_HISTORY = '/api/v5/trade/fills-history'
183 | PLACE_ALGO_ORDER = '/api/v5/trade/order-algo'
184 | CANCEL_ALGOS = '/api/v5/trade/cancel-algos'
185 | AMEND_ALGOS = '/api/v5/trade/amend-algos'
186 | Cancel_Advance_Algos = '/api/v5/trade/cancel-advance-algos'
187 | ORDERS_ALGO_OENDING = '/api/v5/trade/orders-algo-pending'
188 | ORDERS_ALGO_HISTORY = '/api/v5/trade/orders-algo-history'
189 | EASY_CONVERT_CURRENCY_LIST = '/api/v5/trade/easy-convert-currency-list'
190 | EASY_CONVERT = '/api/v5/trade/easy-convert'
191 | EASY_CONVERT_HISTORY = '/api/v5/trade/easy-convert-history'
192 | ONE_CLICK_REPAY_CURRENCY_LIST = '/api/v5/trade/one-click-repay-currency-list'
193 | ONE_CLICK_REPAY = '/api/v5/trade/one-click-repay'
194 | ONE_CLICK_REPAY_HISTORY = '/api/v5/trade/one-click-repay-history'
195 | GET_ORDER_ALGO = '/api/v5/trade/order-algo'
196 | MASS_CANCEL = '/api/v5/trade/mass-cancel'
197 | CANCEL_ALL_AFTER = '/api/v5/trade/cancel-all-after'
198 | FILLS_ARCHIVE = '/api/v5/trade/fills-archive'
199 | FILLS_ARCHIVES = '/api/v5/trade/fills-archive'
200 | ORDER_PRECHECK = '/api/v5/trade/order-precheck'
201 |
202 | #Sprd
203 | SPRD_PLACE_ORDER = '/api/v5/sprd/order'
204 | SPRD_CANCEL_ORDER = '/api/v5/sprd/cancel-order'
205 | SPRD_MASS_CANCELS = '/api/v5/sprd/mass-cancel'
206 | SPRD_AMEND_CANCELS = '/api/v5/sprd/amend-order'
207 | SPRD_ORDER = '/api/v5/sprd/order'
208 | SPRD_ORDERS_PENDING = '/api/v5/sprd/orders-pending'
209 | SPRD_ORDERS_HISTORY = '/api/v5/sprd/orders-history'
210 | SPRD_ORDERS_HISTORY_ARCHIVE = '/api/v5/sprd/orders-history-archive'
211 | SPRD_TRADES = '/api/v5/sprd/trades'
212 | SPRD_SPREADS = '/api/v5/sprd/spreads'
213 | SPRD_BOOKS = '/api/v5/sprd/books'
214 | SPRD_TICKER = '/api/v5/market/sprd-ticker'
215 | SPRD_PUBLIC_TRADES = '/api/v5/sprd/public-trades'
216 | SPRD_CANCEL_ALL_AFTER = '/api/v5/sprd/cancel-all-after'
217 | GET_SPRD_CANDLES = '/api/v5/market/sprd-candles'
218 | GET_SPRD_HISTORY_CANDLES = '/api/v5/market/sprd-history-candles'
219 |
220 |
221 | # SubAccount
222 | BALANCE = '/api/v5/account/subaccount/balances'
223 | BILLs = '/api/v5/asset/subaccount/bills'
224 | DELETE = '/api/v5/users/subaccount/delete-apikey' # 移除此接口
225 | RESET = '/api/v5/users/subaccount/modify-apikey' # 移除此接口
226 | CREATE = '/api/v5/users/subaccount/apikey' # 移除此接口
227 | WATCH = '/api/v5/users/subaccount/apikey' # 移除此接口
228 | VIEW_LIST = '/api/v5/users/subaccount/list'
229 | SUBACCOUNT_TRANSFER = '/api/v5/asset/subaccount/transfer'
230 | ENTRUST_SUBACCOUNT_LIST = '/api/v5/users/entrust-subaccount-list'
231 | MODIFY_APIKEY = '/api/v5/users/subaccount/modify-apikey'
232 | ASSET_BALANCES = '/api/v5/asset/subaccount/balances'
233 | PARTNER_IF_REBATE = '/api/v5/users/partner/if-rebate'
234 | MAX_WITHDRAW = '/api/v5/account/subaccount/max-withdrawal'
235 | SUB_BILLS = '/api/v5/asset/subaccount/managed-subaccount-bills'
236 |
237 | # Broker
238 | BROKER_INFO = '/api/v5/broker/nd/info'
239 | CREATE_SUBACCOUNT = '/api/v5/broker/nd/create-subaccount'
240 | DELETE_SUBACCOUNT = '/api/v5/broker/nd/delete-subaccount'
241 | SUBACCOUNT_INFO = '/api/v5/broker/nd/subaccount-info'
242 | SET_SUBACCOUNT_LEVEL = '/api/v5/broker/nd/set-subaccount-level'
243 | SET_SUBACCOUNT_FEE_REAT = '/api/v5/broker/nd/set-subaccount-fee-rate'
244 | SUBACCOUNT_DEPOSIT_ADDRESS = '/api/v5/asset/broker/nd/subaccount-deposit-address'
245 | SUBACCOUNT_DEPOSIT_HISTORY = '/api/v5/asset/broker/nd/subaccount-deposit-history'
246 | REBATE_DAILY = '/api/v5/broker/nd/rebate-daily'
247 | # BROKER_INFO = '/api/v5/broker/nd/info' Broker 获取充值地址文档无法打开,预留位置
248 | ND_CREAET_APIKEY = '/api/v5/broker/nd/subaccount/apikey'
249 | ND_SELECT_APIKEY = '/api/v5/broker/nd/subaccount/apikey'
250 | ND_MODIFY_APIKEY = '/api/v5/broker/nd/subaccount/modify-apikey'
251 | ND_DELETE_APIKEY = '/api/v5/broker/nd/subaccount/delete-apikey'
252 | GET_REBATE_PER_ORDERS = '/api/v5/broker/nd/rebate-per-orders'
253 | REBATE_PER_ORDERS = '/api/v5/broker/nd/rebate-per-orders'
254 | MODIFY_SUBACCOUNT_DEPOSIT_ADDRESS = '/api/v5/asset/broker/nd/modify-subaccount-deposit-address'
255 | ND_SUBACCOUNT_WITHDRAWAL_HISTORY = '/api/v5/asset/broker/nd/subaccount-withdrawal-history'
256 | SET_SUBACCOUNT_ASSETS = '/api/v5/broker/nd/set-subaccount-assets'
257 | R_SACCOUNT_IP = '/api/v5/broker/nd/report-subaccount-ip'
258 | IF_REBATE = '/api/v5/broker/nd/if-rebate'
259 |
260 | # Convert
261 | GET_CURRENCIES = '/api/v5/asset/convert/currencies'
262 | GET_CURRENCY_PAIR = '/api/v5/asset/convert/currency-pair'
263 | ESTIMATE_QUOTE = '/api/v5/asset/convert/estimate-quote'
264 | CONVERT_TRADE = '/api/v5/asset/convert/trade'
265 | CONVERT_HISTORY = '/api/v5/asset/convert/history'
266 |
267 | # FDBroker
268 | FD_GET_REBATE_PER_ORDERS = '/api/v5/broker/fd/rebate-per-orders'
269 | FD_REBATE_PER_ORDERS = '/api/v5/broker/fd/rebate-per-orders'
270 | FD_IF_REBATE = '/api/v5/broker/fd/if-rebate'
271 |
272 | # Rfq
273 | COUNTERPARTIES = '/api/v5/rfq/counterparties'
274 | CREATE_RFQ = '/api/v5/rfq/create-rfq'
275 | CANCEL_RFQ = '/api/v5/rfq/cancel-rfq'
276 | CANCEL_BATCH_RFQS = '/api/v5/rfq/cancel-batch-rfqs'
277 | CANCEL_ALL_RSQS = '/api/v5/rfq/cancel-all-rfqs'
278 | EXECUTE_QUOTE = '/api/v5/rfq/execute-quote'
279 | CREATE_QUOTE = '/api/v5/rfq/create-quote'
280 | CANCEL_QUOTE = '/api/v5/rfq/cancel-quote'
281 | CANCEL_BATCH_QUOTES = '/api/v5/rfq/cancel-batch-quotes'
282 | CANCEL_ALL_QUOTES = '/api/v5/rfq/cancel-all-quotes'
283 | GET_RFQS = '/api/v5/rfq/rfqs'
284 | GET_QUOTES = '/api/v5/rfq/quotes'
285 | GET_RFQ_TRADES = '/api/v5/rfq/trades'
286 | GET_PUBLIC_TRADES = '/api/v5/rfq/public-trades'
287 | RFQ_CANCEL_ALL_AFTER = '/api/v5/rfq/cancel-all-after'
288 | MARKET_INSTRUMENT_SETTINGS = '/api/v5/rfq/maker-instrument-settings'
289 | MMP_RESET = '/api/v5/rfq/mmp-reset'
290 | MMP_CONFIG = '/api/v5/rfq/mmp-config'
291 | MMP_CONF = '/api/v5/rfq/mmp-config'
292 | MMP_CONFIG = '/api/v5/account/mmp-config'
293 | MMP = '/api/v5/account/mmp-config'
294 | SET_ACCOUNT_LEVEL = '/api/v5/account/set-account-level'
295 | GET_MAKER_INSTRUMENT_SETTINGS = '/api/v5/rfq/maker-instrument-settings'
296 | POSITION_BUILDER = '/api/v5/account/position-builder'
297 |
298 | # tradingBot
299 | GRID_ORDER_ALGO = '/api/v5/tradingBot/grid/order-algo'
300 | GRID_AMEND_ORDER_ALGO = '/api/v5/tradingBot/grid/amend-order-algo'
301 | GRID_STOP_ORDER_ALGO = '/api/v5/tradingBot/grid/stop-order-algo'
302 | GRID_ORDERS_ALGO_PENDING = '/api/v5/tradingBot/grid/orders-algo-pending'
303 | GRID_ORDERS_ALGO_HISTORY = '/api/v5/tradingBot/grid/orders-algo-history'
304 | GRID_ORDERS_ALGO_DETAILS = '/api/v5/tradingBot/grid/orders-algo-details'
305 | GRID_SUB_ORDERS = '/api/v5/tradingBot/grid/sub-orders'
306 | GRID_POSITIONS = '/api/v5/tradingBot/grid/positions'
307 | GRID_WITHDRAW_INCOME = '/api/v5/tradingBot/grid/withdraw-income'
308 | GRID_COMPUTE_MARGIN_BALANCE = '/api/v5/tradingBot/grid/compute-margin-balance'
309 | GRID_MARGIN_BALANCE = '/api/v5/tradingBot/grid/margin-balance'
310 | GRID_AI_PARAM = '/api/v5/tradingBot/grid/ai-param'
311 | GRID_ADJUST_INVESTMETN = '/api/v5/tradingBot/grid/adjust-investment'
312 | GRID_QUANTITY = '/api/v5/tradingBot/grid/grid-quantity'
313 | SIGNAL_ORDERS_ALGO_PENDING = '/api/v5/tradingBot/signal/orders-algo-pending'
314 | SIGNAL_CLOSE_POSITION = '/api/v5/tradingBot/signal/close-position'
315 |
316 | # finance
317 | STAKING_DEFI_OFFERS = '/api/v5/finance/staking-defi/offers'
318 | STAKING_DEFI_PURCHASE = '/api/v5/finance/staking-defi/purchase'
319 | STAKING_DEFI_REDEEM = '/api/v5/finance/staking-defi/redeem'
320 | STAKING_DEFI_CANCEL = '/api/v5/finance/staking-defi/cancel'
321 | STAKING_DEFI_ORDERS_ACTIVE = '/api/v5/finance/staking-defi/orders-active'
322 | STAKING_DEFI_ORDERS_HISTORY = '/api/v5/finance/staking-defi/orders-history'
323 | STAKING_DEFI_ETH_PURCASE = '/api/v5/finance/staking-defi/eth/purchase'
324 | STAKING_DEFI_ETH_REDEEM = '/api/v5/finance/staking-defi/eth/redeem'
325 | STAKING_DEFI_ETH_BALANCE ='/api/v5/finance/staking-defi/eth/balance'
326 | STAKING_DEFI_ETH_P_R_HISTORY= '/api/v5/finance/staking-defi/eth/purchase-redeem-history'
327 | STAKING_DEFI_ETH_APY_HISTORY = '/api/v5/finance/staking-defi/eth/apy-history'
328 | SAVINGS_LENDING_RATE_SUM = '/api/v5/finance/savings/lending-rate-summary'
329 | SAVINGS_LENDING_RATE_HIS = '/api/v5/finance/savings/lending-rate-history'
330 | FIXED_LOAN_LENDING_OFFERS = '/api/v5/finance/fixed-loan/lending-offers'
331 | FIXED_LOAN_LENDING_APY_HIS = '/api/v5/finance/fixed-loan/lending-apy-history'
332 | FIXED_LOAN_PENDING_LENDING_VOL = '/api/v5/finance/fixed-loan/pending-lending-volume'
333 | FIXED_LOAN_LENDING_ORDER = '/api/v5/finance/fixed-loan/lending-order'
334 | FIXED_LOAN_AMEND_LENDING_ORDER = '/api/v5/finance/fixed-loan/amend-lending-order'
335 | FIXED_LOAN_LENDING_ORDERS_LIST = '/api/v5/finance/fixed-loan/lending-orders-list'
336 | FIXED_LOAN_LENDING_SUB_ORDERS = '/api/v5/finance/fixed-loan/lending-sub-orders'
337 | STAKING_DEFI_ETH_PRODUCT_INFO = '/api/v5/finance/staking-defi/eth/product-info'
338 |
339 |
340 |
341 |
342 | # copytrading
343 | CURRENT_SUBPOSITIONS = '/api/v5/copytrading/current-subpositions'
344 | SUBPOSITIONS_HISTORY = '/api/v5/copytrading/subpositions-history'
345 | COPYTRADING_ALGO_ORDER = '/api/v5/copytrading/algo-order'
346 | COPYTRADING_CLOSE_POS = '/api/v5/copytrading/close-subposition'
347 | COPYTRADING_INSTRUMENTS = '/api/v5/copytrading/instruments'
348 | COPYTRADING_SET_INSTRUMENTS = '/api/v5/copytrading/set-instruments'
349 | PROFIT_SHARING_DETAILS = '/api/v5/copytrading/profit-sharing-details'
350 | TOTAL_PROFIT_SHARING = '/api/v5/copytrading/total-profit-sharing'
351 | UNREALIZED_PROFIT_SHARING_DETAILS = '/api/v5/copytrading/unrealized-profit-sharing-details'
352 | FIRST_COPY_SETTINGS = '/api/v5/copytrading/first-copy-settings'
353 | AMEND_COPY_SETTINGS = '/api/v5/copytrading/amend-copy-settings'
354 | STOP_COPY_SETTINGS = 'api/v5/copytrading/stop-copy-trading'
355 | COPY_SETTINGS = 'api/v5/copytrading/copy-trading'
356 | BATCH_LEVERAGE_INF = '/api/v5/copytrading/batch-leverage-info'
357 | BATCH_SET_LEVERAGE = '/api/v5/copytrading/batch-set-leverage'
358 | CURRENT_LEAD_TRADERS = '/api/v5/copytrading/current-lead-traders'
359 | LEAD_TRADERS_HISTORY = '/api/v5/copytrading/lead-traders-history'
360 | PUBLIC_LEAD_TRADERS = '/api/v5/copytrading/public-lead-traders'
361 | PUBLIC_WEEKLY_PNL = '/api/v5/copytrading/public-weekly-pnl'
362 | PUBLIC_PNL = '/api/v5/copytrading/public-pnl'
363 | PUBLIC_STATS = '/api/v5/copytrading/public-stats'
364 | PUBLIC_PRE_CURR = '/api/v5/copytrading/public-preference-currency'
365 | PUBLIC_CURR_SUBPOS = '/api/v5/copytrading/public-current-subpositions'
366 | PUBLIC_SUBPOS_HIS = '/api/v5/copytrading/public-subpositions-history'
367 | APP_LEA_TRAD = '/api/v5/copytrading/apply-lead-trading'
368 | STOP_LEA_TRAD = '/api/v5/copytrading/stop-lead-trading'
369 | AMEDN_PRO_SHAR_RATIO = '/api/v5/copytrading/amend-profit-sharing-ratio'
370 | LEAD_TRADERS = '/api/v5/copytrading/lead-traders'
371 | WEEKLY_PNL = '/api/v5/copytrading/weekly-pnl'
372 | PNL = '/api/v5/copytrading/pnl'
373 | STATS = '/api/v5/copytrading/stats'
374 | PRE_CURR = '/api/v5/copytrading/preference-currency'
375 | PRE_CURR_SUNPOSITION = '/api/v5/copytrading/performance-current-subpositions'
376 | PRE_SUNPOSITION_HISTORY = '/api/v5/copytrading/performance-subpositions-history'
377 | COPY_TRADERS = '/api/v5/copytrading/copy-traders'
378 | PUB_COPY_TRADERS = '/api/v5/copytrading/public-copy-traders'
379 | CONFIG = '/api/v5/copytrading/config'
380 | TOTAL_UNREA_PRO_SHAR = '/api/v5/copytrading/total-unrealized-profit-sharing'
381 |
382 |
383 | # recurring
384 | RECURRING_ORDER_ALGO = '/api/v5/tradingBot/recurring/order-algo'
385 | RECURRING_AMEND_ORDER_ALGO = '/api/v5/tradingBot/recurring/amend-order-algo'
386 | RECURRING_STOP_ORDER_ALGO = '/api/v5/tradingBot/recurring/stop-order-algo'
387 | RECURRING_ORDER_ALGO_PENDING = '/api/v5/tradingBot/recurring/orders-algo-pending'
388 | RECURRING_ORDER_ALGO_HISTORY = '/api/v5/tradingBot/recurring/orders-algo-history'
389 | RECURRING_ORDER_ALGO_DETAILS = '/api/v5/tradingBot/recurring/orders-algo-details'
390 | RECURRING_SUB_ORDERS = '/api/v5/tradingBot/recurring/sub-orders'
391 |
392 | # status
393 | STATUS = '/api/v5/system/status'
394 | GET_ANNOUNCEMENTS = '/api/v5/support/announcements'
395 | GET_ANNOUNCEMENTS_TYPES = '/api/v5/support/announcement-types'
396 |
--------------------------------------------------------------------------------
/okx/exceptions.py:
--------------------------------------------------------------------------------
1 | # coding=utf-8
2 |
3 |
4 | class OkxAPIException(Exception):
5 |
6 | def __init__(self, response):
7 | print(response.text + ', ' + str(response.status_code))
8 | self.code = 0
9 | try:
10 | json_res = response.json()
11 | except ValueError:
12 | self.message = 'Invalid JSON error message from Okx: {}'.format(response.text)
13 | else:
14 | if "code" in json_res.keys() and "msg" in json_res.keys():
15 | self.code = json_res['code']
16 | self.message = json_res['msg']
17 | else:
18 | self.code = 'None'
19 | self.message = 'System error'
20 |
21 | self.status_code = response.status_code
22 | self.response = response
23 | self.request = getattr(response, 'request', None)
24 |
25 | def __str__(self): # pragma: no cover
26 | return 'API Request Error(code=%s): %s' % (self.code, self.message)
27 |
28 |
29 | class OkxRequestException(Exception):
30 |
31 | def __init__(self, message):
32 | self.message = message
33 |
34 | def __str__(self):
35 | return 'OkxRequestException: %s' % self.message
36 |
37 |
38 | class OkxParamsException(Exception):
39 |
40 | def __init__(self, message):
41 | self.message = message
42 |
43 | def __str__(self):
44 | return 'OkxParamsException: %s' % self.message
45 |
--------------------------------------------------------------------------------
/okx/status_api.py:
--------------------------------------------------------------------------------
1 | from .client import Client
2 | from .consts import *
3 |
4 |
5 | class StatusAPI(Client):
6 | def __init__(self, api_key, api_secret_key, passphrase, use_server_time=False, flag='1'):
7 | Client.__init__(self, api_key, api_secret_key, passphrase, use_server_time, flag)
8 |
9 | def status(self, state=''):
10 | params = {'state': state}
11 | return self._request_with_params(GET, STATUS, params)
12 |
13 | # GET /api/v5/support/announcements
14 | def get_announcements(self, annType = '', page = ''):
15 | params = {'annType': annType, 'page': page}
16 | return self._request_with_params(GET, GET_ANNOUNCEMENTS, params)
17 |
18 | # GET /api/v5/support/announcement-types
19 | def get_announcements_types(self):
20 | params = {}
21 | return self._request_with_params(GET, GET_ANNOUNCEMENTS_TYPES, params)
--------------------------------------------------------------------------------
/okx/subAccount_api.py:
--------------------------------------------------------------------------------
1 | from .client import Client
2 | from .consts import *
3 |
4 |
5 | class SubAccountAPI(Client):
6 | def __init__(self, api_key, api_secret_key, passphrase, use_server_time=False, flag='1'):
7 | Client.__init__(self, api_key, api_secret_key, passphrase, use_server_time, flag)
8 |
9 | def balances(self, subAcct):
10 | params = {"subAcct": subAcct}
11 | return self._request_with_params(GET, BALANCE, params)
12 |
13 | def bills(self, ccy='', type='', subAcct='', after='', before='', limit=''):
14 | params = {"ccy": ccy, 'type': type, 'subAcct': subAcct, 'after': after, 'before': before, 'limit': limit}
15 | return self._request_with_params(GET, BILLs, params)
16 | # 移除此接口
17 | def delete(self, pwd, subAcct, apiKey):
18 | params = {'pwd': pwd, 'subAcct': subAcct, 'apiKey': apiKey}
19 | return self._request_with_params(POST, DELETE, params)
20 | # 移除此接口
21 | def reset(self, pwd, subAcct, label, apiKey, perm, ip=''):
22 | params = {'pwd': pwd, 'subAcct': subAcct, 'label': label, 'apiKey': apiKey, 'perm': perm, 'ip': ip}
23 | return self._request_with_params(POST, RESET, params)
24 | # 移除此接口
25 | def create(self, pwd, subAcct, label, Passphrase, perm='', ip=''):
26 | params = {'pwd': pwd, 'subAcct': subAcct, 'label': label, 'Passphrase': Passphrase, 'perm': perm, 'ip': ip}
27 | return self._request_with_params(POST, CREATE, params)
28 | # 移除此接口
29 | def watch(self, subAcct,apiKey=''):
30 | params = {'subAcct': subAcct,'apiKey':apiKey}
31 | return self._request_with_params(GET, WATCH, params)
32 |
33 | def view_list(self, enable='', subAcct='', after='', before='', limit='',uid=''):
34 | params = {'enable': enable, 'subAcct': subAcct, 'after': after,
35 | 'before': before, 'limit': limit,'uid':uid}
36 | return self._request_with_params(GET, VIEW_LIST, params)
37 |
38 | def subAccount_transfer(self, ccy, amt, froms, to, fromSubAccount,toSubAccount,loanTrans='',omitPosRisk=''):
39 | params = {'ccy': ccy, 'amt': amt, 'from': froms, 'to': to, 'fromSubAccount': fromSubAccount, 'toSubAccount': toSubAccount,'loanTrans':loanTrans,'omitPosRisk':omitPosRisk}
40 | return self._request_with_params(POST, SUBACCOUNT_TRANSFER, params)
41 |
42 | def entrust_subaccount_list(self, subAcct):
43 | params = {'subAcct': subAcct}
44 | return self._request_with_params(GET, ENTRUST_SUBACCOUNT_LIST, params)
45 |
46 | def modify_apikey(self, subAcct, apiKey, label, perm, ip):
47 | params = {'subAcct': subAcct, 'apiKey': apiKey, 'label': label, 'perm': perm, 'ip': ip}
48 | return self._request_with_params(POST, MODIFY_APIKEY, params)
49 |
50 | def partner_if_rebate(self, apiKey = ''):
51 | params = {'apiKey': apiKey}
52 | return self._request_with_params(GET, PARTNER_IF_REBATE, params)
53 |
54 | # 获取子账户最大可转余额 max-withdrawal
55 | def max_withdrawal(self, subAcct, ccy = ''):
56 | params = {'subAcct': subAcct,'ccy': ccy,}
57 | return self._request_with_params(GET, MAX_WITHDRAW, params)
58 |
59 | # 查询托管子账户转账记录 managed-subaccount-bills
60 | def managed_subaccount_bills(self,ccy='',type='',subAcct='',subUid='',after='',before='',limit=''):
61 | params = {'ccy': ccy,'type': type,'subAcct': subAcct,'subUid': subUid,'after': after,'before': before,
62 | 'limit': limit,}
63 | return self._request_with_params(GET,SUB_BILLS,params)
64 |
--------------------------------------------------------------------------------
/okx/utils.py:
--------------------------------------------------------------------------------
1 | import hmac
2 | import base64
3 | import time
4 | import datetime
5 | from . import consts as c
6 |
7 |
8 | def sign(message, secretKey):
9 | mac = hmac.new(bytes(secretKey, encoding='utf8'), bytes(message, encoding='utf-8'), digestmod='sha256')
10 | d = mac.digest()
11 | return base64.b64encode(d)
12 |
13 |
14 | def pre_hash(timestamp, method, request_path, body):
15 | return str(timestamp) + str.upper(method) + request_path + body
16 |
17 |
18 | def get_header(api_key, sign, timestamp, passphrase, flag):
19 | header = dict()
20 | header[c.CONTENT_TYPE] = c.APPLICATION_JSON
21 | header[c.OK_ACCESS_KEY] = api_key
22 | header[c.OK_ACCESS_SIGN] = sign
23 | header[c.OK_ACCESS_TIMESTAMP] = str(timestamp)
24 | header[c.OK_ACCESS_PASSPHRASE] = passphrase
25 | header['x-simulated-trading'] = flag
26 | return header
27 |
28 |
29 | def parse_params_to_str(params):
30 | url = '?'
31 | for key, value in params.items():
32 | url = url + str(key) + '=' + str(value) + '&'
33 | return url[0:-1]
34 |
35 |
36 | def get_timestamp():
37 | now = datetime.datetime.utcnow()
38 | t = now.isoformat("T", "milliseconds")
39 | return t + "Z"
40 |
41 |
42 | def signature(timestamp, method, request_path, body, secret_key):
43 | if str(body) == '{}' or str(body) == 'None':
44 | body = ''
45 | message = str(timestamp) + str.upper(method) + request_path + str(body)
46 |
47 | mac = hmac.new(bytes(secret_key, encoding='utf8'), bytes(message, encoding='utf-8'), digestmod='sha256')
48 | d = mac.digest()
49 |
50 | return base64.b64encode(d)
51 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | ccxt==4.4.86
2 | requests==2.27.1
3 |
--------------------------------------------------------------------------------