Expand default strike rows and add hedge fund transfer / sell-coin.

Show the default five chain rows without a scroll box, add funding transfer under manual pick, and wire sell-back-coin above positions via hedge APIs.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-10-14 19:11:44 +08:00
parent d40a0d25be
commit fc83905cf6
6 changed files with 287 additions and 34 deletions
+166 -20
View File
@@ -1431,8 +1431,12 @@
} else if (acct.trading_usdc != null && acct.trading_usdc !== "") {
state.tradingUsdt = Number(acct.trading_usdc);
}
if (acct.funding_usdc != null && acct.funding_usdc !== "") {
if (acct.funding_usdt != null && acct.funding_usdt !== "") {
state.fundingUsdt = Number(acct.funding_usdt);
state.fundingUsdc = Number(acct.funding_usdt);
} else if (acct.funding_usdc != null && acct.funding_usdc !== "") {
state.fundingUsdc = Number(acct.funding_usdc);
state.fundingUsdt = Number(acct.funding_usdc);
}
if (chain && chain.trade_budget_usdc != null && chain.trade_budget_usdc !== "") {
state.tradeBudgetUsdc = Number(chain.trade_budget_usdc);
@@ -1461,11 +1465,19 @@
const tradeEl = $("hp-oo-trading-usdc");
if (fundEl) fundEl.textContent = fmt(acct.funding_usdt != null ? acct.funding_usdt : acct.funding_usdc, 2);
if (tradeEl) tradeEl.textContent = equityTxt;
const poFund = $("hp-po-funding-usdt");
const poTrade = $("hp-po-trading-usdt");
if (poFund) poFund.textContent = fmt(acct.funding_usdt != null ? acct.funding_usdt : acct.funding_usdc, 2);
if (poTrade) poTrade.textContent = equityTxt;
state.fundingEth = acct.funding_eth != null ? Number(acct.funding_eth) : null;
state.tradingEth = acct.trading_eth != null ? Number(acct.trading_eth) : null;
state.fundingBtc = acct.funding_btc != null ? Number(acct.funding_btc) : null;
state.tradingBtc = acct.trading_btc != null ? Number(acct.trading_btc) : null;
autoFillOoSheets();
}
function setOoXferMsg(text, kind) {
const el = $("hp-oo-xfer-msg");
function setXferMsg(prefix, text, kind) {
const el = $(prefix + "-xfer-msg");
if (!el) return;
el.textContent = text || "";
el.classList.toggle("is-err", kind === "err");
@@ -1473,31 +1485,131 @@
el.classList.toggle("muted", !kind);
}
function setOoXferMsg(text, kind) {
setXferMsg("hp-oo", text, kind);
}
function setPoXferMsg(text, kind) {
setXferMsg("hp-po", text, kind);
}
function ooXferDir() {
const sel = $("hp-oo-xfer-dir");
return (sel && sel.value) || "funding_to_trading";
}
async function submitOoUsdcTransfer(amount) {
const dir = ooXferDir();
function poXferDir() {
const sel = $("hp-po-xfer-dir");
return (sel && sel.value) || "funding_to_trading";
}
function poXferCcy() {
const sel = $("hp-po-xfer-ccy");
return ((sel && sel.value) || "USDT").toUpperCase();
}
function xferAvailFor(ccy, fromAcct) {
const c = String(ccy || "USDT").toUpperCase();
const from = String(fromAcct || "funding").toLowerCase();
if (c === "USDT") {
if (from === "trading") {
return Number(
state.tradingUsdt != null
? state.tradingUsdt
: state.tradingUsdc != null
? state.tradingUsdc
: 0
);
}
return Number(
state.fundingUsdt != null
? state.fundingUsdt
: state.fundingUsdc != null
? state.fundingUsdc
: 0
);
}
if (c === "ETH") {
return Number(from === "trading" ? state.tradingEth || 0 : state.fundingEth || 0);
}
if (c === "BTC") {
return Number(from === "trading" ? state.tradingBtc || 0 : state.fundingBtc || 0);
}
return 0;
}
async function submitHedgeTransfer(opts) {
const prefix = opts.prefix || "hp-oo";
const dir = opts.dir || "funding_to_trading";
const ccy = String(opts.ccy || "USDT").toUpperCase();
const amount = Number(opts.amount || 0);
const setMsg = prefix === "hp-po" ? setPoXferMsg : setOoXferMsg;
const from = dir === "trading_to_funding" ? "trading" : "funding";
const to = dir === "trading_to_funding" ? "funding" : "trading";
setOoXferMsg("划转中…", null);
if (!(amount > 0)) {
setMsg("请输入有效数量", "err");
return;
}
setMsg("划转中…", null);
try {
const d = await apiJson("/api/options/transfer", {
const d = await apiJson("/api/hedge-plan/transfer", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ ccy: "USDT", from: from, to: to, amount: amount }),
body: JSON.stringify({ ccy: ccy, from: from, to: to, amount: amount }),
});
if (!d.ok) {
setOoXferMsg(d.msg || "划转失败", "err");
setMsg(d.msg || "划转失败", "err");
return;
}
setOoXferMsg("划转成功", "ok");
if ($("hp-oo-xfer-amount")) $("hp-oo-xfer-amount").value = "";
setMsg("划转成功", "ok");
const amtEl = $(prefix + "-xfer-amount");
if (amtEl) amtEl.value = "";
await loadChain();
} catch (e) {
setOoXferMsg(e.message || "划转失败", "err");
setMsg(e.message || "划转失败", "err");
}
}
async function submitOoUsdcTransfer(amount) {
return submitHedgeTransfer({ prefix: "hp-oo", dir: ooXferDir(), ccy: "USDT", amount: amount });
}
function setSellCoinMsg(text, kind) {
const el = $("hp-sell-coin-msg");
if (!el) return;
el.textContent = text || "";
el.classList.toggle("is-err", kind === "err");
el.classList.toggle("is-ok", kind === "ok");
el.classList.toggle("muted", !kind);
}
async function submitSellCoin() {
const uly = String(state.underlying || "ETH").toUpperCase();
if (!window.confirm("确认市价卖出交易账户全部可用 " + uly + " 换回 USDT?")) return;
setSellCoinMsg("卖回中…", null);
const btn = $("hp-sell-coin-btn");
if (btn) btn.disabled = true;
try {
const d = await apiJson("/api/hedge-plan/sell-coin", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ underlying: uly }),
});
if (!d.ok) {
setSellCoinMsg(d.msg || "卖回失败", "err");
return;
}
const sold =
d.sell && d.sell.coin_sold != null
? "已卖 " + d.sell.coin_sold + " " + uly
: d.msg || "卖回成功";
setSellCoinMsg(sold, "ok");
await loadChain();
void loadLivePositions();
} catch (e) {
setSellCoinMsg(e.message || "卖回失败", "err");
} finally {
if (btn) btn.disabled = false;
}
}
@@ -2901,18 +3013,14 @@
if ($("hp-oo-xfer-btn")) {
$("hp-oo-xfer-btn").addEventListener("click", function () {
const amount = Number(($("hp-oo-xfer-amount") && $("hp-oo-xfer-amount").value) || 0);
if (!(amount > 0)) {
setOoXferMsg("请输入有效数量", "err");
return;
}
void submitOoUsdcTransfer(amount);
void submitHedgeTransfer({ prefix: "hp-oo", dir: ooXferDir(), ccy: "USDT", amount: amount });
});
}
if ($("hp-oo-xfer-all")) {
$("hp-oo-xfer-all").addEventListener("click", function () {
const dir = ooXferDir();
const max =
dir === "trading_to_funding" ? Number(state.tradingUsdc || 0) : Number(state.fundingUsdc || 0);
const from = dir === "trading_to_funding" ? "trading" : "funding";
const max = xferAvailFor("USDT", from);
if (!(max > 0)) {
setOoXferMsg("划出账户可用余额不足", "err");
return;
@@ -2925,11 +3033,49 @@
amtEl.removeAttribute("readonly");
amtEl.value = String(amt);
}
void submitOoUsdcTransfer(amt);
void submitHedgeTransfer({ prefix: "hp-oo", dir: dir, ccy: "USDT", amount: amt });
});
}
if ($("hp-po-xfer-btn")) {
$("hp-po-xfer-btn").addEventListener("click", function () {
const amount = Number(($("hp-po-xfer-amount") && $("hp-po-xfer-amount").value) || 0);
void submitHedgeTransfer({
prefix: "hp-po",
dir: poXferDir(),
ccy: poXferCcy(),
amount: amount,
});
});
}
if ($("hp-po-xfer-all")) {
$("hp-po-xfer-all").addEventListener("click", function () {
const dir = poXferDir();
const ccy = poXferCcy();
const from = dir === "trading_to_funding" ? "trading" : "funding";
const max = xferAvailFor(ccy, from);
if (!(max > 0)) {
setPoXferMsg("划出账户可用余额不足", "err");
return;
}
const amt = ccy === "USDT" ? Math.floor(max * 100) / 100 : Math.floor(max * 1e6) / 1e6;
const label = dir === "trading_to_funding" ? "交易 → 资金" : "资金 → 交易";
if (!window.confirm("确认全部划转?\n币种:" + ccy + "\n方向:" + label + "\n数量:" + amt)) return;
const amtEl = $("hp-po-xfer-amount");
if (amtEl) {
amtEl.removeAttribute("readonly");
amtEl.value = String(amt);
}
void submitHedgeTransfer({ prefix: "hp-po", dir: dir, ccy: ccy, amount: amt });
});
}
if ($("hp-sell-coin-btn")) {
$("hp-sell-coin-btn").addEventListener("click", function () {
void submitSellCoin();
});
}
hardenAmountAutofill([
"hp-oo-xfer-amount",
"hp-po-xfer-amount",
"hp-entry",
"hp-contracts",
"hp-tp",
+12 -11
View File
@@ -3864,12 +3864,13 @@ html[data-theme="light"] .opt-be-dist-down {
.hedge-plan-page-wrap #hp-po-fields-option-primary[hidden] {
display: none !important;
}
/* 默认约 5 档全部展开,不设滚动框(展开全部时随内容增高) */
.hedge-plan-page-wrap .hp-strike-table-wrap--6 {
max-height: 280px;
min-height: 200px;
overflow-y: auto;
max-height: none;
min-height: 0;
overflow: visible;
margin-top: 4px;
flex: 1 1 auto;
flex: 0 0 auto;
}
.hedge-plan-page-wrap .hp-po-field {
display: flex;
@@ -4101,13 +4102,13 @@ html[data-theme="light"] .opt-be-dist-down {
min-height: 26px;
font-size: 0.72rem;
}
/* 永期期权列表:视口约 5 行 + 表头,超出滚动 */
/* 永期期权列表:默认档位全部展开,无下滑框 */
.hedge-plan-page-wrap .hp-strike-table-wrap--5 {
max-height: 248px;
min-height: 248px;
overflow-y: auto;
max-height: none;
min-height: 0;
overflow: visible;
margin-top: 4px;
flex: 1 1 auto;
flex: 0 0 auto;
}
/* 期期 T 型:默认 3+3 一页展示,无下滑框 */
.hedge-plan-page-wrap .hp-oo-table-wrap {
@@ -4342,8 +4343,8 @@ html[data-theme="light"] .opt-be-dist-down {
}
.hedge-plan-page-wrap .hp-po-left-stack > .hp-opt-card .hp-strike-table-wrap--6,
.hedge-plan-page-wrap .hp-po-select-card .hp-strike-table-wrap--6 {
flex: 1 1 auto;
min-height: 220px;
flex: 0 0 auto;
min-height: 0;
}
.hedge-plan-page-wrap .hp-po-pair-hint,
.hedge-plan-page-wrap .hp-po-chain-hint {