Finex.Investment (finex v0.1.1)

View Source

Comprehensive investment and savings calculations with fee transparency.

All functions require separate annual yield and annual fees parameters to ensure transparency and accuracy in financial calculations. This approach matches real-world investment scenarios where yields and fees are reported separately.

Features

  • Fee Transparency: Separate yield and fees for accurate net return calculations
  • Decimal Precision: All calculations use Decimal to avoid floating-point errors
  • Flexible Scenarios: Handles both simple savings and complex investments
  • Timeline Planning: Calculate how long goals will take to achieve
  • Inflation Analysis: Understand purchasing power over time
  • Inflation-Adjusted Goals: Plan for targets that grow with inflation

Core Calculations

  • Investment outcome projections
  • Savings timeline calculations
  • Required contribution calculations
  • Goal feasibility analysis
  • Inflation impact analysis
  • Inflation-adjusted goal planning (accounts for moving targets)

Usage Pattern

All calculation functions follow the same pattern: (params..., annual_yield, annual_fees)

# Simple savings with 5% yield, no fees
Finex.Investment.calculate_outcome(0, 500, 0.05, 0.0, 2)

# Investment with 7% yield and 1% management fees
Finex.Investment.calculate_outcome(1000, 500, 0.07, 0.01, 5)

# Plan for inflation-adjusted goal (house price appreciation)
Finex.Investment.months_to_inflation_adjusted_goal(60_000, 1200, 0.04, 0.07, 0.01)

Summary

Functions

Calculate final investment outcome with initial and monthly contributions.

Calculate timeline to reach savings goal using monthly contributions.

Calculate timeline for lump sum investment to grow to target.

Analyze investment goal feasibility given income constraints.

Calculate future purchasing power accounting for inflation.

Calculate progress percentage toward investment goal.

Calculate required monthly contribution to reach investment goal.

Types

amount()

@type amount() :: Decimal.t() | number()

period()

@type period() :: pos_integer()

rate()

@type rate() :: float()

Functions

calculate_outcome(initial, monthly, years, annual_yield, annual_fees \\ 0.0)

@spec calculate_outcome(amount(), amount(), number(), rate(), rate()) ::
  {:ok,
   %{
     final_amount: Decimal.t(),
     total_contributions: Decimal.t(),
     total_interest: Decimal.t(),
     initial_growth: Decimal.t(),
     monthly_growth: Decimal.t()
   }}
  | {:error, atom()}

Calculate final investment outcome with initial and monthly contributions.

Combines the growth of an initial investment with regular monthly contributions to project the final portfolio value after a specified time period.

Parameters

  • initial - Initial lump sum investment (can be 0)
  • monthly - Monthly contribution amount (can be 0)
  • years - Investment period in years
  • annual_yield - Expected annual return before fees (as decimal, e.g., 0.07 for 7%)
  • annual_fees - Annual fees and expenses (as decimal, e.g., 0.01 for 1%)

Returns

  • final_amount - Total portfolio value at the end
  • total_contributions - Sum of all money you put in
  • total_interest - Earnings from compound growth
  • initial_growth - Growth from the initial investment only
  • monthly_growth - Growth from monthly contributions only

Examples

# Emergency fund: Save $500/month for 2 years at 5% yield, no fees
iex> Finex.Investment.calculate_outcome(0, 500, 2, 0.05, 0.0)
{:ok, %{
  final_amount: Decimal.new("12592.96"),
  total_contributions: Decimal.new("12000.00"),
  total_interest: Decimal.new("592.96"),
  initial_growth: Decimal.new("0.00"),
  monthly_growth: Decimal.new("12592.96")
}}

# Investment: $1000 initial + $500/month for 5 years at 7% yield with 1% fees
iex> Finex.Investment.calculate_outcome(1000, 500, 5, 0.07, 0.01)
{:ok, %{
  final_amount: Decimal.new("36228.25"),
  total_contributions: Decimal.new("31000.00"),
  total_interest: Decimal.new("5228.25"),
  initial_growth: Decimal.new("1348.46"),
  monthly_growth: Decimal.new("34879.79")
}}

# Retirement planning: $10k initial + $1000/month for 10 years
iex> Finex.Investment.calculate_outcome(10000, 1000, 10, 0.08, 0.005)
{:ok, %{final_amount: Decimal.new("199011.10"), total_contributions: Decimal.new("130000.00"), total_interest: Decimal.new("69011.10"), initial_growth: Decimal.new("21113.65"), monthly_growth: Decimal.new("177897.46")}}

calculate_timeline(target, monthly, annual_yield, annual_fees \\ 0.0)

@spec calculate_timeline(amount(), amount(), rate(), rate()) ::
  {:ok, %{years: float(), months: integer()}} | {:error, atom()}

