property.mortgage-affordability@1.0.1
impl/python.py
2,344 bytes · the Python implementation · view raw
Imports name this capability’s declared dependencies, which fune builds next to it in your project; each one links to its page.
from .lending_affordability import affordability ← from lending.affordability ^1.0.0 · built alongside by fune
from .math_round_div import round_div ← from math.round-div ^1.0.0 · built alongside by fune
from .money_amount import Money, money ← from money.amount ^1.0.0 · built alongside by fune
from .property_mortgage_affordability_types import MortgageAffordability
_MAX_INCOME = 10_000_000_000
_MAX_MULTIPLE = 200_000
def mortgage_affordability(
annual_income: Money,
monthly_commitments: Money,
loan: Money,
annual_rate_basis_points: int,
stress_rate_basis_points: int,
term_months: int,
max_income_multiple_basis_points: int,
max_debt_to_income_basis_points: int,
) -> MortgageAffordability:
"""Loan-to-income against the lender's multiple, and the stressed
repayment against income via lending.affordability. Every rounding goes
against the borrower, and the multiple comparison itself is exact."""
if loan.currency != annual_income.currency:
raise ValueError("currency mismatch: %s and %s" % (annual_income.currency, loan.currency))
if annual_income.minor < 12 or annual_income.minor > _MAX_INCOME:
raise ValueError(
"annualIncome must be between 12 and %d minor units, received %r" % (_MAX_INCOME, annual_income.minor)
)
if loan.minor <= 0 or loan.minor > _MAX_INCOME * 20:
raise ValueError("loan must be between 1 and %d minor units, received %r" % (_MAX_INCOME * 20, loan.minor))
m = max_income_multiple_basis_points
if isinstance(m, bool) or not isinstance(m, int) or m < 1 or m > _MAX_MULTIPLE:
raise ValueError("maxIncomeMultipleBasisPoints must be between 1 and %d, received %r" % (_MAX_MULTIPLE, m))
currency = annual_income.currency
monthly_income = money(annual_income.minor // 12, currency)
repayment = affordability(
monthly_income,
monthly_commitments,
loan,
annual_rate_basis_points,
stress_rate_basis_points,
term_months,
max_debt_to_income_basis_points,
)
within = loan.minor * 10000 <= annual_income.minor * m
return MortgageAffordability(
income_multiple_basis_points=round_div(loan.minor * 10000, annual_income.minor, "up"),
max_loan_by_multiple=money(round_div(annual_income.minor * m, 10000, "down"), currency),
within_multiple=within,
monthly_income=monthly_income,
repayment=repayment,
affordable=within and repayment.affordable,
)