f-Itinera planning simulator library and examples
Project description
f-Itinera Simulator Library
f-Itinera Simulator is an open source, extensible, and high-quality financial planning simulation library that allows individuals or CFPs to simulate a wide range of long-term horizons around the most important wealth building resources: Assets, Liabilities, Transactions, and Time.
Additionally, every simulated scenario provides a common reporting structure enabling comparative analysis across plans that can help validate or compare a wide variety wealth strategies and plans.
Some common use cases we facilitate include:
- Understanding "how much" and "when" one may retire from their standard job.
- Determining "when" one may retire given a certain savings, ROI, and expense rates.
- Validate strategic fitness by stress-testing over risk vectors (sequence of returns, inflation, etc.).
- Extending to more advanced wealth-building strategies such as rental real estate, business (e.g., side-hustles), or some hybrid in between.
NOTE: f-Itinera stands for "Fiscus Itinera". While not correct latin, this roughly translates to "Fund Trips" in english. Our liberal interpretation of this is more like funding your wealth journey, which is at the heart of any finanicial plan.
Quickstart API Examples
from fitinera import (
Age,
AnnualGrowth,
AssetBuilder,
ContributionConstraint,
ExpenseBuilder,
FinancialScenarioBuilder,
IncomeBuilder,
Month,
MonthlyGrowth,
Penalty,
Simulator,
TimeHorizon,
RetirementGoal,
TaxRateBuilder,
TimeBounds,
)
# 1. Define the simulation's time horizon and retirement goals.
time_horizon = TimeHorizon(current_age=Age(30, Month.JANUARY), life_expectancy=Age(95, Month.JANUARY))
retirement_goal = RetirementGoal(
retirement_age=Age(65, Month.JANUARY), desired_estate_value=1_000_000
)
# 2. Build the financial scenario using a builder pattern.
scenario_builder = FinancialScenarioBuilder(name="Retirement Plan", time_horizon=time_horizon)
scenario = (
scenario_builder
# Add a 401k retirement asset
.with_asset(
AssetBuilder("401k")
.with_initial_value(75_000)
.with_growth_strategy(MonthlyGrowth(annual_rate=0.07))
.with_contribution_priority(1)
.with_withdrawal_priority(2)
.with_contribution_constraint(
ContributionConstraint(
effective_monthly_max=23_500 / 12,
effective_time_bounds=TimeBounds(end=Age(59, Month.JULY)),
)
)
.with_withdrawal_penalty(
Penalty(rate=0.10, time_bounds=TimeBounds(end=Age(59, Month.JULY)))
) # 10% penalty until 59.5
.build()
)
# Add a taxable brokerage asset
.with_asset(
AssetBuilder("Taxable Brokerage")
.with_initial_value(25_000)
.with_growth_strategy(MonthlyGrowth(annual_rate=0.07))
.with_contribution_priority(2)
.with_withdrawal_priority(1)
.with_withdrawal_tax(
TaxRateBuilder(0.15).build()
) # 15% capital gains tax on withdrawals
.build()
)
# Add an active W2 income stream
.with_income(
IncomeBuilder("W2 Income", monthly_amount=6_000)
.is_active_income()
.with_growth_strategy(
AnnualGrowth(annual_rate=0.03, month_of_year=Month.MARCH)
) # 3% raise every March
.with_time_bounds(TimeBounds(end=retirement_goal.retirement_age))
.build()
)
# Add a recurring expense stream
.with_expense(
ExpenseBuilder("Living Expenses", monthly_amount=3_500)
.with_growth_strategy(MonthlyGrowth(annual_rate=0.025)) # 2.5% inflation
.build()
)
# Add a tax strategy
.with_tax_rate(
TaxRateBuilder(0.22)
.with_time_bounds(TimeBounds(end=retirement_goal.retirement_age))
.build()
)
.with_tax_rate(
TaxRateBuilder(0.12)
.with_time_bounds(TimeBounds(start=retirement_goal.retirement_age))
.build()
)
# Set the final retirement goal
.with_retirement_goal(retirement_goal)
.build()
)
# 3. Run the simulation and view the results.
simulator = Simulator()
results = simulator.run(scenario)
print(results.summary())
Conceptual Guide
The f-Itinera Simulator is built around a few core concepts that model your financial life. By providing inputs for each of these, you can create a detailed simulation of your journey to financial independence and retirement.
At a high level, a simulation is defined by four components: a Financial Scenario, the Time Horizon, your Assets, your Cash Flow, and your Goals.
1. Financial Scenario
The Financial Scenario is the top-level container for a simulation. It bundles together all the components of a financial plan.
| Parameter | Type | Description |
|---|---|---|
name |
str |
A unique name to identify the scenario. |
time_horizon |
TimeHorizon |
The time horizon for the simulation. |
retirement_goal |
RetirementGoal |
The retirement goal for the simulation. |
assets |
list[Asset] |
A list of all assets in the scenario. |
incomes |
list[Income] |
A list of all income streams in the scenario. |
expenses |
list[Expense] |
A list of all expense streams in the scenario. |
tax_rates |
list[TaxRate] |
A list of all tax rates in the scenario. |
2. Time Horizon
The Time Horizon defines the duration and key milestones of the simulation. It is the foundational context for all events.
| Parameter | Type | Description |
|---|---|---|
current_age |
Age |
The starting age of the subject of the simulation. |
life_expectancy |
Age |
The end point of the simulation (default is 100 years). |
3. Retirement Goals
This defines the primary objective of the simulation: achieving retirement.
| Parameter | Type | Description |
|---|---|---|
retirement_age |
Age |
The age you plan to stop working. This is a key milestone for the simulation. |
desired_estate_value |
float |
Optional (default: 0). The desired minimum total asset value you wish to have at the end of the simulation. |
IMPORTANT: The retirement age must be equal to or greater than the starting age and strictly less than the life expectancy.
4. Assets & Investments
Assets represent your current and future investments that you can live off of. You can add multiple asset accounts to a simulation.
| Parameter | Type | Description |
|---|---|---|
name |
str |
A unique name that identifies the account/asset. |
initial_value |
float |
The starting value of the asset. |
growth_strategy |
GrowthStrategy |
The compounding growth rate of the asset. See Core Data Types. |
contribution_priority |
int |
A positive integer indicating the preference to contribute extra net cash flow to this asset. Higher numbers have higher priority. |
withdrawal_priority |
int |
A positive integer indicating the preference to withdraw from this asset to cover deficits. Higher numbers have higher priority. |
contribution_constraints |
list[ContributionConstraint] |
Optional. A list of constraints that limit how much can be contributed to this asset. |
withdrawal_penalties |
list[Penalty] |
Optional. A list of penalties applied to withdrawals, useful for modeling early withdrawal from tax-advantaged accounts. |
withdrawal_taxes |
list[TaxRate] |
Optional. A list of tax rates applied to withdrawals, useful for modeling capital gains or income tax on withdrawals. |
4.1. Contribution Constraints
You can apply one or more constraints to an asset to model contribution limits, such as annual 401(k) or IRA maximums.
| Parameter | Type | Description |
|---|---|---|
effective_time_bounds |
TimeBounds |
Optional. The time range when this constraint is in effect. |
effective_monthly_max |
float |
The maximum that can be contributed monthly during the specified time range. |
4.2. Withdrawal Penalties
Withdrawal penalties can be used to model early withdrawal fees from tax-advantaged accounts.
| Parameter | Type | Description |
|---|---|---|
rate |
float |
The penalty rate, expressed as a decimal between 0.0 and 1.0. |
time_bounds |
TimeBounds |
The time range when this penalty is in effect. |
5. Cash Flow
Cash Flow models the money moving in and out of your accounts over the course of the simulation. It is composed of income, taxes, and expenses.
5.1. Income Streams
You can add any number of income sources. The kind of income is critical for determining financial independence.
| Parameter | Type | Description |
|---|---|---|
name |
str |
A unique name for the income stream. |
monthly_amount |
float |
The initial monthly amount received. |
time_bounds |
TimeBounds |
The time range when this income is active. See Core Data Types. |
kind |
IncomeKind |
ACTIVE or PASSIVE. Passive income counts towards financial independence goals. |
growth_strategy |
GrowthStrategy |
The rate at which the income changes over time (e.g., raises). See Core Data Types. |
5.2. Expense Streams
You can add any number of after-tax expense sources.
| Parameter | Type | Description |
|---|---|---|
name |
str |
A unique name for the expense stream. |
monthly_amount |
float |
The initial monthly amount spent. |
time_bounds |
TimeBounds |
The time range when this expense is active. See Core Data Types. |
growth_strategy |
GrowthStrategy |
The rate at which the expense changes over time (i.e., inflation). See Core Data Types. |
5.3. Tax Rates
Tax rates are applied to your gross income each month. You can specify different rates for different periods (e.g., pre- and post-retirement).
| Parameter | Type | Description |
|---|---|---|
rate |
float |
A decimal between [0.0, 1.0) representing the effective tax rate. |
time_bounds |
TimeBounds |
The time range when this tax rate is in effect. See Core Data Types. |
5.4. One-Time Payments
The simulator allows for modeling one-off lump sum payments (positive for income, negative for expenses).
| Parameter | Type | Description |
|---|---|---|
amount |
float |
The value of the payment. |
age |
Age |
The age at which this payment occurs. |
6. The Simulation Lifecycle
The simulator executes on a month-by-month loop. For each month, the following operations are executed in order:
- Check Retirement Status: Determine if the subject's age has reached the
retirement_agemilestone. - Compute Gross Income: Sum all active income streams for the current month.
- Apply Taxes: Apply the relevant tax rate to the gross income to calculate net income.
- Aggregate Expenses: Sum all active expense streams for the current month.
- Calculate Net Cash Flow: Compute
Net Income - Expenses. - Apply Asset Flows:
- If Net Cash Flow is positive, deposit the surplus into assets based on their
contribution_priority. - If Net Cash Flow is negative, withdraw the deficit from assets based on their
withdrawal_priority.
- If Net Cash Flow is positive, deposit the surplus into assets based on their
- Check State: Assess the simulation for end conditions (see below).
- Compound Values: Apply the
growth_strategyto all assets, income streams, and expenses to prepare for the next month.
The simulation concludes when one of the following conditions is met:
- Pre-Retirement Bankruptcy (Failure): Assets are depleted before reaching retirement age.
- Post-Retirement Bankruptcy (Failure): Assets are depleted after retirement age but before life expectancy.
- Insufficient Estate (Partial Success): Life expectancy is reached, but the final asset value is less than the
desired_estate_value. - Success: Life expectancy is reached with sufficient assets to meet the estate goal.
6.1. Simulation Results
The simulator.run() method returns a SimulationResult object that contains the final status of the simulation and a
detailed history of each time step.
| Parameter | Type | Description |
|---|---|---|
status |
SimulationStatus |
The final status of the simulation (e.g., SUCCESS, PRE_RETIREMENT_BANKRUPTCY). |
history |
list[SimulationTurn] |
A list of SimulationTurn objects, one for each month of the simulation. |
scenario |
FinancialScenario |
The original financial scenario that was simulated. |
Each SimulationTurn object provides a detailed breakdown of the financial state for a single month, including income,
expenses, taxes, asset growth, and key metrics like the financial freedom ratio and savings rate.
7. Core Data Types
These are the common, low-level data structures used to configure the concepts above.
7.1. Age and TimeBounds
The simulator models time based on the subject's age, specified with a Year and Month. The Month is a strongly-
typed enum to prevent invalid month values. Most entities use a TimeBounds object to define when they are active.
Age(year: int, month: Month): Represents a specific point in time (e.g.,Age(65, Month.JANUARY)).TimeBounds(start: Age | RetirementGoal, end: Age | RetirementGoal): Defines a time range. Thestartandendcan be a specificAgeor can be relative to theRetirementGoal. ANonevalue means the start or end of the simulation.
7.2. Growth Strategy
This interface models how values change over time.
Monthly(annual_rate: float): The preferred and simplest method. The value compounds each month byannual_rate / 12.Annual(annual_rate: float, month_of_year: Month): The value compounds once per year in the specifiedMonth.
Here are some common rules of thumb:
- Most
ACTIVEincomes should be modeled withAnnualgrowth (representing an annual raise). - Most
PASSIVEincomes andExpensesshould be modeled withMonthlygrowth.
License
All code contained in this repositoriy is licensed under GPL-v3.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file fitinera-0.1.0.tar.gz.
File metadata
- Download URL: fitinera-0.1.0.tar.gz
- Upload date:
- Size: 11.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.7.15
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a8ca3f9d999c0a0f84b8b5f2d500c58b89b4d210b1b0e30540dc16377515897c
|
|
| MD5 |
c0aabffd11a4c70f2eab132f9a55f756
|
|
| BLAKE2b-256 |
ca40d2025f49594eb4ea026fae4b2474689000ddfffd131c8660dace5fae161d
|
File details
Details for the file fitinera-0.1.0-py3-none-any.whl.
File metadata
- Download URL: fitinera-0.1.0-py3-none-any.whl
- Upload date:
- Size: 14.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.7.15
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
209963463ac10734479a00155a000fab7bdd819657d9b379705bc8ae3bdaa1b6
|
|
| MD5 |
baceab4890d8e4e18017787d455d1529
|
|
| BLAKE2b-256 |
e61351b9035b823916d310482b608075b949a8235237da7ef1efc96bcd370c3e
|