Deciding Between Prime-Location Resale HDB or a More Remote HDB
Should you choose a prime-location resale HDB or a more remote resale HDB?
So, here's the deal. I've been itching to tear apart this classic dilemma with my rusty data analytical skills. We're not just shooting in the dark here; we're talking cold, hard facts and figures. Plus, I'll throw in some raw code snippets for educational purposes.
Snagging 34 Years of Data Without Breaking the Bank
First things first, let's acquire all the resale HDB transactions. However, data.gov.sg only goes back to 2017. Seven years of data is definitely not enough for our use case. A quick Google search led me to some sites selling this goldmine for 100 bucks.
I mean, sure, I get the business angle, but c'mon, we can get this stuff for free from the government. Check out my script, no API token necessary. Completely legal too.
Let's set the assumptions
Okay, let's keep it simple. I'm a first-time homebuyer in Singapore, eyeing a 4-room resale HDB with my better half. No grants, just us and a private bank loan.
Note that there is no official endorsement for 'Remote' towns. This is clearly my own slightly-crude interpretation of towns outside of prime and plus areas. Calling it standard is too boring tbh.
Prime location stats for 2023
# Calculate number of transactions and average and median price in the prime area for year 2023
prime_location_towns = ["BUKIT MERAH", "CENTRAL AREA", "QUEENSTOWN", "KALLANG/WHAMPOA"]
fourrm_prime_2023_mask = (
(df["year"] == "2023") & (df["town"].isin(prime_location_towns)) & (df["flat_type"] == "4 ROOM")
)
df[fourrm_prime_2023_mask].groupby(["town"]).agg(
{"_id": "count", "resale_price": ["mean", "median"], "price_per_sqft": ["mean"]}
).reset_index()
# Get percentage of 4 room transactions in the prime area for year 2023
fourrm_all_2023_mask = (df["year"] == "2023") & (df["flat_type"] == "4 ROOM")
len(df[fourrm_prime_2023_mask]) / len(df[fourrm_all_2023_mask])And with this function, we can get the following table.
Prices for 4-room flats at prime locations
| town | count | avg_price | median_price | avg_price_per_sqft |
|---|---|---|---|---|
| CENTRAL AREA | 77 | 913977 | 800000 | 929 |
| QUEENSTOWN | 261 | 859895 | 878000 | 880 |
| BUKIT MERAH | 428 | 803362 | 845750 | 803 |
| KALLANG/WHAMPOA | 294 | 759759 | 780000 | 757 |
Prices for 4-room flats at remote locations (top 7 cheapest)
| town | count | avg_price | median_price | avg_price_per_sqft |
|---|---|---|---|---|
| CHOA CHU KANG | 596 | 502280 | 500000 | 471 |
| JURONG EAST | 142 | 490796 | 477500 | 476 |
| JURONG WEST | 597 | 499462 | 486000 | 480 |
| WOODLANDS | 958 | 499028 | 495000 | 484 |
| YISHUN | 870 | 497659 | 498000 | 496 |
| BUKIT PANJANG | 367 | 515237 | 498000 | 502 |
| PASIR RIS | 269 | 566849 | 548000 | 515 |
In 2023, 9.3% if all 4-room transactions are from the prime location, i.e. Bukit Merah, Central area, Queenstown and Kallang/Whampoa. This is a rather unsurprising statistic because the prime area cost an arm and a leg. Demand for flats in these locations would reasonably be expected to be in the minorities.
Notice a stark difference between the average and median price in these towns. This suggests the presence of outliers or skewed distributions.
For example, in CENTRAL AREA, the average price is higher than the median price, which could indicate that there are a few very expensive flats, i.e. >1million flats, that are driving up the average price.
The takeaway? Brace yourself to shell out over 800K for a 4-room flat in these fancy schmancy areas.
The 10-Year Faceoff: Prime vs. Remote
Let's start with a function to calculate annualized returns.
def calculate_yoy_increase(df):
"""
Calculate the Year-on-Year (YoY) increase in average resale prices for '4 ROOM' HDB flats
in prime and remote locations.
Args:
df (pd.DataFrame): The DataFrame containing HDB resale data.
Returns:
pd.DataFrame: A DataFrame containing the YoY increase and annualized increase in average resale prices.
"""
# Define prime and remote towns
prime_towns = ["BUKIT MERAH", "CENTRAL AREA", "QUEENSTOWN", "KALLANG/WHAMPOA"]
remote_towns = ["CHOA CHU KANG", "JURONG EAST", "JURONG WEST", "WOODLANDS", "YISHUN", "BUKIT PANJANG", "PASIR RIS"]
# Filter for '4 ROOM' flats
mask = (df["flat_type"] == "4 ROOM") & (df["year"] >= "2013") & (df["year"] <= "2023")
df_4_room = df[mask]
# Split data into prime and remote
prime_df = df_4_room[df_4_room["town"].isin(prime_towns)]
remote_df = df_4_room[df_4_room["town"].isin(remote_towns)]
# Calculate yearly average resale price
prime_yearly_avg = prime_df.groupby("year")["price_per_sqft"].mean()
remote_yearly_avg = remote_df.groupby("year")["price_per_sqft"].mean()
# Calculate YoY increase
prime_yoy = prime_yearly_avg.pct_change().fillna(0) * 100
remote_yoy = remote_yearly_avg.pct_change().fillna(0) * 100
# Calculate annualized increase over 20 years
prime_annualized = ((prime_yearly_avg.iloc[-1] / prime_yearly_avg.iloc[0]) ** (1 / 20) - 1) * 100
remote_annualized = ((remote_yearly_avg.iloc[-1] / remote_yearly_avg.iloc[0]) ** (1 / 20) - 1) * 100
# Print annualized increases
print(f"Prime Annualized Increase: {prime_annualized:.2f}%")
print(f"Remote Annualized Increase: {remote_annualized:.2f}%")
# Prepare final DataFrame
result_df = pd.DataFrame(
{
"Year": prime_yoy.index,
"Prime PSF YoY %": prime_yoy.values.round(2),
"Remote PSF YoY %": remote_yoy.values.round(2),
}
)
return result_df, prime_annualized, remote_annualized
df_temp, prime_annualized, remote_annualized = calculate_yoy_increase(df)| Year | Prime PSF YoY % | Remote PSF YoY % |
|---|---|---|
| 2013 | 0 | 0 |
| 2014 | -2.93 | -7.34 |
| 2015 | 3.95 | -6.18 |
| 2016 | -0.76 | 0.14 |
| 2017 | 0.02 | -1.03 |
| 2018 | 1.19 | -2.89 |
| 2019 | -0.77 | 3.38 |
| 2020 | 4.83 | 6.79 |
| 2021 | 7.92 | 14.28 |
| 2022 | 4.93 | 8.63 |
| 2023 | 6.42 | 4.85 |
| 10-year Annuallized | 1.20 | 0.93 |
Ok. We're talking about a 20-year rollercoaster here. years, and it's like everyone suddenly realized the value of space post-pandemic, with remote areas showing some serious muscle in 2021. What's really cool is the long game - over 20 years, prime areas had a steady climb at 5.27%, while remote areas were quite far behind at 4.01%.
Here's the kicker: in the last 10 years, the prime spots only edged out with 1.2% annual returns, compared to remote areas' 0.93%.
One possible explanation for the outperformance of prime locations is that the rising tide of private property prices is steering buyers towards Central HDBs. Once eyeing private residences, many now find themselves priced out, their options narrowed from 3-bedroom units in the Outside Central Region (OCR) to smaller 2-bedroom spaces in just a year or two. Imagine having 1.2 million bucks burning a hole in your pocket. You could either squeeze into a tiny 1 or 2-bed condo or you can sprawl out in a quality 4-room HDB with a view of the CBD.
And get this: luxury HDBs are now a thing. We're talking lofts and shophouse-style pads in places like Tanjong Pagar, fetching over $1.4 million. Once unthinkable for HDBs, these prices are now the new normal, thanks to the private market's insanity.
P&L for 800K flat at prime locations
| Description | Amount (SGD) |
|---|---|
| Purchase price | $800,000 |
| Loan Required (Assuming a 75% Loan-to-Value) | $600,000 |
| Cost Incurred | |
| BSD (Buyer's Stamp Duty) | $18,600 |
| Interest Expense for 10 years (4% interest, 30-year tenure) | $288,590 |
| Property Tax | $4,000 |
| Town Council Service & Conservancy Fees (Assuming $80/month) | $9,600 |
| Total Costs for Flat | $320,790 |
| Future Value (at 1.2% annual growth, 10 years) | $901,353 |
| Net Profit & Loss (10 years) | -$219,437 |
P&L for $500K flat at remote locations
| Description | Amount (SGD) |
|---|---|
| Costs for $500K Flat | |
| Purchase Price | $500,000 |
| Loan Required (75% Loan-to-Value) | $375,000 |
| Cost Incurred | |
| Interest Expense for 10 years (4% interest, 30-year tenure) | $135,277 |
| BSD (Buyer's Stamp Duty) | $9,600 |
| Property Tax (Proportional to Flat Value) | $3,000 |
| Town Council Service & Conservancy Fees | $9,600 |
| Total Costs for Flat | $157,477 |
| Future Value (at 0.93% annual growth, 10 years) | $548,495 |
| Net Profit & Loss (10 years) | -$108,982 |
The results are clear. With a high-interest rate environment in 2024, we are bound to see higher losses the larger loans we take. I want to stress that this analysis is a little too cutthroat, and we may not see a 4 percent interest rate for the next 10 years. FED is likely going to reduce interest rates in 2024 and coming years now that inflation has more or less calmed down.
This is one of the times where you really feel the pinch of the economy as a future home owner. And I haven't even factored in inflation and other misclleaneous costs like renovations and property upkeep.
One thing i know for sure is if interest rates are kept high, HDB will remain a liability. We can just hope that SIBOR will go back to the lows of 2009 to 2014. 2020 to 2021.
So, what's the move?
Drumroll, please... Our analysis says: going for a prime area 4-room flat might set you back an extra $110,455. Ouch. But hey, buying a home? That's a personal journey. Grew up in the infamous Yishun and 3-mall trifecta Jurong West and don't mind the trek? Remote areas could be your happy place. But for the city slickers, those prime spots might be worth every dollar, especially if your heart's set on CBD living and the perks that come with it.
Just remember, this is one piece of the puzzle. We're talking specific scenarios here—4-room flats, resale, private bank loans. Do your homework and tailor the analysis to your own story.
Check out my code in this GitHub prime_vs_remote_hdb_2024.ipynb page.