zfin/docs/reference/cli/snapshot.md
Emil Lerch 6ebd944f94
All checks were successful
Generic zig build / build (push) Successful in 6m49s
Generic zig build / deploy (push) Successful in 20s
Generic zig build / publish-macos (push) Successful in 1m2s
additional snapshot documentation
2026-08-21 12:38:13 -07:00

3.6 KiB

zfin snapshot

Compute a portfolio snapshot and write it to history/ -- the building block of your value time series.

Usage: zfin snapshot [opts]

By default, refreshes candles for held symbols, derives the as-of date from the cached candle dates, prices each lot at the close on or before that date, and writes history/<as_of_date>-portfolio.srf atomically. The file is a discriminated SRF whose records start with kind::<meta|total|tax_type|account|lot>.

Options

Flag Effect
--dry-run Compute and print to stdout; write nothing.
--force Overwrite an existing snapshot for the date.
--out <path> Override the output path.
--as-of <DATE> Write a snapshot for a historical date (uses git to recover state and the candle cache for pricing). Accepts YYYY-MM-DD or 1W/1M/1Q/1Y.

If the target file already exists and --force isn't passed, the run skips with a stderr message.

What gets written

Each snapshot is a valuation record for one date, in two layers:

Record kind Contents
meta As-of date, capture time, zfin version, quote-date span, stale-quote count.
total net_worth, liquid, illiquid. Authoritative totals.
tax_type Value per tax treatment (Traditional, Roth, Taxable, HSA).
account Value per account.
lot Per-lot decomposition: symbol, account, security type, shares, open price, cost basis, price, value, quote date/staleness.

Two things to know before reading lot rows:

  • The total rows are authoritative. Lot rows are a decomposition aid and do not carry portfolio-level adjustments, so summing them is not guaranteed to reproduce total::liquid exactly.
  • What shares, open_price, cost_basis, and value mean differs by security type, and so do the relationships between them. In particular, a stock lot's shares is the raw as-transacted count while its value is split-adjusted, so shares * price is not generally value.

A snapshot deliberately omits most of a lot's detail -- it is not a lot-level record. The snapshot model covers the full field semantics, what is left out, and why.

Examples

zfin snapshot --dry-run            # preview today's snapshot
zfin snapshot                      # write history/<today>-portfolio.srf
zfin snapshot --as-of 2025-01-02   # back-fill a past date

Automate with cron for a self-building series:

0 18 * * 1-5  cd ~/finance && /usr/local/bin/zfin snapshot

See also


CLI command reference