add additional data in examples/ directories
This commit is contained in:
parent
bdd827734d
commit
d94ffb3410
6 changed files with 227 additions and 0 deletions
163
examples/README.md
Normal file
163
examples/README.md
Normal file
|
|
@ -0,0 +1,163 @@
|
|||
# zfin examples
|
||||
|
||||
Realistic-but-fictional portfolio configurations for spot-checking
|
||||
zfin features and showing users how the configuration files fit
|
||||
together. Run any zfin command against an example by setting
|
||||
`ZFIN_HOME` to its directory:
|
||||
|
||||
```sh
|
||||
ZFIN_HOME=examples/pre-retirement-both zfin projections
|
||||
ZFIN_HOME=examples/pre-retirement-age zfin projections
|
||||
ZFIN_HOME=examples/pre-retirement-spending zfin projections
|
||||
ZFIN_HOME=examples/pre-retirement-spending-target zfin projections
|
||||
ZFIN_HOME=examples/post-retirement zfin projections
|
||||
ZFIN_HOME=examples/pre-retirement-both zfin --tui
|
||||
```
|
||||
|
||||
All names, share counts, account numbers, prices, and life events in
|
||||
these examples are fictional. Do not interpret them as advice.
|
||||
|
||||
## Available examples
|
||||
|
||||
The five scenarios share the same fictional couple and balance sheet
|
||||
(~$1.3M, age ~45, contributing $80k/yr) for the four pre-retirement
|
||||
variants, and a separate retired couple for the distribution example.
|
||||
Only the `projections.srf` configuration differs across the
|
||||
pre-retirement variants — making it easy to see how each
|
||||
retirement-planning input shapes the output.
|
||||
|
||||
### Background: how the projection accepts input
|
||||
|
||||
The simulation always runs the same two-phase model: an
|
||||
**accumulation phase** (contributions in, no spending) followed by
|
||||
a **distribution phase** (spending out, no contributions). What the
|
||||
user configures in `projections.srf` decides which questions the
|
||||
display answers:
|
||||
|
||||
- **Target retirement date** (`retirement_age` or `retirement_at`) —
|
||||
"Given my retirement date, what can I spend?" Produces the
|
||||
Accumulation phase block: median portfolio at retirement, p10–p90
|
||||
range, and the dated headline retirement line.
|
||||
- **Target spending** (`target_spending`) — "Given my desired
|
||||
spending, when can I retire?" Produces the Earliest retirement
|
||||
grid (one cell per horizon × confidence) and promotes one cell
|
||||
into the Accumulation phase block as the headline.
|
||||
- **Both** — both blocks render back-to-back. The configured
|
||||
retirement date wins for the headline; the grid is the
|
||||
side-by-side comparison.
|
||||
- **Neither** — distribution-only mode. The Accumulation phase
|
||||
block reduces to a soft "Years until possible retirement: none"
|
||||
line.
|
||||
|
||||
### `pre-retirement-age/`
|
||||
|
||||
**Input: target retirement date only.** `retirement_age:num:65` is
|
||||
set, `target_spending` is not. Output renders:
|
||||
|
||||
- **Accumulation phase** block — median portfolio at the configured
|
||||
retirement date, p10–p90 range, and the
|
||||
`Years until possible retirement: 19 (2046-04-12, ages 65/62)` line
|
||||
showing both partners' ages at retirement.
|
||||
- Standard Safe Withdrawal table for the configured horizons.
|
||||
- No "Earliest retirement" grid (no spending target to search against).
|
||||
|
||||
### `pre-retirement-spending/`
|
||||
|
||||
**Input: target spending only.** `target_spending:num:80000` is set,
|
||||
`retirement_age`/`retirement_at` are not. Output renders:
|
||||
|
||||
- **Earliest retirement** grid — one cell per (horizon × confidence)
|
||||
showing the earliest year the household can retire and sustain
|
||||
$80k/yr at that confidence over that distribution horizon.
|
||||
- The **Accumulation phase** block is populated by **promoting one
|
||||
cell** from the grid into the headline retirement line, plus the
|
||||
median portfolio at retirement and p10-p90 range. The default
|
||||
promotion rule walks horizons longest → shortest and picks the
|
||||
longest one whose end year keeps the oldest configured person
|
||||
under age 100, at 99% confidence (most conservative). If even
|
||||
the shortest horizon overshoots, it's used anyway.
|
||||
- The grid stays rendered for transparency — the user can see how
|
||||
the headline cell compares to the rest of the matrix.
|
||||
|
||||
### `pre-retirement-spending-target/`
|
||||
|
||||
Same household and balance sheet as `pre-retirement-spending/`, but
|
||||
with a much higher `target_spending` ($2.4M/yr) AND an explicit
|
||||
`retirement_target:num:99` annotation on the `horizon_age:num:95`
|
||||
record. That combination demonstrates two things at once:
|
||||
|
||||
- The **explicit override** mechanism: instead of the default
|
||||
promotion rule (longest horizon at 99% confidence, capped at age
|
||||
100), the user explicitly anchors the headline to the resolved
|
||||
`horizon_age:95 × 99%` cell. The override survives age-resolution
|
||||
— it rides on `horizon_age` records too, not just `horizon`.
|
||||
- The **"not feasible" rendering path**: the annotated cell turns
|
||||
out to be infeasible at this spending level (no value of
|
||||
`accumulation_years` ≤ 50 sustains $2.4M/yr at 99% over a
|
||||
50-year retirement). The headline line renders
|
||||
"Years until possible retirement: not feasible" instead of a
|
||||
date, and the contribution / median lines below it are
|
||||
suppressed. The full Earliest retirement grid still renders so
|
||||
the user can see which (horizon × confidence) cells DO work and
|
||||
pick a different anchor.
|
||||
|
||||
Use this variant when the user has a preferred planning anchor
|
||||
that's different from "longest feasible horizon at maximum
|
||||
conservatism." Allowed `retirement_target` values are 90, 95, 99.
|
||||
At most one horizon may carry the annotation; configuring two or
|
||||
more drops them all (warning logged) and falls back to the default
|
||||
rule.
|
||||
|
||||
### `pre-retirement-both/`
|
||||
|
||||
**Inputs: both target retirement date AND target spending.** Both
|
||||
`retirement_age` and `target_spending` are set. Output renders both
|
||||
blocks back-to-back so the user can compare "what I planned"
|
||||
(target retirement date) against "what's earliest feasible" (target
|
||||
spending). The configured retirement date wins for the headline
|
||||
line; the Earliest retirement grid is rendered below for
|
||||
comparison.
|
||||
|
||||
### `post-retirement/`
|
||||
|
||||
A retired couple, ~age 68, ~$2M total. Distribution-only mode (no
|
||||
`target_spending`, no `retirement_age`/`retirement_at`).
|
||||
Demonstrates the legacy projection behavior, including the soft
|
||||
"Years until possible retirement: none" line that confirms the model
|
||||
isn't projecting any pre-retirement growth.
|
||||
|
||||
Includes a late-life healthcare expense modeled as a life event
|
||||
starting at age 80, plus Social Security already in pay status.
|
||||
Asset allocation target: 60/40 (more bond-heavy than the
|
||||
pre-retirement examples).
|
||||
|
||||
## Configuration file map
|
||||
|
||||
Every example contains:
|
||||
|
||||
- **`portfolio.srf`** — open lots, one per line. The source of truth
|
||||
for shares, cost basis, and account assignment.
|
||||
- **`accounts.srf`** — tax type and institution metadata for each
|
||||
account name referenced by `portfolio.srf`.
|
||||
- **`metadata.srf`** — sector / geography / asset-class
|
||||
classifications for each symbol.
|
||||
- **`projections.srf`** — retirement projection configuration:
|
||||
birthdates, target allocation, horizons, life events, and (in the
|
||||
pre-retirement variants) the accumulation-phase / earliest-retirement
|
||||
fields. This is the only file that differs across the four
|
||||
pre-retirement variants.
|
||||
|
||||
There's no `watchlist.srf` in either example. Add one if you're
|
||||
spot-checking watchlist features.
|
||||
|
||||
## Symbol selection
|
||||
|
||||
The examples use symbols whose candle data is commonly cached and
|
||||
kept fresh by ongoing cron jobs:
|
||||
|
||||
- **Equity ETFs:** SPY, VTI, QQQ, SCHD
|
||||
- **Bond ETF:** AGG
|
||||
|
||||
If you add a symbol not in this list, run `zfin quote <SYM>` once
|
||||
inside the example directory to populate the cache before running
|
||||
analytics commands.
|
||||
8
examples/post-retirement/metadata.srf
Normal file
8
examples/post-retirement/metadata.srf
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
#!srfv1
|
||||
# Symbol classification metadata for the post-retirement example.
|
||||
|
||||
symbol::VTI,sector::Diversified,geo::US,asset_class::US Large Cap
|
||||
symbol::SPY,sector::Diversified,geo::US,asset_class::US Large Cap
|
||||
symbol::QQQ,sector::Technology,geo::US,asset_class::US Large Cap
|
||||
symbol::SCHD,sector::Diversified,geo::US,asset_class::US Large Cap
|
||||
symbol::AGG,sector::Bonds,geo::US,asset_class::Bonds
|
||||
14
examples/pre-retirement-age/metadata.srf
Normal file
14
examples/pre-retirement-age/metadata.srf
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
#!srfv1
|
||||
# Symbol classification metadata for the pre-retirement example.
|
||||
# Each line: symbol::<SYM>,sector::<S>,geo::<G>,asset_class::<A>
|
||||
|
||||
# Broad-market ETFs
|
||||
symbol::VTI,sector::Diversified,geo::US,asset_class::US Large Cap
|
||||
symbol::SPY,sector::Diversified,geo::US,asset_class::US Large Cap
|
||||
symbol::QQQ,sector::Technology,geo::US,asset_class::US Large Cap
|
||||
|
||||
# Dividend ETF
|
||||
symbol::SCHD,sector::Diversified,geo::US,asset_class::US Large Cap
|
||||
|
||||
# Bond ETF
|
||||
symbol::AGG,sector::Bonds,geo::US,asset_class::Bonds
|
||||
14
examples/pre-retirement-both/metadata.srf
Normal file
14
examples/pre-retirement-both/metadata.srf
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
#!srfv1
|
||||
# Symbol classification metadata for the pre-retirement example.
|
||||
# Each line: symbol::<SYM>,sector::<S>,geo::<G>,asset_class::<A>
|
||||
|
||||
# Broad-market ETFs
|
||||
symbol::VTI,sector::Diversified,geo::US,asset_class::US Large Cap
|
||||
symbol::SPY,sector::Diversified,geo::US,asset_class::US Large Cap
|
||||
symbol::QQQ,sector::Technology,geo::US,asset_class::US Large Cap
|
||||
|
||||
# Dividend ETF
|
||||
symbol::SCHD,sector::Diversified,geo::US,asset_class::US Large Cap
|
||||
|
||||
# Bond ETF
|
||||
symbol::AGG,sector::Bonds,geo::US,asset_class::Bonds
|
||||
14
examples/pre-retirement-spending-target/metadata.srf
Normal file
14
examples/pre-retirement-spending-target/metadata.srf
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
#!srfv1
|
||||
# Symbol classification metadata for the pre-retirement example.
|
||||
# Each line: symbol::<SYM>,sector::<S>,geo::<G>,asset_class::<A>
|
||||
|
||||
# Broad-market ETFs
|
||||
symbol::VTI,sector::Diversified,geo::US,asset_class::US Large Cap
|
||||
symbol::SPY,sector::Diversified,geo::US,asset_class::US Large Cap
|
||||
symbol::QQQ,sector::Technology,geo::US,asset_class::US Large Cap
|
||||
|
||||
# Dividend ETF
|
||||
symbol::SCHD,sector::Diversified,geo::US,asset_class::US Large Cap
|
||||
|
||||
# Bond ETF
|
||||
symbol::AGG,sector::Bonds,geo::US,asset_class::Bonds
|
||||
14
examples/pre-retirement-spending/metadata.srf
Normal file
14
examples/pre-retirement-spending/metadata.srf
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
#!srfv1
|
||||
# Symbol classification metadata for the pre-retirement example.
|
||||
# Each line: symbol::<SYM>,sector::<S>,geo::<G>,asset_class::<A>
|
||||
|
||||
# Broad-market ETFs
|
||||
symbol::VTI,sector::Diversified,geo::US,asset_class::US Large Cap
|
||||
symbol::SPY,sector::Diversified,geo::US,asset_class::US Large Cap
|
||||
symbol::QQQ,sector::Technology,geo::US,asset_class::US Large Cap
|
||||
|
||||
# Dividend ETF
|
||||
symbol::SCHD,sector::Diversified,geo::US,asset_class::US Large Cap
|
||||
|
||||
# Bond ETF
|
||||
symbol::AGG,sector::Bonds,geo::US,asset_class::Bonds
|
||||
Loading…
Add table
Reference in a new issue