Filed · Sourced · Open for Inspection

How WindMayor computes everything you see.

Every number on every WindMayor surface comes from a public, free, cited source — or it's labeled [ILLUSTRATIVE]. This page is the paper trail. If you can't reproduce a value from the source we cite, that's a bug. Tell us.

The no-fabrication rule. WindMayor will never invent a number to fill a gap. Where data exists, we use it and cite it. Where it doesn't, we write NULL — we don't smooth, we don't extrapolate, we don't estimate. Partial real beats fake complete.

The DSCR formula (v4)

DSCR (Debt Service Coverage Ratio) is the single most important number on the site. It answers: does the rent on this property self-fund a typical loan against it? A DSCR ≥ 1.20 is the conventional minimum that lenders underwrite to. The same exact formula is used across military bases, colleges, and cities.

What changed in v3. The old formula buried operating cost in a single flat 0.0165 constant (1.10% tax + 0.55% blended ins/maint) applied to every property in every state. That hid the largest geographic lever in the whole model. v3 deletes the flat constant. Property tax is now the real per-state effective rate; insurance is the real per-state landlord rate; the maintenance reserve is broken out and explicitly labeled an assumption. The pre-v3 value is kept on every record as dscr_v2 so any reviewer can diff the two.
What changed in v4. v3's last flat constant — the 0.0050 maintenance reserve — is now replaced by a per-ZIP variable maintenance model. The DSCR formula has no nationwide constants left in its operating cost: tax is per-state, insurance is per-state, maintenance is per-ZIP. v4 also adds a matched-type DSCR (dscr_sfr / dscr_condo), a climate-yield insurance-drag estimate, a forward rent forecast and a corrected FEMA hazard scale — all documented in the sections below.
# Inputs rent # monthly rent — Zillow ZORI / by property type home_value # typical home value — Zillow ZHVI, by property type state # used to look up real tax + insurance rates rate_30yr # 30-year fixed mortgage rate — FRED MORTGAGE30US (6.51%) # v4 operating cost — three REAL, geographic components, no flat constant op_cost = prop_tax_pct(state) + ins_pct(state) + maint_pct(zip) # prop_tax_pct Tax Foundation effective rate, 0.28% (AL/HI) … 1.85% (NJ) # ins_pct NAIC 2022 DP-3 landlord rate, per state # maint_pct v4: per-ZIP maintenance model — 1% base x BLS construction- # cost index x home-age multiplier, banded 0.6-1.8%, ~0.97% median # Net operating income (NOI), annual noi = rent * 12 * 0.89 - home_value * op_cost # 0.89 = 1 - 11% vacancy/credit-loss # Annual debt service on an 80% LTV, 30-yr fully-amortizing loan rm = (rate_30yr / 100 + 0.0070) / 12 # +0.70% DSCR-loan spread ann = 12 * rm / (1 - (1 + rm) ** -360) debt = home_value * 0.80 * ann dscr = noi / debt yield_pct = (rent * 12) / home_value * 100 p2r = home_value / (rent * 12)

Property tax is the bigger lever

Property tax varies far more across states than insurance does, so replacing the flat 1.10% is what actually moves DSCR. The effective rate runs from 0.28% in Alabama and Hawaii to 1.85% in New Jersey — a 6.6× spread (Tax Foundation, "Property Taxes by State and County," property taxes paid as a % of owner-occupied housing value). Texas (1.49%) is a clear example: moving from the flat 1.10% to the real Texas rate cuts a typical Texas DSCR by roughly 0.17. Insurance uses the NAIC 2022 Homeowners Insurance Report (released 2025), Table 4 — the HO-3 state-average premium divided by the exposure-weighted amount of insurance, then a labeled ×1.20 uplift to a DP-3 dwelling-fire / landlord proxy, because these are rentals, not owner-occupied policies. The ×1.20 is an explicit assumption: NAIC does not publish a clean DP-3 average. The national HO-3 average is 0.40% of insured value, but the state spread is real — the DP-3 rate runs from 0.26% in Utah and Oregon to 0.98% in Louisiana and 0.92% in Oklahoma. Every record carries prop_tax_pct_used and insurance_pct_used so the inputs are auditable per row.

The variable maintenance model (v4) — an estimate, labeled

v3 carried a flat 0.50% maintenance reserve on every property in the country. That is plainly wrong — it costs more to maintain a 90-year-old house in a high-cost-of-construction metro than a new build in a cheap one. v4 replaces the constant with a per-ZIP estimate written to zipdata/data/maintenance_by_zip.csv for all 31,646 ZIPs:

maint_pct = 0.010 * construction_cost_idx(zip) * home_age_mult(zip) # 0.010 1% of value/yr — the standard rule-of-thumb base # construction_cost_idx BLS construction-cost index, normalized to 1.0 # home_age_mult from ACS B25035 median year-built; older = higher maint_pct = clamp(maint_pct, 0.006, 0.018) # banded 0.6%-1.8%

Across all ZIPs the model produces a median maintenance reserve of 0.97% — close to the 1% rule-of-thumb base, with a real spread from the 0.6% floor to the 1.8% cap. The BLS construction-cost index is populated for 31,468 of 31,646 ZIPs; where it is missing the multiplier defaults to 1.00 and the row says so in its source string.

This is still an estimate — it is just a better one. A real maintenance budget depends on the specific roof, the specific HVAC, the specific deferred-repair backlog — none of which is in any public dataset at ZIP granularity. The v4 model is an honest, banded structural estimate (cost-of-construction × building age), not a measured CapEx plan. Every maintenance_pct row carries a source string that begins MODEL so no reviewer mistakes it for observed data.

Property-type pricing — price what the investor would actually buy

