118 lines
3.7 KiB
Python
118 lines
3.7 KiB
Python
import numpy as np
|
|
import matplotlib.pyplot as plt
|
|
from multipolyfit import multipolyfit as mpf
|
|
|
|
|
|
class ConsumerNotEligibleError(Exception):
|
|
def __init__(self, reason, *args):
|
|
super().__init__(args)
|
|
self.reason = reason
|
|
|
|
def __str__(self):
|
|
return f'Consumer is ineligible due to {self.reason}'
|
|
|
|
|
|
def fico_default_risk_modifier_by_lend_percent(credit_score, loan_percent):
|
|
# The initial data set is organized as [{credit_score}, {loan_percent}]
|
|
initial_data = [[620, 1],
|
|
[620, 70],
|
|
[620, 85],
|
|
[620, 90],
|
|
[620, 95],
|
|
[660, 1],
|
|
[660, 70],
|
|
[660, 85],
|
|
[660, 90],
|
|
[660, 95],
|
|
[700, 1],
|
|
[700, 70],
|
|
[700, 85],
|
|
[700, 90],
|
|
[700, 95],
|
|
[740, 1],
|
|
[740, 70],
|
|
[740, 85],
|
|
[740, 90],
|
|
[740, 95]]
|
|
# the default rates to use
|
|
def_rate_620 = 3.03
|
|
def_rate_660 = 2.01
|
|
def_rate_700 = 1.50
|
|
def_rate_740 = 0.94
|
|
# the risk factor multiples to use
|
|
risk_factor_620 = [0.20, 0.61, 1.22, 1.48, 1.80]
|
|
risk_factor_660 = [0.20, 0.62, 1.22, 1.48, 1.82]
|
|
risk_factor_700 = [0.20, 0.62, 1.22, 1.49, 1.83]
|
|
risk_factor_740 = [0.20, 0.63, 1.21, 1.47, 1.81]
|
|
|
|
net_def_risks_620 = np.multiply(def_rate_620, risk_factor_620)
|
|
net_def_risks_660 = np.multiply(def_rate_660, risk_factor_660)
|
|
net_def_risks_700 = np.multiply(def_rate_700, risk_factor_700)
|
|
net_def_risks_740 = np.multiply(def_rate_740, risk_factor_740)
|
|
|
|
initial_risk_mults = [r for r in net_def_risks_620] + [r for r in net_def_risks_660] + [r for r in net_def_risks_700] + [r for r in net_def_risks_740]
|
|
|
|
x, y = zip(*initial_data)
|
|
ax = plt.axes(projection='3d')
|
|
ax.scatter(x, y, initial_risk_mults)
|
|
|
|
coefficients = mpf(initial_data, initial_risk_mults, 1)
|
|
result = np.multiply(coefficients[1], x) + np.multiply(coefficients[2], y) + coefficients[0]
|
|
ax.plot3D(x, y, result)
|
|
ax.set_title('Credit Score/Loan % Line of Best Fit')
|
|
plt.savefig('graph.png')
|
|
|
|
return coefficients[0] + coefficients[1] * credit_score + coefficients[2] * loan_percent
|
|
|
|
|
|
def get_loss_severity():
|
|
return 0.19
|
|
|
|
|
|
def get_recovery_rate():
|
|
return 0.9
|
|
|
|
|
|
def get_risk_pool_allocation_percent():
|
|
return 0.01
|
|
|
|
|
|
def get_gross_rent_yield():
|
|
return 3.686
|
|
|
|
|
|
def compute_mre(home_value, down_payment_percent, consumer_fico):
|
|
if not 0 <= down_payment_percent < 100:
|
|
raise ValueError('Down payment percent must be contained in [0, 100)')
|
|
|
|
if consumer_fico < 620:
|
|
raise ConsumerNotEligibleError('Credit score too low (must be 620 or Greater)')
|
|
|
|
monthly_payment = home_value * get_gross_rent_yield()/100/12
|
|
|
|
income_interruption_home_percentage = 100 * (monthly_payment * 4 / home_value)
|
|
risk_pool_percent = get_risk_pool_allocation_percent()
|
|
|
|
loss_severity = get_loss_severity()
|
|
recovery_rate = get_recovery_rate()
|
|
default_rate = fico_default_risk_modifier_by_lend_percent(consumer_fico, 100 - down_payment_percent)
|
|
|
|
at_risk_value = home_value * loss_severity
|
|
|
|
def_rate_mult = 100/default_rate
|
|
risk_pool_allocation = risk_pool_percent * home_value
|
|
denom = recovery_rate
|
|
num = at_risk_value - (def_rate_mult * risk_pool_allocation)
|
|
result = num/denom
|
|
mre = result/home_value + income_interruption_home_percentage
|
|
mre += income_interruption_home_percentage
|
|
|
|
return mre
|
|
|
|
|
|
if __name__ == '__main__':
|
|
print(compute_mre(742500, 2.5, 680))
|
|
# print(fico_default_risk_modifier_by_lend_percent(620, 85))
|
|
|
|
|