117 lines
4.3 KiB
Markdown
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)
|