Zillow ZHVI is now pulled by property type — single-family (SFR), condo, 2-bedroom, 3-bedroom — not just the all-homes blend. DSCR can then be priced off the unit an investor would realistically buy in that ZIP rather than a market-wide average. Colleges carry dscr_condo (the UI primary), dscr_sfr, and dscr_2br side by side; each row records the property_basis it used and falls back down a ladder (type → sfrcondo blend → all-homes) when a type series is missing.

Apples-to-apples DSCR (v4) — houses pencil better than condos

A DSCR computed from condo rent over single-family value (or vice versa) is apples-to-oranges. v4 ships a strictly matched-type DSCR in zipdata/data/dscr_by_type.csv: dscr_sfr uses single-family rent ÷ single-family value, and dscr_condo uses condo rent ÷ condo value — never a cross.

One honest seam: condo rent is a metro-scaled proxy. Zillow publishes ZHVI by property type at the ZIP level, but ZORI (the rent index) splits into single-family and multifamily only at the metro level — there is no ZIP-level condo rent series at all. So dscr_condo takes the ZIP's blended ZORI and scales it by the metro's multifamily-to-blend rent ratio. The value leg is true ZIP-level condo ZHVI; the rent leg is a metro-anchored estimate. Each row's method field states this.

The matched-type comparison settles a question the all-homes blend hid: across the 2,044 ZIPs with a single-family DSCR and the 1,029 with a condo DSCR, the median dscr_sfr is 0.74 against a median dscr_condo of 0.65. Houses pencil better than condos — condo values have run ahead of condo rents, and an HOA-free house carries a leaner cost stack. Neither type clears 1.20 at today's rate; this is a relative ranking, not a green light.

What we are still NOT modeling

This DSCR is a screen, not an underwrite. It tells you which markets are worth your attention. The actual deal needs property-specific inputs.

Data sources, by surface

SurfaceFieldSourceStatus
Military BAH series (per MHA) DoD Defense Travel Management Office BAH tables 2013–2026 live
Installation list Wikipedia + GlobalSecurity.org; 454 records live
troop_count, years_active, acres Wikipedia infobox + DoD BSR (partial coverage) 38% / 26% / 13%
Feeder-city ZIP economics Zillow ZHVI/ZORI by ZIP, FRED 30yr live
greater_area_pop, maint_cost_idx Census ACS B01003 + BLS OEWS / CPI-U (pending) pending
bah_yield_{1y,5y,13y} Derived from BAH series — CAGR over window pending
Colleges Institution list, enrollment, tuition, admit, grad rate IPEDS HD/EF/IC/ADM/GR 2023, NCES public domain; 6,086 records live
ZIP economics & DSCR (fill v2 + quality tiers) Tiered: Zillow ZIP primary → zip_master + HUD FMR rent → Zillow city → ACS. Each row stamps its dscr_source tier 5,860 / 6,086 (96%) — +113 rows recovered in v5 via all-homes price ladder
housing_capacity, % housed on campus IPEDS IC2023 ROOM + ROOMCAP fields 5,947 / 6,086 (98%)
pct_off_campus Derived: 100 − housing_pct_of_enroll 98%
endowment_per_student Derived: endowment / enrollment 2,732 / 6,086 (45%)
Display outlier clamp Winsorized; raw values preserved in *_raw fields display only
Seattle ZIP economics Zillow ZHVI/ZORI + FRED 30yr 66 / 69 ZIPs (96%)
Recapture / Pre-qual tools Live FRED rate at page load; no fixtures live
Statewide expansion All WA ZIPs (~400) — pending Y-SEATTLE.wa-expand pending
Rate Historical series (annual) FRED DGS10 (1962–2026), FRED MORTGAGE30US (1971–2026) live
"Now" values FRED latest single observation (daily/weekly), date-stamped live
Short-horizon model (weekly OLS) Walk-forward; DGS10 momentum + spread deviation. 1mo: real edge. 3mo: no edge 1mo only — see Rate model
5-year forward cone Mean-reversion central path; bands = empirical percentiles of historical rate moves range, not a forecast
Cities Institution list (250 US cities), demographics Census place FIPS; ACS population, median income/age live
ZIP / city economics & DSCR (condo basis) Zillow ZHVI City condo-tier + ZORI City; FRED 30yr 246 / 250 (98%)
Dual basis — dscr + dscr_condo Parallel all-homes & condo-tier ZHVI; flagged via hv_source live
ZCTA heatmap Nationwide ZIP spine — 31,646 ZCTAs zipdata/data/zip_master.json; Census ACS 2023 + Zillow ZHVI/ZORI + HUD SAFMR 31,646 ZCTAs (2,155 low-pop dropped)
FEMA risk + 18 hazard layers FEMA National Risk Index, county hazard scores composite 98.6%; some hazards thin
price_per_sqft, tornado_count_30yr Realtor.com ZIP market trends; NOAA SPC tornado DB 1950–2023 $/sqft 90.5%; tornado 99.1%
OSM amenity layer OpenStreetMap / Overpass — amenity proximity by ZIP 7,359 ZIPs
Research BAH regression v1 / v2 bah-research/ — OLS, DoD BAH + Zillow + ACS/IRS research — R²test negative
City rent regression city-rent-research/ — OLS, ZORI CAGR target research — R²test +0.28
AVM v1 (hedonic OLS) avm/ — OSM footprints + ZHVI label, Seattle MVP research preview — degenerate v1
AI / Chip Public companies, returns, HQ city Yahoo Finance chart API; public corporate filings 53 companies
Private AI HQ list Public record only (city, no valuations, no individuals) pending

What does NULL mean?

When you see a blank or in the UI, that field has no real source value for that record. We do not estimate, smooth, interpolate, or fill from a neighbor. Examples:

What does [ILLUSTRATIVE] mean?

