from .lending_affordability import affordability from .math_round_div import round_div from .money_amount import Money, money 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, )