Fix max option sheets: shared trading USDT = buy premium + perp margin.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -506,46 +506,50 @@
|
||||
return Number.isFinite(eth) && eth > 0 ? eth : 5;
|
||||
}
|
||||
|
||||
/** 按交易账户 USDT(买币+5%滑点)与合约账户永续杠杆算最大期权张数. */
|
||||
/**
|
||||
* 期权开仓最大张数:OKX 交易账户 USDT 共用.
|
||||
* 每张开仓需:买币(权利金×1.05×指数) + 永续保证金(对冲名义÷杠杆);
|
||||
* 选最大 N 时须保证扣完买币后剩余仍够永续保证金.
|
||||
*/
|
||||
function computeMaxSheets() {
|
||||
const ask = state.selected && Number(state.selected.ask);
|
||||
const ct = Number((state.selected && state.selected.ct_mult) || 0.01);
|
||||
const ratio = numInput("hp-opt-perp-ratio", 2);
|
||||
const cs = Number((state.market && state.market.contract_size) || 0.01);
|
||||
const mark = Number((state.market && (state.market.mark || state.market.index_px)) || indexPx() || 0);
|
||||
const mark = Number(
|
||||
(state.market && (state.market.mark || state.market.index_px)) || indexPx() || 0
|
||||
);
|
||||
const lev = defaultPerpLeverage(state.underlying);
|
||||
const tradingUsdt = Number(state.tradingUsdt != null ? state.tradingUsdt : state.tradingUsdc);
|
||||
const perpAvail = Number((state.market && state.market.available_usdt) || 0);
|
||||
if (!(ask > 0) || !(ct > 0) || !(ratio > 0) || !(cs > 0) || !(mark > 0) || !(lev > 0)) {
|
||||
const tradingUsdt = Number(
|
||||
state.tradingUsdt != null ? state.tradingUsdt : state.tradingUsdc
|
||||
);
|
||||
if (!(ask > 0) || !(ct > 0) || !(ratio > 0) || !(mark > 0) || !(lev > 0)) {
|
||||
return null;
|
||||
}
|
||||
// 买币:权利金币×1.05×指数 ≈ 所需 USDT
|
||||
const coinPerSheet = ask * ct;
|
||||
const usdtPerSheet = coinPerSheet * 1.05 * mark;
|
||||
let maxByOpt = Infinity;
|
||||
if (tradingUsdt > 0 && usdtPerSheet > 0) {
|
||||
maxByOpt = Math.floor(tradingUsdt / usdtPerSheet + 1e-12);
|
||||
if (!(tradingUsdt > 0)) {
|
||||
return {
|
||||
max_sheets: 0,
|
||||
lev: lev,
|
||||
trading_usdt: tradingUsdt,
|
||||
buy_usdt_per_sheet: 0,
|
||||
margin_per_sheet: 0,
|
||||
total_per_sheet: 0,
|
||||
};
|
||||
}
|
||||
// 永续:名义 = 保证金×杠杆; 永续币 = 期权币/比例; 合约张 = 永续币/cs
|
||||
// 期权张 n → 永续名义 = (n*ct/ratio)*mark ≤ avail*lev
|
||||
let maxByPerp = Infinity;
|
||||
if (perpAvail > 0) {
|
||||
const maxPerpNotional = perpAvail * lev;
|
||||
const notionalPerSheet = (ct / ratio) * mark;
|
||||
if (notionalPerSheet > 0) {
|
||||
maxByPerp = Math.floor(maxPerpNotional / notionalPerSheet + 1e-12);
|
||||
}
|
||||
}
|
||||
const maxSheets = Math.max(0, Math.min(maxByOpt, maxByPerp));
|
||||
if (!(maxSheets > 0) && !(tradingUsdt > 0) && !(perpAvail > 0)) return null;
|
||||
// 买币 USDT/张 = 权利金币 × 1.05 × 指数
|
||||
const buyUsdtPerSheet = ask * ct * 1.05 * mark;
|
||||
// 永续名义/张 = (期权币/比例)×指数; 保证金 = 名义÷杠杆
|
||||
const perpNotionalPerSheet = (ct / ratio) * mark;
|
||||
const marginPerSheet = perpNotionalPerSheet / lev;
|
||||
const totalPerSheet = buyUsdtPerSheet + marginPerSheet;
|
||||
if (!(totalPerSheet > 0)) return null;
|
||||
const maxSheets = Math.max(0, Math.floor(tradingUsdt / totalPerSheet + 1e-12));
|
||||
return {
|
||||
max_sheets: maxSheets,
|
||||
max_by_opt: Number.isFinite(maxByOpt) ? maxByOpt : null,
|
||||
max_by_perp: Number.isFinite(maxByPerp) ? maxByPerp : null,
|
||||
lev: lev,
|
||||
trading_usdt: tradingUsdt,
|
||||
perp_avail: perpAvail,
|
||||
usdt_per_sheet: usdtPerSheet,
|
||||
buy_usdt_per_sheet: buyUsdtPerSheet,
|
||||
margin_per_sheet: marginPerSheet,
|
||||
total_per_sheet: totalPerSheet,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -556,23 +560,37 @@
|
||||
const sized = currentOpSizing();
|
||||
const coin = (state.underlying || "ETH").toUpperCase();
|
||||
const lev = defaultPerpLeverage(state.underlying);
|
||||
const mark = Number(
|
||||
(state.market && (state.market.mark || state.market.index_px)) || indexPx() || 0
|
||||
);
|
||||
if (maxEl) {
|
||||
if (maxInfo) {
|
||||
maxEl.innerHTML =
|
||||
"最大约 <strong>" +
|
||||
"期权开仓最大 <strong>" +
|
||||
maxInfo.max_sheets +
|
||||
"</strong> 张 · 永续杠杆 " +
|
||||
lev +
|
||||
"x(env) · 交易 USDT " +
|
||||
"</strong> 张 · 交易 USDT " +
|
||||
fmt(maxInfo.trading_usdt, 2) +
|
||||
" · 合约可用 " +
|
||||
fmt(maxInfo.perp_avail, 2);
|
||||
" · 每张约买币 " +
|
||||
fmt(maxInfo.buy_usdt_per_sheet, 2) +
|
||||
" + 永续保证金 " +
|
||||
fmt(maxInfo.margin_per_sheet, 2) +
|
||||
" (杠杆 " +
|
||||
lev +
|
||||
"x)";
|
||||
} else {
|
||||
maxEl.textContent = "选择期权并刷新行情后显示最大开仓张数(交易账户买币+永续杠杆)";
|
||||
maxEl.textContent =
|
||||
"选择期权并刷新后显示:期权开仓最大张数(扣买币后剩余须够永续保证金)";
|
||||
}
|
||||
}
|
||||
if (perpEl) {
|
||||
if (sized) {
|
||||
const buyUsdt = sized.premium_est * 1.05 * (mark > 0 ? mark : 0);
|
||||
const marginUsdt =
|
||||
sized.perp_qty * (mark > 0 ? mark : 0) / (lev > 0 ? lev : 1);
|
||||
const remain =
|
||||
Number(state.tradingUsdt != null ? state.tradingUsdt : state.tradingUsdc) -
|
||||
buyUsdt;
|
||||
const marginOk = remain + 1e-9 >= marginUsdt;
|
||||
perpEl.innerHTML =
|
||||
"永续自动开 <strong>" +
|
||||
fmt(sized.perp_qty, 4) +
|
||||
@@ -584,7 +602,14 @@
|
||||
fmt(sized.premium_est * 1.05, 4) +
|
||||
" " +
|
||||
coin +
|
||||
"(含5%滑点)";
|
||||
"(≈" +
|
||||
fmt(buyUsdt, 2) +
|
||||
" U含5%) · 扣后剩 " +
|
||||
fmt(remain, 2) +
|
||||
" U · 永续保证金约 " +
|
||||
fmt(marginUsdt, 2) +
|
||||
" U" +
|
||||
(marginOk ? "" : ' <span class="is-err">不足</span>');
|
||||
} else {
|
||||
perpEl.textContent = "永续开仓 — (填张数并选择期权后按比例自动算)";
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user