Automated trader for Polymarket weather highest temperature markets. Uses Simmer SDK's importable endpoint for market discovery and trades only during local...
---
name: polymarket-weather-high-temp-sniper
description: Automated trader for Polymarket weather highest temperature markets. Uses Simmer SDK's importable endpoint for market discovery and trades only during local 9-10 AM window when YES price exceeds threshold. Supports Telegram notifications.
metadata:
author: "OpenClaw"
version: "1.0.4"
displayName: "Weather High-Temp Sniper"
difficulty: "intermediate"
tags: ["weather", "polymarket", "simmer", "sniper"]
---
# Weather High-Temp Sniper
Automated trading bot for Polymarket weather markets focusing on "highest temperature" predictions. Uses Simmer SDK's modern market discovery workflow to find and import new weather markets, then executes trades during a specific time window.
## Features
- **Market Discovery**: Uses `/markets/importable` endpoint to find new Polymarket weather markets
- **Duplicate Prevention**: Checks `/markets/check` before importing to avoid duplicates
- **Active Market Fetching**: Retrieves active weather markets via `get_markets(import_source='polymarket', tags=['weather'])`
- **Time-Window Trading**: Only trades during local 9-10 AM based on market location's timezone
- **Fallback Window**: Optional 10:00-10:05 fallback if configured
- **Telegram Notifications**: Real-time alerts for trades, errors, and daily reports
- **Configurable Parameters**: All trading parameters tunable via environment or automaton
## How It Works
### 1. Market Discovery & Import
The bot runs a discovery phase every 6 hours to find new weather markets:
1. Fetches daily import quota from Simmer
2. Queries `list_importable_markets(venue="polymarket", q="highest temperature")`
3. Filters markets using `is_weather_market_question()` heuristics
4. For each candidate, checks if it already exists via `check_market_exists()`
5. Imports new markets using `import_market()` until quota is exhausted
### 2. Active Market Scanning
After discovery, the bot fetches active weather markets:
```python
markets = client.get_markets(
import_source="polymarket",
status="active",
max_hours_to_resolution=48
)
```
It then locally filters to only weather-related markets using the same heuristics.
### 3. Trading Logic
For each weather market:
1. **Extract location** from the question string and detect timezone (via `CITY_TZ_MAP`)
2. **Check time window**: Only trade if local time is 9:00-9:59 AM (or fallback 10:00-10:05)
3. **Get current price** (YES probability)
4. **Check threshold**: Price must be ≥ `ENTRY_PRICE_THRESHOLD`
5. **Validate position size**: Cost (shares × price) must be ≤ `MAX_POSITION_USD`
6. **Execute trade**: `place_order(market_id, "buy", shares, price, slippage)`
7. **Record state**: Mark market as traded today to avoid re-entry
### 4. Position Management
- No position in the same market on the same day
- All trades tracked in `sniper.state.json`
- State persists across restarts
## Configuration
All parameters are configurable via environment variables or via the OpenClaw automaton (`--set` flag):
| Parameter | Environment Variable | Default | Description |
|-----------|---------------------|---------|-------------|
| `entry_price_threshold` | `SIMMER_SNIPER2_ENTRY_PRICE_THRESHOLD` | `0.35` (35%) | Minimum YES price to trigger a buy |
| `max_position_usd` | `SIMMER_SNIPER2_MAX_POSITION_USD` | `2.50` | Maximum USD risk per trade |
| `shares_per_order` | `SIMMER_SNIPER2_SHARES` | `5` | Number of YES shares per order (min 5 on Polymarket) |
| `slippage_tolerance` | `SIMMER_SNIPER2_SLIPPAGE` | `0.15` (15%) | Maximum acceptable slippage |
| `scan_interval_seconds` | `SIMMER_SNIPER2_SCAN_INTERVAL` | `300` (5 min) | How often to scan for opportunities |
| `fallback_at_local_10` | `SIMMER_SNIPER2_FALLBACK_10AM` | `true` | Enable 10:00-10:05 fallback window |
| `telegram_enabled` | `SIMMER_SNIPER2_TELEGRAM_ENABLED` | `false` | Enable Telegram notifications |
| `telegram_chat_id` | `SIMMER_SNIPER2_TELEGRAM_CHAT_ID` | `""` | Your Telegram chat ID |
| `report_interval_seconds` | `SIMMER_SNIPER2_REPORT_INTERVAL` | `240` (4 min) | How often to send periodic reports |
### Setting Configuration
**Via environment variable**:
```bash
export SIMMER_SNIPER2_ENTRY_PRICE_THRESHOLD=0.40
export SIMMER_SNIPER2_MAX_POSITION_USD=5.00
```
**Via command line** (overrides config.json):
```bash
python sniper.py --set entry_price_threshold=0.40
python sniper.py --set max_position_usd=5.00
```
**Via OpenClaw automaton** (persistent tuning):
The skill integrates with the Simmer Automaton — configuration changes via automaton are automatically persisted and synced.
## Installation & Setup
### Prerequisites
- Python 3.8+
- Simmer API key (from [simmer.markets/dashboard](https://simmer.markets/dashboard))
- Polymarket linked wallet (bot will auto-link on first run)
- Telegram bot token and chat ID (optional, for notifications)
### Install Dependencies
```bash
cd polymarket-weather-high-temp-sniper-1
pip install -r requirements.txt
```
### Configure Environment
Create `.env` file in the skill folder:
```bash
# Required
SIMMER_API_KEY=your_simmer_api_key_here
# Optional (Telegram)
TELEGRAM_BOT_TOKEN=123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11
TELEGRAM_CHAT_ID=123456789 # Your Telegram user ID
TELEGRAM_ENABLED=true
```
Or set environment variables directly in your shell/automaton config.
### Test Telegram
```bash
python sniper.py --test-telegram
```
This verifies bot token and sends a test message.
## Usage
### Dry Run (Default)
See what would be traded without executing:
```bash
python scripts/sniper.py
```
### Live Trading
Execute real trades:
```bash
python scripts/sniper.py --live
```
The daemon will:
- Run discovery phase every 6 hours
- Scan every 5 minutes (configurable via `scan_interval_seconds`)
- Send Telegram notifications on trades and errors
- Print periodic reports every 4 minutes
### Show Current Positions
```bash
python scripts/sniper.py --positions
```
### Show Active Configuration
```bash
python scripts/sniper.py --config
```
### Adjust Parameters On-The-Fly
```bash
python scripts/sniper.py --set entry_price_threshold=0.40
python scripts/sniper.py --set max_position_usd=5.00
python scripts/sniper.py --set scan_interval_seconds=180
```
### Stop the Bot
Press `Ctrl+C` in the terminal where it's running. A shutdown notification will be sent via Telegram if enabled.
## State Persistence
The skill stores its runtime state in `sniper.state.json`:
```json
{
"date": "2025-01-15",
"traded_today": ["market_id_1", "market_id_2"],
"last_report_ts": 1705312345,
"last_discovery_ts": 1705312000
}
```
- `traded_today`: List of markets already traded today (reset at midnight UTC)
- `last_report_ts`: Timestamp of last periodic report
- `last_discovery_ts`: Timestamp of last market discovery phase
## Important Notes
### Timezone Detection
The bot auto-detects timezone from city names in the market question. It recognizes major cities worldwide (see `CITY_TZ_MAP` in the code). If a city is not recognized, the market is skipped.
### Price Source
The bot reads `current_probability` or `external_price_yes` from the Simmer market object. Prices are expressed as probabilities (0.0 - 1.0).
### Market Question Filtering
Only markets meeting these criteria are considered:
- Must contain "temperature", "temp", "°c", or "°f"
- Must contain "highest" or "high"
- Must NOT contain "lowest", "minimum", "low", "below", "fall below"
- Must NOT contain noise keywords: crypto, bitcoin, election, president, sports, etc.
### Import Quota
Simmer imposes daily import limits (typically ~10/day). The bot respects remaining quota and will skip discovery when exhausted.
### Position Sizing
Each trade costs: `shares_per_order × price`. The bot checks this ≤ `max_position_usd` before buying. Example: With `max_position_usd=2.50`, `shares=5`, and price `0.35`, cost = `5 × 0.35 = $1.75` ✅.
### Minimum Shares
Polymarket requires a minimum of 5 shares per order. The default `shares_per_order=5` satisfies this constraint.
## Troubleshooting
### "SIMMER_API_KEY not set"
Set your API key in `.env` or environment. Get it from [simmer.markets/dashboard](https://simmer.markets/dashboard) → SDK tab.
### "Telegram: bot token invalid"
Test with `--test-telegram`. Verify:
- `TELEGRAM_BOT_TOKEN` is correct (format: `123456:ABC-DEF...`)
- Bot has been started (send `/start` to your bot in Telegram)
- `TELEGRAM_CHAT_ID` is your numeric user ID (not username)
### Markets Not Being Traded
- Check if current time is within 9-10 AM local time for the market location
- Verify price is ≥ `entry_price_threshold` (default 35%)
- Ensure cost (`shares × price`) ≤ `max_position_usd`
- Check logs for skipped markets and reasons
### Quota Exhausted
The bot will log when daily import quota (10/day) is exhausted. Wait for the next UTC day or request quota increase from Simmer.
### No Positions Showing
Use `--positions` to fetch current positions. Ensure wallet is linked (bot attempts auto-link on first run).
## Support
For issues or feature requests, refer to the OpenClaw documentation or contact the skill author.
don't have the plugin yet? install it then click "run inline in claude" again.
restructured into six required components, made decision logic explicit with if-else branches, detailed external api connections and edge cases (rate limits, auth expiry, network timeouts, empty result sets), preserved all original procedure steps and configuration, added outcome signals and failure modes.
This skill runs an automated trading bot for Polymarket weather markets focused on "highest temperature" predictions. it discovers new markets every 6 hours using Simmer's /markets/importable endpoint, then executes buy orders on YES shares during a specific 9-10 AM local time window when the probability price exceeds a configurable threshold. use this when you want hands-off arbitrage on weather prediction markets with timezone-aware entry logic and optional Telegram alerts.
Required
SIMMER_API_KEY (environment variable): your Simmer API key from simmer.markets/dashboard. no default; skill will not run without it.Optional
TELEGRAM_BOT_TOKEN (environment variable): telegram bot token in format 123456:ABC-DEF.... required only if telegram notifications are enabled.TELEGRAM_CHAT_ID (environment variable): your numeric telegram user ID (not username). required only if telegram notifications are enabled.SIMMER_SNIPER2_ENTRY_PRICE_THRESHOLD (environment variable): minimum YES probability to buy. default 0.35 (35%).SIMMER_SNIPER2_MAX_POSITION_USD (environment variable): max USD per trade. default 2.50.SIMMER_SNIPER2_SHARES (environment variable): shares per order. default 5 (polymarket minimum).SIMMER_SNIPER2_SLIPPAGE (environment variable): max slippage tolerance. default 0.15 (15%).SIMMER_SNIPER2_SCAN_INTERVAL (environment variable): seconds between opportunity scans. default 300 (5 minutes).SIMMER_SNIPER2_FALLBACK_10AM (environment variable): enable 10:00-10:05 AM fallback window. default true.SIMMER_SNIPER2_TELEGRAM_ENABLED (environment variable): enable telegram alerts. default false.SIMMER_SNIPER2_REPORT_INTERVAL (environment variable): seconds between periodic reports. default 240 (4 minutes).External Dependencies
list_importable_markets(), check_market_exists(), import_market(), get_markets(), place_order().Phase 1: Market Discovery (runs every 6 hours)
Query daily import quota from Simmer API.
Call list_importable_markets(venue="polymarket", q="highest temperature").
For each candidate market, filter using weather heuristics: must contain ("temperature" OR "temp" OR "°c" OR "°f") AND ("highest" OR "high"), and must NOT contain ("lowest" OR "minimum" OR "low" OR "below" OR "fall below" OR "crypto" OR "bitcoin" OR "election" OR "president" OR "sports" OR noise keywords).
For each filtered candidate, call check_market_exists(market_id) to avoid duplicate imports.
If market does not exist and quota remains, call import_market(market_id).
Repeat steps 4-5 until quota exhausted or no more candidates.
sniper.state.json as last_discovery_tsPhase 2: Active Market Scanning (runs every scan_interval_seconds, default 5 minutes)
Call get_markets(import_source="polymarket", status="active", max_hours_to_resolution=48).
Locally filter markets using same weather heuristics as phase 1.
For each weather market, extract city name from question string.
Look up timezone from CITY_TZ_MAP (hardcoded mapping of major cities to IANA tznames).
Get current local time in that timezone. check if local hour is 9 (9:00-9:59 AM).
If in window, read current_probability from market object (expressed 0.0-1.0).
Compare yes price to entry_price_threshold. if yes_price >= threshold, proceed. else skip market.
Check sniper.state.json for traded_today list. if market_id already in list, skip. else proceed.
Calculate cost: shares_per_order × yes_price.
Compare cost to max_position_usd. if cost <= max_position_usd, proceed. else skip.
Call place_order(market_id=market_id, side="buy", shares=shares_per_order, price=yes_price, slippage=slippage_tolerance).
If order succeeds, append market_id to sniper.state.json["traded_today"]. log timestamp.
If telegram enabled, send trade notification with market details, price, shares, cost.
If any error occurs (network timeout, api rate limit, invalid order), log error and send telegram alert if enabled.
Phase 3: Periodic Reporting (runs every report_interval_seconds, default 4 minutes)
Check timestamp of last report in sniper.state.json["last_report_ts"].
If current_time - last_report_ts > report_interval, send summary.
Compose report: total trades today (length of traded_today), current positions (call get_positions()), pnl summary, next discovery window.
Send via telegram if enabled, else print to stdout.
Update sniper.state.json["last_report_ts"] to current time.
Phase 4: Shutdown & Cleanup
On Ctrl+C or termination signal, gracefully close connections.
Send "bot offline" telegram message if enabled.
Exit process.
Discovery Window (if/else)
Market Filtering (if/else)
Timezone Lookup (if/else)
CITY_TZ_MAP: use detected timezone.Time Window (if/else)
Price Threshold (if/else)
Trade History (if/else)
sniper.state.json["traded_today"]: proceed to position size check.traded_today: skip market, already traded today. reset list at midnight UTC.Position Size (if/else)
Order Execution (if/else)
Telegram (if/else)
Import Quota (if/else)
State File: sniper.state.json
Located in skill root directory. format:
{
"date": "2025-01-15",
"traded_today": ["market_id_1", "market_id_2"],
"last_report_ts": 1705312345,
"last_discovery_ts": 1705312000
}
date: ISO date string (YYYY-MM-DD). reset to current UTC date daily.traded_today: list of market_ids already traded today (empty list if no trades yet).last_report_ts: unix timestamp of last periodic report sent.last_discovery_ts: unix timestamp of last market discovery phase.Telegram Notifications (if enabled)
Logs
Polymarket Orders
place_order() execute immediately if price available and wallet funded.success is confirmed by any of these signals:
Trade Executed: order_id returned from place_order(), market_id appended to traded_today in state file, stdout logs "BOUGHT X YES on MARKET_ID @ PRICE cost=$Y.ZZ".
Telegram Trade Alert: if telegram enabled, user receives notification within 10 seconds of order execution.
Periodic Report Received: if telegram enabled, user receives summary report every 4 minutes (configurable). if stdout only, report printed to console.
State File Updated: sniper.state.json reflects latest traded_today list and timestamps, persists across restarts.
No Errors in Logs: if skill runs for 6+ hours without "ERROR" or "EXCEPTION" messages, it's operating normally. network timeouts logged as "WARN", not "ERROR".
Dry Run Matches Live: run with python sniper.py (dry run) and verify markets/prices printed match those traded in --live mode, confirming logic is deterministic.
failure signals:
SIMMER_API_KEY not set: skill exits immediately, logs error.Telegram: bot token invalid: skill logs "WARN: telegram unavailable", continues without alerts.No markets found: skill logs "INFO: no weather markets matched criteria", continues scanning every 5 min.Quota exhausted: skill logs "INFO: import quota exhausted (0/10)", skips discovery until next UTC day.Wallet not linked: skill logs "ERROR: polymarket wallet not linked", attempts auto-link on first run, exits if fails.Network timeout on order: logged as "WARN: order timeout, retrying next scan", does not block future scans.