← Writing

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.

30 years of hdb data on sale for 100usd
30 years of hdb data on sale for 100 USD teoalida.com

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

towncountavg_pricemedian_priceavg_price_per_sqft
CENTRAL AREA77913977800000929
QUEENSTOWN261859895878000880
BUKIT MERAH428803362845750803
KALLANG/WHAMPOA294759759780000757

Prices for 4-room flats at remote locations (top 7 cheapest)

towncountavg_pricemedian_priceavg_price_per_sqft
CHOA CHU KANG596502280500000471
JURONG EAST142490796477500476
JURONG WEST597499462486000480
WOODLANDS958499028495000484
YISHUN870497659498000496
BUKIT PANJANG367515237498000502
PASIR RIS269566849548000515

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)
YearPrime PSF YoY %Remote PSF YoY %
201300
2014-2.93-7.34
20153.95-6.18
2016-0.760.14
20170.02-1.03
20181.19-2.89
2019-0.773.38
20204.836.79
20217.9214.28
20224.938.63
20236.424.85
10-year Annuallized1.200.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

DescriptionAmount (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

DescriptionAmount (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.