diff --git a/index.html b/index.html index e92df3f..be2c86c 100644 --- a/index.html +++ b/index.html @@ -69,6 +69,7 @@ transition:border-color .15s; } input[type=number]:focus{border-color:var(--border-hi)} + input[type=number]:disabled{opacity:.5;cursor:not-allowed} input::-webkit-outer-spin-button,input::-webkit-inner-spin-button{-webkit-appearance:none;margin:0} .side-toggle{display:flex;gap:8px} @@ -172,8 +173,15 @@
- - + +
+ + +
+
+ + +
@@ -198,15 +206,25 @@
-
+
止损价
+
+
止盈价
+
+
+
+
若止盈 · 盈利
+
+
止盈幅度
+
+
@@ -229,8 +247,9 @@
- 说明:真正把亏损锁定在风险金额的是止损单,不是杠杆。表中「状态」校验爆仓价是否在止损之外—— - 安全表示会先触发止损、不会被强平;危险表示杠杆过高、爆仓在止损之前。 + 说明:真正把亏损锁定在风险金额的是止损单,不是杠杆。止盈默认按盈亏比自动反算—— + 止盈点位差 = 止损点位差 × 盈亏比 R,按方向算出止盈价;也可切「按价格」手动输入。 + 表中「状态」校验爆仓价是否在止损之外——安全表示会先触发止损、不会被强平;危险表示杠杆过高、爆仓在止损之前。 爆仓价为逐仓简化估算(爆仓距离≈1/杠杆,忽略维持保证金与手续费),实盘以交易所显示为准。这只是数学计算,不构成投资建议。
@@ -239,7 +258,7 @@ (function(){ const $=id=>document.getElementById(id); const levs=[3,5,10,20,25,50,75,100]; - let side='long', slMode='pct'; + let side='long', slMode='pct', tpMode='rr'; // side toggle $('side').addEventListener('click',e=>{ @@ -258,7 +277,17 @@ calc(); }); - ['balance','riskPct','entry','slPct','slPrice','tp'].forEach(id=>$(id).addEventListener('input',calc)); + // take-profit mode toggle + $('tpMode').addEventListener('click',e=>{ + const b=e.target.closest('button'); if(!b)return; + tpMode=b.dataset.mode; + [...$('tpMode').children].forEach(x=>x.classList.toggle('on',x===b)); + $('tpRR').disabled = tpMode!=='rr'; + $('tp').disabled = tpMode!=='price'; + calc(); + }); + + ['balance','riskPct','entry','slPct','slPrice','tp','tpRR'].forEach(id=>$(id).addEventListener('input',calc)); const fmtN=(n,d=2)=>isFinite(n)?n.toLocaleString('en-US',{minimumFractionDigits:d,maximumFractionDigits:d}):'—'; const fmtP=n=>isFinite(n)?n.toLocaleString('en-US',{minimumFractionDigits:5,maximumFractionDigits:5}):'—'; @@ -292,15 +321,32 @@ $('slPriceShow').textContent = fmtP(slPrice); $('slShow').textContent = '止损 '+fmtN(slPctVal)+'%'; - // take profit / RR - const tp=+$('tp').value; - if(tp>0){ - const tpDist=Math.abs(tp-entry); + // take profit — 两种模式:按盈亏比反算 / 按价格 + let tpPrice, rr; + if(tpMode==='rr'){ + rr=+$('tpRR').value; // 目标盈亏比 + if(rr>0){ + // 止盈点位差 = 止损点位差 × 盈亏比,按方向反算止盈价 + tpPrice = side==='long' ? entry + dist*rr : entry - dist*rr; + $('tp').value = (+tpPrice.toPrecision(8)); // 同步显示到价格框,方便核对/切换 + } + }else{ + tpPrice=+$('tp').value; + if(tpPrice>0) rr = Math.abs(tpPrice-entry)/dist; + } + + if(tpPrice>0 && rr>0){ + const tpDist=Math.abs(tpPrice-entry); const profit=qty*tpDist; - const rr=tpDist/dist; + const tpPct=tpDist/entry*100; $('rr').textContent = '1 : '+fmtN(rr); + $('tpPriceShow').textContent = fmtP(tpPrice); $('tpProfit').innerHTML = '+'+fmtN(profit)+' U'; - }else{ $('rr').textContent='—'; $('tpProfit').textContent='—'; } + $('tpPctShow').textContent = fmtN(tpPct)+'%'; + }else{ + $('rr').textContent='—'; $('tpPriceShow').textContent='—'; + $('tpProfit').textContent='—'; $('tpPctShow').textContent='—'; + } // leverage ladder const rows=levs.map(L=>{ @@ -321,7 +367,7 @@ } function clearOut(){ - ['qty','notional','rr','slPriceShow','tpProfit'].forEach(id=>$(id).textContent='—'); + ['qty','notional','rr','slPriceShow','tpPriceShow','tpProfit','tpPctShow'].forEach(id=>$(id).textContent='—'); $('slShow').textContent=''; $('ladder').innerHTML=''; }