404 lines
No EOL
13 KiB
HTML
404 lines
No EOL
13 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
|
|
<title>Bank of America Preferred Rewards Suck</title>
|
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
<link href="https://fonts.googleapis.com/css2?family=M+PLUS+Code+Latin&display=swap" rel="stylesheet">
|
|
<!-- If anyone is snooping around and would like to contribute a favicon, let me know :P -->
|
|
<link rel="icon" href="data:,">
|
|
|
|
<script src="https://cdn.jsdelivr.net/npm/chart.js@4/dist/chart.umd.min.js"></script>
|
|
|
|
<style>
|
|
html {
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
}
|
|
|
|
body {
|
|
font-family: 'M PLUS Code Latin', sans-serif;
|
|
background-color: #000;
|
|
max-width: 84ch;
|
|
width: 84ch;
|
|
padding: 0 2ch;
|
|
margin-top: 10vh;
|
|
color: #ccc;
|
|
font-size: 16pt;
|
|
}
|
|
|
|
a:visited {
|
|
color: #999;
|
|
}
|
|
|
|
a {
|
|
color: #ccc;
|
|
}
|
|
|
|
ul {
|
|
list-style-type: "> ";
|
|
}
|
|
|
|
.alignRight {
|
|
text-align: right;
|
|
}
|
|
|
|
table {
|
|
width: 100%;
|
|
}
|
|
|
|
.fill {
|
|
min-width: 6ch;
|
|
}
|
|
</style>
|
|
</head>
|
|
|
|
<body>
|
|
<h1>Bank of America Preferred Rewards Probably Suck</h1>
|
|
|
|
<h3>2023-04-03</h3>
|
|
|
|
<p>
|
|
Bank of America (BofA) has a rewards program that is tiered based on how
|
|
much of money you have with BofA or an associated Merrill account. There are
|
|
five tiers that they offer, with (among other things) a credit card percent
|
|
bonus:
|
|
</p>
|
|
|
|
<table>
|
|
<tr>
|
|
<th>Tier Name</th>
|
|
<th>Minimum Balance Required (USD)</th>
|
|
<th>Credit Card Bonus</th>
|
|
</tr>
|
|
<tr>
|
|
<td>Gold</td>
|
|
<td class="alignRight">20,000</td>
|
|
<td class="alignRight">25%</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Platinum</td>
|
|
<td class="alignRight">50,000</td>
|
|
<td class="alignRight">50%</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Platinum Honors</td>
|
|
<td class="alignRight">100,000</td>
|
|
<td class="alignRight">75%</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Diamond</td>
|
|
<td class="alignRight">1,000,000</td>
|
|
<td class="alignRight">75%</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Diamond Honors</td>
|
|
<td class="alignRight">10,000,000</td>
|
|
<td class="alignRight">75%</td>
|
|
</tr>
|
|
</table>
|
|
|
|
<p>
|
|
The credit card percent bonus is an additional amount of points or cash back
|
|
based on how much you original were going to get. For example, a 75% percent
|
|
bonus on a 1.5 points per dollar purchase gives you an additional 1.125
|
|
points, or an effective rate of 2.625 points back.
|
|
</p>
|
|
|
|
<p>
|
|
Preferred Rewards also comes with a interest rate booster on a savings
|
|
account, from 5% on the Gold tier to a maximum of 20% at the Platinum Honors
|
|
and above. That sounds nice, except that the base Annual Percent Yield (APY)
|
|
on these savings account as of writing this, is a whopping 0.01% APY. Not
|
|
1%. 0.01%. They're generous enough to round up, though, so Gold gets an rate
|
|
of 0.02%, Platinum Honors and higher gets an astounding 0.04%. What a steal!
|
|
</p>
|
|
|
|
<p>
|
|
High Yield Savings Accounts (HYSA) are FDIC-insured accounts that offer a
|
|
high interest rate for money in your account. Because they are a savings
|
|
account, you cannot ever lose numerical value in this account. They have a
|
|
variable APY though, so while it may have a high APY now, it might not in
|
|
the future.
|
|
</p>
|
|
|
|
<p>As of March 2023, they have an APY from anywhere of 2% to 5%.</p>
|
|
|
|
<p>
|
|
If you look at just APY alone, it's clear that if you're looking to park an
|
|
emergency fund or have short-term plans in mind, it makes absolutely no
|
|
sense to keep your money at BofA. But if you attempt to consider the credit
|
|
card bonus, it might not be as clear. After all, earning an extra percent or
|
|
two on your credit card purchasing is incredibly enticing. In reality, it
|
|
only makes sense if you have an brokerage account with Merrill and you're
|
|
happy with what Merrill offers.
|
|
</p>
|
|
|
|
<p>
|
|
Lets consider the total value that a person gets from keeping money in a
|
|
BofA savings account and getting the credit card bonus over moving to a
|
|
HYSA. We'll say that the person wants to keep it in a savings account as
|
|
they want to save this money as an emergency fund. We'll also assume that
|
|
additional points have a 100 to 1.00 USD exchange rate.
|
|
</p>
|
|
|
|
<div>
|
|
<canvas id="myChart"></canvas>
|
|
</div>
|
|
|
|
<br />
|
|
|
|
<table>
|
|
<tr>
|
|
<td><label for="saved">Savings (USD)</label></td>
|
|
<td class="alignRight fill" id="savedDisplay">25%</td>
|
|
<td><input id="saved" type="range" min="0" max="120000" step="5000" value="50000"></input></td>
|
|
</tr>
|
|
<tr>
|
|
<td><label for="hysaPercent">HYSA APY (%)</label></td>
|
|
<td class="alignRight fill" id="hysaPercentDisplay">25%</td>
|
|
<td><input id="hysaPercent" type="range" min="0" max="9" step="0.05" value="3.75"></input></td>
|
|
</tr>
|
|
<tr>
|
|
<td><label for="monthlySpending">Monthly Spending (USD)</label></td>
|
|
<td class="alignRight fill" id="monthlySpendingDisplay">25%</td>
|
|
<td><input id="monthlySpending" type="range" min="0" max="10000" step="200" value="2000"></input></td>
|
|
</tr>
|
|
<tr>
|
|
<td><label for="avgBasePoints">Avg. points gained per USD (Without preferred rewards)</label></td>
|
|
<td class="alignRight fill" id="avgBasePointsDisplay">25%</td>
|
|
<td><input id="avgBasePoints" type="range" min="0" max="5" step="0.5" value="3"></input></td>
|
|
</tr>
|
|
</table>
|
|
|
|
<p>
|
|
Playing around with the chart, you'll notice that with the bare minimum to
|
|
get the Platinum tier, generous amounts of spending on your cards, and an
|
|
HYSA APY of 0.5%, you <i>still</i> get better returns in the HYSA than
|
|
keeping money in the savings account. Even if you were to find a scenario
|
|
where you are earning more with the credit card bonus, unless you're
|
|
spending that much already (and not spending for the sake of bonus points),
|
|
it makes absolutely no sense to do so.
|
|
</p>
|
|
|
|
<h2>What about Money Market Mutual Funds?</h2>
|
|
|
|
<p>
|
|
Merrill also offers Money Market Mutual Funds (MMMFs) such as <a
|
|
href="https://www.blackrock.com/cash/en-us/products/282697/">TTTXX</a> and
|
|
offer competitive rates to a HYSA outside BofA. However, the key difference
|
|
here is that they are not FDIC-insured and run the risk of <a
|
|
href="https://www.investopedia.com/terms/b/breaking-the-buck.asp">"breaking the
|
|
buck"</a>. They are also much more sensitive to fluctuations in the
|
|
market. As a result, even the risk is miniscule, they are fundamentally
|
|
in a different risk class than a savings account.
|
|
</p>
|
|
|
|
<p>
|
|
If you think that the Preferred Rewards are valuable enough to expose your
|
|
emergency funds and/or short-term holdings to the market, then sure, it's a
|
|
way to have the best of both worlds. However, for me, I've decided that it's
|
|
not, especially with the current situation.
|
|
</p>
|
|
|
|
<h2>When does it make sense?</h2>
|
|
|
|
<p>
|
|
I think there are only a few real scenarios where keeping your money in a
|
|
BofA savings account is reasonable.
|
|
</p>
|
|
|
|
<ol>
|
|
<li>You already have a brokerage account in Merrill that meets the minimum for a tier.</li>
|
|
<li>You are willing to invest your savings/emergency fund into a Money Market Mutual Fund AND think the Preferred
|
|
Rewards are worthwhile.</li>
|
|
<li>You have less than 10k in savings AND HYSA APYs are below 0.7% AND you spent over 5k per month.</li>
|
|
</ol>
|
|
|
|
<p>
|
|
I put less than a couple hundreds of dollars on my BofA card, so there's
|
|
almost zero incentive for me to keep my money with BofA. In fact, with
|
|
inflation as large as it is, I'm losing an incredible amount of purchasing
|
|
power by keeping it in a BofA saving account.
|
|
</p>
|
|
|
|
<script>
|
|
function monthlyInterest(apy) {
|
|
return Math.pow(1 + apy, 1 / 12) - 1;
|
|
}
|
|
|
|
function rawGrowth(base, monthlyFunc) {
|
|
let data = Array(13).fill(base);
|
|
for (let i = 1; i < data.length; i++) {
|
|
data[i] = (data[i - 1] * (1 + monthlyFunc(data[i - 1]))).toFixed(2);
|
|
}
|
|
return data;
|
|
}
|
|
|
|
const PLAT_HONORS_THRESHOLD = 100_000;
|
|
const PLAT_THRESHOLD = 50_000;
|
|
const GOLD_THRESHOLD = 20_000;
|
|
|
|
|
|
function bofaInterestRateFromSavings(savings) {
|
|
if (savings >= PLAT_HONORS_THRESHOLD) {
|
|
return 0.0004;
|
|
} else if (savings >= PLAT_THRESHOLD) {
|
|
return 0.0003;
|
|
} else if (savings >= GOLD_THRESHOLD) {
|
|
return 0.0002;
|
|
} else {
|
|
return 0.0001;
|
|
}
|
|
}
|
|
|
|
function bofaAdditionalPoints(basePoints, savings) {
|
|
if (savings >= PLAT_HONORS_THRESHOLD) {
|
|
return basePoints * 0.75;
|
|
} else if (savings >= PLAT_THRESHOLD) {
|
|
return basePoints * 0.5;
|
|
} else if (savings >= GOLD_THRESHOLD) {
|
|
return basePoints * 0.25;
|
|
} else {
|
|
return basePoints;
|
|
}
|
|
}
|
|
|
|
function hysaGrowth(base, monthly) {
|
|
return rawGrowth(base, () => monthly).map(v => v - base);
|
|
}
|
|
|
|
function bofaSavingsGrowth(base) {
|
|
return rawGrowth(base, savings => bofaInterestRateFromSavings(savings)).map(v => v - base);
|
|
}
|
|
|
|
function creditCardGrowth(baseSaved, basePoints, monthlySpending) {
|
|
return bofaSavingsGrowth(baseSaved).map(growth => monthlySpending * bofaAdditionalPoints(basePoints, baseSaved + growth) / 100);
|
|
}
|
|
|
|
function bofaCombined(baseSaved, basePoints, monthlySpending) {
|
|
let savings = bofaSavingsGrowth(baseSaved);
|
|
return creditCardGrowth(baseSaved, basePoints, monthlySpending).map((v, i) => v + savings[i]);
|
|
}
|
|
|
|
function bofaGrossCombined(baseSaved, basePoints, monthlySpending) {
|
|
let savings = bofaSavingsGrowth(baseSaved);
|
|
return creditCardGrowth(baseSaved, basePoints, monthlySpending).map((v, i) => v + savings[i] - monthlySpending * i);
|
|
}
|
|
|
|
|
|
function getDatasets(saved, hysaPercent, monthlySpending, avgBasePoints) {
|
|
return [
|
|
{
|
|
label: 'HYSA',
|
|
data: hysaGrowth(saved, monthlyInterest(hysaPercent / 100)),
|
|
borderWidth: 1
|
|
},
|
|
{
|
|
label: 'BofA Savings Interest',
|
|
data: bofaSavingsGrowth(saved),
|
|
borderWidth: 1
|
|
},
|
|
{
|
|
label: 'Credit Card Bonus',
|
|
data: creditCardGrowth(saved, avgBasePoints, monthlySpending),
|
|
borderWidth: 1
|
|
},
|
|
{
|
|
label: 'BofA Savings Interest + Credit Card Bonus',
|
|
data: bofaCombined(saved, avgBasePoints, monthlySpending),
|
|
borderWidth: 1
|
|
},
|
|
{
|
|
label: 'BofA Savings Interest + Credit Card Bonus - Amount spent',
|
|
data: bofaGrossCombined(saved, avgBasePoints, monthlySpending),
|
|
borderWidth: 1,
|
|
hidden: true,
|
|
}
|
|
];
|
|
}
|
|
|
|
document.addEventListener("DOMContentLoaded", () => {
|
|
function getOrInit(id, value) {
|
|
const ele = document.getElementById(id);
|
|
if (ele.value) {
|
|
document.getElementById(id + "Display").textContent = ele.value;
|
|
return ele.value;
|
|
} else {
|
|
document.getElementById(id + "Display").textContent = value;
|
|
ele.value = value;
|
|
return value;
|
|
}
|
|
}
|
|
|
|
let saved = getOrInit("saved", 50_000);
|
|
let hysaPercent = getOrInit("hysaPercent", 3.75);
|
|
let monthlySpending = getOrInit("monthlySpending", 2_000);
|
|
let avgBasePoints = getOrInit("avgBasePoints", 1.5);
|
|
|
|
|
|
Chart.defaults.color = "#ccc";
|
|
Chart.defaults.borderColor = "#9993";
|
|
Chart.defaults.font.family = "'M PLUS Code Latin', sans-serif";
|
|
Chart.defaults.font.size = 16;
|
|
let chart = new Chart(document.getElementById('myChart'), {
|
|
normalized: true,
|
|
type: 'line',
|
|
data: {
|
|
labels: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", "Jan"],
|
|
datasets: getDatasets(saved, hysaPercent, monthlySpending, avgBasePoints),
|
|
},
|
|
options: {
|
|
scales: {
|
|
y: {
|
|
beginAtZero: true,
|
|
}
|
|
},
|
|
animation: false,
|
|
}
|
|
});
|
|
|
|
function updateChart() {
|
|
chart.data.datasets = getDatasets(saved, hysaPercent, monthlySpending, avgBasePoints);
|
|
chart.update();
|
|
}
|
|
|
|
document.getElementById("saved").addEventListener("input", (ev) => {
|
|
if (ev.target.value) {
|
|
saved = ev.target.value;
|
|
document.getElementById("savedDisplay").textContent = ev.target.value;
|
|
updateChart();
|
|
}
|
|
});
|
|
document.getElementById("monthlySpending").addEventListener("input", (ev) => {
|
|
if (ev.target.value) {
|
|
monthlySpending = ev.target.value;
|
|
document.getElementById("monthlySpendingDisplay").textContent = ev.target.value;
|
|
updateChart();
|
|
}
|
|
});
|
|
document.getElementById("avgBasePoints").addEventListener("input", (ev) => {
|
|
if (ev.target.value) {
|
|
avgBasePoints = ev.target.value;
|
|
document.getElementById("avgBasePointsDisplay").textContent = ev.target.value;
|
|
updateChart();
|
|
}
|
|
});
|
|
document.getElementById("hysaPercent").addEventListener("input", (ev) => {
|
|
if (ev.target.value) {
|
|
hysaPercent = ev.target.value;
|
|
document.getElementById("hysaPercentDisplay").textContent = ev.target.value;
|
|
updateChart();
|
|
}
|
|
});
|
|
});
|
|
</script>
|
|
</body>
|
|
|
|
</html> |