Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Updated Financials #9

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions brownian_motion.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

# function is default set to have time horizon of 40 years with monthly step size
# Returns numpy array
def simulate_brownian_motion(initial, time=40, steps=480, mu=0.1, sigma=0.05):
def simulate_brownian_motion(initial, mu, sigma, time=40, steps=480):

# essentially just returns an array that represents a line graph of an initial value moving through time
# with random variations (e.g like a stock chart line)
Expand All @@ -14,5 +14,14 @@ def simulate_brownian_motion(initial, time=40, steps=480, mu=0.1, sigma=0.05):
s = initial * np.exp(x)
return s

def simulate_brownian_motion2(initial, mu, sigma, time=40, steps=480):


# essentially just returns an array that represents a line graph of an initial value moving through time
# with random variations (e.g like a stock chart line)
dt = time / steps
t = np.linspace(0, time, steps)
w = np.random.standard_normal(size=steps)
w = np.cumsum(w) * np.sqrt(dt)
x = (mu - 0.5 * sigma ** 2) * t + sigma * w
s = initial * np.exp(x)
return s
50 changes: 29 additions & 21 deletions environment.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,17 @@
from taxes import Taxes


# Probably want to make this a class to allow for multiple agents to run concurrent

class Environment:
def __init__(self):
self.owned_properties = []

self.post_tax_money = 100_000
# pre-tax money is money earned during the month that is subject to tax
self.pre_tax_money = 0
self.saved_monthly_income = 5_000 # placeholder
self.annual_net_income = 0

self.Sim = Simulation()
self.personal_finances = Taxes(100_000, 0.02, 0.3)
self.personal_finances = Taxes(100_000, 0.02, 0.3) # Cash, inflation, split

def update_environment(self, months):
# ---Updates Variables ---
Expand All @@ -29,6 +27,8 @@ def update_environment(self, months):
available_property = self.Sim.new_properties()

self.pre_tax_money += self.saved_monthly_income

self.post_tax_money = self.personal_finances.tfsa + self.personal_finances.rrsp + self.personal_finances.investing_account + self.personal_finances.cash_account
self.annual_net_income += self.saved_monthly_income

self.interest_rate = self.Sim.interest_rate[months]
Expand All @@ -37,17 +37,24 @@ def update_environment(self, months):


n_dels = 0
print("TFSA:", self.personal_finances.tfsa)
print("RRSP:", self.personal_finances.rrsp)
print("Investing Account", self.personal_finances.investing_account)
print("Cash Account", self.personal_finances.cash_account)

# Taxes
if (months + 1) % 12 == 0:
self.personal_finances.update_taxes(self.annual_net_income, 0.015, 0.3)
print(self.annual_net_income)
print(self.personal_finances.tfsa)
print(self.personal_finances.rrsp)
print(self.personal_finances.investing_account)
print(self.personal_finances.cash_account)
#self.post_tax_money = self.personal_finances.tfsa + self.personal_finances.rrsp + self.personal_finances.investing_account + self.personal_finances.cash_account
self.annual_net_income = 0
self.personal_finances.update_taxes(self.pre_tax_money, 0.015, 0.3, 1)
self.pre_tax_money = 0
self.personal_finances.accrued_net_income = 0
else:
self.personal_finances.update_taxes(self.pre_tax_money, 0.015, 0.3, 0)
self.pre_tax_money = 0
print(self.personal_finances.income_deduction)
self.personal_finances.income_deduction = 0

#self.post_tax_money = self.personal_finances.tfsa + self.personal_finances.rrsp + self.personal_finances.investing_account + self.personal_finances.cash_account


