heat_index_anchor
heat_index_anchor is a master switch wired to how hot it is about to feel in the hottest big American city. Air temperature on its own is a poor description of heat. Ninety-five degrees in Phoenix and ninety-five in Houston are different events — one you walk around in, the other you don't — and the difference is the humidity, which decides whether sweat can still cool you. So every three hours we ask one free weather API for the "feels-like" high over the next three days in sixteen major metros, keep the hottest single city and the population-weighted national average, and let you gate a bot on either. While your level holds, the bot trades. While it doesn't, the bot places no trades at all that cycle, in any market. This is, on the evidence below, the best-built signal in this dictionary — and it has nothing to trade.
- Bots using it
- 0 (none live, none out-of-sample, none ever)
- Data source
- Open-Meteo /v1/forecast — the registry says “undocumented”
- Refresh
- Every 3 hours (35 */3 * * *)
- Rows stored
- 240 readings 30 days — the rest is deleted
- Backtest-replayable
- No — and the stated reason is false, see catch #6
- Anchor module
- quants/heat_index_anchor.py
Start with the good news, because for once there is a lot of it and it comes first. The premise is real physics, not folklore. The pipeline is the healthiest in this dictionary: 459 of 459 scheduled runs since the middle of June are accounted for, with one failure. The freshness check is written correctly, which is rarer here than it should be. And unlike its closest sibling ensemble_anchor — same vendor, same three-hourly rhythm, same author — this number really does measure the weather: 79.3% of its variation is which day it is, and only 2.6% is what time we happened to ask.
Now the two things that matter. The first is that there is no heat market. Not a thin one — none. Across 538,368 Kalshi rows we have ingested, the number whose title mentions heat, or a heat index, or a heat advisory, is zero. Kalshi's weather markets are brackets on the dry-bulb air temperature at one airport thermometer. On Polymarket, every heat-advisory contract in existence is a single market about Phoenix with $80 of volume in it. The builder, the one-click recipe and the starter bot all promise this is "the read that drives extreme-heat / heat-advisory markets". Those markets are not there.
The second is subtler and more interesting than the usual finding on these pages. Every threshold this site ships sits off the end of the data we keep — the builder's default of 100 °F was open on 100.00% of our 240 readings, because the lowest reading we hold is 106. But that is not the threshold's fault. We keep thirty days, and they are the thirty days of the year when the answer is always yes. Reconstructing 5.6 years from a free archive the code says doesn't exist, that same 100 °F gate is open about 40% of the time — nothing in November through February, all of July and August. It is a well-chosen number. Our memory is the defect, not the setting. What you are mostly buying, though, is a calendar: the gate gives the same answer as "is the month May to September" on 93.7% of 2,048 days. In the shoulder months it becomes something sharper — a real heat-anomaly detector — and catch #3 is where I had to correct myself on that.
Where the number actually comes from
One HTTP request, no key, no account. predictive/heat_index_poller.py builds a single batched call to api.open-meteo.com/v1/forecast asking for daily=apparent_temperature_max in Fahrenheit at sixteen metro coordinates, with timezone=auto and forecast_days=3. Verified live from production while writing this: HTTP 200 in 0.70 s. The metros are the sixteen biggest American markets — 111.9 million people — and it is byte-for-byte the same list used by degree_days_anchor, wind_anchor and aqi_anchor, which I checked rather than assumed.
For each metro the poller takes the highest feels-like value in the three-day window, then reduces the sixteen to two national numbers: peak_hi, the single hottest metro, rounded to a whole degree; and mean_hi, the population-weighted average, to one decimal. It also stores the name of the hottest metro and how many metros answered — a small thing that turns out to matter, because it is the only reason the analysis further down this page is possible at all. Fewer than eight usable metros and it writes nothing. The row lands in heat_index in predictive.db on cron 35 */3 * * * — eight times a day. The table holds 240 rows covering 14 July to 13 August 2026; everything older is deleted.
The pipe is demonstrably connected. Running the poller's own compute() live returned (108.0, 94.8, 'Dallas-Ft Worth', 16), matching the newest stored row exactly.
What the registry gets wrong
The registry reports this signal's data source as "undocumented". It isn't. The anchor's docstring says, in plain English, "a free, keyless Open-Meteo daily forecast of the maximum apparent temperature". The cause is duller than a bug and worth knowing if you read the registry output for any other signal: SOURCE_HINTS in quants/signal_registry.py is a hand-maintained list of vendor names to look for, and Open-Meteo is not in it. Not misspelt — absent. So the vendor behind five of our weather signals is undetectable by construction. This is a harder version of the same artefact that hit launch_anchor and ensemble_anchor, where at least the excuse was that the registry only reads the anchor's docstring and the vendor was named in the poller's. Here it is named in the file the registry does read, and still missed.
Everything else resolves correctly — poller, cron, table, replayable: false, and live_bots: 0, where for once 0 really does mean zero. And the backlog that queued this page flagged it "NO DOCSTRING"; it has a 24-line one and the registry's own documented field says true. That annotation has now been wrong on every signal it was applied to.
What it does to your bot
It is a switch on the whole strategy, not a filter on related markets. In quants/engine.py a failing heat gate does return [] — the bot produces no candidates at all that cycle, in every category it is configured for. Your crypto leg, your politics leg, your baseball leg: all of them stand down because it isn't hot enough in Phoenix. That is worth saying plainly because the builder presents this beside per-market filters and it does not behave like one.
You pick a metric and a level. peak asks "is any big city about to feel dangerously hot" — a max across sixteen. mean asks about the broad national regime. Then above or below a temperature in °F, and the comparisons are strict, so above: 100 excludes exactly 100.
The catch
Eleven of them, worst first. The unusual thing about this list is how much of it is not the plumbing's fault — read the case for the defence at the end before you write this signal off, because it is the strongest one in this dictionary.
1. 🔴 There is no heat market. Not a thin one — none.
This is the whole ballgame. The builder's description, the one-click recipe and the starter bot's blurb all say this signal reads "the heat that drives extreme-heat / heat-advisory markets". I went looking for those markets. Of the 538,368 Kalshi market rows in our database, the number whose title contains "heat", "heat index", "advisory", "excessive heat" or "feels like" is zero.
What Kalshi lists instead is brackets on the dry-bulb air temperature at a single airport thermometer — ticker families KXHIGHT* and KXLOWT* across twenty cities, with titles like "Will the maximum temperature be 83-84° on May 21, 2026?". To be precise about the scope of that claim: every one of the 26,852 weather-category Kalshi rows we hold is a daily high or low air-temperature bracket — there is no other kind in our data. Our Kalshi ingest is curated rather than exhaustive, so this is a statement about the markets we actually see, not a census of Kalshi's whole catalogue. But it is the universe any bot of ours could trade. Air temperature is precisely the quantity this signal deliberately throws away and replaces. And they are not close substitutes: measured live across our own sixteen metros, the feels-like high runs +5.19 °F above the air temperature on average, ranging from +0.4 °F in Seattle to +15.8 °F in Miami. So the gap is not a constant you could mentally subtract; it is a different number in every city.
On Polymarket a live search returns exactly one heat-weather market anywhere on the book: "Will Phoenix be under an Extreme Heat Warning for 10+ days in August 2026?" It carries $80 of total volume, and it resolves on the number of days the National Weather Service has zone AZZ543 under an Extreme Heat Warning — a bureaucratic count this signal does not compute, from a product it does not read. Heat Advisories explicitly don't count toward it. Every one of the seventeen Polymarket titles in our own data matching "heat" is the Miami Heat basketball team, a tennis player named Heather, or "will the US economy be overheating".
And the starter bot we ship is configured categories: ['weather'] — so in practice it would gate air-temperature brackets on a feels-like number.
The fair version: heat obviously does move air-temperature markets, so using a heat signal in front of temperature brackets is not absurd — a humid, hot air mass raises both. But if that is the trade you want, the quantity you want is the air temperature, and it is a different field in the very same Open-Meteo response we already pay nothing for. The defect is that the tin says heat-advisory markets and there is one of those in the world, worth eighty dollars.
2. 🔴 Every setting we ship is off the end of the data we keep — because we keep the wrong thirty days
Three places recommend a level, and all three say the same thing: the builder's field default is 100 with metric peak; the builder's one-click recipe "Heat-wave regime" is {metric: peak, above: 100}; and the starter bot Heat-Wave Watch 🔥 ships {metric: 'peak', above: 100} on weather markets priced 30–60¢. Against the 240 readings we hold, that gate was open on 100.00% of them — 240 of 240 — because the lowest peak_hi in the table is 106. So is above: 50, and above: 90, and above: 105. The docstring's second example, {mean, above: 85}, is also 100.00% open; our lowest mean_hi is 93.0.
The starter's blurb says "When the country cools off it simply stands down." In 240 readings it has never once stood down. It also offers "flip it to below" as the level-up, and below: 100 is 0.00% open on everything we hold.
The threshold is not dead, though — our memory is what makes it look dead. We retain thirty days, and they happen to be mid-July to mid-August. Reconstructing 2,048 days from an archive the code says doesn't exist (see catch #6), peak > 100 is open 40.2% of the year — 0.0% in November, December, January and February, 59.7% in May, 99.4% in June, 100% in July and August, 93.3% in September and 18.7% in October. Every one of the five prior years agrees: 35.3%, 40.3%, 41.4%, 43.2%, 39.2%. (Read that as ~40–44%: my reconstruction runs 1.74 °F cooler than our own live rows, and correcting for that lifts it to 44.3%. The offset is measured on 28 mid-summer days, so it may be seasonal noise rather than a standing archive bias — either way the monthly pattern is saturated at 0% and 100% and doesn't move.)
So there are two defects here, not one, and the second is the one that survives. The first is that our thirty days are 1.5% of the reconstructable record and they are the slice where the answer is always yes, so from our own data it is impossible to tell a good gate from a broken one. The second is what the retention was hiding: a 40% duty cycle is not evidence of good calibration, because May-to-September is 41.9% of the year. The gate is not tuned to heat; its duty cycle is just the length of summer. And 100 °F is not a tail on this scale at all — it sits at the 59.8th percentile of the year. The median national feels-like peak is 96 °F; the 90th percentile is 114 and the 99th is 120. A setting sold as "dangerous heat is incoming" is pitched a few degrees above the middle of the distribution.
One shipped example is genuinely dead, and now I can say so with five years behind it rather than one month: the docstring's third example {peak, below: 50} was satisfied on 0 of 2,048 days. The lowest national feels-like peak in 5.6 years is 68 °F. Because peak is a max over sixteen metros over three days, and Miami and Phoenix exist, it cannot get there. Nothing warns you.
3. 🟠 Most of what it reads is the calendar — but the part that isn't is real
Granting everything in catch #2 — the level is sensible and the duty cycle is a real 40% — the question left is what those 40% of days have in common. Mostly: they are summer.
Fit a day-of-year climatology to the 2,048 reconstructed readings and it explains R² = 0.9132 of peak_hi (0.9408 for mean_hi). Standard deviation of the level is 12.07 °F; of the departure from the seasonal norm, 3.56 °F. Put more bluntly: peak > 100 gives the identical answer to "is the month May to September" on 93.70% of the 2,048 days. It flips regime 45 times in 2,048 days — about twice a year, on in spring and off in autumn, with a longest open run of 155 days and a longest closed run of 222. So "only trade when dangerous heat is incoming" is delivered, most of the time, as "only trade in summer" — which you can compute from a calendar without an API, a poller or a table.
But I nearly published a stronger claim than the evidence supports, so here is the correction. The obvious test of "is there real weather in here" is to split the days by how abnormal they were for the date. Done naively that gives an answer of zero: the gate was open on 38.7% of the most abnormally hot decile, which is below the 40.2% base rate — literally no lift at all. But that test is confounded and worthless in both directions: a +16 °F anomaly in January still lands nowhere near 100 °F, so most days cannot respond to the anomaly however hot they are, and they drown out the days that can. (The 19.6% for the coolest decile is not skill either; it is cool summer days falling back through the line.)
Restrict to the days where the gate is genuinely contested — where the seasonal norm sits within 8 °F of the 100 °F line, which is 723 of the 2,048 days — and the picture changes completely. On the coolest anomaly decile the gate was open 5.6% of the time; on the hottest, 69.4%. Across terciles: 21.2%, 46.9%, 53.5%. Month by month, the days it opens are measurably the abnormally hot ones — in March the open days averaged +12.9 °F hotter than the shut days, in April +6.6, May +3.8, September +3.5, October +3.0.
And the cleanest version of all: of the 129 days where the gate disagrees with the May-to-September calendar, the 86 where it shut during the season average −2.39 °F for the date, and the 43 where it opened outside the season average +4.40 °F — while the 1,919 days where gate and calendar agree average +0.01 °F. If the gate were just a noisy calendar, all three of those would be zero. It departs from the calendar exactly when the weather does, and in the right direction.
Put on a proper footing: fit open ~ anomaly across the four months where the gate is neither always-on nor always-off (May, June, September, October; n = 671) and each extra degree above the seasonal norm multiplies the odds of the gate opening by 1.32, with the anomaly separating open from shut days at AUC 0.697. That is a modest but unambiguous real signal, and it exists only in those months.
So the honest statement is narrower than "it's a calendar". As a year-round switch it duplicates the month 93.7% of the time. In the shoulder months — roughly a third of the year — it is a genuine heat-anomaly detector, and a fairly sharp one. The defect is that nothing tells you which of those two things you are buying, and the shipped copy sells the second while the duty cycle mostly delivers the first.
4. 🟠 It is not the heat index — and the disagreement has a direction
The signal is called heat_index_anchor, its table is heat_index, and the builder labels it "Heat index (feels-like)". The field it reads is Open-Meteo's apparent_temperature_max, and by Open-Meteo's own documentation that is "the perceived feels-like temperature combining wind chill factor, relative humidity and solar radiation". The US heat index is a different quantity: the Rothfusz regression on temperature and relative humidity only, for a person in the shade in light wind — and the NWS does not apply the regression at all below about 80 °F.
I did not take the solar part on the vendor's word, because documentation copy and implementation often disagree. Holding temperature (78–88 °F), humidity (50–70%) and wind (4–9 mph) inside narrow bands across 6,528 hourly samples, the apparent-minus-air gap climbs monotonically with sunshine: +4.44 °F under 150 W/m² of shortwave radiation, +5.21 at 450–600, +6.82 at 750–900 and +8.03 °F above 900. In darkness it is +4.61 °F; in full sun +6.70 — a +2.09 °F lift from sunshine alone, at otherwise identical conditions (r = 0.43). So the documentation is right, and it is worth knowing the split: humidity does most of the work, and the sun adds roughly two degrees on top that the official heat index does not count at all.
I computed the official heat index from the same hourly temperature and humidity for the same sixteen metros over the same thirty days — 480 metro-days — and compared. Our number is hotter on 75.8% of them, by a mean of +1.66 °F. But it is not an offset you can correct for: the tenth percentile is −2.03 and the ninetieth is +4.91, and the extremes run −9.94 to +9.03 °F. The disagreement is systematic by climate: dry or cool cities read hotter on our number (Denver +7.4, San Francisco +4.7, Seattle +3.9, Phoenix +3.8, Los Angeles +3.5) and hot humid cities read cooler (Miami −7.7, New York −5.5, Dallas −4.9, Philadelphia −4.5). Which is exactly what you would expect from adding sunshine everywhere and weighting humidity less.
The honest size of this. I expected it to be worse than it is. At the level the gate actually reads — the national maximum — taking a max across sixteen metros washes most of it out: our peak averages 113.8 °F against 112.8 °F on the official index, a gap of only +0.94 °F, and the two definitions crown the same hottest city on 24 of 30 days (80%). So this is not "the number is wrong by five degrees". It is that you cannot translate a threshold: a level you read in any heat-advisory context is defined on a scale we are not using, and per city the error is up to ten degrees in either direction. The one visible consequence is a ranking flip at the top — over these thirty days Dallas's hottest heat-index day (123.4 °F) beat Phoenix's (117.8 °F), while on our number Phoenix (121.6) beat Dallas (118.5).
5. 🟠 Which city sets it swings with the season, and six of the sixteen never do
peak is a max, and a max is one city wearing a national badge. Over our thirty days that city is Phoenix on 86.3% of readings (Dallas 10.0%, Houston 2.9%, Washington DC 0.8%) — which would make a humidity-folding "heat stress" metric a description of a desert afternoon. Except that is an artefact of the window too: over 5.6 years the metro that most often sets the national number is Miami, on 42.7% of days, ahead of Phoenix on 33.3%, Houston 10.9% and Dallas 8.0%. Phoenix spikes in high summer; Miami's feels-like stays high across far more of the year. So who the signal is "about" changes with the calendar, and our records only ever show you one answer.
Six of the sixteen metros have never set the peak once in 2,048 days — Chicago, Boston, San Francisco, Detroit, Minneapolis and Denver. They affect mean_hi and nothing else. Detroit is the sharpest illustration: it is polled every three hours, it has never set the number, and it is the one metro of our sixteen with no Kalshi temperature market at all. Meanwhile Las Vegas — which Kalshi does list, and which competes with Phoenix for hottest city in America — is not in our metro list, along with Austin, New Orleans, Oklahoma City and San Antonio. The set we average is neither the hottest cities nor the tradeable ones.
6. 🟠 Not backtest-replayable — and the stated reason is false
heat_index_anchor appears nowhere in quants/backtest.py: not in _SUPPORTED_ENTRY, and not even in the documentary _UNSUPPORTED_ENTRY list, which stops at arb_anchor in June. It is caught by the catch-all that flags any entry key not explicitly supported — which is the designed safety net and worked. The consequence is the one that matters: a backtest containing this signal runs without the gate, returns a full equity curve, and reports unsupported_rules alongside it.
The poller's docstring explains why: "Open-Meteo's free forecast is forward-only (no archive here), so the signal is live-only". That is not true. Verified live from production, both free and keyless, both HTTP 200: Open-Meteo's historical-forecast API serves apparent_temperature_max back to 2021, and its ERA5 archive serves it back to 1940. I rebuilt 2,048 days from the first of those using the poller's own arithmetic, and everything in catch #2, #3 and #5 above comes from it. The history was one HTTP request away the whole time.
One real subtlety, in the code's favour. "Feels-like" is product-defined in a way air temperature is not, and the two archives do not agree with each other: for the same July 2022 days the historical-forecast archive gave 112.3 / 109.2 / 103.1 °F where ERA5 gave 108.2 / 101.7 / 100.7 — up to 7.5 °F apart — while their temperature_2m_max values agreed to within a degree. And my reconstruction runs 1.74 °F cooler than what our poller actually recorded on the 28 overlapping days (mean absolute difference 2.63 °F). So a backfill here needs care about which archive, and it is good enough for base rates — which are nowhere near the margins, being 0% in winter and 100% in July — but it would not be a tick-accurate replay. That is a real obstacle. It is not the stated one.
7. 🟡 The freshness check proves the poller ran, not that the forecast is fresh
The table's schema comments as_of TEXT, # forecast issue time (UTC ISO). The insert passes the current timestamp for both as_of and fetched_at, so the two are identical in 240 of 240 rows and no row records when the forecast it contains was actually issued. The gate's 6-hour staleness test therefore establishes that our cron fired, not that the weather model has run since. Identical defect to ensemble_anchor. It matters less here than it does there — a three-day maximum moves slowly, which is the whole reason a three-hourly poll is defensible — but the column is mislabelled and something built on it later will be misled.
8. 🟡 The three-day window contains a day that has already happened — and here it barely matters
forecast_days=3 with timezone=auto means "today plus two, in each city's own local time". At the 00:35 UTC poll every American city is still on the previous local evening, so the maximum can be set by a day that is essentially over. This is the defect that dominates ensemble_anchor, where it accounts for 70% of the signal.
Measured here, it is almost nothing — and this is the good news the last page asked for. Hour of day explains 2.6% of the variance in peak_hi (3.2% for mean_hi), against 79.3% for which calendar day it is (83.1%). Across the eight daily poll slots the average peak runs 113.7 to 115.7 °F — a two-degree spread on a signal whose day-to-day range is seventeen. Taking a maximum over three days is what saves it: one stale day inside a three-day window rarely changes the max. It is still a design smell, and it is still genuinely a forecast rather than a nowcast — you are gating today's trades partly on Friday's Phoenix sunshine, which will be revised.
9. 🟡 Impossible configurations validate, including one below absolute zero
{metric: peak, above: 100, below: 50} passes validate_config and renders as "only when hottest-metro feels-like high > 100°F and hottest-metro feels-like high < 50°F". That gate can never open and nothing says so — the same hole documented on finance_anchor, crypto_momentum_anchor and btc_dominance_anchor. {above: 200} validates. So does {below: −500}, which is below absolute zero.
Credit where it is due: the validator is otherwise the strictest of the weather anchors — it rejects booleans, strings, an unknown metric and a missing condition, each with a useful message. And it accepts negative numbers, which on this signal is correct and not a bug: apparent temperature folds in wind chill and genuinely goes below zero in an American winter. Contrast degree_days_anchor, where rejecting negatives is the right call. There is simply no physical bound.
10. 🟡 The thirty-day prune keeps thirty-one
DELETE FROM heat_index WHERE fetched_at < datetime('now','-30 days') compares an ISO-8601 string like 2026-07-14T00:35:02+00:00 against SQLite's 2026-07-14 00:35:02 as text, and 'T' > ' ', so the cut-off day never prunes. Real retention is a day more than advertised. This is now the seventh poller in this dictionary with the same line, and here — unlike on crypto_momentum_anchor, where it is the difference between keeping a week and keeping nothing useful — it is harmless. Listed for completeness.
11. 🟡 Not a defect in the signal — a licensing question for Dave
Open-Meteo's terms of use, read from their own site: "You may only use the free API services for non-commercial purposes", with the free tier capped under 10,000 calls a day. Our call volume is nowhere near the cap — sixteen coordinates in one batched request, eight times a day. The non-commercial clause is the part worth a look, because TinyCorp sells a paid plan, and five other signals ride the same vendor. That is a question for a human, not a bug in this module, and it is recorded here rather than quietly left out.
The case for the defence — the strongest in this dictionary
Almost every page in this dictionary ends up describing a pipeline that is broken, stale or lying. This one does not, and it would be dishonest to leave it filed with the others.
- It really does measure the weather. 79.3% of the variation in peak_hi is which day it is; 2.6% is what time we asked. That is the exact inverse of ensemble_anchor, built by the same hand on the same vendor, where the clock explains 70%.
- The healthiest pipeline here, by a clear margin. Every one of the 459 scheduled runs since the file was written on 16 June is accounted for: 458 successes and one failure. The failure was a disk I/O error inside CREATE TABLE IF NOT EXISTS, before the insert — so it wrote nothing and corrupted nothing. There are zero database is locked failures, the error that has hit seven other pollers in this dictionary; this cron sits at :35, clear of the backtest index's 1,11,21,31,41,51. And ok: False — the poller's own "the vendor gave me nothing usable" path — has never once been logged.
- The freshness check is written correctly, and has never needed to fire. It parses the stored timestamp into a real timezone-aware datetime and fails closed if that parse throws — not the string comparison that silently defeats the same check on finance_anchor and tropical_anchor. The largest gap between consecutive rows in the whole table is 360.0 minutes against a 360-minute threshold — it passed by zero seconds, and only because the comparison is strict.
- The poll rate isn't wasted. 7.62 distinct readings per complete day out of eight polls; only 4.6% of consecutive rows are identical. Compare ensemble_anchor, where eight polls produce exactly five distinct forecasts and 37% of consecutive rows are byte-identical.
- It records what it chose. hottest_metro and n_metros are both stored on every row, and both were 16/16 throughout. That is why catch #5 is measurable at all — ensemble_anchor's max metric throws the winning city away, and degree_days_anchor stores no metro count, so neither can be audited the same way.
- The shipped threshold is alive, on five years of evidence. 100 °F is open 40.2% of the year, flips about twice annually, and behaves identically across 2021–2026. Set against btc_dominance_anchor, whose shipped default has been unable to open since 2024, that is a real gate with a real duty cycle. It is not proof that the level was well chosen — 40% is roughly the length of summer, which is catch #2 — but "not dead" is worth something, and it is more than most settings in this dictionary can claim.
- There is genuine weather in it, where it can be. In the four months when the gate is neither always-on nor always-off, each degree above the seasonal norm raises the odds of it opening by 1.32× (AUC 0.697), and the days it opens out of season run +4.40 °F hot while the days it shuts in season run −2.39 °F cool. That is a real instrument having a real opinion, and I only found it after throwing out my own first, confounded test of the same question.
- The premise is physics, not folklore. Humidity-adjusted heat stress is a real quantity, it is what public-health warnings are built on, and it drives summer power demand. Nothing on this page argues that heat doesn't matter. It argues we measure it on the wrong scale, for a market that doesn't exist, and then delete the evidence after thirty days.
The real record
There isn't one, and this page will not manufacture one. No bot has ever used this signal — not live, not out-of-sample, not archived, not a draft. Zero of the 76 strategy configs in quants.db (21 live, 15 out-of-sample, 36 archived, 4 draft) mention heat_index_anchor, and zero of the 88 historical strategy versions do either. There are no trades, no fills, no evaluations, no P&L, and no win rate. Any number in those columns would be invented.
For context on how normal that is here: of the seven weather signals we poll every three hours, all seven have zero bots. The only weather signal anything actually trades is wx_anchor, which appears in ten configs — and it reads the air temperature.
What this page does not tell you
Whether the feels-like high predicts anything about the air-temperature brackets Kalshi actually lists. Nobody has tested it, including me. It is now a cheap test rather than an impossible one: the forecast history is free back to 2021 (catch #6), we hold 430,000 station observations, and 538,000 rows of Kalshi market history sit in the same database. Until somebody runs it, "humid heat is mispriced in temperature brackets" is a reasonable belief and nothing more. I also did not measure how much the three-day-ahead forecast differs from what verified — only that our live readings ran 1.74 °F warmer than the archive's version of the same days, which is suggestive of a warm-leaning forecast and not proof of one.
Three more things a trader would reasonably ask that are not answered here. Which of the three forecast days actually sets the maximum — the poller throws that away, so a reading could be tonight's certainty or Friday's guess and the row looks identical either way. Whether the three-hourly poll adds anything over yesterday's value plus the date, which given the 91% seasonal R² is the obvious next test. And what the gate is worth conditional on being open — whether temperature brackets behave differently on open days versus shut ones, tested in the shoulder months where the gate carries information rather than pooled across a year where it mostly restates the month.
How to actually use it
Don't take a level from the heat-advisory world. Anything you read about heat indices of 100 or 105 is defined on the NWS shade scale, and we are not on it (catch #4). Pick your level off our numbers or the monthly ranges in the diagram above.
If you want a summer switch, this is a good one — and say that's what it is. 100 °F on peak is open about 40% of the year with clean spring-on, autumn-off behaviour. That is a legitimate thing to want. It is not "dangerous heat is incoming".
If you want actual heat stress, use mean, not peak. The population-weighted average moves with the whole country instead of handing the decision to whichever single desert or subtropical city is hottest that week. Across 5.6 years mean > 85 is open 34.0%, and 92 or 94 tightens it sensibly.
Don't read a quiet run as a verdict. A backtest containing this signal ran without it, and returned a curve anyway. And no result here can be attributed to this gate, because no bot has ever had it switched on.
Where to go next
ensemble_anchor is the one to read beside this, as the controlled comparison: same vendor, same three-hourly cron, same author, same sixteen-or-so cities — and the opposite result. There the clock explains 70% of the signal and the weather 16%; here the weather explains 79% and the clock 2.6%. The difference is one parameter, three forecast days instead of one. degree_days_anchor is the closest sibling — literally the same sixteen metros, verified byte-for-byte — and the same finding in a different costume: 96% of that one is the calendar, 91% of this one is. wx_anchor is where the instrument actually is: the only weather signal with live bots, trading the very air-temperature brackets this signal sits in front of without measuring. And btc_dominance_anchor is the instructive contrast on catch #2 — there the shipped default had been unable to open for 800 days, which is what a genuinely badly-chosen threshold looks like next to this one.
The remaining weather signals on this rhythm — qpf_anchor, wind_anchor, sst_anchor and aqi_anchor — have no profile pages yet and no bots either. Three of them share this exact metro list, and Open-Meteo's archive serves their variables too, so the "live-only" claim in catch #6 should be tested on each rather than believed.
Written 13 August 2026. Every number on this page was read from production that day — the live host at /var/www/tinycorp.ai, not a local mirror: the output of quants/signal_registry.py, the source of quants/heat_index_anchor.py, predictive/heat_index_poller.py, quants/engine.py, quants/backtest.py, app.py, static/builder-signals.js and static/starters.js, the live crontab, the poller's log at data/heat-index-poller.log, read-only queries against heat_index, kalshi_markets and polymarket_markets in predictive.db and all 76 strategy configs and 88 strategy versions in quants.db, and live calls to Open-Meteo's forecast, historical-forecast and ERA5-archive endpoints, to Polymarket's public API, and to Open-Meteo's own documentation and terms pages — all made directly from that same host. The 2,048-day reconstruction applies the poller's own arithmetic to Open-Meteo's historical-forecast archive for the identical sixteen coordinates, 1 January 2021 to 10 August 2026, and is validated against our own stored rows on the 28 overlapping days. The NWS heat index figures use the official Rothfusz regression, including its dry and humid adjustments, on the same hourly temperature and humidity series. The variance splits are one-way decompositions over the 240 stored readings; the climatology R², the anomaly tests and the logistic fit are computed over the 2,048 reconstructed days. The solar-radiation test in catch #4 holds temperature, humidity and wind inside narrow bands across 6,528 hourly samples from 16 metros over 17 days. No performance figures appear on this page because no bot has ever used this signal. All signals →