Origin
The Journey
I started my first real job in November 2022. For the first few paychecks I saved a little โ not much. But I'd felt what it was like to have nothing in savings, nothing set aside, and that feeling stuck with me.
In December 2022 I put in $500. That was the start.
Dec '22
The first $500
Opened a Roth IRA with no real plan. Copied other people's portfolios on M1 Finance โ not because I understood the thesis, just because someone else did.
2023
From copying to listening
Started listening to why people bought what they bought โ their backgrounds, their reasoning, their conviction. Stopped picking randomly. Started picking intentionally, even while still learning.
2024
Let it compound
Stopped checking every day. Traveled to New Zealand, caught F1 in Belgium. Went into debt doing it โ and never once touched my retirement money. Still contributed through all of it.
Now
Conviction over noise
Trimming positions in businesses I don't believe in. Doubling down on the ones I do. Every holding has a documented thesis. The spreadsheet keeps me honest.
It didn't click in a snap. It never does. But it clicked.
The Build
Why I Built This
Honestly? I just loved seeing the number go up.
I wanted a live dashboard that showed me exactly where I stood โ not a brokerage app with ads and upsells, but something I built myself that reflected how I actually think about my money. The spreadsheet came first, then the website to surface it.
It's a personal project. The most personal kind โ it's literally my net worth on the screen, updating in real time.
Technical Depth
How It's Built
๐ M1 Raw
31 positions
cost + live price
cost + live price
โ
๐ Dashboard
live totals
=SUM + =RRI
=SUM + =RRI
โ
๐ฅง Allocation
sector weights
auto-recalc
auto-recalc
โ
๐ Website
Sheets API
live render
live render
Live Prices
GOOGLEFINANCE
Every position in M1 Raw pulls its current price via
=GOOGLEFINANCE(ticker) โ no manual updates, ever. Price changes cascade through cost basis, unrealized gain, and sector allocation automatically.Growth Rate
Live CAGR via RRI
CAGR is calculated in the sheet using
=RRI(3.5, D4, B4) โ lifetime deposits vs current net worth over 3.5 years. The website fetches Dashboard!H4 directly and renders the decimal as a percentage.Architecture
Single Source of Truth
Update one position in Holdings and the Dashboard total, sector allocation, and net worth snapshot all recalculate instantly. The website is a read-only view โ the spreadsheet is the source, the site is the display.
Visualization
Net Worth Chart
Historical net worth plotted in Canvas.js โ hand-plotted data points from Dec 2022 to present with the final value updating live from the sheet on every page load.
Dashboard!H4 โ Website
GOOGLE SHEETS โ SHEETS API โ LIVE
// In Google Sheets โ RRI returns annualized growth as a decimal // 3.5 = years ยท D4 = lifetime deposits ยท B4 = current net worth =RRI(3.5, D4, B4) โ 0.167 // Sheets API fetch โ 7 ranges pulled in a single Promise.all() const [m1, k401, hsa, deposits, netWorth, alloc, cagr] = await Promise.all([ fetch(`M1 Raw!A1:H50`), // holdings + live prices fetch(`401k!C4`), // T. Rowe Price balance fetch(`HSA Holdings!F8`), // Fidelity HSA balance fetch(`Dashboard!D4`), // lifetime deposits fetch(`Dashboard!M4`), // total net worth fetch(`Allocation!B3:E11`), // sector weights fetch(`Dashboard!H4`), // live CAGR decimal ]); display(cagr * 100 + "%"); โ "16.7%"
See it live
The Dashboard
Every number on this page is real. Every position has a thesis. Updated live from Google Sheets.