LC-TEST-23 — Math Behind Loans
🌍 Why This Document Exists
Most people learn Python by:
- sorting lists
- reversing strings
- solving toy problems
But banks don’t care about toys.
Banks care about:
- money over time
- interest dynamics
- human financial decisions
This document teaches Python + Math + Real Banking Logic
so students can see their future mortgage before signing it.
🧠 Core Math Behind Loans (Very Important)
When you borrow money, you are solving this problem:
$$ \text{Total Payment} = \sum_{t=1}^{T} \left( \text{Principal}_t + \text{Interest}_t \right) $$
Where interest usually follows:
interest_t = remaining_principal_t_1 * r_t
Understanding this formula is more important than memorizing code.
🟢 Problem 1 — Fixed Rate Mortgage (Reality Check)
📌 Scenario
- Condo price: 3.3 million THB
- Fixed interest rate: 6.5% per year
- Loan duration: 30 years
- No down payment
Assume:
- Interest is compounded monthly
- Payments are equal every month (standard mortgage)
🧮 Mathematical Hint
Monthly interest rate:
$$ r = \frac{0.065}{12} $$
Number of payments:
$$ N = 30 \times 12 $$
Monthly payment formula:
$$ M = P \cdot \frac{r(1+r)^N}{(1+r)^N - 1} $$
🎯 Tasks
- Compute monthly payment
- Compute total money paid
- Compute total interest paid
✅ Solution (Python)
P = 3_300_000
annual_rate = 0.065
r = annual_rate / 12
N = 30 * 12
monthly_payment = P * (r * (1 + r)**N) / ((1 + r)**N - 1)
total_payment = monthly_payment * N
total_interest = total_payment - P
print("Monthly payment:", round(monthly_payment, 2))
print("Total paid:", round(total_payment, 2))
print("Total interest:", round(total_interest, 2))
💡 Concept Insight
- You borrow 3.3M
- You return almost double
- Time is more expensive than interest rate
🟢 Problem 2 — Fixed Rate vs Floating Rate (Bank Knowledge)
Before coding, you must understand bank language.
🏦 Interest Types Explained (Human Language)
Fixed Rate
Interest rate is locked for a period or entire contract.
Example:
- 7% per year
- Fixed for 4 years
- No surprise
Floating Rate
Interest rate moves with the bank’s cost
Usually written as:
$$ \text{Interest} = \text{MRR} - x $$
📘 Bank Reference Rates
MLR — Minimum Loan Rate
Large, high-quality customers (business loans)
MRR — Minimum Retail Rate
Retail customers (home loans, personal loans)
MOR — Minimum Overdraft Rate
Overdraft credit lines
📌 New Scenario (Realistic Mortgage)
- Condo price: 3.3M
- Loan term: 30 years
- First 3 years: MRR = 2.2%
- Remaining years: MRR = 3.3%
- No down payment
🧮 Mathematical Hint
Interest changes at time ( t = 36 ) months:
$$
r_t =
\begin{cases}
\frac{0.022}{12}, & t \le 36
\frac{0.033}{12}, & t > 36
\end{cases}
$$
🎯 Tasks
- Total money paid
- Total interest paid
- Interest paid per year
✅ Solution (Python)
P = 3_300_000
years = 30
months = years * 12
rates = [0.022] * 36 + [0.033] * (months - 36)
balance = P
total_interest = 0
yearly_interest = {}
monthly_payment = P * 0.005 # simplified assumption for teaching
for m, rate in enumerate(rates, start=1):
r = rate / 12
interest = balance * r
principal = monthly_payment - interest
balance -= principal
total_interest += interest
year = (m - 1) // 12 + 1
yearly_interest[year] = yearly_interest.get(year, 0) + interest
print("Total interest:", round(total_interest, 2))
print("Remaining balance:", round(balance, 2))
print("Interest per year:", yearly_interest)
💡 Teaching Insight
- Floating rate = uncertainty
- Early years matter more than later years
- Banks earn most interest at the beginning
🟢 Problem 3 — Add 10% Down Payment
📌 Scenario Change
- Down payment: 10%
- Loan amount:
$$ P = 3.3M \times 0.9 $$
Repeat Problem 2 with new principal.
✅ Solution (Python)
P = 3_300_000 * 0.9
# reuse previous logic
💡 Key Insight
- Small down payment = huge interest savings
- Leverage is expensive
🟢 Problem 4 — Aggressive Payoff in 3 Years (No Down Payment)
📌 Scenario
- Loan: 3.3M
- Finish payment in 3 years
- Same interest as Problem 2
🧮 Hint
Shorter time means:
$$ \text{Interest} \propto \text{Time} $$
But monthly cash flow explodes.
✅ Solution (Python)
P = 3_300_000
months = 36
rate = 0.022 / 12
monthly_payment = P / months + (P * rate)
total_paid = monthly_payment * months
total_interest = total_paid - P
print(total_paid, total_interest)
💡 Life Lesson
- Banks hate early payoff
- Discipline beats interest
🟢 Problem 5 — Extreme Discipline: Pay Off in 2 Years
Same logic as Problem 4, but:
$$ T = 24 \text{ months} $$
✅ Solution (Python)
months = 24
rate = 0.022 / 12
monthly_payment = P / months + (P * rate)
total_paid = monthly_payment * months
total_interest = total_paid - P
print(total_paid, total_interest)
💡 Final Insight
- Interest is the price of time
- Python helps you see the truth before signing
🎓 Final Takeaway
If a student finishes this chapter, they can:
- read bank contracts
- simulate real mortgages
- explain interest mathematically
- write Python like a finance engineer
This is real-world algorithmic thinking.
🌍 Why This Chapter Exists
Most people ask:
“Which bank is cheaper?”
Engineers ask:
“Which bank minimizes expected financial pain under uncertainty?”
Banks price risk, not kindness.
This chapter teaches:
- how to compare banks algorithmically
- how to think in risk-adjusted terms
- how Python exposes hidden costs humans overlook
🧠 Mental Model: What Is a Risk-Adjusted Decision?
A naive decision minimizes:
$$ \min ; \text{Total Payment} $$
A risk-aware decision minimizes:
$$ \min ; \mathbb{E}[\text{Cost}] + \lambda \cdot \text{Risk} $$
Where:
expected_cost = E_cost # Expected total payment risk = volatility # Or uncertainty / worst-case exposure lambda_ = risk_aversion_level # Human parameter for risk aversion
🏦 Problem Setup — Comparing Bank A / B / C
📌 Loan Assumptions (Same for All Banks)
- Condo price: 3.3M THB
- Loan term: 30 years
- No down payment
- Monthly payment system
🏦 Bank Profiles (Very Realistic)
🟢 Bank A — Safe & Predictable
- Fixed rate: 3.0% for entire loan
🟡 Bank B — Promotional Trap
- 2.0% for first 3 years
- 4.0% afterward
🔴 Bank C — Floating & Uncertain
- MRR = 2.0% → 5.0%
- Random yearly fluctuation
🟢 Question 1 — Pure Cost Comparison
🎯 Task
Calculate:
- Total payment
- Total interest
for Bank A and Bank B
Ignore uncertainty for now.
🧮 Hint
Monthly payment:
$$ M = P \cdot \frac{r(1+r)^N}{(1+r)^N - 1} $$
✅ Solution (Python)
def mortgage_total(P, annual_rate, years):
r = annual_rate / 12
N = years * 12
M = P * (r * (1 + r)**N) / ((1 + r)**N - 1)
return M * N, M * N - P
P = 3_300_000
bank_A = mortgage_total(P, 0.03, 30)
bank_B_part1 = mortgage_total(P, 0.02, 30)
print("Bank A:", bank_A)
print("Bank B (naive):", bank_B_part1)
💡 Insight
- Promotional rates lie if you don’t model the future
- Banks love customers who stop calculating at year 3
🟢 Question 2 — Correctly Modeling Bank B (Piecewise Rates)
🎯 Task
Bank B:
- 2% for 3 years
- 4% for remaining 27 years
Compute real total interest.
🧮 Mathematical Hint
Interest rate is time-dependent:
$$
r_t =
\begin{cases}
0.02 & t \le 3
0.04 & t > 3
\end{cases}
$$
✅ Solution (Python)
P = 3_300_000
balance = P
years = 30
monthly_payment = P * 0.005 # simplified for teaching
rates = [0.02]*36 + [0.04]*(years*12 - 36)
total_interest = 0
for rate in rates:
interest = balance * (rate / 12)
principal = monthly_payment - interest
balance -= principal
total_interest += interest
print("Total interest Bank B:", round(total_interest, 2))
💡 Engineering Lesson
- Time segmentation matters
- Banks profit from human short-term thinking
🧠 Question 3 — Modeling Risk: Bank C (Floating Rate)
📌 Scenario
Bank C interest:
- Starts at 2%
- Every year randomly moves ±1%
- Capped at 5%
🎯 Task
Simulate 1000 futures and compute:
- Expected total interest
- Worst 10% outcome (risk)
🧮 Hint (Monte Carlo Thinking)
$$ \mathbb{E}[X] \approx \frac{1}{N} \sum_{i=1}^N X_i $$
✅ Solution (Python)
import random
def simulate_bank_c(P, years, simulations=1000):
results = []
for _ in range(simulations):
balance = P
total_interest = 0
rate = 0.02
for _ in range(years * 12):
if random.random() < 1/12:
rate += random.choice([-0.01, 0.01])
rate = min(max(rate, 0.02), 0.05)
interest = balance * (rate / 12)
balance -= (P / (years*12))
total_interest += interest
results.append(total_interest)
results.sort()
return sum(results)/len(results), results[int(0.9*len(results))]
expected, worst_10 = simulate_bank_c(3_300_000, 30)
print("Expected interest:", expected)
print("Worst 10% interest:", worst_10)
💡 Deep Insight
- Floating rate is not “cheaper”
- It is a distribution
- Humans underestimate tail risk
🧠 Question 4 — Risk-Adjusted Decision Rule
🎯 Task
Define a decision score:
$$ \text{Score} = \mathbb{E}[\text{Interest}] + \lambda \cdot \text{WorstCase} $$
Compare banks for:
lambda_value = 0 # Risk-neutral lambda_value = 0.5 # Moderately risk-averse lambda_value = 1.0 # Highly risk-averse
✅ Solution (Python)
banks = {
"A": {"expected": 1.9e6, "risk": 0.1e6},
"B": {"expected": 1.7e6, "risk": 0.4e6},
"C": {"expected": expected, "risk": worst_10}
}
for lam in [0, 0.5, 1.0]:
print("\nLambda =", lam)
for k, v in banks.items():
score = v["expected"] + lam * v["risk"]
print(k, round(score, 2))
💡 Human Insight
- Young + rich → Bank C
- Family + fixed income → Bank A
- Optimists regret Bank B
🎓 Final Mental Upgrade
After this chapter, students can:
- model banks as stochastic systems
- quantify financial risk
- explain why “cheapest” ≠ “best”
- think like a bank risk analyst
This is real Python for real life decisions.
🌍 Why This Chapter Exists
Most mortgage calculators assume:
“The future is stable.”
Banks never assume that.
Banks ask:
- What if income drops?
- What if interest spikes?
- What if humans panic?
This chapter teaches:
- how to simulate recession scenarios
- how to evaluate decisions using expected utility
- why banks survive crises while households don’t
🧠 Core Upgrade: Cost Is Not Pain
Humans don’t minimize money.
They minimize pain.
Economics models this using utility.
📘 Expected Utility Theory (Very Simple)
Instead of minimizing cost:
$$ \min ; \mathbb{E}[\text{Cost}] $$
Humans actually maximize:
$$ \max ; \mathbb{E}[U(W)] $$
Where:
- ( W ) = wealth after paying mortgage
- ( U(\cdot) ) = utility function (how painful money loss feels)
🧠 Common Utility Function (Risk-Averse Human)
$$ U(W) = \sqrt{W} $$
Why?
- Losing 100k hurts more when you are poor
- Rich people absorb shocks better
🏦 Recession Model — What Changes?
During a recession, three things happen together:
- Interest rates increase
- Income becomes unstable
- Forced selling risk appears
We simulate interest shock + income shock
🟢 Question 1 — Modeling a Recession Shock
📌 Scenario
At year 5:
- Interest jumps by +2%
- Monthly income drops by 30% for 2 years
🎯 Task
Simulate mortgage under recession and compute:
- total interest
- minimum remaining cash buffer
🧮 Mathematical Hint
Interest rate shift:
$$ r_t = \begin{cases} r & t < t_c \ r + 0.02 & t \ge t_c \end{cases} $$
Income shock:
$$ I_t = 0.7 I \quad \text{during recession} $$
✅ Solution (Python)
P = 3_300_000
balance = P
years = 30
monthly_income = 80_000
monthly_payment = 25_000
cash_buffer = 500_000
rate = 0.03
total_interest = 0
min_cash = cash_buffer
for m in range(1, years * 12 + 1):
if m == 5 * 12:
rate += 0.02
income = monthly_income
if 5 * 12 <= m <= 7 * 12:
income *= 0.7
interest = balance * (rate / 12)
principal = monthly_payment - interest
balance -= principal
total_interest += interest
cash_buffer += income - monthly_payment
min_cash = min(min_cash, cash_buffer)
print("Total interest:", round(total_interest, 2))
print("Minimum cash buffer:", round(min_cash, 2))
💡 Reality Insight
- Interest shock hurts slowly
- Income shock kills fast
- Liquidity > interest rate
🧠 Question 2 — Probability of Default (Human View)
📌 Default Rule
Household defaults if:
$$ \text{Cash Buffer} < 0 $$
🎯 Task
Simulate 1000 recession paths and compute:
- probability of default
✅ Solution (Python)
import random
def simulate_default():
cash = 500_000
balance = 3_300_000
rate = 0.03
income = 80_000
payment = 25_000
for m in range(1, 30*12):
if m == 5 * 12:
rate += 0.02
shock = random.random() < 0.3
current_income = income * (0.7 if shock else 1.0)
interest = balance * (rate / 12)
balance -= (payment - interest)
cash += current_income - payment
if cash < 0:
return True
return False
defaults = sum(simulate_default() for _ in range(1000))
print("Default probability:", defaults / 1000)
💡 Bank Insight
- Banks don’t care about averages
- They price default probability
🧠 Question 3 — Expected Utility Comparison (Bank A vs C)
📌 Setup
We compare two choices:
- Bank A: fixed rate, low volatility
- Bank C: floating rate, high volatility
🎯 Task
Compute expected utility under recession risk.
🧮 Utility Function
$$ U(W) = \sqrt{W} $$
Where:
$$ W = \text{Final Wealth} = \text{Savings} - \text{Total Paid} $$
✅ Solution (Python)
import math
def utility(wealth):
return math.sqrt(max(wealth, 0))
def expected_utility(simulations, bank_type):
utilities = []
for _ in range(simulations):
savings = 2_000_000
total_paid = 0
if bank_type == "A":
rate = 0.03
else:
rate = random.uniform(0.02, 0.05)
total_paid = 3_300_000 * (1 + rate * 30)
wealth = savings - total_paid
utilities.append(utility(wealth))
return sum(utilities) / len(utilities)
print("EU Bank A:", expected_utility(1000, "A"))
print("EU Bank C:", expected_utility(1000, "C"))
💡 Key Insight
- Higher expected cost can still give higher utility
- Safety has value
- Volatility destroys utility faster than it saves money
🧠 Question 4 — Why Banks Win (Final Truth)
Banks optimize:
$$ \max ; \mathbb{E}[\text{Profit}] - \text{Tail Risk} $$
Humans ignore tail risk.
🎯 Thought Question (No Code)
Why do banks survive recessions while households don’t?
Hint:
$$ \text{Diversification} + \text{Capital Buffer} \gg \text{Single Mortgage} $$
🎓 Final Mental Shift
After this chapter, students understand:
- why floating rate is psychologically dangerous
- why recession kills liquidity, not math
- why expected utility beats “lowest interest”
- why banks always design contracts to win
You are no longer a borrower.
You are a system thinker.
🌍 Why This Chapter Exists
People often say:
“Banks are greedy.”
That is emotionally true — but technically incomplete.
Banks do not survive because of greed.
They survive because of structure.
This chapter explains:
- why banks can take risks households cannot
- why leverage hurts humans more than math predicts
- why loss hurts more than gain feels good
🏦 Part I — Bank Capital vs Household Leverage
🧠 Core Asymmetry (Very Important)
A household usually has:
$$ \text{Leverage} = \frac{\text{Debt}}{\text{Income}} \gg 1 $$
A bank operates under:
$$ \text{Capital Ratio} = \frac{\text{Equity}}{\text{Risk-Weighted Assets}} \ge 8% $$
Same money system — completely different survival rules.
📘 Definitions (Plain English)
Household Leverage
- One income stream
- One large loan
- Failure = life disruption
Bank Capital
- Thousands of borrowers
- Diversification
- Loss absorption buffer
🟢 Question 1 — Leverage Comparison (Math Reality)
📌 Scenario
Household:
- Income: 80,000 THB/month
- Mortgage: 3.3M
Bank:
- Loans issued: 1,000 × 3.3M
- Capital ratio: 10%
🎯 Tasks
- Compute household leverage
- Compute bank equity buffer
- Compare shock tolerance
🧮 Mathematical Hint
$$ \text{Household Leverage} = \frac{\text{Debt}}{\text{Annual Income}} $$
$$ \text{Bank Capital} = 0.10 \times \text{Total Loans} $$
✅ Solution (Python)
household_income = 80_000 * 12
household_debt = 3_300_000
leverage = household_debt / household_income
bank_loans = 3_300_000 * 1000
bank_capital = bank_loans * 0.10
print("Household leverage:", round(leverage, 2))
print("Bank capital buffer:", bank_capital)
💡 Interpretation
- Household leverage ≈ 3–5× income → fragile
- Bank absorbs millions of defaults before dying
🧠 Question 2 — Shock Absorption Test
📌 Scenario
- Economic shock causes 5% of borrowers to default
- Each default loses 50% of loan value
🎯 Tasks
- Compute total bank loss
- Check if bank survives
- Compare to household shock
✅ Solution (Python)
default_rate = 0.05
loss_given_default = 0.5
loss = bank_loans * default_rate * loss_given_default
bank_survives = loss < bank_capital
print("Bank loss:", loss)
print("Bank survives:", bank_survives)
💡 Key Truth
Banks are built to expect failure. Households are not.
🧠 Part II — Prospect Theory (Why Humans Panic)
📘 Classical Economics Assumption (Wrong)
Humans maximize expected value:
$$ \max ; \mathbb{E}[W] $$
🧠 Prospect Theory (Reality)
Humans evaluate gains and losses asymmetrically.
Utility function:
$$
U(x) =
\begin{cases}
x^\alpha & x \ge 0
-\lambda |x|^\beta & x < 0
\end{cases}
$$
Where:
- ( \lambda > 1 ) (loss hurts more than gain)
- Typically ( \lambda \approx 2.25 )
🟢 Question 3 — Loss Aversion in Mortgage Decisions
📌 Scenario
Two outcomes:
- Option A: Save 100,000 THB
- Option B: Risk losing 100,000 THB
Expected value = same.
🎯 Task
Compare utility using prospect theory.
✅ Solution (Python)
def prospect_utility(x, alpha=0.88, beta=0.88, lam=2.25):
if x >= 0:
return x ** alpha
else:
return -lam * (abs(x) ** beta)
gain = prospect_utility(100_000)
loss = prospect_utility(-100_000)
print("Utility of gain:", gain)
print("Utility of loss:", loss)
💡 Psychological Truth
- Losing 100k hurts ~2× more than gaining 100k feels good
- Floating rate mortgages amplify psychological pain
🧠 Question 4 — Why Households Panic-Sell
📌 Scenario
During recession:
- House price drops 15%
- Mortgage balance unchanged
🎯 Task
Compute perceived loss vs actual loss.
🧮 Hint
Reference point matters:
$$ \text{Loss} = P_{\text{peak}} - P_{\text{current}} $$
✅ Solution (Python)
house_price = 3_300_000
price_drop = 0.15
actual_loss = house_price * price_drop
perceived_pain = prospect_utility(-actual_loss)
print("Actual loss:", actual_loss)
print("Perceived pain:", perceived_pain)
💡 Key Insight
People sell not because of math — they sell because of pain.
Banks know this.
🧠 Question 5 — Final Synthesis (No Code)
Why do banks:
- encourage leverage?
- offer floating rates?
- survive crises?
Answer (Hint):
$$ \text{Diversification} + \text{Capital} + \text{Asymmetric Psychology} $$
Households face:
- concentrated risk
- no buffer
- loss aversion
🎓 Final Mental Model
| Entity | Risk | Buffer | Psychology |
|---|---|---|---|
| Household | Concentrated | None | Loss-averse |
| Bank | Diversified | Capital | Risk-neutral |
Banks don’t win by cheating.
They win because the system was never symmetric.
You now see the matrix.