-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #10 from gchenfc/blogPost/houseBuyingPt2
Blog post/house buying pt2
- Loading branch information
Showing
9 changed files
with
852 additions
and
4 deletions.
There are no files selected for viewing
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
<link rel="stylesheet" type="text/css" href="style.css"> | ||
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script> | ||
<script type="text/javascript" async | ||
src="https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-MML-AM_CHTML"></script> | ||
|
||
<h2>Parameters</h2> | ||
<div id="inputs"> | ||
<table id="sliders"> | ||
<tr> | ||
<td><label for="houseValue">House Value \(V\):</label></td> | ||
<td><input type="range" id="houseValue" min="100000" max="1000000" step="10000" value="500000"></td> | ||
<td>$<input type="number" id="houseValueLabel"></input></td> | ||
</tr> | ||
<tr> | ||
<td><label for="downPayment">Down Payment \(D\):</label></td> | ||
<td><input type="range" id="downPayment" min="0" max="100" value="20"></td> | ||
<td><input type="number" id="downPaymentLabel"></input>%</td> | ||
</tr> | ||
<tr> | ||
<td><label for="mortgageRate">Mortgage Interest Rate \(R_i\):</label></td> | ||
<td><input type="range" id="mortgageRate" min="0" max="10" step="0.1" value="5.5"></td> | ||
<td><input type="number" id="mortgageRateLabel"></input>%</td> | ||
</tr> | ||
<tr> | ||
<td><label for="closingPct">Closing Costs \(A\):</label></td> | ||
<td><input type="range" id="closingPct" min="0" max="10" step="0.1" value="3.5"></td> | ||
<td><input type="number" id="closingPctLabel"></input>% of House Value</td> | ||
</tr> | ||
<tr> | ||
<td><label for="maintenancePct">Maintenance Costs \(P+C\):</label></td> | ||
<td><input type="range" id="maintenancePct" min="0" max="10" step="0.1" value="1.6"></td> | ||
<td><input type="number" id="maintenancePctLabel"></input>% of House Value</td> | ||
</tr> | ||
<tr> | ||
<td><label for="annualRentPct">Annual Rent \(R_l\):</label></td> | ||
<td><input type="range" id="annualRentPct" min="0" max="20" step="0.1" value="7"></td> | ||
<td><input type="number" id="annualRentPctLabel"></input>% of House Value</td> | ||
</tr> | ||
<tr> | ||
<td><label for="realEstateAppreciation">Real Estate Appreciation Rate \(R_a\):</label></td> | ||
<td><input type="range" id="realEstateAppreciation" min="0" max="20" step="0.1" value="3"></td> | ||
<td><input type="number" id="realEstateAppreciationLabel"></input>%</td> | ||
</tr> | ||
<tr> | ||
<td><label for="investmentReturn">Investment Return Rate \(R_m\):</label></td> | ||
<td><input type="range" id="investmentReturn" min="0" max="20" step="0.1" value="5"></td> | ||
<td><input type="number" id="investmentReturnLabel"></input>%</td> | ||
</tr> | ||
</table> | ||
|
||
<!-- <table> | ||
<tr> | ||
<td><label for="houseValue">House Value \(V\):</label></td> | ||
<td>$</td> | ||
<td><input type="number" id="houseValue" value="300000"></td> | ||
<td></td> | ||
</tr> | ||
<tr> | ||
<td><label for="downPayment">Down Payment \(D\):</label></td> | ||
<td></td> | ||
<td><input type="number" id="downPayment" value="20"></td> | ||
<td>%</td> | ||
</tr> | ||
<tr> | ||
<td><label for="mortgageRate">Mortgage Interest Rate \(R_i\):</label></td> | ||
<td></td> | ||
<td><input type="number" id="mortgageRate" value="5.5"></td> | ||
<td>%</td> | ||
</tr> | ||
<tr> | ||
<td><label for="mortgageRate">Closing Costs \(A\):</label></td> | ||
<td></td> | ||
<td><input type="number" id="closingPct" value="3.5"></td> | ||
<td>% of House Value</td> | ||
</tr> | ||
<tr> | ||
<td><label for="mortgageRate">Maintenance Costs \(P+C\):</label></td> | ||
<td></td> | ||
<td><input type="number" id="maintenancePct" value="1.6"></td> | ||
<td>% of House Value</td> | ||
</tr> | ||
<tr> | ||
<td><label for="annualRent">Annual Rent \(R_l\):</label></td> | ||
<td></td> | ||
<td><input type="number" id="annualRentPct" value="7"></td> | ||
<td>% of House Value</td> | ||
</tr> | ||
<tr> | ||
<td><label for="investmentReturn">Real Estate Appreciation Rate \(R_a\):</label></td> | ||
<td></td> | ||
<td><input type="number" id="realEstateAppreciation" value="3"></td> | ||
<td>%</td> | ||
</tr> | ||
<tr> | ||
<td><label for="investmentReturn">Investment Return Rate \(R_m\):</label></td> | ||
<td></td> | ||
<td><input type="number" id="investmentReturn" value="5"></td> | ||
<td>%</td> | ||
</tr> | ||
</table> --> | ||
|
||
<!-- Side-to-side switch for cumulative vs not cumulative --> | ||
<div class="switch-div"> | ||
<label for="cumulative">Cumulative</label> | ||
<label class="switch"> | ||
<input type="checkbox" id="cumulative" checked> | ||
<span class="slider round"></span> | ||
</label> | ||
<label for="notCumulative">Running Monthly Costs (except totals)</label> | ||
</div> | ||
</div> | ||
|
||
<h2>Total Cost (Cumulative)</h2> | ||
<canvas id="costGraph"></canvas> | ||
<h2>Total Cost (Cumulative)</h2> | ||
<div id="resultsTable"></div> | ||
|
||
<script type="module" src="script.js"></script> |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
import { updateResultsTable, rows } from "./table.js"; | ||
import { updateGraph } from "./graph.js"; | ||
|
||
export function calculate() { | ||
// Getting input values | ||
const V = parseFloat(document.getElementById("houseValue").value); | ||
const D = parseFloat(document.getElementById("downPayment").value) / 100; | ||
const Ri = parseFloat(document.getElementById("mortgageRate").value) / 100; | ||
const A = parseFloat(document.getElementById("closingPct").value) / 100; | ||
const PC = parseFloat(document.getElementById("maintenancePct").value) / 100; | ||
const Rl = parseFloat(document.getElementById("annualRentPct").value) / 100; | ||
const Ra = parseFloat(document.getElementById("realEstateAppreciation").value) / 100; | ||
const Rm = parseFloat(document.getElementById("investmentReturn").value) / 100; | ||
const T = 30; | ||
|
||
// Calculations | ||
|
||
function m(ri) { | ||
return (ri * Math.pow(1 + ri, 360)) / (Math.pow(1 + ri, 360) - 1); | ||
} | ||
function p(M, ri) { | ||
return ( | ||
Math.pow(1 + ri, M) - | ||
((Math.pow(1 + ri, M) - 1) / (Math.pow(1 + ri, 360) - 1)) * Math.pow(1 + ri, 360) | ||
); | ||
} | ||
function OwnCosts(M) { | ||
const T = M / 12; | ||
|
||
const downPayment = V * D; | ||
const closingCosts = V * A; | ||
const principle = V * (1 - D); | ||
|
||
const mortgageMonthlyProp = m(Ri / 12); | ||
const mortgageMonthly = mortgageMonthlyProp * principle; | ||
const maintenanceAnnual = V * PC; | ||
|
||
const upfrontCosts = downPayment + closingCosts; | ||
const ongoingCosts = mortgageMonthly * 12 + maintenanceAnnual; | ||
|
||
const totalEquity = V * Math.pow(1 + Ra, T) * (1 - A) - p(M, Ri / 12) * principle; | ||
const totalSpent = upfrontCosts + ongoingCosts * T; | ||
|
||
const net = totalEquity - totalSpent; | ||
|
||
return { | ||
upfrontCosts, | ||
ongoingCosts, | ||
totalEquity, | ||
totalSpent, | ||
net, | ||
}; | ||
} | ||
|
||
function RentCosts(M) { | ||
const T = M / 12; | ||
|
||
const rentMonthly = (V * Rl) / 12; | ||
|
||
const upfrontCosts = 0; | ||
const ongoingCosts = rentMonthly * 12; | ||
|
||
const totalEquity = 0; | ||
const totalSpent = upfrontCosts + ongoingCosts * T; | ||
|
||
const net = totalEquity - totalSpent; | ||
|
||
return { | ||
upfrontCosts, | ||
ongoingCosts, | ||
totalEquity, | ||
totalSpent, | ||
net, | ||
}; | ||
} | ||
|
||
function addInvestmentReturn(M) { | ||
let own = 0, | ||
ownSpend = 0; | ||
let rent = 0, | ||
rentSpend = 0; | ||
const costAtI = (obj, i) => (i == 0 ? obj.upfrontCosts : obj.ongoingCosts / 12); | ||
for (let i = 0; i <= M; i++) { | ||
const own1 = costAtI(OwnCosts(i), i); | ||
const rent1 = costAtI(RentCosts(i), i); | ||
ownSpend += Math.max(own1, rent1) - own1; | ||
rentSpend += Math.max(own1, rent1) - rent1; | ||
own += (Math.max(own1, rent1) - own1) * Math.pow(1 + Rm, (M - i) / 12); | ||
rent += (Math.max(own1, rent1) - rent1) * Math.pow(1 + Rm, (M - i) / 12); | ||
} | ||
return { own, rent, ownSpend, rentSpend }; | ||
} | ||
|
||
const cumulative = !document.getElementById("cumulative").checked; | ||
|
||
// Update table with results | ||
updateResultsTable(rows, OwnCosts, RentCosts, addInvestmentReturn, cumulative); | ||
|
||
// Update graph | ||
updateGraph(OwnCosts, RentCosts, addInvestmentReturn); | ||
} |
Oops, something went wrong.