Listings on TaxFight currently show illustrative example deals — clearly tagged [Illustrative] — because the marketplace is pre-launch. Once live inventory ships, the tag goes away on real listings. Estimates inside an illustrative listing (rent estimate, DSCR estimate) are bracketed (est) for the same reason.

The rate spine

Every DSCR calculation across all surfaces uses the same FRED MORTGAGE30US rate — pulled live where possible, otherwise the latest observation from the cached rate series. The +0.70% spread above the Treasury is documented OfferMarket pricing for DSCR investor loans, used because investor loans price higher than owner-occupied. The single rate spine means no surface can quietly drift from another.

The rate model (v3)

v3 splits the rate question into two honest pieces — a short-horizon model that we tested and only ship where it has real walk-forward skill, and a 5-year forward cone that is explicitly a range of outcomes, not a forecast. We do not pretend to predict multi-year rates.

Short-horizon model — weekly, real edge at 1 month, no edge at 3

The model is OLS at weekly frequency — the cadence of the Freddie Mac PMMS survey. The textbook Treasury-leg + spread-leg decomposition was tested and discarded: forecasting the 10-year Treasury added noise. The signal that actually exists is the weekly lag-catch-up of the PMMS survey rate to Treasury moves that have already happened. Three features: 10-year Treasury 1-week momentum, 10-year 4-week momentum, and the mortgage–Treasury spread's deviation from its 52-week mean. Walk-forward — at each week the model is fit only on pairs whose outcome was observed strictly before that week, no lookahead.

HorizonModel MAENaive MAEModel hit-rateBeats naive?
1 month (4wk), n=2,4800.1890.20163.5%yes — +6.3% MAE skill
3 month (13wk), n=2,4710.4320.42857.2%no — −1.0% MAE skill
The 3-month model has no edge — and we say so. At a 1-month horizon the model genuinely beats a naive "rate stays flat" forecast: lower MAE and a 63.5% directional hit-rate against naive's 56.3%. At 3 months that edge is gone — the model's MAE (0.432) is fractionally worse than naive (0.428). The monthly version of this model does not beat naive at all; the mortgage rate is too close to a random walk at that frequency. We ship the 1-month forecast and label the 3-month output as a no-edge horizon. The current 1-month live forecast is 6.63% (from 6.51% now) — a small upward catch-up to a 10-year Treasury that has already moved.

The 5-year forward cone — a range, not a prediction

The forward cone draws a central path and a fan of bands out to 2031. It is built from 2,878 weekly MORTGAGE30US observations (1971–2026). Read it as a range of plausible outcomes — multi-year rates are not forecastable and the cone does not claim to be a forecast.

That empirical dispersion is wide and worth seeing plainly. The 10th-to-90th percentile spread of historical rate moves is 0.57 pts at 1 month, 2.47 pts at 1 year, and 6.16 pts at 5 years. The 5-year band runs from roughly 3.0% (p10) to 9.2% (p90) by 2031, around a central path near 5.3%. Anyone underwriting a 5-year hold should size against the band, not the central line.

Display outlier handling

Some IPEDS / Zillow records produce wild values — a college reporting a 29,000% enrollment YoY (probably a coding error), a ZIP with $5M ZHVI and $4k rent (real but breaks the screen). We clamp these for display only:

Condo-basis DSCR — and where it misleads

College and city DSCR is computed on Zillow's condo-tier ZHVI (City_zhvi_uc_condo_tier_…) rather than the all-homes blend. The reason: the investable unit near a campus or in a dense city core is usually a condo or small multifamily — not the detached single-family house that dominates the all-homes index. Pricing DSCR off a $600k median house when the actual buy is a $300k condo would understate yield and overstate the loan. Switching the basis flipped the DSCR sign for 1,133 colleges and shifts every city with a condo series.

The condo basis can also mislead — we flag it. In rust-belt cities the condo tier and the all-homes index diverge hard. Detroit is the clearest case: all-homes ZHVI is $76,488 but the condo-tier ZHVI is $214,676 — nearly 3× higher, and a thin, downtown-skewed condo sample drives it. Underwriting Detroit off the condo basis quietly assumes a luxury-loft cost structure for a market whose detached stock costs a quarter as much. Every record carries an explicit hv_source field naming exactly which series fed the DSCR ("Zillow ZHVI City condo tier" vs the sfrcondo blend) so a reviewer can see the basis and discount it where the two diverge.

What the research found

Several WindMayor surfaces have a research arm — out-of-sample regressions that test whether the patterns we screen on actually predict. We publish these including the failures. A negative R² is reported as a negative R². The point of this page is that a reviewer can trust it; that only works if the losses are as visible as the wins.

BAH regression — the model does not extrapolate

We asked: can local economics predict how fast a base's Basic Allowance for Housing grows? OLS on n=177 military housing areas, target bah_5y_cagr, 80/20 train/test split.

ModelFeaturesR² trainR² testMAPE test
v17 (Zillow + geo + troops)0.240−0.27243.6%
v215 (+ ACS income/education/age, HUD FMR, IRS migration)0.288−0.51046.9%

The only two features that carried a real signal were zhvi_5y_cagr (β ≈ +0.009, p < 1e−5) and zillow_zori_5y_cagr (β ≈ +0.005, p ≈ 0.005). Plainly: BAH growth tracks local home-value and rent growth, and nothing else added signal. Troop count, years active, latitude, distance to coast, education, median age, unemployment, IRS net migration — every one was statistically indistinguishable from zero. Worse, adding those eight features in v2 made the test R² more negative (−0.27 → −0.51): the extra parameters overfit the 142-row training set. A negative test R² means the model predicts held-out BAH worse than the training mean. We do not ship this as a forecast. The honest takeaway is the null result itself: if you want to anticipate BAH, watch Zillow for that ZIP — the DoD schedule is already doing roughly that.

City rent regression — better, but ZHVI-dominated, and migration inverted

