v4.5.38: 实时数据查询硬规则(回复前必查)+ check_account.py封装

This commit is contained in:
2026-07-17 22:14:19 +08:00
parent 629ac197de
commit 533c342305
55 changed files with 5437 additions and 599 deletions
+159 -80
View File
@@ -34,122 +34,75 @@ GET /api/v5/account/config
}
```
**切换模式**(需要主账户权限):
```python
POST /api/v5/account/set-position-mode
{"posMode": "long_short_mode"} # 或 "net_mode"
```
---
## 2. OCO订单合并(加仓场景)
**问题**:加仓后,旧OCO只覆盖旧仓位,新OCO只覆盖新仓位,导致多个OCO并存。
**错误示例**
- 持仓5张,OCO(sell 5, SL=1660, TP=1746)
- 加仓1张 → 持仓6张
- 新建OCO(sell 1, SL=1666.8, TP=1775.1)
- 结果:2个OCO并存,旧OCO触发只平5张,剩1张单独走
**正确流程**
1. 查现有OCO`GET /api/v5/trade/orders-algo-pending?ordType=oco`
2. 找到同instId的旧OCO algoId
3. 删除旧OCO`POST /api/v5/trade/cancel-algo``[{instId, algoId}]`
4. 创建新OCO覆盖全部持仓
**验证**
```bash
# 查pending OCO
curl -X GET "https://www.okx.com/api/v5/trade/orders-algo-pending?ordType=oco" \
-H "OK-ACCESS-KEY: $KEY" ...
# 应该只有一个OCO per instId
```
---
## 3. 补推信号必须先查持仓
**场景**:模型断线后补推积压信号。
**错误做法**:直接用历史信号数据推送推荐(如"4,290 ETH加仓到4,455")。
**正确做法**
1. 先查当前持仓:`GET /api/v5/account/positions`
2. 再查当前algo orders`GET /api/v5/trade/orders-algo-pending?ordType=oco`
3. 用**当前持仓数据**而非历史信号数据生成推荐
**案例**
- 历史信号说"4,290 ETH"
- 实际持仓已是5张(可能中间已有多次变动)
- 用历史数据推"加仓到4,455"是错误的
---
## 4. 遍历查询algo orders
**问题**`ordType` 参数不能组合查询,需逐个类型查。
## 3. 条件单API参数(2026-07-05新增)
**Trigger订单(做T用)**
```python
for algo_type in ["oco", "conditional", "trigger", "move_order_stop"]:
result = okx_get(f"/api/v5/trade/orders-algo-pending?ordType={algo_type}")
# 处理 result["data"]
okx_post('/api/v5/trade/order-algo', {
"instId": "ETH-USDT-SWAP",
"tdMode": "cross",
"side": "buy",
"ordType": "trigger", # 用trigger不是conditional
"sz": "4",
"triggerPx": "1770",
"triggerPxType": "last",
"orderPx": "-1" # 参数名是orderPx不是ordPx
})
```
**注意**某些类型可能返回错误(如账户未开通该功能),需忽略错误继续。
**关键错误**
-`"ordPx": "-1"` → 报错`50014: Parameter orderPx can not be empty`
- ❌ 加`"reduceOnly": "true"` → 报错`51205: Reduce Only is not available`
- ❌ 用`conditional`类型 → SL触发价不能低于当前价
**Trigger vs Conditional vs OCO**
| 类型 | 用途 | 触发方向 |
|------|------|----------|
| trigger | 价格到任意方向触发 | 任意 |
| conditional | 止损/止盈 | SL不能低于现价 |
| oco | 同时设TP+SL | 双腿 |
详见 `references/okx-trigger-orders.md`
---
## 5. 密码中含特殊字符
## 4. OCO的sz必须是lot_sz的整数倍
**问题**`OKX_PASSPHRASE``$` 等特殊字符时,bash 会尝试变量展开
**问题**加仓后position=14.77张,但OCO设置sz=14.77时报错 `"Order quantity must be a multiple of the lot size"`
**错误**`export OKX_PASSPHRASE=mikeOkxID$1``$1` 展开为空
**正确**
```bash
export OKX_PASSPHRASE='mikeOkxID$1' # 单引号
```
**或从文件读取**
**解决**OCO的sz向下取整到lot_sz
```python
with open("~/.bashrc", "r") as f:
for line in f:
if "OKX_PASSPHRASE" in line:
passphrase = line.split("=", 1)[1].strip().strip('"').strip("'")
oco_sz = int(position_contracts) # 14.77 → 14
```
---
## 6. 凭证变量名:OKX_SECRET(不是OKX_SECRET_KEY
## 5. 凭证变量名:OKX_SECRET(不是OKX_SECRET_KEY
bashrc里实际变量名是 `OKX_SECRET`,不是 `OKX_SECRET_KEY`
**脚本内部**`load_credentials()``OKX_\w+` 正则匹配,自动兼容,不受影响。
**手动ccxt初始化**agent写临时Python时):
```python
# ❌ 错误 — 会 KeyError
creds['OKX_SECRET_KEY']
# ✅ 正确
creds['OKX_SECRET']
# ✅ 兼容写法
secret = creds.get('OKX_SECRET', '') or creds.get('OKX_SECRET_KEY', '')
```
**三个变量**`OKX_API_KEY``OKX_SECRET``OKX_PASSPHRASE`
---
## 7. --execute 必须同时带 --rec-json
## 6. --execute 必须同时带 --rec-json
脚本代码 `if args.execute and args.rec_json:` 要求两个参数同时存在。
**错误**:只传 `--execute` 不传 `--rec-json` → 静默跳过执行,fall through到推荐流程
**正确两步流程**
```bash
# 第1步:获取推荐JSON
@@ -161,7 +114,7 @@ python3 okx_position_advisor.py --symbol HYPE --side long --leverage 10 --execut
---
## 8. 余额为零时ZeroDivisionError
## 7. 余额为零时ZeroDivisionError
**问题**`recommend_position()` 函数在计算 `margin_pct = total_margin / acct_info['usdt_free'] * 100` 时,如果 `usdt_free=0`(用户满仓),会抛出 `ZeroDivisionError`
@@ -172,4 +125,130 @@ if acct_info['usdt_free'] < 0.01:
sys.exit(0)
```
**format_signal.py 已加 try/except 处理此场景。**
---
## 8. 密码中含特殊字符
**问题**`OKX_PASSPHRASE``$` 等特殊字符时,bash 会尝试变量展开。
**正确**:从文件读取:
```python
with open("~/.bashrc", "r") as f:
for line in f:
if "OKX_PASSPHRASE" in line:
passphrase = line.split("=", 1)[1].strip().strip('"').strip("'")
```
---
## 9. 遍历查询algo orders
**问题**`ordType` 参数不能组合查询,需逐个类型查。
```python
for algo_type in ["oco", "conditional", "trigger", "move_order_stop"]:
result = okx_get(f"/api/v5/trade/orders-algo-pending?ordType={algo_type}")
# 处理 result["data"]
```
---
## 10. raw API posSide显示"net"
**问题**net_mode下,`/api/v5/account/positions` 返回的 `posSide` 字段是 `"net"` 而非 `"long"`/`"short"`
**解决**:用 `pos` 字段判断方向:
```python
side = "long" if float(pos) >= 0 else "short"
```
---
## 11. --close是全平,部分平仓需手动下单(2026-07-06新增)
**问题**advisor脚本的 `--close` 参数会平掉该币种**全部仓位**,无法指定平仓数量。
**部分平仓方法**
```python
from okx_position_advisor import load_credentials, create_exchange
creds = load_credentials()
exchange = create_exchange(creds)
# 卖出指定张数(平多)
order = exchange.create_order(
symbol='ETH/USDT:USDT',
type='market',
side='sell', # sell=平多, buy=平空
amount=4, # 指定张数
params={'tdMode': 'cross'}
)
```
**减仓百分比计算**
```python
import math
current_contracts = 14.09
reduce_pct = 0.30 # 减三成
close_contracts = math.floor(current_contracts * reduce_pct) # 4张
```
**⚠️ 注意**ccxt的`create_order`直接下单,不会自动清理OCO。部分平仓后,旧OCO可能覆盖已不存在的仓位(OKX会自动处理,但最好手动检查)。
---
## 12. 直接curl调OKX API返回403但ccxt正常(2026-07-06新增)
**问题**:用curl+proxy直接调OKX REST API返回403 Forbidden,但通过ccxt(同样走proxy)正常工作。
**可能原因**
- OKX API key绑定了IP白名单,ccxt的请求头与curl不同
- ccxt自动处理了某些认证细节(如nonce、签名格式)
**解决**:所有API操作统一用ccxt,不要手写curl。只有ccxt超时时才回退到curl。
**ccxt标准用法**
```python
from okx_position_advisor import load_credentials, create_exchange
creds = load_credentials()
exchange = create_exchange(creds)
exchange.timeout = 30000 # 30s超时
# 查持仓
positions = exchange.fetch_positions(['ETH/USDT:USDT'])
active = [p for p in positions if abs(float(p.get('contracts', 0))) > 0]
# 查余额
bal = exchange.fetch_balance()
free_usdt = bal.get('free', {}).get('USDT', 0)
# 下单
order = exchange.create_order('ETH/USDT:USDT', 'market', 'buy', 4, {'tdMode': 'cross'})
```
---
## 13. advisor脚本的acct_free和contracts可能不准(2026-07-06新增)
**问题**`okx_position_advisor.py --json` 返回的 `acct_free``contracts` 字段可能与实际不符。
**实测案例**
- advisor返回:`acct_free=0.97, contracts=0.04`
- 实际ccxt查:持仓14.09张ETH多,可用0 USDT(满仓)
**原因**advisor的`recommend_position()`内部计算逻辑可能截断或取整异常,且`acct_free`只反映当时快照(可能已过时)。
**解决**:查持仓和余额必须用ccxt直接查询:
```python
positions = exchange.fetch_positions()
bal = exchange.fetch_balance()
active = [p for p in positions if abs(float(p.get('contracts', 0))) > 0]
for p in active:
side = '' if float(p['contracts']) > 0 else ''
print(f"{p['symbol']}: {p['contracts']}{side} | 均价: {p.get('entryPrice','-')} | 浮盈: {p.get('unrealizedPnl','-')}")
print(f"可用: {bal.get('free',{}).get('USDT',0)} USDT")
```
**advisor脚本用途**
- ✅ 算TP/SL/ATR/性价比
- ❌ 查实际持仓数量(不准)
- ❌ 查可用余额(不准)