
Emergency Fund
- 405 installs
- 161 repo stars
- Updated July 18, 2026
- joellewis/finance_skills
emergency-fund is a finance_skills agent skill that sizes and structures tiered emergency funds from essential expenses, income stability, and liquidity vehicles for developers building financial planning and cash-reserv
About
emergency-fund is a wealth-management skill from joellewis/finance_skills with emergency_fund.py (numpy, --verify mode) for emergency fund sizing and tiered allocation. It recommends 3-6 months for stable dual-income households and 6-12 months for variable or self-employed earners, sizing from essential expenses excluding discretionary spending. Tiered structures split funds across checking (1 month), high-yield savings (2-3 months), and T-bill ladders (3-6 months) with a worked $27,000 example yielding ~3.85% blended return. Developers reach for emergency-fund when building robo-planning tools, cash-flow analyzers, or liquidity recommendation features that need expense-based formulas and vehicle selection tables.
- Expense-based reserve sizing
- Income stability adjustment factors
- Tiered liquidity bucket design
- Savings timeline projections
- High-yield cash placement guidance
Emergency Fund by the numbers
- 405 all-time installs (skills.sh)
- +16 installs in the week ending Aug 2, 2026 (Skillselion tracking)
- Ranked #247 of 1,106 Finance & Trading skills by installs in the Skillselion catalog
- Data as of Aug 2, 2026 (Skillselion catalog sync)
npx skills add https://github.com/joellewis/finance_skills --skill emergency-fundAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 405 |
|---|---|
| repo stars | ★ 161 |
| Last updated | July 18, 2026 |
| Repository | joellewis/finance_skills ↗ |
How do you size an emergency fund by expenses?
Calculate recommended emergency fund targets, savings timelines, and liquidity tiers based on client income stability, expenses, and dependents.
Who is it for?
Fintech developers building financial planning calculators that need expense-based emergency fund sizing with tiered liquidity vehicle recommendations.
Skip if: Developers modeling investment portfolio allocation or tax-efficient withdrawal strategies, which other finance_skills cover separately.
When should I use this skill?
User asks about emergency fund sizing, months of expenses to save, tiered cash reserves, or rainy day fund calculations.
What you get
Emergency fund dollar target, tiered allocation across checking/HYSA/T-bills, opportunity cost estimate, and replenishment timeline after withdrawals.
- Emergency fund dollar target
- Tiered allocation plan
- Opportunity cost and replenishment timeline
By the numbers
- Includes emergency_fund.py script with --verify against worked examples
- Compares 7 cash vehicle types in a yield-liquidity selection table
- Part of finance_skills repository with 81 skills across 7 domain plugins
Files
Emergency Fund Planning
Core Concepts
Rule of Thumb
- Employed with stable income: 3-6 months of essential expenses
- Dual-income household (both stable): 3 months may suffice (lower probability of simultaneous job loss)
- Single income, variable income, or self-employed: 6-12 months of essential expenses
- High job-search risk (niche industry, senior executive, specialized role): 6-12 months
- These are guidelines — individual assessment is essential
Essential Expenses
The emergency fund should cover non-discretionary spending only:
- Housing: Mortgage/rent, property tax, insurance, HOA
- Food: Groceries (not dining out)
- Insurance: Health, auto, life (premiums that cannot be paused)
- Utilities: Electric, gas, water, internet, phone
- Transportation: Car payment, gas, basic maintenance, public transit
- Minimum debt payments: Credit cards, student loans, other obligations
- Healthcare: Regular medications, co-pays
- Exclude: Dining out, entertainment, travel, shopping, subscriptions that can be cancelled
Expense-Based Sizing
Monthly essential expenses multiplied by the desired months of coverage:
- Emergency fund = monthly essential expenses × months of coverage
- Example: $4,500/month essentials × 6 months = $27,000
- More precise than income-based because it reflects actual spending needs during a crisis
Income Replacement Approach
After-tax monthly income multiplied by months of coverage:
- Emergency fund = after-tax monthly income × months of coverage
- Simpler to calculate but may overstate need (assumes maintaining full spending during emergency)
- Useful as an upper bound or for high earners whose expenses scale with income
Variable Income Adjustment
For commission-based, freelance, seasonal, or gig workers:
- Calculate average monthly income over 12-24 months
- Set base budget at the lowest 3-month average income level
- Buffer = average income - base budget (accumulated during high-earning months)
- Emergency fund should be 6-12 months of essential expenses (longer because income disruption is more likely and less predictable)
- Maintain a separate "income smoothing" buffer beyond the emergency fund
Tiered Emergency Fund
Structure the fund across tiers for optimal balance of access and yield:
- Tier 1 — Immediate access (1 month): Checking or savings account at primary bank. Instantly accessible for urgent needs. Low or no yield, but maximum liquidity.
- Tier 2 — Short-term (2-3 months): High-yield savings account (HYSA) or money market fund. Available in 1-2 business days. Earns competitive short-term rates.
- Tier 3 — Extended (3-6 months): Short-term Treasury bills, I-bonds (after 1-year lock-up), short-term bond fund, or CD ladder. May take a few days to a few weeks to access. Higher yield compensates for slightly lower liquidity.
Vehicle Selection
| Vehicle | Yield | Liquidity | FDIC/SIPC | Best For |
|---|---|---|---|---|
| Checking account | Very low | Instant | FDIC | Tier 1 (1 month) |
| HYSA | Moderate | 1-2 days | FDIC | Tier 2 (core fund) |
| Money market fund | Moderate | 1-2 days | SIPC | Tier 2 (core fund) |
| T-bills (4-week) | Moderate-high | At maturity | Full faith & credit | Tier 2/3 (ladder) |
| CD (3-12 month) | Moderate-high | At maturity (penalty) | FDIC | Tier 3 (ladder) |
| I-bonds | Inflation-linked | After 12 months | Full faith & credit | Tier 3 (long-term) |
| Short-term bond fund | Variable | 1-3 days | SIPC | Tier 3 (flexible) |
Opportunity Cost
Holding cash has a real cost — the difference between what the cash earns and what it could earn if invested:
- Cash drag: Emergency fund earning 4% HYSA vs 8-10% equity expected return = 4-6% annual opportunity cost
- On a $30K emergency fund: $1,200-$1,800/year in foregone returns
- Mitigant: The purpose of the fund is insurance, not investment return. The "premium" is the opportunity cost.
- Over-funded risk: Holding 12+ months when 3-6 months suffices wastes significant capital
- Under-funded risk: Having to use credit cards at 20%+ APR or sell investments at a loss during an emergency
When to Tap the Emergency Fund
Appropriate uses:
- Job loss or significant income reduction
- Medical emergency or unexpected healthcare costs
- Essential home repair (roof leak, HVAC failure, plumbing emergency)
- Essential car repair (needed for commuting to work)
- Unexpected essential travel (family emergency)
NOT appropriate uses:
- Vacations or planned travel
- Planned purchases (holiday gifts, electronics)
- Investment opportunities ("buy the dip")
- Non-essential home improvements
- Expenses that should have been budgeted (annual insurance, property tax)
Replenishment Plan
After using the emergency fund:
- Prioritize rebuilding before resuming discretionary spending or non-essential savings goals
- Set a monthly replenishment target (e.g., rebuild within 6-12 months)
- Temporarily reduce or pause contributions to other goals if needed
- Redirect windfalls (tax refund, bonus) to accelerate replenishment
Key Formulas
| Formula | Expression | Use Case |
|---|---|---|
| Expense-based fund | Monthly essentials × months of coverage | Core sizing calculation |
| Income-based fund | After-tax monthly income × months of coverage | Upper bound estimate |
| Opportunity cost | Fund balance × (investment return - cash return) | Cost of holding cash |
| Replenishment timeline | Fund shortfall / monthly replenishment amount | Months to rebuild |
| Variable income buffer | Avg monthly income - base budget | Surplus for smoothing |
Worked Examples
Example 1: Emergency fund sizing for a dual-income household
Given: Married couple, both employed in stable jobs. Monthly essential expenses: $4,500 (housing $1,800, food $600, insurance $400, utilities $300, transportation $500, debt minimums $400, healthcare $200, other essentials $300). Calculate: Recommended emergency fund size. Solution: 1. Dual income, stable employment: 3 months is the baseline; 4 months provides a comfortable margin. 2. Emergency fund = $4,500 × 3 = $13,500 (minimum) to $4,500 × 4 = $18,000 (recommended). 3. Considerations: If either spouse works in a cyclical industry or has less job security, increase to 6 months ($27,000). 4. If one spouse could cover essentials alone: May reduce to 3 months since the risk of zero income is lower. 5. Recommendation: $13,500-$18,000 for this stable dual-income household.
Example 2: Tiered fund allocation
Given: Target emergency fund of $27,000 (6 months × $4,500/month) for a single-income household. Calculate: Optimal tiered allocation. Solution: 1. Tier 1 — Checking account: $4,500 (1 month). Immediate access for sudden expenses (car repair, medical co-pay). Earning ~0.01% but provides instant liquidity. 2. Tier 2 — High-yield savings account: $13,500 (3 months). Core emergency reserves. Earning ~4.5% APY (e.g., ~4-5% as of 2025 — check current HYSA rates). Available in 1-2 business days via transfer. 3. Tier 3 — T-bill ladder: $9,000 (2 months). Three $3,000 T-bills maturing at 4-week, 8-week, and 13-week intervals. Earning ~4.8% (e.g., ~4-5% as of 2025 — check current T-bill rates). At least one tranche matures every ~4 weeks. 4. Blended yield: (4,500 × 0.01% + 13,500 × 4.5% + 9,000 × 4.8%) / 27,000 ≈ 3.85% weighted average. 5. vs all checking (0.01%): Earning ~$1,040/year more with the tiered approach — effectively free money for modest complexity.
Common Pitfalls
- Too little: financial stress during emergencies, forced to use high-interest debt (credit cards at 20%+), potential to sell investments at a loss
- Too much: significant opportunity cost from excess cash eroded by inflation; common among risk-averse savers
- Not adjusting for life changes — new baby (higher expenses), job change (less stability), mortgage (larger fixed obligation), spouse stops working
- Keeping the emergency fund in investments that can lose value — stocks, long-term bonds, or crypto are not appropriate vehicles
- Using the emergency fund for non-emergencies — erodes the safety net and creates a cycle of depletion
- Not having a replenishment plan — spending the fund without a strategy to rebuild leaves ongoing vulnerability
- Ignoring inflation: a $20K fund in 2020 has less purchasing power in 2030; periodically reassess the target
- Treating the emergency fund as an investment account rather than an insurance policy
Cross-References
- liquidity-management: emergency fund is the foundation of the personal liquidity tier structure
- savings-goals: emergency fund is typically the highest priority savings goal
- debt-management: adequate emergency fund prevents taking on new high-interest debt during crises
- lending: emergency reserves are a factor in mortgage qualification
- investment-policy: emergency fund size feeds the liquidity constraint in an IPS
- financial-planning-workflow (advisory-practice plugin): emergency fund adequacy is assessed early in the comprehensive financial planning process
Running the Script
uv run scripts/emergency_fund.py # run the demo (uses PEP 723 inline deps)
uv run scripts/emergency_fund.py --verify # check demo outputs against the worked examples (exit 1 on mismatch)
python3 scripts/emergency_fund.py # alternative (requires: pip install numpy)The demo prints the calculations covered above; its values match the worked examples in this skill. Run --help for a list of the classes and functions. For programmatic use, import the module rather than running it — the demo only executes under python emergency_fund.py.
# /// script
# dependencies = ["numpy"]
# requires-python = ">=3.11"
# ///
"""
Emergency Fund Planning
=======================
Compute emergency fund sizing (expense-based and income-based), tiered allocation,
opportunity cost analysis, drawdown modeling, and replenishment schedules.
Part of Layer 6 (Personal Finance) in the finance skills framework.
"""
import argparse
import sys
import numpy as np
class EmergencyFund:
"""Emergency fund sizing, allocation, and analysis computations.
All methods are static — no instance state is required.
"""
@staticmethod
def expense_based_fund(
monthly_essentials: float, months_coverage: int
) -> float:
"""Compute the emergency fund target using the expense-based method.
Emergency fund = monthly essential expenses * months of coverage
Parameters
----------
monthly_essentials : float
Total monthly essential (non-discretionary) expenses.
months_coverage : int
Desired months of expense coverage (typically 3-6).
Returns
-------
float
Target emergency fund size.
"""
return monthly_essentials * months_coverage
@staticmethod
def income_based_fund(
after_tax_monthly_income: float, months_coverage: int
) -> float:
"""Compute the emergency fund target using the income replacement method.
Emergency fund = after-tax monthly income * months of coverage
Parameters
----------
after_tax_monthly_income : float
Monthly take-home pay.
months_coverage : int
Desired months of income replacement.
Returns
-------
float
Target emergency fund size (upper bound estimate).
"""
return after_tax_monthly_income * months_coverage
@staticmethod
def recommended_months(
dual_income: bool = True,
stable_employment: bool = True,
variable_income: bool = False,
high_search_risk: bool = False,
) -> tuple[int, int]:
"""Recommend months of coverage based on personal circumstances.
Parameters
----------
dual_income : bool, optional
True if household has two income earners. Default is True.
stable_employment : bool, optional
True if employment is stable. Default is True.
variable_income : bool, optional
True if income is commission, freelance, or seasonal. Default is False.
high_search_risk : bool, optional
True if job search would be difficult (niche, senior). Default is False.
Returns
-------
tuple[int, int]
(minimum_months, recommended_months) of expense coverage.
"""
if variable_income or high_search_risk:
return (6, 12)
if not stable_employment:
return (6, 9)
if dual_income and stable_employment:
return (3, 4)
return (3, 6)
@staticmethod
def tiered_allocation(
total_fund: float, monthly_essentials: float
) -> dict:
"""Allocate an emergency fund across liquidity tiers.
Tier 1 (checking): 1 month of expenses — instant access.
Tier 2 (HYSA/money market): 2-3 months — 1-2 day access.
Tier 3 (T-bills/CDs/I-bonds): remainder — slightly delayed access.
Parameters
----------
total_fund : float
Total emergency fund target.
monthly_essentials : float
Monthly essential expenses (used to size tiers).
Returns
-------
dict
Keys: 'tier_1', 'tier_2', 'tier_3', each with 'amount',
'months', and 'vehicle' fields.
"""
tier_1 = min(monthly_essentials, total_fund)
remaining = total_fund - tier_1
# Tier 2: up to 3 months
tier_2_target = monthly_essentials * 3.0
tier_2 = min(tier_2_target, remaining)
remaining -= tier_2
# Tier 3: everything else
tier_3 = max(remaining, 0.0)
return {
"tier_1": {
"amount": round(tier_1, 2),
"months": round(tier_1 / monthly_essentials, 1) if monthly_essentials > 0 else 0,
"vehicle": "Checking / savings account",
},
"tier_2": {
"amount": round(tier_2, 2),
"months": round(tier_2 / monthly_essentials, 1) if monthly_essentials > 0 else 0,
"vehicle": "High-yield savings / money market fund",
},
"tier_3": {
"amount": round(tier_3, 2),
"months": round(tier_3 / monthly_essentials, 1) if monthly_essentials > 0 else 0,
"vehicle": "T-bills / CDs / I-bonds",
},
}
@staticmethod
def blended_yield(
tier_amounts: list[float], tier_yields: list[float]
) -> float:
"""Compute the weighted average yield across fund tiers.
Parameters
----------
tier_amounts : list[float]
Dollar amounts in each tier.
tier_yields : list[float]
Annual yield for each tier as a decimal.
Returns
-------
float
Blended annual yield as a decimal.
"""
amounts = np.array(tier_amounts, dtype=np.float64)
yields = np.array(tier_yields, dtype=np.float64)
total = np.sum(amounts)
if total <= 0:
return 0.0
return float(np.dot(amounts, yields) / total)
@staticmethod
def opportunity_cost(
fund_balance: float,
cash_yield: float,
investment_return: float,
) -> float:
"""Compute the annual opportunity cost of holding cash reserves.
Opportunity cost = fund balance * (investment return - cash yield)
Parameters
----------
fund_balance : float
Total emergency fund balance.
cash_yield : float
Annual yield on emergency fund as a decimal.
investment_return : float
Expected annual return on investments as a decimal.
Returns
-------
float
Annual opportunity cost in dollars.
"""
return fund_balance * max(investment_return - cash_yield, 0.0)
@staticmethod
def drawdown_schedule(
fund_balance: float,
monthly_draw: float,
fund_yield: float = 0.0,
) -> np.ndarray:
"""Model emergency fund drawdown over time.
Simulates monthly withdrawals from the fund, accounting for any
yield earned on the remaining balance.
Parameters
----------
fund_balance : float
Starting fund balance.
monthly_draw : float
Monthly withdrawal amount.
fund_yield : float, optional
Annual yield on fund as a decimal. Default is 0.0.
Returns
-------
np.ndarray
Structured array with columns: month, withdrawal, interest_earned,
remaining_balance.
"""
r = fund_yield / 12.0
rows: list[tuple[int, float, float, float]] = []
balance = fund_balance
month = 0
while balance > 0.005:
month += 1
interest = balance * r
balance += interest
withdrawal = min(monthly_draw, balance)
balance -= withdrawal
rows.append((month, withdrawal, interest, max(balance, 0.0)))
dtype = np.dtype(
[
("month", np.int32),
("withdrawal", np.float64),
("interest_earned", np.float64),
("remaining_balance", np.float64),
]
)
return np.array(rows, dtype=dtype)
@staticmethod
def drawdown_duration(
fund_balance: float,
monthly_draw: float,
fund_yield: float = 0.0,
) -> float:
"""Compute how many months the emergency fund lasts.
Parameters
----------
fund_balance : float
Starting fund balance.
monthly_draw : float
Monthly withdrawal amount.
fund_yield : float, optional
Annual yield on the fund. Default is 0.0.
Returns
-------
float
Number of months the fund can sustain withdrawals.
"""
if monthly_draw <= 0:
return float("inf")
schedule = EmergencyFund.drawdown_schedule(fund_balance, monthly_draw, fund_yield)
return float(len(schedule))
@staticmethod
def replenishment_schedule(
current_balance: float,
target_balance: float,
monthly_contribution: float,
fund_yield: float = 0.0,
) -> dict:
"""Compute the timeline to rebuild the emergency fund after a drawdown.
Parameters
----------
current_balance : float
Current fund balance after drawdown.
target_balance : float
Full emergency fund target.
monthly_contribution : float
Monthly amount allocated to replenishment.
fund_yield : float, optional
Annual yield earned during replenishment. Default is 0.0.
Returns
-------
dict
Keys: 'shortfall', 'months_to_rebuild', 'total_contributed',
'interest_earned'.
"""
shortfall = target_balance - current_balance
if shortfall <= 0:
return {
"shortfall": 0.0,
"months_to_rebuild": 0,
"total_contributed": 0.0,
"interest_earned": 0.0,
}
if monthly_contribution <= 0:
return {
"shortfall": round(shortfall, 2),
"months_to_rebuild": float("inf"),
"total_contributed": 0.0,
"interest_earned": 0.0,
}
r = fund_yield / 12.0
balance = current_balance
total_contributed = 0.0
total_interest = 0.0
months = 0
while balance < target_balance - 0.005:
months += 1
interest = balance * r
total_interest += interest
balance += interest + monthly_contribution
total_contributed += monthly_contribution
if months > 1200: # safety limit
break
return {
"shortfall": round(shortfall, 2),
"months_to_rebuild": months,
"total_contributed": round(total_contributed, 2),
"interest_earned": round(total_interest, 2),
}
@staticmethod
def variable_income_buffer(
monthly_incomes: np.ndarray, monthly_essentials: float
) -> dict:
"""Analyze variable income and recommend a smoothing buffer.
Parameters
----------
monthly_incomes : np.ndarray
Array of monthly income values over a historical period.
monthly_essentials : float
Monthly essential expenses.
Returns
-------
dict
Keys: 'average_income', 'min_income', 'max_income',
'income_volatility', 'months_below_expenses',
'recommended_buffer' (2-3 months of essentials).
"""
incomes = np.asarray(monthly_incomes, dtype=np.float64)
avg = float(np.mean(incomes))
volatility = float(np.std(incomes, ddof=1)) if len(incomes) > 1 else 0.0
below = int(np.sum(incomes < monthly_essentials))
# Recommend buffer: 2 months if relatively stable, 3 if volatile
cv = volatility / avg if avg > 0 else 0.0
buffer_months = 3 if cv > 0.30 else 2
buffer_amount = monthly_essentials * buffer_months
return {
"average_income": round(avg, 2),
"min_income": round(float(np.min(incomes)), 2),
"max_income": round(float(np.max(incomes)), 2),
"income_volatility": round(volatility, 2),
"coefficient_of_variation": round(cv, 4),
"months_below_expenses": below,
"recommended_buffer_months": buffer_months,
"recommended_buffer": round(buffer_amount, 2),
}
def _demo() -> None:
# ----------------------------------------------------------------
# Demo: Emergency fund computations
# ----------------------------------------------------------------
EF = EmergencyFund
print("=" * 60)
print("Emergency Fund Planning - Demo")
print("=" * 60)
# --- Example 1: Expense-Based Sizing ---
print("\n--- Example 1: Expense-Based Fund Sizing ---")
monthly_exp = 4500
min_mo, rec_mo = EF.recommended_months(dual_income=True, stable_employment=True)
fund_min = EF.expense_based_fund(monthly_exp, min_mo)
fund_rec = EF.expense_based_fund(monthly_exp, rec_mo)
print(f" Monthly essentials: ${monthly_exp:,.0f}")
print(f" Dual income, stable: {min_mo}-{rec_mo} months recommended")
print(f" Minimum fund: ${fund_min:,.0f}")
print(f" Recommended fund: ${fund_rec:,.0f}")
# --- Example 2: Tiered Allocation ---
print("\n--- Example 2: Tiered Allocation ---")
total_fund = 27_000
allocation = EF.tiered_allocation(total_fund, monthly_exp)
for tier_name, tier_data in allocation.items():
print(
f" {tier_name}: ${tier_data['amount']:,.2f} "
f"({tier_data['months']:.1f} months) - {tier_data['vehicle']}"
)
# --- Example 3: Blended Yield ---
print("\n--- Example 3: Blended Yield ---")
amounts = [4500.0, 13500.0, 9000.0]
yields = [0.0001, 0.045, 0.048]
blended = EF.blended_yield(amounts, yields)
print(f" Tier amounts: {amounts}")
print(f" Tier yields: {[f'{y:.2%}' for y in yields]}")
print(f" Blended yield: {blended:.4%}")
print(f" Annual earnings: ${total_fund * blended:,.2f}")
# --- Example 4: Opportunity Cost ---
print("\n--- Example 4: Opportunity Cost ---")
opp_cost = EF.opportunity_cost(27_000, 0.04, 0.09)
print(f" Fund: $27K, cash yield: 4%, investment return: 9%")
print(f" Annual opportunity cost: ${opp_cost:,.2f}")
print(f" Think of this as the 'insurance premium' for liquidity")
# --- Example 5: Drawdown Modeling ---
print("\n--- Example 5: Drawdown Duration ---")
duration = EF.drawdown_duration(27_000, 4_500, fund_yield=0.04)
print(f" $27K fund, $4.5K/mo withdrawals, 4% yield")
print(f" Fund lasts: {duration:.0f} months")
schedule = EF.drawdown_schedule(27_000, 4_500, fund_yield=0.04)
print(f" {'Month':>5} {'Withdrawal':>11} {'Interest':>9} {'Balance':>11}")
for row in schedule:
print(
f" {row['month']:5d} ${row['withdrawal']:10,.2f}"
f" ${row['interest_earned']:8,.2f} ${row['remaining_balance']:10,.2f}"
)
# --- Example 6: Replenishment ---
print("\n--- Example 6: Replenishment Schedule ---")
replenish = EF.replenishment_schedule(
current_balance=10_000,
target_balance=27_000,
monthly_contribution=1_500,
fund_yield=0.04,
)
print(f" Balance: $10K, Target: $27K, Contributing: $1.5K/mo")
print(f" Shortfall: ${replenish['shortfall']:,.2f}")
print(f" Months to rebuild: {replenish['months_to_rebuild']}")
print(f" Total contributed: ${replenish['total_contributed']:,.2f}")
print(f" Interest earned: ${replenish['interest_earned']:,.2f}")
# --- Example 7: Variable Income Analysis ---
print("\n--- Example 7: Variable Income Buffer ---")
np.random.seed(42)
# Simulate freelancer income: base $5K + variable $0-$10K
incomes = 5000 + np.random.exponential(3000, size=24)
analysis = EF.variable_income_buffer(incomes, monthly_essentials=5500)
print(f" Average income: ${analysis['average_income']:,.2f}")
print(f" Min income: ${analysis['min_income']:,.2f}")
print(f" Max income: ${analysis['max_income']:,.2f}")
print(f" Income volatility: ${analysis['income_volatility']:,.2f}")
print(f" Coeff. of variation: {analysis['coefficient_of_variation']:.4f}")
print(f" Months below expenses: {analysis['months_below_expenses']}")
print(f" Recommended buffer: ${analysis['recommended_buffer']:,.2f} "
f"({analysis['recommended_buffer_months']} months)")
# --- Example 8: Single Income, Variable ---
print("\n--- Example 8: Recommendations by Situation ---")
situations = [
("Dual income, stable", dict(dual_income=True, stable_employment=True)),
("Single income, stable", dict(dual_income=False, stable_employment=True)),
("Single income, unstable", dict(dual_income=False, stable_employment=False)),
("Variable / self-employed", dict(dual_income=False, variable_income=True)),
("Niche / senior role", dict(dual_income=False, high_search_risk=True)),
]
for label, kwargs in situations:
lo, hi = EF.recommended_months(**kwargs)
print(f" {label:30s}: {lo}-{hi} months")
print("\n" + "=" * 60)
print("Demo complete.")
print("=" * 60)
def _check(failures: list, name: str, actual: float, expected: float, tol: float) -> None:
"""Record a verification check result."""
ok = abs(actual - expected) <= tol
status = "PASS" if ok else "FAIL"
print(f" [{status}] {name}: actual={actual:.6g}, expected={expected:.6g}, tol={tol:.2g}")
if not ok:
failures.append(name)
def _verify() -> None:
"""Verify key outputs against the SKILL.md worked examples."""
failures: list = []
# SKILL.md Example 1: dual-income sizing
_check(failures, "Ex1 minimum fund (3 months)", EmergencyFund.expense_based_fund(4500, 3), 13500, 0)
_check(failures, "Ex1 recommended fund (4 months)", EmergencyFund.expense_based_fund(4500, 4), 18000, 0)
# SKILL.md Example 2: tiered allocation of $27,000
alloc = EmergencyFund.tiered_allocation(27000, 4500)
_check(failures, "Ex2 tier 1 amount", alloc["tier_1"]["amount"], 4500, 0)
_check(failures, "Ex2 tier 2 amount", alloc["tier_2"]["amount"], 13500, 0)
_check(failures, "Ex2 tier 3 amount", alloc["tier_3"]["amount"], 9000, 0)
blended = EmergencyFund.blended_yield([4500.0, 13500.0, 9000.0], [0.0001, 0.045, 0.048])
_check(failures, "Ex2 blended yield", blended, 0.038517, 1e-5)
# Opportunity cost concept check
_check(failures, "opportunity cost $27K at 5pp spread",
EmergencyFund.opportunity_cost(27000, 0.04, 0.09), 1350.0, 1e-9)
if failures:
print(f"\n{len(failures)} check(s) FAILED: {', '.join(failures)}")
sys.exit(1)
print("\nAll checks passed.")
def main() -> None:
parser = argparse.ArgumentParser(
description=__doc__.strip().splitlines()[2] if __doc__ else "",
epilog=(
"Provides: EmergencyFund. "
"For programmatic use, import this module (emergency_fund) instead of running it. "
"Bare run executes a demo whose printed values match the SKILL.md worked examples; "
"--verify asserts those values and exits nonzero on mismatch."
),
)
parser.add_argument(
"--verify",
action="store_true",
help="run the verification checks against the SKILL.md worked-example values",
)
args = parser.parse_args()
if args.verify:
_verify()
else:
_demo()
if __name__ == "__main__":
main()
Related skills
How it compares
Pick emergency-fund over liquidity-management when you specifically need expense-based sizing rules and tiered vehicle allocation rather than broader personal liquidity frameworks.
FAQ
How does emergency-fund recommend sizing by employment type?
emergency-fund recommends 3-6 months of essential expenses for stable dual-income households and 6-12 months for single-income, freelance, or commission-based earners, sized from non-discretionary spending only.
What tiered structure does emergency-fund use?
emergency-fund structures funds in three tiers: 1 month in checking for instant access, 2-3 months in HYSA or money market, and 3-6 months in T-bill ladders or short-term bonds for higher yield.