Created
October 11, 2022 04:26
-
-
Save hamidzr/09725baff31938ad4b4684dd11da5783 to your computer and use it in GitHub Desktop.
car cost calculator. Why you neeeed that sweet new ride, numbers edition.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
import numpy_financial as npf | |
import numpy as np | |
import typing as t | |
import json | |
""" | |
TODO: | |
- opportunity cost calc | |
""" | |
# utilities start | |
# number type union of int or float | |
Number = t.Union[int, float] | |
def serialize_number(n: Number): | |
if isinstance(n, float): | |
if n % 1 == 0: | |
return str(int(n)) | |
else: | |
return str(round(n, 3)) | |
else: | |
return str(n) | |
# print as formatted json | |
def print_as_json(d: dict): | |
print(json.dumps(d, indent=4, sort_keys=True)) | |
# utilities end | |
fixed_vars = { | |
'interest_rate': 0.03, # 0.025, | |
'loan_term': 3 * 12, # months | |
'sales_tax_rate': 0.095, | |
'registration_rate': 0.01, | |
'keep_for': 5, # years | |
'usage': 5000, # miles per year. 20000/4 = 5000 | |
'fuel_cost': 5.3, # dollars per gallon | |
'down_payment': 15000, | |
} | |
vars = { # car A | |
**fixed_vars, | |
'car_value': 87000, | |
'residual_value_rate': { | |
1: 0.96, | |
2: 0.92, | |
3: 0.87, | |
4: 0.85, | |
5: 0.84, | |
}, | |
'maintenance_cost': 400, # per year | |
'insurance_yearly': 2400, | |
'mpg': 18, # miles per gallon | |
} | |
# vars = { # miata. base case | |
# **fixed_vars, | |
# 'car_value': 30000, | |
# # 'down_payment': 0, | |
# 'residual_value_rate': { | |
# 1: 0.94, | |
# 2: 0.91, | |
# 3: 0.91, | |
# 4: 0.87, | |
# 5: 0.82, | |
# }, | |
# 'maintenance_cost': 200, # per year | |
# 'insurance_yearly': 1200, | |
# 'mpg': 27, # miles per gallon | |
# } | |
def monthly_loan_payment(loan_value, interest_rate, loan_term): # CHECK | |
return (interest_rate/12) * (1/(1-(1+interest_rate/12)**(-loan_term)))*loan_value | |
def principal_schedule(month, loan_value, interest_rate, loan_term): | |
return npf.ppmt(interest_rate/12, np.arange(1*month)+1, loan_term, loan_value) | |
# principal amount paid by month `month` | |
def principal_at(month, loan_value, interest_rate, loan_term): | |
if month >= loan_term: | |
month = loan_term | |
return -1 * float(np.sum(principal_schedule(month, loan_value, interest_rate, loan_term))) | |
def interest_schedule(month, loan_value, interest_rate, loan_term): | |
return npf.ipmt(interest_rate/12, np.arange(1*month)+1, loan_term, loan_value) | |
# interest amount paid by month `month` | |
def interest_at(month, loan_value, interest_rate, loan_term): | |
if month >= loan_term: | |
month = loan_term | |
interests = interest_schedule(month, loan_value, interest_rate, loan_term) | |
return -1 * float(np.sum(interests)) | |
tax = vars['car_value'] * vars['sales_tax_rate'] | |
loan_value = vars['car_value'] + tax - vars['down_payment'] | |
monthly_payment = monthly_loan_payment(loan_value, vars['interest_rate'], vars['loan_term']) | |
# compute vars after a keeping the car for `keep_for` years | |
# how much we can sell the car for | |
sale_price = vars['car_value'] * vars['residual_value_rate'][vars['keep_for']] | |
# how much of the original loan we've paid off that's applied to the principal | |
principal_paid = principal_at(vars['keep_for'] * 12, loan_value, vars['interest_rate'], vars['loan_term']) | |
# the amount of payments that has gone to interest | |
interest_paid = interest_at(vars['keep_for'] * 12, loan_value, vars['interest_rate'], vars['loan_term']) | |
# the cost of registering the car | |
registration_paid = vars['car_value'] * vars['registration_rate'] * vars['keep_for'] | |
# insurance cost | |
insurance_paid = vars['insurance_yearly'] * vars['keep_for'] | |
# gas cost | |
gas_cost = (vars['usage'] / vars['mpg']) * vars['fuel_cost'] * vars['keep_for'] | |
# maintenance cost | |
maintenance_cost = vars['maintenance_cost'] * vars['keep_for'] | |
loan_payments = monthly_payment * min(vars['keep_for'] * 12, vars['loan_term']) | |
# effective loan rate. at the end of the 'keep_for' period what percentage of the principal did you | |
# pas as interest. | |
effective_rate = interest_paid / principal_paid | |
remaining_principal = loan_value - principal_paid | |
loan_termination_cost = loan_value-principal_paid | |
overall_cost = vars['down_payment'] + loan_termination_cost + loan_payments + registration_paid + insurance_paid + gas_cost + maintenance_cost | |
# overall financial change after the car is sold | |
net_balance = sale_price - overall_cost | |
computed_vars = { | |
'loan_value': loan_value, | |
'monthly_payment': monthly_payment, | |
'expected_sale_price': sale_price, | |
'effective_rate': effective_rate, | |
'sale_price': sale_price, | |
'overall_paid': overall_cost, | |
'costs': { | |
'total_tax': tax, | |
'insurance_paid': insurance_paid, | |
'registration_paid': registration_paid, | |
'interest_paid': interest_paid, | |
'depreciation': vars['car_value'] - sale_price, | |
'gas_cost': gas_cost, | |
'maintenance_cost': maintenance_cost, | |
'net_balance': net_balance, | |
'monthly_change': net_balance / (vars['keep_for'] * 12), | |
'monthly_state_tax': tax / (vars['keep_for'] * 12), | |
}, | |
# other | |
'loan_payments': loan_payments, | |
'principal_paid': principal_paid, | |
'loan_termination_cost': loan_termination_cost, | |
} | |
output = {'inputs': vars, 'computed': computed_vars} | |
# check if yaml is installed | |
try: | |
import yaml | |
def float_representer(dumper, value): | |
text = '{0:.2f}'.format(value) | |
return dumper.represent_scalar(u'tag:yaml.org,2002:float', text) | |
yaml.add_representer(float, float_representer) | |
print(yaml.dump(output)) | |
except ImportError: | |
print_as_json(output) | |
# print('diff', 930-370) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
sample output: