🔍 About this code showcase
These snippets show the three pieces that make the system trustworthy: how each lead is labelled, how a landlord report is written from the numbers, and how the monthly recommendations are decided.
The full project (dataset, generators, dashboard, owner-report template, insight engine, and the Power BI spec) lives in projects/property-lead-tracker/. Every figure on every page traces back to one seeded dataset of 1,140 enquiries.
📁 Project structure
projects/property-lead-tracker/
generate_dataset.py
listings.csv enquiries.csv
ad_spend.csv platform_costs.csv
ui-1-internal-dashboard.html
ui-2-owner-report.html
ui-3-case-study.html
owner-reports/
owner_report_template.html.j2
generate_owner_reports.py
out/
insights/
generate_insights.py
2026-03-notes.md ...
powerbi-spec/
data-model.md measures.dax pages.md
🏷️ 1. Labelling each lead: where it came from, how good it is
The whole analysis rests on labelling every enquiry by channel, with a realistic quality and conversion profile for each. This is the table that lets the dashboard separate the busy channel from the one that actually signs tenants.
SOURCES = {
"mudah": dict(share=0.38, q=0.15, view=0.30, show=0.55),
"propertyguru": dict(share=0.27, q=0.42, view=0.55, show=0.75),
"meta_ads": dict(share=0.16, q=0.35, view=0.45, show=0.65),
"google_ads": dict(share=0.11, q=0.55, view=0.68, show=0.80),
"referral": dict(share=0.08, q=0.75, view=0.80, show=0.90),
}
📝 2. Writing the landlord report from the numbers
The owner report is not hand-typed. A rule reads each listing's month and decides the one recommendation that matters: reprice a stale unit, celebrate a signing, or stay the course. The reprice range is computed from the asking rent, so the advice is always grounded in the data.
def recommendation(f, anchor):
rent = int(f["row"].asking_rent_myr)
if f["signed_this_month"]:
return celebrate_signing()
if f["is_active"] and f["velocity_drop"] >= 0.5 and f["weeks_on_market"] >= 6:
low = round(rent * 0.88 / 50) * 50
high = round(rent * 0.913 / 50) * 50
return reprice_advice(low, high, anchor)
if f["new_enq"] >= 4 and f["viewings"] >= 1:
return stay_the_course()
return refresh_listing()
🚩 3. The monthly flag: catching a stale listing automatically
The insight engine compares a unit's recent enquiry pace against its opening fortnight. When interest has halved and the unit is still empty after six weeks, it writes the flag, names a cheaper comparable that kept moving, and recommends a price review instead of more ad spend.
if drop >= 0.5 and weeks_on >= 6:
anchor = cheaper_comparable(listing)
yield ("flag",
f"{name} (RM{rent}) has gone stale: enquiry velocity is down "
f"{drop:.0%} from its opening fortnight after {weeks_on} weeks. "
f"Recommend a price review toward RM{low}-{high}, not more ad spend.")
📐 4. The same answer in Power BI (DAX)
For a client who runs on Microsoft tools, the headline measure is one line. It returns blank when a channel produced no tenancies, which the dashboard shows as "Undefined", because cost divided by zero tenants is not zero, it is unanswerable.
Cost per Tenancy =
DIVIDE ( [Source Cost], [Tenancies Signed] )
Cost per Tenancy (label) =
IF ( ISBLANK ( [Cost per Tenancy] ), "Undefined",
FORMAT ( [Cost per Tenancy], "\R\M #,0" ) )