wind_anchor
wind_anchor is a master switch wired to how hard the wind is forecast to gust in the windiest of sixteen big American cities. Every three hours we ask one free weather API for the strongest gust expected in each metro over the next two days, and keep two numbers: the single largest of the sixteen, and the population-weighted national average of them. While your level holds, the bot trades. While it doesn't, the bot places no trades at all that cycle, in any market. A gust is a brief spike, not the steady wind — which turns out to matter a great deal, because every official definition of a windstorm is written in terms of both.
- 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 (53 */3 * * *)
- Rows stored
- 241 readings 30 days — the rest is deleted
- Backtest-replayable
- No — see catch #7 for what it would take
- Anchor module
- quants/wind_anchor.py
Start with the fact that decides everything else. There is no wind market. I pulled Kalshi's entire series catalogue — 12,940 series across eighteen categories — and searched every ticker and title for wind, gust, gale and derecho. The count is zero. Kalshi lists 334 weather series: daily highs and lows in dozens of cities, rain, snow, hurricanes, air quality, earthquakes, drought, Lake Mead, even cloud cover during an eclipse. Not one contract on how hard the wind blows. Polymarket, across 124,745 distinct titles we have ingested, has ever listed exactly three: “Will the highest recorded wind on Mt. Washington in July be at least 90 / 95 / 100 mph?” — $63,934 of combined volume, all resolved YES, all closed on 31 July. Mount Washington is a 6,288-foot summit in New Hampshire famous for having the worst weather in America. It is not one of our sixteen metros, and Polymarket filed those three under other, so the starter bot we ship — which filters on categories: ['weather'] — would not have been allowed to touch them anyway.
That is the honest headline, and it is the opposite of the one on qpf_anchor, where a liquid rain market existed and we simply weren't ingesting it. Here the exchange has looked at wind and declined.
The second finding is what happened when I stopped asking whether anyone trades this and started asking whether it is even true. Gusts, unlike almost everything else in this dictionary, can be checked against an official observation: the National Weather Service publishes the peak gust recorded every day at every major airport. So I took all 241 of our stored readings, looked up what the wind actually did at all sixteen cities over the two days each reading was forecasting, and compared like with like. When the gate was open, some metro went on to record a gust above 45 mph on 51.9% of polls. When the gate was shut, on 63.1%. The difference is not statistically significant — the interval runs from 31 points the wrong way to 9 points the right way — so the fair conclusion is not that the signal is backwards. It is that there is no evidence it sorts windy from calm at all, and what evidence there is leans the wrong way.
The reason turns out to be arithmetic rather than meteorology, and it is the most interesting thing on this page. At the one city the forecast names as windiest, the forecast is essentially perfect: it says 37.9 mph on average and the airport records 37.8. But the number we store is a maximum over sixteen cities, and a maximum of sixteen smooth model forecasts is systematically smaller than a maximum of sixteen noisy real observations. Across the same thirty days the observed national peak averaged 47.9 mph against our forecast's 37.9. We are thresholding at 45 a series that runs ten miles an hour below the thing it is named after.
Where the data really comes from
One free, keyless call to api.open-meteo.com/v1/forecast, made once every three hours by predictive/wind_poller.py on cron 53 */3 * * *. The request asks for daily=wind_gusts_10m_max in miles per hour, with forecast_days=2 and timezone=auto, for sixteen metro centre points in a single batched query — New York, Los Angeles, Chicago, Dallas-Ft Worth, Houston, Washington DC, Philadelphia, Atlanta, Miami, Phoenix, Boston, San Francisco, Detroit, Seattle, Minneapolis and Denver, about 111.9 million people between them. I called the exact URL the poller builds from production this morning and it returned HTTP 200.
For each city the poller takes the larger of the two daily maxima, then reduces the sixteen results to two stored numbers: peak_gust, the single largest, rounded to a whole mile per hour, and mean_gust, the population-weighted average of all sixteen. It also records the name of the winning metro and how many cities reported. Each run appends one row to wind_forecast in predictive.db, which is pruned to thirty days and currently holds 241 rows spanning 14 July to 13 August 2026. All 241 have all sixteen cities present.
That metro list is byte-for-byte identical — same SHA-256 — across five different weather pollers: this one, aqi, heat_index, qpf and degree_days. I diffed them rather than assuming.
Two corrections to our own record, both of which this dictionary has now made repeatedly. The signal registry reports the source as “undocumented”, although the anchor's docstring names “a free, keyless Open-Meteo daily forecast” in plain English; the cause, found on the heat_index page and still unfixed, is that SOURCE_HINTS in the registry has no Open-Meteo entry at all, so the vendor behind five weather signals is undetectable by construction. And the as_of column, documented in the schema as the forecast issue time, holds the fetch time in all 241 rows — the fourth signal here with that defect. Poller, cron, table, replayable: false and live_bots: 0 are all correct, and here zero really does mean zero.
What it does for your bot
It is a whole-bot master switch, not a filter on wind-related markets. When the reading is outside your range the engine short-circuits the entire strategy and returns no candidates at all that cycle — the same shape as sentiment_anchor and the other weather regimes. It affects only bots that set it.
Three settings ship with the product. The builder's default is {metric:'peak', above:40}, which was open on 24.9% of our 241 readings. The builder recipe “High-wind regime” and the starter bot “High-Wind Watch” both use {metric:'peak', above:45}, open on 11.6%. Those are, on their face, perfectly reasonable duty cycles — this is not btc_dominance_anchor, where every shipped setting was a constant. The problem here is not the rate at which the switch flips. It is what the switch is called, and whether it is connected to anything.
One quietly good thing worth saying before the catches: the docstring's English is correct. It says {metric:'peak', below:25} means “only when every major metro is calm” — and because peak is a maximum, a maximum below 25 really does mean all sixteen are below 25. That is more care than several anchors in this dictionary manage.
The catch
1. There is no wind market. Not on Kalshi, and essentially not on Polymarket.
I pulled Kalshi's full series catalogue — 12,940 series across eighteen categories — and searched every ticker and title for wind, gust, gale and derecho. Zero matches. The exchange lists 334 weather series and they cover daily highs and lows in dozens of cities worldwide, rain, snowfall, hurricanes by landfall point, air quality, earthquakes, volcanic eruptions, drought level, Lake Mead, arctic sea ice and cloud cover during an eclipse. Wind is the conspicuous absence. Our own ingest agrees: 0 of 539,344 stored Kalshi rows.
Polymarket has listed exactly three, out of 124,745 distinct titles we hold: “Will the highest recorded wind on Mt. Washington in July be at least 90 / 95 / 100 mph?”, carrying $17,081, $28,458 and $18,395 of volume, all closed 31 July 2026 and all resolved YES. Mount Washington is a single 6,288-foot summit with a cult reputation and one official observer — the opposite of a sixteen-city blend, and 180 km from the nearest metro we poll. Polymarket filed all three under other, and the starter bot we ship filters on categories: ['weather'], so even the one wind market that has ever existed would have been invisible to it.
That absence is probably rational rather than an oversight. A gust is the noisiest settleable weather variable there is — it depends on the exposure of one anemometer and on whether you average over three seconds or five — and “will Denver gust 45” has none of the cultural pull of “will it hit 100 degrees”. This is the market declining, not the market not having noticed.
2. Checked against the wind that actually blew, the gate does not sort windy days from calm ones.
Gusts can be verified, which makes this signal unusual in this dictionary. The National Weather Service publishes the peak gust recorded each day at every major airport, free, through Iowa State's Environmental Mesonet. So for all 241 stored readings I looked up what the wind actually did at all sixteen cities across the two days each reading was forecasting, and applied the identical “largest of sixteen” rule to the observations that the poller applies to the forecast — so both sides of the comparison are selected the same way.
Gate open: a gust above 45 mph was actually observed somewhere on 51.9% of polls (14 of 27). Gate shut: 63.1% (130 of 206). The base rate across everything was 61.8%. Two-proportion z = −1.13, p = 0.26, and the 95% interval on the difference runs from −31.2 to +8.7 percentage points. Grouping by day instead of by poll, to be conservative about how much adjacent readings repeat themselves, gives 71.4% on the 14 open days against 87.5% on the 16 shut ones — same direction, same lack of significance. Ranked as a score rather than a threshold, the forecast's ability to order days by what the wind did gives an AUC of 0.513 at 45 mph and 0.512 at 40 mph: a coin flip. It does better at 50 mph (0.631), which is the one hint in here that something real is buried in the series.
So the honest verdict is not “the signal is backwards”. It is that there is no evidence it sorts windy from calm, and the point estimate leans the wrong way. With 27 open polls across 14 days this test cannot rule out a modest edge in either direction — but it can rule out the strong claim the product makes.
3. The number we threshold runs ten miles an hour below the reality it is named after — and it is the maximum, not the forecast, that breaks.
Over the same thirty days, the observed two-day national peak gust averaged 47.9 mph. Our stored forecast averaged 37.9. Mean error −10.0 mph, mean absolute error 11.6, and the forecast was the higher of the two on only 15% of polls.
The obvious explanation is wrong, and I checked. The poller reads city-centre coordinates while the observations come from airports — up to 30 km away at Denver. So I re-ran the same Open-Meteo product over the same thirty days at both coordinate sets. The difference across all sixteen metros was −0.01 mph, and on the national maximum −0.06 mph. Location explains none of it.
The real explanation is arithmetic. At the one city the forecast names as windiest, it is essentially unbiased — 37.9 forecast against 37.8 observed, median error +1.0 mph, higher on 51.9% of polls. The per-city forecast is good. But a maximum over sixteen smooth model forecasts is systematically smaller than a maximum over sixteen noisy real observations, because reality gets sixteen independent chances to spike and a smoothed field does not. The aggregation, not the meteorology, is what puts ten miles an hour between the gate and the world. Every threshold anyone sets on this series is therefore being set in units that are not the units on the label.
4. A bot called “High-Wind Watch” fires below the weakest official wind product in America.
The National Weather Service publishes its criteria, and I read them rather than recalling them. A Wind Advisory — the mildest wind product there is — is issued for sustained winds of 31 to 39 mph for an hour or more and/or wind gusts of 46 to 57 mph for any duration. A High Wind Warning requires sustained winds of 40 mph or more for an hour, or gusts of 58 mph or greater. A High Wind Watch uses the same numbers for a possible event. An Extreme Wind Warning starts at 115 mph.
Our shipped threshold is 45 mph — one mile per hour below the bottom of the advisory range, and 13 below the line that means damage. The bot's name is “High-Wind Watch”; the National Weather Service's High Wind Watch begins 13 mph further up. And 58 mph was crossed exactly once in 241 readings (a 62 on 11 August). Local offices adjust these numbers — Denver's foothills use a higher bar because 45 mph there is a Tuesday — but adjusting them upward only makes the point worse.
Read plainly, {peak, above:45} does not mean “a windstorm is coming”. It means “a model currently believes that at one of sixteen points, on one of the next two days, the peak gust will be a bit breezier than usual”.
5. Thirty days of memory, taken in the calmest month of the year.
Wind is the most seasonal variable in this dictionary, and our thirty-day retention window sits exactly on the annual floor. Rebuilding the same statistic from the ERA5 reanalysis across 3,875 two-day windows from 2016 to 2026, the shipped 45 mph setting would have been open on 2.1% of days in July and 4.1% in August — against 40.5% in March, 32% in January and February, and 31% in December. Our exact calendar slice, across ten years, comes out at 3.7%.
This changes one verdict for the better. The docstring's {metric:'mean', above:30} example never opens in our data — the highest mean_gust we have ever stored is 29.5. It would be easy to call that a dead setting. It isn't: over the full reanalysis the national average clears 30 on 16.1% of days and has reached 44.5. It is a winter setting pointed at a series we only ever look at in summer. Our memory is the defect, not the number.
It also means everything else on this page — every duty cycle, the verification, the ten-mile-an-hour gap — was measured at the annual minimum, on the kind of wind that comes out of a summer thunderstorm rather than off a winter cyclone. Those are different physics, and a signal can be useless at one and useful at the other. We delete the evidence that would settle it every thirty days.
6. Most of the movement is the winner changing, not the weather changing.
The stored number is a maximum, so it jumps whenever a different city takes the lead. Decomposing the variance of all 241 readings: the hour of day explains 3.0% — so this signal does not inherit ensemble_anchor's clock defect, which is now confirmed for the third weather signal running. The calendar day explains 27.0%. But the identity of whichever metro happened to be windiest explains 29.0% — more than the date does.
The split makes it concrete. On the three days when one city stayed windiest from midnight to midnight, the reading moved by a median of 3.0 mph. On the 28 days when the winner changed hands, it moved by 14.5 mph. There were a mean of 3.68 different winners per day, and the gate changed state 38 times in 241 polls at the 45 mph setting (54 times at 40). Denver won 50 times and Chicago 46; Los Angeles and Seattle never won at all.
And the stored label is usually wrong: the metro the forecast named as windiest really was the windiest on 18.0% of polls. That is nearly three times chance (6.25%), so the forecast knows something — but four times in five, windiest_metro names the wrong city.
7. The backtester silently ignores it — and here the standard excuse is wrong in letter but right in substance.
wind appears nowhere in quants/backtest.py: not in the supported list, not even in the documentary _UNSUPPORTED_ENTRY comment. It is caught only by the catch-all that rejects any key it doesn't recognise. The consequence is the one that matters: a backtest of a bot with this gate runs without the gate and still returns an equity curve, flagging unsupported_rules. You get a number that looks like a test of your idea and isn't.
The poller's docstring justifies this by saying “Open-Meteo's free forecast is forward-only (no archive here), so the signal is live-only”. In letter that is false — I verified both the ERA5 archive and the historical-forecast archive return HTTP 200 for wind_gusts_10m_max, and pulled 3,876 days from one of them for this page. But backfilling from either would be actively misleading, and I can put a number on it: over our own thirty days the near-analysis archive produces a national peak averaging 33.5 mph that clears 45 on 0.0% of days, where the live feed produced 38.0 mph and 11.6%. A backtest built from the archive would conclude the gate essentially never opens. The excuse is wrong about the archive existing and right about not trusting it.
8. The “level up” the starter bot suggests is a one-in-550-day event.
The starter's blurb offers: “flip it to ‘below’ to trade only dead-calm stretches.” The docstring's own example of that is {metric:'peak', below:25}. Across our entire record the lowest reading is 27 mph, so it has never opened; across ten and a half years of reanalysis it would have been true on 0.18% of days — about one day in 550. Sixteen large American cities are essentially never all calm at once, which is a property of taking a maximum over sixteen cities rather than a property of the weather. Nothing in the builder warns you.
9. The usual validator gaps, and the usual off-by-one prune.
{metric:'peak', above:45, below:25} validates cleanly and renders as “only when windiest-metro peak wind gust > 45 mph and windiest-metro peak wind gust < 25 mph” — two opposite regimes in one sentence, unsatisfiable, no warning. {above:1000} validates. {below:0} validates and can never open, since a gust is never negative and the comparison is strict. {metric:'mean', above:0} is always open. In fairness the units here are unambiguous — the field says mph and the stored value is mph, which is more than finance_anchor can say.
And the prune keeps 726 hours, not the 720 it intends, because it compares an ISO timestamp containing a T against SQLite's datetime() format containing a space, as text. This is the ninth poller in this dictionary with that exact bug.
The case for the defence
- This is the healthiest pipeline on the shelf. 466 runs, 464 successes, two crashes — one disk I/O error and one database or disk is full — and zero database is locked failures, the error that has crippled seven other feeds in this dictionary. Its :53 slot never collides with the backtest ticker index that runs at :01, :11, :21, :31, :41, :51. All 241 rows have all sixteen cities.
- Its freshness check is correctly written, and it has actually fired. It parses the timestamp into a real timezone-aware datetime rather than comparing strings — the bug that defeats the check in finance_anchor and tropical_anchor — and fails closed on anything it cannot parse. On 3 August a run was missed and the gap reached 21,601 seconds against a 21,600-second threshold: the gate shut, correctly, by one second. A separate gap in July came in at exactly 21,600.000 seconds and passed by nothing at all, the comparison being strict.
- The forecast itself is good. At the city it names, it is unbiased to a tenth of a mile per hour. Nothing on this page is a complaint about Open-Meteo, or about the idea that wind is a real and independent dimension of weather. The defect is in three lines of aggregation.
- The shipped duty cycles are sane. 24.9% and 11.6% are usable filter rates, and the docstring's English about what a maximum means is accurate. Compared with the constants shipped on btc_dominance_anchor or onchain_fees_anchor, whoever picked 40 and 45 was paying attention to something.
- Building the pipe before the contract exists is not stupid. If any exchange ever lists a wind market, one working, free, eight-times-a-day feed and a validated gate are already here. The cost of being early is one HTTP request every three hours.
- Nobody was hurt. Zero bots have ever used it, so none of this cost anyone anything.
The track record
There isn't one. 0 of 76 strategy configurations (21 live, 15 out-of-sample, 36 archived, 4 draft) and 0 of 88 strategy versions mention wind_anchor — none live, none out-of-sample, none archived, none ever. No trades, no fills, no evaluations, no profit and loss. Both files have been unmodified since 16 June 2026, 58 days.
For context, that is not unusual company: all seven of our three-hourly weather signals have zero bots. The only weather signal anything trades is wx_anchor, in 10 configurations — and it reads the air temperature, for which Kalshi runs hundreds of contracts.
What this page does not tell you
Whether this would have made money. I tested the gate against the wind, not against a price, for the simple reason that there is no wind price to test against. Everything here is a claim about whether the signal describes the world accurately. Whether an accurate wind signal would beat the market on some other contract — a temperature bracket on a frontal passage day, say — is completely untested, and is the only argument for this signal that has not been examined.
Whether mean_gust is any better. Everything measured here indicts peak. The population-weighted average is a genuinely different variable — it cannot be moved by one thunderstorm, which is precisely the flaw in peak — and the reanalysis says it clears 30 mph on one day in six across a full year. It might well be the better of the two. Nobody has tested it and this page will not guess.
Whether an airport gust and a model gust are the same measurement. I showed that the model does not care which coordinates you ask for. I did not show that an ASOS five-second peak at a flat, exposed airfield measures the same thing as a grid cell's hourly maximum. They are different instruments, and some part of the ten-mile-an-hour gap belongs to that rather than to the aggregation.
How the local day lines up. Open-Meteo's forecast_days=2 with timezone=auto means each city's window starts at midnight in its own time zone, so “the next two days” is really sixteen different 48-hour windows. Matching those to observation dates required a fixed UTC offset per city, which can be off by one day for polls near local midnight.
How the seasonality would look in our own feed. The monthly figures come from a reanalysis, not from this poller. Reanalyses are known to smooth extremes, so the July figure of 2.1% is probably too low in absolute terms. The shape — a deep summer minimum and a March peak — is the part to trust.
Sources for every figure on this page: quants/wind_anchor.py and predictive/wind_poller.py on production; the wind_forecast table in predictive.db (241 rows, 14 Jul – 13 Aug 2026) and the poller's own log; quants.db for the bot counts; Kalshi's public series API and Polymarket's ingested catalogue, read 13 August 2026; Open-Meteo's forecast, ERA5 archive and historical-forecast APIs; observed peak gusts from National Weather Service ASOS stations via the Iowa Environmental Mesonet; and the National Weather Service's own published definitions of the Wind Advisory, High Wind Watch and High Wind Warning on weather.gov. Nothing here is estimated or remembered. All TinyCorp bots trade simulated money.