Skip to main content

GeraMarket / US house price momentum / Methodology

Gera US Price Momentum (GUSPM) β€” Methodology

Full, reproducible formula behind the GUSPM index. Every number traces to real, free, authoritative data: the Federal Housing Finance Agency (FHFA) House Price Index (US public domain). No estimates, no synthetic data.

What is GUSPM?

The Gera US Price Momentum (GUSPM) index combines four signals per US state and CBSA metro area, all derived from real FHFA HPI data:

  • latestHpi β€” latest FHFA All-Transactions HPI value (index, base 1980Q1=100)
  • pct1yr β€” 1-year % change (same quarter prior year)
  • pct5yr β€” 5-year % change (same quarter 5 years ago)
  • volatility β€” std dev of 1yr HPI changes over last 10 quarters; band: low / medium / high

GUSPM raw formula: 0.5 Γ— pct1yr + 0.3 Γ— (pct5yr / 5) + 0.2 Γ— max(0, 3 βˆ’ volatility)

Normalized to 0–100 across all 461 entries. Areas with insufficient FHFA data output β€œinsufficient data” β€” never a fabricated estimate.

Data source

SourceFHFA House Price Index (HPI) β€” All-Transactions, Not Seasonally Adjusted
State filehpi_at_state.txt (All-Transactions, NSA β€” 51 states + DC)
Metro filehpi_at_metro.txt (All-Transactions, NSA β€” 410 CBSA metro areas with data)
Reference period2026 Q1
Last computed2026-06-20
PublisherFederal Housing Finance Agency (FHFA)
LicenceUS public domain β€” federal government work
Key required?No β€” bulk TXT/CSV, no registration

Step-by-step formula

  1. 1

    Download the FHFA HPI datasets

    Fetch hpi_at_state.txt and hpi_at_metro.txt from https://www.fhfa.gov/data/hpi/datasets. No API key required. Files are plain tab-delimited text. State file: columns = state_code, year, quarter, hpi_value. Metro file: columns = metro_name (quoted), cbsa_code, year, quarter, hpi_value (or "-" for no data). Data goes back to 1975 for some states.

  2. 2

    Parse and build time series per area

    For states: read each row, skip if hpi_value is not a float. For metros: skip rows where hpi_value is "-". Build a per-area array of {yr, qtr, hpi} objects sorted by (yr, qtr). Metros with fewer than 8 valid data points are excluded from the published dataset.

  3. 3

    Identify the latest quarter

    The latest data point for each area is the maximum (yr, qtr) pair with a valid HPI value. As of this computation, the latest available quarter for all 51 states is 2026 Q1.

  4. 4

    Compute pct1yr

    Find the data point with yr = latestYr βˆ’ 1 and qtr = latestQtr (exactly 4 quarters prior). pct1yr = (latestHpi βˆ’ hpiOneYrAgo) / hpiOneYrAgo Γ— 100, rounded to 2 d.p. If no matching point exists, pct1yr = null ("insufficient data").

  5. 5

    Compute pct5yr

    Find the data point with yr = latestYr βˆ’ 5 and qtr = latestQtr. pct5yr = (latestHpi βˆ’ hpiFiveYrAgo) / hpiFiveYrAgo Γ— 100, rounded to 2 d.p. If no matching point, pct5yr = null.

  6. 6

    Compute volatility

    For each of the last 10 quarterly periods, compute the 1-year HPI % change (current quarter vs same quarter 1 year prior). Take the population standard deviation of these 10 values (std dev = sqrt(variance)). If fewer than 4 such periods exist, volatility = null. Volatility band: "low" if < 1.0%, "medium" if 1.0–2.5%, "high" if > 2.5%.

  7. 7

    Compute GUSPM raw score

    If pct1yr is null: guspm = null. Otherwise: guspm_raw = 0.5 Γ— pct1yr + 0.3 Γ— (pct5yr ?? 0) / 5 + 0.2 Γ— max(0, 3 βˆ’ (volatility ?? 3)). This blends 1yr momentum (50%), annualized 5yr momentum (30%), and an inverse-volatility stability bonus (20%). Areas with volatility β‰₯ 3% get zero stability bonus.

  8. 8

    Normalize to 0–100

    guspmNorm = (guspm_raw βˆ’ min_raw) / (max_raw βˆ’ min_raw) Γ— 100, rounded to 1 d.p. Normalization is across all 461 entries (states + metros) in the current dataset so that scores are comparable. The range updates each quarter when new FHFA data is published.

