zfin/docs/guides/track-contributions.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

117 lines
4.3 KiB
Markdown

# Track contributions
**Goal:** see how much new money you've added (or withdrawn) over a
period, separated from market movement -- and stop internal transfers
between your own accounts from being counted as contributions.
**You'll need:** your portfolio under **git** version control, with
commits over time. `contributions` works by diffing two revisions of
your `portfolio.srf`, so it only sees money movement you've committed.
## How it works
Market gains change your portfolio's *value*; contributions change its
*shares and lots*. [`zfin contributions`](../reference/cli/contributions.md)
diffs your portfolio file between two git revisions, attributes the
share/lot changes to contributions vs. withdrawals, and ignores price
movement.
This means the workflow is: **keep `portfolio.srf` in a git repo, and
commit it whenever you update it.** A natural cadence is a commit per
account update or per weekly review.
> **Do this bookkeeping when the market is closed -- a weekend is
> ideal.** Prices and balances have settled, your brokerage statements
> are final, and zfin's cached closing prices won't shift under you
> mid-run, so the numbers are stable and reproducible. The same applies
> to [`audit`](audit-against-brokerage.md): reconciling against an
> export lines up cleanly when both sides reflect the same settled
> close, rather than a moving intraday price.
## The default modes
With no flags, the comparison depends on your working tree:
```bash
zfin contributions
```
- **Clean working tree:** compares `HEAD~1` against `HEAD` -- i.e.
"what changed in my last commit."
- **Dirty working tree:** compares `HEAD` against the working copy --
i.e. "what have I edited but not yet committed."
Against a freshly-checked-out example (clean, nothing to diff) you'll
see:
```
Portfolio contributions report
Working tree clean — comparing HEAD~1 against HEAD
No changes detected.
```
## Choosing a window
Use `--since` (and optionally `--until`) to pick the endpoints. Dates
accept `YYYY-MM-DD` or relative shortcuts (`1W`, `1M`, `1Q`, `1Y`):
```bash
zfin contributions --since 1Y # a year ago vs. now
zfin contributions --since 2025-01-01 --until 2025-12-31
```
Each date resolves to the commit at or before it. When a review date
and its commit date diverge (you committed two days after your Sunday
review), pin commits directly with `--commit-before` / `--commit-after`
(which accept `HEAD`, `HEAD~N`, a SHA, or `working`).
## Don't double-count transfers
Moving money between two accounts you own isn't a contribution, but a
naive diff sees the receiving account gain lots and counts it as new
money. `transaction_log.srf` is how you tell zfin "this was a transfer,
not new money."
Like the other sibling files, it's **optional and additive**: you only
need it if you move money between your own accounts and want clean
attribution. Without it nothing breaks -- those transfers just show up
as contributions, inflating the total by the amount moved. If you never
shuffle money between accounts, skip the file entirely.
When you do, declare each move in
[`transaction_log.srf`](../reference/config/transaction-log-srf.md) so
it cancels out:
```srf
#!srfv1
transfer::2026-05-02,type::cash,amount:num:50000,from::Joint taxable,to::Pat Roth,dest_lot::cash
```
zfin matches the transfer against the diff and removes it from the
attribution total. Only `type::cash` is wired up today; `in_kind`
parses but isn't yet supported.
## Cash that *is* a contribution
By default, raw cash-balance increases are treated as internal noise
(interest, dividends, sweeps). For accounts whose cash movement is
dominated by real external deposits (payroll ESPP, direct 401k cash),
set `cash_is_contribution:bool:true` in
[`accounts.srf`](set-up-accounts.md#4-advanced-flags) so those increases
count.
## Related: `compare`
[`zfin compare`](../reference/cli/compare.md) shows the same
attribution alongside value and per-symbol price moves between two
dates. See [Snapshots and history](snapshots-and-history.md).
## Next steps
- [Snapshots and history](snapshots-and-history.md) -- record value over time.
- [`transaction_log.srf` reference](../reference/config/transaction-log-srf.md)
---
[Previous: Read your portfolio](read-your-portfolio.md) | [Next: Snapshots and history](snapshots-and-history.md) | [Documentation home](../README.md)