Remove USDC product path; CoinOX is coin-margined only.

Drop USDC open/quote/swap APIs and env knobs; retarget hedge/settings copy to USDT/coin.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-10-14 12:33:59 +08:00
parent 5608173784
commit 2854d94e6b
13 changed files with 1682 additions and 2183 deletions
+2 -10
View File
@@ -120,21 +120,16 @@ OKX_OPTIONS_ENABLED=true
# OKX_OPTIONS_API_SECRET= # OKX_OPTIONS_API_SECRET=
# OKX_OPTIONS_API_PASSPHRASE= # OKX_OPTIONS_API_PASSPHRASE=
OKX_OPTIONS_ACCOUNT_LABEL=账户·期权 OKX_OPTIONS_ACCOUNT_LABEL=账户·期权
# 单笔期权本位: coin(默认,币本位+USDT买币桥) | usdc(权利金USDC;对冲仍仅USDC) # CoinOX 固定币本位(USDT 买币桥);勿再配置 USDC 权利金模式
OKX_OPTIONS_MARGIN_MODE=coin OKX_OPTIONS_MARGIN_MODE=coin
OKX_OPTIONS_TRADE_BUDGET_USDC=10
OKX_OPTIONS_BUDGET_BUFFER=0.95 OKX_OPTIONS_BUDGET_BUFFER=0.95
# 币本位:按交易户USDT×缓冲复利;上限开关默认关(靠人工转走) # 按交易户USDT×缓冲复利;上限开关默认关(靠人工转走)
OKX_OPTIONS_COIN_COMPOUND=true OKX_OPTIONS_COIN_COMPOUND=true
OKX_OPTIONS_COIN_BUDGET_USDT=10 OKX_OPTIONS_COIN_BUDGET_USDT=10
OKX_OPTIONS_COIN_MAX_USDT_ENABLED=false OKX_OPTIONS_COIN_MAX_USDT_ENABLED=false
OKX_OPTIONS_COIN_MAX_USDT=50 OKX_OPTIONS_COIN_MAX_USDT=50
# 现货买入相对权利金缓冲:1.10=多买10%;也可写 0.10。按最大可开张数×权利金×缓冲买币,不全额兑换 # 现货买入相对权利金缓冲:1.10=多买10%;也可写 0.10。按最大可开张数×权利金×缓冲买币,不全额兑换
OKX_OPTIONS_COIN_SPOT_BUY_BUFFER=1.10 OKX_OPTIONS_COIN_SPOT_BUY_BUFFER=1.10
# 全仓复利:开启时隐藏单笔预算且不可用打满;关闭后恢复单笔预算
OKX_OPTIONS_COMPOUND_FULL_ENABLED=true
OKX_OPTIONS_COMPOUND_FULL_CAP_ENABLED=false
OKX_OPTIONS_COMPOUND_FULL_CAP_USDC=300
# 交易模式三选一(热更):options=单独期权 / perp_options=永期对冲 / options_options=期期对冲 # 交易模式三选一(热更):options=单独期权 / perp_options=永期对冲 / options_options=期期对冲
# 选单独期权时隐藏对冲导航与对冲配置;选对冲时不可单独开期权,仓位按「对冲组数上限」 # 选单独期权时隐藏对冲导航与对冲配置;选对冲时不可单独开期权,仓位按「对冲组数上限」
OKX_TRADE_MODE=perp_options OKX_TRADE_MODE=perp_options
@@ -152,10 +147,8 @@ OKX_OPTIONS_TD_MODE=isolated
OKX_OPTIONS_ALLOW_MARKET_CLOSE=false OKX_OPTIONS_ALLOW_MARKET_CLOSE=false
# 目标平仓门控(目标触达后自动平才校验;比较口径均为 USDT 估值) # 目标平仓门控(目标触达后自动平才校验;比较口径均为 USDT 估值)
OKX_OPTIONS_CLOSE_GATE_MODE=premium OKX_OPTIONS_CLOSE_GATE_MODE=premium
# 全局倍数可选;留空则按本位用下方 COIN/USDC
OKX_OPTIONS_CLOSE_RECYCLE_MULT= OKX_OPTIONS_CLOSE_RECYCLE_MULT=
OKX_OPTIONS_CLOSE_RECYCLE_MULT_COIN=1.05 OKX_OPTIONS_CLOSE_RECYCLE_MULT_COIN=1.05
OKX_OPTIONS_CLOSE_RECYCLE_MULT_USDC=2
OKX_OPTIONS_CLOSE_NET_PNL_MIN_U=0 OKX_OPTIONS_CLOSE_NET_PNL_MIN_U=0
OKX_OPTIONS_CLOSE_HOLD_SECONDS=120 OKX_OPTIONS_CLOSE_HOLD_SECONDS=120
# 对冲买期权等成交超时(秒);超时撤未成交部分,未完全成交则开仓失败 # 对冲买期权等成交超时(秒);超时撤未成交部分,未完全成交则开仓失败
@@ -337,5 +330,4 @@ APP_TIMEZONE=Asia/Shanghai
# 切实盘:填 OKX_API_* , LIVE_TRADING_ENABLED=true , SIM_DEFAULT_MODE=live , 并在 OKX 白名单加云主机出口 IP # 切实盘:填 OKX_API_* , LIVE_TRADING_ENABLED=true , SIM_DEFAULT_MODE=live , 并在 OKX 白名单加云主机出口 IP
SIM_DEFAULT_MODE=sim SIM_DEFAULT_MODE=sim
SIM_INITIAL_EQUITY_USDT=10000 SIM_INITIAL_EQUITY_USDT=10000
SIM_INITIAL_USDC=0
SIM_FEE_RATE=0.0005 SIM_FEE_RATE=0.0005
+11 -11
View File
@@ -694,16 +694,16 @@
} }
const line = const line =
label + label +
" · 交易 USDC " + " · 交易 USDT " +
fmt(acct.trading_usdc, 2) + fmt(acct.trading_usdt != null ? acct.trading_usdt : acct.trading_usdc, 2) +
" · 资金 USDC " + " · 资金 USDT " +
fmt(acct.funding_usdc, 2); fmt(acct.funding_usdt != null ? acct.funding_usdt : acct.funding_usdc, 2);
const el = $("hp-opt-bal-line"); const el = $("hp-opt-bal-line");
if (el) el.textContent = line; if (el) el.textContent = line;
const fundEl = $("hp-oo-funding-usdc"); const fundEl = $("hp-oo-funding-usdc");
const tradeEl = $("hp-oo-trading-usdc"); const tradeEl = $("hp-oo-trading-usdc");
if (fundEl) fundEl.textContent = fmt(acct.funding_usdc, 2); if (fundEl) fundEl.textContent = fmt(acct.funding_usdt != null ? acct.funding_usdt : acct.funding_usdc, 2);
if (tradeEl) tradeEl.textContent = fmt(acct.trading_usdc, 2); if (tradeEl) tradeEl.textContent = fmt(acct.trading_usdt != null ? acct.trading_usdt : acct.trading_usdc, 2);
autoFillOoSheets(); autoFillOoSheets();
} }
@@ -730,7 +730,7 @@
const d = await apiJson("/api/options/transfer", { const d = await apiJson("/api/options/transfer", {
method: "POST", method: "POST",
headers: { "Content-Type": "application/json" }, headers: { "Content-Type": "application/json" },
body: JSON.stringify({ ccy: "USDC", from: from, to: to, amount: amount }), body: JSON.stringify({ ccy: "USDT", from: from, to: to, amount: amount }),
}); });
if (!d.ok) { if (!d.ok) {
setOoXferMsg(d.msg || "划转失败", "err"); setOoXferMsg(d.msg || "划转失败", "err");
@@ -1312,7 +1312,7 @@
const ct = Number(state.selected.ct_mult || 0.01); const ct = Number(state.selected.ct_mult || 0.01);
const ask = Number(state.selected.ask || 0); const ask = Number(state.selected.ask || 0);
const prem = ask * sheets * ct; const prem = ask * sheets * ct;
line.textContent = "预估权利金 ≈ " + fmt(prem, 4) + " USDC(期权账户)"; line.textContent = "预估权利金 ≈ " + fmt(prem, 4) + " 币(币本位)";
} }
function buildStraddleRows(contracts) { function buildStraddleRows(contracts) {
@@ -1561,7 +1561,7 @@
fmt(b, 4) + fmt(b, 4) +
" ≈ " + " ≈ " +
fmt(a + b, 4) + fmt(a + b, 4) +
" USDC"; " 币";
} }
function legPayload(c, sheets) { function legPayload(c, sheets) {
@@ -2051,7 +2051,7 @@
} }
const amt = Math.floor(max * 100) / 100; const amt = Math.floor(max * 100) / 100;
const label = dir === "trading_to_funding" ? "交易 → 资金" : "资金 → 交易"; const label = dir === "trading_to_funding" ? "交易 → 资金" : "资金 → 交易";
if (!window.confirm("确认全部划转?\n方向:" + label + "\n数量:" + amt + " USDC")) return; if (!window.confirm("确认全部划转?\n方向:" + label + "\n数量:" + amt + " USDT")) return;
const amtEl = $("hp-oo-xfer-amount"); const amtEl = $("hp-oo-xfer-amount");
if (amtEl) { if (amtEl) {
amtEl.removeAttribute("readonly"); amtEl.removeAttribute("readonly");
@@ -2435,7 +2435,7 @@
html += html +=
"<div><span class=\"muted\">权利金合计</span> " + "<div><span class=\"muted\">权利金合计</span> " +
fmt(p.premium_total, 4) + fmt(p.premium_total, 4) +
" USDC</div>"; " 币</div>";
html += html +=
"<div><span class=\"muted\">合约摘要</span> <code>" + "<div><span class=\"muted\">合约摘要</span> <code>" +
(d.contracts_summary || "—") + (d.contracts_summary || "—") +
-1
View File
@@ -169,7 +169,6 @@ SELECT_OPTIONS: dict[str, tuple[tuple[str, str], ...]] = {
), ),
"OKX_OPTIONS_MARGIN_MODE": ( "OKX_OPTIONS_MARGIN_MODE": (
("coin", "币本位(USDT买币桥)"), ("coin", "币本位(USDT买币桥)"),
("usdc", "USDC(USDⓈ权利金)"),
), ),
"OKX_OPTIONS_CLOSE_GATE_MODE": ( "OKX_OPTIONS_CLOSE_GATE_MODE": (
("premium", "权利金×倍数"), ("premium", "权利金×倍数"),
+19 -58
View File
@@ -27,7 +27,7 @@ _EXCHANGE_LIVE_FIELDS: dict[str, list[tuple[str, str, str]]] = {
( (
"OKX_SHOW_PERP_FUNDS", "OKX_SHOW_PERP_FUNDS",
"显示永续资金", "显示永续资金",
"默认开启;关闭后顶栏隐藏 USDT 资金账户与交易账户,总资金仅计期权 USDC 侧", "默认开启;关闭后顶栏隐藏 USDT 资金账户与交易账户",
), ),
], ],
"binance": [ "binance": [
@@ -176,63 +176,38 @@ _OPTIONS_SECTION: dict[str, Any] = {
"title": "期权账户", "title": "期权账户",
"exchanges": frozenset({"okx"}), "exchanges": frozenset({"okx"}),
"fields": [ "fields": [
("OKX_OPTIONS_ENABLED", "启用期权模块", "与永续共用上方 OKX_API_*;不再单独配置期权密钥"), ("OKX_OPTIONS_ENABLED", "启用期权模块", "与永续共用上方 OKX_API_*;CoinOX 固定币本位"),
("OKX_OPTIONS_ACCOUNT_LABEL", "期权账户备注", ""), ("OKX_OPTIONS_ACCOUNT_LABEL", "期权账户备注", ""),
( ("OKX_OPTIONS_BUDGET_BUFFER", "预算缓冲比例", "如 0.95;币本位复利/固定预算共用"),
"OKX_OPTIONS_MARGIN_MODE",
"单笔期权本位",
"usdc=USDⓈ权利金;coin=币本位+USDT买币桥(默认)。有持仓/半成品桥时勿切换;改后需重启",
),
(
"OKX_OPTIONS_TRADE_BUDGET_USDC",
"单笔预算(USDC)",
"仅 USDC 模式且全仓复利关闭时显示/生效;用于「按可用余额打满」及张数/币数上限",
),
("OKX_OPTIONS_BUDGET_BUFFER", "预算缓冲比例", "如 0.95;USDC 打满/全仓复利与币本位复利共用"),
( (
"OKX_OPTIONS_COIN_COMPOUND", "OKX_OPTIONS_COIN_COMPOUND",
"币本位按交易户USDT复利", "按交易户USDT复利",
"默认 true;预算=交易账户USDT×缓冲;关闭则用下方固定 USDT 预算×缓冲", "默认 true;预算=交易账户USDT×缓冲;关闭则用下方固定 USDT 预算×缓冲",
), ),
( (
"OKX_OPTIONS_COIN_BUDGET_USDT", "OKX_OPTIONS_COIN_BUDGET_USDT",
"币本位固定预算(USDT)", "固定预算(USDT)",
"仅币本位且复利关闭时生效", "仅复利关闭时生效",
), ),
( (
"OKX_OPTIONS_COIN_MAX_USDT_ENABLED", "OKX_OPTIONS_COIN_MAX_USDT_ENABLED",
"币本位单笔上限开关", "单笔上限开关",
"默认 false=靠人工转走控规模;true 时预算不超过下方 N U", "默认 false=靠人工转走控规模;true 时预算不超过下方 N U",
), ),
( (
"OKX_OPTIONS_COIN_MAX_USDT", "OKX_OPTIONS_COIN_MAX_USDT",
"币本位单笔上限(USDT)", "单笔上限(USDT)",
"仅上限开关开启时生效", "仅上限开关开启时生效",
), ),
( (
"OKX_OPTIONS_COIN_SPOT_BUY_BUFFER", "OKX_OPTIONS_COIN_SPOT_BUY_BUFFER",
"币本位现货买入缓冲", "现货买入缓冲",
"相对权利金倍数,默认 1.10(=多买10%);也可写 0.10 表示+10%。按最大可开张数×卖一权利金×本缓冲买币,不全额兑换", "相对权利金倍数,默认 1.10(=多买10%);按最大可开张数×卖一权利金×本缓冲买币",
),
(
"OKX_OPTIONS_COMPOUND_FULL_ENABLED",
"全仓复利开关",
"默认 true;仅 USDC 模式。开启时隐藏单笔预算且不可用打满预算,下单以全仓复利为主;关闭则恢复单笔预算并隐藏全仓复利",
),
(
"OKX_OPTIONS_COMPOUND_FULL_CAP_ENABLED",
"全仓复利上限开关",
"仅全仓复利开启时有意义;默认 false=不设上限用期权户全部可用;true 时按下方上限封顶",
),
(
"OKX_OPTIONS_COMPOUND_FULL_CAP_USDC",
"全仓复利上限(USDC)",
"仅「全仓复利」且「上限开关」都开启时生效;例如 300",
), ),
( (
"OKX_OPTIONS_MAX_ACTIVE_POSITIONS", "OKX_OPTIONS_MAX_ACTIVE_POSITIONS",
"期权持仓上限(笔)", "期权持仓上限(笔)",
"仅「单独期权」模式生效;默认 0=不限制;按交易所期权合约笔数计数,同合约加仓不占新笔数", "仅「单独期权」模式生效;默认 0=不限制",
), ),
("OKX_OPTIONS_DEFAULT_UNDERLY", "默认标的", "如 ETH"), ("OKX_OPTIONS_DEFAULT_UNDERLY", "默认标的", "如 ETH"),
( (
@@ -248,7 +223,7 @@ _OPTIONS_SECTION: dict[str, Any] = {
( (
"OKX_OPTIONS_CHAIN_ASK_LIQ_FILTER_ENABLED", "OKX_OPTIONS_CHAIN_ASK_LIQ_FILTER_ENABLED",
"链上仅显示有卖一", "链上仅显示有卖一",
"默认 true;开启后隐藏无卖一深度或深度不足1张的合约(含标记价估算行)", "默认 true;开启后隐藏无卖一深度或深度不足1张的合约",
), ),
( (
"OKX_OPTIONS_CLOSE_GATE_MODE", "OKX_OPTIONS_CLOSE_GATE_MODE",
@@ -258,18 +233,13 @@ _OPTIONS_SECTION: dict[str, Any] = {
( (
"OKX_OPTIONS_CLOSE_RECYCLE_MULT", "OKX_OPTIONS_CLOSE_RECYCLE_MULT",
"门控权利金倍数(全局)", "门控权利金倍数(全局)",
"可选;填写则覆盖下方分本位默认值", "可选;填写则覆盖下方币本位默认值",
), ),
( (
"OKX_OPTIONS_CLOSE_RECYCLE_MULT_COIN", "OKX_OPTIONS_CLOSE_RECYCLE_MULT_COIN",
"门控权利金倍数(币本位)", "门控权利金倍数",
"默认 1.05;premium 模式下 recyclable(U)≥premium(U)×本值", "默认 1.05;premium 模式下 recyclable(U)≥premium(U)×本值",
), ),
(
"OKX_OPTIONS_CLOSE_RECYCLE_MULT_USDC",
"门控权利金倍数(USDC)",
"默认 2;premium 模式下 recyclable(U)≥premium(U)×本值",
),
( (
"OKX_OPTIONS_CLOSE_NET_PNL_MIN_U", "OKX_OPTIONS_CLOSE_NET_PNL_MIN_U",
"门控净盈亏下限(U)", "门控净盈亏下限(U)",
@@ -583,28 +553,19 @@ def build_env_ui_payload(
def _mark_options_env_field_visibility(fields: list[dict[str, Any]]) -> list[dict[str, Any]]: def _mark_options_env_field_visibility(fields: list[dict[str, Any]]) -> list[dict[str, Any]]:
"""按本位/全仓复利隐藏无关项(供 SSR/前端;切换开关仍可再显示).""" """CoinOX 固定币本位;按复利开关隐藏固定预算等项."""
compound_on = True coin_compound = True
margin_mode = "coin"
for f in fields: for f in fields:
key = f.get("key") key = f.get("key")
cur = str(f.get("current") or f.get("default") or "").strip() cur = str(f.get("current") or f.get("default") or "").strip()
if key == "OKX_OPTIONS_COMPOUND_FULL_ENABLED": if key == "OKX_OPTIONS_COIN_COMPOUND":
compound_on = _env_truthy(cur or "true") coin_compound = _env_truthy(cur or "true")
elif key == "OKX_OPTIONS_MARGIN_MODE":
margin_mode = (cur or "coin").lower()
if margin_mode not in ("coin", "usdc"):
margin_mode = "coin"
out: list[dict[str, Any]] = [] out: list[dict[str, Any]] = []
for f in fields: for f in fields:
item = dict(f) item = dict(f)
key = item.get("key") key = item.get("key")
hide = False hide = False
if key == "OKX_OPTIONS_TRADE_BUDGET_USDC" and compound_on: if key == "OKX_OPTIONS_COIN_BUDGET_USDT" and coin_compound:
hide = True
if key == "OKX_OPTIONS_CLOSE_RECYCLE_MULT_USDC" and margin_mode == "coin":
hide = True
if key == "OKX_OPTIONS_CLOSE_RECYCLE_MULT_COIN" and margin_mode == "usdc":
hide = True hide = True
if hide: if hide:
item["hidden"] = True item["hidden"] = True
+1 -1
View File
@@ -850,7 +850,7 @@ def build_option_chain(
family = inst_family_for_underlying(u, margin_mode=margin_mode) family = inst_family_for_underlying(u, margin_mode=margin_mode)
except Exception: except Exception:
family = f"{u}-USD_UM" family = f"{u}-USD"
uly = f"{u}-USD" uly = f"{u}-USD"
idx = index_px if index_px is not None else fetch_index_price(ex, uly) idx = index_px if index_px is not None else fetch_index_price(ex, uly)
chain_margin = "usdc" if "_UM" in family.upper() else "coin" chain_margin = "usdc" if "_UM" in family.upper() else "coin"
+6 -2
View File
@@ -93,7 +93,11 @@ def _build_cfg(app_module: Any) -> dict[str, Any]:
"chain_max_dte": float(os.getenv("OKX_OPTIONS_CHAIN_MAX_DTE_DAYS") or os.getenv("OKX_OPTIONS_MAX_DTE_DAYS") or "14"), "chain_max_dte": float(os.getenv("OKX_OPTIONS_CHAIN_MAX_DTE_DAYS") or os.getenv("OKX_OPTIONS_MAX_DTE_DAYS") or "14"),
"perp_account_label": (os.getenv("OKX_ACCOUNT_LABEL") or "合约账户").strip(), "perp_account_label": (os.getenv("OKX_ACCOUNT_LABEL") or "合约账户").strip(),
"options_account_label": (os.getenv("OKX_OPTIONS_ACCOUNT_LABEL") or "期权账户").strip(), "options_account_label": (os.getenv("OKX_OPTIONS_ACCOUNT_LABEL") or "期权账户").strip(),
"trade_budget_usdc": float(os.getenv("OKX_OPTIONS_TRADE_BUDGET_USDC") or "10"), "trade_budget_usdc": float(
os.getenv("OKX_OPTIONS_COIN_BUDGET_USDT")
or os.getenv("OKX_OPTIONS_TRADE_BUDGET_USDC")
or "10"
),
# 对冲专用缓冲;与期权页 OKX_OPTIONS_BUDGET_BUFFER 独立 # 对冲专用缓冲;与期权页 OKX_OPTIONS_BUDGET_BUFFER 独立
"budget_buffer": float(os.getenv("HEDGE_PLAN_BUDGET_BUFFER") or "0.95"), "budget_buffer": float(os.getenv("HEDGE_PLAN_BUDGET_BUFFER") or "0.95"),
"oo_bias_split_by": _oo_bias_split_by(), "oo_bias_split_by": _oo_bias_split_by(),
@@ -769,7 +773,7 @@ def register_hedge_plan_routes(app: Flask, cfg: dict[str, Any]) -> None:
"chain_max_dte_days": chain_max_dte, "chain_max_dte_days": chain_max_dte,
"account_kind": "options", "account_kind": "options",
"account_label": cfg.get("options_account_label") or "期权账户", "account_label": cfg.get("options_account_label") or "期权账户",
"account_note": "期权腿使用期权账户(交易 USDC)", "account_note": "期权腿使用币本位(交易账户 USDT 买币开期权)",
"options_account": opt_acct, "options_account": opt_acct,
"trade_budget_usdc": cfg.get("trade_budget_usdc"), "trade_budget_usdc": cfg.get("trade_budget_usdc"),
"budget_buffer": cfg.get("budget_buffer"), "budget_buffer": cfg.get("budget_buffer"),
@@ -53,7 +53,7 @@
<details class="tip-collapse hp-rule-collapse"> <details class="tip-collapse hp-rule-collapse">
<summary class="tip-collapse-summary">规则说明</summary> <summary class="tip-collapse-summary">规则说明</summary>
<div class="tip-collapse-body rule-tip"> <div class="tip-collapse-body rule-tip">
<p><strong>账户</strong>:永续腿走<strong>合约账户</strong>(USDT);期权腿走<strong>期权账户</strong>(USDC)。两账户分开下单、资金不互通。</p> <p><strong>账户</strong>:永续腿走<strong>合约账户</strong>(USDT);期权腿走<strong>币本位</strong>(交易账户 USDT 买币开期权)。</p>
<p><strong>模式</strong>:在 env <code>HEDGE_PLAN_OPTION_PRIMARY</code> 切换(true=以期权为主 / false=保险模式);标题前标识当前模式。</p> <p><strong>模式</strong>:在 env <code>HEDGE_PLAN_OPTION_PRIMARY</code> 切换(true=以期权为主 / false=保险模式);标题前标识当前模式。</p>
<p><strong>保险模式</strong>:做多配 Put、做空配 Call;左填开仓/止盈止损;仅实值/平值;交易所 TP/SL 出场。</p> <p><strong>保险模式</strong>:做多配 Put、做空配 Call;左填开仓/止盈止损;仅实值/平值;交易所 TP/SL 出场。</p>
<p><strong>以期权为主</strong>:填参后点「策略启动」进入<strong>盯盘</strong>(非现场开仓);杠杆/间隔达标后自动先开期权再市价永续。右侧列表仅展示达标候选。</p> <p><strong>以期权为主</strong>:填参后点「策略启动」进入<strong>盯盘</strong>(非现场开仓);杠杆/间隔达标后自动先开期权再市价永续。右侧列表仅展示达标候选。</p>
@@ -92,7 +92,7 @@
<h3 id="hp-po-sec-capital" class="hp-po-section-title">资金与杠杆配置</h3> <h3 id="hp-po-sec-capital" class="hp-po-section-title">资金与杠杆配置</h3>
<div class="hp-po-fields hp-po-fields--section hp-po-fields--capital"> <div class="hp-po-fields hp-po-fields--section hp-po-fields--capital">
<label class="hp-po-field"> <label class="hp-po-field">
<span class="hp-po-field-lab">权利金 <em>USDC</em></span> <span class="hp-po-field-lab">权利金 <em>币</em></span>
<input type="number" step="any" id="hp-premium-budget" placeholder="预算(执行×0.95)" autocomplete="off" inputmode="decimal" data-lpignore="true" data-1p-ignore="true" data-form-type="other" /> <input type="number" step="any" id="hp-premium-budget" placeholder="预算(执行×0.95)" autocomplete="off" inputmode="decimal" data-lpignore="true" data-1p-ignore="true" data-form-type="other" />
</label> </label>
<label class="hp-po-field"> <label class="hp-po-field">
@@ -211,7 +211,7 @@
<details class="tip-collapse hp-rule-collapse"> <details class="tip-collapse hp-rule-collapse">
<summary class="tip-collapse-summary">规则说明</summary> <summary class="tip-collapse-summary">规则说明</summary>
<div class="tip-collapse-body rule-tip"> <div class="tip-collapse-body rule-tip">
<p><strong>账户</strong>:两腿都在<strong>期权账户</strong>。可用预算 = min(交易 USDC × 对冲缓冲 <strong id="hp-oo-buf-ratio">{{ '%.2f'|format(hedge_plan_budget_buffer|default(0.95)|float) }}</strong>, 单笔预算);可在 env「对冲预算缓冲比例」改。</p> <p><strong>账户</strong>:两腿都走<strong>币本位期权</strong>。可用预算 = min(交易 USDT × 对冲缓冲 <strong id="hp-oo-buf-ratio">{{ '%.2f'|format(hedge_plan_budget_buffer|default(0.95)|float) }}</strong>, 单笔预算);可在 env「对冲预算缓冲比例」改。</p>
<p><strong>下单</strong>:选 Call + Put 后「计算」再「启动」。启动会再拉卖一并按最新价重算张数,IOC 完全成交才算成功;资金不足可在右侧划转。</p> <p><strong>下单</strong>:选 Call + Put 后「计算」再「启动」。启动会再拉卖一并按最新价重算张数,IOC 完全成交才算成功;资金不足可在右侧划转。</p>
<p><strong>板块</strong>:左填<strong>盈亏比</strong>(盈利金额÷总权利金,默认2)与张数模式(同张数/做多/做空);右 T 型选腿。<strong>两腿仅允许平值或虚值</strong>(禁实值)。出场:盈利腿达盈亏比即平;亏损腿「残值平」=本合约权利金跌至20%且有买一时平,「到期平」=持有至到期。</p> <p><strong>板块</strong>:左填<strong>盈亏比</strong>(盈利金额÷总权利金,默认2)与张数模式(同张数/做多/做空);右 T 型选腿。<strong>两腿仅允许平值或虚值</strong>(禁实值)。出场:盈利腿达盈亏比即平;亏损腿「残值平」=本合约权利金跌至20%且有买一时平,「到期平」=持有至到期。</p>
</div> </div>
@@ -294,7 +294,7 @@
<span>资金 <strong id="hp-oo-funding-usdc">—</strong></span> <span>资金 <strong id="hp-oo-funding-usdc">—</strong></span>
<span class="hp-oo-transfer-sep">·</span> <span class="hp-oo-transfer-sep">·</span>
<span>交易 <strong id="hp-oo-trading-usdc">—</strong></span> <span>交易 <strong id="hp-oo-trading-usdc">—</strong></span>
<span class="hp-oo-transfer-unit">USDC</span> <span class="hp-oo-transfer-unit">USDT</span>
<span class="muted" id="hp-oo-xfer-msg"></span> <span class="muted" id="hp-oo-xfer-msg"></span>
</div> </div>
<div class="form-row hp-oo-transfer-form" autocomplete="off"> <div class="form-row hp-oo-transfer-form" autocomplete="off">
@@ -405,4 +405,4 @@
</div> </div>
</div> </div>
</div> </div>
<script src="/static/hedge_plan.js?v=48"></script> <script src="/static/hedge_plan.js?v=49"></script>
+2 -2
View File
@@ -26,7 +26,7 @@ DEFAULT_INSTANCE_DISPLAY: dict[str, bool] = {
"show_settings_transfer": True, "show_settings_transfer": True,
"show_settings_export": True, "show_settings_export": True,
"show_settings_password": True, "show_settings_password": True,
"show_settings_options_swap": True, "show_settings_options_swap": False, # CoinOX 已移除 USDT↔USDC 兑换
"show_settings_options_transfer": True, "show_settings_options_transfer": True,
} }
@@ -86,6 +86,7 @@ def normalize_display_prefs(raw: dict | None) -> dict[str, bool]:
out["show_nav_strategy"] = False out["show_nav_strategy"] = False
out["show_nav_strategy_records"] = False out["show_nav_strategy_records"] = False
out["show_nav_system_guide"] = False out["show_nav_system_guide"] = False
out["show_settings_options_swap"] = False
return out return out
@@ -140,7 +141,6 @@ def display_meta_for_ui() -> list[dict[str, Any]]:
"show_settings_transfer", "show_settings_transfer",
"show_settings_export", "show_settings_export",
"show_settings_password", "show_settings_password",
"show_settings_options_swap",
"show_settings_options_transfer", "show_settings_options_transfer",
] ]
return [ return [
+2 -3
View File
@@ -53,9 +53,8 @@ def margin_mode_from_inst_id(inst_id: str) -> str:
def premium_ccy_for_mode(margin_mode: str, underlying: str = "ETH") -> str: def premium_ccy_for_mode(margin_mode: str, underlying: str = "ETH") -> str:
if normalize_options_margin_mode(margin_mode) == MODE_COIN: """CoinOX 仅币本位:权利金币种为标的币."""
return (underlying or "ETH").strip().upper() or "ETH" return (underlying or "ETH").strip().upper() or "ETH"
return "USDC"
def spot_quote_inst_id(underlying: str) -> str: def spot_quote_inst_id(underlying: str) -> str:
File diff suppressed because it is too large Load Diff
@@ -4,8 +4,9 @@
<input type="text" name="username" autocomplete="username" tabindex="-1" aria-hidden="true" <input type="text" name="username" autocomplete="username" tabindex="-1" aria-hidden="true"
style="position:absolute;left:-9999px;width:1px;height:1px;opacity:0" value=""> style="position:absolute;left:-9999px;width:1px;height:1px;opacity:0" value="">
<select id="opt-set-int-ccy" aria-label="币种" autocomplete="off"> <select id="opt-set-int-ccy" aria-label="币种" autocomplete="off">
<option value="USDC" selected>USDC</option> <option value="USDT" selected>USDT</option>
<option value="USDT">USDT</option> <option value="ETH">ETH</option>
<option value="BTC">BTC</option>
</select> </select>
<select id="opt-set-int-from" aria-label="划出账户"> <select id="opt-set-int-from" aria-label="划出账户">
<option value="funding" selected>from: 资金</option> <option value="funding" selected>from: 资金</option>
+30
View File
@@ -0,0 +1,30 @@
#!/usr/bin/env python3
import paramiko
import sys
HOST = "47.245.56.5"
USER = "root"
PASSWORD = "woaini88@"
def main():
sys.stdout.reconfigure(encoding="utf-8", errors="replace")
c = paramiko.SSHClient()
c.set_missing_host_key_policy(paramiko.AutoAddPolicy())
c.connect(HOST, username=USER, password=PASSWORD, timeout=20)
cmd = (
"cd /opt/coinox && git fetch origin main && git reset --hard origin/main && "
"git log -1 --oneline && pm2 restart coinox --update-env && sleep 2 && "
"grep -n '仅支持币本位' lib/options/options_register.py | head -3 && "
"grep -n 'TRADE_BUDGET_USDC' lib/env/env_ui_manifest.py || echo NO_USDC_BUDGET_IN_UI"
)
_, o, e = c.exec_command(cmd, timeout=90)
print(o.read().decode("utf-8", "replace")[:4000])
err = e.read().decode("utf-8", "replace")
if err.strip():
print("ERR:", err[:1000])
c.close()
if __name__ == "__main__":
main()
+70
View File
@@ -0,0 +1,70 @@
#!/usr/bin/env python3
"""Strip dead USDC quote/open paths from options_register.py."""
from __future__ import annotations
from pathlib import Path
P = Path(__file__).resolve().parents[1] / "lib" / "options" / "options_register.py"
text = P.read_text(encoding="utf-8")
MARKER_Q = 'return jsonify({"ok": False, "msg": f"币本位报价失败: {e}"})'
MARKER_O = 'return jsonify({"ok": False, "msg": f"币本位开仓失败: {e}"})'
ROUTE_OPEN = ' @app.route("/api/options/open", methods=["POST"])'
ROUTE_PENDING = ' @app.route("/api/options/orders/pending")'
iq = text.find(MARKER_Q)
io = text.find(MARKER_O)
i_open = text.find(ROUTE_OPEN)
i_pending = text.find(ROUTE_PENDING)
if min(iq, io, i_open, i_pending) < 0:
raise SystemExit(f"anchors missing q={iq} o={io} open={i_open} pending={i_pending}")
# after quote coin except → reject; drop USDC quote body
q_end = text.find("\n", iq) + 1
new_q = (
text[:q_end]
+ "\n return jsonify({\"ok\": False, \"msg\": \"CoinOX 仅支持币本位期权\"})\n\n"
+ text[i_open:]
)
# recompute open anchors on new text
io = new_q.find(MARKER_O)
i_pending = new_q.find(ROUTE_PENDING)
o_end = new_q.find("\n", io) + 1
new_text = (
new_q[:o_end]
+ "\n return jsonify({\"ok\": False, \"msg\": \"CoinOX 仅支持币本位期权\"})\n\n"
+ new_q[i_pending:]
)
# Replace convert + spot swap handlers with 410 stubs (keep route names for old UI)
import re
def stub_route(src: str, route_sig: str, stub_body: str) -> str:
m = re.search(
rf"( @app\.route\({re.escape(route_sig)}.*?\)\n @lr\n def \w+\(.*?\):\n)",
src,
flags=re.S,
)
if not m:
print("warn: route not found", route_sig)
return src
start = m.end()
# find next route at same indent
n = re.search(r"\n @app\.route\(", src[start:])
end = start + n.start() + 1 if n else len(src)
return src[:start] + stub_body + src[end:]
stub = ' return jsonify({"ok": False, "msg": "CoinOX 已移除 USDC 兑换"}), 410\n\n'
for sig in ('"/api/options/convert/quote", methods=["POST"]', '"/api/options/convert/execute", methods=["POST"]', '"/api/options/spot/swap", methods=["POST"]'):
new_text = stub_route(new_text, sig, stub)
# transfer default USDC -> USDT
new_text = new_text.replace(
'ccy = (data.get("ccy") or "USDC").upper()',
'ccy = (data.get("ccy") or "USDT").upper()',
)
P.write_text(new_text, encoding="utf-8")
print("updated", P)
print("size", len(text), "->", len(new_text))