Milestones and Timing
Almost every input in FinZot has a time it applies. An income stream runs from one point to another. An expense starts when a child turns 18. A Roth conversion runs for the five years after retirement. FinZot expresses all of these with the same two building blocks: an anchor, which names a point in time, and an effective period, which is a start anchor and an end anchor.
Static anchors
Section titled “Static anchors”A static anchor is a point in time known from the inputs alone. It can be:
- a Calendar Year, such as 2035
- a Primary Age or Spouse Age, the year that person reaches the age
- a child’s age, the year a named child reaches the age
- the start of the plan or the end of the plan
- the primary person’s or spouse’s longevity year, the year that person reaches their life expectancy
A static anchor can carry a Start month or End month. A start with no month begins in January. An end with no month runs through December. An end month is inclusive. The month matters because income and expenses prorate by whole months within a year (plan start date).
Milestones
Section titled “Milestones”A milestone is a named event that other inputs can anchor on, such as “Move to Florida” or “FIRE target hit”. Once a milestone is reached it stays reached. Anchoring several inputs on one milestone means they all move together when you change its trigger.
A milestone’s trigger is either static or dynamic.
- A static trigger is a static anchor, such as a year or an age, plus an optional month. A static trigger has no month for the plan’s start or end.
- A dynamic trigger fires in the first year a condition is true. The condition is either a formula that evaluates to true or false, or a FIRE target: a dollar amount in today’s dollars that fires the first year invested assets exceed it after inflation. A formula trigger can read any planner variable (planner context). A dynamic trigger resolves to a whole year, so it has no month.
A dynamic trigger is checked before its year runs. FinZot evaluates every dynamic trigger at
the start of each year, before that year’s returns, income, and spending. The condition reads last
year’s closing balances and last year’s flows, such as invested_assets, portfolio_return, and
withdrawal_amount. Only the ages, calendar_year, year_index, and years_remaining describe
the year being checked. In the first plan year the trigger reads the starting balances instead. So
portfolio_return < 0 fires in the year after a down year. A FIRE target fires the year after
invested assets close above it. Inside a trigger, LAG(net_worth, 1) reaches two years back,
because last year’s close is already the value in hand. A sizing formula reads the current year
instead (planner context).
A trigger waits for the data it reads. The first plan year has no closed year behind it, so it
has no flows. A trigger that reads consumption or total_income there has no answer and does not
fire. The same holds for a look back that reaches before the plan started, and for a rolling window
with no year in it. FinZot asks again the next year. So a trigger of
invested_assets >= 25 * ROLLING_AVG(consumption, 3) cannot fire until a year of spending has
closed. A sizing formula reads the same look back as 0 (formula language).
A trigger cannot reference another milestone, which rules out cycles. To say “three years after retirement”, anchor on the retirement milestone and add an offset.
A named formula means the same thing everywhere. A trigger or a sizing formula can read the formula another milestone fires on. It gets that formula’s value for the year, not whether the milestone has fired. To act once a milestone has fired, anchor the entry on the milestone.
Retirement is a milestone. Every person in the plan has a retirement milestone, and it drives where earned income stops and where a spending phase begins. Its trigger can be an age, already retired at the start of the plan, never retiring, which puts it at the end of the plan, or a FIRE target.
Dynamic milestones differ in every trial. Each Monte Carlo trial draws its own market history, so a FIRE target or a formula trigger fires in a different year in each trial, and in some trials never. Everything anchored on that milestone moves with it. This is what lets the Monte Carlo measure how often a plan that adjusts survives, not just how often a fixed schedule does (Projections & Monte Carlo, formulas).
Effective periods
Section titled “Effective periods”An effective period is a start anchor and an end anchor. Either can be a static anchor, a static milestone, or a dynamic milestone. A milestone anchor can carry an offset in years, so “two years after retirement” is the retirement milestone plus two.
Periods are half-open. A period that ends at a milestone stops exactly where a period that starts at the same milestone begins, so the two never overlap and never leave a gap. An income stream ending at retirement and an expense starting at retirement hand off cleanly.
Some inputs have a default period. A contribution runs for the lifetime of its income stream unless you set a custom period. The default spending phase runs from retirement to the end of the plan.
Recurrence
Section titled “Recurrence”An expense can recur every N years from the start of its effective period instead of every year. One means annual, two means every other year. You can set a maximum number of occurrences. Left unlimited, it recurs until the effective period ends. A car purchase every eight years is a single expense with a recurrence of eight.
See also
Section titled “See also”- Planner Context — The live variables and helper functions a formula can read, such as net worth, age, balances, income, and returns.
- How a Year Works — The order FinZot processes each projection year. Income, expenses, and required payments first, then each list of actions you control, ending in Roth Conversions and Withdrawals. This order is also what a formula reads: it decides which of the year’s flows have happened by the time an entry is sized. Also the three stages that cover a shortfall and the default account that absorbs surplus.