Compound Your Future
INVESTING · PERFORMANCE LAB

Did you beat the market?

Drop in your portfolio's historical values and a benchmark's historical prices. Compare growth on the same dates—without sending your files to a server.

↥ Your portfolio CSVDrag & drop or choose a filedate,value · e.g. 2025-01-02,10000No file selected

Loading historical benchmark prices…

One-click comparison

Historical benchmark prices are refreshed automatically when the data service is available. No benchmark upload required.

Portfolio values must exclude deposits and withdrawals during the comparison period. Benchmark prices are historical daily series, not live quotes. This comparison is price-based unless the source explicitly supplies adjusted total-return prices.

How to prepare your files

Export historical portfolio values from your brokerage or spreadsheet, with a date and a total value on each row. Select a benchmark above; no ETF file is required. Your portfolio file is processed locally in your browser.

Important: A portfolio balance series with deposits, withdrawals, or transfers is not a valid investment return series. This initial tool cannot calculate time-weighted or money-weighted returns. We plan to add transaction imports and cash-flow adjustment later.

For educational comparison only. Not investment advice. Past performance does not predict future results.

← All tools
+last.portfolio.toFixed(2)+'; '+el('benchmarkSelect').value+' el('output').classList.remove('hidden');el('message').textContent='Comparison ready.';draw()} function draw(){const c=el('chart'),rect=c.getBoundingClientRect(),dpr=window.devicePixelRatio||1;c.width=Math.round(rect.width*dpr);c.height=Math.round(rect.height*dpr);const ctx=c.getContext('2d');ctx.scale(dpr,dpr);const w=rect.width,h=rect.height,pad=40;ctx.clearRect(0,0,w,h);const values=state.rows.flatMap(r=>[r.portfolio,r.benchmark]);let min=Math.min(...values),max=Math.max(...values);if(max===min){max+=1;min-=1}const x=i=>pad+i*(w-pad-15)/(state.rows.length-1),y=v=>h-pad-(v-min)/(max-min)*(h-2*pad);ctx.strokeStyle='#dce8e0';for(let i=0;i<4;i++){const yy=pad+i*(h-2*pad)/3;ctx.beginPath();ctx.moveTo(pad,yy);ctx.lineTo(w-10,yy);ctx.stroke()}for(const [key,color] of [['portfolio','#0a9c77'],['benchmark','#466fbd']]){ctx.beginPath();ctx.strokeStyle=color;ctx.lineWidth=3;state.rows.forEach((r,i)=>i?ctx.lineTo(x(i),y(r[key])):ctx.moveTo(x(i),y(r[key])));ctx.stroke()}ctx.fillStyle='#0a9c77';ctx.font='13px sans-serif';ctx.fillText('Portfolio',pad,20);ctx.fillStyle='#466fbd';ctx.fillText('Benchmark',pad+90,20)} window.addEventListener('resize',()=>{if(state.rows.length)draw()});el('download').addEventListener('click',()=>{const csv='date,portfolio_normalized,benchmark_normalized\n'+state.rows.map(r=>[r.date,r.portfolio.toFixed(4),r.benchmark.toFixed(4)].join(',')).join('\n');const url=URL.createObjectURL(new Blob([csv],{type:'text/csv'}));const a=document.createElement('a');a.href=url;a.download='Compound Your Future-comparison.csv';a.click();URL.revokeObjectURL(url)}); +last.benchmark.toFixed(2)+'. Benchmark values reflect the data provider’s historical price series, not necessarily total return including reinvested dividends.';el('output').classList.remove('hidden');el('message').textContent='Comparison ready.';draw()} function draw(){const c=el('chart'),rect=c.getBoundingClientRect(),dpr=window.devicePixelRatio||1;c.width=Math.round(rect.width*dpr);c.height=Math.round(rect.height*dpr);const ctx=c.getContext('2d');ctx.scale(dpr,dpr);const w=rect.width,h=rect.height,pad=40;ctx.clearRect(0,0,w,h);const values=state.rows.flatMap(r=>[r.portfolio,r.benchmark]);let min=Math.min(...values),max=Math.max(...values);if(max===min){max+=1;min-=1}const x=i=>pad+i*(w-pad-15)/(state.rows.length-1),y=v=>h-pad-(v-min)/(max-min)*(h-2*pad);ctx.strokeStyle='#dce8e0';for(let i=0;i<4;i++){const yy=pad+i*(h-2*pad)/3;ctx.beginPath();ctx.moveTo(pad,yy);ctx.lineTo(w-10,yy);ctx.stroke()}for(const [key,color] of [['portfolio','#0a9c77'],['benchmark','#466fbd']]){ctx.beginPath();ctx.strokeStyle=color;ctx.lineWidth=3;state.rows.forEach((r,i)=>i?ctx.lineTo(x(i),y(r[key])):ctx.moveTo(x(i),y(r[key])));ctx.stroke()}ctx.fillStyle='#0a9c77';ctx.font='13px sans-serif';ctx.fillText('Portfolio',pad,20);ctx.fillStyle='#466fbd';ctx.fillText('Benchmark',pad+90,20)} window.addEventListener('resize',()=>{if(state.rows.length)draw()});el('download').addEventListener('click',()=>{const csv='date,portfolio_normalized,benchmark_normalized\n'+state.rows.map(r=>[r.date,r.portfolio.toFixed(4),r.benchmark.toFixed(4)].join(',')).join('\n');const url=URL.createObjectURL(new Blob([csv],{type:'text/csv'}));const a=document.createElement('a');a.href=url;a.download='Compound Your Future-comparison.csv';a.click();URL.revokeObjectURL(url)});