From 5e09bdbdcc5e9b29b265855cb6e208b1dc3e565b Mon Sep 17 00:00:00 2001 From: Theodore Song Date: Sun, 12 Jul 2026 11:41:10 -0400 Subject: [PATCH] Polish return charts --- index.html | 75 +++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 51 insertions(+), 24 deletions(-) diff --git a/index.html b/index.html index d121d4a..359b925 100644 --- a/index.html +++ b/index.html @@ -107,10 +107,11 @@ h1,h2,h3,.brand-name{font-family:'Space Grotesk','Inter',sans-serif} .pos-val{color:var(--green)}.neg-val{color:var(--red)} /* ---------- charts ---------- */ -#chart,#chart2{width:100%;height:240px;display:block} -.legend{display:flex;flex-wrap:wrap;gap:8px 16px;margin-top:14px} -.leg{display:flex;align-items:center;gap:7px;font-size:12.5px;color:#cdd6e8} -.legdot{width:10px;height:10px;border-radius:3px;display:inline-block} +#chart,#chart2{width:100%;height:300px;display:block;margin-top:6px;overflow:visible} +.legend{display:grid;grid-template-columns:repeat(auto-fit,minmax(170px,1fr));gap:8px 12px;margin-top:14px} +.leg{display:flex;align-items:center;gap:8px;font-size:12px;color:#cdd6e8;background:rgba(255,255,255,.035);border:1px solid rgba(255,255,255,.06);border-radius:8px;padding:7px 9px;min-width:0} +.leg b{margin-left:auto;font-family:'Space Grotesk',sans-serif} +.legdot{width:9px;height:9px;border-radius:50%;display:inline-block;box-shadow:0 0 0 3px rgba(255,255,255,.06)} .rangebar{display:flex;gap:5px;flex-wrap:wrap;justify-content:flex-end} .rangebtn{appearance:none;border:1px solid var(--border);background:rgba(255,255,255,.04);color:var(--muted); font:700 11px 'Inter',sans-serif;padding:5px 8px;border-radius:8px;cursor:pointer} @@ -223,6 +224,8 @@ a.market-title:hover{color:#fff;text-decoration:underline;text-decoration-color: .btn{padding:9px 11px} .section-title{font-size:19px} .stats{grid-template-columns:1fr;gap:12px} + #chart,#chart2{height:280px} + .legend{grid-template-columns:1fr} .agent-brief{grid-template-columns:1fr} .pos{align-items:flex-start;gap:12px} .pos .pq{max-width:none} @@ -311,7 +314,7 @@ footer{margin-top:34px;padding-top:22px;border-top:1px solid var(--border);color

Agent Returns

- +
Use the range buttons to zoom from one week to all history. New live points are added whenever you click "Run cycle"; the dashed line tracks the average agent return.
@@ -328,7 +331,7 @@ footer{margin-top:34px;padding-top:22px;border-top:1px solid var(--border);color

Returns — all agents

$10,000 start each
- +
Past week is a backtest. After that, each manual or daily run adds another return snapshot for every agent.
@@ -1262,6 +1265,25 @@ function chartTicks(times,maxTicks=5){ } return ticks; } +function niceChartBounds(vals){ + let min=Math.min(...vals,0),max=Math.max(...vals,0); + if(min===max){min-=1;max+=1;} + const span=max-min,pad=Math.max(0.5,span*0.12); + min-=pad;max+=pad; + const step=Math.max(0.5,Math.pow(10,Math.floor(Math.log10(max-min)))/2); + min=Math.floor(min/step)*step;max=Math.ceil(max/step)*step; + return {min,max}; +} +function smoothPath(points){ + if(points.length<2)return points.map((p,i)=>`${i?"L":"M"}${p.x},${p.y}`).join(" "); + let d=`M${points[0].x},${points[0].y}`; + for(let i=1;ir.id===chartRange())||CHART_RANGES[0]; if(!range.days)return times; @@ -1278,7 +1300,7 @@ function drawCombo(svgId,legendId){ const allTimes=rangeFilteredTimes([...new Set(series.flatMap(s=>s.snaps.map(snapTime)))].sort((a,b)=>a-b)); const svg=$(svgId); if(!svg)return; if(!allTimes.length){svg.innerHTML="";if($(legendId))$(legendId).innerHTML=`No history yet — click "Run cycle".`;return;} - const W=600,H=240,padL=42,padR=18,padT=18,padB=38; const vals=[0]; + const W=720,H=300,padL=58,padR=28,padT=34,padB=50; const vals=[0]; const lines=series.map(s=>{ let last=0,idx=0; const pts=allTimes.map(t=>{ @@ -1292,37 +1314,42 @@ function drawCombo(svgId,legendId){ }); const avgPts=allTimes.map((_,i)=>+(lines.reduce((sum,l)=>sum+l.pts[i],0)/Math.max(1,lines.length)).toFixed(2)); vals.push(...avgPts); - const min=Math.min(...vals,0),max=Math.max(...vals,0),span=(max-min)||1; + const bounds=niceChartBounds(vals),min=bounds.min,max=bounds.max,span=(max-min)||1; const x=i=>allTimes.length===1?(padL+(W-padR))/2:padL+(i/(allTimes.length-1))*(W-padL-padR); const y=v=>H-padB-((v-min)/span)*(H-padT-padB); - const yTicks=[...new Set([min,(min+max)/2,max].map(v=>+v.toFixed(1)))]; + const yTicks=Array.from({length:5},(_,i)=>+(min+(span*i/4)).toFixed(1)); const zeroY=y(0).toFixed(1); let inner=` - - + + + + + `; - inner+=``; + inner+=``; for(const v of yTicks){ const yy=y(v).toFixed(1); - inner+=``; - inner+=`${fmtPct(v)}`; + inner+=``; + inner+=`${fmtPct(v)}`; } - inner+=``; + inner+=``; for(const tick of chartTicks(allTimes,5)){ const xx=x(tick.i).toFixed(1); - inner+=``; - inner+=`${chartDateLabel(tick.t,true)}`; + inner+=``; + inner+=`${chartDateLabel(tick.t,true)}`; } for(const ln of lines){ - const d=ln.pts.map((v,i)=>`${i===0?"M":"L"}${x(i).toFixed(1)},${y(v).toFixed(1)}`).join(" "); - const dot=allTimes.length===1?``:""; - inner+=`${dot}`; + const points=ln.pts.map((v,i)=>({x:x(i).toFixed(1),y:y(v).toFixed(1)})); + const d=smoothPath(points); + const last=points[points.length-1]; + inner+=``; + inner+=``; } - const avgD=avgPts.map((v,i)=>`${i===0?"M":"L"}${x(i).toFixed(1)},${y(v).toFixed(1)}`).join(" "); - inner+=``; - inner+=`${chartDateLabel(allTimes[0])}`; - inner+=`${chartDateLabel(allTimes[allTimes.length-1])}`; + const avgPoints=avgPts.map((v,i)=>({x:x(i).toFixed(1),y:y(v).toFixed(1)})); + inner+=``; + inner+=`Return %`; + inner+=`${chartDateLabel(allTimes[0])} - ${chartDateLabel(allTimes[allTimes.length-1])}`; svg.innerHTML=inner; if($(legendId)){ const b=board();const avg=b.reduce((s,r)=>s+r.ret,0)/b.length;