zfin/docs/guides/snapshots-and-history.md
Emil Lerch f1cabdcf9a
All checks were successful
Generic zig build / build (push) Successful in 4m54s
Generic zig build / deploy (push) Successful in 19s
Generic zig build / publish-macos (push) Successful in 32s
add stock split guide with full rationale
2026-07-06 14:25:56 -07:00

5.6 KiB

Snapshots and history

Goal: record your portfolio's value over time and review how it has changed -- day to day, year over year, and between any two dates.

You'll need: a working portfolio. The post-retirement example ships with a history/ folder of snapshots, so you can explore the read side immediately:

ZFIN_HOME=examples/post-retirement zfin history

The idea

zfin doesn't track your value automatically -- it reads what you have right now. To build a time series, you write a snapshot each day (or week), and the history/compare commands read those snapshots back.

Snapshots live in <portfolio-dir>/history/<date>-portfolio.srf. Each is an immutable record of totals, per-account values, and lot-level state for one date.

1. Write a snapshot

The simplest way is to run it yourself. zfin snapshot computes today's snapshot and writes it under history/. Try a dry run first -- it computes and prints the snapshot without writing anything:

zfin snapshot --dry-run        # compute + print, write nothing
zfin snapshot                  # write history/<today>-portfolio.srf

Run it whenever you want a record on the books -- after a monthly review, say. The snapshot is just a file in history/; nothing else is required.

Back-filling a past date (optional, needs git). If you keep your portfolio file under git version control, --as-of can reconstruct a snapshot for an earlier date: it recovers your portfolio as it was then (from git) and prices it from the cached price history.

zfin snapshot --as-of 2025-01-02

If you don't use git, skip this -- just snapshot going forward.

2. Keep it current automatically (optional)

Most people would rather not remember to run it every day. You can hand that off to your operating system's task scheduler -- a built-in service that runs a command on a set timetable, even while you're away.

When to schedule it. Run it in the early morning, after the prior trading day's closing prices have posted. ETF and mutual-fund values update overnight, and while data providers say "after midnight," in practice 3:30am US Eastern is the first time yesterday's closing NAVs reliably land -- schedule it earlier and you risk capturing stale prices.

macOS and Linux use cron. Run crontab -e and add a line like this (3:30am, Monday-Friday -- adjust the hour for your machine's timezone if it isn't US Eastern):

30 3 * * 1-5  cd ~/finance && /usr/local/bin/zfin snapshot

The five fields are minute, hour, day-of-month, month, day-of-week (1-5 = Mon-Fri); the full path to zfin matters because cron runs with a minimal PATH. macOS ships cron, though the first run may prompt you to grant your terminal "Full Disk Access."

Windows has no cron -- use Task Scheduler to run zfin snapshot daily. (zfin should run on Windows, but it isn't regularly tested there.)

3. Review the timeline with history

Run zfin history with no symbol for the portfolio-value timeline: rolling-window changes, a chart (an inline Kitty image when your terminal supports it, else braille), and a recent-snapshots table.

ZFIN_HOME=examples/post-retirement zfin history
Portfolio Timeline: Liquid
========================================
  Change                        Δ           %      % / yr
  1 year              +$230,000.00      +9.79%      +9.79%
  3 years             +$459,059.08     +21.64%      +6.72%
  5 years             +$686,215.45     +36.24%      +6.37%
  All-time          +$1,073,725.79     +71.28%      +6.00%

Useful flags: --metric liquid|illiquid|net_worth, --since / --until to bound the window, and --resolution daily|weekly|monthly.

The percentage change includes contributions and withdrawals, not just market movement. To separate new money from market gains, use contributions.

4. Compare two points with compare

zfin compare diffs two dates: liquid totals, per-symbol price moves, and -- when your portfolio is tracked in git -- contribution attribution. Pass one date to compare against the live portfolio, or two dates to compare historical snapshots:

ZFIN_HOME=examples/post-retirement zfin compare 2024-04-01 2025-04-01
Portfolio comparison: 2024-04-01 -> 2025-04-01 (365 days)

Liquid:  $2,350,000.00 -> $2,580,000.00    +$230,000.00   +9.79%

Arguments can be given in any order; output always reads older -> newer. On a missing snapshot date, compare prints the nearest available dates and exits rather than silently snapping. Add --projections to include projected-return and safe-withdrawal deltas.

Back-history without daily snapshots

If you have historical totals from a spreadsheet but no per-day snapshots, record them in history/imported_values.srf (one liquid:: total per date). The history and projection-overlay tools read it as a lower-fidelity fallback when no native snapshot covers a date. The post-retirement example includes one spanning 2016-2024.

Next steps


Previous: Track contributions | Next: Handle a stock split | Documentation home