{"id":"f432816c-a882-4244-bf50-88d9d081c6d1","entityType":"agent","slug":"clawhub-simmer-polymarket-weather-trader","name":"polymarket-weather-trader","canonicalUrl":"https://www.xpersona.co/agent/clawhub-simmer-polymarket-weather-trader","canonicalPath":"/agent/clawhub-simmer-polymarket-weather-trader","generatedAt":"2026-10-09T20:41:47.589Z","source":"CLAWHUB","claimStatus":"UNCLAIMED","verificationTier":"NONE","summary":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-09T02:13:58.015Z","emptyReason":null},"description":"Trade Polymarket weather markets using NOAA (US) and Open-Meteo (international) forecasts via Simmer API. Inspired by gopfan2's weather trading approach. Use when user wants to trade temperature markets, automate weather bets, check forecasts, or run weather-based strategies.","descriptionLabel":"Source description","evidenceSummary":"Capability contract not published. No trust telemetry is available yet. 11.5K downloads reported by the source. Last updated 10/9/2026.","installCommand":"clawhub skill install s17eez0vajry6hjb97y9mbtv2s85wekv:polymarket-weather-trader","sourceUrl":"https://clawhub.ai/simmer/polymarket-weather-trader","homepage":"https://clawhub.ai/simmer/skills/polymarket-weather-trader","primaryLinks":[{"label":"View on ClawHub","url":"https://clawhub.ai/simmer/polymarket-weather-trader","kind":"source"},{"label":"Homepage","url":"https://clawhub.ai/simmer/skills/polymarket-weather-trader","kind":"homepage"}],"safetyScore":84,"overallRank":62,"popularityScore":81,"trustScore":null,"claimedByName":null,"isOwner":false,"seoDescription":"polymarket-weather-trader technical dossier on Xpersona with agent coverage, OPENCLEW support, and live trust metadata."},"coverage":{"evidence":{"source":"public-profile","verified":false,"confidence":"medium","updatedAt":"2026-10-09T02:13:58.015Z","emptyReason":null},"protocols":[{"protocol":"OPENCLEW","label":"OpenClaw","status":"self-declared","notes":"Declared in the public agent profile."}],"capabilities":[],"verifiedCount":0,"selfDeclaredCount":1,"capabilityMatrix":{"rows":[{"key":"OPENCLEW","type":"protocol","support":"unknown","confidenceSource":"profile","notes":"Listed on profile"}],"flattenedTokens":"protocol:OPENCLEW|unknown|profile"}},"adoption":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-09T02:13:58.015Z","emptyReason":null},"stars":null,"forks":null,"downloads":11485,"packageName":null,"latestVersion":"1.23.22","tractionLabel":"11.5K downloads"},"release":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-09T02:13:58.015Z","emptyReason":null},"lastUpdatedAt":"2026-10-09T02:13:58.015Z","lastCrawledAt":"2026-10-09T02:13:58.015Z","lastIndexedAt":null,"nextCrawlAt":"2026-10-10T02:13:58.015Z","lastVerifiedAt":null,"highlights":[{"version":"1.23.22","createdAt":"2026-09-18T05:14:24.718Z","changelog":"SIM-5499: per-market position cap (max_buys_per_market, default 1) checked against held positions before entry; run summary prints a per-location skip-reason breakdown. Risk-reducing by default; set 0 for the old unbounded DCA.","fileCount":12,"zipByteSize":76233},{"version":"1.23.21","createdAt":"2026-09-17T16:33:05.989Z","changelog":"v1.23.21 is a regular update with minor fixes and refinements. - Updated documentation and metadata to reflect v1.23.21. - No major logic or user-facing changes introduced. - Maintenance update to align versioning and changelogs.","fileCount":12,"zipByteSize":73514},{"version":"1.23.18","createdAt":"2026-09-17T14:59:20.177Z","changelog":"SIM-5484: replay positions no longer 422 (venue filter omitted under replay); backtest recipe uses --set locations; forecast-archive env passthrough documented. Replay/backtest-only; live trading unchanged.","fileCount":12,"zipByteSize":72271},{"version":"1.23.17","createdAt":"2026-09-16T09:05:10.173Z","changelog":"1.23.11–1.23.17: backtest-as-gate (SIM-5428), replay forecast archive loader (SIM-5429), historical forecast archive builder with tz-correct leads and DST guard (SIM-5434). Live trading path unchanged.","fileCount":12,"zipByteSize":70152},{"version":"1.23.10","createdAt":"2026-09-14T04:39:50.982Z","changelog":"v1.23.10 expands weather market discovery to match the minimum hours-to-resolve threshold. - Discovery now adapts to `SIMMER_WEATHER_MIN_HOURS_TO_RESOLVE`, searching +1/+2 days so higher `MIN_HOURS` values still find tradable markets. - The discovery horizon is set to `max(MIN_HOURS, 48h)`—raising the hours knob widens the search, with no separate horizon env. - Added tests for the new discovery and replay logic. - Updated documentation; removed outdated skill-card.md file.","fileCount":17,"zipByteSize":72499},{"version":"1.23.8","createdAt":"2026-09-08T08:02:41.924Z","changelog":"Polymarket Weather Trader v1.23.8 - Added entry safeguard tests (`tests/test_entry_safeguards.py`) to improve test coverage on entry conditions. - Updated and clarified safeguard logic in documentation (SKILL.md): now details that the time-decay (`SIMMER_WEATHER_MIN_HOURS_TO_RESOLVE`) and minimum entry price (`SIMMER_WEATHER_MIN_ENTRY_PRICE`) are both configurable via environment variables. - Reworded and expanded the strategy-side safeguards description for clarity. - Removed outdated `skill-card.md`. - Miscellaneous test and code improvements for resolution criteria and entry checks.","fileCount":15,"zipByteSize":64075},{"version":"1.23.6","createdAt":"2026-09-06T04:02:46.776Z","changelog":"v1.23.6 - Improved tests: added coverage for reworded resolution criteria. - Refined logic for station name resolution in weather market parsing. - Updated documentation: removed redundant skill-card.md, refreshed SKILL.md content. - Minor code and test maintenance; no breaking changes.","fileCount":14,"zipByteSize":57647},{"version":"1.23.5","createdAt":"2026-09-06T01:17:53.859Z","changelog":"Polymarket Weather Trader v1.23.5 - skill-card.md removed from repository (retired duplicate or outdated info). - Documentation updates in SKILL.md; no changes to trading logic. - General cleanup of repository files for maintenance.","fileCount":13,"zipByteSize":49701}]},"execution":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No published capability contract is available yet."},"installCommand":"clawhub skill install s17eez0vajry6hjb97y9mbtv2s85wekv:polymarket-weather-trader","setupComplexity":"low","setupSteps":["Install using `clawhub skill install s17eez0vajry6hjb97y9mbtv2s85wekv:polymarket-weather-trader` in an isolated environment before connecting it to live workloads.","No published capability contract is available yet, so validate auth and request/response behavior manually.","Review the upstream CLAWHUB listing at https://clawhub.ai/simmer/polymarket-weather-trader before using production credentials."],"contract":{"contractStatus":"missing","authModes":[],"requires":[],"forbidden":[],"supportsMcp":false,"supportsA2a":false,"supportsStreaming":false,"inputSchemaRef":null,"outputSchemaRef":null,"dataRegion":null,"contractUpdatedAt":null,"sourceUpdatedAt":null,"freshnessSeconds":null},"invocationGuide":{"preferredApi":{"snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-simmer-polymarket-weather-trader/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-simmer-polymarket-weather-trader/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-simmer-polymarket-weather-trader/trust"},"curlExamples":["curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-simmer-polymarket-weather-trader/snapshot\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-simmer-polymarket-weather-trader/contract\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-simmer-polymarket-weather-trader/trust\""],"jsonRequestTemplate":{"query":"summarize this repo","constraints":{"maxLatencyMs":2000,"protocolPreference":["OPENCLEW"]}},"jsonResponseTemplate":{"ok":true,"result":{"summary":"...","confidence":0.9},"meta":{"source":"CLAWHUB","generatedAt":"2026-10-09T20:41:47.585Z"}},"retryPolicy":{"maxAttempts":3,"backoffMs":[500,1500,3500],"retryableConditions":["HTTP_429","HTTP_503","NETWORK_TIMEOUT"]}},"endpoints":{"dossierUrl":"https://www.xpersona.co/api/v1/agents/clawhub-simmer-polymarket-weather-trader/dossier","snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-simmer-polymarket-weather-trader/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-simmer-polymarket-weather-trader/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-simmer-polymarket-weather-trader/trust"}},"reliability":{"evidence":{"source":"runtime-metrics","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No trust, reliability, or runtime telemetry is available."},"trust":{"status":"unavailable","handshakeStatus":"UNKNOWN","verificationFreshnessHours":null,"reputationScore":null,"p95LatencyMs":null,"successRate30d":null,"fallbackRate":null,"attempts30d":null,"trustUpdatedAt":null,"trustConfidence":"unknown","sourceUpdatedAt":null,"freshnessSeconds":null},"decisionGuardrails":{"doNotUseIf":["Contract metadata is missing or unavailable for deterministic execution."],"safeUseWhen":[],"riskFlags":["missing_or_unavailable_contract","trust_data_unavailable","schema_references_missing"],"operationalConfidence":"low"},"executionMetrics":{"observedLatencyMsP50":null,"observedLatencyMsP95":null,"estimatedCostUsd":null,"uptime30d":null,"rateLimitRpm":null,"rateLimitBurst":null,"lastVerifiedAt":null,"verificationSource":null},"runtimeMetrics":{"successRate":null,"avgLatencyMs":null,"avgCostUsd":null,"hallucinationRate":null,"retryRate":null,"disputeRate":null,"p50Latency":null,"p95Latency":null,"lastUpdated":null}},"benchmarks":{"evidence":{"source":"no-benchmark-data","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No benchmark suites or observed failure patterns are available."},"suites":[],"failurePatterns":[]},"artifacts":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-09T02:13:58.015Z","emptyReason":null},"readme":"Skill: polymarket-weather-trader\n\nOwner: simmer\n\nSummary: Trade Polymarket weather markets using NOAA (US) and Open-Meteo (international) forecasts via Simmer API. Inspired by gopfan2's weather trading approach. Use when user wants to trade temperature markets, automate weather bets, check forecasts, or run weather-based strategies.\n\nTags: latest:1.23.22\n\nVersion history:\n\nv1.23.22 | 2026-09-18T05:14:24.718Z | user\n\nSIM-5499: per-market position cap (max_buys_per_market, default 1) checked against held positions before entry; run summary prints a per-location skip-reason breakdown. Risk-reducing by default; set 0 for the old unbounded DCA.\n\nv1.23.21 | 2026-09-17T16:33:05.989Z | auto\n\nv1.23.21 is a regular update with minor fixes and refinements.\n\n- Updated documentation and metadata to reflect v1.23.21.\n- No major logic or user-facing changes introduced.\n- Maintenance update to align versioning and changelogs.\n\nv1.23.18 | 2026-09-17T14:59:20.177Z | user\n\nSIM-5484: replay positions no longer 422 (venue filter omitted under replay); backtest recipe uses --set locations; forecast-archive env passthrough documented. Replay/backtest-only; live trading unchanged.\n\nv1.23.17 | 2026-09-16T09:05:10.173Z | user\n\n1.23.11–1.23.17: backtest-as-gate (SIM-5428), replay forecast archive loader (SIM-5429), historical forecast archive builder with tz-correct leads and DST guard (SIM-5434). Live trading path unchanged.\n\nv1.23.10 | 2026-09-14T04:39:50.982Z | auto\n\nv1.23.10 expands weather market discovery to match the minimum hours-to-resolve threshold.\n\n- Discovery now adapts to `SIMMER_WEATHER_MIN_HOURS_TO_RESOLVE`, searching +1/+2 days so higher `MIN_HOURS` values still find tradable markets.\n- The discovery horizon is set to `max(MIN_HOURS, 48h)`—raising the hours knob widens the search, with no separate horizon env.\n- Added tests for the new discovery and replay logic.\n- Updated documentation; removed outdated skill-card.md file.\n\nv1.23.8 | 2026-09-08T08:02:41.924Z | auto\n\nPolymarket Weather Trader v1.23.8\n\n- Added entry safeguard tests (`tests/test_entry_safeguards.py`) to improve test coverage on entry conditions.\n- Updated and clarified safeguard logic in documentation (SKILL.md): now details that the time-decay (`SIMMER_WEATHER_MIN_HOURS_TO_RESOLVE`) and minimum entry price (`SIMMER_WEATHER_MIN_ENTRY_PRICE`) are both configurable via environment variables.\n- Reworded and expanded the strategy-side safeguards description for clarity.\n- Removed outdated `skill-card.md`.\n- Miscellaneous test and code improvements for resolution criteria and entry checks.\n\nv1.23.6 | 2026-09-06T04:02:46.776Z | auto\n\nv1.23.6\n\n- Improved tests: added coverage for reworded resolution criteria.\n- Refined logic for station name resolution in weather market parsing.\n- Updated documentation: removed redundant skill-card.md, refreshed SKILL.md content.\n- Minor code and test maintenance; no breaking changes.\n\nv1.23.5 | 2026-09-06T01:17:53.859Z | auto\n\nPolymarket Weather Trader v1.23.5\n\n- skill-card.md removed from repository (retired duplicate or outdated info).\n- Documentation updates in SKILL.md; no changes to trading logic.\n- General cleanup of repository files for maintenance.\n\nv1.23.4 | 2026-07-22T08:13:05.598Z | user\n\nFOK order type now overridden to GTC like FAK (weather markets are structurally illiquid, both cancel on no-fill); EGLC London City Airport added to the international station map.\n\nv1.23.3 | 2026-07-07T18:12:05.396Z | user\n\nevent_ref grouping (SIM-3825)\n\nv1.23.2 | 2026-06-20T05:10:36.223Z | auto\n\nv1.23.2\n\n- Internal documentation updated; SKILL.md revised for clarity and accuracy.\n- Removed outdated file: skill-card.md.\n- No changes to core logic or user-facing features.\n\nv1.23.1 | 2026-06-13T05:07:41.164Z | user\n\nDisclose that the auto stop-loss can't catch gap-resolution on weather temperature markets (price gaps to ~0 at resolution); size for full loss.\n\nv1.23.0 | 2026-05-26T14:22:56.478Z | auto\n\n**v1.23.0 summary: Adds weather station name resolution for international markets & improved test coverage.**\n\n- Adds support for resolving international weather station names, allowing trading on more global markets.\n- Expands and refines test coverage, particularly for the station name resolver logic.\n- Minor internal changes and cleanups in weather_trader.py and related modules.\n\nv1.22.2 | 2026-05-24T06:59:38.424Z | auto\n\nv1.22.2 — Adds station name resolution tests and internal improvements\n\n- Added new test file: `tests/test_station_name_resolve.py` for validating station name resolution logic.\n- Updated `weather_trader.py` with improvements related to station name handling.\n- Updated documentation in `SKILL.md` and `CHANGELOG.md`.\n- No changes to user-facing features or configuration.\n\nv1.22.1 | 2026-05-24T06:34:49.014Z | auto\n\nv1.22.1\n\n- Documentation and metadata update.\n- No strategy or logic changes; core functionality unchanged.\n- SKILL.md revised for clarity and metadata bumped to 1.22.1.\n\nv1.22.0 | 2026-05-24T06:15:32.206Z | auto\n\nv1.22.0 expands test coverage and core logic reliability.\n\n- Added tests for source agreement logic and preflight safeguards.\n- Improved reliability of market source selection and validation.\n- Bugfixes and internal improvements based on expanded test scenarios.\n- Documentation and metadata update for new test files and logic.\n\nv1.21.2 | 2026-05-23T11:13:55.310Z | auto\n\nPolymarket Weather Trader v1.21.2\n\n- Added top-level disclaimer reference and included `DISCLAIMER.md` for clarity on use and risk.\n- Introduced a `tests/test_sources_none.py` test to improve source edge case coverage.\n- Minor documentation updates/clarifications in SKILL.md.\n- No changes to core trading logic.\n\nv1.21.1 | 2026-05-19T05:37:45.902Z | auto\n\n## Polymarket Weather Trader v1.21.1\n\n- Minor release with documentation updates.\n- No user-facing strategy or API changes.\n- SKILL.md updated for accuracy and clarity.\n\nv1.21.0 | 2026-05-03T07:01:30.103Z | auto\n\nv1.21.0 introduces robust per-market weather station routing and expanded coverage for more accurate weather market trades.\n\n- Each market now routes to the specific weather station named in its `resolution_criteria`, matching Polymarket's source rather than using a fixed default. If a station is not recognized, the market is skipped with a log message.\n- Expanded NOAA station support: now covers KLGA, KJFK, KEWR, KNYC, KORD, KMDW, KSEA, KATL, KDAL, KDFW, KMIA, KBOS, KDCA, KIAD, KPHX, KLAS, KSFO, KLAX, KDEN, KMSP, KPHL.\n- Added international Open-Meteo routing for Madrid, Milan, Amsterdam, Taipei, as well as previously supported cities.\n- The skill now requires the new `?include=resolution_criteria` flag when calling `/api/sdk/markets` (supported as of 2026-05-03).\n\nv1.20.1 | 2026-05-03T02:43:12.712Z | user\n\nv1.20.1 — ASI scanner reframe per engine v2.4.22 calibration. Adds Safety rails (read first) section surfacing the bounding contract (dry-run default, --live opt-in, $SIM paper sandbox, linked-wallet requirement, configurable caps, server-side stop-loss ON, strategy-side safeguards, reversibility). Genericizes risk monitor framing (stop-loss/take-profit thresholds described as configurable user settings — sidesteps a code-vs-DB-default divergence tracked in a separate platform consolidation). Drops named cross-skill link in Setup section. Strategy logic + env var contract unchanged from v1.20.0. Requires simmer-sdk >= 0.13.0.\n\nv1.20.0 | 2026-05-01T05:44:59.522Z | user\n\nv1.20.0 — Phase 3 canary of skill catalog reshape. Migrated to simmer-sdk 0.13.0 helpers (SimmerClient.from_env() replaces direct os.environ reads). Removed dead AUTOMATON_* env reads (automaton retired 2026-04-20). Slimmed SKILL.md (303 → 203 lines): dropped duplicated wallet setup content, trimmed example output, reworded cross-skill reference. Strategy logic, env var contract for SIMMER_WEATHER_*, and TRADING_VENUE behavior unchanged. Requires simmer-sdk >= 0.13.0.\n\nv1.19.2 | 2026-04-24T10:07:10.866Z | auto\n\nPolymarket Weather Trader v1.19.2\n\n- Updated skill version and metadata to 1.19.2 in documentation.\n- No new features or user-facing changes noted.\n- Documentation and configuration details remain unchanged since previous release.\n\nv1.19.1 | 2026-04-23T05:56:59.012Z | user\n\nV2 migration (2026-04-28): updated troubleshooting copy to point users at the Wrap USDC.e → pUSD flow at simmer.markets/dashboard + docs.simmer.markets/v2-migration. Also refines clawhub.json envVars schema (WALLET_PRIVATE_KEY now correctly optional for managed-wallet users).\n\nv1.18.3 | 2026-04-22T09:15:44.411Z | user\n\nSchema fix: primaryEnv + envVars with required:false for optional credentials. Clears OpenClaw 'disproportionate requirements' verdict.\n\nv1.18.2 | 2026-04-22T08:19:20.351Z | user\n\nDeclare WALLET_PRIVATE_KEY in requires.env for OpenClaw moderation alignment.\n\nv1.18.1 | 2026-04-20T06:50:47.519Z | user\n\nSKILL.md content revision: frames paper mode and $SIM venue as test features. No code/config changes from 1.18.0.\n\nv1.18.0 | 2026-04-20T06:27:28.894Z | user\n\nv1.18.0: clawhub.json autotune defaults realigned with code defaults (entry 0.15, exit 0.45, max , sizing 0.05); 7 additional tunables exposed for autotune (LOCATIONS, BINARY_ONLY, SLIPPAGE_MAX, MIN_LIQUIDITY, VOL_*); max_position_usd range tightened to [1,50] and sizing_pct to [0.01,0.25]; SKILL.md updated with server-side risk-monitor framing. No code behavior changes — tunable surface only.\n\nv1.17.2 | 2026-04-16T10:06:07.966Z | user\n\nAdd pip install simmer-sdk to setup flow\n\nv1.17.1 | 2026-04-03T02:47:18.805Z | user\n\nAdd auto_redeem() call at start of each cycle for external wallet support\n\nv1.17.0 | 2026-03-29T13:41:02.242Z | auto\n\n**v1.17.0 introduces dynamic position sizing using volatility targeting.**\n\n- Adds volatility targeting mode: dynamically adjust trade size based on recent market volatility (enable with `--vol-targeting` or `SIMMER_WEATHER_VOL_TARGETING`).\n- New configuration parameters: `SIMMER_WEATHER_TARGET_VOL`, `SIMMER_WEATHER_VOL_MAX_LEVERAGE`, `SIMMER_WEATHER_VOL_MIN_ALLOC`, and `SIMMER_WEATHER_VOL_SPAN` for managing volatility targeting behavior.\n- Position size will decrease in high-volatility markets and increase (capped) in low-volatility markets.\n- Volatility calculated with EWMA of log returns from price history.\n- All previous features and safeguards remain available.\n\nv1.16.1 | 2026-03-29T07:04:14.201Z | auto\n\nv1.16.1 Changelog\n\n- Minor update to weather_trader.py; no user-facing changes documented.\n- No updates to documentation or configuration detected.\n\nv1.16.0 | 2026-03-26T07:13:19.661Z | user\n\nDefault order type changed from FAK to GTC for better fills on illiquid weather markets. Configurable via SIMMER_WEATHER_ORDER_TYPE env var.\n\nv1.15.2 | 2026-03-25T08:48:58.248Z | auto\n\nPolymarket Weather Trader v1.16.0\n\n- Default order type changed from GTC to FAK for safer automated trading; all Polymarket order types (FAK, GTC, FOK, GTD) now supported with clear startup validation.\n- New: Before live trading, the system checks USDC.e balance and prints a clear error with a bridge guide link if funds are missing.\n- Added `docs/usdc-bridge.md` with detailed instructions for bridging USDC from any chain to Polygon USDC.e.\n- Minor updates and clarifications in documentation and configuration.\n\nv1.15.1 | 2026-03-17T09:41:14.137Z | auto\n\n- No user-facing changes in this release (v1.15.1).\n- Internal update: weather_trader.py was modified with no impact to documentation or configuration.\n\nv1.15.0 | 2026-03-15T08:57:11.395Z | auto\n\n**International forecast support added**\n- Adds Open-Meteo as a secondary forecast source for non-US weather markets, enabling trading on international locations.\n- Skill description and documentation updated to clarify support for both NOAA (US) and Open-Meteo (international) data.\n- Weather trader logic enhanced to select the appropriate forecast provider based on event location.\n- No changes to configuration or routine usage for US users.\n\nv1.14.1 | 2026-03-11T04:24:51.207Z | auto\n\n## Polymarket Weather Trader v1.14.1\n\n- Updated `clawhub.json`.\n- No user-facing changes.\n\nv1.14.0 | 2026-03-11T03:48:19.478Z | auto\n\n**Changelog v1.14.0**\n\n- Updated environment variable names for autotune compatibility (`SIMMER_WEATHER_ENTRY` → `SIMMER_WEATHER_ENTRY_THRESHOLD`, etc.); old variables still supported as aliases.\n- Added `SIMMER_WEATHER_SLIPPAGE_MAX` tunable to adjust slippage safeguard (default 15%).\n- Added `SIMMER_WEATHER_MIN_LIQUIDITY` tunable to skip low-liquidity markets (default disabled).\n- Exposed `SIMMER_WEATHER_LOCATIONS` and `SIMMER_WEATHER_BINARY_ONLY` as autotune parameters.\n\nv1.13.0 | 2026-03-03T03:16:44.330Z | auto\n\n- Version bump to 1.13.0.\n- SKILL.md: Updated metadata version to 1.13.0.\n- No feature or configuration changes documented in user-facing docs.\n\nv1.12.4 | 2026-03-03T02:53:17.411Z | user\n\nAgentSkills format — moved platform config to clawhub.json for cross-agent compatibility\n\nv1.12.3 | 2026-02-27T10:22:33.309Z | auto\n\n- Minor documentation updates in SKILL.md\n- Added \"difficulty: beginner\" field to metadata\n- No code or functional changes in this version\n\nv1.12.2 | 2026-02-27T06:06:30.423Z | auto\n\nNo user-visible changes in this version. This release updates the skill version metadata only.\n\nv1.12.1 | 2026-02-27T06:04:37.794Z | auto\n\nv1.12.1 Changelog\n\n- Updated internal logic in weather_trader.py (details not shown in input).\n- No user-facing changes to documentation or configuration.\n- All existing features and setup remain unchanged.\n\nv1.12.0 | 2026-02-26T16:06:13.676Z | auto\n\n**v1.12.0 highlights: Adds binary-only trading mode and enhanced config tunables**\n\n- Introduced \"binary only\" mode (`SIMMER_WEATHER_BINARY_ONLY`) to restrict trading to binary (yes/no) temperature markets, skipping range-bucket events.\n- Added detailed tunable settings in metadata for thresholds, sizing, and position limits.\n- Updated configuration documentation to reflect new binary-only mode and expanded options.\n- Version bump to 1.12.0.\n\nv1.10.2 | 2026-02-24T13:44:10.071Z | auto\n\n- Bumped internal version to 1.10.2.\n- No user-facing changes; documentation and functionality remain unchanged from the previous version.\n\nv1.10.1 | 2026-02-21T17:46:32.683Z | user\n\nFix: event grouping now works — markets properly grouped by location/date for entry logic\n\nv1.10.0 | 2026-02-21T17:41:12.307Z | user\n\nFix: event grouping now works — markets properly grouped by location/date for entry logic\n\nv1.9.2 | 2026-02-21T10:10:36.338Z | user\n\nAuto-discovers and imports weather markets before trading\n\nv1.9.1 | 2026-02-21T09:59:17.491Z | user\n\nRe-publish: auto-discovers and imports weather markets before trading\n\nv1.9.0 | 2026-02-21T09:48:22.422Z | user\n\nAuto-discovers and imports weather markets before trading — no more manual import step\n\nv1.8.0 | 2026-02-19T15:16:30.574Z | auto\n\n**Automaton support and management improvements.**\n\n- Added automaton management metadata and entrypoint to SKILL.md for platform integration.\n- Updated skill version to 1.8.0.\n\nArchive index:\n\nArchive v1.23.22: 12 files, 76233 bytes\n\nFiles: CHANGELOG.md (20845b), clawhub.json (9836b), config.json (30b), DISCLAIMER.md (2349b), fixtures/replay_forecasts.sample.json (192b), scripts/build_replay_forecast_archive.py (14481b), scripts/run_backtest_gate.py (5700b), scripts/status.py (4441b), skill-card.md (2994b), SKILL.md (30469b), weather_trader.py (123319b), _meta.json (146b)\n\nFile v1.23.22:SKILL.md\n\n---\nname: polymarket-weather-trader\ndescription: Trade Polymarket weather markets using NOAA (US) and Open-Meteo (international) forecasts via Simmer API. Inspired by gopfan2's weather trading approach. Use when user wants to trade temperature markets, automate weather bets, check forecasts, or run weather-based strategies.\nmetadata:\n  author: Simmer (@simmer_markets)\n  version: \"1.23.22\"\n  displayName: Polymarket Weather Trader\n  difficulty: beginner\n  attribution: Strategy inspired by gopfan2 (public Polymarket trader — approach referenced, not endorsed).\n---\n# Polymarket Weather Trader\n\nTrade temperature markets on Polymarket using NOAA forecast data.\n\n> 🚨 **Framework, not a production trading system.** Read [DISCLAIMER.md](./DISCLAIMER.md) before connecting to a wallet with real funds.\n\n> **Template skill.** Defaults to dry-run mode (no real money). The `--live` flag is a deliberate single-command opt-in for real-money execution. Configure tunables (entry/exit thresholds, locations, etc.) via env vars listed below.\n\n## Safety rails (read first)\n\nThis skill executes real-money trades on Polymarket only when the `--live` flag is passed AND the human's wallet is linked to their Simmer account. Trading is bounded by default:\n\n- **Dry-run is the default.** `python weather_trader.py` (no flag) shows opportunities but executes no trades. The `--live` flag is required for real-money execution. There is no \"auto-graduate\" path.\n- **`$SIM` paper sandbox option.** Set `TRADING_VENUE=sim` to trade Simmer's $SIM virtual currency at real prices — useful for validating the strategy without USDC exposure.\n- **Real-money trading requires explicit human verification.** A wallet must be linked at [simmer.markets/dashboard](https://simmer.markets/dashboard?ref=sdk-skill&utm_campaign=sdk-skill) before any real trade lands. Without a linked wallet the SDK rejects real-money order construction.\n- **Per-trade cap.** `SIMMER_WEATHER_MAX_POSITION_USD` defaults to `$2.00` per trade. Configurable via env var, capped at the user's dashboard-set platform per-trade limit.\n- **Daily caps.** Platform-level daily caps apply (max trades/day, max USD/day). Set at [simmer.markets/dashboard](https://simmer.markets/dashboard?ref=sdk-skill&utm_campaign=sdk-skill) → SDK settings.\n- **Auto stop-loss is ON by default.** Server-side risk monitor watches every buy. Threshold is configurable per user at simmer.markets/dashboard → Settings → Auto Risk Monitor. **It cannot protect against gap-resolution, though:** weather temperature buckets jump straight to about 0 at resolution rather than decaying through your stop, so a percentage stop has no price to trigger on and no liquidity to exit into. Size for the full loss, not for the stop. See [DISCLAIMER.md](./DISCLAIMER.md).\n- **Strategy-side safeguards.** Beyond platform risk monitors, this skill checks flip-flop, slippage (`SIMMER_WEATHER_SLIPPAGE_MAX`, default 15%), time-decay (`SIMMER_WEATHER_MIN_HOURS_TO_RESOLVE`, default 2h), and resolved-market status before every order. Disable only with `--no-safeguards` (not recommended).\n- **Reversibility.** Open positions exit automatically when price > `SIMMER_WEATHER_EXIT_THRESHOLD` (default `0.45`), or via `client.cancel_order()` / a manual sell. `ENTRY_THRESHOLD` is an **upper** bound (buy *below*). If you raise it above the exit default (e.g. entry `0.50` vs exit `0.45`), the skill will try to sell the same position on the next cycle — raise `EXIT_THRESHOLD` too, or own exits yourself.\n\nIf anything above isn't clear, stop and ask the user before passing `--live`.\n\n## Strategy logic\n\nWeather market outcomes are discrete: a temperature bucket (\"34-35°F\") either matches the actual high on resolution day or it doesn't. The strategy works when the NOAA forecast is more accurate than what the market has priced in.\n\n**Test before going live.** The `$SIM` venue gives you a fully virtual sandbox at real market prices — recommended before any `--live` run.\n\n**Risk monitor.** Stop-loss and take-profit thresholds are user settings (configurable at [simmer.markets/dashboard](https://simmer.markets/dashboard?ref=sdk-skill&utm_campaign=sdk-skill) → Settings → Auto Risk Monitor), shared across all skills under that user account. Per-position overrides via `client.set_monitor(market_id, side, stop_loss_pct=..., take_profit_pct=...)`.\n\n**External wallet users**: monitors emit alerts via the briefing endpoint — your agent must be running for sells to execute. Managed wallet users: server executes directly.\n\n## When to Use This Skill\n\nUse this skill when the user wants to:\n- Trade weather markets automatically\n- Set up gopfan2-style temperature trading\n- Buy low on weather predictions\n- Check their weather trading positions\n- Configure trading thresholds or locations\n\n## What's New in v1.23.21\n\n- **Per-market position cap (SIM-5499).** `SIMMER_WEATHER_MAX_BUYS_PER_MARKET` (default `1`) checks held positions before entry so a replay backtest and live trading measure the same strategy — replay previously DCA'd into every underpriced bucket every tick (mean 34 buys/market on a full-tape run) while live is naturally throttled by balance/backoffs. Run summaries now also print a per-location skip-reason breakdown so a location entering zero markets is diagnosable from the run's own output.\n\n## What's New in v1.23.19\n\n- **Replay archive builder hardening (SIM-5440).** Open-Meteo HTTP 5xx responses now retry up to 3 attempts with backoff while 4xx remains fail-closed. Long windows are fetched in 10-day chunks and merged only when `utc_offset_seconds` is identical across chunks. `--stations us|intl|all` lets US-only backtests avoid international DST guards and unnecessary requests.\n\n## What's New in v1.23.17\n\n- **Timezone-correct leads (SIM-5434).** Lead N is the smallest 1–3 such that every hourly issuance for the event day precedes the tick: `N = ceil((E_end_utc − tick) / 24h)`, where `E_end_utc` is the event date's 23:59:59 in the station offset. Builder records Open-Meteo `utc_offset_seconds` per station in `_meta`. Missing offset assumes UTC−12 (`tz=assumed`). Each date must carry hours `00:00`–`23:00` exactly once.\n\n## What's New in v1.23.16\n\n- **Lead-aware archive (SIM-5434).** Builder fetches `temperature_2m_previous_day{1,2,3}` in one request per station. Each date is `{high, low, leads}` with top-level high/low = lead 1. Under replay, `_station_forecast(..., event_date=)` picks `lead = (event_date − tick.date).days + 1` in 1–3; further-out events skip. Incomplete hourly arrays abort the build. Provenance appends `leads=1-3` when present. Hand-built / sample files without `leads` keep the old shape.\n\n## What's New in v1.23.15\n\n- **Historical forecast archive builder (SIM-5434).** `scripts/build_replay_forecast_archive.py` fills the SIM-5429 loader plane from Open-Meteo Previous Runs. Tick D sees the D-1 forecast (`temperature_2m_previous_day1` hourly → daily high/low). US stations are °F; international stations are °C. The file may include `_meta` (source, fetched_at, lead=previous_day1); the loader ignores it. Auto-load is still only `fixtures/replay_forecasts.json` (uncommitted). `.sample.json` stays shape-only and is never loaded.\n\n## What's New in v1.23.14\n\n- **Replay forecast archive (SIM-5429).** This release ships a **loader**, not an archive. Under `SIMMER_REPLAY=1` the skill fills `_REPLAY_FORECASTS` from `SIMMER_REPLAY_FORECASTS=/path.json`, or from a user file `fixtures/replay_forecasts.json` when present (uncommitted). Copy your archive to `fixtures/replay_forecasts.json` (uncommitted); the `.sample.json` is shape reference only and is never loaded. Live NOAA stays dark. A set-but-missing path fails the tick. One forced provenance line (`force=True`, survives `--quiet`): path, station count, min/max date — or `no archive: NOAA dark, 0 entries is FIX`.\n- **KEEP/KILL path.** A full-tape run stays **FIX** until a real historical-forecast file covers the window. Do not treat the sample temps as history.\n\n## What's New in v1.23.13\n\n- **Replay forecast archive (SIM-5429) first cut.** Loader + sample. Round 2 (1.23.14) stopped auto-loading the invented sample.\n\n## What's New in v1.23.12\n\n- **Live price path unchanged.** `_market_yes_price` is `external_price_yes or 0.5` when not in replay. Replay-only fallthrough to `yes_price` / `current_probability`.\n- **Gate script does not print KEEP.** Unit tests are a path check. KEEP needs a full-tape `simmer backtest ... --q temperature` with evals > 0, entries > 0, and an honest forecast.\n\n## What's New in v1.23.11\n\n- **Backtest-as-gate (SIM-5428).** Replay discovery already used `q=temperature`. The entry path now works under the same harness: frozen tick (`SIMMER_REPLAY_NOW`) for horizon/date parse, replay `yes_price` (not a silent 0.50), city-station fallback when the tape omits `resolution_criteria` (Dallas still excluded), no live NOAA/Open-Meteo (look-ahead), and preflight skipped so `WALLET_UNVERIFIED` cannot block SimState fills. Import is skipped under replay so it does not burn the eval budget.\n- **Keep / kill / fix** for the real-capital path is below. 90-day Simmer P&L is still the lock. Dogfood `MIN_HOURS=12` is a separate canary — this release does not change it.\n- **Agent glue:** `python scripts/run_backtest_gate.py` runs the pinned replay tests and prints the verdict table.\n\n## What's New in v1.23.10\n\n- **Discovery horizon tracks `SIMMER_WEATHER_MIN_HOURS_TO_RESOLVE`.** The existing `tags=weather` fetch and location keyword import were newest-first / same-day heavy. They now also query +1/+2 calendar days so a morning heartbeat with `MIN_HOURS=24` still sees markets that can clear the floor. Horizon is `max(MIN_HOURS, 48h)` — raising the hours knob widens discovery; there is no separate horizon env. Do not lower the hours floor to \"fix\" morning no-fills.\n\n## What's New in v1.23.9\n\n- **Replay-compatible discovery.** Under `simmer backtest` (`SIMMER_REPLAY=1`) the skill lists markets with `q=temperature` instead of `tags=weather&status=active`. Replay rejects those filters (422). Live still uses the tag.\n- **Fail-closed on listing failure.** A failed market fetch now exits non-zero (`MarketFetchError`) so `bundle.clean` is not green on a 0-eval tick. An empty listing after a successful fetch is still a clean no-trade — that is an empty tape, not a fetch failure.\n- **Tape follow-up.** Default HF volume slices often have **0** weather markets (vol floor ~$201k in the #368 dogfood). `--min-volume` / a weather-capable tape query is server-side work; this skill does not invent weather on a high-volume slice.\n\n## What's New in v1.23.7\n\n- **Min entry price.** `SIMMER_WEATHER_MIN_ENTRY_PRICE` (default `0` = off) rejects lottery-ticket mids below the floor. `SIMMER_WEATHER_ENTRY_THRESHOLD` remains an **upper** bound only (buy when price is below it).\n- **Hours-to-resolve is now an env knob.** `SIMMER_WEATHER_MIN_HOURS_TO_RESOLVE` overrides the previous hardcoded 2h time-decay safeguard. Same check, same `check_context_safeguards` path — raise it (e.g. `24`) to skip resolve-day entries. Entry-only: exits keep the original 2h floor, so a raised value never blocks a sell. Discovery looks ahead `max(this, 48h)` so morning runs still see tomorrow's markets.\n\n## What's New in v1.23.3\n\n- **Event grouping now keys on `event_ref`** (the canonical parent-event id, present on every market) instead of the legacy `event_id`, which SDK-imported markets historically lacked. Fixes temperature buckets silently dropping out of their event group (missing buckets when `event_id` came back null).\n\n## What's New in v1.21.0\n\n- **Per-market resolution source.** Each market is now routed to the specific weather station Polymarket actually reads (parsed from the market's `resolution_criteria` field). Previously the skill used a hardcoded city → station map, which silently traded against the wrong forecast in a few cases (notably Dallas, where Polymarket resolves on Love Field / KDAL but the skill assumed DFW / KDFW). Markets that name a station the skill doesn't know are now skipped with a log line — better to skip than to trade a stale oracle. Robust to Polymarket swapping airports.\n- **Expanded NOAA station coverage.** KLGA, KJFK, KEWR, KNYC, KORD, KMDW, KSEA, KATL, KDAL, KDFW, KMIA, KBOS, KDCA, KIAD, KPHX, KLAS, KSFO, KLAX, KDEN, KMSP, KPHL.\n- **Expanded international coverage.** Adds Madrid, Milan, Amsterdam, Taipei to Open-Meteo routing (alongside existing Tel Aviv, Munich, London, Tokyo, Seoul, Ankara, Lucknow, Wellington).\n- **Requires the new `?include=resolution_criteria` flag** on `/api/sdk/markets` (live on Simmer backend 2026-05-03).\n\n## What's New in v1.20.1\n\n- **Safety rails section first.** Bounding contract surfaced at the top — paper-default, `--live` requirement, configurable caps, server-side risk monitor, strategy-side safeguards, reversibility.\n- **Risk monitor framing genericized.** Stop-loss / take-profit thresholds are described as configurable user settings rather than specific percentages. (See FAQ at docs.simmer.markets for current defaults — they're user-tunable in the dashboard.)\n- **Wallet setup link genericized.** Points at [docs.simmer.markets/wallets](https://docs.simmer.markets/wallets) instead of a named cross-skill.\n\n## What's New in v1.20.0\n\n- **SDK 0.13.0 integration** — uses `SimmerClient.from_env()` (auto-reads `SIMMER_API_KEY`, raises a clear `RuntimeError` with a dashboard pointer if unset). Requires `simmer-sdk>=0.13.0`.\n- **Slim per skill catalog reshape (Phase 3)** — duplicated wallet-setup / changelog / decorative content removed; SKILL.md trimmed to focus on what's specific to this skill.\n- **Dead code removed** — retired `AUTOMATON_*` env reads (the automaton runtime was retired 2026-04-20).\n\n## Setup\n\nFor wallet setup, see [docs.simmer.markets/wallets](https://docs.simmer.markets/wallets).\n\nRequired environment:\n- `SIMMER_API_KEY` — get from `simmer.markets/dashboard → SDK tab`\n- `WALLET_PRIVATE_KEY` — Polymarket wallet private key (the SDK signs orders client-side)\n\nThen `pip install --upgrade simmer-sdk` (>=0.13.0) and configure tunables below.\n\n## Configuration\n\n| Setting | Environment Variable | Default | Description |\n|---------|---------------------|---------|-------------|\n| Trading venue | `TRADING_VENUE` | polymarket | Venue to trade on. Set `sim` for paper trading. |\n| Entry threshold | `SIMMER_WEATHER_ENTRY_THRESHOLD` | 0.15 | **Upper** bound — buy when price is *below* this |\n| Min entry price | `SIMMER_WEATHER_MIN_ENTRY_PRICE` | 0 | **Lower** bound — skip lottery tickets below this (`0` = off), e.g. `0.15` to skip sub-15¢ tickets. Must be below the entry threshold. |\n| Min hours to resolve | `SIMMER_WEATHER_MIN_HOURS_TO_RESOLVE` | 2 | Skip entries if the market resolves in fewer than this many hours. Entry-only; exits keep a fixed 2h floor. Discovery looks ahead `max(this, 48h)` calendar days — raise it and the scan widens; a 24h floor still sees +1/+2 day markets in a morning heartbeat. |\n| Exit threshold | `SIMMER_WEATHER_EXIT_THRESHOLD` | 0.45 | Sell when price above this. Raise this if you raise entry above `0.45`, or the skill will self-exit. |\n| Max position | `SIMMER_WEATHER_MAX_POSITION_USD` | 2.00 | Maximum USD per trade |\n| Max trades/run | `SIMMER_WEATHER_MAX_TRADES_PER_RUN` | 5 | Maximum trades per scan cycle |\n| Max buys/market | `SIMMER_WEATHER_MAX_BUYS_PER_MARKET` | 1 | Cap on buy-fills into the same market (bucket), checked against held positions before entry. `1` = one entry then hold; raise to keep DCA-ing into an underpriced bucket; `0` disables the cap (unbounded DCA). |\n| Locations | `SIMMER_WEATHER_LOCATIONS` | NYC | Comma-separated cities (NYC, Chicago, Seattle, Atlanta, Dallas, Miami, Austin, Houston, Denver, Beijing, Shanghai, Guangzhou, Shenzhen, Chengdu, Chongqing, Wuhan, Qingdao, Zhengzhou, Singapore, Kuala Lumpur, Manila, Busan, Toronto, Buenos Aires, Sao Paulo, Mexico City, Cape Town, Helsinki, Jeddah, Warsaw, Paris, Panama City) |\n| Binary only | `SIMMER_WEATHER_BINARY_ONLY` | false | Skip range-bucket events (e.g., \"34-35°F\"), only trade binary yes/no markets |\n| Smart sizing % | `SIMMER_WEATHER_SIZING_PCT` | 0.05 | % of balance per trade |\n| Slippage max | `SIMMER_WEATHER_SLIPPAGE_MAX` | 0.15 | Skip trades with slippage above this (0.15 = 15%) |\n| Min liquidity | `SIMMER_WEATHER_MIN_LIQUIDITY` | 0 | Skip markets with liquidity below this USD amount (0 = disabled) |\n| Vol targeting | `SIMMER_WEATHER_VOL_TARGETING` | false | Enable volatility targeting for dynamic position sizing |\n| Target vol | `SIMMER_WEATHER_TARGET_VOL` | 0.20 | Target annualized volatility (0.20 = 20%) |\n| Vol max leverage | `SIMMER_WEATHER_VOL_MAX_LEVERAGE` | 2.0 | Max scale-up multiplier in calm markets |\n| Vol min alloc | `SIMMER_WEATHER_VOL_MIN_ALLOC` | 0.2 | Min allocation floor in volatile markets (0.2 = 20%) |\n| Vol EWMA span | `SIMMER_WEATHER_VOL_SPAN` | 10 | EWMA span for vol calculation (lower = more responsive) |\n| Order type | `SIMMER_WEATHER_ORDER_TYPE` | GTC | GTC (limit, waits for fill) or FAK (cancel if not filled). GTC recommended. |\n| Replay forecast archive | `SIMMER_REPLAY_FORECASTS` | (none) | Replay-only. JSON `{station: {YYYY-MM-DD: {high, low}}}`. Live NOAA is never used under replay. If unset, loads `fixtures/replay_forecasts.json` when you add that file (not committed). `.sample.json` is never auto-loaded. |\n\n**Legacy env var aliases** (still accepted for backwards compatibility): `SIMMER_WEATHER_ENTRY`, `SIMMER_WEATHER_EXIT`, `SIMMER_WEATHER_MAX_POSITION`, `SIMMER_WEATHER_MAX_TRADES`\n\n**Supported locations** (city-name filter applied to market questions): NYC, Chicago, Seattle, Atlanta, Dallas, Miami, Austin, Houston, Denver, Tel Aviv, Munich, London, Tokyo, Seoul, Ankara, Lucknow, Wellington, Madrid, Milan, Amsterdam, Taipei, Beijing, Shanghai, Guangzhou, Shenzhen, Chengdu, Chongqing, Wuhan, Qingdao, Zhengzhou, Singapore, Kuala Lumpur, Manila, Busan, Toronto, Buenos Aires, Sao Paulo, Mexico City, Cape Town, Helsinki, Jeddah, Warsaw, Paris, Panama City. The actual oracle station is parsed per-market from `resolution_criteria` — see \"Resolution-source routing\" below.\n\n## Resolution-source routing\n\nPolymarket weather markets carry a `resolution_criteria` field that names the exact station the market resolves on (e.g. \"Chicago O'Hare Intl Airport Station\" with `wunderground.com/.../KORD`). v1.21.0+ parses that text per-market and routes to the matching forecast station instead of a city default. If a market names a station the skill doesn't know, the event is skipped with a log line. Add new stations to `STATION_ID_TO_NOAA` (US) or `INTERNATIONAL_STATION_COORDS` (international) in `weather_trader.py` to extend coverage — PRs welcome.\n\n## SDK initialization\n\n```python\nfrom simmer_sdk import SimmerClient\n\nclient = SimmerClient.from_env(venue=\"polymarket\", live=True)\n```\n\n`from_env()` (added in simmer-sdk 0.13.0) reads `SIMMER_API_KEY` from the environment and raises `RuntimeError` with a dashboard pointer if unset. If `OWS_WALLET` is set, it auto-routes through the OpenClaw shared wallet.\n\n## Quick Commands\n\n```bash\n# Check account balance and positions\npython scripts/status.py\n\n# Detailed position list\npython scripts/status.py --positions\n```\n\n**API Reference:**\n- Base URL: `https://api.simmer.markets`\n- Auth: `Authorization: Bearer $SIMMER_API_KEY`\n- Portfolio: `GET /api/sdk/portfolio`\n- Positions: `GET /api/sdk/positions`\n\n## Running the Skill\n\n```bash\n# Dry run (default — shows opportunities, no trades)\npython weather_trader.py\n\n# Execute real trades\npython weather_trader.py --live\n\n# With smart position sizing (uses portfolio balance)\npython weather_trader.py --live --smart-sizing\n\n# Check positions only\npython weather_trader.py --positions\n\n# View config\npython weather_trader.py --config\n\n# Disable safeguards (not recommended)\npython weather_trader.py --no-safeguards\n\n# Disable trend detection\npython weather_trader.py --no-trends\n\n# Enable volatility targeting (dynamic sizing based on market vol)\npython weather_trader.py --live --smart-sizing --vol-targeting\n\n# Quiet mode — only output on trades/errors (ideal for high-frequency runs)\npython weather_trader.py --live --quiet\n```\n\n## Backtest gate (keep / kill / fix)\n\n90-day **real-capital P&L on Simmer** is the lock. This gate is the fast filter before more real capital. Dogfood's `MIN_HOURS=12` canary is a separate seat — do not change it here.\n\nReuse the existing replay harness. Do not invent a second one.\n\n```bash\n# Pinned gate (no tape, no network, no API key)\npython skills/polymarket-weather-trader/scripts/run_backtest_gate.py\n\n# Same tests, direct\npython -m pytest skills/polymarket-weather-trader/tests/test_replay_discovery.py -q\n\n# Full-tape KEEP/KILL — build a window archive, copy it (uncommitted), then replay.\n# Auto-load is fixtures/replay_forecasts.json only. .sample.json is shape-only\n# and is never loaded.\npython skills/polymarket-weather-trader/scripts/build_replay_forecast_archive.py \\\n  --start YYYY-MM-DD --end YYYY-MM-DD --out /tmp/replay_forecasts.json\ncp /tmp/replay_forecasts.json \\\n  skills/polymarket-weather-trader/fixtures/replay_forecasts.json\n# SIMMER_WEATHER_LOCATIONS defaults to \"NYC\" — a tape covering other cities\n# (Seoul, London, Chicago, ...) will show 0 entries for every one of them\n# unless you widen this list to match the tape's city mix (SIM-5484). That\n# is expected scoping, not a station/forecast bug — see the note below.\n#\n# A plain `export SIMMER_WEATHER_LOCATIONS=...` does NOT reach the skill:\n# the replay harness builds the bundle subprocess env from a strict\n# allowlist (SIM-5067) that this var is not on, so it is silently stripped\n# and the run measures NYC regardless. Use --set on the entrypoint instead\n# — it writes config.json next to weather_trader.py, which load_config()\n# reads before env vars and which survives the per-tick bundle copy.\n#\n# Name the tape's actual cities, not a generic US list. E.g. for an\n# April tape weighted Seoul/Hong Kong/London/Shanghai/NYC/Paris: Seoul,\n# London, Paris and Shanghai are mapped (INTERNATIONAL_STATION_COORDS) and\n# will enter; Hong Kong has no station mapping anywhere in the skill and\n# cannot enter no matter what's in this list.\nsimmer backtest skills/polymarket-weather-trader \\\n  --entrypoint weather_trader.py --t0 YYYY-MM-DD --t1 YYYY-MM-DD \\\n  --cadence 12h --q temperature --min-volume 0 \\\n  --args \"--live --quiet --set locations=NYC,Chicago,Seattle,Atlanta,Miami,Austin,Houston,Denver,Seoul,London,Paris,Shanghai\"\n# Then read the KEEP/KILL table below, plus the per-city entry count the\n# report prints — a KEEP/PIVOT read needs coverage across the mapped\n# international cities, not just NYC. Optional in-process / pytest:\n# export SIMMER_REPLAY_FORECASTS=/tmp/replay_forecasts.json\n```\n\n| Verdict | What the backtest / replay outcome means for the money path |\n|---------|--------------------------------------------------------------|\n| **FIX** | Path is broken or the tape cannot evaluate the skill. Do not add capital. Repair: discovery 422 / fail-open empty listing; wall-clock horizon under replay; `yes_price` ignored (silent 0.50); every event skipped for missing `resolution_criteria`; live NOAA/Open-Meteo under replay (look-ahead); preflight `WALLET_UNVERIFIED` blocking SimState fills; 0 temperature markets on a high-volume slice (`--q temperature`, lower `--min-volume`); 0 entries because the forecast archive is missing, empty, or does not cover the tape dates (`SIMMER_REPLAY_FORECASTS` / `fixtures/replay_forecasts.json` — missing forecast plane, not \"no edge\"). |\n| **not a defect** | Every entry lands in one city (default NYC) on a multi-city tape. `SIMMER_WEATHER_LOCATIONS` defaults to `\"NYC\"` — that is the skill honoring its configured scope, not a station/parsing bug. Widen it via `--set locations=...` (a plain `export` is stripped by the replay harness allowlist) to the tape's full city mix before judging KEEP/KILL from entry count (SIM-5484). Hong Kong specifically never enters on any tape — the skill has no station mapping for it, not a defect. |\n| **KILL** | Pinned pytest gate fails, **or** the path is green on a weather-capable tape, evals > 0, and the skill still cannot reach `execute_trade` when a forecast is injected or loaded from the archive, **or** after the path works, P&L after costs is clearly ≤ 0 on an honest (not live-NOAA) forecast. Do not add more real capital. |\n| **KEEP** | Full-tape `simmer backtest ... --q temperature` with evals > 0 **and** entries > 0 **and** an honest archive (not live NOAA). Pinned unit tests passing is a path check only — not KEEP. Provisional; the 90-day Simmer P&L lock still decides scale-up. |\n\nA green full-tape run that places **0** trades because NOAA is correctly dark is **FIX** (forecast plane), not **KILL**. Copy a real window-covering archive to `fixtures/replay_forecasts.json`, then re-run. The committed `.sample.json` is not loaded.\n\n## How It Works\n\nEach cycle the script:\n1. Fetches active weather markets from Simmer API (newest weather page plus dated queries out to `max(MIN_HOURS_TO_RESOLVE, 48h)`)\n2. Groups markets by event (each temperature day is one event)\n3. Parses event names to get location and date; keeps events inside that discovery horizon\n4. Fetches NOAA forecast for that location/date (under replay: archive only — never live NOAA)\n5. Finds the temperature bucket that matches the forecast\n6. **Safeguards**: Checks context for flip-flop warnings, slippage, time decay\n7. **Trend Detection**: Looks for recent price drops (stronger buy signal)\n8. **Entry**: If min-entry ≤ bucket price < entry threshold and safeguards pass → BUY\n9. **Exit**: Checks open positions, sells if price > exit threshold\n10. **Tagging**: All trades tagged with `sdk:weather` for tracking\n\n## Smart Sizing\n\nWith `--smart-sizing`, position size is calculated as:\n- 5% of available USDC balance (configurable via `SIMMER_WEATHER_SIZING_PCT`)\n- Capped at max position setting ($2.00 default)\n- Falls back to fixed size if portfolio unavailable\n\n## Volatility Targeting\n\nWith `--vol-targeting`, position sizes are dynamically adjusted based on realized market volatility:\n\n```\nposition_size = base_size × clamp(target_vol / realized_vol, min_alloc, max_leverage)\n```\n\n- **High volatility**: positions scale down → less risk\n- **Low volatility**: positions scale up → more alpha capture\n- Falls back to base size if insufficient price history (< 15 data points)\n\n## Safeguards\n\nBefore trading, the skill checks:\n- **Flip-flop warning**: Skips if you've been reversing too much\n- **Slippage**: Skips if estimated slippage > 15% (tunable via `SIMMER_WEATHER_SLIPPAGE_MAX`)\n- **Time decay**: Skips if market resolves in < `SIMMER_WEATHER_MIN_HOURS_TO_RESOLVE` hours (default 2). Discovery looks ahead `max(this, 48h)` so raising the floor does not starve morning heartbeats.\n- **Market status**: Skips if market already resolved\n\n`SIMMER_WEATHER_MIN_ENTRY_PRICE` (default 0 = off) is the other side of the entry-price check, not this list — `--no-safeguards` does not disable it.\n\nDisable the flip-flop / slippage / time-decay / resolved checks with `--no-safeguards` (not recommended).\n\n## Source Tagging\n\nAll trades are tagged with `source: \"sdk:weather\"`. This means:\n- Portfolio shows breakdown by strategy\n- Trades tagged `sdk:weather` are excluded from generic copytrade sells.\n- You can track weather P&L separately\n\n## Troubleshooting\n\n**\"Safeguard blocked: Severe flip-flop warning\"** — you've been changing direction too much on this market; wait before trading again.\n\n**\"Slippage too high\"** — market is illiquid; reduce position size or skip.\n\n**\"Resolves in Xh - too soon\"** — market resolving sooner than `SIMMER_WEATHER_MIN_HOURS_TO_RESOLVE` (default 2h). Raise the env to skip resolve-day entries. Discovery already looks ahead `max(MIN_HOURS, 48h)`, so a morning run with `MIN_HOURS=24` can still take +1/+2 day markets. Same-day buckets will always fail a 24h floor before they have 24h left.\n\n**\"Price $X.XX below min entry\"** — mid is below `SIMMER_WEATHER_MIN_ENTRY_PRICE`. Lottery-ticket floor; default is off (`0`).\n\n**\"No weather markets found\"** — weather markets may not be active (seasonal).\n\n**`simmer backtest` / \"Failed to fetch markets from Simmer API\"** — replay does not implement `tags` or `status` (422 since sdk 0.25.3/0.25.4). v1.23.9+ uses `q=temperature` under replay. A fetch failure now fails the tick (`failed_ticks`, not a clean 0-eval). If the fetch succeeds and you still see 0 weather markets, the HF volume slice likely has none — default `--min-volume` / top-volume selection is a tape follow-up, not a skill bug. Replay listings omit `resolution_criteria`; v1.23.11+ falls back to the city station table only when criteria is **missing** (Dallas excluded; present-but-unreadable still skips). Live NOAA is never called under replay.\n\n**A full-tape run with 0 entries and NOAA dark is FIX** until a real archive covers the tape dates. Build one with `scripts/build_replay_forecast_archive.py`, then copy it to `fixtures/replay_forecasts.json` before `simmer backtest` (harness strips host env; that user file is copied with the bundle). Shape: `{ \"_meta\": {…}, \"KLGA\": { \"2026-04-30\": { \"high\": 72, \"low\": 50, \"leads\": { \"1\": {…}, \"2\": {…}, \"3\": {…} } } } }` — top-level high/low is lead 1; `_meta` is ignored. Hand-built files may omit `leads`. `fixtures/replay_forecasts.sample.json` is that shape only — invented test temps, never auto-loaded. A set-but-missing path fails the tick. Do not treat a 0-entry tape as no-edge. See **Backtest gate** above.\n\n**\"External wallet requires a pre-signed order\"** — `WALLET_PRIVATE_KEY` is not set. Fix: `export WALLET_PRIVATE_KEY=0x<your-polymarket-wallet-private-key>`. The SDK signs orders automatically when this env var is present — do not attempt to sign orders manually.\n\n**\"Balance shows $0 but I have funds on Polygon\"** — Polymarket V2 (live 2026-04-28) uses **pUSD** (PolyUSD, 1:1 backed by USDC.e). Migrate at [simmer.markets/dashboard](https://simmer.markets/dashboard?ref=sdk-skill&utm_campaign=sdk-skill) (~30s). Full guide: [docs.simmer.markets/v2-migration](https://docs.simmer.markets/v2-migration).\n\n**\"API key invalid\"** — get a new key from simmer.markets/dashboard → SDK tab.\n\nFile v1.23.22:_meta.json\n\n{\n  \"ownerId\": \"kn7axnp7bzqsf5fkx0z8px7han7zyq1x\",\n  \"slug\": \"polymarket-weather-trader\",\n  \"version\": \"1.23.22\",\n  \"publishedAt\": 1789708464718\n}\n\nFile v1.23.22:CHANGELOG.md\n\n# Changelog\n\n## [1.23.22] - 2026-09-18\n\n### Added\n- **Per-market position cap (SIM-5499).** `max_buys_per_market` (`SIMMER_WEATHER_MAX_BUYS_PER_MARKET`, default `1`) checks held positions via `get_positions()` before entry and skips a market that's already at cap. The 2026-09-17 gate run's replay DCA'd into every underpriced bucket every tick (mean 34 buys/market, max 137, 94.8% max DD) while live lands 1-2 because balance/backoffs throttle it — the two were measuring different strategies. Default `1` makes replay one-buy-per-market like live; raise it to keep DCA, or set `0` for the old unbounded behavior.\n\n### Changed\n- Requires `simmer-sdk>=0.25.8`, the first release whose `preflight()` is replay-aware. On an older SDK a backtest of this skill stops filling, because preflight blocks replay trades now that the skill no longer passes `skip_preflight`. Live trading is unaffected.\n\n### Fixed\n- **Skip reasons were collected but never surfaced.** `run_weather_strategy` built a `skip_reasons` list all run and never printed it, so diagnosing \"location X entered zero markets\" (the London 0/36 half of SIM-5499) meant re-reading per-tick logs. The summary now prints a per-location skip-reason breakdown (forces past `--quiet`, same as the station-parse coverage guard), and the two skip paths that carried no reason at all (\"no forecast available\", \"no bucket found\") now record one. Events whose text never parses into a location are tracked separately by a snippet of the event name.\n\n## [1.23.20] - 2026-09-17\n\n### Changed\n- **Replay trades no longer pass the deprecated `skip_preflight` valve (SIM-5430).** `SimmerClient.preflight()` is replay-aware under `SIMMER_REPLAY=1` on a loopback base URL, so `execute_trade` / `execute_sell` drop `skip_preflight=replay`. Live behaviour unchanged: preflight still runs and still blocks on `WALLET_UNVERIFIED`. Version skips 1.23.18/1.23.19, reserved for #384 and SIM-5440 which are in flight.\n## [1.23.19] - 2026-09-17\n\n### Fixed\n- Replay archive builder hardening from the KEEP/KILL run (SIM-5440): Open-Meteo HTTP 5xx responses retry up to 3 attempts with backoff, while HTTP 4xx still aborts immediately.\n- Long or old Previous Runs windows are fetched in 10-day chunks and merged internally. The build aborts if `utc_offset_seconds` differs across chunks for a station.\n- Added `--stations us|intl|all` (default `all`). `us` limits the build to the 8 configured Polymarket US resolution stations, so US-only archives avoid international DST guards and 56 needless requests.\n\n## [1.23.18] - 2026-09-17\n\n### Fixed\n- **Replay positions were always empty (SIM-5484).** `get_positions()` filtered by `venue=\"polymarket\"` even under replay, but the replay server rejects any `venue` filter (422, SIM-5067). The 422 was swallowed to `[]`, so the skill never knew what it already held and re-bought the same bucket every tick (13-25x/market observed on a full-tape run). Replay now omits the venue filter; live is unchanged.\n\n### Docs\n- **`SIMMER_WEATHER_LOCATIONS` defaulting to `\"NYC\"` is not a bug.** A full-tape backtest with markets from many cities will show entries in NYC only unless this env var is widened to match the tape's city mix. Documented in the KEEP/KILL table and the reproduction recipe so a single-city result isn't misread as a station/forecast defect.\n- **The reproduction recipe's `export SIMMER_WEATHER_LOCATIONS=...` does not work under replay.** The bundle subprocess env is built from a strict allowlist (SIM-5067) that this var is not on, so the export was silently stripped and every re-run still measured NYC only. Recipe now uses `--set locations=...` on the entrypoint (writes `config.json`, which `load_config()` reads before env vars and which survives the bundle copy), and names the tape's actual cities instead of a generic US list. Hong Kong is called out separately: it has no station mapping anywhere in the skill (checked `LOCATIONS` and `INTERNATIONAL_STATION_COORDS`) and cannot enter regardless of this list — not a defect, just unmapped coverage.\n\n## [1.23.17] - 2026-09-16\n\n### Fixed\n- **Lead selection uses station-local event end, not UTC date (SIM-5434).** `_replay_lead_for_event(event_date, station_id)` picks the smallest N in 1–3 such that `E_end_utc − N·24h ≤ tick`. `E_end_utc` is the event date's 23:59:59 in `_meta[\"utc_offset_seconds\"][station]`. Unknown offset assumes UTC−12; provenance then includes `tz=assumed`. A 00:30Z tick no longer assigns Seattle May 1 to lead 2.\n- **Hourly fold requires 00:00–23:00 each once.** No 23–25 DST blanket. A missing 18:00 aborts the build.\n- Builder fetch retries URL errors twice (60s timeout) so a transient SSL timeout does not abort a 64-station build.\n- **Windows that cross a DST transition are refused.** Open-Meteo labels every hour with the request-time offset, so a cross-transition window folds the wrong local hours. `reject_dst_crossing` (zoneinfo on the payload `timezone`) aborts with \"split the window at the transition date\".\n\n## [1.23.16] - 2026-09-16\n\n### Fixed\n- **Look-ahead via `previous_day1` (SIM-5434).** Hourly `temperature_2m_previous_day1` at valid hour H is the run ~24h before H, not one D-1 issuance. Horizon (D+2) and same-day-ahead evening hours could see a run issued after the replay tick. The builder now fetches leads 1–3 in one request and writes `{high, low, leads}`. The loader picks `lead = (event_date − tick.date).days + 1` in 1–3; further-out events skip. Top-level high/low stays lead 1. Archives without `leads` (sample / hand-built) keep the old path. Provenance appends `leads=1-3` when present.\n- **Incomplete hourly responses fail closed.** Missing or short arrays, a null hour, or a missing requested date raise `ArchiveBuildError` naming station/date/lead. One valid hour is not a daily high/low.\n\n## [1.23.15] - 2026-09-16\n\n### Added\n- **Historical forecast archive builder (SIM-5434).** `scripts/build_replay_forecast_archive.py --start YYYY-MM-DD --end YYYY-MM-DD --out …` fetches Open-Meteo Previous Runs (`temperature_2m_previous_day1` hourly on the forecast endpoint, per station coord) and writes `{_meta, station: {date: {high, low}}}`. Tick D sees the D-1 forecast. US stations (LOCATIONS / STATION_ID_TO_NOAA) are °F; international stations are °C — same as `_station_forecast`. `_meta` is source / fetched_at / lead=previous_day1.\n\n### Fixed\n- Loader ignores `_meta` so a builder file does not look like a station.\n\n### Docs\n- KEEP/KILL sequence is now build → copy to `fixtures/replay_forecasts.json` (uncommitted; `.sample.json` is shape-only) → `simmer backtest` → read the table. Auto-load is still only the user file, never the sample.\n\n## [1.23.14] - 2026-09-16\n\n### Fixed\n- The committed sample is never auto-loaded. Invented KLGA / 2026-04-30 temps live only in `fixtures/replay_forecasts.sample.json` (shape reference). Auto-load is `SIMMER_REPLAY_FORECASTS` or a user file `fixtures/replay_forecasts.json` (gitignored). Default plane is empty → honest FIX.\n- One forced provenance line (`force=True`): path, station count, min/max date, or `no archive: NOAA dark, 0 entries is FIX`.\n- Startup uses `_ensure_replay_forecasts_loaded()` so an inject is not clobbered by a later file load.\n\n### Docs\n- Copy your archive to `fixtures/replay_forecasts.json` (uncommitted); the `.sample.json` is shape reference only and is never loaded. This release ships a loader, not an archive. A full-tape run stays FIX until a real historical-forecast file covers the window.\n\n## [1.23.13] - 2026-09-16\n\n### Added\n- **Replay forecast archive loader (SIM-5429).** Under `SIMMER_REPLAY=1`, `load_replay_forecasts()` fills `_REPLAY_FORECASTS` from `SIMMER_REPLAY_FORECASTS=/path.json` (same `{station: {YYYY-MM-DD: {high, low}}}` shape the tests inject). If the env is unset, a user file `fixtures/replay_forecasts.json` is used when present (not committed). The shipped `fixtures/replay_forecasts.sample.json` is a shape example only and is never auto-loaded. Live NOAA/Open-Meteo stay dark. A set-but-missing path raises `ReplayForecastArchiveError`. The replay archive line always prints (`force=True`) with station count and min/max date.\n\n### Docs\n- Full-tape KEEP/KILL: copy a window-covering archive to `fixtures/replay_forecasts.json`, then `simmer backtest … --q temperature`. 0 entries with NOAA dark is FIX when no user archive is in place. Do not treat the sample temps as history.\n\n## [1.23.12] - 2026-09-16\n\n### Fixed\n- Live price path is again `external_price_yes or 0.5`. Replay-only fallthrough to `yes_price` / `current_probability`. `None` and `0.0` stay 0.5 on live.\n- City-station fallback only when criteria is missing (`SKIP_MISSING_CRITERIA`). Present-but-unreadable still skips. Fallbacks use their own counter, not `station_parse_ok`.\n\n### Docs\n- `run_backtest_gate.py` prints a path-check line, not KEEP. KEEP requires a full-tape `simmer backtest ... --q temperature` with evals > 0, entries > 0, and an honest forecast. A full-tape run cannot produce KEEP or KILL until a forecast archive exists; 0 entries with NOAA dark is FIX.\n\n## [1.23.11] - 2026-09-16\n\n### Added\n- **Backtest-as-gate (SIM-5428).** Extends the #368 replay discovery tests into an explicit keep/kill gate for the real-capital path. `scripts/run_backtest_gate.py` runs those pinned tests and prints the verdict table. 90-day Simmer P&L remains the lock. Dogfood `MIN_HOURS=12` is unchanged.\n\n### Fixed\n- Replay entry path used wall-clock `datetime.now()` (horizon/date parse dropped historical tape rows), ignored replay `yes_price` (silent 0.50), skipped every event when the tape omitted `resolution_criteria`, called live NOAA (look-ahead), and hit `WALLET_UNVERIFIED` on `agents/me` so SimState never filled. Under `SIMMER_REPLAY=1` the skill now uses `SIMMER_REPLAY_NOW`, replay price fields, the existing city-station fallback (Dallas still excluded), injected `_REPLAY_FORECASTS` only, skips live import (eval budget), and passes `skip_preflight=True`.\n\n## [1.23.10] - 2026-09-14\n\n### Fixed\n- Discovery/scan was newest-first and same-calendar-day heavy. A morning heartbeat with `SIMMER_WEATHER_MIN_HOURS_TO_RESOLVE=24` then saw only resolve-day buckets (\"Resolves in 10–22h - too soon\") and took 0 fills. The existing `tags=weather` fetch and location keyword import now also query +1/+2 calendar days. Horizon is `max(MIN_HOURS_TO_RESOLVE, 48h)` — no new env knob.\n\n### Docs\n- Raising `MIN_HOURS_TO_RESOLVE` widens discovery. Do not lower the hours floor to fix morning no-fills.\n\n## [1.23.9] - 2026-09-14\n\n### Fixed\n- **Replay discovery.** `GET /api/sdk/markets?tags=weather&status=active` 422s on the backtest replay server (sdk 0.25.3/0.25.4). Under `SIMMER_REPLAY=1` the skill now uses the existing replay `q=` path (`q=temperature`) and omits `tags`/`status`. Live still uses the weather tag — questions like \"Austin 82-83F on Sep 7\" do not contain \"weather\".\n- **Fail-closed on listing failure.** `fetch_weather_markets()` used to swallow the 422, return `[]`, and exit 0 — `bundle.clean=true` with 0 evals. It now raises `MarketFetchError` so the tick is `failed_ticks`. An empty 200 is still a clean no-trade (empty tape).\n\n### Docs\n- Tape gap: default HF volume slices in the #368 dogfood had 0 weather/temperature markets (vol floor ~$201k). A weather-capable tape query (`tags`, lower `--min-volume`, or a dedicated weather slice) is server/slice follow-up. This skill does not pretend a high-volume slice contains weather.\n\n## [1.23.8] - 2026-09-08\n\n### Added\n- Added 26 Polymarket weather resolution stations: `KAUS`, `KHOU`, `KBKF`, `ZBAA`, `ZSPD`, `ZGGG`, `ZGSZ`, `ZUUU`, `ZUCK`, `ZHHH`, `ZSQD`, `ZHCC`, `WSSS`, `WMKK`, `RPLL`, `RKPK`, `CYYZ`, `SAEZ`, `SBGR`, `MMMX`, `FACT`, `EFHK`, `OEJN`, `EPWA`, `LFPB`, and `MPMG`. US stations route through NOAA with Open-Meteo cross-checks; international stations route through exact airport coordinates instead of city centers.\n\n## [1.23.7] - 2026-09-08\n\n### Added\n- `SIMMER_WEATHER_MIN_ENTRY_PRICE` (default `0` = off). Rejects entries below this mid so a raised `ENTRY_THRESHOLD` (upper bound only) cannot buy lottery tickets. Same entry-price check as before; this is the missing floor.\n- `SIMMER_WEATHER_MIN_HOURS_TO_RESOLVE` (default `2`). Env override of the hardcoded time-decay constant inside `check_context_safeguards`. Entry-only: exits keep the original 2h floor. No new gate, no calendar-day skip.\n\n### Docs\n- `ENTRY_THRESHOLD` is documented as an upper bound only. Raising it above the `0.45` exit default will self-exit unless `EXIT_THRESHOLD` is raised too.\n\n## [1.23.6] - 2026-09-06\n\n### Fixed\n- **Polymarket reworded every weather-temperature market on 2026-08-22 and the station parser stopped reading all of them.** The criteria dropped their Wunderground URL (resolution source moved to NOAA) and gained an agency clause — `recorded BY NOAA at the LaGuardia Airport Station`. Both parser patterns matched neither, so `parse_resolution_station()` returned `None` on 100% of current criteria and the skill skipped every event without entering. Verified against the live corpus: 2,195 of 2,596 active weather-temperature markets carry the new wording; only 84 keep the old. The station phrase now accepts an optional, generic agency clause, so `by NWS` or `by the National Weather Service` will not break it again.\n- Added name aliases for three stations Polymarket cites under a different name than our coordinate tables hold: `Hartsfield-Jackson International Airport` → `KATL`, `Amsterdam Airport Schiphol` → `EHAM`, `Malpensa Intl Airport` → `LIMC`. With these, all 16 advertised locations route again — the six US cities in `SIMMER_WEATHER_LOCATIONS` plus every international alias. Aliases may only point at stations we already have coordinates for; routing a market to an airport we cannot forecast is the silent KDFW/KDAL failure mode.\n- The skip log no longer claims `need SDK ≥ 2026-05-03` when criteria is present. Missing criteria and unreadable criteria were sharing one message that blamed a stale SDK for both; they are now distinct reasons.\n\n### Added\n- Parse-coverage guard. When a run reads a station out of fewer than 50% of the events that had criteria, the skill says so loudly (surviving `--quiet`) instead of reporting a clean scan. A parser that falls behind upstream wording throws nothing, fails no trade and retries nothing, so every downstream health metric stays green while the skill quietly stops entering — this was invisible for two weeks. The warning names the real cause: it is not finding no opportunities, it is failing to look.\n- `parse_resolution_station_result(criteria)` — returns the station plus the reason it could not be read (`SKIP_MISSING_CRITERIA` / `SKIP_UNPARSEABLE_CRITERIA`). `parse_resolution_station()` is unchanged for existing callers.\n- Whitespace in the station phrase is collapsed before matching, so the pattern uses literal single spaces. The first cut used `\\s+` around the lazy capture, which let the engine repartition a whitespace run on every failure — `recorded at the` followed by 1,600 spaces took 6.8s, growing ~8x per doubling. Criteria text is authored upstream, so one malformed market would have stalled the whole scan. Collapsing first also means a station phrase wrapped across newlines now parses, which the old pattern could not do.\n- `tests/test_resolution_criteria_reword.py` — pins the new and old wording, the reason split, alias-to-coordinate integrity, and the coverage guard's thresholds against live criteria strings.\n\n### Thanks\n- Reported by the Grok Bot dogfood seat, which caught it on a clean v1.23.5 install and correctly identified that the log message was lying about the cause.\n\n\n## [1.23.4] - 2026-07-22\n\n### Fixed\n- Added `EGLC` (London City Airport) to the international station coordinate map so Polymarket London weather markets that cite the official London City station can route to Open-Meteo instead of fail-closing as an unsupported station. This does not change markets whose Simmer/SDK metadata lacks usable `resolution_criteria`; those still fail closed.\n- `order_type=FOK` (Fill Or Kill) is now overridden to GTC, the same way `FAK` has been since v1.20.0. Weather markets are structurally illiquid — both FOK and FAK orders are cancelled immediately with no fill, creating a retry-loop that burns attempts on every run. The warning message now names the actual configured type (`FAK` or `FOK`) so it's actionable.\n\n## [1.22.2] - 2026-05-24\n\n### Fixed\n- Intl markets where Polymarket cites the resolution station by NAME only (no Wunderground URL / no ICAO) are no longer silently skipped (SIM-2428). Added a normalized-name → ICAO fallback index covering all 21 US + 16 intl stations. Normalizer strips diacritics (`ğ→g`), trailing `Intl` / `International` / `Airport` tokens, and lowercases — so `Esenboğa Intl Airport`, `Esenboga International Airport`, and `Esenboga Intl Airport` all resolve to `LTAC`.\n- Added `name` field to all 16 `INTERNATIONAL_STATION_COORDS` entries (US table already had it). The name-index is built from both tables at module load.\n\n### Added\n- `resolve_station_id_from_name(station_name)` — public helper for name-to-ICAO lookup.\n- `_normalize_station_name(name)` — internal normalizer used by the index + resolver.\n\n### Behavior delta\nRouting logic now: (a) if `station_id` is present in maps → as before; (b) if `station_id is None` but `station_name` matches an index entry → resolved and logged; (c) otherwise skip with the same message as before. No behavior change for markets that already resolve via ICAO.\n\n## [1.22.1] - 2026-05-24\n\n### Fixed\n- `Matching bucket: None` log when a market's `outcome_name` field is explicitly `None` (matcher loop fell back to `question`, but post-selection line used `.get(\"outcome_name\", \"\")` which returns `None` not the default). Same class-of-bug as SIM-2371. Closes SIM-2427 issue 1.\n- Source-tier classification + log now runs for EVERY bucket-matched candidate, not only those that pass safeguards. Moved the cross-check fetch + `evaluate_source_agreement` call from inside the entry-threshold branch to immediately after bucket-match. Sizing application stays in the entry-threshold branch. Autoresearch + dogfood receipts now see would-have-been tier classification on slippage-blocked candidates too. Closes SIM-2427 issue 2.\n\n### Cost note\nThe cross-check now fires on every bucket-matched candidate (vs. only entry-eligible ones in 1.22.0). `secondary_cache[station_id]` deduplicates within a scan run, so worst case = 1 Open-Meteo fetch per unique station per scan, unchanged from 1.22.0 for any candidate that reached entry-threshold evaluation. New cost: candidates above entry threshold now also incur the fetch — bounded by the per-station cache.\n\n## [1.22.0] - 2026-05-24\n\n### Added\n- Multi-source bucket-confidence scoring (SIM-2420). Cross-checks NOAA primary against Open-Meteo secondary at the same station coords before sizing live entries. Four tiers:\n  - `match` (same bucket) → normal size\n  - `adjacent` (neighboring bucket, spread ≤ MAX_SOURCE_SPREAD_F) → cap to MAX_CANARY_USD (default $2)\n  - `wide` (spread > MAX_SOURCE_SPREAD_F or non-adjacent buckets) → skip\n  - `missing_secondary` (intl markets — Open-Meteo IS primary) → behave per REQUIRE_SOURCE_AGREEMENT\n- Four new env knobs:\n  - `SIMMER_WEATHER_REQUIRE_SOURCE_AGREEMENT` (default `false`)\n  - `SIMMER_WEATHER_CANARY_ON_ADJACENT_DISAGREEMENT` (default `true`)\n  - `SIMMER_WEATHER_MAX_CANARY_USD` (default `2.0`)\n  - `SIMMER_WEATHER_MAX_SOURCE_SPREAD_F` (default `2.0`)\n- `source_agreement` block added to trade signal payload (tier, primary/secondary temps, spread, secondary bucket).\n- `get_openmeteo_forecast_for_us_station(station_id)` — returns Open-Meteo forecast at a NOAA-mapped US station's coords, converted to °F.\n- 14 unit tests covering the 4 tier branches + edge cases (Celsius spread conversion, canary ceiling-not-floor behavior, etc.).\n\n### Rationale\nPolymarket weather markets have whole-degree buckets — a ~1°F source disagreement can flip the outcome. Prior versions sized fully whenever NOAA crossed an entry threshold. Herman's dogfood (Atlanta May 26 KATL) surfaced cases where NOAA placed the forecast in one bucket while Open-Meteo placed it in an adjacent or non-adjacent bucket; this release downgrades sizing tier in those cases instead of trading with full conviction.\n\n## [1.21.2] - 2026-05-23\n\n### Fixed\n- `check_exit_opportunities` no longer crashes with `TypeError: argument of type 'NoneType' is not iterable` when a position's `sources` field is `None` (e.g. paper-mode entries). Changed `pos.get(\"sources\", [])` → `pos.get(\"sources\") or []` so explicit `None` values are coalesced to `[]`. Closes SIM-2371.\n\n## [1.21.1] - prior\n- See git history.\n\nFile v1.23.22:DISCLAIMER.md\n\n# Disclaimer\n\nThis skill is a **framework**, not a production trading system. Read this\nin full before connecting it to a wallet with real funds.\n\n## No financial advice\n\nNothing in this skill constitutes financial, investment, or trading\nadvice. The default strategy implemented here is a starting point, not a\ntested edge. Suitability for any account size or risk tolerance is your\nresponsibility to assess.\n\n## Default parameters are not validated\n\nDefault parameters are calibrated for testing the plumbing, not for live\nprofit. They have not been validated to produce positive returns under\ncurrent market conditions. Run paper mode for an extended period before\nscaling beyond default position sizes.\n\n## Automated trading carries irreversible risk\n\nWhen this skill runs with `--live`, it places real on-chain orders.\nOn-chain trades cannot be recalled. Strategy errors, signal lag, market\nregime shifts, and operator misconfiguration can produce losses\nexceeding any specific position size.\n\n## Risk monitoring may not apply to all market types\n\nStop-loss and take-profit monitors run on a fixed schedule. Markets that\nresolve faster than the monitor cycle cannot be exited automatically.\n\nSome markets also resolve by gapping rather than decaying. Weather\ntemperature buckets are the clearest case: the losing side can sit near\nyour entry, then jump straight to about 0 at resolution, with no\nintermediate price for a percentage stop to trigger on and no liquidity\nto exit into. On these markets a stop-loss cannot cap your loss\nregardless of the monitor cycle.\n\nPosition sizing is the only reliable risk control on these markets. Set\nit conservatively, assuming the full position can go to zero.\n\n## Use of this skill is at your own risk\n\nBy installing and running this skill you agree that the authors are not\nliable for any losses, direct or indirect, that arise from its use. This\napplies regardless of skill provenance — official Simmer skills,\ncommunity skills, and skills imported from external repositories all\ncarry this same disclaimer.\n\n## Where to learn more before going live\n\n- The skill's own `SKILL.md` documents the strategy and parameters\n- Your trading venue's documentation covers fee structure, order types,\n  and resolution rules\n- Simmer SDK documentation covers paper mode, dry-run flags, and\n  position monitoring\n\nFile v1.23.22:skill-card.md\n\n## Description:\n\nTrades Polymarket weather markets using NOAA and Open-Meteo forecasts through the Simmer API.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[simmer](https://clawhub.ai/user/simmer)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nExternal users and developers use this skill to inspect, configure, paper-trade, or explicitly live-trade weather prediction markets based on forecast data and market prices. It also supports position checks and replay/backtest workflows for validating the trading path before adding capital.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: The skill can place real-money trades when live mode is enabled, and automated trading can produce irreversible losses.\n\nMitigation: Start in dry-run or TRADING_VENUE=sim, keep tight platform and per-trade caps, and use --live only after accepting the trading risk.\n\nRisk: Some safeguards can be bypassed or fail open when context data is unavailable or when --no-safeguards is used.\n\nMitigation: Keep safeguards enabled, review preflight/status output before live use, and avoid --no-safeguards unless the operator has independently verified the market context.\n\nRisk: Weather bucket markets can resolve by gapping directly to near zero, so stop-loss monitoring may not cap downside.\n\nMitigation: Size positions assuming the full position can be lost, keep max position and max buys per market conservative, and rely on position sizing rather than stop-losses alone.\n\nRisk: External-wallet self-custody mode may require WALLET_PRIVATE_KEY, which increases credential exposure if handled casually.\n\nMitigation: Avoid providing WALLET_PRIVATE_KEY unless external-wallet live trading is required, prefer paper or managed-wallet flows first, and keep credentials scoped to the runtime environment.\n\n## Reference(s):\n\n- [ClawHub skill page](https://clawhub.ai/simmer/skills/polymarket-weather-trader)\n- [Simmer wallet setup](https://docs.simmer.markets/wallets)\n- [Simmer V2 migration](https://docs.simmer.markets/v2-migration)\n- [Open-Meteo Previous Runs API](https://previous-runs-api.open-meteo.com/v1/forecast)\n- [NOAA Weather API](https://api.weather.gov)\n\n## Skill Output:\n\n**Output Type(s):** [Text, Markdown, Code, Shell commands, Configuration, Guidance]\n\n**Output Format:** [Markdown guidance with inline shell commands, Python entrypoints, JSON configuration, and console summaries.]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [May place simulated or live trading orders only when invoked with the required runtime configuration and explicit live mode.]\n\n## Skill Version(s):\n\n1.23.22 (source: server evidence, SKILL.md frontmatter, CHANGELOG)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nFile v1.23.22:clawhub.json\n\n{\n  \"emoji\": \"\\ud83c\\udf21\\ufe0f\",\n  \"primaryEnv\": \"SIMMER_API_KEY\",\n  \"requires\": {\n    \"env\": [\n      \"SIMMER_API_KEY\"\n    ],\n    \"pip\": [\n      \"simmer-sdk>=0.25.8\"\n    ]\n  },\n  \"envVars\": [\n    {\n      \"name\": \"SIMMER_API_KEY\",\n      \"required\": true,\n      \"description\": \"Your Simmer SDK API key \\u2014 get from simmer.markets/dashboard\"\n    },\n    {\n      \"name\": \"WALLET_PRIVATE_KEY\",\n      \"required\": false,\n      \"description\": \"Only needed for external-wallet self-custody trading. Not required when using managed wallets.\"\n    },\n    {\n      \"name\": \"TRADING_VENUE\",\n      \"required\": false,\n      \"description\": \"Optional. Set to 'sim' for paper trading or 'kalshi' for Solana trading. Defaults to 'polymarket'.\"\n    },\n    {\n      \"name\": \"SIMMER_WEATHER_ENTRY_THRESHOLD\",\n      \"required\": false,\n      \"description\": \"Upper bound: buy when bucket price is below this (default 0.15).\"\n    },\n    {\n      \"name\": \"SIMMER_WEATHER_MIN_ENTRY_PRICE\",\n      \"required\": false,\n      \"description\": \"Lower bound: skip lottery-ticket mids below this (default 0 = off).\"\n    },\n    {\n      \"name\": \"SIMMER_WEATHER_MIN_HOURS_TO_RESOLVE\",\n      \"required\": false,\n      \"description\": \"Skip entries if the market resolves in fewer than this many hours (default 2). Entry-only; exits keep a 2h floor. Discovery looks ahead max(this, 48h) so a morning heartbeat can still see +1/+2 day markets.\"\n    },\n    {\n      \"name\": \"SIMMER_WEATHER_EXIT_THRESHOLD\",\n      \"required\": false,\n      \"description\": \"Sell when price above this (default 0.45). Raise this if you raise ENTRY above 0.45, or the skill will self-exit.\"\n    },\n    {\n      \"name\": \"SIMMER_WEATHER_MAX_POSITION_USD\",\n      \"required\": false,\n      \"description\": \"Max USD per trade (default 2.00).\"\n    },\n    {\n      \"name\": \"SIMMER_WEATHER_SIZING_PCT\",\n      \"required\": false,\n      \"description\": \"Smart-sizing fraction of available balance (default 0.05).\"\n    },\n    {\n      \"name\": \"SIMMER_WEATHER_MAX_TRADES_PER_RUN\",\n      \"required\": false,\n      \"description\": \"Max trades per scan cycle (default 5).\"\n    },\n    {\n      \"name\": \"SIMMER_WEATHER_LOCATIONS\",\n      \"required\": false,\n      \"description\": \"Comma-separated cities (default 'NYC'). Supported: NYC, Chicago, Seattle, Atlanta, Dallas, Miami, Austin, Houston, Denver, Tel Aviv, Munich, London, Tokyo, Seoul, Ankara, Lucknow, Wellington, Madrid, Milan, Amsterdam, Taipei, Beijing, Shanghai, Guangzhou, Shenzhen, Chengdu, Chongqing, Wuhan, Qingdao, Zhengzhou, Singapore, Kuala Lumpur, Manila, Busan, Toronto, Buenos Aires, Sao Paulo, Mexico City, Cape Town, Helsinki, Jeddah, Warsaw, Paris, Panama City.\"\n    },\n    {\n      \"name\": \"SIMMER_WEATHER_BINARY_ONLY\",\n      \"required\": false,\n      \"description\": \"Set true to skip range-bucket events and only trade binary yes/no markets (default false).\"\n    },\n    {\n      \"name\": \"SIMMER_WEATHER_SLIPPAGE_MAX\",\n      \"required\": false,\n      \"description\": \"Skip trades with slippage above this (default 0.15 = 15%).\"\n    },\n    {\n      \"name\": \"SIMMER_WEATHER_MIN_LIQUIDITY\",\n      \"required\": false,\n      \"description\": \"Skip markets with liquidity below this USD threshold (default 0 = disabled).\"\n    },\n    {\n      \"name\": \"SIMMER_WEATHER_ORDER_TYPE\",\n      \"required\": false,\n      \"description\": \"Order type: GTC (default, limit waits for fill) or FAK (cancel if not filled immediately).\"\n    },\n    {\n      \"name\": \"SIMMER_WEATHER_VOL_TARGETING\",\n      \"required\": false,\n      \"description\": \"Enable volatility targeting for dynamic position sizing (default false).\"\n    },\n    {\n      \"name\": \"SIMMER_WEATHER_TARGET_VOL\",\n      \"required\": false,\n      \"description\": \"Target annualized volatility when vol_targeting is enabled (default 0.20 = 20%).\"\n    },\n    {\n      \"name\": \"SIMMER_WEATHER_VOL_MAX_LEVERAGE\",\n      \"required\": false,\n      \"description\": \"Max scale-up multiplier from vol targeting (default 2.0).\"\n    },\n    {\n      \"name\": \"SIMMER_WEATHER_VOL_MIN_ALLOC\",\n      \"required\": false,\n      \"description\": \"Min allocation floor from vol targeting (default 0.2).\"\n    },\n    {\n      \"name\": \"SIMMER_WEATHER_VOL_SPAN\",\n      \"required\": false,\n      \"description\": \"EWMA span for vol calculation; lower = more responsive (default 10).\"\n    },\n    {\n      \"name\": \"SIMMER_WEATHER_REQUIRE_SOURCE_AGREEMENT\",\n      \"required\": false,\n      \"description\": \"Skip on any NOAA/Open-Meteo bucket disagreement (no canary fallback). Default false.\"\n    },\n    {\n      \"name\": \"SIMMER_WEATHER_CANARY_ON_ADJACENT_DISAGREEMENT\",\n      \"required\": false,\n      \"description\": \"Cap to MAX_CANARY_USD on adjacent-bucket source disagreement instead of skipping. Default true.\"\n    },\n    {\n      \"name\": \"SIMMER_WEATHER_MAX_CANARY_USD\",\n      \"required\": false,\n      \"description\": \"Max position USD when source disagreement triggers canary mode (default $2).\"\n    },\n    {\n      \"name\": \"SIMMER_WEATHER_MAX_SOURCE_SPREAD_F\",\n      \"required\": false,\n      \"description\": \"Max degrees-F spread between primary + secondary forecast before skipping outright (default 2.0).\"\n    },\n    {\n      \"name\": \"SIMMER_REPLAY_FORECASTS\",\n      \"required\": false,\n      \"description\": \"Replay-only. Path to a JSON forecast archive {station: {YYYY-MM-DD: {high, low}}}. Live NOAA is never used under replay. For simmer backtest, copy a real archive to fixtures/replay_forecasts.json (not committed; host env is stripped). The .sample.json file is never auto-loaded.\"\n    }\n  ],\n  \"cron\": null,\n  \"autostart\": false,\n  \"automaton\": {\n    \"managed\": true,\n    \"entrypoint\": \"weather_trader.py\"\n  },\n  \"tunables\": [\n    {\n      \"env\": \"SIMMER_WEATHER_ENTRY_THRESHOLD\",\n      \"type\": \"number\",\n      \"default\": 0.15,\n      \"range\": [\n        0.01,\n        0.3\n      ],\n      \"step\": 0.01,\n      \"label\": \"Entry edge threshold (upper bound)\"\n    },\n    {\n      \"env\": \"SIMMER_WEATHER_MIN_ENTRY_PRICE\",\n      \"type\": \"number\",\n      \"default\": 0,\n      \"range\": [\n        0,\n        0.5\n      ],\n      \"step\": 0.01,\n      \"label\": \"Min entry price (lottery-ticket floor; 0 = off)\"\n    },\n    {\n      \"env\": \"SIMMER_WEATHER_MIN_HOURS_TO_RESOLVE\",\n      \"type\": \"number\",\n      \"default\": 2,\n      \"range\": [\n        0,\n        72\n      ],\n      \"step\": 1,\n      \"label\": \"Min hours to resolution (time-decay skip)\"\n    },\n    {\n      \"env\": \"SIMMER_WEATHER_EXIT_THRESHOLD\",\n      \"type\": \"number\",\n      \"default\": 0.45,\n      \"range\": [\n        0.1,\n        0.99\n      ],\n      \"step\": 0.01,\n      \"label\": \"Exit probability threshold\"\n    },\n    {\n      \"env\": \"SIMMER_WEATHER_MAX_POSITION_USD\",\n      \"type\": \"number\",\n      \"default\": 2.0,\n      \"range\": [\n        1,\n        50\n      ],\n      \"step\": 1,\n      \"label\": \"Max position size (USD)\"\n    },\n    {\n      \"env\": \"SIMMER_WEATHER_SIZING_PCT\",\n      \"type\": \"number\",\n      \"default\": 0.05,\n      \"range\": [\n        0.01,\n        0.25\n      ],\n      \"step\": 0.01,\n      \"label\": \"Position sizing percentage\"\n    },\n    {\n      \"env\": \"SIMMER_WEATHER_MAX_TRADES_PER_RUN\",\n      \"type\": \"number\",\n      \"default\": 5,\n      \"range\": [\n        1,\n        20\n      ],\n      \"step\": 1,\n      \"label\": \"Max trades per run\"\n    },\n    {\n      \"env\": \"SIMMER_WEATHER_LOCATIONS\",\n      \"type\": \"string\",\n      \"default\": \"NYC\",\n      \"label\": \"Target cities (comma-separated)\"\n    },\n    {\n      \"env\": \"SIMMER_WEATHER_BINARY_ONLY\",\n      \"type\": \"boolean\",\n      \"default\": false,\n      \"label\": \"Binary markets only (skip range-bucket)\"\n    },\n    {\n      \"env\": \"SIMMER_WEATHER_SLIPPAGE_MAX\",\n      \"type\": \"number\",\n      \"default\": 0.15,\n      \"range\": [\n        0.01,\n        0.5\n      ],\n      \"step\": 0.01,\n      \"label\": \"Max slippage tolerated (skip trades above)\"\n    },\n    {\n      \"env\": \"SIMMER_WEATHER_MIN_LIQUIDITY\",\n      \"type\": \"number\",\n      \"default\": 0,\n      \"range\": [\n        0,\n        1000\n      ],\n      \"step\": 10,\n      \"label\": \"Min market liquidity in USD (0 = disabled)\"\n    },\n    {\n      \"env\": \"SIMMER_WEATHER_VOL_TARGETING\",\n      \"type\": \"boolean\",\n      \"default\": false,\n      \"label\": \"Enable volatility targeting (dynamic sizing)\"\n    },\n    {\n      \"env\": \"SIMMER_WEATHER_TARGET_VOL\",\n      \"type\": \"number\",\n      \"default\": 0.2,\n      \"range\": [\n        0.05,\n        1.0\n      ],\n      \"step\": 0.01,\n      \"label\": \"Target annualized volatility\"\n    },\n    {\n      \"env\": \"SIMMER_WEATHER_VOL_MAX_LEVERAGE\",\n      \"type\": \"number\",\n      \"default\": 2.0,\n      \"range\": [\n        1.0,\n        5.0\n      ],\n      \"step\": 0.1,\n      \"label\": \"Max scale-up multiplier (calm markets)\"\n    },\n    {\n      \"env\": \"SIMMER_WEATHER_VOL_MIN_ALLOC\",\n      \"type\": \"number\",\n      \"default\": 0.2,\n      \"range\": [\n        0.05,\n        1.0\n      ],\n      \"step\": 0.05,\n      \"label\": \"Min allocation floor (volatile markets)\"\n    },\n    {\n      \"env\": \"SIMMER_WEATHER_VOL_SPAN\",\n      \"type\": \"number\",\n      \"default\": 10,\n      \"range\": [\n        2,\n        60\n      ],\n      \"step\": 1,\n      \"label\": \"EWMA span for vol calculation\"\n    },\n    {\n      \"env\": \"SIMMER_WEATHER_REQUIRE_SOURCE_AGREEMENT\",\n      \"type\": \"boolean\",\n      \"default\": false,\n      \"label\": \"Require source agreement (skip any disagreement)\"\n    },\n    {\n      \"env\": \"SIMMER_WEATHER_CANARY_ON_ADJACENT_DISAGREEMENT\",\n      \"type\": \"boolean\",\n      \"default\": true,\n      \"label\": \"Canary mode on adjacent-bucket disagreement\"\n    },\n    {\n      \"env\": \"SIMMER_WEATHER_MAX_CANARY_USD\",\n      \"type\": \"number\",\n      \"default\": 2.0,\n      \"range\": [\n        0.5,\n        20\n      ],\n      \"step\": 0.5,\n      \"label\": \"Max canary USD (source-disagreement mode)\"\n    },\n    {\n      \"env\": \"SIMMER_WEATHER_MAX_SOURCE_SPREAD_F\",\n      \"type\": \"number\",\n      \"default\": 2.0,\n      \"range\": [\n        0.5,\n        10\n      ],\n      \"step\": 0.5,\n      \"label\": \"Max source spread °F before skip\"\n    }\n  ]\n}\n\nFile v1.23.22:config.json\n\n{\n  \"max_position_usd\": 2.0\n}\n\nFile v1.23.22:fixtures/replay_forecasts.sample.json\n\n{\n  \"_meta\": {\n    \"source\": \"open-meteo-previous-runs\",\n    \"fetched_at\": \"2026-09-16T00:00:00Z\",\n    \"lead\": \"previous_day1\"\n  },\n  \"KLGA\": {\n    \"2026-04-30\": {\"high\": 72, \"low\": 50}\n  }\n}\n\nArchive v1.23.21: 12 files, 73514 bytes\n\nFiles: CHANGELOG.md (19693b), clawhub.json (9836b), config.json (30b), DISCLAIMER.md (2349b), fixtures/replay_forecasts.sample.json (192b), scripts/build_replay_forecast_archive.py (14481b), scripts/run_backtest_gate.py (5700b), scripts/status.py (4441b), skill-card.md (2677b), SKILL.md (29667b), weather_trader.py (118397b), _meta.json (146b)\n\nFile v1.23.21:SKILL.md\n\n---\nname: polymarket-weather-trader\ndescription: Trade Polymarket weather markets using NOAA (US) and Open-Meteo (international) forecasts via Simmer API. Inspired by gopfan2's weather trading approach. Use when user wants to trade temperature markets, automate weather bets, check forecasts, or run weather-based strategies.\nmetadata:\n  author: Simmer (@simmer_markets)\n  version: \"1.23.21\"\n  displayName: Polymarket Weather Trader\n  difficulty: beginner\n  attribution: Strategy inspired by gopfan2 (public Polymarket trader — approach referenced, not endorsed).\n---\n# Polymarket Weather Trader\n\nTrade temperature markets on Polymarket using NOAA forecast data.\n\n> 🚨 **Framework, not a production trading system.** Read [DISCLAIMER.md](./DISCLAIMER.md) before connecting to a wallet with real funds.\n\n> **Template skill.** Defaults to dry-run mode (no real money). The `--live` flag is a deliberate single-command opt-in for real-money execution. Configure tunables (entry/exit thresholds, locations, etc.) via env vars listed below.\n\n## Safety rails (read first)\n\nThis skill executes real-money trades on Polymarket only when the `--live` flag is passed AND the human's wallet is linked to their Simmer account. Trading is bounded by default:\n\n- **Dry-run is the default.** `python weather_trader.py` (no flag) shows opportunities but executes no trades. The `--live` flag is required for real-money execution. There is no \"auto-graduate\" path.\n- **`$SIM` paper sandbox option.** Set `TRADING_VENUE=sim` to trade Simmer's $SIM virtual currency at real prices — useful for validating the strategy without USDC exposure.\n- **Real-money trading requires explicit human verification.** A wallet must be linked at [simmer.markets/dashboard](https://simmer.markets/dashboard?ref=sdk-skill&utm_campaign=sdk-skill) before any real trade lands. Without a linked wallet the SDK rejects real-money order construction.\n- **Per-trade cap.** `SIMMER_WEATHER_MAX_POSITION_USD` defaults to `$2.00` per trade. Configurable via env var, capped at the user's dashboard-set platform per-trade limit.\n- **Daily caps.** Platform-level daily caps apply (max trades/day, max USD/day). Set at [simmer.markets/dashboard](https://simmer.markets/dashboard?ref=sdk-skill&utm_campaign=sdk-skill) → SDK settings.\n- **Auto stop-loss is ON by default.** Server-side risk monitor watches every buy. Threshold is configurable per user at simmer.markets/dashboard → Settings → Auto Risk Monitor. **It cannot protect against gap-resolution, though:** weather temperature buckets jump straight to about 0 at resolution rather than decaying through your stop, so a percentage stop has no price to trigger on and no liquidity to exit into. Size for the full loss, not for the stop. See [DISCLAIMER.md](./DISCLAIMER.md).\n- **Strategy-side safeguards.** Beyond platform risk monitors, this skill checks flip-flop, slippage (`SIMMER_WEATHER_SLIPPAGE_MAX`, default 15%), time-decay (`SIMMER_WEATHER_MIN_HOURS_TO_RESOLVE`, default 2h), and resolved-market status before every order. Disable only with `--no-safeguards` (not recommended).\n- **Reversibility.** Open positions exit automatically when price > `SIMMER_WEATHER_EXIT_THRESHOLD` (default `0.45`), or via `client.cancel_order()` / a manual sell. `ENTRY_THRESHOLD` is an **upper** bound (buy *below*). If you raise it above the exit default (e.g. entry `0.50` vs exit `0.45`), the skill will try to sell the same position on the next cycle — raise `EXIT_THRESHOLD` too, or own exits yourself.\n\nIf anything above isn't clear, stop and ask the user before passing `--live`.\n\n## Strategy logic\n\nWeather market outcomes are discrete: a temperature bucket (\"34-35°F\") either matches the actual high on resolution day or it doesn't. The strategy works when the NOAA forecast is more accurate than what the market has priced in.\n\n**Test before going live.** The `$SIM` venue gives you a fully virtual sandbox at real market prices — recommended before any `--live` run.\n\n**Risk monitor.** Stop-loss and take-profit thresholds are user settings (configurable at [simmer.markets/dashboard](https://simmer.markets/dashboard?ref=sdk-skill&utm_campaign=sdk-skill) → Settings → Auto Risk Monitor), shared across all skills under that user account. Per-position overrides via `client.set_monitor(market_id, side, stop_loss_pct=..., take_profit_pct=...)`.\n\n**External wallet users**: monitors emit alerts via the briefing endpoint — your agent must be running for sells to execute. Managed wallet users: server executes directly.\n\n## When to Use This Skill\n\nUse this skill when the user wants to:\n- Trade weather markets automatically\n- Set up gopfan2-style temperature trading\n- Buy low on weather predictions\n- Check their weather trading positions\n- Configure trading thresholds or locations\n\n## What's New in v1.23.19\n\n- **Replay archive builder hardening (SIM-5440).** Open-Meteo HTTP 5xx responses now retry up to 3 attempts with backoff while 4xx remains fail-closed. Long windows are fetched in 10-day chunks and merged only when `utc_offset_seconds` is identical across chunks. `--stations us|intl|all` lets US-only backtests avoid international DST guards and unnecessary requests.\n\n## What's New in v1.23.17\n\n- **Timezone-correct leads (SIM-5434).** Lead N is the smallest 1–3 such that every hourly issuance for the event day precedes the tick: `N = ceil((E_end_utc − tick) / 24h)`, where `E_end_utc` is the event date's 23:59:59 in the station offset. Builder records Open-Meteo `utc_offset_seconds` per station in `_meta`. Missing offset assumes UTC−12 (`tz=assumed`). Each date must carry hours `00:00`–`23:00` exactly once.\n\n## What's New in v1.23.16\n\n- **Lead-aware archive (SIM-5434).** Builder fetches `temperature_2m_previous_day{1,2,3}` in one request per station. Each date is `{high, low, leads}` with top-level high/low = lead 1. Under replay, `_station_forecast(..., event_date=)` picks `lead = (event_date − tick.date).days + 1` in 1–3; further-out events skip. Incomplete hourly arrays abort the build. Provenance appends `leads=1-3` when present. Hand-built / sample files without `leads` keep the old shape.\n\n## What's New in v1.23.15\n\n- **Historical forecast archive builder (SIM-5434).** `scripts/build_replay_forecast_archive.py` fills the SIM-5429 loader plane from Open-Meteo Previous Runs. Tick D sees the D-1 forecast (`temperature_2m_previous_day1` hourly → daily high/low). US stations are °F; international stations are °C. The file may include `_meta` (source, fetched_at, lead=previous_day1); the loader ignores it. Auto-load is still only `fixtures/replay_forecasts.json` (uncommitted). `.sample.json` stays shape-only and is never loaded.\n\n## What's New in v1.23.14\n\n- **Replay forecast archive (SIM-5429).** This release ships a **loader**, not an archive. Under `SIMMER_REPLAY=1` the skill fills `_REPLAY_FORECASTS` from `SIMMER_REPLAY_FORECASTS=/path.json`, or from a user file `fixtures/replay_forecasts.json` when present (uncommitted). Copy your archive to `fixtures/replay_forecasts.json` (uncommitted); the `.sample.json` is shape reference only and is never loaded. Live NOAA stays dark. A set-but-missing path fails the tick. One forced provenance line (`force=True`, survives `--quiet`): path, station count, min/max date — or `no archive: NOAA dark, 0 entries is FIX`.\n- **KEEP/KILL path.** A full-tape run stays **FIX** until a real historical-forecast file covers the window. Do not treat the sample temps as history.\n\n## What's New in v1.23.13\n\n- **Replay forecast archive (SIM-5429) first cut.** Loader + sample. Round 2 (1.23.14) stopped auto-loading the invented sample.\n\n## What's New in v1.23.12\n\n- **Live price path unchanged.** `_market_yes_price` is `external_price_yes or 0.5` when not in replay. Replay-only fallthrough to `yes_price` / `current_probability`.\n- **Gate script does not print KEEP.** Unit tests are a path check. KEEP needs a full-tape `simmer backtest ... --q temperature` with evals > 0, entries > 0, and an honest forecast.\n\n## What's New in v1.23.11\n\n- **Backtest-as-gate (SIM-5428).** Replay discovery already used `q=temperature`. The entry path now works under the same harness: frozen tick (`SIMMER_REPLAY_NOW`) for horizon/date parse, replay `yes_price` (not a silent 0.50), city-station fallback when the tape omits `resolution_criteria` (Dallas still excluded), no live NOAA/Open-Meteo (look-ahead), and preflight skipped so `WALLET_UNVERIFIED` cannot block SimState fills. Import is skipped under replay so it does not burn the eval budget.\n- **Keep / kill / fix** for the real-capital path is below. 90-day Simmer P&L is still the lock. Dogfood `MIN_HOURS=12` is a separate canary — this release does not change it.\n- **Agent glue:** `python scripts/run_backtest_gate.py` runs the pinned replay tests and prints the verdict table.\n\n## What's New in v1.23.10\n\n- **Discovery horizon tracks `SIMMER_WEATHER_MIN_HOURS_TO_RESOLVE`.** The existing `tags=weather` fetch and location keyword import were newest-first / same-day heavy. They now also query +1/+2 calendar days so a morning heartbeat with `MIN_HOURS=24` still sees markets that can clear the floor. Horizon is `max(MIN_HOURS, 48h)` — raising the hours knob widens discovery; there is no separate horizon env. Do not lower the hours floor to \"fix\" morning no-fills.\n\n## What's New in v1.23.9\n\n- **Replay-compatible discovery.** Under `simmer backtest` (`SIMMER_REPLAY=1`) the skill lists markets with `q=temperature` instead of `tags=weather&status=active`. Replay rejects those filters (422). Live still uses the tag.\n- **Fail-closed on listing failure.** A failed market fetch now exits non-zero (`MarketFetchError`) so `bundle.clean` is not green on a 0-eval tick. An empty listing after a successful fetch is still a clean no-trade — that is an empty tape, not a fetch failure.\n- **Tape follow-up.** Default HF volume slices often have **0** weather markets (vol floor ~$201k in the #368 dogfood). `--min-volume` / a weather-capable tape query is server-side work; this skill does not invent weather on a high-volume slice.\n\n## What's New in v1.23.7\n\n- **Min entry price.** `SIMMER_WEATHER_MIN_ENTRY_PRICE` (default `0` = off) rejects lottery-ticket mids below the floor. `SIMMER_WEATHER_ENTRY_THRESHOLD` remains an **upper** bound only (buy when price is below it).\n- **Hours-to-resolve is now an env knob.** `SIMMER_WEATHER_MIN_HOURS_TO_RESOLVE` overrides the previous hardcoded 2h time-decay safeguard. Same check, same `check_context_safeguards` path — raise it (e.g. `24`) to skip resolve-day entries. Entry-only: exits keep the original 2h floor, so a raised value never blocks a sell. Discovery looks ahead `max(this, 48h)` so morning runs still see tomorrow's markets.\n\n## What's New in v1.23.3\n\n- **Event grouping now keys on `event_ref`** (the canonical parent-event id, present on every market) instead of the legacy `event_id`, which SDK-imported markets historically lacked. Fixes temperature buckets silently dropping out of their event group (missing buckets when `event_id` came back null).\n\n## What's New in v1.21.0\n\n- **Per-market resolution source.** Each market is now routed to the specific weather station Polymarket actually reads (parsed from the market's `resolution_criteria` field). Previously the skill used a hardcoded city → station map, which silently traded against the wrong forecast in a few cases (notably Dallas, where Polymarket resolves on Love Field / KDAL but the skill assumed DFW / KDFW). Markets that name a station the skill doesn't know are now skipped with a log line — better to skip than to trade a stale oracle. Robust to Polymarket swapping airports.\n- **Expanded NOAA station coverage.** KLGA, KJFK, KEWR, KNYC, KORD, KMDW, KSEA, KATL, KDAL, KDFW, KMIA, KBOS, KDCA, KIAD, KPHX, KLAS, KSFO, KLAX, KDEN, KMSP, KPHL.\n- **Expanded international coverage.** Adds Madrid, Milan, Amsterdam, Taipei to Open-Meteo routing (alongside existing Tel Aviv, Munich, London, Tokyo, Seoul, Ankara, Lucknow, Wellington).\n- **Requires the new `?include=resolution_criteria` flag** on `/api/sdk/markets` (live on Simmer backend 2026-05-03).\n\n## What's New in v1.20.1\n\n- **Safety rails section first.** Bounding contract surfaced at the top — paper-default, `--live` requirement, configurable caps, server-side risk monitor, strategy-side safeguards, reversibility.\n- **Risk monitor framing genericized.** Stop-loss / take-profit thresholds are described as configurable user settings rather than specific percentages. (See FAQ at docs.simmer.markets for current defaults — they're user-tunable in the dashboard.)\n- **Wallet setup link genericized.** Points at [docs.simmer.markets/wallets](https://docs.simmer.markets/wallets) instead of a named cross-skill.\n\n## What's New in v1.20.0\n\n- **SDK 0.13.0 integration** — uses `SimmerClient.from_env()` (auto-reads `SIMMER_API_KEY`, raises a clear `RuntimeError` with a dashboard pointer if unset). Requires `simmer-sdk>=0.13.0`.\n- **Slim per skill catalog reshape (Phase 3)** — duplicated wallet-setup / changelog / decorative content removed; SKILL.md trimmed to focus on what's specific to this skill.\n- **Dead code removed** — retired `AUTOMATON_*` env reads (the automaton runtime was retired 2026-04-20).\n\n## Setup\n\nFor wallet setup, see [docs.simmer.markets/wallets](https://docs.simmer.markets/wallets).\n\nRequired environment:\n- `SIMMER_API_KEY` — get from `simmer.markets/dashboard → SDK tab`\n- `WALLET_PRIVATE_KEY` — Polymarket wallet private key (the SDK signs orders client-side)\n\nThen `pip install --upgrade simmer-sdk` (>=0.13.0) and configure tunables below.\n\n## Configuration\n\n| Setting | Environment Variable | Default | Description |\n|---------|---------------------|---------|-------------|\n| Trading venue | `TRADING_VENUE` | polymarket | Venue to trade on. Set `sim` for paper trading. |\n| Entry threshold | `SIMMER_WEATHER_ENTRY_THRESHOLD` | 0.15 | **Upper** bound — buy when price is *below* this |\n| Min entry price | `SIMMER_WEATHER_MIN_ENTRY_PRICE` | 0 | **Lower** bound — skip lottery tickets below this (`0` = off), e.g. `0.15` to skip sub-15¢ tickets. Must be below the entry threshold. |\n| Min hours to resolve | `SIMMER_WEATHER_MIN_HOURS_TO_RESOLVE` | 2 | Skip entries if the market resolves in fewer than this many hours. Entry-only; exits keep a fixed 2h floor. Discovery looks ahead `max(this, 48h)` calendar days — raise it and the scan widens; a 24h floor still sees +1/+2 day markets in a morning heartbeat. |\n| Exit threshold | `SIMMER_WEATHER_EXIT_THRESHOLD` | 0.45 | Sell when price above this. Raise this if you raise entry above `0.45`, or the skill will self-exit. |\n| Max position | `SIMMER_WEATHER_MAX_POSITION_USD` | 2.00 | Maximum USD per trade |\n| Max trades/run | `SIMMER_WEATHER_MAX_TRADES_PER_RUN` | 5 | Maximum trades per scan cycle |\n| Locations | `SIMMER_WEATHER_LOCATIONS` | NYC | Comma-separated cities (NYC, Chicago, Seattle, Atlanta, Dallas, Miami, Austin, Houston, Denver, Beijing, Shanghai, Guangzhou, Shenzhen, Chengdu, Chongqing, Wuhan, Qingdao, Zhengzhou, Singapore, Kuala Lumpur, Manila, Busan, Toronto, Buenos Aires, Sao Paulo, Mexico City, Cape Town, Helsinki, Jeddah, Warsaw, Paris, Panama City) |\n| Binary only | `SIMMER_WEATHER_BINARY_ONLY` | false | Skip range-bucket events (e.g., \"34-35°F\"), only trade binary yes/no markets |\n| Smart sizing % | `SIMMER_WEATHER_SIZING_PCT` | 0.05 | % of balance per trade |\n| Slippage max | `SIMMER_WEATHER_SLIPPAGE_MAX` | 0.15 | Skip trades with slippage above this (0.15 = 15%) |\n| Min liquidity | `SIMMER_WEATHER_MIN_LIQUIDITY` | 0 | Skip markets with liquidity below this USD amount (0 = disabled) |\n| Vol targeting | `SIMMER_WEATHER_VOL_TARGETING` | false | Enable volatility targeting for dynamic position sizing |\n| Target vol | `SIMMER_WEATHER_TARGET_VOL` | 0.20 | Target annualized volatility (0.20 = 20%) |\n| Vol max leverage | `SIMMER_WEATHER_VOL_MAX_LEVERAGE` | 2.0 | Max scale-up multiplier in calm markets |\n| Vol min alloc | `SIMMER_WEATHER_VOL_MIN_ALLOC` | 0.2 | Min allocation floor in volatile markets (0.2 = 20%) |\n| Vol EWMA span | `SIMMER_WEATHER_VOL_SPAN` | 10 | EWMA span for vol calculation (lower = more responsive) |\n| Order type | `SIMMER_WEATHER_ORDER_TYPE` | GTC | GTC (limit, waits for fill) or FAK (cancel if not filled). GTC recommended. |\n| Replay forecast archive | `SIMMER_REPLAY_FORECASTS` | (none) | Replay-only. JSON `{station: {YYYY-MM-DD: {high, low}}}`. Live NOAA is never used under replay. If unset, loads `fixtures/replay_forecasts.json` when you add that file (not committed). `.sample.json` is never auto-loaded. |\n\n**Legacy env var aliases** (still accepted for backwards compatibility): `SIMMER_WEATHER_ENTRY`, `SIMMER_WEATHER_EXIT`, `SIMMER_WEATHER_MAX_POSITION`, `SIMMER_WEATHER_MAX_TRADES`\n\n**Supported locations** (city-name filter applied to market questions): NYC, Chicago, Seattle, Atlanta, Dallas, Miami, Austin, Houston, Denver, Tel Aviv, Munich, London, Tokyo, Seoul, Ankara, Lucknow, Wellington, Madrid, Milan, Amsterdam, Taipei, Beijing, Shanghai, Guangzhou, Shenzhen, Chengdu, Chongqing, Wuhan, Qingdao, Zhengzhou, Singapore, Kuala Lumpur, Manila, Busan, Toronto, Buenos Aires, Sao Paulo, Mexico City, Cape Town, Helsinki, Jeddah, Warsaw, Paris, Panama City. The actual oracle station is parsed per-market from `resolution_criteria` — see \"Resolution-source routing\" below.\n\n## Resolution-source routing\n\nPolymarket weather markets carry a `resolution_criteria` field that names the exact station the market resolves on (e.g. \"Chicago O'Hare Intl Airport Station\" with `wunderground.com/.../KORD`). v1.21.0+ parses that text per-market and routes to the matching forecast station instead of a city default. If a market names a station the skill doesn't know, the event is skipped with a log line. Add new stations to `STATION_ID_TO_NOAA` (US) or `INTERNATIONAL_STATION_COORDS` (international) in `weather_trader.py` to extend coverage — PRs welcome.\n\n## SDK initialization\n\n```python\nfrom simmer_sdk import SimmerClient\n\nclient = SimmerClient.from_env(venue=\"polymarket\", live=True)\n```\n\n`from_env()` (added in simmer-sdk 0.13.0) reads `SIMMER_API_KEY` from the environment and raises `RuntimeError` with a dashboard pointer if unset. If `OWS_WALLET` is set, it auto-routes through the OpenClaw shared wallet.\n\n## Quick Commands\n\n```bash\n# Check account balance and positions\npython scripts/status.py\n\n# Detailed position list\npython scripts/status.py --positions\n```\n\n**API Reference:**\n- Base URL: `https://api.simmer.markets`\n- Auth: `Authorization: Bearer $SIMMER_API_KEY`\n- Portfolio: `GET /api/sdk/portfolio`\n- Positions: `GET /api/sdk/positions`\n\n## Running the Skill\n\n```bash\n# Dry run (default — shows opportunities, no trades)\npython weather_trader.py\n\n# Execute real trades\npython weather_trader.py --live\n\n# With smart position sizing (uses portfolio balance)\npython weather_trader.py --live --smart-sizing\n\n# Check positions only\npython weather_trader.py --positions\n\n# View config\npython weather_trader.py --config\n\n# Disable safeguards (not recommended)\npython weather_trader.py --no-safeguards\n\n# Disable trend detection\npython weather_trader.py --no-trends\n\n# Enable volatility targeting (dynamic sizing based on market vol)\npython weather_trader.py --live --smart-sizing --vol-targeting\n\n# Quiet mode — only output on trades/errors (ideal for high-frequency runs)\npython weather_trader.py --live --quiet\n```\n\n## Backtest gate (keep / kill / fix)\n\n90-day **real-capital P&L on Simmer** is the lock. This gate is the fast filter before more real capital. Dogfood's `MIN_HOURS=12` canary is a separate seat — do not change it here.\n\nReuse the existing replay harness. Do not invent a second one.\n\n```bash\n# Pinned gate (no tape, no network, no API key)\npython skills/polymarket-weather-trader/scripts/run_backtest_gate.py\n\n# Same tests, direct\npython -m pytest skills/polymarket-weather-trader/tests/test_replay_discovery.py -q\n\n# Full-tape KEEP/KILL — build a window archive, copy it (uncommitted), then replay.\n# Auto-load is fixtures/replay_forecasts.json only. .sample.json is shape-only\n# and is never loaded.\npython skills/polymarket-weather-trader/scripts/build_replay_forecast_archive.py \\\n  --start YYYY-MM-DD --end YYYY-MM-DD --out /tmp/replay_forecasts.json\ncp /tmp/replay_forecasts.json \\\n  skills/polymarket-weather-trader/fixtures/replay_forecasts.json\n# SIMMER_WEATHER_LOCATIONS defaults to \"NYC\" — a tape covering other cities\n# (Seoul, London, Chicago, ...) will show 0 entries for every one of them\n# unless you widen this list to match the tape's city mix (SIM-5484). That\n# is expected scoping, not a station/forecast bug — see the note below.\n#\n# A plain `export SIMMER_WEATHER_LOCATIONS=...` does NOT reach the skill:\n# the replay harness builds the bundle subprocess env from a strict\n# allowlist (SIM-5067) that this var is not on, so it is silently stripped\n# and the run measures NYC regardless. Use --set on the entrypoint instead\n# — it writes config.json next to weather_trader.py, which load_config()\n# reads before env vars and which survives the per-tick bundle copy.\n#\n# Name the tape's actual cities, not a generic US list. E.g. for an\n# April tape weighted Seoul/Hong Kong/London/Shanghai/NYC/Paris: Seoul,\n# London, Paris and Shanghai are mapped (INTERNATIONAL_STATION_COORDS) and\n# will enter; Hong Kong has no station mapping anywhere in the skill and\n# cannot enter no matter what's in this list.\nsimmer backtest skills/polymarket-weather-trader \\\n  --entrypoint weather_trader.py --t0 YYYY-MM-DD --t1 YYYY-MM-DD \\\n  --cadence 12h --q temperature --min-volume 0 \\\n  --args \"--live --quiet --set locations=NYC,Chicago,Seattle,Atlanta,Miami,Austin,Houston,Denver,Seoul,London,Paris,Shanghai\"\n# Then read the KEEP/KILL table below, plus the per-city entry count the\n# report prints — a KEEP/PIVOT read needs coverage across the mapped\n# international cities, not just NYC. Optional in-process / pytest:\n# export SIMMER_REPLAY_FORECASTS=/tmp/replay_forecasts.json\n```\n\n| Verdict | What the backtest / replay outcome means for the money path |\n|---------|--------------------------------------------------------------|\n| **FIX** | Path is broken or the tape cannot evaluate the skill. Do not add capital. Repair: discovery 422 / fail-open empty listing; wall-clock horizon under replay; `yes_price` ignored (silent 0.50); every event skipped for missing `resolution_criteria`; live NOAA/Open-Meteo under replay (look-ahead); preflight `WALLET_UNVERIFIED` blocking SimState fills; 0 temperature markets on a high-volume slice (`--q temperature`, lower `--min-volume`); 0 entries because the forecast archive is missing, empty, or does not cover the tape dates (`SIMMER_REPLAY_FORECASTS` / `fixtures/replay_forecasts.json` — missing forecast plane, not \"no edge\"). |\n| **not a defect** | Every entry lands in one city (default NYC) on a multi-city tape. `SIMMER_WEATHER_LOCATIONS` defaults to `\"NYC\"` — that is the skill honoring its configured scope, not a station/parsing bug. Widen it via `--set locations=...` (a plain `export` is stripped by the replay harness allowlist) to the tape's full city mix before judging KEEP/KILL from entry count (SIM-5484). Hong Kong specifically never enters on any tape — the skill has no station mapping for it, not a defect. |\n| **KILL** | Pinned pytest gate fails, **or** the path is green on a weather-capable tape, evals > 0, and the skill still cannot reach `execute_trade` when a forecast is injected or loaded from the archive, **or** after the path works, P&L after costs is clearly ≤ 0 on an honest (not live-NOAA) forecast. Do not add more real capital. |\n| **KEEP** | Full-tape `simmer backtest ... --q temperature` with evals > 0 **and** entries > 0 **and** an honest archive (not live NOAA). Pinned unit tests passing is a path check only — not KEEP. Provisional; the 90-day Simmer P&L lock still decides scale-up. |\n\nA green full-tape run that places **0** trades because NOAA is correctly dark is **FIX** (forecast plane), not **KILL**. Copy a real window-covering archive to `fixtures/replay_forecasts.json`, then re-run. The committed `.sample.json` is not loaded.\n\n## How It Works\n\nEach cycle the script:\n1. Fetches active weather markets from Simmer API (newest weather page plus dated queries out to `max(MIN_HOURS_TO_RESOLVE, 48h)`)\n2. Groups markets by event (each temperature day is one event)\n3. Parses event names to get location and date; keeps events inside that discovery horizon\n4. Fetches NOAA forecast for that location/date (under replay: archive only — never live NOAA)\n5. Finds the temperature bucket that matches the forecast\n6. **Safeguards**: Checks context for flip-flop warnings, slippage, time decay\n7. **Trend Detection**: Looks for recent price drops (stronger buy signal)\n8. **Entry**: If min-entry ≤ bucket price < entry threshold and safeguards pass → BUY\n9. **Exit**: Checks open positions, sells if price > exit threshold\n10. **Tagging**: All trades tagged with `sdk:weather` for tracking\n\n## Smart Sizing\n\nWith `--smart-sizing`, position size is calculated as:\n- 5% of available USDC balance (configurable via `SIMMER_WEATHER_SIZING_PCT`)\n- Capped at max position setting ($2.00 default)\n- Falls back to fixed size if portfolio unavailable\n\n## Volatility Targeting\n\nWith `--vol-targeting`, position sizes are dynamically adjusted based on realized market volatility:\n\n```\nposition_size = base_size × clamp(target_vol / realized_vol, min_alloc, max_leverage)\n```\n\n- **High volatility**: positions scale down → less risk\n- **Low volatility**: positions scale up → more alpha capture\n- Falls back to base size if insufficient price history (< 15 data points)\n\n## Safeguards\n\nBefore trading, the skill checks:\n- **Flip-flop warning**: Skips if you've been reversing too much\n- **Slippage**: Skips if estimated slippage > 15% (tunable via `SIMMER_WEATHER_SLIPPAGE_MAX`)\n- **Time decay**: Skips if market resolves in < `SIMMER_WEATHER_MIN_HOURS_TO_RESOLVE` hours (default 2). Discovery looks ahead `max(this, 48h)` so raising the floor does not starve morning heartbeats.\n- **Market status**: Skips if market already resolved\n\n`SIMMER_WEATHER_MIN_ENTRY_PRICE` (default 0 = off) is the other side of the entry-price check, not this list — `--no-safeguards` does not disable it.\n\nDisable the flip-flop / slippage / time-decay / resolved checks with `--no-safeguards` (not recommended).\n\n## Source Tagging\n\nAll trades are tagged with `source: \"sdk:weather\"`. This means:\n- Portfolio shows breakdown by strategy\n- Trades tagged `sdk:weather` are excluded from generic copytrade sells.\n- You can track weather P&L separately\n\n## Troubleshooting\n\n**\"Safeguard blocked: Severe flip-flop warning\"** — you've been changing direction too much on this market; wait before trading again.\n\n**\"Slippage too high\"** — market is illiquid; reduce position size or skip.\n\n**\"Resolves in Xh - too soon\"** — market resolving sooner than `SIMMER_WEATHER_MIN_HOURS_TO_RESOLVE` (default 2h). Raise the env to skip resolve-day entries. Discovery already looks ahead `max(MIN_HOURS, 48h)`, so a morning run with `MIN_HOURS=24` can still take +1/+2 day markets. Same-day buckets will always fail a 24h floor before they have 24h left.\n\n**\"Price $X.XX below min entry\"** — mid is below `SIMMER_WEATHER_MIN_ENTRY_PRICE`. Lottery-ticket floor; default is off (`0`).\n\n**\"No weather markets found\"** — weather markets may not be active (seasonal).\n\n**`simmer backtest` / \"Failed to fetch markets from Simmer API\"** — replay does not implement `tags` or `status` (422 since sdk 0.25.3/0.25.4). v1.23.9+ uses `q=temperature` under replay. A fetch failure now fails the tick (`failed_ticks`, not a clean 0-eval). If the fetch succeeds and you still see 0 weather markets, the HF volume slice likely has none — default `--min-volume` / top-volume selection is a tape follow-up, not a skill bug. Replay listings omit `resolution_criteria`; v1.23.11+ falls back to the city station table only when criteria is **missing** (Dallas excluded; present-but-unreadable still skips). Live NOAA is never called under replay.\n\n**A full-tape run with 0 entries and NOAA dark is FIX** until a real archive covers the tape dates. Build one with `scripts/build_replay_forecast_archive.py`, then copy it to `fixtures/replay_forecasts.json` before `simmer backtest` (harness strips host env; that user file is copied with the bundle). Shape: `{ \"_meta\": {…}, \"KLGA\": { \"2026-04-30\": { \"high\": 72, \"low\": 50, \"leads\": { \"1\": {…}, \"2\": {…}, \"3\": {…} } } } }` — top-level high/low is lead 1; `_meta` is ignored. Hand-built files may omit `leads`. `fixtures/replay_forecasts.sample.json` is that shape only — invented test temps, never auto-loaded. A set-but-missing path fails the tick. Do not treat a 0-entry tape as no-edge. See **Backtest gate** above.\n\n**\"External wallet requires a pre-signed order\"** — `WALLET_PRIVATE_KEY` is not set. Fix: `export WALLET_PRIVATE_KEY=0x<your-polymarket-wallet-private-key>`. The SDK signs orders automatically when this env var is present — do not attempt to sign orders manually.\n\n**\"Balance shows $0 but I have funds on Polygon\"** — Polymarket V2 (live 2026-04-28) uses **pUSD** (PolyUSD, 1:1 backed by USDC.e). Migrate at [simmer.markets/dashboard](https://simmer.markets/dashboard?ref=sdk-skill&utm_campaign=sdk-skill) (~30s). Full guide: [docs.simmer.markets/v2-migration](https://docs.simmer.markets/v2-migration).\n\n**\"API key invalid\"** — get a new key from simmer.markets/dashboard → SDK tab.\n\nFile v1.23.21:_meta.json\n\n{\n  \"ownerId\": \"kn7axnp7bzqsf5fkx0z8px7han7zyq1x\",\n  \"slug\": \"polymarket-weather-trader\",\n  \"version\": \"1.23.21\",\n  \"publishedAt\": 1789662785989\n}\n\nFile v1.23.21:CHANGELOG.md\n\n# Changelog — polymarket-weather-trader\n\n## [1.23.21] - 2026-09-17\n\n### Changed\n- Requires `simmer-sdk>=0.25.8`, the first release whose `preflight()` is replay-aware. On an older SDK a backtest of this skill stops filling, because preflight blocks replay trades now that the skill no longer passes `skip_preflight`. Live trading is unaffected.\n\n## [1.23.20] - 2026-09-17\n\n### Changed\n- **Replay trades no longer pass the deprecated `skip_preflight` valve (SIM-5430).** `SimmerClient.preflight()` is replay-aware under `SIMMER_REPLAY=1` on a loopback base URL, so `execute_trade` / `execute_sell` drop `skip_preflight=replay`. Live behaviour unchanged: preflight still runs and still blocks on `WALLET_UNVERIFIED`. Version skips 1.23.18/1.23.19, reserved for #384 and SIM-5440 which are in flight.\n## [1.23.19] - 2026-09-17\n\n### Fixed\n- Replay archive builder hardening from the KEEP/KILL run (SIM-5440): Open-Meteo HTTP 5xx responses retry up to 3 attempts with backoff, while HTTP 4xx still aborts immediately.\n- Long or old Previous Runs windows are fetched in 10-day chunks and merged internally. The build aborts if `utc_offset_seconds` differs across chunks for a station.\n- Added `--stations us|intl|all` (default `all`). `us` limits the build to the 8 configured Polymarket US resolution stations, so US-only archives avoid international DST guards and 56 needless requests.\n\n## [1.23.18] - 2026-09-17\n\n### Fixed\n- **Replay positions were always empty (SIM-5484).** `get_positions()` filtered by `venue=\"polymarket\"` even under replay, but the replay server rejects any `venue` filter (422, SIM-5067). The 422 was swallowed to `[]`, so the skill never knew what it already held and re-bought the same bucket every tick (13-25x/market observed on a full-tape run). Replay now omits the venue filter; live is unchanged.\n\n### Docs\n- **`SIMMER_WEATHER_LOCATIONS` defaulting to `\"NYC\"` is not a bug.** A full-tape backtest with markets from many cities will show entries in NYC only unless this env var is widened to match the tape's city mix. Documented in the KEEP/KILL table and the reproduction recipe so a single-city result isn't misread as a station/forecast defect.\n- **The reproduction recipe's `export SIMMER_WEATHER_LOCATIONS=...` does not work under replay.** The bundle subprocess env is built from a strict allowlist (SIM-5067) that this var is not on, so the export was silently stripped and every re-run still measured NYC only. Recipe now uses `--set locations=...` on the entrypoint (writes `config.json`, which `load_config()` reads before env vars and which survives the bundle copy), and names the tape's actual cities instead of a generic US list. Hong Kong is called out separately: it has no station mapping anywhere in the skill (checked `LOCATIONS` and `INTERNATIONAL_STATION_COORDS`) and cannot enter regardless of this list — not a defect, just unmapped coverage.\n\n## [1.23.17] - 2026-09-16\n\n### Fixed\n- **Lead selection uses station-local event end, not UTC date (SIM-5434).** `_replay_lead_for_event(event_date, station_id)` picks the smallest N in 1–3 such that `E_end_utc − N·24h ≤ tick`. `E_end_utc` is the event date's 23:59:59 in `_meta[\"utc_offset_seconds\"][station]`. Unknown offset assumes UTC−12; provenance then includes `tz=assumed`. A 00:30Z tick no longer assigns Seattle May 1 to lead 2.\n- **Hourly fold requires 00:00–23:00 each once.** No 23–25 DST blanket. A missing 18:00 aborts the build.\n- Builder fetch retries URL errors twice (60s timeout) so a transient SSL timeout does not abort a 64-station build.\n- **Windows that cross a DST transition are refused.** Open-Meteo labels every hour with the request-time offset, so a cross-transition window folds the wrong local hours. `reject_dst_crossing` (zoneinfo on the payload `timezone`) aborts with \"split the window at the transition date\".\n\n## [1.23.16] - 2026-09-16\n\n### Fixed\n- **Look-ahead via `previous_day1` (SIM-5434).** Hourly `temperature_2m_previous_day1` at valid hour H is the run ~24h before H, not one D-1 issuance. Horizon (D+2) and same-day-ahead evening hours could see a run issued after the replay tick. The builder now fetches leads 1–3 in one request and writes `{high, low, leads}`. The loader picks `lead = (event_date − tick.date).days + 1` in 1–3; further-out events skip. Top-level high/low stays lead 1. Archives without `leads` (sample / hand-built) keep the old path. Provenance appends `leads=1-3` when present.\n- **Incomplete hourly responses fail closed.** Missing or short arrays, a null hour, or a missing requested date raise `ArchiveBuildError` naming station/date/lead. One valid hour is not a daily high/low.\n\n## [1.23.15] - 2026-09-16\n\n### Added\n- **Historical forecast archive builder (SIM-5434).** `scripts/build_replay_forecast_archive.py --start YYYY-MM-DD --end YYYY-MM-DD --out …` fetches Open-Meteo Previous Runs (`temperature_2m_previous_day1` hourly on the forecast endpoint, per station coord) and writes `{_meta, station: {date: {high, low}}}`. Tick D sees the D-1 forecast. US stations (LOCATIONS / STATION_ID_TO_NOAA) are °F; international stations are °C — same as `_station_forecast`. `_meta` is source / fetched_at / lead=previous_day1.\n\n### Fixed\n- Loader ignores `_meta` so a builder file does not look like a station.\n\n### Docs\n- KEEP/KILL sequence is now build → copy to `fixtures/replay_forecasts.json` (uncommitted; `.sample.json` is shape-only) → `simmer backtest` → read the table. Auto-load is still only the user file, never the sample.\n\n## [1.23.14] - 2026-09-16\n\n### Fixed\n- The committed sample is never auto-loaded. Invented KLGA / 2026-04-30 temps live only in `fixtures/replay_forecasts.sample.json` (shape reference). Auto-load is `SIMMER_REPLAY_FORECASTS` or a user file `fixtures/replay_forecasts.json` (gitignored). Default plane is empty → honest FIX.\n- One forced provenance line (`force=True`): path, station count, min/max date, or `no archive: NOAA dark, 0 entries is FIX`.\n- Startup uses `_ensure_replay_forecasts_loaded()` so an inject is not clobbered by a later file load.\n\n### Docs\n- Copy your archive to `fixtures/replay_forecasts.json` (uncommitted); the `.sample.json` is shape reference only and is never loaded. This release ships a loader, not an archive. A full-tape run stays FIX until a real historical-forecast file covers the window.\n\n## [1.23.13] - 2026-09-16\n\n### Added\n- **Replay forecast archive loader (SIM-5429).** Under `SIMMER_REPLAY=1`, `load_replay_forecasts()` fills `_REPLAY_FORECASTS` from `SIMMER_REPLAY_FORECASTS=/path.json` (same `{station: {YYYY-MM-DD: {high, low}}}` shape the tests inject). If the env is unset, a user file `fixtures/replay_forecasts.json` is used when present (not committed). The shipped `fixtures/replay_forecasts.sample.json` is a shape example only and is never auto-loaded. Live NOAA/Open-Meteo stay dark. A set-but-missing path raises `ReplayForecastArchiveError`. The replay archive line always prints (`force=True`) with station count and min/max date.\n\n### Docs\n- Full-tape KEEP/KILL: copy a window-covering archive to `fixtures/replay_forecasts.json`, then `simmer backtest … --q temperature`. 0 entries with NOAA dark is FIX when no user archive is in place. Do not treat the sample temps as history.\n\n## [1.23.12] - 2026-09-16\n\n### Fixed\n- Live price path is again `external_price_yes or 0.5`. Replay-only fallthrough to `yes_price` / `current_probability`. `None` and `0.0` stay 0.5 on live.\n- City-station fallback only when criteria is missing (`SKIP_MISSING_CRITERIA`). Present-but-unreadable still skips. Fallbacks use their own counter, not `station_parse_ok`.\n\n### Docs\n- `run_backtest_gate.py` prints a path-check line, not KEEP. KEEP requires a full-tape `simmer backtest ... --q temperature` with evals > 0, entries > 0, and an honest forecast. A full-tape run cannot produce KEEP or KILL until a forecast archive exists; 0 entries with NOAA dark is FIX.\n\n## [1.23.11] - 2026-09-16\n\n### Added\n- **Backtest-as-gate (SIM-5428).** Extends the #368 replay discovery tests into an explicit keep/kill gate for the real-capital path. `scripts/run_backtest_gate.py` runs those pinned tests and prints the verdict table. 90-day Simmer P&L remains the lock. Dogfood `MIN_HOURS=12` is unchanged.\n\n### Fixed\n- Replay entry path used wall-clock `datetime.now()` (horizon/date parse dropped historical tape rows), ignored replay `yes_price` (silent 0.50), skipped every event when the tape omitted `resolution_criteria`, called live NOAA (look-ahead), and hit `WALLET_UNVERIFIED` on `agents/me` so SimState never filled. Under `SIMMER_REPLAY=1` the skill now uses `SIMMER_REPLAY_NOW`, replay price fields, the existing city-station fallback (Dallas still excluded), injected `_REPLAY_FORECASTS` only, skips live import (eval budget), and passes `skip_preflight=True`.\n\n## [1.23.10] - 2026-09-14\n\n### Fixed\n- Discovery/scan was newest-first and same-calendar-day heavy. A morning heartbeat with `SIMMER_WEATHER_MIN_HOURS_TO_RESOLVE=24` then saw only resolve-day buckets (\"Resolves in 10–22h - too soon\") and took 0 fills. The existing `tags=weather` fetch and location keyword import now also query +1/+2 calendar days. Horizon is `max(MIN_HOURS_TO_RESOLVE, 48h)` — no new env knob.\n\n### Docs\n- Raising `MIN_HOURS_TO_RESOLVE` widens discovery. Do not lower the hours floor to fix morning no-fills.\n\n## [1.23.9] - 2026-09-14\n\n### Fixed\n- **Replay discovery.** `GET /api/sdk/markets?tags=weather&status=active` 422s on the backtest replay server (sdk 0.25.3/0.25.4). Under `SIMMER_REPLAY=1` the skill now uses the existing replay `q=` path (`q=temperature`) and omits `tags`/`status`. Live still uses the weather tag — questions like \"Austin 82-83F on Sep 7\" do not contain \"weather\".\n- **Fail-closed on listing failure.** `fetch_weather_markets()` used to swallow the 422, return `[]`, and exit 0 — `bundle.clean=true` with 0 evals. It now raises `MarketFetchError` so the tick is `failed_ticks`. An empty 200 is still a clean no-trade (empty tape).\n\n### Docs\n- Tape gap: default HF volume slices in the #368 dogfood had 0 weather/temperature markets (vol floor ~$201k). A weather-capable tape query (`tags`, lower `--min-volume`, or a dedicated weather slice) is server/slice follow-up. This skill does not pretend a high-volume slice contains weather.\n\n## [1.23.8] - 2026-09-08\n\n### Added\n- Added 26 Polymarket weather resolution stations: `KAUS`, `KHOU`, `KBKF`, `ZBAA`, `ZSPD`, `ZGGG`, `ZGSZ`, `ZUUU`, `ZUCK`, `ZHHH`, `ZSQD`, `ZHCC`, `WSSS`, `WMKK`, `RPLL`, `RKPK`, `CYYZ`, `SAEZ`, `SBGR`, `MMMX`, `FACT`, `EFHK`, `OEJN`, `EPWA`, `LFPB`, and `MPMG`. US stations route through NOAA with Open-Meteo cross-checks; international stations route through exact airport coordinates instead of city centers.\n\n## [1.23.7] - 2026-09-08\n\n### Added\n- `SIMMER_WEATHER_MIN_ENTRY_PRICE` (default `0` = off). Rejects entries below this mid so a raised `ENTRY_THRESHOLD` (upper bound only) cannot buy lottery tickets. Same entry-price check as before; this is the missing floor.\n- `SIMMER_WEATHER_MIN_HOURS_TO_RESOLVE` (default `2`). Env override of the hardcoded time-decay constant inside `check_context_safeguards`. Entry-only: exits keep the original 2h floor. No new gate, no calendar-day skip.\n\n### Docs\n- `ENTRY_THRESHOLD` is documented as an upper bound only. Raising it above the `0.45` exit default will self-exit unless `EXIT_THRESHOLD` is raised too.\n\n## [1.23.6] - 2026-09-06\n\n### Fixed\n- **Polymarket reworded every weather-temperature market on 2026-08-22 and the station parser stopped reading all of them.** The criteria dropped their Wunderground URL (resolution source moved to NOAA) and gained an agency clause — `recorded BY NOAA at the LaGuardia Airport Station`. Both parser patterns matched neither, so `parse_resolution_station()` returned `None` on 100% of current criteria and the skill skipped every event without entering. Verified against the live corpus: 2,195 of 2,596 active weather-temperature markets carry the new wording; only 84 keep the old. The station phrase now accepts an optional, generic agency clause, so `by NWS` or `by the National Weather Service` will not break it again.\n- Added name aliases for three stations Polymarket cites under a different name than our coordinate tables hold: `Hartsfield-Jackson International Airport` → `KATL`, `Amsterdam Airport Schiphol` → `EHAM`, `Malpensa Intl Airport` → `LIMC`. With these, all 16 advertised locations route again — the six US cities in `SIMMER_WEATHER_LOCATIONS` plus every international alias. Aliases may only point at stations we already have coordinates for; routing a market to an airport we cannot forecast is the silent KDFW/KDAL failure mode.\n- The skip log no longer claims `need SDK ≥ 2026-05-03` when criteria is present. Missing criteria and unreadable criteria were sharing one message that blamed a stale SDK for both; they are now distinct reasons.\n\n### Added\n- Parse-coverage guard. When a run reads a station out of fewer than 50% of the events that had criteria, the skill says so loudly (surviving `--quiet`) instead of reporting a clean scan. A parser that falls behind upstream wording throws nothing, fails no trade and retries nothing, so every downstream health metric stays green while the skill quietly stops entering — this was invisible for two weeks. The warning names the real cause: it is not finding no opportunities, it is failing to look.\n- `parse_resolution_station_result(criteria)` — returns the station plus the reason it could not be read (`SKIP_MISSING_CRITERIA` / `SKIP_UNPARSEABLE_CRITERIA`). `parse_resolution_station()` is unchanged for existing callers.\n- Whitespace in the station phrase is collapsed before matching, so the pattern uses literal single spaces. The first cut used `\\s+` around the lazy capture, which let the engine repartition a whitespace run on every failure — `recorded at the` followed by 1,600 spaces took 6.8s, growing ~8x per doubling. Criteria text is authored upstream, so one malformed market would have stalled the whole scan. Collapsing first also means a station phrase wrapped across newlines now parses, which the old pattern could not do.\n- `tests/test_resolution_criteria_reword.py` — pins the new and old wording, the reason split, alias-to-coordinate integrity, and the coverage guard's thresholds against live criteria strings.\n\n### Thanks\n- Reported by the Grok Bot dogfood seat, which caught it on a clean v1.23.5 install and correctly identified that the log message was lying about the cause.\n\n\n## [1.23.4] - 2026-07-22\n\n### Fixed\n- Added `EGLC` (London City Airport) to the international station coordinate map so Polymarket London weather markets that cite the official London City station can route to Open-Meteo instead of fail-closing as an unsupported station. This does not change markets whose Simmer/SDK metadata lacks usable `resolution_criteria`; those still fail closed.\n- `order_type=FOK` (Fill Or Kill) is now overridden to GTC, the same way `FAK` has been since v1.20.0. Weather markets are structurally illiquid — both FOK and FAK orders are cancelled immediately with no fill, creating a retry-loop that burns attempts on every run. The warning message now names the actual configured type (`FAK` or `FOK`) so it's actionable.\n\n## [1.22.2] - 2026-05-24\n\n### Fixed\n- Intl markets where Polymarket cites the resolution station by NAME only (no Wunderground URL / no ICAO) are no longer silently skipped (SIM-2428). Added a normalized-name → ICAO fallback index covering all 21 US + 16 intl stations. Normalizer strips diacritics (`ğ→g`), trailing `Intl` / `International` / `Airport` tokens, and lowercases — so `Esenboğa Intl Airport`, `Esenboga International Airport`, and `Esenboga Intl Airport` all resolve to `LTAC`.\n- Added `name` field to all 16 `INTERNATIONAL_STATION_COORDS` entries (US table already had it). The name-index is built from both tables at module load.\n\n### Added\n- `resolve_station_id_from_name(station_name)` — public helper for name-to-ICAO lookup.\n- `_normalize_station_name(name)` — internal normalizer used by the index + resolver.\n\n### Behavior delta\nRouting logic now: (a) if `station_id` is present in maps → as before; (b) if `station_id is None` but `station_name` matches an index entry → resolved and logged; (c) otherwise skip with the same message as before. No behavior change for markets that already resolve via ICAO.\n\n## [1.22.1] - 2026-05-24\n\n### Fixed\n- `Matching bucket: None` log when a market's `outcome_name` field is explicitly `None` (matcher loop fell back to `question`, but post-selection line used `.get(\"outcome_name\", \"\")` which returns `None` not the default). Same class-of-bug as SIM-2371. Closes SIM-2427 issue 1.\n- Source-tier classification + log now runs for EVERY bucket-matched candidate, not only those that pass safeguards. Moved the cross-check fetch + `evaluate_source_agreement` call from inside the entry-threshold branch to immediately after bucket-match. Sizing application stays in the entry-threshold branch. Autoresearch + dogfood receipts now see would-have-been tier classification on slippage-blocked candidates too. Closes SIM-2427 issue 2.\n\n### Cost note\nThe cross-check now fires on every bucket-matched candidate (vs. only entry-eligible ones in 1.22.0). `secondary_cache[station_id]` deduplicates within a scan run, so worst case = 1 Open-Meteo fetch per unique station per scan, unchanged from 1.22.0 for any candidate that reached entry-threshold evaluation. New cost: candidates above entry threshold now also incur the fetch — bounded by the per-station cache.\n\n## [1.22.0] - 2026-05-24\n\n### Added\n- Multi-source bucket-confidence scoring (SIM-2420). Cross-checks NOAA primary against Open-Meteo secondary at the same station coords before sizing live entries. Four tiers:\n  - `match` (same bucket) → normal size\n  - `adjacent` (neighboring bucket, spread ≤ MAX_SOURCE_SPREAD_F) → cap to MAX_CANARY_USD (default $2)\n  - `wide` (spread > MAX_SOURCE_SPREAD_F or non-adjacent buckets) → skip\n  - `missing_secondary` (intl markets — Open-Meteo IS primary) → behave per REQUIRE_SOURCE_AGREEMENT\n- Four new env knobs:\n  - `SIMMER_WEATHER_REQUIRE_SOURCE_AGREEMENT` (default `false`)\n  - `SIMMER_WEATHER_CANARY_ON_ADJACENT_DISAGREEMENT` (default `true`)\n  - `SIMMER_WEATHER_MAX_CANARY_USD` (default `2.0`)\n  - `SIMMER_WEATHER_MAX_SOURCE_SPREAD_F` (default `2.0`)\n- `source_agreement` block added to trade signal payload (tier, primary/secondary temps, spread, secondary bucket).\n- `get_openmeteo_forecast_for_us_station(station_id)` — returns Open-Meteo forecast at a NOAA-mapped US station's coords, converted to °F.\n- 14 unit tests covering the 4 tier branches + edge cases (Celsius spread conversion, canary ceiling-not-floor behavior, etc.).\n\n### Rationale\nPolymarket weather markets have whole-degree buckets — a ~1°F source disagreement can flip the outcome. Prior versions sized fully whenever NOAA crossed an entry threshold. Herman's dogfood (Atlanta May 26 KATL) surfaced cases where NOAA placed the forecast in one bucket while Open-Meteo placed it in an adjacent or non-adjacent bucket; this release downgrades sizing tier in those cases instead of trading with full conviction.\n\n## [1.21.2] - 2026-05-23\n\n### Fixed\n- `check_exit_opportunities` no longer crashes with `TypeError: argument of type 'NoneType' is not iterable` when a position's `sources` field is `None` (e.g. paper-mode entries). Changed `pos.get(\"sources\", [])` → `pos.get(\"sources\") or []` so explicit `None` values are coalesced to `[]`. Closes SIM-2371.\n\n## [1.21.1] - prior\n- See git history.\n\nFile v1.23.21:DISCLAIMER.md\n\n# Disclaimer\n\nThis skill is a **framework**, not a production trading system. Read this\nin full before connecting it to a wallet with real funds.\n\n## No financial advice\n\nNothing in this skill constitutes financial, investment, or trading\nadvice. The default strategy implemented here is a starting point, not a\ntested edge. Suitability for any account size or risk tolerance is your\nresponsibility to assess.\n\n## Default parameters are not validated\n\nDefault parameters are calibrated for testing the plumbing, not for live\nprofit. They have not been validated to produce positive returns under\ncurrent market conditions. Run paper mode for an extended period before\nscaling beyond default position sizes.\n\n## Automated trading carries irreversible risk\n\nWhen this skill runs with `--live`, it places real on-chain orders.\nOn-chain trades cannot be recalled. Strategy errors, signal lag, market\nregime shifts, and operator misconfiguration can produce losses\nexceeding any specific position size.\n\n## Risk monitoring may not apply to all market types\n\nStop-loss and take-profit monitors run on a fixed schedule. Markets that\nresolve faster than the monitor cycle cannot be exited automatically.\n\nSome markets also resolve by gapping rather than decaying. Weather\ntemperature buckets are the clearest case: the losing side can sit near\nyour entry, then jump straight to about 0 at resolution, with no\nintermediate price for a percentage stop to trigger on and no liquidity\nto exit into. On these markets a stop-loss cannot cap your loss\nregardless of the monitor cycle.\n\nPosition sizing is the only reliable risk control on these markets. Set\nit conservatively, assuming the full position can go to zero.\n\n## Use of this skill is at your own risk\n\nBy installing and running this skill you agree that the authors are not\nliable for any losses, direct or indirect, that arise from its use. This\napplies regardless of skill provenance — official Simmer skills,\ncommunity skills, and skills imported from external repositories all\ncarry this same disclaimer.\n\n## Where to learn more before going live\n\n- The skill's own `SKILL.md` documents the strategy and parameters\n- Your trading venue's documentation covers fee structure, order types,\n  and resolution rules\n- Simmer SDK documentation covers paper mode, dry-run flags, and\n  position monitoring\n\nFile v1.23.21:skill-card.md\n\n## Description:\n\nTrade Polymarket weather markets using NOAA (US) and Open-Meteo (international) forecasts via Simmer API.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[simmer](https://clawhub.ai/user/simmer)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nExternal users and agent developers use this skill to evaluate, configure, paper-trade, or explicitly live-trade weather prediction markets based on forecast data and market prices.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: The skill can place real-money weather-market trades when live mode and wallet credentials are enabled.\n\nMitigation: Keep the default dry-run mode or set TRADING_VENUE=sim until tested; use --live and WALLET_PRIVATE_KEY only when accepting possible loss.\n\nRisk: Weather temperature buckets can resolve by gapping to near zero, so percentage stop-loss controls may not cap losses.\n\nMitigation: Size positions assuming the full position can be lost, keep per-trade caps conservative, and review threshold settings before live use.\n\nRisk: Misconfigured thresholds, locations, source agreement settings, or SDK versions can lead to unwanted or failed trades.\n\nMitigation: Review all tunables, keep strategy safeguards enabled, and use the required simmer-sdk version before relying on automated execution.\n\nRisk: API keys and wallet private keys can authorize account access or order signing.\n\nMitigation: Protect SIMMER_API_KEY and WALLET_PRIVATE_KEY, provide wallet credentials only for intended live external-wallet use, and rotate credentials if exposed.\n\n## Reference(s):\n\n- [ClawHub skill page](https://clawhub.ai/simmer/skills/polymarket-weather-trader)\n- [Simmer wallet documentation](https://docs.simmer.markets/wallets)\n- [Simmer API](https://api.simmer.markets)\n- [Simmer V2 migration guide](https://docs.simmer.markets/v2-migration)\n\n## Skill Output:\n\n**Output Type(s):** [Text, Markdown, Shell commands, Configuration, API calls, Guidance]\n\n**Output Format:** [Markdown guidance with command examples and environment-variable configuration; runtime scripts emit console status.]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Defaults to dry-run; live trading requires explicit --live use and configured credentials.]\n\n## Skill Version(s):\n\n1.23.21 (source: server release evidence, frontmatter, changelog released 2026-09-17)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nFile v1.23.21:clawhub.json\n\n{\n  \"emoji\": \"\\ud83c\\udf21\\ufe0f\",\n  \"primaryEnv\": \"SIMMER_API_KEY\",\n  \"requires\": {\n    \"env\": [\n      \"SIMMER_API_KEY\"\n    ],\n    \"pip\": [\n      \"simmer-sdk>=0.25.8\"\n    ]\n  },\n  \"envVars\": [\n    {\n      \"name\": \"SIMMER_API_KEY\",\n      \"required\": true,\n      \"description\": \"Your Simmer SDK API key \\u2014 get from simmer.markets/dashboard\"\n    },\n    {\n      \"name\": \"WALLET_PRIVATE_KEY\",\n      \"required\": false,\n      \"description\": \"Only needed for external-wallet self-custody trading. Not required when using managed wallets.\"\n    },\n    {\n      \"name\": \"TRADING_VENUE\",\n      \"required\": false,\n      \"description\": \"Optional. Set to 'sim' for paper trading or 'kalshi' for Solana trading. Defaults to 'polymarket'.\"\n    },\n    {\n      \"name\": \"SIMMER_WEATHER_ENTRY_THRESHOLD\",\n      \"required\": false,\n      \"description\": \"Upper bound: buy when bucket price is below this (default 0.15).\"\n    },\n    {\n      \"name\": \"SIMMER_WEATHER_MIN_ENTRY_PRICE\",\n      \"required\": false,\n      \"description\": \"Lower bound: skip lottery-ticket mids below this (default 0 = off).\"\n    },\n    {\n      \"name\": \"SIMMER_WEATHER_MIN_HOURS_TO_RESOLVE\",\n      \"required\": false,\n      \"description\": \"Skip entries if the market resolves in fewer than this many hours (default 2). Entry-only; exits keep a 2h floor. Discovery looks ahead max(this, 48h) so a morning heartbeat can still see +1/+2 day markets.\"\n    },\n    {\n      \"name\": \"SIMMER_WEATHER_EXIT_THRESHOLD\",\n      \"required\": false,\n      \"description\": \"Sell when price above this (default 0.45). Raise this if you raise ENTRY above 0.45, or the skill will self-exit.\"\n    },\n    {\n      \"name\": \"SIMMER_WEATHER_MAX_POSITION_USD\",\n      \"required\": false,\n      \"description\": \"Max USD per trade (default 2.00).\"\n    },\n    {\n      \"name\": \"SIMMER_WEATHER_SIZING_PCT\",\n      \"required\": false,\n      \"description\": \"Smart-sizing fraction of available balance (default 0.05).\"\n    },\n    {\n      \"name\": \"SIMMER_WEATHER_MAX_TRADES_PER_RUN\",\n      \"required\": false,\n      \"description\": \"Max trades per scan cycle (default 5).\"\n    },\n    {\n      \"name\": \"SIMMER_WEATHER_LOCATIONS\",\n      \"required\": false,\n      \"description\": \"Comma-separated cities (default 'NYC'). Supported: NYC, Chicago, Seattle, Atlanta, Dallas, Miami, Austin, Houston, Denver, Tel Aviv, Munich, London, Tokyo, Seoul, Ankara, Lucknow, Wellington, Madrid, Milan, Amsterdam, Taipei, Beijing, Shanghai, Guangzhou, Shenzhen, Chengdu, Chongqing, Wuhan, Qingdao, Zhengzhou, Singapore, Kuala Lumpur, Manila, Busan, Toronto, Buenos Aires, Sao Paulo, Mexico City, Cape Town, Helsinki, Jeddah, Warsaw, Paris, Panama City.\"\n    },\n    {\n      \"name\": \"SIMMER_WEATHER_BINARY_ONLY\",\n      \"required\": false,\n      \"description\": \"Set true to skip range-bucket events and only trade binary yes/no markets (default false).\"\n    },\n    {\n      \"name\": \"SIMMER_WEATHER_SLIPPAGE_MAX\",\n      \"required\": false,\n      \"description\": \"Skip trades with slippage above this (default 0.15 = 15%).\"\n    },\n    {\n      \"name\": \"SIMMER_WEATHER_MIN_LIQUIDITY\",\n      \"required\": false,\n      \"description\": \"Skip markets with liquidity below this USD threshold (default 0 = disabled).\"\n    },\n    {\n      \"name\": \"SIMMER_WEATHER_ORDER_TYPE\",\n      \"required\": false,\n      \"description\": \"Order type: GTC (default, limit waits for fill) or FAK (cancel if not filled immediately).\"\n    },\n    {\n      \"name\": \"SIMMER_WEATHER_VOL_TARGETING\",\n      \"required\": false,\n      \"description\": \"Enable volatility targeting for dynamic position sizing (default false).\"\n    },\n    {\n      \"name\": \"SIMMER_WEATHER_TARGET_VOL\",\n      \"required\": false,\n      \"description\": \"Target annualized volatility when vol_targeting is enabled (default 0.20 = 20%).\"\n    },\n    {\n      \"name\": \"SIMMER_WEATHER_VOL_MAX_LEVERAGE\",\n      \"required\": false,\n      \"description\": \"Max scale-up multiplier from vol targeting (default 2.0).\"\n    },\n    {\n      \"name\": \"SIMMER_WEATHER_VOL_MIN_ALLOC\",\n      \"required\": false,\n      \"description\": \"Min allocation floor from vol targeting (default 0.2).\"\n    },\n    {\n      \"name\": \"SIMMER_WEATHER_VOL_SPAN\",\n      \"required\": false,\n      \"description\": \"EWMA span for vol calculation; lower = more responsive (default 10).\"\n    },\n    {\n      \"name\": \"SIMMER_WEATHER_REQUIRE_SOURCE_AGREEMENT\",\n      \"required\": false,\n      \"description\": \"Skip on any NOAA/Open-Meteo bucket disagreement (no canary fallback). Default false.\"\n    },\n    {\n      \"name\": \"SIMMER_WEATHER_CANARY_ON_ADJACENT_DISAGREEMENT\",\n      \"required\": false,\n      \"description\": \"Cap to MAX_CANARY_USD on adjacent-bucket source disagreement instead of skipping. Default true.\"\n    },\n    {\n      \"name\": \"SIMMER_WEATHER_MAX_CANARY_USD\",\n      \"required\": false,\n      \"description\": \"Max position USD when source disagreement triggers canary mode (default $2).\"\n    },\n    {\n      \"name\": \"SIMMER_WEATHER_MAX_SOURCE_SPREAD_F\",\n      \"required\": false,\n      \"description\": \"Max degrees-F spread between primary + secondary forecast before skipping outright (default 2.0).\"\n    },\n    {\n      \"name\": \"SIMMER_REPLAY_FORECASTS\",\n      \"required\": false,\n      \"description\": \"Replay-only. Path to a JSON forecast archive {station: {YYYY-MM-DD: {high, low}}}. Live NOAA is never used under replay. For simmer backtest, copy a real archive to fixtures/replay_forecasts.json (not committed; host env is stripped). The .sample.json file is never auto-loaded.\"\n    }\n  ],\n  \"cron\": null,\n  \"autostart\": false,\n  \"automaton\": {\n    \"managed\": true,\n    \"entrypoint\": \"weather_trader.py\"\n  },\n  \"tunables\": [\n    {\n      \"env\": \"SIMMER_WEATHER_ENTRY_THRESHOLD\",\n      \"type\": \"number\",\n      \"default\": 0.15,\n      \"range\": [\n        0.01,\n        0.3\n      ],\n      \"step\": 0.01,\n      \"label\": \"Entry edge threshold (upper bound)\"\n    },\n    {\n      \"env\": \"SIMMER_WEATHER_MIN_ENTRY_PRICE\",\n      \"type\": \"number\",\n      \"default\": 0,\n      \"range\": [\n        0,\n        0.5\n      ],\n      \"step\": 0.01,\n      \"label\": \"Min entry price (lottery-ticket floor; 0 = off)\"\n    },\n    {\n      \"env\": \"SIMMER_WEATHER_MIN_HOURS_TO_RESOLVE\",\n      \"type\": \"number\",\n      \"default\": 2,\n      \"range\": [\n        0,\n        72\n      ],\n      \"step\": 1,\n      \"label\": \"Min hours to resolution (time-decay skip)\"\n    },\n    {\n      \"env\": \"SIMMER_WEATHER_EXIT_THRESHOLD\",\n      \"type\": \"number\",\n      \"default\": 0.45,\n      \"range\": [\n        0.1,\n        0.99\n      ],\n      \"step\": 0.01,\n      \"label\": \"Exit probability threshold\"\n    },\n    {\n      \"env\": \"SIMMER_WEATHER_MAX_POSITION_USD\",\n      \"type\": \"number\",\n      \"default\": 2.0,\n      \"range\": [\n        1,\n        50\n      ],\n      \"step\": 1,\n      \"label\": \"Max position size (USD)\"\n    },\n    {\n      \"env\": \"SIMMER_WEATHER_SIZING_PCT\",\n      \"type\": \"number\",\n      \"default\": 0.05,\n      \"range\": [\n        0.01,\n        0.25\n      ],\n      \"step\": 0.01,\n      \"label\": \"Position sizing percentage\"\n    },\n    {\n      \"env\": \"SIMMER_WEATHER_MAX_TRADES_PER_RUN\",\n      \"type\": \"number\",\n      \"default\": 5,\n      \"range\": [\n        1,\n        20\n      ],\n      \"step\": 1,\n      \"label\": \"Max trades per run\"\n    },\n    {\n      \"env\": \"SIMMER_WEATHER_LOCATIONS\",\n      \"type\": \"string\",\n      \"default\": \"NYC\",\n      \"label\": \"Target cities (comma-separated)\"\n    },\n    {\n      \"env\": \"SIMMER_WEATHER_BINARY_ONLY\",\n      \"type\": \"boolean\",\n      \"default\": false,\n      \"label\": \"Binary markets only (skip range-bucket)\"\n    },\n    {\n      \"env\": \"SIMMER_WEATHER_SLIPPAGE_MAX\",\n      \"type\": \"number\",\n      \"default\": 0.15,\n      \"range\": [\n        0.01,\n        0.5\n      ],\n      \"step\": 0.01,\n      \"label\": \"Max slippage tolerated (skip trades above)\"\n    },\n    {\n      \"env\": \"SIMMER_WEATHER_MIN_LIQUIDITY\",\n      \"type\": \"number\",\n      \"default\": 0,\n      \"range\": [\n        0,\n        1000\n      ],\n      \"step\": 10,\n      \"label\": \"Min market liquidity in USD (0 = disabled)\"\n    },\n    {\n      \"env\": \"SIMMER_WEATHER_VOL_TARGETING\",\n      \"type\": \"boolean\",\n      \"default\": false,\n      \"label\": \"Enable volatility targeting (dynamic sizing)\"\n    },\n    {\n      \"env\": \"SIMMER_WEATHER_TARGET_VOL\",\n      \"type\": \"number\",\n      \"default\": 0.2,\n      \"range\": [\n        0.05,\n        1.0\n      ],\n      \"step\": 0.01,\n      \"label\": \"Target annualized volatility\"\n    },\n    {\n      \"env\": \"SIMMER_WEATHER_VOL_MAX_LEVERAGE\",\n      \"type\": \"number\",\n      \"default\": 2.0,\n      \"range\": [\n        1.0,\n        5.0\n      ],\n      \"step\": 0.1,\n      \"label\": \"Max scale-up multiplier (calm markets)\"\n    },\n    {\n      \"env\": \"SIMMER_WEATHER_VOL_MIN_ALLOC\",\n      \"type\": \"number\",\n      \"default\": 0.2,\n      \"range\": [\n        0.05,\n        1.0\n      ],\n      \"step\": 0.05,\n      \"label\": \"Min allocation floor (volatile markets)\"\n    },\n    {\n      \"env\": \"SIMMER_WEATHER_VOL_SPAN\",\n      \"type\": \"number\",\n      \"default\": 10,\n      \"range\": [\n        2,\n        60\n      ],\n      \"step\": 1,\n      \"label\": \"EWMA span for vol calculation\"\n    },\n    {\n      \"env\": \"SIMMER_WEATHER_REQUIRE_SOURCE_AGREEMENT\",\n      \"type\": \"boolean\",\n      \"default\": false,\n      \"label\": \"Require source agreement (skip any disagreement)\"\n    },\n    {\n      \"env\": \"SIMMER_WEATHER_CANARY_ON_ADJACENT_DISAGREEMENT\",\n      \"type\": \"boolean\",\n      \"default\": true,\n      \"label\": \"Canary mode on adjacent-bucket disagreement\"\n    },\n    {\n      \"env\": \"SIMMER_WEATHER_MAX_CANARY_USD\",\n      \"type\": \"number\",\n      \"default\": 2.0,\n      \"range\": [\n        0.5,\n        20\n      ],\n      \"step\": 0.5,\n      \"label\": \"Max canary USD (source-disagreement mode)\"\n    },\n    {\n      \"env\": \"SIMMER_WEATHER_MAX_SOURCE_SPREAD_F\",\n      \"type\": \"number\",\n      \"default\": 2.0,\n      \"range\": [\n        0.5,\n        10\n      ],\n      \"step\": 0.5,\n      \"label\": \"Max source spread °F before skip\"\n    }\n  ]\n}\n\nFile v1.23.21:config.json\n\n{\n  \"max_position_usd\": 2.0\n}\n\nFile v1.23.21:fixtures/replay_forecasts.sample.json\n\n{\n  \"_meta\": {\n    \"source\": \"open-meteo-previous-runs\",\n    \"fetched_at\": \"2026-09-16T00:00:00Z\",\n    \"lead\": \"previous_day1\"\n  },\n  \"KLGA\": {\n    \"2026-04-30\": {\"high\": 72, \"low\": 50}\n  }\n}\n\nArchive v1.23.18: 12 files, 72271 bytes\n\nFiles: CHANGELOG.md (18350b), clawhub.json (9836b), config.json (30b), DISCLAIMER.md (2349b), fixtures/replay_forecasts.sample.json (192b), scripts/build_replay_forecast_archive.py (12303b), scripts/run_backtest_gate.py (5700b), scripts/status.py (4441b), skill-card.md (2617b), SKILL.md (29270b), weather_trader.py (118467b), _meta.json (146b)\n\nFile v1.23.18:SKILL.md\n\n---\nname: polymarket-weather-trader\ndescription: Trade Polymarket weather markets using NOAA (US) and Open-Meteo (international) forecasts via Simmer API. Inspired by gopfan2's weather trading approach. Use when user wants to trade temperature markets, automate weather bets, check forecasts, or run weather-based strategies.\nmetadata:\n  author: Simmer (@simmer_markets)\n  version: \"1.23.18\"\n  displayName: Polymarket Weather Trader\n  difficulty: beginner\n  attribution: Strategy inspired by gopfan2 (public Polymarket trader — approach referenced, not endorsed).\n---\n# Polymarket Weather Trader\n\nTrade temperature markets on Polymarket using NOAA forecast data.\n\n> 🚨 **Framework, not a production trading system.** Read [DISCLAIMER.md](./DISCLAIMER.md) before connecting to a wallet with real funds.\n\n> **Template skill.** Defaults to dry-run mode (no real money). The `--live` flag is a deliberate single-command opt-in for real-money execution. Configure tunables (entry/exit thresholds, locations, etc.) via env vars listed below.\n\n## Safety rails (read first)\n\nThis skill executes real-money trades on Polymarket only when the `--live` flag is passed AND the human's wallet is linked to their Simmer account. Trading is bounded by default:\n\n- **Dry-run is the default.** `python weather_trader.py` (no flag) shows opportunities but executes no trades. The `--live` flag is required for real-money execution. There is no \"auto-graduate\" path.\n- **`$SIM` paper sandbox option.** Set `TRADING_VENUE=sim` to trade Simmer's $SIM virtual currency at real prices — useful for validating the strategy without USDC exposure.\n- **Real-money trading requires explicit human verification.** A wallet must be linked at [simmer.markets/dashboard](https://simmer.markets/dashboard?ref=sdk-skill&utm_campaign=sdk-skill) before any real trade lands. Without a linked wallet the SDK rejects real-money order construction.\n- **Per-trade cap.** `SIMMER_WEATHER_MAX_POSITION_USD` defaults to `$2.00` per trade. Configurable via env var, capped at the user's dashboard-set platform per-trade limit.\n- **Daily caps.** Platform-level daily caps apply (max trades/day, max USD/day). Set at [simmer.markets/dashboard](https://simmer.markets/dashboard?ref=sdk-skill&utm_campaign=sdk-skill) → SDK settings.\n- **Auto stop-loss is ON by default.** Server-side risk monitor watches every buy. Threshold is configurable per user at simmer.markets/dashboard → Settings → Auto Risk Monitor. **It cannot protect against gap-resolution, though:** weather temperature buckets jump straight to about 0 at resolution rather than decaying through your stop, so a percentage stop has no price to trigger on and no liquidity to exit into. Size for the full loss, not for the stop. See [DISCLAIMER.md](./DISCLAIMER.md).\n- **Strategy-side safeguards.** Beyond platform risk monitors, this skill checks flip-flop, slippage (`SIMMER_WEATHER_SLIPPAGE_MAX`, default 15%), time-decay (`SIMMER_WEATHER_MIN_HOURS_TO_RESOLVE`, default 2h), and resolved-market status before every order. Disable only with `--no-safeguards` (not recommended).\n- **Reversibility.** Open positions exit automatically when price > `SIMMER_WEATHER_EXIT_THRESHOLD` (default `0.45`), or via `client.cancel_order()` / a manual sell. `ENTRY_THRESHOLD` is an **upper** bound (buy *below*). If you raise it above the exit default (e.g. entry `0.50` vs exit `0.45`), the skill will try to sell the same position on the next cycle — raise `EXIT_THRESHOLD` too, or own exits yourself.\n\nIf anything above isn't clear, stop and ask the user before passing `--live`.\n\n## Strategy logic\n\nWeather market outcomes are discrete: a temperature bucket (\"34-35°F\") either matches the actual high on resolution day or it doesn't. The strategy works when the NOAA forecast is more accurate than what the market has priced in.\n\n**Test before going live.** The `$SIM` venue gives you a fully virtual sandbox at real market prices — recommended before any `--live` run.\n\n**Risk monitor.** Stop-loss and take-profit thresholds are user settings (configurable at [simmer.markets/dashboard](https://simmer.markets/dashboard?ref=sdk-skill&utm_campaign=sdk-skill) → Settings → Auto Risk Monitor), shared across all skills under that user account. Per-position overrides via `client.set_monitor(market_id, side, stop_loss_pct=..., take_profit_pct=...)`.\n\n**External wallet users**: monitors emit alerts via the briefing endpoint — your agent must be running for sells to execute. Managed wallet users: server executes directly.\n\n## When to Use This Skill\n\nUse this skill when the user wants to:\n- Trade weather markets automatically\n- Set up gopfan2-style temperature trading\n- Buy low on weather predictions\n- Check their weather trading positions\n- Configure trading thresholds or locations\n\n## What's New in v1.23.17\n\n- **Timezone-correct leads (SIM-5434).** Lead N is the smallest 1–3 such that every hourly issuance for the event day precedes the tick: `N = ceil((E_end_utc − tick) / 24h)`, where `E_end_utc` is the event date's 23:59:59 in the station offset. Builder records Open-Meteo `utc_offset_seconds` per station in `_meta`. Missing offset assumes UTC−12 (`tz=assumed`). Each date must carry hours `00:00`–`23:00` exactly once.\n\n## What's New in v1.23.16\n\n- **Lead-aware archive (SIM-5434).** Builder fetches `temperature_2m_previous_day{1,2,3}` in one request per station. Each date is `{high, low, leads}` with top-level high/low = lead 1. Under replay, `_station_forecast(..., event_date=)` picks `lead = (event_date − tick.date).days + 1` in 1–3; further-out events skip. Incomplete hourly arrays abort the build. Provenance appends `leads=1-3` when present. Hand-built / sample files without `leads` keep the old shape.\n\n## What's New in v1.23.15\n\n- **Historical forecast archive builder (SIM-5434).** `scripts/build_replay_forecast_archive.py` fills the SIM-5429 loader plane from Open-Meteo Previous Runs. Tick D sees the D-1 forecast (`temperature_2m_previous_day1` hourly → daily high/low). US stations are °F; international stations are °C. The file may include `_meta` (source, fetched_at, lead=previous_day1); the loader ignores it. Auto-load is still only `fixtures/replay_forecasts.json` (uncommitted). `.sample.json` stays shape-only and is never loaded.\n\n## What's New in v1.23.14\n\n- **Replay forecast archive (SIM-5429).** This release ships a **loader**, not an archive. Under `SIMMER_REPLAY=1` the skill fills `_REPLAY_FORECASTS` from `SIMMER_REPLAY_FORECASTS=/path.json`, or from a user file `fixtures/replay_forecasts.json` when present (uncommitted). Copy your archive to `fixtures/replay_forecasts.json` (uncommitted); the `.sample.json` is shape reference only and is never loaded. Live NOAA stays dark. A set-but-missing path fails the tick. One forced provenance line (`force=True`, survives `--quiet`): path, station count, min/max date — or `no archive: NOAA dark, 0 entries is FIX`.\n- **KEEP/KILL path.** A full-tape run stays **FIX** until a real historical-forecast file covers the window. Do not treat the sample temps as history.\n\n## What's New in v1.23.13\n\n- **Replay forecast archive (SIM-5429) first cut.** Loader + sample. Round 2 (1.23.14) stopped auto-loading the invented sample.\n\n## What's New in v1.23.12\n\n- **Live price path unchanged.** `_market_yes_price` is `external_price_yes or 0.5` when not in replay. Replay-only fallthrough to `yes_price` / `current_probability`.\n- **Gate script does not print KEEP.** Unit tests are a path check. KEEP needs a full-tape `simmer backtest ... --q temperature` with evals > 0, entries > 0, and an honest forecast.\n\n## What's New in v1.23.11\n\n- **Backtest-as-gate (SIM-5428).** Replay discovery already used `q=temperature`. The entry path now works under the same harness: frozen tick (`SIMMER_REPLAY_NOW`) for horizon/date parse, replay `yes_price` (not a silent 0.50), city-station fallback when the tape omits `resolution_criteria` (Dallas still excluded), no live NOAA/Open-Meteo (look-ahead), and preflight skipped so `WALLET_UNVERIFIED` cannot block SimState fills. Import is skipped under replay so it does not burn the eval budget.\n- **Keep / kill / fix** for the real-capital path is below. 90-day Simmer P&L is still the lock. Dogfood `MIN_HOURS=12` is a separate canary — this release does not change it.\n- **Agent glue:** `python scripts/run_backtest_gate.py` runs the pinned replay tests and prints the verdict table.\n\n## What's New in v1.23.10\n\n- **Discovery horizon tracks `SIMMER_WEATHER_MIN_HOURS_TO_RESOLVE`.** The existing `tags=weather` fetch and location keyword import were newest-first / same-day heavy. They now also query +1/+2 calendar days so a morning heartbeat with `MIN_HOURS=24` still sees markets that can clear the floor. Horizon is `max(MIN_HOURS, 48h)` — raising the hours knob widens discovery; there is no separate horizon env. Do not lower the hours floor to \"fix\" morning no-fills.\n\n## What's New in v1.23.9\n\n- **Replay-compatible discovery.** Under `simmer backtest` (`SIMMER_REPLAY=1`) the skill lists markets with `q=temperature` instead of `tags=weather&s\n\nArchive v1.23.17: 12 files, 70152 bytes\n\nFiles: CHANGELOG.md (16836b), clawhub.json (9836b), config.json (30b), DISCLAIMER.md (2349b), fixtures/replay_forecasts.sample.json (192b), scripts/build_replay_forecast_archive.py (12303b), scripts/run_backtest_gate.py (4246b), scripts/status.py (4441b), skill-card.md (2554b), SKILL.md (27421b), weather_trader.py (118117b), _meta.json (146b)\n\nArchive v1.23.10: 17 files, 72499 bytes\n\nFiles: CHANGELOG.md (10884b), clawhub.json (9455b), config.json (30b), DISCLAIMER.md (2349b), scripts/status.py (4441b), skill-card.md (2440b), SKILL.md (19689b), tests/test_discovery_horizon.py (7513b), tests/test_entry_safeguards.py (6601b), tests/test_replay_discovery.py (6534b), tests/test_resolution_criteria_reword.py (12279b), tests/test_source_agreement.py (7211b), tests/test_sources_none.py (4067b), tests/test_station_name_resolve.py (6213b), tests/test_weathertrader_preflight_gate.py (6385b), weather_trader.py (102121b), _meta.json (146b)\n\nArchive v1.23.8: 15 files, 64075 bytes\n\nFiles: CHANGELOG.md (9392b), clawhub.json (9362b), config.json (30b), DISCLAIMER.md (2349b), scripts/status.py (4441b), skill-card.md (2680b), SKILL.md (17201b), tests/test_entry_safeguards.py (6601b), tests/test_resolution_criteria_reword.py (12279b), tests/test_source_agreement.py (7211b), tests/test_sources_none.py (4067b), tests/test_station_name_resolve.py (6213b), tests/test_weathertrader_preflight_gate.py (6385b), weather_trader.py (96887b), _meta.json (145b)\n\nArchive v1.23.6: 14 files, 57647 bytes\n\nFiles: CHANGELOG.md (8314b), clawhub.json (8026b), config.json (30b), DISCLAIMER.md (2349b), scripts/status.py (4441b), skill-card.md (2312b), SKILL.md (14847b), tests/test_resolution_criteria_reword.py (10885b), tests/test_source_agreement.py (7211b), tests/test_sources_none.py (4067b), tests/test_station_name_resolve.py (6213b), tests/test_weathertrader_preflight_gate.py (6385b), weather_trader.py (89806b), _meta.json (145b)\n\nArchive v1.23.5: 13 files, 49701 bytes\n\nFiles: CHANGELOG.md (5176b), clawhub.json (8026b), config.json (30b), DISCLAIMER.md (2349b), scripts/status.py (4441b), skill-card.md (2674b), SKILL.md (14847b), tests/test_source_agreement.py (7211b), tests/test_sources_none.py (4067b), tests/test_station_name_resolve.py (5721b), tests/test_weathertrader_preflight_gate.py (6385b), weather_trader.py (83649b), _meta.json (145b)\n\nArchive v1.23.4: 13 files, 49502 bytes\n\nFiles: CHANGELOG.md (5176b), clawhub.json (8026b), config.json (30b), DISCLAIMER.md (2349b), scripts/status.py (4083b), skill-card.md (2862b), SKILL.md (14847b), tests/test_source_agreement.py (7211b), tests/test_sources_none.py (4067b), tests/test_station_name_resolve.py (5721b), tests/test_weathertrader_preflight_gate.py (6385b), weather_trader.py (83645b), _meta.json (145b)\n\nArchive v1.23.3: 13 files, 49070 bytes\n\nFiles: CHANGELOG.md (4787b), clawhub.json (8026b), config.json (30b), DISCLAIMER.md (2349b), scripts/status.py (4083b), skill-card.md (2472b), SKILL.md (14699b), tests/test_source_agreement.py (7211b), tests/test_sources_none.py (4067b), tests/test_station_name_resolve.py (5721b), tests/test_weathertrader_preflight_gate.py (6385b), weather_trader.py (83557b), _meta.json (145b)","readmeExcerpt":"Skill: polymarket-weather-trader Owner: simmer Summary: Trade Polymarket weather markets using NOAA (US) and Open-Meteo (international) forecasts via Simmer API. Inspired by gopfan2's weather trading approach. Use when user wants to trade temperature markets, automate weather bets, check forecasts, or run weather-based strategies. Tags: latest:1.23.22 Version history: v1.23.22 | 2026-09-18T05:14:24.718Z | user SIM-54","codeSnippets":[],"executableExamples":[{"language":"python","snippet":"from simmer_sdk import SimmerClient\n\nclient = SimmerClient.from_env(venue=\"polymarket\", live=True)"},{"language":"bash","snippet":"# Check account balance and positions\npython scripts/status.py\n\n# Detailed position list\npython scripts/status.py --positions"},{"language":"bash","snippet":"# Dry run (default — shows opportunities, no trades)\npython weather_trader.py\n\n# Execute real trades\npython weather_trader.py --live\n\n# With smart position sizing (uses portfolio balance)\npython weather_trader.py --live --smart-sizing\n\n# Check positions only\npython weather_trader.py --positions\n\n# View config\npython weather_trader.py --config\n\n# Disable safeguards (not recommended)\npython weather_trader.py --no-safeguards\n\n# Disable trend detection\npython weather_trader.py --no-trends\n\n# Enable volatility targeting (dynamic sizing based on market vol)\npython weather_trader.py --live --smart-sizing --vol-targeting\n\n# Quiet mode — only output on trades/errors (ideal for high-frequency runs)\npython weather_trader.py --live --quiet"},{"language":"bash","snippet":"# Pinned gate (no tape, no network, no API key)\npython skills/polymarket-weather-trader/scripts/run_backtest_gate.py\n\n# Same tests, direct\npython -m pytest skills/polymarket-weather-trader/tests/test_replay_discovery.py -q\n\n# Full-tape KEEP/KILL — build a window archive, copy it (uncommitted), then replay.\n# Auto-load is fixtures/replay_forecasts.json only. .sample.json is shape-only\n# and is never loaded.\npython skills/polymarket-weather-trader/scripts/build_replay_forecast_archive.py \\\n  --start YYYY-MM-DD --end YYYY-MM-DD --out /tmp/replay_forecasts.json\ncp /tmp/replay_forecasts.json \\\n  skills/polymarket-weather-trader/fixtures/replay_forecasts.json\n# SIMMER_WEATHER_LOCATIONS defaults to \"NYC\" — a tape covering other cities\n# (Seoul, London, Chicago, ...) will show 0 entries for every one of them\n# unless you widen this list to match the tape's city mix (SIM-5484). That\n# is expected scoping, not a station/forecast bug — see the note below.\n#\n# A plain `export SIMMER_WEATHER_LOCATIONS=...` does NOT reach the skill:\n# the replay harness builds the bundle subprocess env from a strict\n# allowlist (SIM-5067) that this var is not on, so it is silently stripped\n# and the run measures NYC regardless. Use --set on the entrypoint instead\n# — it writes config.json next to weather_trader.py, which load_config()\n# reads before env vars and which survives the per-tick bundle copy.\n#\n# Name the tape's actual cities, not a generic US list. E.g. for an\n# April tape weighted Seoul/Hong Kong/London/Shanghai/NYC/Paris: Seoul,\n# London, Paris and Shanghai are mapped (INTERNATIONAL_STATION_COORDS) and\n# will enter; Hong Kong has no station mapping anywhere in the skill and\n# cannot enter no matter what's in this list.\nsimmer backtest skills/polymarket-weather-trader \\\n  --entrypoint weather_trader.py --t0 YYYY-MM-DD --t1 YYYY-MM-DD \\\n  --cadence 12h --q temperature --min-volume 0 \\\n  --args \"--live --quiet --set locations=NYC,Chicago,Seattle,Atlanta,Miami,Austin,Houston,Denver,Seoul"},{"language":"text","snippet":"position_size = base_size × clamp(target_vol / realized_vol, min_alloc, max_leverage)"},{"language":"python","snippet":"from simmer_sdk import SimmerClient\n\nclient = SimmerClient.from_env(venue=\"polymarket\", live=True)"}],"parameters":null,"dependencies":[],"permissions":[],"extractedFiles":[{"path":"SKILL.md","content":"---\nname: polymarket-weather-trader\ndescription: Trade Polymarket weather markets using NOAA (US) and Open-Meteo (international) forecasts via Simmer API. Inspired by gopfan2's weather trading approach. Use when user wants to trade temperature markets, automate weather bets, check forecasts, or run weather-based strategies.\nmetadata:\n  author: Simmer (@simmer_markets)\n  version: \"1.23.22\"\n  displayName: Polymarket Weather Trader\n  difficulty: beginner\n  attribution: Strategy inspired by gopfan2 (public Polymarket trader — approach referenced, not endorsed).\n---\n# Polymarket Weather Trader\n\nTrade temperature markets on Polymarket using NOAA forecast data.\n\n> 🚨 **Framework, not a production trading system.** Read [DISCLAIMER.md](./DISCLAIMER.md) before connecting to a wallet with real funds.\n\n> **Template skill.** Defaults to dry-run mode (no real money). The `--live` flag is a deliberate single-command opt-in for real-money execution. Configure tunables (entry/exit thresholds, locations, etc.) via env vars listed below.\n\n## Safety rails (read first)\n\nThis skill executes real-money trades on Polymarket only when the `--live` flag is passed AND the human's wallet is linked to their Simmer account. Trading is bounded by default:\n\n- **Dry-run is the default.** `python weather_trader.py` (no flag) shows opportunities but executes no trades. The `--live` flag is required for real-money execution. There is no \"auto-graduate\" path.\n- **`$SIM` paper sandbox option.** Set `TRADING_VENUE=sim` to trade Simmer's $SIM virtual currency at real prices — useful for validating the strategy without USDC exposure.\n- **Real-money trading requires explicit human verification.** A wallet must be linked at [simmer.markets/dashboard](https://simmer.markets/dashboard?ref=sdk-skill&utm_campaign=sdk-skill) before any real trade lands. Without a linked wallet the SDK rejects real-money order construction.\n- **Per-trade cap.** `SIMMER_WEATHER_MAX_POSITION_USD` defaults to `$2.00` per trade. Configurable via env var, capped at the user's dashboard-set platform per-trade limit.\n- **Daily caps.** Platform-level daily caps apply (max trades/day, max USD/day). Set at [simmer.markets/dashboard](https://simmer.markets/dashboard?ref=sdk-skill&utm_campaign=sdk-skill) → SDK settings.\n- **Auto stop-loss is ON by default.** Server-side risk monitor watches every buy. Threshold is configurable per user at simmer.markets/dashboard → Settings → Auto Risk Monitor. **It cannot protect against gap-resolution, though:** weather temperature buckets jump straight to about 0 at resolution rather than decaying through your stop, so a percentage stop has no price to trigger on and no liquidity to exit into. Size for the full loss, not for the stop. See [DISCLAIMER.md](./DISCLAIMER.md).\n- **Strategy-side safeguards.** Beyond platform risk monitors, this skill checks flip-flop, slippage (`SIMMER_WEATHER_SLIPPAGE_MAX`, default 15%), time-decay (`SIMMER_WEATHER_MIN_HOURS_TO_RESOLVE`, default 2h), and re"},{"path":"_meta.json","content":"{\n  \"ownerId\": \"kn7axnp7bzqsf5fkx0z8px7han7zyq1x\",\n  \"slug\": \"polymarket-weather-trader\",\n  \"version\": \"1.23.22\",\n  \"publishedAt\": 1789708464718\n}"},{"path":"CHANGELOG.md","content":"# Changelog\n\n## [1.23.22] - 2026-09-18\n\n### Added\n- **Per-market position cap (SIM-5499).** `max_buys_per_market` (`SIMMER_WEATHER_MAX_BUYS_PER_MARKET`, default `1`) checks held positions via `get_positions()` before entry and skips a market that's already at cap. The 2026-09-17 gate run's replay DCA'd into every underpriced bucket every tick (mean 34 buys/market, max 137, 94.8% max DD) while live lands 1-2 because balance/backoffs throttle it — the two were measuring different strategies. Default `1` makes replay one-buy-per-market like live; raise it to keep DCA, or set `0` for the old unbounded behavior.\n\n### Changed\n- Requires `simmer-sdk>=0.25.8`, the first release whose `preflight()` is replay-aware. On an older SDK a backtest of this skill stops filling, because preflight blocks replay trades now that the skill no longer passes `skip_preflight`. Live trading is unaffected.\n\n### Fixed\n- **Skip reasons were collected but never surfaced.** `run_weather_strategy` built a `skip_reasons` list all run and never printed it, so diagnosing \"location X entered zero markets\" (the London 0/36 half of SIM-5499) meant re-reading per-tick logs. The summary now prints a per-location skip-reason breakdown (forces past `--quiet`, same as the station-parse coverage guard), and the two skip paths that carried no reason at all (\"no forecast available\", \"no bucket found\") now record one. Events whose text never parses into a location are tracked separately by a snippet of the event name.\n\n## [1.23.20] - 2026-09-17\n\n### Changed\n- **Replay trades no longer pass the deprecated `skip_preflight` valve (SIM-5430).** `SimmerClient.preflight()` is replay-aware under `SIMMER_REPLAY=1` on a loopback base URL, so `execute_trade` / `execute_sell` drop `skip_preflight=replay`. Live behaviour unchanged: preflight still runs and still blocks on `WALLET_UNVERIFIED`. Version skips 1.23.18/1.23.19, reserved for #384 and SIM-5440 which are in flight.\n## [1.23.19] - 2026-09-17\n\n### Fixed\n- Replay archive builder hardening from the KEEP/KILL run (SIM-5440): Open-Meteo HTTP 5xx responses retry up to 3 attempts with backoff, while HTTP 4xx still aborts immediately.\n- Long or old Previous Runs windows are fetched in 10-day chunks and merged internally. The build aborts if `utc_offset_seconds` differs across chunks for a station.\n- Added `--stations us|intl|all` (default `all`). `us` limits the build to the 8 configured Polymarket US resolution stations, so US-only archives avoid international DST guards and 56 needless requests.\n\n## [1.23.18] - 2026-09-17\n\n### Fixed\n- **Replay positions were always empty (SIM-5484).** `get_positions()` filtered by `venue=\"polymarket\"` even under replay, but the replay server rejects any `venue` filter (422, SIM-5067). The 422 was swallowed to `[]`, so the skill never knew what it already held and re-bought the same bucket every tick (13-25x/market observed on a full-tape run). Replay now omits the venue filter; live is unchanged.\n\n### Docs\n- **`SIMMER_"},{"path":"DISCLAIMER.md","content":"# Disclaimer\n\nThis skill is a **framework**, not a production trading system. Read this\nin full before connecting it to a wallet with real funds.\n\n## No financial advice\n\nNothing in this skill constitutes financial, investment, or trading\nadvice. The default strategy implemented here is a starting point, not a\ntested edge. Suitability for any account size or risk tolerance is your\nresponsibility to assess.\n\n## Default parameters are not validated\n\nDefault parameters are calibrated for testing the plumbing, not for live\nprofit. They have not been validated to produce positive returns under\ncurrent market conditions. Run paper mode for an extended period before\nscaling beyond default position sizes.\n\n## Automated trading carries irreversible risk\n\nWhen this skill runs with `--live`, it places real on-chain orders.\nOn-chain trades cannot be recalled. Strategy errors, signal lag, market\nregime shifts, and operator misconfiguration can produce losses\nexceeding any specific position size.\n\n## Risk monitoring may not apply to all market types\n\nStop-loss and take-profit monitors run on a fixed schedule. Markets that\nresolve faster than the monitor cycle cannot be exited automatically.\n\nSome markets also resolve by gapping rather than decaying. Weather\ntemperature buckets are the clearest case: the losing side can sit near\nyour entry, then jump straight to about 0 at resolution, with no\nintermediate price for a percentage stop to trigger on and no liquidity\nto exit into. On these markets a stop-loss cannot cap your loss\nregardless of the monitor cycle.\n\nPosition sizing is the only reliable risk control on these markets. Set\nit conservatively, assuming the full position can go to zero.\n\n## Use of this skill is at your own risk\n\nBy installing and running this skill you agree that the authors are not\nliable for any losses, direct or indirect, that arise from its use. This\napplies regardless of skill provenance — official Simmer skills,\ncommunity skills, and skills imported from external repositories all\ncarry this same disclaimer.\n\n## Where to learn more before going live\n\n- The skill's own `SKILL.md` documents the strategy and parameters\n- Your trading venue's documentation covers fee structure, order types,\n  and resolution rules\n- Simmer SDK documentation covers paper mode, dry-run flags, and\n  position monitoring"},{"path":"skill-card.md","content":"## Description:\n\nTrades Polymarket weather markets using NOAA and Open-Meteo forecasts through the Simmer API.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[simmer](https://clawhub.ai/user/simmer)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nExternal users and developers use this skill to inspect, configure, paper-trade, or explicitly live-trade weather prediction markets based on forecast data and market prices. It also supports position checks and replay/backtest workflows for validating the trading path before adding capital.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: The skill can place real-money trades when live mode is enabled, and automated trading can produce irreversible losses.\n\nMitigation: Start in dry-run or TRADING_VENUE=sim, keep tight platform and per-trade caps, and use --live only after accepting the trading risk.\n\nRisk: Some safeguards can be bypassed or fail open when context data is unavailable or when --no-safeguards is used.\n\nMitigation: Keep safeguards enabled, review preflight/status output before live use, and avoid --no-safeguards unless the operator has independently verified the market context.\n\nRisk: Weather bucket markets can resolve by gapping directly to near zero, so stop-loss monitoring may not cap downside.\n\nMitigation: Size positions assuming the full position can be lost, keep max position and max buys per market conservative, and rely on position sizing rather than stop-losses alone.\n\nRisk: External-wallet self-custody mode may require WALLET_PRIVATE_KEY, which increases credential exposure if handled casually.\n\nMitigation: Avoid providing WALLET_PRIVATE_KEY unless external-wallet live trading is required, prefer paper or managed-wallet flows first, and keep credentials scoped to the runtime environment.\n\n## Reference(s):\n\n- [ClawHub skill page](https://clawhub.ai/simmer/skills/polymarket-weather-trader)\n- [Simmer wallet setup](https://docs.simmer.markets/wallets)\n- [Simmer V2 migration](https://docs.simmer.markets/v2-migration)\n- [Open-Meteo Previous Runs API](https://previous-runs-api.open-meteo.com/v1/forecast)\n- [NOAA Weather API](https://api.weather.gov)\n\n## Skill Output:\n\n**Output Type(s):** [Text, Markdown, Code, Shell commands, Configuration, Guidance]\n\n**Output Format:** [Markdown guidance with inline shell commands, Python entrypoints, JSON configuration, and console summaries.]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [May place simulated or live trading orders only when invoked with the required runtime configuration and explicit live mode.]\n\n## Skill Version(s):\n\n1.23.22 (source: server evidence, SKILL.md frontmatter, CHANGELOG)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment."}],"languages":[],"docsSourceLabel":"CLAWHUB","editorialOverview":null,"editorialQuality":{"score":100,"threshold":65,"status":"thin","wordCount":2420,"uniquenessScore":41,"reasons":["uniqueness-below-45"]}},"media":{"evidence":{"source":"no-media","verified":false,"confidence":"low","updatedAt":"2026-10-09T02:13:58.015Z","emptyReason":"No screenshots, media assets, or demo links are available."},"primaryImageUrl":null,"mediaAssetCount":0,"assets":[],"demoUrl":null},"ownerResources":{"evidence":{"source":"unclaimed","verified":false,"confidence":"low","updatedAt":"2026-10-09T02:13:58.015Z","emptyReason":"This page has not been claimed by the agent owner."},"hasCustomPage":false,"customPageUpdatedAt":null,"customLinks":[],"structuredLinks":{"docsUrl":null,"demoUrl":null,"supportUrl":null,"pricingUrl":null,"statusUrl":null},"customPage":null},"relatedAgents":{"evidence":{"source":"protocol-neighbors","verified":false,"confidence":"medium","updatedAt":"2026-10-09T20:41:47.589Z","emptyReason":null},"items":[{"id":"8ebccd8e-3863-4187-8355-c3f14e1f9edf","entityType":"agent","canonicalPath":"/agent/iofficeai-aionui","slug":"iofficeai-aionui","name":"AionUi","description":"Free, local, open-source 24/7 Cowork app and OpenClaw for Gemini CLI, Claude Code, Codex, OpenCode, Qwen Code, Goose CLI, Auggie, and more | 🌟 Star if you like it!","url":"https://github.com/iOfficeAI/AionUi","homepage":"https://www.aionui.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-10-09T19:11:12.944Z","createdAt":"2026-02-25T03:38:16.584Z","downloads":null},{"id":"b917f68a-ebff-438e-84f8-3f4b2494c0bc","entityType":"agent","canonicalPath":"/agent/activepieces-activepieces","slug":"activepieces-activepieces","name":"activepieces","description":"AI Agents & MCPs & AI Workflow Automation • (~400 MCP servers for AI agents) • AI Automation / AI Agent with MCPs • AI Workflows & AI Agents • MCPs for AI Agents","url":"https://github.com/activepieces/activepieces","homepage":"https://www.activepieces.com","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-15T02:22:12.426Z","createdAt":"2026-02-25T03:38:12.412Z","downloads":null},{"id":"5cb26759-3a39-483f-94cf-276a98c13bb8","entityType":"agent","canonicalPath":"/agent/cherryhq-cherry-studio","slug":"cherryhq-cherry-studio","name":"cherry-studio","description":"AI productivity studio with smart chat, autonomous agents, and 300+ assistants. Unified access to frontier LLMs","url":"https://github.com/CherryHQ/cherry-studio","homepage":"https://cherry-ai.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-11T14:38:40.986Z","createdAt":"2026-02-25T03:38:19.379Z","downloads":null},{"id":"6f6582d0-5d76-4f0f-b81d-86520247950b","entityType":"agent","canonicalPath":"/agent/copilotkit-copilotkit","slug":"copilotkit-copilotkit","name":"CopilotKit","description":"The Frontend for Agents & Generative UI. React + Angular","url":"https://github.com/CopilotKit/CopilotKit","homepage":"https://docs.copilotkit.ai","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-03-25T09:50:57.846Z","createdAt":"2026-02-25T03:39:14.617Z","downloads":null}],"links":{"hub":"/agent","source":"/agent/source/clawhub","protocols":[{"label":"OpenClaw","href":"/agent/protocol/openclew"}]}}}