Same method, applied to 250-city rent. OLS, n=244, target zori_5y_cagr. R² train 0.482, R² test +0.276, MAPE test 16.8%. A genuinely positive out-of-sample R² — the model does carry real signal — but it is again dominated by zhvi_5y_cagr (β +0.0071, p ≈ 4e−15): home-value growth predicts rent growth.

The migration sign inverted — do not build a long-Phoenix thesis on it. irs_net_migration_2022 entered with a negative coefficient (β = −0.0030, p = 0.0002): in this window, cities gaining the most IRS-filed in-migrants had lower 5-year rent CAGR, not higher. This is almost certainly a COVID base effect — Sun Belt destinations had already repriced rent hard in 2020–2021, so their 5-year-trailing CAGR is measured off an elevated base. The sign is real in the data but it is a window artifact, not a structural law. Do not underwrite a "migration → rent growth" thesis on this coefficient.

AVM v1 — the pipeline is the deliverable; the accuracy is degenerate

The AVM research preview is a hedonic OLS home-value model built entirely on free public data — 7,141 OpenStreetMap building footprints for the Seattle metro, ZIP-level ZHVI as the label.

v1's headline accuracy is not real. v1 reports MAPE 0.43%, MdAPE 0.28%, R² train 0.9991 — numbers that would be extraordinary if they meant anything. They do not. The label is the ZIP's ZHVI, so every building in a ZIP shares the same target value. With ZIP identity in the feature matrix the model simply memorizes ZIP centroids — classic label leakage. The five highest-significance features are all ZIP dummies. We flag this as degenerate. What v1 actually delivers is a working, dependency-free pipeline (OSM → features → OLS → audit-ready coefficients). v2 needs a true per-property label — county assessor parcel data (beds/baths/finished sqft/sale history) — before any accuracy number can be believed.

DSCR rate stress test — who survives a +73bp rate shock

The DSCR stress test reprices every surface at the rate-forecast upper band. Rate now: 6.51% (FRED MORTGAGE30US). Five-year upper band (p90): 7.24% for 2031 — a +73bp shock. Rent and home value are held constant; only the rate moves.

SurfaceAbove 1.0 nowAbove 1.0 stressedDropout
Military bases103−70%
Colleges1,3641,132−17%
Cities7162−13%
Seattle00

Military bases are the fragile surface: at +73bp, 7 of the 10 bases that clear DSCR 1.0 today fall below it — a 70% dropout, with the survivors clustered at razor-thin margins. Seattle shows 0% dropout for the worst reason: no Seattle ZIP clears 1.0 even today (median DSCR 0.16), so there is nothing left to lose — it is already underwater, not resilient.

This is a worst-case static stress, by design. It holds rent and home value frozen and moves only the rate. In real rate cycles bonds and housing often move together — a rate spike usually softens prices too — so actual dropouts will likely be milder. We publish the harsh version because a screen should fail loud, not quiet.

One caveat on vintage: the stress page still reprices against the older forecast_ensemble p90 band (7.24% for 2031) and the pre-v3 flat operating-cost constant. The newer empirical 5-year cone above is wider; a refresh of the stress test onto the v3 cone and the per-state DSCR is a tracked follow-up.

The ZIP spine — zip_master

Every nationwide surface (the ZCTA heatmap, Opportunity Sigma, the zipdata research) is built on one file: zipdata/data/zip_master.json, 31,646 ZCTAs. It joins ACS 5-year 2023 demographics, Zillow ZHVI/ZORI, HUD SAFMR FY2026, BLS county unemployment, IRS 2022–2023 migration flows and several new layers shipped in this round:

Coverage is honest and uneven. ZHVI reaches 82.7% of ZCTAs and ZORI only 26.3% — Zillow simply does not publish a rent index for most rural ZIPs. Some hazard layers are geographically thin by nature (coastal flood 26%, tsunami 5%, volcano 12%). Where a source is missing the field is NULL, never filled from a neighbor. 2,155 very-low-population ZCTAs were dropped outright rather than carried with thin, unstable stats.

The FEMA hazard fix (v4) — a map that was lying

Every FEMA hazard layer on the ZCTA heatmap was wrong, and we shipped it wrong. The fix is worth documenting plainly.

The bug: the hazard layers were national percentiles, not risk. The hazard_* fields, fema_risk_score and fema_eal_score were populated from FEMA NRI's percentile-normalized score columns. A percentile is uniform by construction — its national median is ~50 no matter the hazard. So the wildfire map painted half the country (including the rain-soaked Southeast) warm, and every hazard map looked equally "blown out." Verified against the live FEMA service: the score column was byte-identical to the percentile column.

v4 re-pulls the absolute, dollar-denominated NRI Risk Index Values — the genuinely right-skewed measure where most counties sit near zero and only truly hazardous counties are elevated. Those values are cube-root power-transformed (a monotone transform that keeps the right-skew — a log transform would flatten it back toward normal, re-introducing the very bug) and linearly rescaled 0–100 against the 99.5th percentile. The result is a map that tells the truth:

Hazard layerOld (percentile) medianv4 (absolute) medianv4 p90
Wildfire~5411.749.7
Hurricane~508.842.7
Tornado~5032.768.6
Riverine flood~5035.576.6
Composite fema_risk_score~5033.874.7

The wildfire median dropping from ~54 to 11.7 is the fix in one number: most ZIPs do not face meaningful wildfire risk, and the corrected layer now shows the West hot and the East calm — a right-skewed distribution with a long warm tail instead of a uniform wash. The composite fema_risk_score and fema_eal_score were corrected the same way.

Climate-adjusted yield (v4) — a screen, not a quote

A high gross yield in a hurricane-exposed ZIP is not the same as a high net yield. The climate-yield layer (zipdata/data/climate_yield.json, 29,734 ZIPs) estimates how much of a ZIP's gross yield is eaten by insurance:

