Skip to content

Financial KPIs Reference

This reference document provides detailed explanations of all financial Key Performance Indicators (KPIs) calculated by the Real Estate Investor application.

Overview

The application computes five primary financial metrics for investment properties:

  1. Net Operating Income (NOI) — Annual income minus operating expenses
  2. Capitalization Rate (Cap Rate) — Return on property value
  3. Cash-on-Cash Return — Return on cash invested
  4. Internal Rate of Return (IRR) — Time-weighted return
  5. Debt Service Coverage Ratio (DSCR) — Ability to cover debt payments

All calculations use Decimal precision for currency values to ensure accurate financial computations.

Net Operating Income (NOI)

Definition

Net Operating Income represents the annual income generated by a property minus all operating expenses, excluding debt service and capital expenditures.

Formula

NOI = (Monthly Rental Income × 12) - (Monthly Operating Expenses × 12)

Or:

NOI = Annual Gross Income - Annual Operating Expenses

Implementation

Located in investor_app/finance/utils.py:

def noi(monthly_income: Decimal, monthly_expenses: Decimal) -> Decimal:
    return to_decimal(monthly_income) * Decimal(12) - to_decimal(
        monthly_expenses
    ) * Decimal(12)

Calculation Details

  1. Monthly Income is calculated as the sum of all rental income adjusted for vacancy:

    Effective Gross Income = Monthly Rent × (1 - Vacancy Rate)
    

  2. Monthly Expenses include all operating expenses normalized to monthly amounts:

  3. Annual expenses are divided by 12
  4. Monthly expenses are used as-is

  5. Both values are annualized by multiplying by 12

Example

Property details: - Monthly rent: $2,500 - Vacancy rate: 5% (0.05) - Annual property tax: $4,200 - Annual insurance: $1,200 - Monthly maintenance: $200

Calculation:

Effective Monthly Income = $2,500 × (1 - 0.05) = $2,375
Annual Income = $2,375 × 12 = $28,500

Monthly Expenses = ($4,200/12) + ($1,200/12) + $200 = $350 + $100 + $200 = $650
Annual Expenses = $650 × 12 = $7,800

NOI = $28,500 - $7,800 = $20,700

Interpretation

  • Positive NOI: Property generates more income than operating expenses
  • Negative NOI: Property operates at a loss (before debt service)
  • Higher NOI: Better property performance

Notes

  • NOI excludes mortgage payments (debt service)
  • NOI excludes capital expenditures (major repairs, improvements)
  • NOI includes vacancy allowance through the effective gross income calculation

Capitalization Rate (Cap Rate)

Definition

The capitalization rate (cap rate) measures the rate of return on a real estate investment based on the property's net operating income.

Formula

Cap Rate = NOI ÷ Property Value (Purchase Price)

Expressed as a percentage:

Cap Rate % = (NOI ÷ Purchase Price) × 100

Implementation

Located in investor_app/finance/utils.py:

def cap_rate(annual_noi: Decimal, purchase_price: Decimal) -> Decimal:
    if to_decimal(purchase_price) == 0:
        return Decimal("0")
    return to_decimal(annual_noi) / to_decimal(purchase_price)

Calculation Details

  1. Calculate annual NOI (see above)
  2. Divide NOI by the property's purchase price
  3. Result is stored as a decimal (e.g., 0.0591 represents 5.91%)

Example

Using the previous example: - NOI: $20,700 - Purchase price: $350,000

Calculation:

Cap Rate = $20,700 ÷ $350,000 = 0.0591 or 5.91%

Interpretation

  • Higher cap rate: Better return relative to property value
  • Lower cap rate: Lower return, but potentially in a more stable/appreciating market
  • Industry benchmarks:
  • 4-6%: Low-risk, stable markets (Class A properties)
  • 6-8%: Moderate-risk markets (Class B properties)
  • 8%+: Higher-risk markets (Class C properties)

Uses

  • Compare properties in the same market
  • Estimate property value: Property Value = NOI ÷ Cap Rate
  • Assess investment opportunities

Notes

  • Cap rate does not account for financing costs
  • Does not consider property appreciation or depreciation
  • Does not factor in time value of money
  • Best used for comparing similar properties in similar markets

Cash-on-Cash Return

Definition

Cash-on-Cash return measures the annual pre-tax cash flow relative to the total cash invested in the property.

