Weather Bot — Episode 9: Scaling to 15 Cities — Two Weeks of Live Polymarket Weather Trading
The bot was working. Resolution holds were profitable. The bugs from Episode 8 were fixed. So I did what felt natural: add more cities.
Going from 5 to 15 turned out to be more than just copy-pasting city names into a config file. The API couldn't handle the extra load, same-day markets turned out to be a trap, and one METAR trade in Toronto taught me a $2 lesson about safety margins.
What This Post Covers
The expansion from 5 to 15 cities, the API optimization that made it possible, two hard lessons about when not to trade, and where things actually stand after two weeks of live operation. This isn't a wrap-up — the strategy is still changing and there's a lot I'm still figuring out.
Finding New Cities
I wrote a quick script to check Polymarket's gamma API for temperature markets in every major city I could think of. Atlanta, Tokyo, Shanghai, Toronto — all active, all with real volume.
The numbers surprised me. Atlanta was doing $1.68 million in weekly volume. More than NYC. I'd been ignoring it because I assumed US cities were all the same high-competition mess I'd seen with Chicago and Seattle. Wrong — Atlanta had volume and less bot competition than the big coastal cities.
| City | Weekly Volume | Added? |
|---|---|---|
| Atlanta | $1,681K | Yes |
| Shanghai | $463K | Yes |
| Tokyo | $310K | Yes |
| Toronto | $149K | Yes |
All four had enough liquidity for $1-2 bets. I added them along with several others, bringing the total to 15 active cities.
The API Problem
More cities meant more API calls. I did the math and didn't like what I saw:
Before: 11 cities × 3 calls = 33 calls/scan
20 scans/hour × 24 hours = 15,840 calls/day
Open-Meteo free limit: 10,000/day ← exceeded
I was burning through the free tier in 15 hours. The fix was something I should've done from the start: Open-Meteo's combined endpoint.
# Before — 3 separate calls per city
gfs = requests.get(
"https://api.open-meteo.com/v1/gfs",
params=...
)
ecmwf = requests.get(
"https://api.open-meteo.com/v1/ecmwf",
params=...
)
icon = requests.get(
"https://api.open-meteo.com/v1/dwd-icon",
params=...
)
# After — 1 combined call
resp = requests.get(
"https://api.open-meteo.com/v1/forecast",
params={
"latitude": lat, "longitude": lon,
"hourly": "temperature_2m",
"models": "gfs_seamless,ecmwf_ifs025,
icon_seamless",
"forecast_days": 3,
}
)
15 cities × 1 call = 15 calls per scan. Daily total dropped to around 7,200. Comfortably under the limit, even with room to add more cities later.
Same-Day Trading: The Trap
My biggest mistake in the first week of expansion was buying same-day markets. The logic seemed sound: forecast says 30°C, market has it at $0.15, buy.
But by the time a market is "today," the price already reflects the latest GFS update, actual morning temperatures, and every other bot's position. When the market says $0.15 on game day, it means "15% chance" — and the market is usually right.
I checked when the last GFS update gets priced in for each city:
| City | Last GFS Reflected | Peak | Gap |
|---|---|---|---|
| NYC | ~UTC 16:00 | UTC 19:00 | 3h |
| Seoul | ~UTC 22:00 (prev day) | UTC 05:00 | 7h |
| London | ~UTC 10:00 | UTC 14:00 | 4h |
By the time you can trade a same-day market, the forecast edge is gone. The code change was simple — if days_ahead == 0, skip. The only exception is METAR NO trades, which are based on actual real-time measurements and get more accurate as peak approaches.
The Toronto METAR Lesson
METAR NO is the one same-day strategy that still works — in theory. If the airport thermometer reads 4°C and peak is two hours away, betting "won't reach 10°C" is nearly certain.
Toronto, March 15. METAR read 4°C. My bot calculated a ceiling of 5°C (4°C + 1°C safety margin) and bought NO on the "≥5°C" bucket.
Temperature reached exactly 5°C. -$2 loss.
Two fixes came out of that. First, I doubled the safety margin from 1°C to 2°C. Second, I banned edge buckets entirely — the "≥X" and "≤X" ranges that have infinite range on one side. One degree of margin error on an edge bucket decides everything.
# Ban edge buckets for METAR NO
low, high = temp_range
if low == -999 or high == 999: # "≤X" or "≥X"
continue # too risky
if low <= ceiling:
continue # bucket starts below safety ceiling
Two Weeks In: The Numbers
Here's what my actual Polymarket portfolio looked like on March 20 — some green, some red, one Wellington position at -99% that I'd rather not talk about.
| Metric | Value |
|---|---|
| Starting capital | $198 |
| Current portfolio | ~$188 |
| Realized P&L | +$3.24 |
| Total trades | 20+ |
| Win rate (realized) | 62.5% (5/8) |
| Biggest win | +$5.89 (Ankara resolution) |
| Biggest loss | -$2.00 (Toronto METAR NO) |
| Cities | 15 |
The portfolio is slightly down from the $198 starting point because of open positions that haven't resolved yet. The realized P&L is positive at +$3.24 — mostly carried by that one Ankara resolution win. It's not impressive, but it's not negative either. The system works; it just needs more volume and more time.
What I'd Change
Same-day YES should've been banned from the start. Every same-day trade I took lost money. The market is smarter than my forecast model on game day, and it took me a week of losses to accept that.
The 1°C METAR safety margin was too tight. Toronto proved it. I should've started with 2°C and loosened it if the data supported it, not the other way around.
I also should've checked city volume before dismissing US cities as a group. Atlanta's $1.68M volume with moderate competition was a better opportunity than several of the non-US cities I'd been focused on. Not every US city is Chicago.
Key Takeaways
- Open-Meteo's combined endpoint cuts API calls 3:1. Should've used it from day one.
- Same-day YES trades are a trap. By the time you can buy, the forecast edge is priced in. Only METAR NO works on game day.
- METAR safety margins need to be wide. Toronto's 1°C margin wasn't enough. Doubled to 2°C and banned edge buckets.
- Check volume per city, not per country. Atlanta at $1.68M weekly was hiding in plain sight.
What's Happening Now
The bot's running 15 cities from my MacBook. The resolution strategy is holding, but barely — one big win carries a lot of small losses, and I'm right at the edge of breakeven. The next step is getting off the laptop entirely (it dies every time I close the lid), and there are some stop-loss decisions I've been putting off that the data is starting to make obvious.
The strategy is still changing. I'm still learning. More coming.
← Previous: Episode 8: FOK Ghost Orders, Orderbook Lies Next: Episode 10: Moving to Oracle Cloud and the Stop-Loss Surgery →
More updates on the way. If you're working on something similar or found a smarter way to do it, drop it in the comments — the more we share, the faster we all move.
Disclaimer: This blog documents my personal learning journey. Nothing here is financial advice.
Comments
Post a Comment