4.5 KiB
4.5 KiB
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:
GET /api/v5/account/positions?instId=SPCX-USDT-SWAPreturns empty listGET /api/v5/account/balancedetails[ccy=USDT].frozenBalunchanged- No order_id anywhere in advisor stdout
- 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
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)
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