123 lines
5.2 KiB
Markdown
123 lines
5.2 KiB
Markdown
# Handle a stock split
|
|
|
|
**Goal:** keep your holdings correct through a stock split without
|
|
breaking the history that zfin's other commands rely on.
|
|
|
|
**The one rule:** when a stock you hold splits, **do not edit the share
|
|
count on your existing lot.** Leave the lot exactly as you transacted
|
|
it, and tell zfin about the split with one line in `metadata.srf`. zfin
|
|
does the rest on read.
|
|
|
|
## Why not just change the share count?
|
|
|
|
It seems natural: NVDA does a 10:1 split, your 100 shares become 1,000,
|
|
so you open `portfolio.srf` and change `shares:num:100` to
|
|
`shares:num:1000`. Don't -- here is what that quietly breaks.
|
|
|
|
**Your portfolio file is history, and zfin reads the history, not just
|
|
the latest version.** If you are utilizing all zfin features, `portfolio.srf`
|
|
lives in git, and several commands diff *past commits* of it:
|
|
|
|
- [`contributions`](track-contributions.md) attributes what changed
|
|
between two commits to *new money* vs. *market movement*. It works on
|
|
the raw share/lot changes in the diff.
|
|
- [`compare`](../reference/cli/compare.md) and
|
|
[`audit`](audit-against-brokerage.md) read git history the same way.
|
|
|
|
A split changes your **share count** but not your **money**: 100 shares
|
|
at $400 and 1,000 shares at $40 are the same $40,000. But if you edit the
|
|
lot from 100 to 1,000 and commit, the git diff shows **+900 shares**.
|
|
`contributions` cannot tell that apart from you *buying* 900 shares, so
|
|
it reports a large **phantom contribution** that never happened -- and it
|
|
is now baked into your commit history permanently.
|
|
|
|
**Snapshots make it worse.** [`zfin snapshot`](snapshots-and-history.md)
|
|
writes immutable, point-in-time records of your portfolio under
|
|
`history/`. A snapshot taken *before* your edit recorded 100 shares;
|
|
after the edit, your live file says 1,000. The two no longer agree, and
|
|
you **cannot fix the old snapshot** -- it is a frozen record of a past
|
|
day, and `compare` / `history` read it as-is.
|
|
|
|
Both git history and snapshots are **append-only truth**: undoing the
|
|
damage means rewriting git history (dangerous) or hand-editing frozen
|
|
snapshot files (error-prone). So the safe design is simple -- a split
|
|
must never touch your recorded shares. It is a *derivation*, not an
|
|
*edit*.
|
|
|
|
## What to do instead
|
|
|
|
Leave the lot alone. Add a per-symbol `splits_current_through` date to
|
|
that symbol's row in
|
|
[`metadata.srf`](../reference/config/metadata-srf.md#stock-split-adjustment):
|
|
|
|
```srf
|
|
#!srfv1
|
|
symbol::NVDA,sector::Technology,geo::US,asset_class::US Large Cap,splits_current_through::2020-01-01
|
|
```
|
|
|
|
Set the date to **when that symbol's recorded shares were last
|
|
accurate** -- for a lot you entered as transacted, that is on or around
|
|
the purchase. zfin then applies every split *after* that date to compute
|
|
the **effective** (split-adjusted) share count on the fly. Your
|
|
`portfolio.srf`, git history, and snapshots stay exactly as transacted;
|
|
only the *displayed and valued* shares reflect the split.
|
|
|
|
You can see the split zfin will apply with
|
|
[`zfin splits`](../reference/cli/splits.md):
|
|
|
|
```bash
|
|
zfin splits NVDA
|
|
```
|
|
|
|
## Copying post-split numbers from your brokerage is fine
|
|
|
|
Brokerages *do* restate: after a split, Fidelity or Schwab show you the
|
|
post-split share count and split-adjusted cost basis. Recording a lot
|
|
from one of those statements is **not** the mistake above -- you are
|
|
stating a holding as it stands today, not reaching back to rewrite a lot
|
|
that already lived through the split in your file.
|
|
|
|
The only thing zfin needs to know is whether the split is **already
|
|
baked into the number you typed.** The cutover date answers that:
|
|
|
|
- **Shares entered as transacted (pre-split).** The split happened after
|
|
you recorded them, so set `splits_current_through` to a date *before*
|
|
the split. zfin applies it.
|
|
- **Shares copied post-split from a statement.** The number already
|
|
includes the split, so set `splits_current_through` to the statement
|
|
date (*after* the split). zfin leaves it alone instead of applying it
|
|
twice.
|
|
|
|
Either way the rule holds: you never went back and edited an existing
|
|
lot's shares. You either left it as transacted or recorded a fresh lot
|
|
from a statement, and the cutover date tells zfin which.
|
|
|
|
> **Bright line:** recording a lot from a post-split statement is fine.
|
|
> Reaching back to change an *existing* committed lot's `shares` because
|
|
> of a split is what corrupts your history. If you are tempted to edit a
|
|
> number that is already committed, set the cutover instead.
|
|
|
|
## Verify
|
|
|
|
`zfin audit`'s hygiene check lists any held symbol that has a
|
|
post-purchase split but no `splits_current_through` yet, under
|
|
**Unhandled stock splits** -- so you can see at a glance which rows still
|
|
need the line:
|
|
|
|
```bash
|
|
zfin audit
|
|
```
|
|
|
|
Once set, [`zfin portfolio`](../reference/cli/portfolio.md) shows the
|
|
effective (split-adjusted) share count and the correct market value,
|
|
while your files stay untouched.
|
|
|
|
## Next steps
|
|
|
|
- [`metadata.srf` reference](../reference/config/metadata-srf.md#stock-split-adjustment) -- the field's exact semantics.
|
|
- [Track contributions](track-contributions.md) -- why the git diff must stay honest.
|
|
- [Snapshots and history](snapshots-and-history.md) -- the frozen records a restate would desync.
|
|
|
|
---
|
|
|
|
[Previous: Snapshots and history](snapshots-and-history.md) | [Next: Plan for retirement](plan-retirement.md) | [Documentation home](../README.md)
|