# Prints Global Simulation Attributes for User
print("Month:", months + 1, "Interest Rate: {0:.2f}%".format(self.interest_rate * 100),
Expand All @@ -56,29 +63,30 @@ def update_environment(self, months):
# Properties Owned
for i in range(len(temporary_list)):
capital_gains = 0
self.annual_net_income = self.annual_net_income + temporary_list[i].cash_flow + temporary_list[
i].monthly_principal_payments
self.pre_tax_money += temporary_list[i].cash_flow
#self.annual_net_income = self.annual_net_income + temporary_list[i].cash_flow + temporary_list[
# i].monthly_principal_payments # Previous net income + curent cash flow + principal payments are all taxable

self.pre_tax_money += temporary_list[i].cash_flow + temporary_list[i].monthly_principal_payments
self.personal_finances.income_deduction += temporary_list[i].monthly_principal_payments
print(
"Property: {0} | Price: ${1:,.2f} | Mortgage Payment: ${2:,.2f} | Principal Payment: ${3:,.2f} | Interest Payment: ${4:,.2f} | Loan Outstanding ${5:,.2f}".format(
i + 1,
temporary_list[i].price, temporary_list[i].total_monthly_payments,
temporary_list[i].monthly_principal_payments, temporary_list[i].monthly_interest_payments,
temporary_list[i].loan_outstanding))
self.post_tax_money, n_dels, self.capital_gains = decision(temporary_list[i], self.personal_finances.tfsa, self.personal_finances.rrsp, self.personal_finances.investing_account, self.personal_finances.cash_account, self.interest_rate,
self.personal_finances, n_dels, self.capital_gains, rrsp_used, investment_used = decision(temporary_list[i], self.personal_finances, self.interest_rate,
self.owned_properties, i, n_dels)

self.post_tax_money -= self.capital_gains
self.pre_tax_money += self.capital_gains

self.annual_net_income += capital_gains * 0.5
self.pre_tax_money += self.capital_gains * 0.5 + rrsp_used
#self.annual_net_income += capital_gains * 0.5

# Properties to Buy
for i in range(3):
print(
"Purchase Price: {0:0.2f}, Rental Yield: {1:0.2f}%, Expenses Rate: {2:0.2f}%, Appreciation Rate: {3:0.4f}% ".format(
available_property[i].purchase_price, available_property[i].rent_yield * 100,
available_property[i].expenses_rate * 100, available_property[i].appreciation_rate * 100 * 12))
self.post_tax_money, n_dels, self.capital_gains = decision(available_property[i], self.personal_finances.tfsa, self.personal_finances.rrsp, self.personal_finances.investing_account, self.personal_finances.cash_account, self.interest_rate,
self.personal_finances, n_dels, self.capital_gains, rrsp_used, investment_used = decision(available_property[i], self.personal_finances, self.interest_rate,
self.owned_properties, i, n_dels)


47 changes: 23 additions & 24 deletions simulation.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,13 @@ class Simulation:

# Not sure how accurate these motions with these initials will be
def __init__(self):
self.interest_rate = simulate_brownian_motion(.03)
self.inflation = simulate_brownian_motion(.02)
self.cash_appreciation = simulate_brownian_motion(.08)
# Interest rate (%)
self.interest_rate = simulate_brownian_motion(initial=0.05, mu=0, sigma=0.01)
# Inflation rate (%)
self.inflation = simulate_brownian_motion(initial=0.02, mu=0.00, sigma=0.005)
# Stock appreciation, modelled roughly after S&P 500.
# -- NOTE -- Let's add some market cycles to simulate bear + bull markets.
self.cash_appreciation = simulate_brownian_motion(initial=1, mu=0.083, sigma=0.1589)

@staticmethod
def new_properties():
Expand Down Expand Up @@ -105,9 +109,9 @@ def update_properties(owned_property_array):
i].total_monthly_payments

# Receives decision from player or agent on current property shown
def decision(property, tfsa, rrsp, investment_account, cash_account, interest_rate, owned_properties, index, n_dels):
def decision(property, financial_accounts, interest_rate, owned_properties, index, n_dels):

total_liquid_assets = tfsa + rrsp + investment_account + cash_account
total_liquid_assets = financial_accounts.tfsa + financial_accounts.rrsp + financial_accounts.investing_account + financial_accounts.cash_account

# Shows options to player
print("""
Expand All @@ -124,6 +128,8 @@ def decision(property, tfsa, rrsp, investment_account, cash_account, interest_ra

# Init Variable
capital_gains = 0
rrsp_used = 0
investment_used = 0

# --- Decision effects ---
# Mortgage, 20 year + 20% down
Expand All @@ -136,11 +142,9 @@ def decision(property, tfsa, rrsp, investment_account, cash_account, interest_ra
property.term_length = 240

# Adds new property to list of owned properties, removes down payment from cash account
total_liquid_assets = total_liquid_assets - property.purchase_price * 0.2
tfsa, rrsp, cash_account, investment_account, investment_used, rrsp_used = payment_selection(tfsa, rrsp,
cash_account,
investment_account,
property.purchase_price * 0.2)
#total_liquid_assets = total_liquid_assets - property.purchase_price * 0.2
financial_accounts, investment_used, rrsp_used = payment_selection(financial_accounts, property.purchase_price * 0.2)

owned_properties.append(property)

# Mortgage, 30 year + 20% down
Expand All @@ -153,11 +157,8 @@ def decision(property, tfsa, rrsp, investment_account, cash_account, interest_ra
property.status = 1

# Adds new property to list of owned properties, removes down payment from cash account
total_liquid_assets = total_liquid_assets - property.purchase_price * 0.2
tfsa, rrsp, cash_account, investment_account, investment_used, rrsp_used = payment_selection(tfsa, rrsp,
cash_account,
investment_account,
property.purchase_price * 0.2)
#total_liquid_assets = total_liquid_assets - property.purchase_price * 0.2
financial_accounts, investment_used, rrsp_used = payment_selection(financial_accounts, property.purchase_price * 0.2)
owned_properties.append(property)

# Bought in full, no mortgage
Expand All @@ -170,20 +171,18 @@ def decision(property, tfsa, rrsp, investment_account, cash_account, interest_ra
property.status = 1

# Adds new property to list of owned properties, removes full purchase price from cash account
total_liquid_assets = total_liquid_assets - property.purchase_price
tfsa, rrsp, cash_account, investment_account, investment_used, rrsp_used = payment_selection(tfsa, rrsp,
cash_account,
investment_account,
property.purchase_price)
#total_liquid_assets = total_liquid_assets - property.purchase_price
financial_accounts, investment_used, rrsp_used = payment_selection(financial_accounts, property.purchase_price)
owned_properties.append(property)

# Sells property
elif dec == '4' and property.status == 1:
# Cash account increased by difference between sale price and amount of debt still owing
total_liquid_assets = total_liquid_assets + property.price - property.loan_outstanding
# Adds change in property value since purchase/refinance to capital gains account
capital_gains = property.accrued_gains + property.price - property.purchase_price

# Pre-allocated cash account increased by difference between sale price and amount of debt still owing
financial_accounts.remaining_cash = financial_accounts.remaining_cash + property.price - property.loan_outstanding - capital_gains

# Future Note: return gains to main.py or taxes.

# Property removed from list of owned properties.
Expand All @@ -194,7 +193,7 @@ def decision(property, tfsa, rrsp, investment_account, cash_account, interest_ra
# Refinances property, leaves 20% of property value in as equity
elif dec == '5' and property.status == 1:
# Cash account increased by difference between property value and the sum of debt owing and 20% down payment
total_liquid_assets = total_liquid_assets + property.price - property.loan_outstanding - property.price * 0.2
financial_accounts.remaining_cash = financial_accounts.remaining_cash + property.price - property.loan_outstanding - property.price * 0.2
# Resets the property attributes, to reflect the new mortgage
property.accrued_gains = property.price - property.purchase_price # Tracks capital gains
property.purchase_price = property.price # Resets house with refinance
Expand All @@ -214,7 +213,7 @@ def decision(property, tfsa, rrsp, investment_account, cash_account, interest_ra
else:
print("Invalid Choice")
# Returns updated cash account and # of properties sold thus far in the month
return total_liquid_assets, n_dels, capital_gains
return financial_accounts, n_dels, capital_gains, rrsp_used, investment_used



Expand Down
Loading