Calculate timeline to reach savings goal using monthly contributions.

Determines how long it will take to reach a target amount by saving a fixed amount each month with compound interest.

Parameters

  • target - Target savings/investment amount
  • monthly - Monthly contribution amount
  • annual_yield - Expected annual return before fees
  • annual_fees - Annual fees and expenses (default: 0)

Examples

# Emergency fund: How long to save $10k at $500/month with 5% yield?
iex> Finex.Investment.calculate_timeline(10_000, 500, 0.05, 0.0)
{:ok, %{years: 1.6, months: 19.25}}

# House down payment: $60k target, $1200/month, 4% yield, 0.5% fees
iex> Finex.Investment.calculate_timeline(60_000, 1200, 0.04, 0.005)
{:ok, %{years: 3.9, months: 46.74}}

# Retirement contribution: Max out 401k ($23k) at $1917/month
iex> Finex.Investment.calculate_timeline(23_000, 1917, 0.07, 0.01)
{:ok, %{years: 0.97, months: 11.68}}

calculate_timeline_lump_sum(target, initial, annual_yield, annual_fees \\ 0.0)

@spec calculate_timeline_lump_sum(amount(), amount(), rate(), rate()) ::
  {:ok, %{years: float(), months: integer()}} | {:error, atom()}

Calculate timeline for lump sum investment to grow to target.

Determines how long it will take for an initial investment to grow to a target amount through compound interest alone (no additional contributions).

Parameters

  • target - Target investment amount
  • initial - Initial lump sum investment
  • annual_yield - Expected annual return before fees
  • annual_fees - Annual fees and expenses (default: 0)

Examples

# Investment doubling: How long for $5k to grow to $10k at 7% yield?
iex> Finex.Investment.calculate_timeline_lump_sum(10_000, 5_000, 0.07, 0.0)
{:ok, %{years: 10.0, months: 120}}

# Portfolio growth: $50k to $100k with 6% yield and 1% fees
iex> Finex.Investment.calculate_timeline_lump_sum(100_000, 50_000, 0.06, 0.01)
{:ok, %{years: 13.9, months: 167}}

feasibility_analysis(monthly_income, target, initial, years, annual_yield, annual_fees \\ 0.0)

@spec feasibility_analysis(amount(), amount(), amount(), number(), rate(), rate()) ::
  {:ok,
   %{
     required_monthly: Decimal.t(),
     income_percentage: float(),
     difficulty: atom(),
     recommendation: String.t()
   }}
  | {:error, atom()}

Analyze investment goal feasibility given income constraints.

Evaluates whether an investment goal is realistic based on required monthly contributions as a percentage of take-home income.

Parameters

  • monthly_income - Monthly take-home income
  • target - Investment goal amount
  • initial - Initial investment amount
  • years - Timeline to achieve goal in years
  • annual_yield - Expected annual return before fees
  • annual_fees - Annual fees and expenses (default: 0)

Difficulty Levels

  • Easy (≤10% of income): Very achievable goal
  • Moderate (11-20% of income): Reasonable with good budgeting
  • Challenging (21-35% of income): Requires significant commitment
  • Difficult (36-50% of income): Consider extending timeline
  • Unrealistic (>50% of income): Major lifestyle changes needed

Examples

# House down payment feasibility: $5k income, need $60k in 5 years
iex> Finex.Investment.feasibility_analysis(5000, 60_000, 10_000, 5, 0.06, 0.01)
{:ok, %{
  required_monthly: Decimal.new("693.70"),
  income_percentage: 13.87,
  difficulty: :moderate,
  recommendation: "Reasonable goal with good budgeting"
}}

# Aggressive savings goal: $3k income, need $100k in 5 years
iex> Finex.Investment.feasibility_analysis(3000, 100_000, 0, 5, 0.07, 0.01)
{:ok, %{
  required_monthly: Decimal.new("1433.49"),
  income_percentage: 47.78,
  difficulty: :difficult,
  recommendation: "Consider extending timeline or reducing target"
}}

future_value_with_inflation(amount_today, years, inflation_rate)

@spec future_value_with_inflation(amount(), number(), rate()) ::
  {:ok,
   %{
     future_nominal_value: Decimal.t(),
     purchasing_power: Decimal.t(),
     purchasing_power_loss: Decimal.t(),
     purchasing_power_percentage: float()
   }}
  | {:error, atom()}

Calculate future purchasing power accounting for inflation.

Shows what an amount today will be worth in the future when considering the erosive effects of inflation on purchasing power.

Parameters

  • amount_today - Current amount/value
  • years - Number of years in the future
  • inflation_rate - Annual inflation rate (as decimal, e.g., 0.03 for 3%)

Examples

