Show average profit and loss in option stats panel.
Expose avg_win and avg_loss from stats API and update chart labels and values to match the average-based P/L ratio. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -800,12 +800,12 @@
|
||||
}
|
||||
if (closedEl) closedEl.textContent = String(d.total_closed || 0);
|
||||
if (profitEl) {
|
||||
profitEl.textContent = d.total_profit != null && d.total_profit > 0
|
||||
? fmt(d.total_profit, 2) + " USDC" : (d.total_closed ? "0 USDC" : "—");
|
||||
profitEl.textContent = d.avg_win != null && d.avg_win > 0
|
||||
? fmt(d.avg_win, 2) + " USDC" : (d.win_count ? "0 USDC" : "—");
|
||||
}
|
||||
if (lossEl) {
|
||||
lossEl.textContent = d.total_loss != null && d.total_loss > 0
|
||||
? fmt(d.total_loss, 2) + " USDC" : (d.total_closed ? "0 USDC" : "—");
|
||||
lossEl.textContent = d.avg_loss != null && d.avg_loss > 0
|
||||
? fmt(d.avg_loss, 2) + " USDC" : (d.loss_count ? "0 USDC" : "—");
|
||||
}
|
||||
if (avgHoldEl) avgHoldEl.textContent = fmtDuration(d.avg_hold_sec);
|
||||
if (winHoldEl) winHoldEl.textContent = fmtDuration(d.avg_win_hold_sec);
|
||||
@@ -868,8 +868,8 @@
|
||||
if (ring) ring.style.setProperty("--win-pct", String(winRate));
|
||||
if (ringLabel) ringLabel.textContent = d.total_closed ? winRate.toFixed(0) + "%" : "0%";
|
||||
|
||||
const profit = Math.max(0, Number(d.total_profit) || 0);
|
||||
const loss = Math.max(0, Number(d.total_loss) || 0);
|
||||
const profit = Math.max(0, Number(d.avg_win) || 0);
|
||||
const loss = Math.max(0, Number(d.avg_loss) || 0);
|
||||
const pnlTotal = profit + loss;
|
||||
if (pnlTotal > 0) {
|
||||
setBarFill(profitBar, (profit / pnlTotal) * 100);
|
||||
@@ -879,8 +879,8 @@
|
||||
} else {
|
||||
setBarFill(profitBar, 0);
|
||||
setBarFill(lossBar, 0);
|
||||
if (profitBarLabel) profitBarLabel.textContent = d.total_closed ? "0 USDC" : "—";
|
||||
if (lossBarLabel) lossBarLabel.textContent = d.total_closed ? "0 USDC" : "—";
|
||||
if (profitBarLabel) profitBarLabel.textContent = d.win_count ? "0 USDC" : "—";
|
||||
if (lossBarLabel) lossBarLabel.textContent = d.loss_count ? "0 USDC" : "—";
|
||||
}
|
||||
|
||||
const winHold = Number(d.avg_win_hold_sec) || 0;
|
||||
|
||||
@@ -93,6 +93,8 @@ def compute_options_stats(get_db) -> dict[str, Any]:
|
||||
"loss_count": len(losses),
|
||||
"win_rate": win_rate,
|
||||
"profit_loss_ratio": profit_loss_ratio_from_averages(avg_win, avg_loss),
|
||||
"avg_win": round(avg_win, 4) if avg_win is not None else None,
|
||||
"avg_loss": round(abs(avg_loss), 4) if avg_loss is not None else None,
|
||||
"total_profit": round(sum(wins), 4) if wins else 0.0,
|
||||
"total_loss": round(abs(sum(losses)), 4) if losses else 0.0,
|
||||
"avg_hold_sec": _avg_seconds(all_holds),
|
||||
|
||||
@@ -115,14 +115,14 @@
|
||||
</div>
|
||||
<div class="opt-stats-chart opt-stats-chart--pnl">
|
||||
<div class="opt-stats-bar-row">
|
||||
<span class="k">盈利</span>
|
||||
<span class="k">平均盈利</span>
|
||||
<div class="opt-stats-bar-track">
|
||||
<div class="opt-stats-bar-fill opt-stats-bar-fill--profit" id="opt-stats-bar-profit"></div>
|
||||
</div>
|
||||
<span class="v pos-pnl-profit" id="opt-stats-bar-profit-label">—</span>
|
||||
</div>
|
||||
<div class="opt-stats-bar-row">
|
||||
<span class="k">亏损</span>
|
||||
<span class="k">平均亏损</span>
|
||||
<div class="opt-stats-bar-track">
|
||||
<div class="opt-stats-bar-fill opt-stats-bar-fill--loss" id="opt-stats-bar-loss"></div>
|
||||
</div>
|
||||
@@ -161,11 +161,11 @@
|
||||
<span class="v" id="opt-stats-closed">—</span>
|
||||
</div>
|
||||
<div class="options-stat-item">
|
||||
<span class="k">盈利</span>
|
||||
<span class="k">平均盈利</span>
|
||||
<span class="v pos-pnl-profit" id="opt-stats-profit">—</span>
|
||||
</div>
|
||||
<div class="options-stat-item">
|
||||
<span class="k">亏损</span>
|
||||
<span class="k">平均亏损</span>
|
||||
<span class="v pos-pnl-loss" id="opt-stats-loss">—</span>
|
||||
</div>
|
||||
<div class="options-stat-item">
|
||||
@@ -212,4 +212,4 @@
|
||||
</div>
|
||||
</div>
|
||||
<script src="/static/options_expiry_countdown.js?v=1"></script>
|
||||
<script src="/static/options_panel.js?v=25"></script>
|
||||
<script src="/static/options_panel.js?v=26"></script>
|
||||
|
||||
@@ -61,6 +61,8 @@ class OptionsStatsLibTests(TestCase):
|
||||
self.assertEqual(out["win_count"], 1)
|
||||
self.assertEqual(out["loss_count"], 1)
|
||||
self.assertEqual(out["win_rate"], 50.0)
|
||||
self.assertAlmostEqual(out["avg_win"], 1.2, places=4)
|
||||
self.assertAlmostEqual(out["avg_loss"], 1.0, places=4)
|
||||
self.assertAlmostEqual(out["avg_win_hold_sec"], 3600.0, delta=5.0)
|
||||
self.assertAlmostEqual(out["avg_loss_hold_sec"], 3 * 3600.0, delta=5.0)
|
||||
self.assertEqual(out["open_count"], 1)
|
||||
|
||||
Reference in New Issue
Block a user