personal-financial-advisor
8
总安装量
1
周安装量
#35505
全站排名
安装命令
npx skills add https://github.com/tringo0108/z-command --skill personal-financial-advisor
Agent 安装分布
amp
1
opencode
1
kimi-cli
1
codex
1
github-copilot
1
claude-code
1
Skill 文档
Personal Financial Advisor
Comprehensive toolkit for personal finance planning, helping individuals achieve financial wellness through budgeting, debt management, savings, investing, and goal-based planning.
When to Use This Skill
- Creating personal budgets and spending plans
- Developing debt payoff strategies
- Planning emergency funds and savings goals
- Retirement planning and projections
- Investment portfolio allocation for individuals
- Tax optimization for personal finances
- Insurance needs assessment
- Net worth tracking and financial health analysis
- Setting and tracking financial goals
Core Concepts
1. Financial Planning Hierarchy
âââââââââââââââââââââââââââââââââââââââââââ
â WEALTH BUILDING â
â (Investing, Retirement, Legacy) â
âââââââââââââââââââââââââââââââââââââââââââ¤
â PROTECTION â
â (Insurance, Estate Planning) â
âââââââââââââââââââââââââââââââââââââââââââ¤
â DEBT ELIMINATION â
â (High-interest â Low-interest) â
âââââââââââââââââââââââââââââââââââââââââââ¤
â EMERGENCY FUND â
â (3-6 months expenses) â
âââââââââââââââââââââââââââââââââââââââââââ¤
â FOUNDATION â
â (Budget, Cash Flow, Basic Savings) â
âââââââââââââââââââââââââââââââââââââââââââ
2. Key Financial Health Metrics
| Metric | Target | Formula |
|---|---|---|
| Savings Rate | â¥20% | Savings / Gross Income |
| Debt-to-Income | <36% | Monthly Debt / Monthly Income |
| Emergency Fund | 3-6 months | Liquid Savings / Monthly Expenses |
| Housing Ratio | <28% | Housing Costs / Gross Income |
| Net Worth Growth | Positive YoY | Assets – Liabilities |
Budgeting Methods
Pattern 1: Budgeting Frameworks
from dataclasses import dataclass
from typing import Dict, List, Optional
from enum import Enum
import pandas as pd
class BudgetMethod(Enum):
FIFTY_THIRTY_TWENTY = "50/30/20"
ZERO_BASED = "zero_based"
ENVELOPE = "envelope"
PAY_YOURSELF_FIRST = "pay_yourself_first"
@dataclass
class Income:
"""Monthly income sources."""
salary: float
side_income: float = 0
investment_income: float = 0
other: float = 0
@property
def total_gross(self) -> float:
return self.salary + self.side_income + self.investment_income + self.other
def after_tax(self, tax_rate: float = 0.25) -> float:
"""Calculate after-tax income."""
return self.total_gross * (1 - tax_rate)
@dataclass
class Expense:
"""Expense item with category."""
name: str
amount: float
category: str # 'need', 'want', 'savings'
is_fixed: bool = True
class BudgetPlanner:
"""Personal budget planning and analysis."""
def __init__(self, income: Income, tax_rate: float = 0.25):
self.income = income
self.tax_rate = tax_rate
self.expenses: List[Expense] = []
def add_expense(self, expense: Expense) -> None:
"""Add an expense to the budget."""
self.expenses.append(expense)
@property
def monthly_income(self) -> float:
"""After-tax monthly income."""
return self.income.after_tax(self.tax_rate)
# ==================== 50/30/20 RULE ====================
def fifty_thirty_twenty(self) -> Dict[str, float]:
"""
50/30/20 Budget Rule.
- 50% Needs: Housing, utilities, groceries, insurance, minimum debt payments
- 30% Wants: Entertainment, dining out, hobbies, subscriptions
- 20% Savings: Emergency fund, retirement, investments, extra debt payments
"""
income = self.monthly_income
return {
'needs_budget': income * 0.50,
'wants_budget': income * 0.30,
'savings_budget': income * 0.20,
'needs_actual': sum(e.amount for e in self.expenses if e.category == 'need'),
'wants_actual': sum(e.amount for e in self.expenses if e.category == 'want'),
'savings_actual': sum(e.amount for e in self.expenses if e.category == 'savings'),
}
def analyze_fifty_thirty_twenty(self) -> Dict[str, any]:
"""Analyze budget against 50/30/20 targets."""
budget = self.fifty_thirty_twenty()
return {
'needs': {
'budget': budget['needs_budget'],
'actual': budget['needs_actual'],
'variance': budget['needs_budget'] - budget['needs_actual'],
'on_track': budget['needs_actual'] <= budget['needs_budget']
},
'wants': {
'budget': budget['wants_budget'],
'actual': budget['wants_actual'],
'variance': budget['wants_budget'] - budget['wants_actual'],
'on_track': budget['wants_actual'] <= budget['wants_budget']
},
'savings': {
'budget': budget['savings_budget'],
'actual': budget['savings_actual'],
'variance': budget['savings_actual'] - budget['savings_budget'],
'on_track': budget['savings_actual'] >= budget['savings_budget']
}
}
# ==================== ZERO-BASED BUDGETING ====================
def zero_based_budget(self) -> Dict[str, float]:
"""
Zero-Based Budgeting.
Every dollar has a job. Income - All Expenses = $0
"""
total_expenses = sum(e.amount for e in self.expenses)
unallocated = self.monthly_income - total_expenses
return {
'income': self.monthly_income,
'total_allocated': total_expenses,
'unallocated': unallocated,
'is_balanced': abs(unallocated) < 1.0, # Within $1
'expenses_by_category': self._group_expenses_by_category()
}
def _group_expenses_by_category(self) -> Dict[str, float]:
"""Group expenses by category."""
categories = {}
for expense in self.expenses:
if expense.category not in categories:
categories[expense.category] = 0
categories[expense.category] += expense.amount
return categories
# ==================== ENVELOPE SYSTEM ====================
def envelope_budget(self, envelopes: Dict[str, float]) -> Dict[str, Dict]:
"""
Envelope Budgeting System.
Allocate cash to specific spending categories.
When envelope is empty, stop spending.
"""
result = {}
for category, budget in envelopes.items():
spent = sum(e.amount for e in self.expenses if e.category == category)
result[category] = {
'budget': budget,
'spent': spent,
'remaining': budget - spent,
'percent_used': (spent / budget * 100) if budget > 0 else 0
}
return result
# ==================== PAY YOURSELF FIRST ====================
def pay_yourself_first(self, savings_target_percent: float = 0.20) -> Dict[str, float]:
"""
Pay Yourself First Strategy.
Save first, then budget the rest for expenses.
"""
savings_amount = self.monthly_income * savings_target_percent
spending_budget = self.monthly_income - savings_amount
actual_spending = sum(e.amount for e in self.expenses if e.category != 'savings')
return {
'target_savings': savings_amount,
'spending_budget': spending_budget,
'actual_spending': actual_spending,
'spending_variance': spending_budget - actual_spending,
'on_track': actual_spending <= spending_budget
}
# ==================== SAVINGS RATE ====================
def calculate_savings_rate(self) -> float:
"""Calculate monthly savings rate."""
savings = sum(e.amount for e in self.expenses if e.category == 'savings')
return savings / self.income.total_gross if self.income.total_gross > 0 else 0
Pattern 2: Debt Management Strategies
from dataclasses import dataclass
from typing import List, Dict
import numpy as np
@dataclass
class Debt:
"""Individual debt account."""
name: str
balance: float
interest_rate: float # Annual rate as decimal
minimum_payment: float
def monthly_interest(self) -> float:
"""Calculate monthly interest charge."""
return self.balance * (self.interest_rate / 12)
class DebtPayoffCalculator:
"""Debt payoff strategy calculator."""
def __init__(self, debts: List[Debt], extra_payment: float = 0):
self.debts = debts
self.extra_payment = extra_payment
@property
def total_debt(self) -> float:
return sum(d.balance for d in self.debts)
@property
def total_minimum_payments(self) -> float:
return sum(d.minimum_payment for d in self.debts)
@property
def weighted_avg_rate(self) -> float:
"""Calculate weighted average interest rate."""
if self.total_debt == 0:
return 0
return sum(d.balance * d.interest_rate for d in self.debts) / self.total_debt
# ==================== DEBT SNOWBALL ====================
def debt_snowball(self) -> Dict:
"""
Debt Snowball Method.
Pay minimum on all debts, put extra toward SMALLEST balance first.
Psychological wins build momentum.
"""
# Sort by balance (smallest first)
sorted_debts = sorted(self.debts, key=lambda d: d.balance)
return self._simulate_payoff(sorted_debts, "snowball")
# ==================== DEBT AVALANCHE ====================
def debt_avalanche(self) -> Dict:
"""
Debt Avalanche Method.
Pay minimum on all debts, put extra toward HIGHEST interest rate first.
Mathematically optimal - minimizes total interest paid.
"""
# Sort by interest rate (highest first)
sorted_debts = sorted(self.debts, key=lambda d: d.interest_rate, reverse=True)
return self._simulate_payoff(sorted_debts, "avalanche")
def _simulate_payoff(self, sorted_debts: List[Debt], method: str) -> Dict:
"""Simulate debt payoff over time."""
# Create working copies
balances = {d.name: d.balance for d in sorted_debts}
rates = {d.name: d.interest_rate for d in sorted_debts}
minimums = {d.name: d.minimum_payment for d in sorted_debts}
total_paid = 0
total_interest = 0
months = 0
payoff_order = []
monthly_schedule = []
while any(b > 0 for b in balances.values()):
months += 1
if months > 360: # 30 year cap
break
month_interest = 0
month_principal = 0
extra_remaining = self.extra_payment
# Apply interest to all debts
for name in balances:
if balances[name] > 0:
interest = balances[name] * (rates[name] / 12)
balances[name] += interest
month_interest += interest
# Pay minimums on all debts
for name in balances:
if balances[name] > 0:
payment = min(minimums[name], balances[name])
balances[name] -= payment
month_principal += payment
if balances[name] <= 0:
balances[name] = 0
payoff_order.append({'name': name, 'month': months})
extra_remaining += minimums[name] # Freed up payment
# Apply extra payment to target debt
for debt in sorted_debts:
if balances[debt.name] > 0 and extra_remaining > 0:
payment = min(extra_remaining, balances[debt.name])
balances[debt.name] -= payment
month_principal += payment
extra_remaining -= payment
if balances[debt.name] <= 0:
balances[debt.name] = 0
payoff_order.append({'name': debt.name, 'month': months})
total_interest += month_interest
total_paid += month_interest + month_principal
monthly_schedule.append({
'month': months,
'interest_paid': month_interest,
'principal_paid': month_principal,
'remaining_balance': sum(balances.values())
})
return {
'method': method,
'months_to_payoff': months,
'years_to_payoff': months / 12,
'total_paid': total_paid,
'total_interest': total_interest,
'original_balance': self.total_debt,
'payoff_order': payoff_order,
'monthly_schedule': monthly_schedule
}
def compare_methods(self) -> Dict:
"""Compare snowball vs avalanche methods."""
snowball = self.debt_snowball()
avalanche = self.debt_avalanche()
return {
'snowball': snowball,
'avalanche': avalanche,
'interest_savings': snowball['total_interest'] - avalanche['total_interest'],
'time_difference_months': snowball['months_to_payoff'] - avalanche['months_to_payoff'],
'recommended': 'avalanche' if avalanche['total_interest'] < snowball['total_interest'] else 'snowball'
}
Pattern 3: Emergency Fund Calculator
@dataclass
class MonthlyExpenses:
"""Monthly essential expenses."""
housing: float # Rent/mortgage
utilities: float
groceries: float
transportation: float
insurance: float
minimum_debt_payments: float
other_essentials: float = 0
@property
def total(self) -> float:
return (
self.housing + self.utilities + self.groceries +
self.transportation + self.insurance +
self.minimum_debt_payments + self.other_essentials
)
class EmergencyFundPlanner:
"""Emergency fund planning and tracking."""
def __init__(
self,
monthly_expenses: MonthlyExpenses,
current_savings: float = 0,
job_stability: str = "stable" # stable, moderate, unstable
):
self.expenses = monthly_expenses
self.current_savings = current_savings
self.job_stability = job_stability
def recommended_months(self) -> int:
"""Get recommended emergency fund months based on job stability."""
recommendations = {
"stable": 3, # Stable job, dual income
"moderate": 6, # Single income, some variability
"unstable": 9, # Freelance, commission-based, volatile industry
"self_employed": 12 # Business owners
}
return recommendations.get(self.job_stability, 6)
def target_amount(self) -> float:
"""Calculate target emergency fund amount."""
return self.expenses.total * self.recommended_months()
def current_coverage(self) -> float:
"""Calculate current months of coverage."""
return self.current_savings / self.expenses.total if self.expenses.total > 0 else 0
def gap_analysis(self) -> Dict:
"""Analyze emergency fund gap."""
target = self.target_amount()
gap = max(0, target - self.current_savings)
return {
'target_months': self.recommended_months(),
'target_amount': target,
'current_savings': self.current_savings,
'current_months_coverage': self.current_coverage(),
'gap_amount': gap,
'percent_funded': (self.current_savings / target * 100) if target > 0 else 100,
'is_fully_funded': self.current_savings >= target
}
def savings_plan(self, monthly_contribution: float) -> Dict:
"""Create plan to reach emergency fund target."""
gap = self.gap_analysis()['gap_amount']
if gap <= 0:
return {'already_funded': True, 'months_to_goal': 0}
months_to_goal = gap / monthly_contribution if monthly_contribution > 0 else float('inf')
return {
'already_funded': False,
'gap_amount': gap,
'monthly_contribution': monthly_contribution,
'months_to_goal': months_to_goal,
'years_to_goal': months_to_goal / 12,
'target_date_months': int(np.ceil(months_to_goal))
}
Pattern 4: Retirement Planning
class RetirementPlanner:
"""Retirement savings and projection calculator."""
def __init__(
self,
current_age: int,
retirement_age: int,
current_savings: float,
annual_contribution: float,
expected_return: float = 0.07, # 7% average market return
inflation_rate: float = 0.03
):
self.current_age = current_age
self.retirement_age = retirement_age
self.current_savings = current_savings
self.annual_contribution = annual_contribution
self.expected_return = expected_return
self.inflation_rate = inflation_rate
@property
def years_to_retirement(self) -> int:
return max(0, self.retirement_age - self.current_age)
def future_value(self) -> float:
"""
Calculate future value of retirement savings.
FV = PV Ã (1 + r)^n + PMT Ã [((1 + r)^n - 1) / r]
"""
n = self.years_to_retirement
r = self.expected_return
# Future value of current savings
fv_current = self.current_savings * ((1 + r) ** n)
# Future value of annual contributions (annuity)
if r > 0:
fv_contributions = self.annual_contribution * (((1 + r) ** n - 1) / r)
else:
fv_contributions = self.annual_contribution * n
return fv_current + fv_contributions
def real_future_value(self) -> float:
"""Future value adjusted for inflation (today's dollars)."""
nominal_fv = self.future_value()
return nominal_fv / ((1 + self.inflation_rate) ** self.years_to_retirement)
def retirement_income(self, withdrawal_rate: float = 0.04) -> Dict:
"""
Calculate sustainable retirement income using 4% rule.
The 4% rule: Withdraw 4% of portfolio in year 1, then adjust for inflation.
"""
portfolio = self.future_value()
real_portfolio = self.real_future_value()
return {
'portfolio_at_retirement': portfolio,
'portfolio_real_value': real_portfolio,
'annual_income_nominal': portfolio * withdrawal_rate,
'annual_income_real': real_portfolio * withdrawal_rate,
'monthly_income_nominal': portfolio * withdrawal_rate / 12,
'monthly_income_real': real_portfolio * withdrawal_rate / 12
}
def required_savings_for_income(
self,
target_annual_income: float,
withdrawal_rate: float = 0.04
) -> Dict:
"""Calculate required savings to achieve target retirement income."""
required_portfolio = target_annual_income / withdrawal_rate
# Solve for required annual contribution
# FV = PV Ã (1 + r)^n + PMT Ã [((1 + r)^n - 1) / r]
# PMT = (FV - PV Ã (1 + r)^n) / [((1 + r)^n - 1) / r]
n = self.years_to_retirement
r = self.expected_return
fv_current = self.current_savings * ((1 + r) ** n)
remaining_needed = required_portfolio - fv_current
if r > 0 and n > 0:
annuity_factor = ((1 + r) ** n - 1) / r
required_annual = remaining_needed / annuity_factor
else:
required_annual = remaining_needed / max(n, 1)
return {
'target_annual_income': target_annual_income,
'required_portfolio': required_portfolio,
'current_trajectory': self.future_value(),
'gap': max(0, required_portfolio - self.future_value()),
'required_annual_contribution': max(0, required_annual),
'required_monthly_contribution': max(0, required_annual / 12)
}
def compound_growth_schedule(self) -> List[Dict]:
"""Generate year-by-year growth projection."""
schedule = []
balance = self.current_savings
for year in range(self.years_to_retirement + 1):
age = self.current_age + year
schedule.append({
'year': year,
'age': age,
'starting_balance': balance,
'contribution': self.annual_contribution if year > 0 else 0,
'growth': balance * self.expected_return if year > 0 else 0,
'ending_balance': balance
})
if year < self.years_to_retirement:
balance = balance * (1 + self.expected_return) + self.annual_contribution
# Update ending balances
for i in range(len(schedule) - 1):
schedule[i]['ending_balance'] = schedule[i + 1]['starting_balance']
schedule[-1]['ending_balance'] = balance
return schedule
# ==================== RETIREMENT ACCOUNT OPTIMIZATION ====================
def contribution_priority(
self,
has_employer_401k: bool = True,
employer_match_percent: float = 0.03,
has_hsa: bool = False
) -> List[str]:
"""
Recommended contribution priority order.
Standard priority:
1. 401(k) up to employer match (free money)
2. HSA (triple tax advantage)
3. Max out Roth IRA
4. Max out 401(k)
5. Taxable brokerage
"""
priority = []
if has_employer_401k and employer_match_percent > 0:
priority.append(f"1. 401(k) to employer match ({employer_match_percent*100:.0f}%)")
if has_hsa:
priority.append("2. Max HSA ($4,150 individual / $8,300 family 2024)")
priority.extend([
"3. Max Roth IRA ($7,000 / $8,000 if 50+ in 2024)",
"4. Max 401(k) ($23,000 / $30,500 if 50+ in 2024)",
"5. Taxable brokerage account"
])
return priority
Pattern 5: Investment Portfolio Allocation
class PortfolioAllocator:
"""Personal investment portfolio allocation."""
def __init__(self, age: int, risk_tolerance: str = "moderate"):
self.age = age
self.risk_tolerance = risk_tolerance # conservative, moderate, aggressive
def age_based_allocation(self) -> Dict[str, float]:
"""
Age-based asset allocation rule.
Traditional: Bonds = Age (e.g., 30 years old = 30% bonds)
Modern: Bonds = Age - 20 (more aggressive for longer life expectancy)
"""
# Modern rule (age - 20)
bond_percent = max(0, min(80, self.age - 20)) / 100
stock_percent = 1 - bond_percent
return {
'stocks': stock_percent,
'bonds': bond_percent,
'rationale': f"At age {self.age}, allocate {stock_percent*100:.0f}% stocks, {bond_percent*100:.0f}% bonds"
}
def risk_based_allocation(self) -> Dict[str, float]:
"""Allocation based on risk tolerance."""
allocations = {
"conservative": {
'stocks': 0.30,
'bonds': 0.50,
'cash': 0.20
},
"moderate": {
'stocks': 0.60,
'bonds': 0.30,
'cash': 0.10
},
"aggressive": {
'stocks': 0.80,
'bonds': 0.15,
'cash': 0.05
},
"very_aggressive": {
'stocks': 0.95,
'bonds': 0.05,
'cash': 0.00
}
}
return allocations.get(self.risk_tolerance, allocations["moderate"])
def three_fund_portfolio(self, international_percent: float = 0.30) -> Dict[str, float]:
"""
Three-Fund Portfolio (Bogleheads approach).
Simple, low-cost, diversified portfolio:
1. US Total Stock Market
2. International Stock Market
3. US Total Bond Market
"""
base = self.age_based_allocation()
stock_allocation = base['stocks']
bond_allocation = base['bonds']
return {
'us_total_stock': stock_allocation * (1 - international_percent),
'international_stock': stock_allocation * international_percent,
'us_total_bond': bond_allocation,
'total': 1.0,
'example_funds': {
'us_total_stock': 'VTI, VTSAX, FSKAX',
'international_stock': 'VXUS, VTIAX, FTIHX',
'us_total_bond': 'BND, VBTLX, FXNAX'
}
}
def target_date_equivalent(self, retirement_year: int) -> Dict:
"""Calculate allocation similar to target-date funds."""
years_to_retirement = retirement_year - 2024
if years_to_retirement > 40:
stocks = 0.90
elif years_to_retirement > 25:
stocks = 0.85
elif years_to_retirement > 15:
stocks = 0.75
elif years_to_retirement > 5:
stocks = 0.60
elif years_to_retirement > 0:
stocks = 0.50
else: # In retirement
stocks = 0.40
return {
'retirement_year': retirement_year,
'years_to_retirement': years_to_retirement,
'stocks': stocks,
'bonds': 1 - stocks,
'glide_path': "Becomes more conservative as retirement approaches"
}
Pattern 6: Net Worth Tracker
@dataclass
class FinancialSnapshot:
"""Point-in-time financial snapshot."""
date: str
# Assets
checking: float = 0
savings: float = 0
investments: float = 0 # Brokerage accounts
retirement_401k: float = 0
retirement_ira: float = 0
home_value: float = 0
vehicle_value: float = 0
other_assets: float = 0
# Liabilities
mortgage: float = 0
auto_loans: float = 0
student_loans: float = 0
credit_cards: float = 0
other_debt: float = 0
@property
def total_assets(self) -> float:
return (
self.checking + self.savings + self.investments +
self.retirement_401k + self.retirement_ira +
self.home_value + self.vehicle_value + self.other_assets
)
@property
def liquid_assets(self) -> float:
return self.checking + self.savings + self.investments
@property
def retirement_assets(self) -> float:
return self.retirement_401k + self.retirement_ira
@property
def total_liabilities(self) -> float:
return (
self.mortgage + self.auto_loans + self.student_loans +
self.credit_cards + self.other_debt
)
@property
def net_worth(self) -> float:
return self.total_assets - self.total_liabilities
class NetWorthTracker:
"""Track net worth over time."""
def __init__(self):
self.snapshots: List[FinancialSnapshot] = []
def add_snapshot(self, snapshot: FinancialSnapshot) -> None:
"""Add a financial snapshot."""
self.snapshots.append(snapshot)
self.snapshots.sort(key=lambda s: s.date)
def current_net_worth(self) -> float:
"""Get most recent net worth."""
return self.snapshots[-1].net_worth if self.snapshots else 0
def net_worth_change(self, periods: int = 1) -> Dict:
"""Calculate net worth change over periods."""
if len(self.snapshots) < 2:
return {'change': 0, 'percent_change': 0}
current = self.snapshots[-1].net_worth
previous = self.snapshots[-min(periods + 1, len(self.snapshots))].net_worth
change = current - previous
return {
'current': current,
'previous': previous,
'change': change,
'percent_change': (change / previous * 100) if previous != 0 else 0
}
def financial_ratios(self) -> Dict[str, float]:
"""Calculate key financial health ratios."""
if not self.snapshots:
return {}
latest = self.snapshots[-1]
return {
'liquidity_ratio': latest.liquid_assets / latest.total_liabilities if latest.total_liabilities > 0 else float('inf'),
'debt_to_asset': latest.total_liabilities / latest.total_assets if latest.total_assets > 0 else 0,
'emergency_fund_months': latest.liquid_assets / (latest.total_liabilities + 1), # Rough estimate
'retirement_progress': latest.retirement_assets / latest.total_assets if latest.total_assets > 0 else 0
}
def asset_allocation(self) -> Dict[str, float]:
"""Current asset allocation breakdown."""
if not self.snapshots:
return {}
latest = self.snapshots[-1]
total = latest.total_assets
if total == 0:
return {}
return {
'cash': (latest.checking + latest.savings) / total,
'investments': latest.investments / total,
'retirement': latest.retirement_assets / total,
'real_estate': latest.home_value / total,
'other': (latest.vehicle_value + latest.other_assets) / total
}
Pattern 7: Financial Goal Planner
from datetime import datetime, timedelta
from typing import List, Dict, Optional
@dataclass
class FinancialGoal:
"""SMART financial goal."""
name: str
target_amount: float
target_date: str # YYYY-MM-DD
current_savings: float = 0
priority: int = 1 # 1 = highest priority
@property
def remaining_amount(self) -> float:
return max(0, self.target_amount - self.current_savings)
@property
def percent_complete(self) -> float:
return (self.current_savings / self.target_amount * 100) if self.target_amount > 0 else 100
@property
def months_remaining(self) -> int:
target = datetime.strptime(self.target_date, "%Y-%m-%d")
today = datetime.now()
delta = target - today
return max(0, delta.days // 30)
class GoalPlanner:
"""Multi-goal financial planning."""
def __init__(self, monthly_savings_budget: float):
self.monthly_budget = monthly_savings_budget
self.goals: List[FinancialGoal] = []
def add_goal(self, goal: FinancialGoal) -> None:
"""Add a financial goal."""
self.goals.append(goal)
self.goals.sort(key=lambda g: g.priority)
def analyze_goal(self, goal: FinancialGoal) -> Dict:
"""Analyze single goal feasibility."""
months = goal.months_remaining
required_monthly = goal.remaining_amount / months if months > 0 else goal.remaining_amount
return {
'goal': goal.name,
'target_amount': goal.target_amount,
'current_savings': goal.current_savings,
'remaining': goal.remaining_amount,
'percent_complete': goal.percent_complete,
'months_remaining': months,
'required_monthly': required_monthly,
'is_achievable': required_monthly <= self.monthly_budget,
'surplus_deficit': self.monthly_budget - required_monthly
}
def allocate_to_goals(self) -> Dict[str, float]:
"""Allocate monthly savings across goals by priority."""
allocations = {}
remaining_budget = self.monthly_budget
for goal in self.goals:
analysis = self.analyze_goal(goal)
required = analysis['required_monthly']
allocation = min(required, remaining_budget)
allocations[goal.name] = {
'allocated': allocation,
'required': required,
'shortfall': max(0, required - allocation)
}
remaining_budget -= allocation
allocations['unallocated'] = remaining_budget
return allocations
def summary(self) -> Dict:
"""Generate goals summary."""
total_needed = sum(g.remaining_amount for g in self.goals)
total_monthly_required = sum(
self.analyze_goal(g)['required_monthly'] for g in self.goals
)
return {
'total_goals': len(self.goals),
'total_amount_needed': total_needed,
'total_monthly_required': total_monthly_required,
'monthly_budget': self.monthly_budget,
'budget_gap': total_monthly_required - self.monthly_budget,
'can_achieve_all': total_monthly_required <= self.monthly_budget
}
Quick Reference
Key Rules of Thumb
# Budgeting
FIFTY_THIRTY_TWENTY = "50% needs, 30% wants, 20% savings"
PAY_YOURSELF_FIRST = "Save before you spend"
# Emergency Fund
EMERGENCY_FUND = "3-6 months of essential expenses"
STABLE_JOB = 3 # months
UNSTABLE_JOB = 6 # months
SELF_EMPLOYED = 12 # months
# Debt
DEBT_TO_INCOME_LIMIT = 0.36 # 36% max
HOUSING_RATIO_LIMIT = 0.28 # 28% max
# Retirement
SAVINGS_RATE_TARGET = 0.15 # 15% of income minimum
RULE_OF_25 = "Save 25x annual expenses for retirement"
FOUR_PERCENT_RULE = "Withdraw 4% annually in retirement"
# Investing
STOCKS_ALLOCATION = lambda age: 100 - age # or 110 - age (aggressive)
Financial Health Scorecard
| Metric | Poor | Fair | Good | Excellent |
|---|---|---|---|---|
| Savings Rate | <5% | 5-10% | 10-20% | >20% |
| Emergency Fund | <1 mo | 1-3 mo | 3-6 mo | >6 mo |
| Debt-to-Income | >50% | 36-50% | 20-36% | <20% |
| Retirement Savings | <1x salary | 1-3x | 3-6x | >6x |
| Net Worth | Negative | Break-even | Growing | Accelerating |
Best Practices
Do’s
- Pay yourself first – Automate savings before spending
- Build emergency fund before investing – Foundation first
- Take full employer match – It’s free money
- Track net worth monthly – What gets measured improves
- Review and rebalance annually – Stay on track
- Increase savings with raises – Avoid lifestyle inflation
Don’ts
- Don’t skip emergency fund – Debt can spiral without buffer
- Don’t time the market – Consistent investing beats timing
- Don’t ignore high-interest debt – Paying 20% interest beats 7% returns
- Don’t over-leverage housing – Stay under 28% of income
- Don’t neglect insurance – Protect against catastrophic loss
- Don’t compare to others – Focus on your own progress
Common Pitfalls
| Pitfall | Impact | Solution |
|---|---|---|
| No budget | Overspending | Use 50/30/20 rule |
| No emergency fund | Debt spiral | Build 3-6 months first |
| Only saving in 401k | Limited access | Balance with Roth & taxable |
| Too conservative young | Missed growth | Age – 20 = bond percentage |
| Lifestyle inflation | Never catch up | Save raises & bonuses |