insurance_drag_pct = state_dp3_rate * hazard_multiplier(fema_risk_score) climate_adjusted_yield = gross_yield - insurance_drag_pct # state_dp3_rate NAIC per-state DP-3 landlord insurance rate # hazard_multiplier scales the state rate up/down by the ZIP's # FEMA composite hazard — clamped 0.55x to 2.5x

Nationally the median insurance drag is 0.48% of value (about $1,268/yr), and the median ZIP loses 9.9% of its gross yield to insurance. But the spread is the story. Florida ZIPs lose a median 20.1% of gross yield to insurance — followed by Texas (16.4%), Louisiana (15.7%), Rhode Island (15.6%) and California (15.3%). A high-yield Florida ZIP can be a "high-yield-but-uninsured-risk" market: the headline number survives only until the carrier quote arrives.

This is a relative screen, not an insurance quote. Insurance is resolved at the state level; FEMA hazard is resolved at the county level; the hazard→premium multiplier is a labeled, capped assumption, not a measured curve. The DP-3 landlord rate is itself the NAIC HO-3 average ×1.20. The model does not separately price NFIP/private flood insurance, deductibles, wind/hail sublimits, or non-renewal risk. It tells you which markets to discount for insurance drag; a landlord must still get a real carrier quote.

The demand-anchor score (v4)an honest null result

The demand-anchor score asks a reasonable question: does a ZIP's proximity to big, durable employers — military bases, colleges and semiconductor fabs — predict its rent growth? For 28,630 ZIPs we computed a distance-decayed sum (exp(−d/30mi), 90-mile cutoff) of nearby anchor "mass" across 6,236 anchors — troop count for bases, enrollment for colleges, market cap for fabs — weighted up for ZIPs near all three anchor types.

It does not predict appreciation — and we say so. We validated the score against actual 3-year ZORI rent CAGR on 4,525 paired ZIPs. The result is a null: Pearson r = 0.123, R² = 0.015. The top quintile of anchor score grew rent just 0.23 points faster than the bottom quintile over three years. The demand-anchor score does not predict rent growth. What it is — honestly — is a demand-stability indicator: a ZIP ringed by a Navy base, three universities and a chip fab has a structurally diversified tenant base that is unlikely to evaporate. That is a vacancy-risk read, not an appreciation forecast. We ship it labeled as exactly that.

The rent forecast (v4) — making DSCR forward-looking

Spot DSCR is a snapshot — today's rent over today's value. The v4 rent forecast (rate/data/rent_forecast.json) projects where metro rent is heading so DSCR can be read 1 and 3 years forward. The model is a pooled AR(1) mean-reversion on year-over-year rent growth: g(t+h) = a + b·g(t), fit by OLS across all metro-month pairs (29,770 observations) and clamped to the empirical p1–p99 of observed growth. Resolution is metro level — ZIP-level monthly rent is too noisy to forecast honestly.

HorizonModel MAENaive MAESkill vs naiveBeats naive?
1 year, n=91,8733.68 pts4.04 pts+9.1%yes
3 year, n=204,4374.84 pts6.35 pts+23.8%yes
A per-metro AR(1) was tried first — and discarded. Fitting an AR(1) separately per metro overfit badly, producing explosive extrapolations that lost to a naive forecast by 35–50%. The pooled fit (one set of coefficients across all metros) plus the p1–p99 clamp is the honest, stable replacement. Walk-forward tested: at each cut-off month the model is fit only on pairs whose outcome was already observed.

The appreciation forecast (R-MODEL.appreciation-forecast) — the value side

DSCR has two drivers — rent (numerator) and home value (denominator, through the loan). The rent-forecast above makes the rent side forward-looking; the appreciation forecast does the value side. Same model family, same diagnostics, same honesty: pooled AR(1) on YoY home-value growth, clamped to the empirical p1–p99 of observed growth, fit on 72,908 metro-month pairs.

HorizonModel MAENaive MAESkill vs naiveBeats naive?
1 year, n=264,7345.88 pts6.17 pts+4.7%yes
3 year, n=722,7369.14 pts10.06 pts+9.2%yes

The appreciation-forecast skill is real but smaller than rent's (+4.7%/+9.2% vs rent's +9.1%/+23.8%). Home-value growth is highly autocorrelated — sticky momentum means a naive "growth continues at its current pace" baseline is hard to beat. Beating naive by single-digit MAE points at the 1-year horizon, and by ~9% at 3 years, is the honest ceiling on what a pooled AR(1) on a single autocorrelated series will deliver.

Forward DSCR is now paired, not one-sided. With both the rent and appreciation forecasts in place, the forward DSCR projection is dscr_forward_3y = dscr_now × (1+rent_cagr)3 / (1+value_cagr)3 — rising rent lifts it, rising value drags it down (because the loan on the new value is bigger). Coverage: 244 metros. The rent-only convention (dscr_forward_3y_rentonly) is preserved for comparison with the prior surface. Mortgage rate is held at today's level — a stated assumption, not a forecast. A rate-scenario slider on the page lets a user swap in their own rate.

Backtests — does any of this predict, or only describe?

WindMayor sells DSCR and Opportunity Sigma as present-tense screens — can a property cash-flow today, and is its yield statistically unusual relative to peers. Whether either has forward predictive value is a separate question. We backtested both, honestly, and report the result as-is.

DSCR backtest (R-VALIDATE.dscr-backtest) — an honest null

At each backtest date T we computed DSCR for 242–244 cities using only data known at T — point-in-time rent and home-value (from the rent_ts/home_value_ts arrays) and the FRED MORTGAGE30US rate prevailing at T. Then we measured the forward 5-year rent CAGR and value CAGR that actually arrived, and regressed forward growth on DSCR-at-T. Two windows: 2019→2024 (rate ~4.46%) and 2021→2026 (rate ~2.74%).

