add docs relating to comprehension of dividend-focused holdings vs other

This commit is contained in:
Emil Lerch 2026-06-29 08:33:40 -07:00
parent 0202652d09
commit 027f3b67ab
Signed by: lobo
GPG key ID: A7B62D657EF764F8
5 changed files with 52 additions and 55 deletions

52
TODO.md
View file

@ -143,57 +143,7 @@ bigger than the REST quote path (persistent connection, reconnect
handling, a background task feeding the TUI) and squarely a
paid-plan feature. Sequence it after the REST quote path proves out.
## Analysis: dividend equity / income-shaped equity - think about it
Dividend-equity ETFs (SCHD, VYM, DGRO, NOBL, SDY, VIG, etc.)
bucket as Equity in `analysis.bucketSector`. That's correct for
risk-exposure analysis - they drop with the market in a
2008-style crash, regardless of the dividend stream - but it
loses the income-vs-growth distinction that retirement-planning
tools care about.
Open question: is there a useful second dimension to add?
Possibilities:
- **Yield-weighted breakdown.** Aggregate `current_yield` per
position, weight by market value, report a portfolio-level
yield. Doesn't change the asset-class taxonomy; adds a new
metric.
- **Income coverage of expenses.** "My dividends + bond coupons
cover X% of projected retirement spending." Closer to what the
income-side framing actually wants - answers the question
rather than redefining the buckets.
- **Income-equity sub-bucket within Equity.** A sub-row in the
Asset Category breakdown, not a 5th top-level bucket. Would
need a way to mark funds as "income-shaped" - probably a
per-symbol opt-in in `metadata.srf`.
Not a bug. Not blocking anything. Could end up being a feature.
This is a note to revisit after using the 4-bucket view for a
while and seeing whether the missing dimension actually matters
in practice.
Resist the temptation to:
- **Add a 5th top-level bucket** ("Income Equity" / "Dividend
Equity"). The 4-bucket view is already the right answer for
"how much equity exposure do I have?". A 5th bucket
fragments the headline number.
- **Override SCHD to Fixed Income.** Wrong on risk grounds.
SCHD will lose 35-45% in an equity crash; treating it as FI
makes the user think they have downside protection they don't.
- **Add per-symbol "intent" metadata** (`held_for_income::true`).
Smell of putting framing into data. Intent is a property of
the holder's strategy, not the security.
If a fix lands, it's probably a separate analysis section (yield
breakdown, income coverage) - not a change to the asset-class
taxonomy.
The following items are acknowledged but not prioritized. Listed here
so they don't get lost; pick up opportunistically.
### Infra / performance
## Infra / performance
- **HTTP connection pooling.** Parallel server sync in `loadAllPrices`
spawns up to 8 threads, each with its own HTTP connection. Could

View file

@ -101,6 +101,22 @@ zfin reports Sharpe at **3Y and 10Y** rather than 1Y. When the two
disagree, lean on the longer window to judge a holding's risk-adjusted
quality.
### Risk character vs. asset class
A dividend or low-volatility equity fund -- SCHD, VYM, USMV -- is still
equity: it falls with the market in a crash, so
[`analysis`](../reference/cli/analysis.md) buckets it under Equity, the
view that answers "how exposed am I to an equity drawdown?" But two
holdings of the *same* asset class can ride very differently, and that
difference lives in the volatility and max-drawdown columns of
[`review`](../reference/cli/review.md), not in the asset-class label. In
the [`pre-retirement-both`](../../examples/pre-retirement-both/) example,
SCHD and QQQ are both `US Large Cap`, yet SCHD's 5-year max drawdown runs
about half QQQ's at a few points lower volatility -- QQQ pays for the
bumpier ride with a higher return and Sharpe. Asset class answers *crash
exposure*; the risk columns answer *how bumpy the ride is*. They are
different questions, and zfin keeps them in different views on purpose.
## Portfolio-level returns
The portfolio summary's **Historical** line and the

View file

@ -95,6 +95,13 @@ symbol::VTI,sector::Diversified,geo::US,asset_class::US Large Cap,bucket::US Tot
symbol::SCHD,sector::Diversified,geo::US,asset_class::US Large Cap,bucket::US Dividend
```
Grouping like this also pays off in
[`zfin review`](read-your-portfolio.md#spotting-a-defensive-sleeve): a
`US Dividend` bucket typically shows lower volatility and a shallower
max drawdown than a broad-market or growth bucket, even when both are
the same asset class. Sorting `review` by sector lets you read each
sleeve's risk character at a glance.
## Verify
```bash

View file

@ -98,6 +98,12 @@ The Sector and Asset Category axes need [`metadata.srf`](classify-holdings.md);
the Tax Type axis needs [`accounts.srf`](set-up-accounts.md). Anything
missing classification lands under "Unclassified" / "Unknown."
One thing the Asset Category axis deliberately does *not* capture is
**risk character**. SCHD and QQQ here both land in Equity (`US Large
Cap`), yet one rides far calmer than the other -- that distinction lives
in [`review`](#review-per-holding-performance-and-risk) below, not in
the allocation breakdown.
### Umbrella exposure
A personal **umbrella insurance** policy covers liability -- lawsuits
@ -164,6 +170,22 @@ with the rest of your data. The CLI honors them -- `zfin review
--show-acked` includes acked findings in the table -- but only the TUI
can add or remove them.
### Spotting a defensive sleeve
Asset class tells you what falls in a downturn; the **Vol** and
**MaxDD** columns tell you how hard. The two come apart *within* a
single asset class. Here SCHD and QQQ are both `US Large Cap`, yet
`zfin review` shows SCHD riding far calmer -- its 5-year max drawdown is
roughly half QQQ's (about 16% vs. 33%), at a few points lower
volatility. QQQ earns more for the bumpier ride (higher return and
Sharpe); SCHD trades return for stability. That income/defensive
character is *measured* from each fund's own price history -- you don't
tag a fund with it, the risk columns reveal it. When several holdings
share that profile, give them a common
[`bucket::`](classify-holdings.md#fixing-uninformative-sectors) label
and sort by sector (`--sort sector`, the default) so they group
together and you can read the sleeve's risk character as a whole.
## `exposure`: look-through to a single symbol
```bash

View file

@ -470,10 +470,12 @@ pub fn bucketSector(sector: []const u8) []const u8 {
// bond-like income shape. The Asset Category breakdown
// answers "what's exposed to equity drawdowns?" - and
// dividend funds drop with the market in a 2008-style
// crash. The income-feels-like-bonds intuition belongs in
// a separate yield-weighted analysis (see TODO.md
// "Dividend equity / income-shaped equity"), not in the
// asset-class taxonomy.
// crash. Their calmer risk character (lower volatility,
// shallower drawdown) is real but shows up in the
// per-holding vol/drawdown columns of `review`, not in
// the asset-class taxonomy. See
// docs/explanation/returns-and-performance.md, "Risk
// character vs. asset class".
if (std.mem.startsWith(u8, sector, "Equity")) return bucket_equity;
if (std.mem.startsWith(u8, sector, "Debt")) return bucket_fixed_income;
if (std.mem.startsWith(u8, sector, "Loan")) return bucket_fixed_income;