diff --git a/__init__.py b/__init__.py new file mode 100644 index 0000000..39e5e33 --- /dev/null +++ b/__init__.py @@ -0,0 +1,115 @@ +import numpy as np +from multipolyfit import multipolyfit as mpf + +GROSS_RENT_YIELD: float = 0.03686 +RISK_POOL_ALLOCATION: float = 0.01 +LOSS_SEVERITY: float = 0.19 +RECOVERY_RATE: float = 0.9 + + +def get_default_risk_by_fico(consumer_fico: int, loan_to_value: float) -> float: + # remember that the credit score is the first variable and the ltv is the second + initial_fico_ltv_risks = [ + [620, 0.01], + [620, 0.70], + [620, 0.85], + [620, 0.90], + [620, 0.95], + [660, 0.01], + [660, 0.70], + [660, 0.85], + [660, 0.90], + [660, 0.95], + [700, 0.01], + [700, 0.70], + [700, 0.85], + [700, 0.90], + [700, 0.95], + [740, 0.01], + [740, 0.70], + [740, 0.85], + [740, 0.90], + [740, 0.95] + ] + + default_rates_by_credit_score = { + 620: 0.0303, + 660: 0.0201, + 700: 0.0150, + 740: 0.0094 + } + risk_factors_by_credit_score = { + 620: [0.20, 0.61, 1.22, 1.48, 1.80], + 660: [0.20, 0.62, 1.22, 1.48, 1.82], + 700: [0.20, 0.62, 1.22, 1.49, 1.83], + 740: [0.20, 0.63, 1.21, 1.47, 1.81] + } + + # We should now fill out the table of default rates with the LTV risk factors included + initial_risk_factors_by_ltv_credit_score = [] + for fico in risk_factors_by_credit_score: + initial_risk_factors_by_ltv_credit_score += list(np.multiply(default_rates_by_credit_score[fico], + risk_factors_by_credit_score[fico])) + + # Compute a line of best fit + lobf_coefficients = mpf(initial_fico_ltv_risks, initial_risk_factors_by_ltv_credit_score, 1) + + # the first coeffient is a constant offset, the second is the credit score factor, and the third is the ltv factor + const_offset = lobf_coefficients[0] + consumer_fico_factor = (lobf_coefficients[1] * consumer_fico) + loan_to_value_factor = (lobf_coefficients[2] * loan_to_value) + # now we just sum these up to get the result + result = consumer_fico_factor + loan_to_value_factor + const_offset + return result + +def get_risk_pool_health() -> float: + return 1.0 + + +def compute_mre(home_value: float, + down_payment: float, + consumer_fico: int) -> float: + + investor_value = home_value - down_payment + loan_to_value = float(investor_value/home_value) + # the monthly payment is made on the value from the investors + monthly_payment = investor_value * (GROSS_RENT_YIELD) / 12.0 + # how much is at risk if the occupant "defaults" + at_risk_value = home_value * LOSS_SEVERITY + # how much is expected to be recovered? + recovery_value = at_risk_value * RECOVERY_RATE + # get the default rate with the risk-factors dealt with + default_rate = get_default_risk_by_fico(consumer_fico, loan_to_value) + # get the risk pool allocation + risk_pool_allocation = RISK_POOL_ALLOCATION * home_value + # we should add the 4 month buffer that effectively halves the default rate, + # this is already included in the get_default_risk_by_fico method. + income_interruption_buffer = 4.0 * monthly_payment + default_rate = get_default_risk_by_fico(consumer_fico, loan_to_value) + # the expected loss to the risk pool + default_rate_risk_pool_loss = default_rate * risk_pool_allocation + # adjust the risk pool loss by the risk pool's health + risk_pool_factor = get_risk_pool_health() * default_rate_risk_pool_loss + # since we don't actually lose anything in the risk pool, it does not + # get counted toward the loss + + + + at_risk_value -= risk_pool_factor + # start putting together the pieces + mre = income_interruption_buffer + mre += at_risk_value - recovery_value + # make the mre a percentage of the home value + mre /= home_value + return mre + + + + +#if __name__ == '__main__': +# print('Computing risk factor for consumer with 660 FICO and 70% LTV') +# print(f'Deault Rate: {get_default_risk_by_fico(660, 0.7)}\n') +# print('Comuting MRE for 742,500 home with 2.5% down payment and a 680 fico') +# print(f' MRE: {compute_mre(742500.0, 0.025*742500.0, 680)}') + + diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..dcda92e --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +multipolyfit==0.0.1 +numpy==2.2.4