Pseudocode

# Input: hpi_at_state.txt, hpi_at_metro.txt
# Output: GUSPM_ENTRIES array (normalized 0–100)

for each area_file in [state_file, metro_file]:
  for each row in area_file:
    if hpi_value == "-" or not valid_float(hpi_value): skip
    series[area_key].append({ yr, qtr, hpi: float(hpi_value) })

for each area in series:
  series[area].sort_by(yr, qtr)
  if len(series[area]) < 8: skip  # insufficient data

  latest = series[area][-1]
  oneYrAgo  = find(series[area], yr=latest.yr-1, qtr=latest.qtr)
  fiveYrAgo = find(series[area], yr=latest.yr-5, qtr=latest.qtr)

  pct1yr = oneYrAgo  ? (latest.hpi - oneYrAgo.hpi)  / oneYrAgo.hpi  * 100 : null
  pct5yr = fiveYrAgo ? (latest.hpi - fiveYrAgo.hpi) / fiveYrAgo.hpi * 100 : null

  changes = [(series[area][i].hpi - series[area][i-4].hpi) / series[area][i-4].hpi * 100
             for i in range(4, len(series[area]))][-10:]
  volatility = stdev(changes) if len(changes) >= 4 else null

  if pct1yr is null: guspm_raw = null
  else:
    guspm_raw = 0.5 * pct1yr
               + 0.3 * (pct5yr ?? 0) / 5
               + 0.2 * max(0, 3 - (volatility ?? 3))

  results.append({ ..., latestHpi: latest.hpi, pct1yr, pct5yr, volatility, guspm_raw })

# Normalize
min_g = min(r.guspm_raw for r in results if r.guspm_raw is not null)
max_g = max(r.guspm_raw for r in results if r.guspm_raw is not null)
for r in results:
  r.guspmNorm = (r.guspm_raw - min_g) / (max_g - min_g) * 100 if r.guspm_raw else null

GUSPM_ENTRIES = results.sort_by(guspmNorm, descending=True)

Coverage (2026 Q1)

  • States covered: 51 (all 50 states + DC)
  • Metro areas (CBSAs) covered: 410 (of 410 in FHFA file; those with β‰₯ 8 valid data points and 1yr data)
  • Total pages: 461 entries + 1 hub + 1 methodology
  • US state median 1-year change: +3.79%
  • Source last published: June 2026
  • Update cadence: Quarterly (on each new FHFA HPI release, approx. 2 months after quarter-end)
  • Licence: US public domain β€” federal government work

Limitations & caveats

  • Index-based, not price-based: FHFA HPI is a repeat-sales index. It measures % change in prices, not absolute price levels. An index value of 495 means prices have risen 395% since the base period (1980Q1=100 for All-Transactions NSA), not that homes cost $495.
  • Enterprise mortgages only: The All-Transactions index covers only mortgages acquired or securitised by Fannie Mae and Freddie Mac, plus FHA/VA appraisals for refinancings. It excludes cash sales and jumbo (above conforming limit) mortgages, which can be significant in high-cost metros.
  • GUSPM weights are illustrative: The 50/30/20 split is a judgment call; changing it would reorder areas. The normalized score is for comparison within this dataset, not across datasets with different methodologies.
  • Volatility window: The last 10 quarterly periods (β‰ˆ2.5 years) capture recent cyclical variation. Longer windows would smooth structural changes; shorter windows would amplify recent events. Areas with short FHFA series show β€œinsufficient data” for volatility.
  • Not investment advice: GUSPM is a statistical summary of FHFA HPI data. It is not a property valuation, mortgage advice, or investment recommendation.

Source data: FHFA House Price Index (HPI), published by the Federal Housing Finance Agency (FHFA). FHFA HPI data is a product of the US federal government and is in the public domain under US law (17 U.S.C. Β§ 105). Downloaded from https://www.fhfa.gov/data/hpi/datasets (2026 Q1). GUSPM computation by Gera Systems β€” see methodology above.