<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>WTI Crude Oil DCA Bot Dashboard</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@tabler/icons-webfont@2.44.0/tabler-icons.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/4.4.0/chart.umd.min.js"></script>
<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
:root {
--bg-primary: #ffffff;
--bg-secondary: #f5f5f4;
--bg-tertiary: #eeece8;
--text-primary: #1a1a18;
--text-secondary: #6b6b67;
--text-tertiary: #9e9e9a;
--border: rgba(0,0,0,0.12);
--border-med: rgba(0,0,0,0.22);
--radius-md: 8px;
--radius-lg: 12px;
--green-bg: #EAF3DE; --green-text: #3B6D11;
--blue-bg: #E6F1FB; --blue-text: #185FA5;
--amber-bg: #FAEEDA; --amber-text: #854F0B;
--red-bg: #FCEBEB; --red-text: #A32D2D;
--coral-bg: #FAECE7; --coral-text: #712B13;
}
@media (prefers-color-scheme: dark) {
:root {
--bg-primary: #1c1c1a;
--bg-secondary: #252523;
--bg-tertiary: #2e2e2b;
--text-primary: #f0ede8;
--text-secondary: #a8a8a3;
--text-tertiary: #6b6b67;
--border: rgba(255,255,255,0.10);
--border-med: rgba(255,255,255,0.18);
--green-bg: #173404; --green-text: #C0DD97;
--blue-bg: #042C53; --blue-text: #B5D4F4;
--amber-bg: #412402; --amber-text: #FAC775;
--red-bg: #501313; --red-text: #F7C1C1;
--coral-bg: #4A1B0C; --coral-text: #F5C4B3;
}
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
background: var(--bg-tertiary);
color: var(--text-primary);
min-height: 100vh;
padding: 1.5rem;
font-size: 14px;
line-height: 1.5;
}
.container { max-width: 1100px; margin: 0 auto; }
.header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 1.25rem;
background: var(--bg-primary);
border: 0.5px solid var(--border);
border-radius: var(--radius-lg);
padding: 1rem 1.25rem;
}
.header-left { display: flex; align-items: center; gap: 14px; }
.oil-icon {
width: 44px; height: 44px; border-radius: 50%;
background: var(--coral-bg);
display: flex; align-items: center; justify-content: center; flex-shrink: 0;
}
.ticker { font-size: 30px; font-weight: 500; }
.chg { font-size: 13px; padding: 2px 9px; border-radius: var(--radius-md); margin-left: 8px; font-weight: 500; }
.chg-up { background: var(--green-bg); color: var(--green-text); }
.chg-dn { background: var(--red-bg); color: var(--red-text); }
.pulse {
width: 8px; height: 8px; border-radius: 50%;
background: #639922; display: inline-block; margin-right: 6px;
animation: pulse 2s infinite;
}
@keyframes pulse { 0%,100%{opacity:1} 50%{opacity:.3} }
.label-sm { font-size: 11px; color: var(--text-secondary); margin-bottom: 2px; }
.btn {
font-size: 12px; padding: 5px 12px; cursor: pointer;
background: transparent; border: 0.5px solid var(--border-med);
border-radius: var(--radius-md); color: var(--text-primary);
transition: background .15s;
}
.btn:hover { background: var(--bg-secondary); }
.g4 { display: grid; grid-template-columns: repeat(4, minmax(0,1fr)); gap: 10px; margin-bottom: 1rem; }
.g3 { display: grid; grid-template-columns: repeat(3, minmax(0,1fr)); gap: 10px; margin-bottom: 1rem; }
.g2 { display: grid; grid-template-columns: repeat(2, minmax(0,1fr)); gap: 10px; margin-bottom: 1rem; }
@media (max-width: 768px) {
.g4 { grid-template-columns: repeat(2, minmax(0,1fr)); }
.g3 { grid-template-columns: repeat(1, minmax(0,1fr)); }
.g2 { grid-template-columns: repeat(1, minmax(0,1fr)); }
body { padding: .75rem; }
}
.metric {
background: var(--bg-secondary);
border-radius: var(--radius-md);
padding: 12px 14px;
}
.metric .lbl { font-size: 12px; color: var(--text-secondary); margin-bottom: 4px; }
.metric .val { font-size: 20px; font-weight: 500; }
.metric .sub { font-size: 11px; color: var(--text-tertiary); margin-top: 2px; }
.card {
background: var(--bg-primary);
border: 0.5px solid var(--border);
border-radius: var(--radius-lg);
padding: 1rem 1.25rem;
margin-bottom: 1rem;
}
.ctitle {
font-size: 14px; font-weight: 500;
margin-bottom: 12px;
display: flex; align-items: center; gap: 8px;
}
.row {
display: flex; justify-content: space-between; align-items: center;
padding: 7px 0;
border-bottom: 0.5px solid var(--border);
font-size: 13px;
}
.row:last-child { border-bottom: none; }
.badge {
font-size: 11px; padding: 2px 8px;
border-radius: var(--radius-md); font-weight: 500;
}
.b-green { background: var(--green-bg); color: var(--green-text); }
.b-blue { background: var(--blue-bg); color: var(--blue-text); }
.b-amber { background: var(--amber-bg); color: var(--amber-text); }
.b-red { background: var(--red-bg); color: var(--red-text); }
.pbar { height: 6px; background: var(--bg-secondary); border-radius: 3px; overflow: hidden; margin-top: 6px; }
.pfill { height: 100%; border-radius: 3px; transition: width .4s; }
.dot { width: 8px; height: 8px; border-radius: 50%; display: inline-block; margin-right: 6px; }
.liq-bar {
position: relative; height: 26px;
background: var(--bg-secondary);
border-radius: var(--radius-md); overflow: hidden; margin: 8px 0;
}
.trade-row {
display: flex; justify-content: space-between; align-items: center;
padding: 6px 0; border-bottom: 0.5px solid var(--border); font-size: 12px;
}
.trade-row:last-child { border-bottom: none; }
.param-grid { display: grid; grid-template-columns: repeat(3, minmax(0,1fr)); gap: 8px; }
.param-item { padding: 6px 0; }
.param-item .p-lbl { font-size: 11px; color: var(--text-secondary); margin-bottom: 3px; }
.param-item .p-val { font-size: 13px; font-weight: 500; }
.footer {
text-align: center; margin-top: 1.5rem;
font-size: 12px; color: var(--text-tertiary);
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<div class="header-left">
<div class="oil-icon">
<svg width="26" height="26" viewBox="0 0 24 24" fill="none">
<ellipse cx="12" cy="17" rx="6" ry="4" fill="#D85A30"/>
<path d="M8 17 Q8 10 12 5 Q16 10 16 17" fill="#D85A30"/>
<ellipse cx="12" cy="17" rx="6" ry="4" fill="#F0997B"/>
<path d="M9 16 Q9 10.5 12 6.5 Q15 10.5 15 16" fill="#F0997B"/>
<ellipse cx="12" cy="16.5" rx="3.5" ry="2" fill="#993C1D"/>
<rect x="11" y="3" width="2" height="3" rx="1" fill="#D85A30"/>
<rect x="10" y="2" width="4" height="1.5" rx="0.75" fill="#993C1D"/>
</svg>
</div>
<div>
<div class="label-sm"><span class="pulse"></span>Live · CL-USDT-SWAP · WTI Crude Oil</div>
<span class="ticker" id="price">$101.14</span>
<span class="chg chg-up" id="chg">+0.06%</span>
</div>
</div>
<div style="text-align:right;">
<div class="label-sm">Last update</div>
<div style="font-size:13px;font-weight:500;" id="lastUpdate">—</div>
<button class="btn" onclick="refresh()" style="margin-top:6px;">
<i class="ti ti-refresh"></i> Refresh
</button>
</div>
</div>
<div class="g4">
<div class="metric">
<div class="lbl">Avg entry</div>
<div class="val" id="avgEntry">$101.14</div>
<div class="sub" id="posSub">1 contract open</div>
</div>
<div class="metric">
<div class="lbl">Break-even (fees incl.)</div>
<div class="val" id="breakeven">$101.19</div>
<div class="sub">entry + exit fees</div>
</div>
<div class="metric">
<div class="lbl">Take profit target</div>
<div class="val" id="tpPrice">$101.49</div>
<div class="sub">0.30% above break-even</div>
</div>
<div class="metric">
<div class="lbl">Unrealized PnL</div>
<div class="val" id="pnl">$0.00</div>
<div class="sub" id="pnlSub">after all fees</div>
</div>
</div>
<div class="card">
<div class="ctitle"><i class="ti ti-chart-line"></i> Price history & key levels</div>
<div style="position:relative;height:140px;">
<canvas id="priceChart"></canvas>
</div>
<div style="display:flex;gap:16px;font-size:11px;color:var(--text-secondary);margin-top:8px;flex-wrap:wrap;">
<span style="color:#378ADD;">— Price</span>
<span style="color:#639922;">— TP: <span id="tpLeg">$101.49</span></span>
<span style="color:#185FA5;">— Break-even: <span id="beLeg">$101.19</span></span>
<span style="color:#888780;">— Avg entry: <span id="avgLeg">$101.14</span></span>
<span style="color:#E24B4A;">— Liq: <span id="liqLeg">$81.55</span></span>
</div>
</div>
<div class="g2">
<div class="card">
<div class="ctitle"><i class="ti ti-shield"></i> Risk & liquidation</div>
<div class="liq-bar">
<div style="position:absolute;left:0;top:0;width:58%;height:100%;background:var(--green-bg);"></div>
<div style="position:absolute;left:58%;top:0;width:22%;height:100%;background:var(--amber-bg);"></div>
<div style="position:absolute;right:0;top:0;width:20%;height:100%;background:var(--red-bg);"></div>
<div style="position:absolute;left:72%;top:0;width:2px;height:100%;background:#185FA5;"></div>
<span style="position:absolute;left:3%;top:50%;transform:translateY(-50%);font-size:10px;color:var(--green-text);">Safe</span>
<span style="position:absolute;left:60%;top:50%;transform:translateY(-50%);font-size:10px;color:var(--amber-text);">Warn</span>
<span style="position:absolute;right:3%;top:50%;transform:translateY(-50%);font-size:10px;color:var(--red-text);">Liq</span>
</div>
<div class="row"><span style="color:var(--text-secondary);">Liquidation price</span><span style="color:#A32D2D;font-weight:500;" id="liqPrice">$81.55</span></div>
<div class="row"><span style="color:var(--text-secondary);">Distance to liq.</span><span style="color:#639922;font-weight:500;" id="liqDist">19.37%</span></div>
<div class="row"><span style="color:var(--text-secondary);">Leverage</span><span><span class="badge b-amber">5x</span></span></div>
<div class="row"><span style="color:var(--text-secondary);">Margin mode</span><span>Cross</span></div>
<div class="row"><span style="color:var(--text-secondary);">Fee rate</span><span>0.05% / side</span></div>
</div>
<div class="card">
<div class="ctitle"><i class="ti ti-list"></i> Open positions & DCA levels</div>
<div class="trade-row" style="font-size:11px;color:var(--text-secondary);">
<span>Order</span><span>Entry</span><span>Size</span><span>PnL</span>
</div>
<div class="trade-row">
<span><span class="badge b-green">Long #1</span></span>
<span id="pos1entry">$101.14</span>
<span>1 bbl</span>
<span id="pos1pnl" style="color:#3B6D11;">$0.00</span>
</div>
<div style="margin-top:12px;">
<div class="label-sm">Progress to take profit</div>
<div class="pbar"><div class="pfill" id="tpProg" style="width:0%;background:#639922;"></div></div>
<div style="display:flex;justify-content:space-between;font-size:11px;color:var(--text-secondary);margin-top:3px;">
<span id="beLabel">B/E $101.19</span><span id="tpLabel">TP $101.49</span>
</div>
</div>
<div style="margin-top:12px;display:grid;grid-template-columns:1fr 1fr;gap:8px;">
<div>
<div class="label-sm">Next DCA buy</div>
<div style="font-size:13px;font-weight:500;color:#185FA5;" id="nextDca">$101.13</div>
</div>
<div>
<div class="label-sm">Safety trigger</div>
<div style="font-size:13px;font-weight:500;color:#A32D2D;" id="safetyTrig">$100.64</div>
</div>
</div>
</div>
</div>
<div class="card">
<div class="ctitle"><i class="ti ti-cash"></i> Profit distribution (cumulative)</div>
<div class="g3">
<div>
<div class="row"><span><span class="dot" style="background:#639922;"></span>Spot wallet (30%)</span><span style="font-weight:500;" id="walletP">$0.0000</span></div>
<div class="pbar"><div class="pfill" style="width:30%;background:#639922;"></div></div>
</div>
<div>
<div class="row"><span><span class="dot" style="background:#185FA5;"></span>Reinvest (30%)</span><span style="font-weight:500;" id="reinvestP">$0.0000</span></div>
<div class="pbar"><div class="pfill" style="width:30%;background:#185FA5;"></div></div>
</div>
<div>
<div class="row"><span><span class="dot" style="background:#854F0B;"></span>Staking (40%)</span><span style="font-weight:500;" id="stakingP">$0.0000</span></div>
<div class="pbar"><div class="pfill" style="width:40%;background:#EF9F27;"></div></div>
</div>
</div>
<div style="border-top:0.5px solid var(--border);margin-top:8px;padding-top:10px;display:flex;justify-content:space-between;">
<span style="font-weight:500;">Total net profit</span>
<span style="font-weight:500;color:#3B6D11;" id="totalProfit">$0.0000</span>
</div>
<div style="display:flex;justify-content:space-between;margin-top:6px;font-size:13px;">
<span style="color:var(--text-secondary);">Total commission paid</span>
<span id="commission">$0.0505</span>
</div>
</div>
<div class="card">
<div class="ctitle"><i class="ti ti-activity"></i> Bot statistics</div>
<div class="g4">
<div class="metric"><div class="lbl">Total buys</div><div class="val" id="buyCount">1</div><div class="sub">incl. safety orders</div></div>
<div class="metric"><div class="lbl">Take profits</div><div class="val" id="tpCount">0</div><div class="sub">completed cycles</div></div>
<div class="metric"><div class="lbl">Safety orders</div><div class="val" id="safetyCount">0</div><div class="sub">2x size triggered</div></div>
<div class="metric"><div class="lbl">Base order</div><div class="val" id="baseOrder">$1.00</div><div class="sub">current margin</div></div>
</div>
</div>
<div class="card">
<div class="ctitle"><i class="ti ti-settings"></i> Bot parameters</div>
<div class="param-grid">
<div class="param-item"><div class="p-lbl">Symbol</div><div class="p-val">CL-USDT-SWAP</div></div>
<div class="param-item"><div class="p-lbl">Contract size</div><div class="p-val">1 barrel</div></div>
<div class="param-item"><div class="p-lbl">DCA step</div><div class="p-val">$0.01 drop</div></div>
<div class="param-item"><div class="p-lbl">Take profit</div><div class="p-val">0.30% above B/E</div></div>
<div class="param-item"><div class="p-lbl">Safety trigger</div><div class="p-val">0.50% below avg</div></div>
<div class="param-item"><div class="p-lbl">Check interval</div><div class="p-val">Every 5 seconds</div></div>
</div>
</div>
<div class="footer">
WTI Crude Oil DCA Bot · OKX · Auto-refreshes every 5s
</div>
</div>
<script>
const CTVAL=1.0,FEE=0.0005,TP_R=0.003,SF_R=0.005,STEP=0.01;
const s={
price:101.14,avg:101.14,qty:1,cycFees:0.0505,commission:0.0505,
netProfit:0,wallet:0,reinvest:0,staking:0,
buyCount:1,tpCount:0,safetyCount:0,baseOrder:1.00,history:[]
};
for(let i=30;i>0;i--) s.history.push(+(101.14+(Math.random()-.5)*1.2).toFixed(2));
s.history.push(s.price);
function be(){ const p=s.qty*CTVAL*(1-FEE); return p>0?(s.avg*s.qty*CTVAL+s.cycFees)/p:s.avg; }
function tp(){ return +(be()*(1+TP_R)).toFixed(4); }
function liq(){ return +(s.avg*(1-1/5+0.005)).toFixed(2); }
let chart;
function initChart(){
const ctx=document.getElementById('priceChart').getContext('2d');
chart=new Chart(ctx,{
type:'line',
data:{
labels:s.history.map((_,i)=>i===s.history.length-1?'Now':''),
datasets:[{data:[...s.history],borderColor:'#378ADD',borderWidth:1.5,pointRadius:0,tension:.3,fill:false}]
},
options:{
responsive:true,maintainAspectRatio:false,
plugins:{legend:{display:false},tooltip:{callbacks:{label:c=>'$'+c.raw.toFixed(2)}}},
scales:{
x:{display:false},
y:{display:true,ticks:{font:{size:10},color:'#888',callback:v=>'$'+v.toFixed(2)},
grid:{color:'rgba(128,128,128,0.08)'}}
},animation:{duration:300}
}
});
}
function updateUI(){
const p=s.price,beV=be(),tpV=tp(),liqV=liq();
const pnl=(p-s.avg)*s.qty*CTVAL-s.cycFees;
const prog=beV>0&&tpV>beV?Math.max(0,Math.min(100,((p-beV)/(tpV-beV))*100)):0;
const liqD=liqV>0?((p/liqV)-1)*100:0;
const chgPct=((p/101.08)-1)*100;
const pnlPct=beV>0?((p/beV)-1)*100:0;
document.getElementById('price').textContent='$'+p.toFixed(2);
document.getElementById('avgEntry').textContent='$'+s.avg.toFixed(2);
document.getElementById('posSub').textContent=s.qty+' contract'+(s.qty>1?'s':'')+' open';
document.getElementById('breakeven').textContent='$'+beV.toFixed(4);
document.getElementById('tpPrice').textContent='$'+tpV;
document.getElementById('pnl').textContent=(pnl>=0?'+':'')+'$'+pnl.toFixed(4);
document.getElementById('pnl').style.color=pnl>=0?'#3B6D11':'#A32D2D';
document.getElementById('pnlSub').textContent=(pnlPct>=0?'+':'')+pnlPct.toFixed(3)+'% vs B/E';
document.getElementById('pos1entry').textContent='$'+s.avg.toFixed(2);
document.getElementById('pos1pnl').textContent=(pnl>=0?'+':'')+'$'+pnl.toFixed(4);
document.getElementById('pos1pnl').style.color=pnl>=0?'#3B6D11':'#A32D2D';
document.getElementById('tpProg').style.width=prog.toFixed(1)+'%';
document.getElementById('beLabel').textContent='B/E $'+beV.toFixed(2);
document.getElementById('tpLabel').textContent='TP $'+parseFloat(tpV).toFixed(2);
document.getElementById('tpLeg').textContent='$'+parseFloat(tpV).toFixed(2);
document.getElementById('beLeg').textContent='$'+beV.toFixed(2);
document.getElementById('avgLeg').textContent='$'+s.avg.toFixed(2);
document.getElementById('liqLeg').textContent='$'+liqV;
document.getElementById('liqPrice').textContent='$'+liqV;
document.getElementById('liqDist').textContent=liqD.toFixed(2)+'%';
document.getElementById('nextDca').textContent='$'+(s.price-STEP).toFixed(2);
document.getElementById('safetyTrig').textContent='$'+(s.avg*(1-SF_R)).toFixed(2);
document.getElementById('walletP').textContent='$'+s.wallet.toFixed(4);
document.getElementById('reinvestP').textContent='$'+s.reinvest.toFixed(4);
document.getElementById('stakingP').textContent='$'+s.staking.toFixed(4);
document.getElementById('totalProfit').textContent='$'+s.netProfit.toFixed(4);
document.getElementById('commission').textContent='$'+s.commission.toFixed(4);
document.getElementById('buyCount').textContent=s.buyCount;
document.getElementById('tpCount').textContent=s.tpCount;
document.getElementById('safetyCount').textContent=s.safetyCount;
document.getElementById('baseOrder').textContent='$'+s.baseOrder.toFixed(2);
document.getElementById('lastUpdate').textContent=new Date().toLocaleTimeString('en-US',{hour12:false});
const cel=document.getElementById('chg');
cel.textContent=(chgPct>=0?'+':'')+chgPct.toFixed(2)+'%';
cel.className='chg '+(chgPct>=0?'chg-up':'chg-dn');
}
function refresh(){
const d=(Math.random()-.48)*.15;
s.price=+(s.price+d).toFixed(2);
s.history.push(s.price);
if(s.history.length>60)s.history.shift();
if(chart){
chart.data.labels=s.history.map((_,i)=>i===s.history.length-1?'Now':'');
chart.data.datasets[0].data=[...s.history];
chart.update();
}
updateUI();
}
initChart();
updateUI();
setInterval(refresh,5000);
</script>
</body>
</html>