fix: OKX options buy/close orders with tick alignment and reduceOnly

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-07-07 08:52:18 +08:00
parent ae0c44e20d
commit 05586242f0
6 changed files with 269 additions and 65 deletions
+31 -20
View File
@@ -59,6 +59,8 @@ def install_options_trading(app: Flask, repo_root: str, app_module: Any) -> None
def _build_cfg(app_module: Any) -> dict[str, Any]:
from lib.exchange.okx_options_lib import (
_pos_side_from_position,
_safe_float,
build_option_chain,
estimate_usdt_to_usdc,
execute_convert,
@@ -67,6 +69,7 @@ def _build_cfg(app_module: Any) -> dict[str, Any]:
format_position_row,
options_api_ready,
place_option_limit_order,
place_option_market_order,
quote_option_contract,
transfer_ccy,
)
@@ -91,6 +94,7 @@ def _build_cfg(app_module: Any) -> dict[str, Any]:
"build_option_chain": build_option_chain,
"quote_option_contract": quote_option_contract,
"place_option_limit_order": place_option_limit_order,
"place_option_market_order": place_option_market_order,
"fetch_option_positions": fetch_option_positions,
"fetch_options_balances": fetch_options_balances,
"format_position_row": format_position_row,
@@ -220,6 +224,7 @@ def register_options_routes(app: Flask, cfg: dict[str, Any]) -> None:
if not sizing.get("ok"):
return jsonify({"ok": False, "msg": sizing.get("msg") or "张数计算失败", "sizing": sizing})
sheets = int(sizing["sheets"])
tick_sz = q.get("tick_sz")
order = cfg["place_option_limit_order"](
ex,
inst_id=inst_id,
@@ -227,6 +232,7 @@ def register_options_routes(app: Flask, cfg: dict[str, Any]) -> None:
sheets=sheets,
price=float(ask),
td_mode=cfg["td_mode"],
tick_sz=tick_sz,
)
if not order.get("ok"):
return jsonify(order)
@@ -291,38 +297,43 @@ def register_options_routes(app: Flask, cfg: dict[str, Any]) -> None:
pos = next((p for p in raw_positions if str(p.get("instId")) == inst_id), None)
if not pos:
return jsonify({"ok": False, "msg": "未找到持仓"})
avail = float(pos.get("availPos") or pos.get("pos") or 0)
close_sheets = int(sheets) if sheets else int(abs(avail))
avail = _safe_float(pos.get("availPos"))
if avail is None or avail <= 0:
avail = abs(_safe_float(pos.get("pos")) or 0)
close_sheets = int(sheets) if sheets else int(avail)
if close_sheets < 1:
return jsonify({"ok": False, "msg": "可平张数不足"})
td_mode = str(pos.get("mgnMode") or cfg["td_mode"])
pos_side = _pos_side_from_position(pos) or "net"
tick_sz = q.get("tick_sz")
if use_market:
try:
resp = ex.private_post_trade_order(
{
"instId": inst_id,
"tdMode": cfg["td_mode"],
"side": "sell",
"ordType": "market",
"sz": str(close_sheets),
}
)
data_rows = (resp or {}).get("data") or []
if not data_rows or str(data_rows[0].get("sCode")) != "0":
return jsonify({"ok": False, "msg": data_rows[0].get("sMsg") if data_rows else "市价平仓失败"})
order = {"ok": True, "data": data_rows[0]}
except Exception as e:
return jsonify({"ok": False, "msg": str(e)})
order = cfg["place_option_market_order"](
ex,
inst_id=inst_id,
side="sell",
sheets=close_sheets,
td_mode=td_mode,
reduce_only=True,
pos_side=pos_side,
)
if not order.get("ok"):
return jsonify(order)
else:
close_px = float(bid)
order = cfg["place_option_limit_order"](
ex,
inst_id=inst_id,
side="sell",
sheets=close_sheets,
price=float(bid),
td_mode=cfg["td_mode"],
price=close_px,
td_mode=td_mode,
tick_sz=tick_sz,
reduce_only=True,
pos_side=pos_side,
)
if not order.get("ok"):
return jsonify(order)
bid = order.get("px", close_px)
prem_recv = total_premium(float(bid or 0), close_sheets * float(q.get("ct_mult") or 0.01))
conn = cfg["get_db"]()
try:
+2 -2
View File
@@ -5,7 +5,7 @@
{% if not options_enabled %}
<div class="flash" style="margin-bottom:12px">期权 API 未启用:请在 <code>crypto_monitor_okx/.env</code> 设置 <code>OKX_OPTIONS_ENABLED=true</code> 及主账户 <code>OKX_OPTIONS_API_*</code>,然后 <code>pm2 restart crypto_okx --update-env</code></div>
{% endif %}
<p class="muted options-hint">资金账户兑换 USDT→USDC 后,划转到交易账户即可买入。报价单位为每 1 ETH/BTC1 张 = 0.01 ETH/BTC。</p>
<p class="muted options-hint">资金账户兑换 USDT→USDC 后,划转到交易账户即可买入。报价单位为每 1 ETH/BTC1 张 = 0.01 ETH/BTC。表格中点「买入」直接下单;或点「选择」后在下方确认张数再买入。</p>
<div class="options-funds-grid">
<div class="options-funds-col">
@@ -128,4 +128,4 @@
</div>
</div>
</div>
<script src="/static/options_panel.js?v=1"></script>
<script src="/static/options_panel.js?v=2"></script>