# What is $1M today worth after 4 years with 3% inflation?
iex> Finex.Investment.future_value_with_inflation(1_000_000, 4, 0.03)
{:ok, %{
  future_nominal_value: Decimal.new("1000000.00"),
  purchasing_power: Decimal.new("888487.05"),
  purchasing_power_loss: Decimal.new("111512.95"),
  purchasing_power_percentage: 88.85
}}

# Retirement planning: $50k today vs 25 years from now with 2.5% inflation
iex> Finex.Investment.future_value_with_inflation(50_000, 25, 0.025)
{:ok, %{
  future_nominal_value: Decimal.new("50000.00"),
  purchasing_power: Decimal.new("26969.53"),
  purchasing_power_loss: Decimal.new("23030.47"),
  purchasing_power_percentage: 53.94
}}

# Education costs: $30k today vs 18 years from now with 4% education inflation
iex> Finex.Investment.future_value_with_inflation(30_000, 18, 0.04)
{:ok, %{future_nominal_value: Decimal.new("30000.00"), purchasing_power: Decimal.new("14808.84"), purchasing_power_loss: Decimal.new("15191.16"), purchasing_power_percentage: 49.36}}

months_to_inflation_adjusted_goal(present_goal, monthly_contribution, inflation_rate, annual_yield, annual_fees \\ 0.0)

@spec months_to_inflation_adjusted_goal(amount(), amount(), rate(), rate(), rate()) ::
  {:ok, %{years: float(), months: float()}} | {:error, atom()}

Calculate timeline to reach inflation-adjusted savings goal.

Determines how long it will take to save for a goal whose cost increases with inflation over time. Unlike calculate_timeline/4, this function accounts for the target growing due to inflation while you're saving toward it.

Real-World Use Cases

  • House prices rising with real estate inflation
  • College tuition costs increasing over time
  • Retirement needs adjusted for cost-of-living increases
  • Major purchases with price appreciation

Parameters

  • present_goal - Cost of the goal in today's purchasing power
  • monthly_contribution - Fixed monthly savings amount
  • inflation_rate - Annual inflation rate for the goal
  • annual_yield - Expected annual return before fees
  • annual_fees - Annual fees and expenses (default: 0)

Examples

# House down payment: $60k today, but housing inflates at 4% annually
iex> Finex.Investment.months_to_inflation_adjusted_goal(60_000, 1200, 0.04, 0.07, 0.01)
{:ok, %{years: 4.34, months: 52.05}}

# College tuition: $50k today, education inflates at 6% annually
iex> Finex.Investment.months_to_inflation_adjusted_goal(50_000, 800, 0.06, 0.06, 0.005)
{:ok, %{years: 6.31, months: 75.72}}

# Retirement lifestyle: $1M today purchasing power, 3% inflation, no fees
iex> Finex.Investment.months_to_inflation_adjusted_goal(1_000_000, 2000, 0.03, 0.08)
{:ok, %{years: 26.55, months: 318.62}}

progress_percentage(current, target)

@spec progress_percentage(amount(), amount()) :: {:ok, float()} | {:error, atom()}

Calculate progress percentage toward investment goal.

Simple calculation to track how close you are to reaching your target amount.

Parameters

  • current - Current investment/savings value
  • target - Target investment amount

Examples

iex> Finex.Investment.progress_percentage(7_500, 10_000)
{:ok, 75.0}

iex> Finex.Investment.progress_percentage(12_000, 10_000)
{:ok, 120.0}

iex> Finex.Investment.progress_percentage(0, 50_000)
{:ok, 0.0}

required_monthly_contribution(target, initial, years, annual_yield, annual_fees \\ 0.0)

@spec required_monthly_contribution(amount(), amount(), number(), rate(), rate()) ::
  {:ok, Decimal.t()} | {:error, atom()}

Calculate required monthly contribution to reach investment goal.

Determines the monthly amount needed to reach a target, given an initial investment, time period, and expected returns.

Parameters

  • target - Target investment amount
  • initial - Initial investment amount
  • years - Investment period in years
  • annual_yield - Expected annual return before fees
  • annual_fees - Annual fees and expenses (default: 0)

Examples

# House down payment: Need $60k in 5 years, starting with $5k
iex> Finex.Investment.required_monthly_contribution(60_000, 5_000, 5, 0.06, 0.01)
{:ok, Decimal.new("788.04")}

# Retirement: Need $1M in 30 years, starting with $10k
iex> Finex.Investment.required_monthly_contribution(1_000_000, 10_000, 30, 0.08, 0.005)
{:ok, Decimal.new("672.74")}

# Education fund: Need $100k in 18 years, no initial amount
iex> Finex.Investment.required_monthly_contribution(100_000, 0, 18, 0.07, 0.01)
{:ok, Decimal.new("258.32")}