zfin/docs/reference/cli/audit.md
Emil Lerch 0e1a4862db
All checks were successful
Generic zig build / build (push) Successful in 4m56s
Generic zig build / publish-macos (push) Successful in 17s
Generic zig build / deploy (push) Successful in 24s
add stale harvesting date checks to audit command
2026-07-25 10:45:12 -07:00

82 lines
3.6 KiB
Markdown

# `zfin audit`
Two modes in one command: a portfolio hygiene check, and reconciliation
against a brokerage export.
```
Usage: zfin audit [opts]
```
**Flagless** runs the hygiene check -- stale manual prices,
accounts overdue for update, stale tax-loss-harvested figures,
unhandled stock splits, and auto-discovered brokerage-file candidates.
**With brokerage flags**, it reconciles your portfolio against the
export (treating the brokerage as source of truth) and reports
discrepancies.
## Options
| Flag | Effect |
|--------------------|----------------------------------------------------------------------------|
| `--verbose` | Show full reconciliation output even when clean. |
| `--stale-days <N>` | Manual-price staleness threshold (default 3). |
| `--fidelity <CSV>` | Fidelity positions CSV ("All accounts" -> Positions tab -> Download). |
| `--schwab <CSV>` | Schwab per-account positions CSV. |
| `--schwab-summary` | Schwab account summary: paste from the summary page to stdin, then Ctrl-D. |
Reconciliation matches export accounts to yours via `institution::` and
`account_number::` in [`accounts.srf`](../config/accounts-srf.md); an
unmatched account is reported as "unmapped."
The hygiene check also flags newly-appeared lots worth at least
$10,000 in a **Large new lots - confirm source** section, so you can
confirm whether each is a real contribution or an unrecorded transfer.
The cutoff is per account -- raise or lower it on an account's record
via [`audit_large_lot_threshold`](../config/accounts-srf.md#audit_large_lot_threshold)
in `accounts.srf` (e.g. to silence a noisy ESPP account).
It also lists held symbols that had a stock split *after* a lot's
purchase date but haven't opted into automatic split adjustment, in an
**Unhandled stock splits** section. Each needs a
[`splits_current_through`](../config/metadata-srf.md#stock-split-adjustment)
date on its `metadata.srf` row -- without it, that holding's shares (and
every value derived from them) are misstated across the split.
Accounts carrying a hand-declared
[`harvested`](../config/accounts-srf.md#harvested-and-harvested_date)
figure get a **Stale harvested figures** section once the figure is more
than 90 days old, or if it has no `harvested_date` at all. The section
is omitted entirely for portfolios where no account declares one. Past
12 months the annotation itself retires, and the nag says
`no longer displayed` so it can't vanish without explanation.
## Example (hygiene check)
```bash
ZFIN_HOME=examples/pre-retirement-both zfin audit
```
```
Portfolio hygiene
Stale manual prices (>3 days - --stale-days to configure)
(none)
Accounts overdue for update (weekly default - set update_cadence in accounts.srf)
Sam 401k weekly no update history found
Joint taxable weekly no update history found
```
> Brokerage exports contain real account numbers and holdings. Keep
> them out of any git repo and delete them after reconciling.
## See also
- [Audit against your brokerage](../../guides/audit-against-brokerage.md) -- the workflow.
- [`import`](import.md) -- build a portfolio file *from* an export instead.
- [`accounts.srf` reference](../config/accounts-srf.md) -- `update_cadence`, `institution`, `account_number`.
- [`metadata.srf` reference](../config/metadata-srf.md#stock-split-adjustment) -- `splits_current_through` for the unhandled-splits check.
---
[CLI command reference](index.md)