← Назад

Polymarket Weather Bot — Спека (26 Apr 2026)

Автоматический бот для заработка на weather prediction markets на Polymarket

Статус: ✅ Deployed (DRY RUN) — после полного аудита


🎯 Цель

Бот, который 24/7 сканирует погодные рынки на Polymarket, сравнивает с профессиональными прогнозами (Open-Meteo/NOAA) и ставит limit orders когда находит расхождение >5%.

Целевые метрики:

UI: Web dashboard на szhub.space/weather-bot (FastAPI + Vanilla JS) Правило: НИКОГДА не использовать токен Бендера. Свой TG бот или Web Push.


📦 Архитектура

┌─────────────────────────────────────────────────┐
│                 Weather Bot                      │
│                                                  │
│  ┌──────────┐  ┌──────────┐  ┌───────────────┐ │
│  │  Scanner  │→ │ Analyzer │→ │   Executor    │ │
│  │(Gamma API)│  │(Open-Meteo)│  │(CLOB Orders) │ │
│  └──────────┘  └──────────┘  └───────────────┘ │
│       ↓              ↓              ↓            │
│  ┌──────────────────────────────────────────┐   │
│  │            SQLite DB                      │   │
│  │  markets | forecasts | trades | pnl       │   │
│  └──────────────────────────────────────────┘   │
│       ↓                                          │
│  ┌──────────┐  ┌──────────┐                     │
│  │ Telegram  │  │   Logs   │                     │
│  │  Alerts   │  │ (Winston)│                     │
│  └──────────┘  └──────────┘                     │
└─────────────────────────────────────────────────┘

Компоненты:

# Модуль Что делает
1 Scanner Gamma API → находит активные weather markets (город, тип, порог, дата)
2 Forecaster Open-Meteo API → получает прогноз, строит probability model
3 Analyzer Сравнивает model P vs market P, считает edge
4 Executor Если edge > порог → limit order через CLOB API
5 Tracker Отслеживает открытые позиции, P&L, resolution
6 Notifier Telegram алерты: новые ставки, resolution, daily P&L
7 Risk Manager Max per market, daily loss limit, kill switch

🔧 Tech Stack

Компонент Технология Почему
Язык Python 3.10+ py-clob-client — официальный SDK
Trading py-clob-client Polymarket CLOB API
Weather Open-Meteo API Бесплатно, без API key, hourly 16 дней
DB SQLite Лёгкая, уже используем в futures-screener
Process PM2 Уже есть на сервере
Alerts Telegram Bot У нас уже есть Bender
Scheduler APScheduler Python cron внутри процесса
Logs loguru Простой structured logging

Python Dependencies

py-clob-client>=0.1.0
web3==6.14.0          # ВАЖНО: пиннить! Новые версии ломают py-clob-client
python-dotenv
requests
aiohttp
apscheduler
loguru
python-telegram-bot

📊 Шаг 1: Scanner (Gamma API)

Что делает

Каждые 5 минут сканирует Gamma API на новые/обновлённые weather markets.

Gamma API

GET https://gamma-api.polymarket.com/markets
  ?tag=weather
  &active=true
  &closed=false

Данные с рынка

{
  "condition_id": "0x...",
  "question": "Will the high temperature in NYC on April 27 be 75°F or higher?",
  "tokens": [
    {"token_id": "12345...", "outcome": "Yes", "price": 0.72},
    {"token_id": "67890...", "outcome": "No", "price": 0.28}
  ],
  "volume": 15000,
  "end_date": "2026-04-27T23:59:00Z",
  "resolution_source": "NOAA Climate Data"
}

Парсинг question → структура

Из текста вопроса извлекаем:

DB: таблица markets

CREATE TABLE markets (
  id TEXT PRIMARY KEY,        -- condition_id
  question TEXT,
  city TEXT,
  date TEXT,                  -- YYYY-MM-DD
  metric TEXT,                -- high_temp, low_temp, precip, wind
  threshold REAL,             -- в °C (нормализовано)
  operator TEXT,              -- gte, lte, between
  yes_token_id TEXT,
  no_token_id TEXT,
  volume REAL,
  end_date TEXT,
  resolution_source TEXT,
  created_at TEXT,
  status TEXT DEFAULT 'active' -- active, traded, resolved
);