Formula

Cash-on-Cash = Annual Cash Flow ÷ Total Cash Invested

Where:

Annual Cash Flow = NOI - Annual Debt Service
Total Cash Invested = Down Payment + Closing Costs + Initial Repairs

Implementation

Located in investor_app/finance/utils.py:

def cash_on_cash(annual_cash_flow: Decimal, total_cash_invested: Decimal) -> Decimal:
    if to_decimal(total_cash_invested) == 0:
        return Decimal("0")
    return to_decimal(annual_cash_flow) / to_decimal(total_cash_invested)

Calculation Details (Current MVP)

In the current implementation: - Total Cash Invested is assumed to be the full purchase price - Annual Cash Flow is assumed to equal NOI (no debt service in MVP)

Future versions will incorporate: - Actual down payment amount - Closing costs and transaction fees - Initial repair and improvement costs - Mortgage payments (debt service)

Example

Simplified example (MVP): - Purchase price (cash invested): $350,000 - NOI (cash flow): $20,700

Calculation:

Cash-on-Cash = $20,700 ÷ $350,000 = 0.0591 or 5.91%

With financing (future): - Down payment (20%): $70,000 - Closing costs: $5,000 - Total cash invested: $75,000 - Annual mortgage payment: $15,000 - Annual cash flow: $20,700 - $15,000 = $5,700

Calculation:

Cash-on-Cash = $5,700 ÷ $75,000 = 0.076 or 7.6%

Interpretation

  • Positive return: Investment generates cash flow
  • Negative return: Investment consumes cash
  • Target benchmarks:
  • 8-12%: Good cash-on-cash return
  • 12%+: Excellent return
  • <8%: May not justify the risk

Uses

  • Evaluate leveraged vs. all-cash purchases
  • Compare different financing options
  • Assess short-term cash flow requirements

Notes

  • Unlike cap rate, cash-on-cash accounts for financing
  • Does not consider tax benefits or property appreciation
  • Focuses on actual cash returned to investor

Internal Rate of Return (IRR)

Definition

Internal Rate of Return (IRR) is the discount rate that makes the net present value (NPV) of all cash flows equal to zero. It represents the time-weighted annual return on investment.

Formula

IRR is found by solving for r in:

NPV = 0 = CF₀ + CF₁/(1+r) + CF₂/(1+r)² + ... + CFₙ/(1+r)ⁿ

Where: - CF₀ = Initial investment (negative) - CF₁...CFₙ = Cash flows in periods 1 through n - r = IRR

Implementation

Located in investor_app/finance/utils.py:

def irr(cashflows: Iterable[Decimal]) -> Decimal:
    cf = np.array([float(c) for c in cashflows], dtype=float)
    try:
        return to_decimal(npf.irr(cf))
    except Exception:
        return Decimal("0")

Uses NumPy Financial's IRR function with fallback to zero on calculation errors.

Calculation Details (Current MVP)

The current implementation uses a simplified 12-month cash flow projection:

  1. Initial outlay: -Purchase Price (month 0)
  2. Monthly cash flows: NOI ÷ 12 (months 1-12)

Example:

cashflows = [
    to_decimal(prop.purchase_price) * Decimal(-1),  # Initial investment
    annual_noi / Decimal(12),  # Month 1
    annual_noi / Decimal(12),  # Month 2
    ...
    annual_noi / Decimal(12),  # Month 12
]

Example

Using the previous property: - Purchase price: $350,000 - NOI: $20,700 - Monthly cash flow: $20,700 ÷ 12 = $1,725

Cash flows:

Month 0: -$350,000
Months 1-12: $1,725 each

The IRR calculation finds the monthly rate that makes NPV = 0, then annualizes it.

Interpretation

  • Higher IRR: Better investment return
  • IRR > Cost of Capital: Investment creates value
  • IRR < Cost of Capital: Investment destroys value
  • Target benchmarks:
  • 10-15%: Good IRR for rental properties
  • 15%+: Excellent IRR
  • <10%: May not justify risk

Uses

  • Compare investments with different time horizons
  • Evaluate investments with varying cash flow patterns
  • Consider both cash flow and capital appreciation

