Simon-Pierre Boucher
All apps & projects
QHPI icon
Web Platform
Python

QHPI

Measuring Quebec home prices, not composition

A production-grade index platform that separates true price movement from sales-mix shifts across 81 geography-by-type segments, with uncertainty published on every observation.

~745k

raw transactions ingested

81

published index cells

17

administrative regions

1,100+

municipalities covered

112

series in the dashboard

2021→now

coverage period

Overview

QHPI is an economic-measurement platform, not a median-price tracker: a week where only mansions sell must not register as a price increase. A robust hedonic time-dummy model with hierarchical pooling estimates quality-adjusted indexes for the province, 17 administrative regions, and major municipalities, each split by property type — unifamilial, condo, plex, and composite.

Three estimation regimes are arbitrated by empirical validation. A rolling time-dummy backbone with Huber-IRLS weighting and mean splicing makes published history revision-free by construction. The 50 liquid cells get their own local regressions; the 31 thin cells follow a Kalman-filtered deviation from their parent's path, with the shrinkage weight published on every row.

Uncertainty is never hidden: every observation carries a 95% confidence interval, an A–E reliability grade, effective sample size, and vintage stamp. The full stack ships in one repo — Python engine, PostgreSQL store, FastAPI service, Next.js dashboard, LaTeX methodology paper — while distributing zero individual transaction records.

Key Features

Hedonic, not median

In a composition-shock simulation the raw median jumps +11.7% while the hedonic index moves −0.7% — the index measures prices, not sales mix.

Three arbitrated estimation regimes

Rolling time-dummy backbone, direct local regressions for 50 liquid cells, and hierarchical Kalman shrinkage for 31 thin cells — chosen by validation, not convenience.

Uncertainty on every row

95% confidence intervals, A–E reliability grades, effective sample size, and shrinkage weight are published with every single observation.

Revision-free published history

13-month rolling windows combined by mean splice make the published index history revision-free by construction; first releases and revisions remain queryable.

Benchmarked against repeat sales

Validated against a ~85k-address repeat-sales benchmark — Quebec condos land at 132.0 vs 132, Quebec City condos at 163.5 vs 162.

No microdata distributed

The repo ships only cell-level aggregates with transaction counts; individual sale records never enter version control, enforced at the .gitignore boundary.

Full-stack index service

FastAPI exposes every series with CIs, vintages, liquidity, comparisons, choropleth payloads, stats, and publication-grade PDF reports.

Interactive dashboard

Next.js frontend with a ⌘K palette over 112 series, CI bands, brush zoom, Bank-of-Canada event annotations, choropleth time-lapse, and PNG/CSV export.

Methodology paper included

A LaTeX paper — 'A High-Frequency Hedonic Housing Price Index for Quebec' — documents the methodology with researched citations from index-number theory.

How It Works

  1. Engine pipeline

    Eleven ordered, idempotent scripts run profile → spatial join → documented cleaning → estimation → validation → canonical Parquet, each emitting a run manifest with input hashes.

  2. Geography layer

    Transactions are spatially joined by lat/lng against authoritative Quebec SDA cadastral boundaries — the free-text city field alone is never trusted.

  3. Estimation core

    Robust hedonic time-dummy regressions over 13-month rolling windows with Huber-IRLS, mean-spliced; buildingType is banned after its staggered backfill fabricated a −38 log-point cliff.

  4. Hierarchical pooling

    Liquid cells get direct local regressions with their own coefficients; thin cells follow Kalman-smoothed deviations from their parent path with published shrinkage weights.

  5. Serving layer

    The canonical monthly Parquet (7,504 rows) loads into PostgreSQL behind a FastAPI service; a weekly scheduler ingests new rows, re-estimates, and stamps a new data vintage.

  6. Dashboard

    The Next.js frontend at www.indexqc.house offers explore, compare, choropleth map with time-lapse, methodology, and an in-page API playground.

Tech Stack

Index engine

Python 3.11+
pandas/polars
numpy
Huber-IRLS
Kalman state-space

Data store

Parquet lake
PostgreSQL
Alembic migrations

API

FastAPI
ETag caching
CSV/JSON export
Rate limiting

Dashboard

Next.js
TypeScript
Custom zero-dependency charts

Ops & research

docker-compose
CI with header gate
LaTeX paper
matplotlib PDF reports

Highlights

  • The composition-shock test is the thesis in one number: mix shock moves the raw median +11.7%, the hedonic index −0.7%.
  • buildingType is banned from all hedonic models — its region-staggered backfill fabricated a −38 log-point cliff in Montreal indexes, and the ban is documented in code.
  • Direct local estimation was chosen because pooled deviations compressed real divergence: Quebec City condos moved ~+55%, confirmed independently by repeat sales.
  • A–E reliability tiers are justified empirically by a downsampling experiment thinning Montreal condos to as few as 5 transactions per period.
  • Strict data policy: zero transaction microdata in the repo — only cell-level aggregates — yet the API and dashboard run fully from the included Parquet.
  • Every file carries an author header enforced by a pre-commit hook and CI gate; runs are deterministic and stamped with model version and data vintage.

Explore QHPI

Quebec's quality-adjusted housing price index — the full source is on GitHub.