feat: VBT trade log — show asset, entry/exit prices, Hyperliquid fees
Backend (vbt_runner.py):
- Add asset (BTC/ETH) to each trade record
- Compute per-trade fee using HL taker rate (0.05%)
entry_fee = size * entry_px * fee_rate
exit_fee = size * exit_px * fee_rate
- Add pnl_gross (before fees) and pnl_net (after fees)
- Add fee_rate field for transparency
Server (server.py):
- Normalize old backtest trades: add missing asset, fee,
pnl_net, pnl_gross fields
- Holyliquid default fee rate: 0.05% taker
Frontend (vbt.html):
- Trade log table now shows:
Time | Side + Asset | Size | Entry | Exit | Fee | PnL (net) | Duration
- Asset shown as inline badge in Side column
- Fee column with explicit USD amount
- PnL now explicitly labeled 'net' (after fees)
- Fallback to old 'pnl' field for legacy backtest files
This commit is contained in:
@@ -252,8 +252,14 @@ function renderDetail(r){
|
||||
|
||||
let trades_html='';
|
||||
if(trades.length){
|
||||
const rows=trades.map(t=>'<tr><td style="color:#777;font-size:10px">'+String(t.time||'').substring(0,19)+'</td><td class="'+(String(t.side||'').includes('BUY')?'pos':'neg')+'">'+String(t.side||'')+'</td><td>'+Number(t.size||0).toFixed(6)+'</td><td>$'+Number(t.entry_px||0).toFixed(1)+'</td><td>$'+Number(t.exit_px||0).toFixed(1)+'</td><td class="'+(Number(t.pnl||0)>=0?'pnl-pos':'pnl-neg')+'">$'+Number(t.pnl||0).toFixed(4)+'</td><td>'+String(t.duration||'')+'</td></tr>').join('');
|
||||
trades_html='<div class="chart-box full"><div style="display:flex;justify-content:space-between;align-items:center"><h4>Trade Log ('+trades.length+' trades)</h4></div><div class="trade-scroll"><table class="trades-table"><thead><tr><th>Time</th><th>Side</th><th>Size</th><th>Entry</th><th>Exit</th><th>PnL</th><th>Duration</th></tr></thead><tbody>'+rows+'</tbody></table></div></div>';
|
||||
const rows=trades.map(t=>{
|
||||
const pnl_net=Number(t.pnl_net??t.pnl??0);
|
||||
const fee=Number(t.fee??0);
|
||||
const pnlCls=pnl_net>=0?'pnl-pos':'pnl-neg';
|
||||
const assetBadge = t.asset ? '<span style="font-size:9px;color:#03A9F4;background:#0d1f2b;border:1px solid #1a3a4a;border-radius:2px;padding:0 4px;margin-left:4px">'+t.asset+'</span>' : '';
|
||||
return '<tr><td style="color:#777;font-size:10px">'+String(t.time||'').substring(0,19)+'</td><td class="'+(String(t.side||'').includes('BUY')?'pos':'neg')+'">'+String(t.side||'')+assetBadge+'</td><td>'+Number(t.size||0).toFixed(6)+'</td><td>$'+Number(t.entry_px||0).toFixed(1)+'</td><td>$'+Number(t.exit_px||0).toFixed(1)+'</td><td class="neg" style="font-size:10px">$'+fee.toFixed(6)+'</td><td class="'+pnlCls+'">$'+pnl_net.toFixed(4)+'</td><td style="font-size:10px">'+String(t.duration||'')+'</td></tr>';
|
||||
}).join('');
|
||||
trades_html='<div class="chart-box full"><div style="display:flex;justify-content:space-between;align-items:center"><h4>Trade Log ('+trades.length+' trades)</h4></div><div class="trade-scroll"><table class="trades-table"><thead><tr><th>Time</th><th>Side</th><th>Size</th><th>Entry</th><th>Exit</th><th>Fee</th><th>PnL (net)</th><th>Duration</th></tr></thead><tbody>'+rows+'</tbody></table></div></div>';
|
||||
}
|
||||
|
||||
document.getElementById('content').innerHTML=
|
||||
|
||||
Reference in New Issue
Block a user