🌡️ Шаг 2: Forecaster (Open-Meteo API)

Что делает

Для каждого найденного рынка получает профессиональный прогноз.

Open-Meteo API (бесплатно, без ключа)

GET https://api.open-meteo.com/v1/forecast
  ?latitude=40.71
  &longitude=-74.01
  &hourly=temperature_2m,precipitation,wind_speed_10m
  &temperature_unit=fahrenheit
  &timezone=America/New_York
  &forecast_days=7

Города → координаты (захардкодить топ-10)

CITIES = {
  "NYC":     {"lat": 40.71, "lon": -74.01, "tz": "America/New_York"},
  "London":  {"lat": 51.51, "lon": -0.13,  "tz": "Europe/London"},
  "Seoul":   {"lat": 37.57, "lon": 126.98, "tz": "Asia/Seoul"},
  "Tokyo":   {"lat": 35.68, "lon": 139.69, "tz": "Asia/Tokyo"},
  "LA":      {"lat": 34.05, "lon": -118.24,"tz": "America/Los_Angeles"},
  "Chicago": {"lat": 41.88, "lon": -87.63, "tz": "America/Chicago"},
  "Miami":   {"lat": 25.76, "lon": -80.19, "tz": "America/New_York"},
  "Dallas":  {"lat": 32.78, "lon": -96.80, "tz": "America/Chicago"},
  "Denver":  {"lat": 39.74, "lon": -104.99,"tz": "America/Denver"},
  "Seattle": {"lat": 47.61, "lon": -122.33,"tz": "America/Los_Angeles"},
}

Probability Model

Для вопроса "Will high temp ≥ 75°F?":

  1. Берём hourly forecast на целевой день
  2. Находим max temperature из hourly данных
  3. Open-Meteo даёт точечный прогноз — добавляем uncertainty:
    • ±2°F для 1-2 дня вперёд (NOAA accuracy ~90%)
    • ±4°F для 3-5 дней
    • ±6°F для 6+ дней
  4. Строим нормальное распределение: N(forecast_max, sigma)
  5. P(temp ≥ threshold) = 1 - CDF(threshold)
from scipy.stats import norm

def calculate_probability(forecast_max, threshold, days_ahead):
    sigma = {1: 2, 2: 2, 3: 4, 4: 4, 5: 4}.get(days_ahead, 6)
    prob = 1 - norm.cdf(threshold, loc=forecast_max, scale=sigma)
    return round(prob, 4)

# Пример: прогноз 78°F, порог 75°F, завтра
# P = 1 - CDF(75, μ=78, σ=2) = 0.933 → 93.3% вероятность YES

DB: таблица forecasts

CREATE TABLE forecasts (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  market_id TEXT,
  forecast_value REAL,      -- predicted max/min/etc
  model_probability REAL,   -- наша оценка P(YES)
  sigma REAL,               -- uncertainty
  fetched_at TEXT,
  FOREIGN KEY (market_id) REFERENCES markets(id)
);

📐 Шаг 3: Analyzer (Edge Detection)

Логика

def analyze_opportunity(market, forecast):
    model_prob = forecast.model_probability
    market_prob = market.yes_price  # текущая цена YES на Polymarket

    edge = model_prob - market_prob

    # Фильтры
    if abs(edge) < 0.05:        return None  # edge < 5% → skip
    if market.volume < 5000:     return None  # low liquidity → skip
    if forecast.sigma > 5:       return None  # too uncertain → skip

    # Направление
    if edge > 0:
        side = "YES"   # модель говорит вероятнее чем рынок думает
        price = model_prob - 0.02  # чуть ниже модели для заполнения
    else:
        side = "NO"
        price = (1 - model_prob) - 0.02

    return {
        "market_id": market.id,
        "side": side,
        "price": price,
        "edge": abs(edge),
        "model_prob": model_prob,
        "market_prob": market_prob
    }

Edge Thresholds

Уровень Edge Действие Размер ставки
Weak 5-10% Ставим min $5
Medium 10-20% Стандарт $10-15
Strong 20%+ Aggressive $20-50

💰 Шаг 4: Executor (CLOB Orders)

