""" 手动 raw REST OKX 下单模板 (用于 advisor execute 失败/proxy 抽风时手动救火) 用法: 1. 复制本文件到 /tmp/order_.py 2. 修改 body 字段 (instId/side/sz/ordType/tdMode/posSide/reduceOnly) 3. python3 /tmp/order_.py 注意事项: - 用 127.0.0.1:7890 proxy (国内 VPS 必走, GFW 屏蔽) - 凭证从 ~/.bashrc 读 (export OKX_API_KEY/SECRET/PASSPHRASE) - 永不复用 cost_performance / advisor 的 ccxt 路径 (proxy 抽风时 SSL 不稳) - 只在 process_signal 走 raw REST 失败时手动救火, 不要做"测试" - 下单成功后必须手记 position_history (audit trail, 防 ghost close) - 调杠杆失败 (OKX 59108 = 账户余额不足) 不要无限重试 已知踩坑币种 (advisor execute 隐性失败): SPCX / 1000PEPE / MU / XAU / BTC / SKHYNIX """ import json, time, hmac, hashlib, base64, requests def okx_post(p, body, t=15): creds = open('/home/openclaw/.bashrc').read() k = s = pw = None for line in creds.splitlines(): if line.startswith('export OKX_API_KEY='): k = line.split('=', 1)[1].strip().strip('"').strip("'") elif line.startswith('export OKX_SECRET='): s = line.split('=', 1)[1].strip().strip('"').strip("'") elif line.startswith('export OKX_PASSPHRASE='): pw = line.split('=', 1)[1].strip().strip('"').strip("'") body_str = json.dumps(body) ts = time.strftime('%Y-%m-%dT%H:%M:%S.000Z', time.gmtime()) msg = ts + 'POST' + p + body_str sig = base64.b64encode(hmac.new(s.encode(), msg.encode(), hashlib.sha256).digest()).decode() h = { 'OK-ACCESS-KEY': k, 'OK-ACCESS-SIGN': sig, 'OK-ACCESS-TIMESTAMP': ts, 'OK-ACCESS-PASSPHRASE': pw, 'Content-Type': 'application/json' } px = {'http': 'http://127.0.0.1:7890', 'https': 'http://127.0.0.1:7890'} return requests.post(f'https://www.okx.com{p}', data=body_str, headers=h, proxies=px, timeout=t).json() # ===== 常用下单模板 ===== def open_long(inst_id, sz): """开多 (跟单信号方向=做多)""" body = {'instId': inst_id, 'tdMode': 'cross', 'side': 'buy', 'posSide': 'net', 'ordType': 'market', 'sz': str(sz)} return okx_post('/api/v5/trade/order', body) def open_short(inst_id, sz): """开空""" body = {'instId': inst_id, 'tdMode': 'cross', 'side': 'sell', 'posSide': 'net', 'ordType': 'market', 'sz': str(sz)} return okx_post('/api/v5/trade/order', body) def close_long(inst_id, sz): """平多 (买入平仓)""" body = {'instId': inst_id, 'tdMode': 'cross', 'side': 'sell', 'posSide': 'net', 'ordType': 'market', 'sz': str(sz), 'reduceOnly': True} return okx_post('/api/v5/trade/order', body) def close_short(inst_id, sz): """平空 (买入平仓)""" body = {'instId': inst_id, 'tdMode': 'cross', 'side': 'buy', 'posSide': 'net', 'ordType': 'market', 'sz': str(sz), 'reduceOnly': True} return okx_post('/api/v5/trade/order', body) def adjust_leverage(inst_id, lev): """调杠杆 (路径不同: /api/v5/account/set-leverage)""" body = {'instId': inst_id, 'lever': str(lev), 'mgnMode': 'cross', 'posSide': 'net'} return okx_post('/api/v5/account/set-leverage', body) # ===== 实战示例 ===== if __name__ == '__main__': import sys # 用法: python3 /tmp/order_xxx.py # action: open_long / open_short / close_long / close_short / adjust_leverage if len(sys.argv) >= 4: action, inst_id, sz = sys.argv[1], sys.argv[2], sys.argv[3] if action == 'open_long': print(json.dumps(open_long(inst_id, sz), ensure_ascii=False, indent=2)) elif action == 'open_short': print(json.dumps(open_short(inst_id, sz), ensure_ascii=False, indent=2)) elif action == 'close_long': print(json.dumps(close_long(inst_id, sz), ensure_ascii=False, indent=2)) elif action == 'close_short': print(json.dumps(close_short(inst_id, sz), ensure_ascii=False, indent=2)) elif action == 'adjust_leverage': print(json.dumps(adjust_leverage(inst_id, sz), ensure_ascii=False, indent=2)) else: print(f"Unknown action: {action}") else: print("用法: python3 /tmp/order_xxx.py ") print("action: open_long / open_short / close_long / close_short / adjust_leverage") print("示例: python3 /tmp/order_btc.py close_long BTC-USDT-SWAP 1.43")