Windowfwd RENT CAGR ~ DSCR@Tfwd HV CAGR ~ DSCR@T
2019→2024r +0.28, R² 0.077r +0.26, R² 0.066
2021→2026r +0.29, R² 0.084r +0.14, R² 0.020
The honest read: DSCR is weakly positive, not contrarian, not a forward-return predictor. Sign is consistently positive across both windows and both growth measures — high-DSCR cities went on to slightly better growth — but R² tops out at 8% for rent and 2% for value. The lowest-DSCR quintile is a clear laggard (~4.7–5.0%/yr vs ~6–7% elsewhere); the top quintile buys no extra appreciation kicker (Q5 rent growth actually flattens vs Q4). The one strong, robust result is mean reversion: DSCR levels compress over 5 years (d(DSCR) ~ DSCR@T slope ≈ −0.27, R² 0.66–0.72). DSCR is a present-tense cash-flow screen, useful chiefly as a downside filter. We do not market it as predictive of appreciation, and the R² 0.02–0.08 finding is exactly why.

Sigma backtest (R-VALIDATE.sigma-backtest) — same null shape

Same methodology, same windows, same n. Sigma at T is reconstructed by taking point-in-time gross yield and robust-z-scoring it across the cross-section at that date — identical formula to compute_sigma.py, no lookahead.

Windowfwd RENT CAGR ~ Sigma@Tfwd HV CAGR ~ Sigma@T
2019→2024r +0.23, R² 0.054r +0.24, R² 0.058
2021→2026r +0.29, R² 0.086r +0.15, R² 0.023
Sigma is also a present-tense screen, not a forward-return predictor. R² tops out at 9% for rent and 2% for value — the same shape as DSCR. Sigma rankings are extremely sticky (sigma@end ~ sigma@T R² ≈ 0.94–0.95; no meaningful mean reversion). And high-sigma cities took the biggest DSCR hit from the 2021→2026 rate spike (d(DSCR) ~ sigma@T, R² 0.62–0.73) — high current yield = thin operating margin = most exposed to a rate shock. Both backtests converge on the same honest answer: yield-type metrics are good for screening present cash-flow, weak for predicting future returns, and we do not manufacture predictive power the data does not support.

Opportunity Sigma — where to look, not what to buy

Opportunity Sigma scores how unusual a ZIP's yield (or DSCR) is relative to its peers. It is a robust z-score: it uses the median and 1.4826 × MAD (median absolute deviation), not the mean and standard deviation. The reason is that ZIP-level yield has a long fat tail — a handful of $40k-home ZIPs post 90%+ gross yields. A mean/std z-score lets those outliers inflate the spread and quietly flatten everything else; the median/MAD version is not dragged by them.

R-SIGMA.normalize-v2. A reviewer caught a ZIP that scored +39.6σ — not a real anomaly but a Zillow ZORI scrape error ($27,865/mo at ZIP 28570) producing an "impossible" yield. v2 fixes the normalization in two ways:

On the national yield base (n=14,956 after gating) the robust center is 6.19%; the log-space robust spread is 0.377. Band thresholds below apply on the log-yield z-score for the national surface; per-surface sigmas (cities, milbase, collegemap, seattle) keep their own robust scales.

BandRobust |z|Reading
Typical≤ 1In line with peers
Notable1 – 2Stands out; worth a look
Rare2 – 3Far from the pack
Exceptional> 3Extreme — investigate before trusting
A high sigma is not a buy signal. A statistically unusual yield can be three very different things: a genuine bargain, a data artifact (a stale or thin Zillow series), or a market correctly pricing in risk we do not measure — tenant credit, turnover, deferred CapEx, a declining-population county. Sigma tells you where to look. It does not tell you the answer. Every high-sigma ZIP needs the same property-specific diligence as any other.

What the ZIP data says — and the modest R²

We ran the full 31,646-ZIP spine through a correlation matrix, a yield regression and a k-means clustering. The findings are observational — correlation, not causation; nothing below controls for confounders.

The yield regression explains only a quarter of the variance. An OLS on n=27,261 ZIPs — target gross yield, eleven predictors (home value, FEMA risk, unemployment, income, price-per-sqft, migration and more) — lands at R² = 0.246 (adjusted 0.246). That is honest and modest: roughly three-quarters of ZIP-level yield variation is NOT explained by any metric we hold. Yield is mostly local and idiosyncratic. The single strongest predictor is home value (standardized β −0.012; univariate r −0.42) — cheaper ZIPs yield more, which is close to a tautology since yield is rent over price.

Price-per-sqft beats headline price as a yield killer

Among the cleaner findings: price-per-sqft correlates −0.16 with gross yield. Per-sqft price captures land scarcity better than total home value, and is one of the strongest single negative predictors of yield.

Disaster risk tracks HIGHER home values, not lower

The most counter-intuitive result: the FEMA composite risk score correlates +0.34 with home value across 29,734 ZCTAs. The market is not discounting hazard — it is paying up for the same coastal and metro places that score risky.

This is a measurement artifact as much as a market fact. The FEMA risk score embeds expected annual loss, and expected loss scales with the dollar value and density of property in harm's way. So a dense, expensive metro scores "high risk" partly because it is dense and expensive — the score is partly a wealth proxy, not a pure hazard measure. Read the risk/value correlation with that built in. It is the honest reason the sign comes out positive.

One vintage note: this correlation matrix was computed before the v4 FEMA hazard fix described above. The cube-root rescale is monotone, so the sign and broad direction hold, but the exact coefficients should be re-run on the corrected absolute scale — a tracked follow-up.

