持仓区增加账户内划转,买一平仓规则并入左侧开平仓说明
持仓卡片底部可折叠划转面板(资金/交易 USDT/USDC);移除持仓区重复平仓规则,统一到左侧开平仓规则说明。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -5297,6 +5297,68 @@ html[data-theme="light"] .opt-source-badge--oo {
|
||||
border-color: #ffb347;
|
||||
color: #ffb347;
|
||||
}
|
||||
.options-page-wrap .opt-pos-transfer {
|
||||
margin-top: 10px;
|
||||
padding: 10px 12px;
|
||||
border-radius: 8px;
|
||||
background: rgba(255, 255, 255, 0.03);
|
||||
border: 1px solid rgba(255, 255, 255, 0.06);
|
||||
}
|
||||
.options-page-wrap .opt-pos-transfer-head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 8px;
|
||||
cursor: pointer;
|
||||
list-style: none;
|
||||
font-weight: 600;
|
||||
font-size: 0.88rem;
|
||||
margin: 0 0 8px;
|
||||
}
|
||||
.options-page-wrap .opt-pos-transfer-head::-webkit-details-marker {
|
||||
display: none;
|
||||
}
|
||||
.options-page-wrap .opt-pos-transfer[open] .opt-pos-transfer-closed-hint {
|
||||
display: none;
|
||||
}
|
||||
.options-page-wrap .opt-pos-transfer:not([open]) .opt-pos-transfer-open-hint {
|
||||
display: none;
|
||||
}
|
||||
.options-page-wrap .opt-pos-transfer:not([open]) .opt-pos-transfer-body {
|
||||
display: none;
|
||||
}
|
||||
.options-page-wrap .opt-pos-transfer:not([open]) .opt-pos-transfer-head {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.options-page-wrap .opt-pos-transfer-body .options-settings-subtitle {
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
.options-page-wrap .opt-pos-transfer-form {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
margin: 0;
|
||||
}
|
||||
.options-page-wrap .opt-pos-transfer-form select,
|
||||
.options-page-wrap .opt-pos-transfer-form input[type="number"] {
|
||||
font-size: 0.74rem;
|
||||
}
|
||||
.options-page-wrap .opt-pos-transfer-form input[type="number"] {
|
||||
width: 96px;
|
||||
max-width: 30vw;
|
||||
}
|
||||
.options-page-wrap .opt-pos-xfer-msg {
|
||||
margin-top: 6px;
|
||||
font-size: 0.76rem;
|
||||
min-height: 1.1em;
|
||||
}
|
||||
.options-page-wrap .opt-pos-xfer-msg.opt-error {
|
||||
color: #ff7b72;
|
||||
}
|
||||
.options-page-wrap .opt-pos-xfer-msg.opt-success {
|
||||
color: #3dd68c;
|
||||
}
|
||||
.opt-pos-card {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
@@ -373,6 +373,164 @@
|
||||
}
|
||||
}
|
||||
|
||||
function setXferMsg(text, isErr) {
|
||||
const el = document.getElementById("opt-pos-xfer-msg");
|
||||
if (!el) return;
|
||||
el.textContent = text || "";
|
||||
el.classList.toggle("opt-error", !!isErr);
|
||||
el.classList.toggle("opt-success", !!text && !isErr);
|
||||
}
|
||||
|
||||
function xferRoundAvail(v) {
|
||||
const n = Number(v);
|
||||
if (!Number.isFinite(n) || n <= 0) return null;
|
||||
return Math.round(n * 100) / 100;
|
||||
}
|
||||
|
||||
function xferPickBalance(bal, account, ccy) {
|
||||
if (!bal) return null;
|
||||
const acct = account === "trading" ? "trading" : "funding";
|
||||
const c = String(ccy || "").toLowerCase();
|
||||
const availKey = acct + "_" + c + "_avail";
|
||||
const totalKey = acct + "_" + c;
|
||||
return xferRoundAvail(bal[availKey] != null ? bal[availKey] : bal[totalKey]);
|
||||
}
|
||||
|
||||
function xferAccountLabel(acct) {
|
||||
return acct === "trading" ? "交易账户" : "资金账户";
|
||||
}
|
||||
|
||||
function setPosXferBusy(busy) {
|
||||
["opt-pos-xfer-btn", "opt-pos-xfer-all-btn"].forEach(function (id) {
|
||||
const btn = document.getElementById(id);
|
||||
if (!btn) return;
|
||||
if (busy) {
|
||||
if (!btn.dataset.origText) btn.dataset.origText = btn.textContent;
|
||||
btn.disabled = true;
|
||||
} else {
|
||||
btn.disabled = false;
|
||||
if (btn.dataset.origText) {
|
||||
btn.textContent = btn.dataset.origText;
|
||||
delete btn.dataset.origText;
|
||||
}
|
||||
}
|
||||
});
|
||||
const input = document.getElementById("opt-pos-xfer-amount");
|
||||
if (input) input.disabled = !!busy;
|
||||
}
|
||||
|
||||
async function submitPosTransfer(amount) {
|
||||
const ccyEl = document.getElementById("opt-pos-xfer-ccy");
|
||||
const fromEl = document.getElementById("opt-pos-xfer-from");
|
||||
const toEl = document.getElementById("opt-pos-xfer-to");
|
||||
if (!ccyEl || !fromEl || !toEl) return { ok: false };
|
||||
setPosXferBusy(true);
|
||||
setXferMsg("划转中…", false);
|
||||
try {
|
||||
const r = await apiJson("/api/options/transfer", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
ccy: ccyEl.value,
|
||||
from: fromEl.value,
|
||||
to: toEl.value,
|
||||
amount: amount,
|
||||
}),
|
||||
});
|
||||
if (r.ok) {
|
||||
setXferMsg("划转成功", false);
|
||||
const amtEl = document.getElementById("opt-pos-xfer-amount");
|
||||
if (amtEl) amtEl.value = "";
|
||||
refreshAllPositions();
|
||||
if (typeof refreshAccountSnapshot === "function") refreshAccountSnapshot({ force: true });
|
||||
await refreshBridgeSellUi(true);
|
||||
} else {
|
||||
setXferMsg("划转失败:" + (r.msg || "未知错误"), true);
|
||||
}
|
||||
return r;
|
||||
} catch (e) {
|
||||
setXferMsg("划转失败:" + (e.message || "网络错误"), true);
|
||||
return { ok: false };
|
||||
} finally {
|
||||
setPosXferBusy(false);
|
||||
}
|
||||
}
|
||||
|
||||
function bindPosTransferControls() {
|
||||
const xferBtn = document.getElementById("opt-pos-xfer-btn");
|
||||
const xferAllBtn = document.getElementById("opt-pos-xfer-all-btn");
|
||||
const amtEl = document.getElementById("opt-pos-xfer-amount");
|
||||
if (!xferBtn && !xferAllBtn) return;
|
||||
|
||||
function hardenXferAmountInput() {
|
||||
if (!amtEl) return;
|
||||
function wipe() {
|
||||
const v = String(amtEl.value || "").trim();
|
||||
if (/^[a-z][a-z0-9._-]{1,31}$/i.test(v)) amtEl.value = "";
|
||||
}
|
||||
wipe();
|
||||
amtEl.setAttribute("readonly", "readonly");
|
||||
amtEl.addEventListener("focus", function () {
|
||||
amtEl.removeAttribute("readonly");
|
||||
});
|
||||
amtEl.addEventListener("blur", function () {
|
||||
if (!amtEl.value) amtEl.setAttribute("readonly", "readonly");
|
||||
});
|
||||
setTimeout(wipe, 200);
|
||||
setTimeout(wipe, 800);
|
||||
}
|
||||
hardenXferAmountInput();
|
||||
|
||||
if (xferBtn) {
|
||||
xferBtn.addEventListener("click", async function () {
|
||||
const amount = parseFloat((amtEl || {}).value);
|
||||
if (!amount || amount <= 0) {
|
||||
setXferMsg("请输入有效数量", true);
|
||||
return;
|
||||
}
|
||||
await submitPosTransfer(amount);
|
||||
});
|
||||
}
|
||||
|
||||
if (xferAllBtn) {
|
||||
xferAllBtn.addEventListener(
|
||||
"click",
|
||||
function () {
|
||||
if (amtEl) amtEl.removeAttribute("readonly");
|
||||
},
|
||||
true
|
||||
);
|
||||
xferAllBtn.addEventListener("click", async function () {
|
||||
try {
|
||||
const ccyEl = document.getElementById("opt-pos-xfer-ccy");
|
||||
const fromEl = document.getElementById("opt-pos-xfer-from");
|
||||
const toEl = document.getElementById("opt-pos-xfer-to");
|
||||
const bal = await refreshBridgeSellUi(true);
|
||||
const ccy = ccyEl ? ccyEl.value : "USDT";
|
||||
const from = fromEl ? fromEl.value : "funding";
|
||||
const to = toEl ? toEl.value : "trading";
|
||||
const amount = xferPickBalance(bal, from, ccy);
|
||||
if (!amount) {
|
||||
setXferMsg("划出账户可用余额不足", true);
|
||||
return;
|
||||
}
|
||||
const msg =
|
||||
"确认全部划转?\n\n" +
|
||||
"币种:" + ccy + "\n" +
|
||||
"划出:" + xferAccountLabel(from) + "\n" +
|
||||
"划入:" + xferAccountLabel(to) + "\n" +
|
||||
"金额:" + amount.toFixed(2) + " " + ccy + "\n\n" +
|
||||
"将划转该账户全部可用余额。";
|
||||
if (!confirm(msg)) return;
|
||||
if (amtEl) amtEl.value = String(amount);
|
||||
await submitPosTransfer(amount);
|
||||
} catch (e) {
|
||||
setXferMsg("划转失败:" + (e.message || "余额拉取失败"), true);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async function retrySellBackCoin() {
|
||||
const uly = String(state.underlying || "ETH").toUpperCase();
|
||||
const d = await refreshBridgeSellUi(true);
|
||||
@@ -2860,6 +3018,7 @@
|
||||
});
|
||||
}
|
||||
bindOptionsPosTabs();
|
||||
bindPosTransferControls();
|
||||
hardenOrderAutofill();
|
||||
|
||||
(function bindProfitExitOpenControls() {
|
||||
|
||||
@@ -18,9 +18,9 @@
|
||||
<div class="card options-order-card"{% if options_open_allowed is defined and not options_open_allowed %} style="opacity:.72"{% endif %}>
|
||||
<h2>期权下单{% if options_open_allowed is defined and not options_open_allowed %} <small class="muted">(对冲模式已禁用开仓)</small>{% endif %}</h2>
|
||||
<details class="opt-close-rule opt-open-rule">
|
||||
<summary>开仓规则说明</summary>
|
||||
<summary>开平仓规则说明</summary>
|
||||
<div class="opt-close-rule-body">
|
||||
<p>报价单位为每 1 ETH/BTC;1 张 = 0.01。默认选中<strong>最近一期</strong>到期,可手动改。</p>
|
||||
<p><strong>开仓</strong> · 报价单位为每 1 ETH/BTC;1 张 = 0.01。默认选中<strong>最近一期</strong>到期,可手动改。</p>
|
||||
<ul>
|
||||
<li><strong>列表</strong>含卖一/买一;<strong>T 型</strong>仅卖一(买方开仓),中间为跨式双买测算。</li>
|
||||
<li>环境配置「链上仅显示有卖一」开启时,隐藏无真实卖一或深度不足 1 张的合约(估算价 <strong>~</strong> 亦不显示)。</li>
|
||||
@@ -30,7 +30,15 @@
|
||||
<li>「全仓复利」用期权交易户<strong>全部可用</strong>×缓冲开仓(不受单笔预算限制);可选开启全仓上限;该模式下仅允许同时 1 笔持仓。</li>
|
||||
<li><strong>币本位</strong>(env <code>OKX_OPTIONS_MARGIN_MODE=coin</code>):按交易户 USDT×缓冲买满 ETH/BTC 再开满期权;平仓后自动卖回 USDT;对冲仍仅 USDC。有仓勿切换本位。</li>
|
||||
<li><strong>翻倍出场</strong>:开仓时可勾选;1倍=盈利等于权利金,买一可回收达标后限价平;持仓卡可改倍数或关闭。</li>
|
||||
<li>平仓仅买一限价,详见说明文档。</li>
|
||||
</ul>
|
||||
<p><strong>平仓(买一)</strong> · 平仓前重新读盘口并校验有效流动性;市价平仓已禁用。</p>
|
||||
<ul>
|
||||
<li>本轮只锁<strong>买一</strong>:张数 = min(持仓, 买一深度),限价 = 当场买一。</li>
|
||||
<li>买一不够时只平能吃掉的部分,剩余等下次再点「买一平仓」。</li>
|
||||
<li>手动平仓只验有效买一(非残档);目标触达后才平,2×权利金只是门控(到 2× 本身不会自动平)。</li>
|
||||
<li><strong>翻倍出场</strong>:开启后可自选倍数(默认1);1倍=盈利等于权利金,买一可回收达标即限价平;可随时关闭。</li>
|
||||
<li>全程 <code>reduceOnly</code> 限价卖,不吃买二及以下、不走市价。</li>
|
||||
<li>币本位平仓后自动卖回 USDT;失败可点持仓区「重试卖回」按交易户全部可用量市价卖出。</li>
|
||||
</ul>
|
||||
<p><a href="/options/guide" target="_blank" rel="noopener">打开《期权开平仓与监控说明》</a></p>
|
||||
</div>
|
||||
@@ -207,20 +215,6 @@
|
||||
<div class="pos-empty" id="opt-pos-empty">暂无持仓</div>
|
||||
<div id="opt-pos-cards"></div>
|
||||
</div>
|
||||
<details class="opt-close-rule">
|
||||
<summary>买一平仓规则说明</summary>
|
||||
<div class="opt-close-rule-body">
|
||||
<p>平仓前重新读盘口并校验有效流动性;市价平仓已禁用。</p>
|
||||
<ul>
|
||||
<li>本轮只锁<strong>买一</strong>:张数 = min(持仓, 买一深度),限价 = 当场买一。</li>
|
||||
<li>买一不够时只平能吃掉的部分,剩余等下次再点「买一平仓」。</li>
|
||||
<li>手动平仓只验有效买一(非残档);目标触达后才平,2×权利金只是门控(到 2× 本身不会自动平)。</li>
|
||||
<li><strong>翻倍出场</strong>:开启后可自选倍数(默认1);1倍=盈利等于权利金,买一可回收达标即限价平;可随时关闭。</li>
|
||||
<li>全程 <code>reduceOnly</code> 限价卖,不吃买二及以下、不走市价。</li>
|
||||
</ul>
|
||||
<p><a href="/options/guide" target="_blank" rel="noopener">打开《期权开平仓与监控说明》</a></p>
|
||||
</div>
|
||||
</details>
|
||||
</div>
|
||||
<div class="options-pos-pane" data-opt-pos-pane="pending" role="tabpanel" aria-labelledby="opt-pos-tab-pending" hidden>
|
||||
<div class="opt-pos-pending-pane">
|
||||
@@ -351,8 +345,39 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<details class="opt-pos-transfer" id="opt-pos-transfer" open>
|
||||
<summary class="opt-pos-transfer-head">
|
||||
<span class="opt-pos-transfer-title">划转</span>
|
||||
<span class="opt-pos-transfer-open-hint muted">收起</span>
|
||||
<span class="opt-pos-transfer-closed-hint muted">展开</span>
|
||||
</summary>
|
||||
<div class="opt-pos-transfer-body">
|
||||
<div class="options-settings-subtitle">账户内划转</div>
|
||||
<div class="form-row opt-pos-transfer-form" autocomplete="off">
|
||||
<input type="text" name="username" autocomplete="username" tabindex="-1" aria-hidden="true"
|
||||
style="position:absolute;left:-9999px;width:1px;height:1px;opacity:0" value="">
|
||||
<select id="opt-pos-xfer-ccy" aria-label="币种" autocomplete="off">
|
||||
<option value="USDT" selected>USDT</option>
|
||||
<option value="USDC">USDC</option>
|
||||
</select>
|
||||
<select id="opt-pos-xfer-from" aria-label="划出账户">
|
||||
<option value="funding" selected>from: 资金</option>
|
||||
<option value="trading">from: 交易</option>
|
||||
</select>
|
||||
<select id="opt-pos-xfer-to" aria-label="划入账户">
|
||||
<option value="trading" selected>to: 交易</option>
|
||||
<option value="funding">to: 资金</option>
|
||||
</select>
|
||||
<input type="number" id="opt-pos-xfer-amount" name="cm_opt_pos_xfer_amt" min="0.01" step="0.01" placeholder="数量"
|
||||
autocomplete="off" inputmode="decimal" data-lpignore="true" data-1p-ignore="true" data-bwignore="true" data-form-type="other" readonly>
|
||||
<button type="button" class="btn-secondary btn-sm" id="opt-pos-xfer-all-btn">全部划转</button>
|
||||
<button type="button" class="btn-primary btn-sm" id="opt-pos-xfer-btn">划转</button>
|
||||
</div>
|
||||
<div id="opt-pos-xfer-msg" class="muted opt-pos-xfer-msg"></div>
|
||||
</div>
|
||||
</details>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script src="/static/options_expiry_countdown.js?v=1"></script>
|
||||
<script src="/static/options_panel.js?v=67"></script>
|
||||
<script src="/static/options_panel.js?v=68"></script>
|
||||
|
||||
Reference in New Issue
Block a user