zfin/docs/guides/periodic-review.md
Emil Lerch 74fc219afd
All checks were successful
Generic zig build / build (push) Successful in 5m48s
Generic zig build / publish-macos (push) Successful in 11s
Generic zig build / deploy (push) Successful in 23s
add docs/guides
2026-06-22 14:53:53 -07:00

7 KiB

A periodic review

Goal: on a regular cadence -- weekly works well -- make zfin agree with your brokerages, see what changed since last time, and commit the reconciled state so the next review has a clean baseline to compare against.

This is the loop that ties the other guides together. Each step has its own guide for the details; this one is the routine you actually run. It settles into well under an hour once it's habit.

   reconcile  ──►  what changed?  ──►  (projections)  ──►  commit
   (audit)         (compare)           (optional)          (baseline)
      ▲                                                        │
      └────────────────  next review  ◄────────────────────────┘

1. Reconcile against your brokerages

Pull a fresh export from each brokerage that offers one and drop it in your audit/ folder (or wherever you've pointed $ZFIN_AUDIT_FILES -- see Audit against your brokerage for the export steps and auto-discovery rules). Then:

zfin audit

Fix any flagged share or cash discrepancy in portfolio.srf and re-run until it reconciles. A tight edit loop helps: if you have watchexec installed,

watchexec -- zfin audit

re-runs the audit on every save, so the remaining-discrepancy list shrinks live as you fix lots -- much faster than alt-tab, rerun, read, alt-tab, edit.

Reconcile first, for a reason. Step 2 splits your change in value into contributions vs. market gains, and that split is only as honest as your share counts. Reconcile before you read the headline or the attribution will lie to you.

Blind spots the audit can't see

  • Accounts with no export (some insurers, some 401(k) recordkeepers) -- check the latest statement and update portfolio.srf by hand.
  • Payroll-driven cash -- e.g. ESPP contributions that haven't purchased yet won't appear in a positions export until the purchase posts. Reconcile those against a paystub.
  • A small, expected standing discrepancy -- some accounts just sit a few dollars off every week. Note it and move on rather than chasing it each time.
  • Lagging transaction views. A brokerage's positions view can update overnight before its transaction view posts the dividend, interest, or option assignment that caused the change. Trust the positions numbers and reconcile the totals; the cause-side record catches up later and isn't needed to get today's counts right.

2. The headline -- what changed since last time

One command gives you the whole "since last review" picture:

zfin compare 1W --projections --commit-before HEAD
  • 1W is the point of comparison -- the snapshot from one week ago. Any relative shortcut or an explicit YYYY-MM-DD works.
  • --projections folds in projected-return and safe-withdrawal (SWR@99%) deltas, then vs. now. (Costs ~1-2s per endpoint for the Monte Carlo search; add --no-events to exclude life events.)
  • --commit-before HEAD pins the contributions/gains attribution to your latest reconciliation commit. This matters -- see Attribution and commit timing.

Read off the liquid-total delta, the contributions-vs-gains split, the per-symbol winners and losers, and the projection deltas. For most weeks, this single command is the review. See Snapshots and history for a full walk through compare output.

3. (Optional) Full projections

compare --projections gives you the deltas but not the full benchmark table or every scenario row. When you want the complete picture:

zfin projections                 # default: with life events (SS, college, ...)
zfin projections --no-events     # baseline: life events excluded
zfin projections --as-of 1W      # the same table as of last review
zfin projections --vs 1W         # both ends of the window in one run

See Plan for retirement for what these rows mean.

4. Commit -- the baseline for next time

git add portfolio.srf metadata.srf history/
git commit -m "review 2026-06-20"

Committing does double duty:

  • It snapshots the reconciled portfolio.srf, and the day's snapshot file in history/ rides along, so future --as-of runs can read it.
  • zfin walks the git history of portfolio.srf for contributions analysis, treating each commit as a reconciliation point. Commit timing sets next review's baseline -- a same-day commit keeps a weekly cadence clean.

If you keep your portfolio directory in git (recommended), this is also your backup and your audit trail.

Attribution and commit timing

compare and contributions work out "contributions vs. gains" by walking the git history of portfolio.srf. The positional date (1W) picks the snapshot whose prices you compare against; --commit-before picks which commit anchors the attribution. Those two can drift apart.

If you reconcile on Saturday but don't commit until Monday, next Saturday's 1W snapshot lands before your last commit -- so a bare compare 1W would attribute two weeks of contributions to one week. --commit-before HEAD sidesteps this by pinning attribution to your most recent reconciliation commit regardless of the snapshot date. When the dates line up anyway, the flag is harmless -- which is why it's worth making a habit.

Relative dates

Every date-accepting command takes the same shorthand, so you rarely type a full date:

Shortcut Means
1W one week ago
3W three weeks ago
1M one month ago
1Q one quarter ago
1Y one year ago

compare, contributions --since/--until, projections --as-of/--vs, snapshot --as-of, and history --since/--until all accept it (plus an explicit YYYY-MM-DD).

If there's no snapshot yet

The comparison needs a snapshot to compare against. If your daily snapshot didn't run, or you're reviewing off your normal cadence, make one first:

zfin portfolio --refresh    # fresh close prices for tracked symbols
zfin snapshot               # writes history/<today>-portfolio.srf

See Snapshots and history for the cron setup that automates daily snapshots.

Next steps


Previous: Audit against your brokerage | Next: Customize the TUI | Documentation home