113 lines
4.5 KiB
Markdown
113 lines
4.5 KiB
Markdown
# SPCX-USDT-SWAP Silent-Execute-Failure Repro
|
|
|
|
**Captured**: 2026-07-13
|
|
**Skill version**: okx-auto-position v4.5.4
|
|
**Severity**: High (advisor reports success, but no order fills)
|
|
|
|
## Symptom
|
|
|
|
`okx_position_advisor.py --symbol SPCX --side {short,long} --leverage 5 --execute --json` returns a full success-shaped JSON with `contracts`, `margin`, `tp_price`, `sl_price`, `cost_check.auto_execute=true` etc. However:
|
|
|
|
1. `GET /api/v5/account/positions?instId=SPCX-USDT-SWAP` returns empty list
|
|
2. `GET /api/v5/account/balance` `details[ccy=USDT].frozenBal` unchanged
|
|
3. No order_id anywhere in advisor stdout
|
|
4. process_signal pushes "✅ 已推送 | SPCX short 5x | 1.45张 | 性价比高" — but position is actually 0
|
|
|
|
## Reproduction (3 cases confirmed)
|
|
|
|
### Case 3 (2026-07-13): MU short 新开仓静默失败
|
|
- Signal: 熬鹰 MU short 334.95张 @10x @937.67, -0.15% PnL
|
|
- Advisor: 0.51张 @10x, margin=$48.78
|
|
- execute: JSON returned normally
|
|
- Verify (5s after): positions=MU-USDT-SWAP not in list, frozenBal=0
|
|
- Status: ❌ silent failure (3rd coin confirmed)
|
|
|
|
### Key finding: MU 加仓可成功但新开仓失败
|
|
- 紧跟 MU 新开仓静默失败之后,**MU 加仓信号触发 execute 成功**: 0.52张 @10x, avgPx 940.40, 真实持仓确认
|
|
- 推测: ccxt 对 "首次建仓" vs "加仓" 走不同下单路径,首次建仓时可能在 ctVal/minSz 处理上漏掉
|
|
- **MU 实战规则**: 新开仓(existing_pos=0) → 必须 raw REST 手动下单; 加仓(existing_pos>0) → 可信 advisor
|
|
|
|
### Case 1: SPCX short
|
|
- Signal: 熬鹰 SPCX short 17350张 @5x @148.59, +1.52% PnL
|
|
- Advisor: 1.45张, margin=$43.15, tp=$133.86, sl=$153.85, liq=$175.57
|
|
- execute: JSON returned normally
|
|
- Verify (3s after): positions=SPCX-USDT-SWAP not in list, frozenBal=0
|
|
- Status: ❌ silent failure
|
|
|
|
### Case 2: SPCX long
|
|
- Signal: 熬鹰 SPCX long 4514张 @2x @139.21, +0.28% PnL
|
|
- Advisor: 3.5张, margin=$48.78
|
|
- execute: JSON returned normally
|
|
- Verify (5s after): positions=SPCX-USDT-SWAP not in list, frozenBal=0
|
|
- Status: ❌ silent failure (second time same coin, same symptom)
|
|
|
|
## Root cause (hypothesized)
|
|
|
|
OKX's SPCX-USDT-SWAP contract likely has unusual min-size/step-size/lot-size rules that ccxt's `create_market_sell_order` doesn't auto-handle. The advisor's execute path silently catches the error and returns the recommendation JSON anyway (without an `order_id` field).
|
|
|
|
## Detection snippet
|
|
|
|
```python
|
|
import json,time,hmac,hashlib,base64,requests
|
|
|
|
def okx_get(p, params=None, t=15):
|
|
# ... standard raw REST GET with OKX_ACCESS_SIGN ...
|
|
return requests.get(...).json()
|
|
|
|
# 1. Run execute
|
|
import subprocess
|
|
r = subprocess.run(['python3', 'okx_position_advisor.py', '--symbol', 'SPCX',
|
|
'--side', 'short', '--leverage', '5', '--execute', '--json'],
|
|
capture_output=True, text=True, timeout=60)
|
|
exec_json = json.loads(r.stdout)
|
|
|
|
# 2. Verify within 3 seconds
|
|
time.sleep(3)
|
|
pos = okx_get('/api/v5/account/positions', {'instId': 'SPCX-USDT-SWAP'})
|
|
positions = [p for p in pos.get('data', []) if float(p.get('pos', 0) or 0) != 0]
|
|
|
|
bal = okx_get('/api/v5/account/balance')
|
|
frozen = next((float(d['frozenBal']) for d in bal['data'][0]['details'] if d['ccy'] == 'USDT'), 0)
|
|
|
|
if not positions and frozen == 0:
|
|
# SILENT FAILURE
|
|
# Manual raw REST retry
|
|
body = {
|
|
'instId': 'SPCX-USDT-SWAP',
|
|
'tdMode': 'cross',
|
|
'side': 'sell' if 'short' in exec_json.get('side', '') else 'buy',
|
|
'posSide': 'net',
|
|
'ordType': 'market',
|
|
'sz': str(exec_json['contracts']),
|
|
}
|
|
result = okx_post('/api/v5/trade/order', body)
|
|
print(json.dumps(result, indent=2))
|
|
```
|
|
|
|
## Manual fallback (when detected)
|
|
|
|
```python
|
|
body = {
|
|
'instId': 'SPCX-USDT-SWAP',
|
|
'tdMode': 'cross',
|
|
'side': 'sell', # short
|
|
'posSide': 'net',
|
|
'ordType': 'market',
|
|
'sz': '1.45', # from advisor contracts
|
|
# reduceOnly=False (initial open)
|
|
}
|
|
# POST /api/v5/trade/order
|
|
```
|
|
|
|
## When to extend this list
|
|
|
|
Add a new entry whenever a coin shows the same silent-fail pattern:
|
|
- Other small-cap contracts: SKHY, SNDK, MU USDC-margined variants
|
|
- After 2+ confirmed silent failures, treat coin as "manual-only" and skip advisor's --execute path entirely
|
|
- Instead: raw REST direct placement, skip advisor recommendation block
|
|
|
|
## Related pitfalls in SKILL.md
|
|
|
|
- "v4.5.0 新坑 process_signal/advisor `--execute` 不返回 `order_id`" — covers detection
|
|
- "v4.5.2 CCXT vs Raw REST 可靠性差距" — covers ccxt SSL/timeouts but NOT this silent-fail case
|
|
- "v4.5.4 SPCX-USDT-SWAP 自动下单静默失败" — main entry in SKILL.md |