k-means (k=6) sorts the spine into six archetypes — from High-yield / Cheap ($78k median home, 15.2% gross yield, 1,683 ZIPs) to Highly-educated / Expensive ($666k home, 4.1% yield, 4,890 ZIPs). Cluster boundaries are fuzzy; the names describe centroids, not every member.

New tools (v4)

Two interactive surfaces shipped this round; both read the same audited data the rest of the site uses, no separate pipelines.

The Buy-Box Screener

The Buy-Box Screener filters the full 31,646-ZIP spine against an investor's criteria — yield floor, price ceiling, FEMA risk cap, income, ownership rate and more. It is a pure client-side query over a slim ZIP extract; nothing on it is a recommendation. It is the screen made explicit: set your box, see which ZIPs fall inside it, then do the property-specific diligence.

The AI / Chip Stock Heatmap

The AI / Chip Stock Heatmap tracks 53 public companies across the AI and semiconductor supply chain — returns and metadata from the public Yahoo Finance chart API. It pairs with the fab map, which places the physical fabs and offices on a map. It is a context layer for reading where AI capital is concentrating — not a stock screen, and carries no valuations of private companies, only public-record HQ cities.

Stock-wealth geography (R-MODEL.stock-wealth-geography)heavily caveated

When a public company's stock rises, the equity wealth lands with its employees — through RSUs, ESPP and options — who live near the company's offices. Stock appreciation is therefore a geographically concentrated injection of housing-demand money. The stock-wealth-geography surface estimates this per office, ZIP and metro across the 2021-01 → 2026-05 window.

estimated_inflow = employees_at_office * equity_per_employee[ASSUMED] * (stock_appreciation_factor - 1) * participation_haircut[ASSUMED] # equity_per_employee: $45k–$160k by firm type (megacap, semi, AI lab, etc.) — placeholder # participation_haircut: 0.45 globally (sell-on-vest + top-heavy + non-resident + renter)
This is a model with large, labeled assumptions. The dollar figures depend on assumed equity-per-employee multipliers and an assumed 0.45 participation haircut — neither is measured. Survivorship bias: only today's big winners are in the set; companies whose stock fell or that no longer exist are absent, which overstates net wealth. Private companies (OpenAI, Anthropic, xAI, Scale AI) have no public stock and carry a stated paper-value proxy, not a market price. Treat the ranking of metros as more reliable than the absolute dollars; the surface is a directional read on where stock-market wealth is concentrating, not a comp-grade estimate of household equity by ZIP.

Implied cap rate (R-MODEL.cap-rate) — the unlevered view

DSCR is a levered screen — it asks whether rent covers a real mortgage. The cap-rate page is the unlevered companion: how much yield does the ZIP throw off on the property itself, before financing? Cap rate = NOI / home value, scored on 30,002 ZIPs.

NOI = best_rent * 12 * 0.89 - home_value * (prop_tax_pct + dp3_landlord_ins_pct + 0.50% maint) cap_rate = NOI / home_value # 0.89 = 1 - 5% vacancy - 6% management (canonical, matches DSCR v3) # identical operating-cost model to DSCR v3 — only the denominator changes

National median cap rate: 2.54% (mean 3.31%; p10 0.69%, p90 6.46%). 898 of 30,002 ZIPs show a negative NOI — modeled operating costs exceed effective rent. These are retained as a real signal that modeled carry is upside-down, not nulled. Cap rate is unlevered by definition; pair with DSCR for the levered picture.

This is modeled NOI, not a real T-12. The 3-component operating-cost model (state property tax + state DP-3 insurance + 0.50% maintenance reserve) matches DSCR v3 line-for-line, but real deals carry property management, leasing, utilities, HOA and capex lumpiness this model does not itemize. Modeled NOI — and therefore the cap rate — runs optimistic against a real broker T-12. Insurance and property tax are state averages; a high-hazard or high-millage ZIP inside a state pays more than the state mean. Cap rate is a screen, not a valuation.

What changed in v5 — data fixes, new fields, new models

v5 is the biggest round since v3. DSCR's formula constants are unchanged from v4, but v5 adds:

zip_render / zip_master split (B-DATA.zip-master-bloat + slim_zip_render)

The 78 MB zip_master.json was too large for the heatmap to fetch on every page load. v5 splits it into two files and key-shortens the served one:

Net effect on cold-load (B-PERF.heatmap-load): heatmap critical path went from ~49 MB to ~2.6 MB gz. Shape-first paint draws the ZIP polygons before the data file lands; data layers wash in as zip_render.json arrives.

Data-quality fix: demand_anchor_score was the wrong value (B-DATA-FIX-12)

The demand-anchor merge wrote anchor_score_raw (the raw distance-weighted sum) into the demand_anchor_score slot instead of the headline diversity-weighted value. The correct formula is: headline = anchor_score_raw × (0.4 + 0.6 × type_diversity / 3) — where type_diversity (0–3) rewards a ZIP that draws from all three anchor types rather than a single dominant one. Of 27,535 paired ZIPs, 27,450 carried the wrong value before the fix. The corrected values are now the source of truth in demand_anchor.json; the pipeline no longer lets a "never overwrite" guard silently suppress them.

Same class of bug as the collegemap dscr-stale defect. In both cases a raw intermediate value was written into a headline-named field. Both are fixed in v5. Future audits should check that slot names match their declared formulas.

Data-quality fix: ZIP 28570 corrupt rent (B-DATA-FIX-13)

ZIP 28570 (Morehead City NC) carried a Zillow ZORI best_rent of $27,865/mo — a 24.7× multiple of the HUD FMR ($1,130) and 26× the ACS median rent ($951). The value propagated into zip_render.json and cap_rate.json, producing a computed DSCR of 13.55 for that ZIP. In v5 the corrupt ZORI value is removed; best_rent for 28570 falls back to the ACS value ($951) and is no longer a heatmap outlier.

