├── .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 | 73 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 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 | --------------------------------------------------------------------------------