192 lines
8.2 KiB
Python
192 lines
8.2 KiB
Python
# calc.py
|
|
from datetime import datetime, timedelta
|
|
|
|
def add_annotation(finance, dt, amt, text):
|
|
tm = dt.timestamp() * 1000
|
|
finance['annotations'].append( { 'label': text, 'x': tm, 'y': amt } )
|
|
return
|
|
|
|
def calculate_savings_depletion(finance):
|
|
# Extract all the financial data from the database
|
|
D_Salary = finance['D_Salary']
|
|
D_Num_fortnights_pay = finance['D_Num_fortnights_pay']
|
|
School_Fees = finance['School_Fees']
|
|
Car_loan_via_pay = finance['Car_loan_via_pay']
|
|
Car_loan = finance['Car_loan']
|
|
Car_balloon = finance['Car_balloon']
|
|
Living_Expenses = finance['Living_Expenses']
|
|
Savings = finance['Savings']
|
|
Interest_Rate = finance['Interest_Rate']
|
|
Inflation = finance['Inflation']
|
|
Mich_present = finance['Mich_present']
|
|
Overseas_trip = finance['Overseas_trip']
|
|
Mark_reno = finance['Mark_reno']
|
|
D_leave_owed_in_days = finance['D_leave_owed_in_days']
|
|
Sell_shares = finance['Sell_shares']
|
|
D_TLS_shares = finance['D_TLS_shares']
|
|
M_TLS_shares = finance['M_TLS_shares']
|
|
D_CBA_shares = finance['D_CBA_shares']
|
|
TLS_price = finance['TLS_price']
|
|
CBA_price = finance['CBA_price']
|
|
|
|
# leave in days, 10 business days to a fortnight,
|
|
# paid before tax I earn $7830.42 / fortnight. Tax on that will be at 37% or $4933.16 after tax
|
|
# if we could stretch this to July 2026, then would be more (due to less tax)
|
|
after_tax_extra_leave_per_fortnight = 4933.16
|
|
D_leave_after_tax = (D_leave_owed_in_days/10) * after_tax_extra_leave_per_fortnight;
|
|
|
|
# Constants for interest calculations
|
|
annual_interest_rate = Interest_Rate / 100.0
|
|
daily_interest_rate = annual_interest_rate / 365
|
|
|
|
# Time periods: start from now, and simulate till D is 65 (April 25)
|
|
current_date = datetime.now()
|
|
end_date = datetime(2031, 4, 15)
|
|
|
|
# Fortnightly pay
|
|
car_loan_via_pay = Car_loan_via_pay # Fortnightly payment while income is paid
|
|
regular_car_loan = Car_loan # Fortnightly payment after salary ends
|
|
|
|
# Calculate daily living expenses
|
|
daily_living_expenses = Living_Expenses / 365
|
|
|
|
# take a stab at future rego and insurance on the Ioniq 6 when we finish the lease - paid every anniversary of the Car balloon payment date
|
|
post_lease_car_costs = 800 + 2000
|
|
|
|
# Start the calculation
|
|
current_savings = Savings
|
|
depletion_date = None
|
|
savings_per_fortnight = []
|
|
|
|
# significant dates that are non-changeable
|
|
school_fees_date = datetime(2025, 12, 5)
|
|
car_balloon_date = datetime(2026, 11, 15)
|
|
mich_present_date = datetime(2026,10,15)
|
|
|
|
# significant dates - but who knows when? :)
|
|
overseas_trip_date = datetime.strptime( finance['Overseas_trip_date'], "%Y-%m-%d")
|
|
mark_reno_date = datetime.strptime( finance['Mark_reno_date'], "%Y-%m-%d")
|
|
|
|
# to force deakin pay cycles to match reality, we work from the 8th of Jan as our "day-zero" so we are paid on the 8/1/25, 22/1/25, etc.
|
|
days_count = ( current_date - datetime(2025,1,1) ).days
|
|
|
|
# Track the fortnight, and monthly interest
|
|
fortnight_income = 0
|
|
monthly_interest = 0
|
|
|
|
# Create an empty dict to store annotations to display in the GUI
|
|
# (key is date, text is for larger spend items by hand)
|
|
finance['annotations']=[]
|
|
|
|
while current_date <= end_date:
|
|
#paid on 8th or 22nd of Jan (so 8th day of fortnight)
|
|
is_fortnight = (days_count % 14 == 7)
|
|
is_end_of_month = (current_date.day == 1)
|
|
|
|
# Subtract daily living expenses
|
|
current_savings -= daily_living_expenses
|
|
|
|
# Calculate daily interest but apply at the end of the month
|
|
monthly_interest += current_savings * daily_interest_rate
|
|
|
|
# Apply fortnightly salary and handle car loan deduction
|
|
if is_fortnight:
|
|
if D_Num_fortnights_pay > 0:
|
|
fortnight_income += D_Salary
|
|
D_Num_fortnights_pay -= 1
|
|
|
|
if D_Num_fortnights_pay == 0 and D_leave_after_tax > 0:
|
|
print(f"D has resigned {current_date}: get paid out my 9 weeks leave and lose 45% to tax - ${D_leave_after_tax}" )
|
|
current_savings += D_leave_after_tax
|
|
D_leave_after_tax = 0
|
|
|
|
if fortnight_income:
|
|
print(f"salary paid by Deakin: {current_date} adding: {fortnight_income}" )
|
|
current_savings += fortnight_income
|
|
fortnight_income = 0 # reset for next fortnight
|
|
|
|
# keep paying car off until the end of the car loan
|
|
if current_date < car_balloon_date:
|
|
if D_Num_fortnights_pay > 0:
|
|
current_savings -= car_loan_via_pay
|
|
else:
|
|
current_savings -= regular_car_loan
|
|
|
|
savings_per_fortnight.append((current_date.strftime("%Y-%m-%d"), round(current_savings, 2)))
|
|
|
|
if is_end_of_month:
|
|
current_savings += monthly_interest
|
|
#print(f"interest paid {current_date}: ${monthly_interest}")
|
|
monthly_interest = 0
|
|
# monthly increase living expenses by a monthly inflation multiplier
|
|
Living_Expenses += (Inflation/100.0)/12 * Living_Expenses
|
|
daily_living_expenses = Living_Expenses / 365
|
|
#print(f"Living Exp inceased {current_date}: ${Living_Expenses}")
|
|
|
|
if current_date.date() == school_fees_date.date():
|
|
current_savings -= School_Fees
|
|
add_annotation(finance, current_date, current_savings, f"Pay School Fees: ${School_Fees}")
|
|
|
|
if current_date.date() == car_balloon_date.date():
|
|
current_savings -= Car_balloon
|
|
add_annotation(finance, current_date, current_savings, f"car balloon paid: ${Car_balloon}" )
|
|
|
|
# Anniversary of Car balloon so pay insurance/rego
|
|
if current_date.year >= car_balloon_date.year and current_date.month == car_balloon_date.month and current_date.day == car_balloon_date.day:
|
|
current_savings -= post_lease_car_costs
|
|
add_annotation(finance, current_date, current_savings, f"IONIQ 6 ins/rego: ${post_lease_car_costs}" )
|
|
|
|
if current_date.date() == overseas_trip_date.date():
|
|
current_savings -= Overseas_trip
|
|
add_annotation(finance, current_date, current_savings, f"Overseas trip: ${Overseas_trip}")
|
|
|
|
if current_date.date() == mich_present_date.date():
|
|
current_savings -= Mich_present
|
|
add_annotation(finance, current_date, current_savings, f"Michelle's present: ${Mich_present}")
|
|
|
|
if current_date.date() == mark_reno_date.date():
|
|
current_savings -= Mark_reno
|
|
add_annotation(finance, current_date, current_savings, f"Mark/reno costs: ${Mark_reno}")
|
|
|
|
if current_savings < 0:
|
|
depletion_date = current_date
|
|
break
|
|
|
|
# twice a year, CBA has a dividend of $2-2.5 DRP gives back around 20ish shares twice a year, estimate this...
|
|
if current_date.day == 1 and (current_date.month == 4 or current_date.month == 10):
|
|
drp = int( (2.25*D_CBA_shares/CBA_price) )
|
|
print( f"DRP {current_date} - adding {drp} CBA shares" )
|
|
D_CBA_shares += int( (2.25*D_CBA_shares/CBA_price) )
|
|
|
|
if Sell_shares>0 and current_date.month == 7 and current_date.day == 1:
|
|
# 2024 Govt. value
|
|
tax_threshold = 18200
|
|
can_sell = 2*tax_threshold
|
|
actual_sell = 0
|
|
# sell off TLS first - and they are way under the limit, so just sell them all in one hit
|
|
if D_TLS_shares > 0:
|
|
actual_sell += TLS_price*D_TLS_shares
|
|
D_TLS_shares = 0
|
|
if M_TLS_shares > 0:
|
|
actual_sell += TLS_price*M_TLS_shares
|
|
M_TLS_shares = 0
|
|
|
|
while actual_sell + CBA_price < can_sell and D_CBA_shares > 0:
|
|
actual_sell += CBA_price
|
|
D_CBA_shares -= 1
|
|
Sell_shares -= 1
|
|
|
|
current_savings += actual_sell
|
|
add_annotation(finance, current_date, current_savings, f"Selling shares: ${int(actual_sell)}" )
|
|
|
|
|
|
current_date += timedelta(days=1)
|
|
days_count += 1
|
|
|
|
finance['CBA']=D_CBA_shares
|
|
finance['TLS']=D_TLS_shares+M_TLS_shares
|
|
|
|
|
|
return depletion_date, savings_per_fortnight, current_savings
|
|
|