React + Vite frontend with a local-JSON-backed API (Vite middleware) for tracking portfolio holdings, contributions/withdrawals, recurring contribution plans, and a forecast chart comparing the portfolio's real value against a same-contributions S&P 500 benchmark. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
59 lines
2.4 KiB
Markdown
59 lines
2.4 KiB
Markdown
# Investment Visualizer
|
|
|
|
A personal investment dashboard: track contributions, see asset allocation, and
|
|
compare your portfolio's performance against the S&P 500.
|
|
|
|
## Stack
|
|
|
|
- **Frontend**: React + TypeScript + Vite, charts with Recharts.
|
|
- **Backend**: a small REST API implemented as a Vite dev-server middleware
|
|
(`server/apiPlugin.ts`) backed by local JSON files in `data/`. No database,
|
|
no separate process — `npm run dev` starts both.
|
|
- **Data**: everything lives under `data/*.json`. The API layer
|
|
(`src/api/client.ts`) is the only place that knows the data lives in local
|
|
files — swapping it for a real backend later means only changing that file.
|
|
|
|
## Data model (`data/`)
|
|
|
|
- `portfolio.json` — current holdings snapshot (values, asset class, region,
|
|
RV/RF allocation).
|
|
- `history.json` — periodic total-account-value snapshots, used to compute
|
|
time-weighted return (TWR). Add more snapshots over time for a more accurate
|
|
performance line.
|
|
- `contributions.json` — the movements ledger (external contributions/
|
|
withdrawals plus internal fund subscriptions/redemptions) and recurring
|
|
contribution plans (weekly/monthly/etc.) used to project future cash flows.
|
|
- `settings.json` — portfolio inception date, forecast horizon (years), and
|
|
the assumed annual return used for the projected part of the chart
|
|
(historical TWR-derived or a manual assumption).
|
|
- `sp500.json` — cached daily S&P 500 closes, refreshed with:
|
|
|
|
```bash
|
|
node scripts/fetch-sp500.mjs
|
|
```
|
|
|
|
## Performance methodology
|
|
|
|
- **Portfolio return**: simplified chain-linked time-weighted return (TWR)
|
|
computed from `history.json` snapshots and external cash flows in
|
|
`contributions.json`. Internal fund subscriptions/redemptions net to zero on
|
|
total account value and don't affect it.
|
|
- **S&P 500 line**: percentage change of the index since the portfolio's
|
|
inception date, for an apples-to-apples "who's outperforming whom"
|
|
comparison against the portfolio's TWR line.
|
|
- **Forecast segment**: continues the portfolio line past today using either
|
|
the historical annualized TWR or a manual rate, applied to the current value
|
|
plus projected future contributions from active recurring plans.
|
|
- **0% baseline**: cumulative net contributions (actual + projected) with no
|
|
investment return at all — the reference line for "what if it just sat in
|
|
cash."
|
|
|
|
## Development
|
|
|
|
```bash
|
|
npm install
|
|
npm run dev
|
|
```
|
|
|
|
This starts Vite (frontend + local JSON API) on http://localhost:5173.
|