The fix is generalized at the pipeline level: the rent ladder now guards ZORI against HUD FMR — any ZORI value exceeding 15× FMR is dropped as a scrape error; ZIPs where ZORI runs 6–15× FMR are retained but tagged rent_quality = zori_high_vs_fmr (these are real luxury / vacation-rental markets such as Aspen CO, the Hamptons NY, and Westhampton Beach NY).

Data-quality fix: collegemap DSCR stale (B-COLLEGE.dscr-stale)

Zillow ZHVI and ZORI data for the 6,086 collegemap institutions were refreshed, but the stored dscr and dscr_condo values were not recomputed. A fresh run of the canonical v3 formula against current rent and home-value inputs found 987 SFR rows and 1,746 condo rows whose stored DSCR differed from the recomputed value by more than 0.10. All were corrected; a cross-check confirms 0 stale rows on both bases. The fix also recovered +113 collegemap DSCR rows (5,747 → 5,860) by recomputing off the all-homes price ladder, which covers more rural ZIPs than the condo-only basis the prior pass had narrowed to.

New fields in v5

FieldSourceCoverage
crash_fatal_rate_per_100k NHTSA FARS 2021–2023, 3-year average fatal crashes per 100k county population, mapped from county to 31,324 ZIPs. National median 17.2 per 100k. FATAL crashes only — all-severity crash data is fragmented across 50 state DOTs and not uniformly free; no single nationwide all-severity county dataset exists. Labeled in the data as a "directional risk proxy" for overall auto / car-insurance risk, NOT a comprehensive crash count. 99.0% (3,085 counties)
pop_density_per_sq_mi ACS population / ZIP land area derived from the TopoJSON polygon (d3.geoArea). The heatmap computes this on load from the geometry it already fetches — no separate data pull. 97.8%
broadband_pct FCC National Broadband Map — % of locations with broadband service. 99%
school_score NCES EdFacts SY2019–20 state assessment proficiency rates (reading + math). WA state does not report to EdFacts; rural ZIPs with no K–12 school are NULL. 63.4% (20,078 / 31,646 ZIPs)
traffic_intensity FHWA Highway Performance Monitoring System (HPMS) AADT counts, aggregated to ZIP from road segments. Captures vehicle-trip density as a proxy for commute-flow intensity and Uber / short-term-rental demand geography. live
crime_proxy FBI UCR via County Health Rankings 2022 — violent crime rate per 100k, county-level mapped to ZIP. Labeled a proxy: FBI UCR undercounts (not all agencies report) and measures reported crimes, not actual incidents. 96% (30,383 / 31,646 ZIPs)

New insight tools (v5)

Two new research surfaces published using the v5 data:

DSCR ≥ 1.0 Map

A full characterization of the 1,151 U.S. ZIP codes (4.4% of the 26,177 computable) where rental income covers all operating costs plus a 7.21% DSCR-loan debt service at 80% LTV. The finding: 95% of cash-flowing ZIPs have home values under $200k and are concentrated in Appalachia (WV, KY), the Rust Belt (OH, MI, IL, PA) and the Deep South (AL, MS, LA). A second category — the Hamptons, Fort Myers Beach, Kauai — shows DSCR ≥ 1.0 because ZORI captures vacation-rental pricing, a different investment thesis. Median DSCR among positive ZIPs: 1.28× at a $97k median home value with 12.2% gross yield.

Portfolio Insurance-Risk Tool

Paste any list of ZIP codes — a portfolio you own, a market you are underwriting, or a comparison set — and receive an aggregate FEMA risk distribution, total annual insurance drag in dollars, yield impact (gross vs. climate-adjusted), and a per-property table. Covers 29,734 ZIPs, fully client-side. Five preset portfolios: Rust Belt cash-flow ZIPs, coastal metros, Sun Belt, high-wildfire exposure, and hurricane alley.

Audit — real data, sourced, no fabrication 90 / 90 PASS

The most consequential claim WindMayor makes is that the numbers on screen come from real public data, traceable to source, with no fabrication. T-DATA.source-spotcheck (re-run 2026-05-22) is the independent audit of that claim. Methodology: pick a random 5-row sample from each surface (deterministic seed=2026), grab one or two cited numeric fields per row, and trace each back to the original public source — fetching the source file fresh during the audit itself for live APIs.

SurfaceRowsPassFail
seattle (ZHVI + ZORI ZIP)10100
college (ZHVI + ZORI ZIP/city/condo + HUD FMR)10100
cities (ZHVI City + ZORI City)10100
milbase (DoD BAH + ZHVI metro)10100
zip_render (ACS B19013 / B01003 + declared rent_source)15150
crash_by_county (NHTSA FARS formula identity)550
cap_rate (NOI/HV formula identity)550
climate_yield (state DP3 × hazard mult identity)550
demand_anchor (raw × diversity identity)550
rate_spine (FRED MORTGAGE30US live)550
insurance (NAIC 2022 HO-3 published values + DP-3 uplift)10100
TOTAL90900

Across 11 distinct data surfaces and 7 independent public sources every stored value traced to source to the dollar, with the worst observed delta = 0.19% (a cap-rate row) explained entirely by stored 4-decimal rounding of NOI and home-value before division. Where a ZIP has no Zillow coverage, the row honestly cites a fallback (HUD FMR or Zillow City) instead of fabricating — and the fallback value is also verified.

Worst mismatch: none. No silent fallback fills, no fabricated values, no source-mismatched rows. The audit is reproducible: run python3 projects/scripts/source_spotcheck.py (seed=2026, raw matrix written to /tmp/source_spotcheck.json) and you should see the same 90 / 90.

Sources & attribution

Disclaimer

WindMayor is a research and underwriting screen, not investment advice, not legal advice, not tax advice. Numbers are screens for further diligence, not closing-grade values. Past data is not prediction. Real deals require property-specific underwriting with current local comparables.