ΠΠΎΡ Π΄Π»Ρ Π°Π²ΡΠΎΠΌΠ°ΡΠΈΡΠ΅ΡΠΊΠΎΠΉ ΡΠΎΡΠ³ΠΎΠ²Π»ΠΈ Π½Π° ΠΏΠΎΠ³ΠΎΠ΄Π½ΡΡ ΡΡΠ½ΠΊΠ°Ρ Polymarket. Π‘ΠΊΠ°Π½ΠΈΡΡΠ΅Ρ ΡΠ΅ΠΌΠΏΠ΅ΡΠ°ΡΡΡΠ½ΡΠ΅ ΡΡΠ½ΠΊΠΈ ΠΏΠΎ 60 Π³ΠΎΡΠΎΠ΄Π°ΠΌ, ΠΏΡΠΎΠ³Π½ΠΎΠ·ΠΈΡΡΠ΅Ρ ΡΠ΅ΡΠ΅Π· Open-Meteo/WeatherAPI, Π½Π°Ρ ΠΎΠ΄ΠΈΡ edge ΠΈ ΡΠ°Π·ΠΌΠ΅ΡΠ°Π΅Ρ Π»ΠΈΠΌΠΈΡΠ½ΡΠ΅ ΠΎΡΠ΄Π΅ΡΠ° ΡΠ΅ΡΠ΅Π· CLOB API.
/home/app/polymarket-weather-bot/
| Π€Π°ΠΉΠ» | ΠΠ°Π·Π½Π°ΡΠ΅Π½ΠΈΠ΅ |
|---|---|
bot.py |
Π’ΠΎΡΠΊΠ° Π²Ρ ΠΎΠ΄Π°: FastAPI + APScheduler, Π²Π΅Π±-Π΄Π°ΡΠ±ΠΎΡΠ΄ |
scanner.py |
Gamma API β Π½Π°Ρ ΠΎΠ΄ΠΈΡ Π°ΠΊΡΠΈΠ²Π½ΡΠ΅ ΠΏΠΎΠ³ΠΎΠ΄Π½ΡΠ΅ ΡΡΠ½ΠΊΠΈ (49 highest + 8 lowest temp) |
forecaster.py |
Open-Meteo/WeatherAPI β ΠΏΡΠΎΠ³Π½ΠΎΠ· + Π²Π΅ΡΠΎΡΡΠ½ΠΎΡΡΠ½Π°Ρ ΠΌΠΎΠ΄Π΅Π»Ρ (norm CDF) |
analyzer.py |
ΠΠΎΠΈΡΠΊ edge: model_prob vs market_price, ΡΠΈΡΡ weak/medium/strong |
executor.py |
CLOB ΠΎΡΠ΄Π΅ΡΠ° ΡΠ΅ΡΠ΅Π· py-clob-client, retry + idempotency guard |
resolver.py |
Resolution: ΡΠ°ΠΊΡΠΈΡΠ΅ΡΠΊΠ°Ρ ΠΏΠΎΠ³ΠΎΠ΄Π° β outcome β P&L |
risk.py |
Kill switch, Π»ΠΈΠΌΠΈΡΡ ΠΏΠΎΠ·ΠΈΡΠΈΠΉ, cooldown, max daily loss |
db.py |
SQLite: thread-local connections, WAL, ΠΌΠΈΠ³ΡΠ°ΡΠΈΠΈ |
config.py |
ΠΡΠ΅ Π½Π°ΡΡΡΠΎΠΉΠΊΠΈ + CITY_COORDS (Π΅Π΄ΠΈΠ½ΡΠΉ ΠΈΡΡΠΎΡΠ½ΠΈΠΊ Π³ΠΎΡΠΎΠ΄ΠΎΠ²) |
cancel_stale.py |
Π£ΡΠΈΠ»ΠΈΡΠ° ΠΎΡΠΌΠ΅Π½Ρ ΡΡΠ°ΡΡΡ ΠΎΡΠ΄Π΅ΡΠΎΠ² |
ΠΡΠ½ΠΎΠ²Π½ΡΠ΅ ΠΏΠ΅ΡΠ΅ΠΌΠ΅Π½Π½ΡΠ΅ Π² .env ΠΈ config.py:
| ΠΠ°ΡΠ°ΠΌΠ΅ΡΡ | Π’Π΅ΠΊΡΡΠ΅Π΅ | ΠΠΏΠΈΡΠ°Π½ΠΈΠ΅ |
|---|---|---|
| DRY_RUN | true | Π‘ΠΈΠΌΡΠ»ΡΡΠΈΡ Π±Π΅Π· ΡΠ΅Π°Π»ΡΠ½ΡΡ ΠΎΡΠ΄Π΅ΡΠΎΠ² |
| BET_SIZE | $1.0 | ΠΠ°Π·ΠΎΠ²ΡΠΉ ΡΠ°Π·ΠΌΠ΅Ρ ΡΡΠ°Π²ΠΊΠΈ |
| BANKROLL | $100 | ΠΠ±ΡΠΈΠΉ Π±Π°Π½ΠΊΡΠΎΠ»Π» |
| MIN_EDGE | 5% | ΠΠΈΠ½ΠΈΠΌΠ°Π»ΡΠ½ΡΠΉ edge Π΄Π»Ρ Π²Ρ ΠΎΠ΄Π° |
| MIN_VOLUME | $1000 | ΠΠΈΠ½ΠΈΠΌΠ°Π»ΡΠ½ΡΠΉ ΠΎΠ±ΡΡΠΌ ΡΡΠ½ΠΊΠ° |
| SCAN_INTERVAL_SEC | 900 | Π‘ΠΊΠ°Π½ΠΈΡΠΎΠ²Π°Π½ΠΈΠ΅ ΠΊΠ°ΠΆΠ΄ΡΠ΅ 15 ΠΌΠΈΠ½ |
| RESOLVE_CHECK_SEC | 600 | ΠΡΠΎΠ²Π΅ΡΠΊΠ° resolution ΠΊΠ°ΠΆΠ΄ΡΠ΅ 10 ΠΌΠΈΠ½ |
| MAX_DAILY_LOSS | $20 | Kill switch ΠΏΡΠΈ Π΄Π½Π΅Π²Π½ΠΎΠΌ ΡΠ±ΡΡΠΊΠ΅ |
| MAX_OPEN_POSITIONS | 20 | ΠΠ°ΠΊΡΠΈΠΌΡΠΌ ΠΎΡΠΊΡΡΡΡΡ ΠΏΠΎΠ·ΠΈΡΠΈΠΉ |
# PM2
pm2 restart weather-bot
pm2 logs weather-bot --lines 30
pm2 monit
# ΠΠ°ΡΠ±ΠΎΡΠ΄
https://dashboard.szhub.space/weather-bot/
# API endpoints
GET /api/status # Π‘ΡΠ°ΡΡΡ Π±ΠΎΡΠ°
GET /api/trades # Π‘ΠΏΠΈΡΠΎΠΊ ΡΡΠ΅ΠΉΠ΄ΠΎΠ²
GET /api/markets # ΠΠΊΡΠΈΠ²Π½ΡΠ΅ ΡΡΠ½ΠΊΠΈ
GET /api/stats/today # Π‘ΡΠ°ΡΠΈΡΡΠΈΠΊΠ° Π΄Π½Ρ
GET /api/stats/history # ΠΡΡΠΎΡΠΈΡΠ΅ΡΠΊΠΈΠ΅ Π΄Π°Π½Π½ΡΠ΅
GET /api/stats/resolution # Π Π΅Π·ΡΠ»ΡΡΠ°ΡΡ resolution
POST /api/scan # ΠΠ°ΠΏΡΡΠΊ ΡΠΊΠ°Π½ΠΈΡΠΎΠ²Π°Π½ΠΈΡ
POST /api/resolve # ΠΠ°ΠΏΡΡΠΊ resolution
SQLite: /home/app/polymarket-weather-bot/data/weather-bot.db
Π’Π°Π±Π»ΠΈΡΡ: markets, trades, forecasts, daily_stats, bot_state, forecast_cache
ΠΠΈΠ³ΡΠ°ΡΠΈΠΈ β Π°Π²ΡΠΎΠΌΠ°ΡΠΈΡΠ΅ΡΠΊΠΈΠ΅ ΡΠ΅ΡΠ΅Π· _run_migrations() Π² db.py ΠΏΡΠΈ ΡΡΠ°ΡΡΠ΅.
database is lockedm.date < date('now'), Π½Π΅ <=first_seen Π½Π΅ ΡΠ΅ΡΡΠ΅ΡΡΡ ΠΏΡΠΈ ΠΎΠ±Π½ΠΎΠ²Π»Π΅Π½ΠΈΠΈ ΠΌΠ°ΡΠΊΠ΅ΡΠΎΠ²config.py β CITY_COORDS (slug, lat, lon, tz, name)scanner.py β POLYMARKET_CITIES (ΠΈ/ΠΈΠ»ΠΈ LOWEST_TEMP_CITIES)CITIES_BY_NAME ΡΠ³Π΅Π½Π΅ΡΠΈΡΡΠ΅ΡΡΡ Π°Π²ΡΠΎΠΌΠ°ΡΠΈΡΠ΅ΡΠΊΠΈ.env: DRY_RUN=falsePRIVATE_KEY, PROXY_ADDRESS, TRADE_PROXYpm2 restart weather-botcd /home/app/polymarket-weather-bot && source venv/bin/activate
python -c "from resolver import get_resolution_stats; import json; print(json.dumps(get_resolution_stats(), indent=2))"
Π db.py β _run_migrations() Π΄ΠΎΠ±Π°Π²ΠΈΡΡ tuple Π² ΡΠΏΠΈΡΠΎΠΊ migrations:
("table_name", "column_name", "COLUMN_TYPE"),