Notes

  • IRR assumes reinvestment of cash flows at the IRR rate
  • Multiple IRRs can exist for non-conventional cash flows
  • Does not consider investment size (use NPV for that)
  • Current MVP implementation is simplified; future versions will include:
  • Property sale at end of holding period
  • Actual debt service payments
  • Capital expenditures
  • Tax implications

Debt Service Coverage Ratio (DSCR)

Definition

Debt Service Coverage Ratio (DSCR) measures a property's ability to cover its debt obligations with its net operating income.

Formula

DSCR = NOI ÷ Annual Debt Service

Where:

Annual Debt Service = Total annual mortgage payments (principal + interest)

Implementation

Located in investor_app/finance/utils.py:

def dscr(annual_noi: Decimal, annual_debt_service: Decimal) -> Decimal:
    if to_decimal(annual_debt_service) == 0:
        return Decimal("0")
    return to_decimal(annual_noi) / to_decimal(annual_debt_service)

Calculation Details

  1. Calculate annual NOI
  2. Calculate annual debt service (12 × monthly mortgage payment)
  3. Divide NOI by debt service

Example

Property with financing: - NOI: $20,700 - Monthly mortgage payment: $1,250 - Annual debt service: $1,250 × 12 = $15,000

Calculation:

DSCR = $20,700 ÷ $15,000 = 1.38

Interpretation

  • DSCR > 1.0: Property generates sufficient income to cover debt
  • DSCR = 1.0: Property exactly covers debt (break-even)
  • DSCR < 1.0: Property cannot cover debt from operating income
  • Lender requirements:
  • 1.25+: Most lenders' minimum requirement
  • 1.35-1.50: Preferred range for investment properties
  • 2.0+: Very strong coverage

Uses

  • Assess loan qualification and risk
  • Evaluate refinancing opportunities
  • Monitor property performance over time

Notes

  • Current MVP returns 0 when debt service is 0 (all-cash purchases)
  • DSCR is crucial for financing approval
  • Lenders may use different calculation methods
  • Does not account for other expenses (taxes, insurance, capex)

Precision and Data Types

Decimal Usage

All financial calculations use Python's Decimal type for precision:

from decimal import Decimal

# Database fields use Decimal
purchase_price = models.DecimalField(max_digits=12, decimal_places=2)

# Calculations maintain Decimal precision
noi = Decimal(monthly_income) * Decimal(12)

Conversion Boundaries

  • Database ↔ Python: Use Decimal throughout
  • NumPy/NumPy-Financial: Convert Decimal to float for calculations, then back to Decimal
  • Display: Format Decimal values for user presentation
# Example: IRR calculation
cashflows_decimal = [Decimal("-350000"), Decimal("1725"), ...]
cashflows_float = [float(c) for c in cashflows_decimal]  # Convert for NumPy
result_float = npf.irr(cashflows_float)  # NumPy calculation
result_decimal = Decimal(str(result_float))  # Convert back

Quantization

Results are quantized for consistent decimal places:

# Cap rate stored with 4 decimal places (0.0591)
analysis.cap_rate = cap_rate(noi, price).quantize(Decimal("0.0001"))

# NOI stored with 2 decimal places ($20,700.00)
analysis.noi = noi_value.quantize(Decimal("0.01"))

Default Assumptions

Financial calculations use default rates from environment configuration:

# From .env.example
VACANCY_RATE=0.05         # 5% vacancy
MANAGEMENT_FEE_RATE=0.08   # 8% management fee
CAPEX_RESERVE_RATE=0.05    # 5% capital expenditure reserve

These can be overridden per property or rental income record.

Calculation Pipeline

The complete calculation flow in compute_analysis_for_property:

  1. Gather data:
  2. Fetch rental income records
  3. Fetch operating expense records

  4. Calculate monthly values:

  5. Sum effective gross income (rent × (1 - vacancy))
  6. Sum monthly operating expenses

  7. Calculate NOI:

  8. Annualize income and expenses
  9. Subtract expenses from income

  10. Calculate other metrics:

  11. Cap Rate: NOI ÷ purchase price
  12. Cash-on-Cash: cash flow ÷ cash invested
  13. DSCR: NOI ÷ debt service
  14. IRR: time-weighted return

  15. Store results:

  16. Create or update InvestmentAnalysis record
  17. Quantize all decimal values
  18. Save to database

See also:

Source Code

Financial calculation utilities: investor_app/finance/utils.py

Model definitions: core/models.py