Limit Order (0% maker fee!)

from py_clob_client.clob_types import OrderArgs, OrderType
from py_clob_client.order_builder.constants import BUY

def place_bet(client, token_id, price, size):
    order = OrderArgs(
        token_id=token_id,
        price=round(price, 2),  # кратно 0.01
        size=size,
        side=BUY
    )
    signed = client.create_order(order)
    response = client.post_order(signed, OrderType.GTC)
    return response

Почему LIMIT, а не MARKET


🛡️ Шаг 5: Risk Manager

Правила

RISK_CONFIG = {
    "max_per_market": 50,          # макс $50 на 1 рынок
    "max_daily_loss": 100,         # -$100/день → стоп
    "max_open_positions": 20,      # не более 20 одновременно
    "max_total_deployed": 300,     # макс $300 в позициях
    "min_volume": 5000,            # skip рынки с volume < $5K
    "min_edge": 0.05,              # skip edge < 5%
    "max_position_pct": 0.15,      # не более 15% банка на 1 ставку
    "cooldown_same_market": 3600,  # 1 час между ставками на один рынок
}

Kill Switch


📱 Шаг 6: Telegram Notifications

Сообщения

🌤️ NEW BET
NYC High Temp ≥ 75°F (Apr 27)
Model: 93.3% | Market: 72% | Edge: 21.3%
→ BUY YES @ $0.71 × $15
Status: Order placed (GTC)

✅ RESOLVED — WIN
NYC High Temp ≥ 75°F (Apr 27)
Actual: 79°F → YES wins
Profit: +$4.35 (29% ROI)

📊 DAILY SUMMARY
Bets: 12 | Won: 9 | Lost: 3 | WR: 75%
P&L: +$38.50 | Total deployed: $180
Bank: $538.50 (+7.7% today)

📁 Структура проекта

/home/app/polymarket-weather-bot/
├── .env                    # PRIVATE_KEY, TELEGRAM_TOKEN, etc
├── ecosystem.config.js     # PM2 config
├── requirements.txt
├── bot.py                  # Main entry point + scheduler
├── scanner.py              # Gamma API market discovery
├── forecaster.py           # Open-Meteo + probability model
├── analyzer.py             # Edge detection
├── executor.py             # CLOB order placement
├── risk.py                 # Risk management
├── tracker.py              # Position tracking + P&L
├── notifier.py             # Telegram alerts
├── db.py                   # SQLite schema + helpers
├── config.py               # Constants, cities, thresholds
├── utils.py                # Parsing, conversion helpers
├── data/
│   └── weather-bot.db      # SQLite database
└── logs/
    └── bot.log

🚀 План реализации (5 шагов)

# Шаг Что делаем Время
1 Scaffold + Auth Проект, .env, py-clob-client подключение, тест API 30 мин
2 Scanner + Forecaster Gamma API парсинг weather markets + Open-Meteo прогнозы + probability model 1-2 часа
3 Analyzer + Executor Edge detection + limit order placement + SQLite tracking 1-2 часа
4 Risk + Notifier Risk limits, kill switch, Telegram алерты, daily summary 1 час
5 Test + Deploy Тест с $5-10 реальных, PM2, мониторинг первые 24ч 1 час

Итого: 1-2 дня до рабочего бота.


⚠️ Критические моменты

  1. web3==6.14.0 — пиннить! Новые версии ломают py-clob-client
  2. Нет testnet — все запросы = production. Первые тесты с $1-5
  3. Resolution source — матчить data source с тем что рынок использует (NOAA vs Open-Meteo)
  4. Fahrenheit/Celsius — аккуратно конвертить, рынки обычно в °F
  5. Token ID — длинные числа из Gamma API, clobTokenIds[0] = YES
  6. MetaMask wallet — отдельный от основного! Только для бота
  7. USDC на Polygon — нужен USDC.e + немного MATIC на газ
  8. Approve contracts — одноразовый setup: approve USDC + conditional tokens на Exchange

💵 Стартовые затраты

Что Сколько
USDC на Polygon $200-500
MATIC на газ $1-2
Open-Meteo API $0 (free)
Gamma API $0 (free)
VPS $0 (наш сервер)
Итого $201-502