feat: Add database-backed user and subscription management, update project architecture documentation, and outline technical debt.
This commit is contained in:
@@ -1,10 +1,14 @@
|
||||
# 🌡️ PolyWeather: Intelligent Weather Quant Analysis Bot
|
||||
# PolyWeather
|
||||
|
||||
[](https://www.python.org/downloads/)
|
||||
[](https://opensource.org/licenses/MIT)
|
||||
[](https://deepwiki.com/yangyuan-zhen/PolyWeather)
|
||||
PolyWeather is a weather intelligence system built around live airport observations, multi-model forecasts, DEB blending, and Telegram alert delivery.
|
||||
|
||||
PolyWeather is a multi-source weather analysis and quantification tool. It aggregates high-precision forecasts, real-time airport METAR observations, a math-based probability engine, and AI-driven decision support to provide deep insights for weather-related risk assessment and data-driven decision making.
|
||||
Current production layout:
|
||||
|
||||
- Frontend: Next.js on Vercel
|
||||
- Backend API: FastAPI on VPS
|
||||
- Bot / alert loop: Telegram bot on VPS
|
||||
|
||||
The old FastAPI static web page has been removed. Vercel is the only web entry point.
|
||||
|
||||
<p align="center">
|
||||
<img src="docs/images/demo_ankara.png" alt="PolyWeather Demo - Ankara Live Analysis" width="420">
|
||||
@@ -18,203 +22,164 @@ PolyWeather is a multi-source weather analysis and quantification tool. It aggre
|
||||
<em>🗺️ Interactive Web Map: Real-time global monitoring with rich data visualization</em>
|
||||
</p>
|
||||
|
||||
---
|
||||
## Features
|
||||
|
||||
## ✨ Core Features
|
||||
- Multi-source weather aggregation
|
||||
- Open-Meteo
|
||||
- METAR live observations
|
||||
- MGM official data for Ankara
|
||||
- Multi-model highs such as ECMWF / GFS / ICON / GEM / JMA when available
|
||||
- DEB blended forecast
|
||||
- Dynamic weighting based on recent model error
|
||||
- City dashboard
|
||||
- Global city list
|
||||
- City detail panel
|
||||
- Nearby station map markers
|
||||
- Trend chart
|
||||
- Multi-model comparison
|
||||
- Daily forecast table
|
||||
- Telegram proactive alerts
|
||||
- Ankara Center reached DEB
|
||||
- Momentum spike
|
||||
- Forecast breakthrough
|
||||
- Advection / nearby lead station signal
|
||||
- Late-day suppression
|
||||
- If the local daily high has likely already passed and the market is cooling off, active alerts are downgraded to status only and are not pushed
|
||||
|
||||
### 1. 🌐 Interactive Web Map Dashboard
|
||||
## Alert Rules
|
||||
|
||||
- **Global Overview**: Real-time Leaflet-based dark-themed map pinpointed to official Polymarket settlement airport coordinates.
|
||||
- **Progressive Background Loading**: Intelligently fetches multi-source data across all cities without hitting API rate limits.
|
||||
- **Rich Visualization**: Chart.js-powered temperature trends with METAR scatter overlay, multi-model comparison bars, Gaussian probability distribution, and dynamic risk badges.
|
||||
- **Zoom-based Intelligence**: Map automatically filters minor cities (e.g., Atlanta/Ankara) and local station labels at lower zoom levels to maintain clarity, showing only major global hubs when zoomed out.
|
||||
- **Technical Guide Interface**: Features an interactive on-map technical guide explaining DEB prediction curves, probability bands, and risk factors.
|
||||
- **Cinematic Interaction & Sync**: City selection triggers a smooth fly-to zoom animation. The **Multi-Model Forecast** panel automatically synchronizes with the selected day in the 5-day forecast table, showing historical model performance and future projections.
|
||||
- **Forced Sync & Cache Control**: For specific regions like Ankara, the dashboard supports a 60-second real-time cache TTL with a manual "Force Refresh" button to bypass global caches and fetch the absolute latest MGM/METAR data.
|
||||
- **Dual-Engine Architecture**: Runs concurrently with the Telegram bot via a FastAPI backend, sharing the same data collection, analysis logic (`analyze_weather_trend`), and AI prompt pipeline.
|
||||
Implemented rules:
|
||||
|
||||
### 2. 🧬 Dynamic Ensemble Blending (DEB Algorithm)
|
||||
- `ankara_center_deb_hit`
|
||||
- Only uses `Ankara (Bolge/Center)` station / `istNo=17130`
|
||||
- This is the official Ankara center station used for the Center signal
|
||||
- `momentum_spike`
|
||||
- 30-minute slope exceeds the configured threshold
|
||||
- `forecast_breakthrough`
|
||||
- Current observed temperature is above the highest available major model high by margin
|
||||
- `advection`
|
||||
- Nearby station leads the airport station and wind regime supports warm advection
|
||||
|
||||
The system automatically tracks the historical performance of weather models (ECMWF, GFS, ICON, GEM, JMA) per city:
|
||||
Suppression rule:
|
||||
|
||||
- **Error-Based Weighting**: Dynamically adjusts model weights based on their Mean Absolute Error (MAE) over the past 7 days. Lower error = higher weight.
|
||||
- **Blended Forecast**: Provides a bias-corrected "DEB Blended High Temperature" recommendation.
|
||||
- **Multi-Source Training**: Integrates official regional sources (like Turkey's MGM) into the training pipeline alongside international models (ECMWF, GFS, etc.).
|
||||
- **Accuracy Tracking**: Use the `/deb` command to view DEB's historical settlement hit rate and MAE, compared against individual models.
|
||||
- **Auto-Cleanup**: Only retains the last 14 days of records to prevent unbounded data growth.
|
||||
- `peak_passed_guard`
|
||||
- No active push if the city's local peak has already passed, enough time has elapsed, and the current temperature has materially rolled over from the day's high
|
||||
|
||||
### 3. 🎲 Math Probability Engine (Settlement Probability)
|
||||
Push dedupe rule:
|
||||
|
||||
Automatically computes the probability for each possible settlement integer using a Gaussian distribution:
|
||||
- Same city + same trigger type only pushes once while still active
|
||||
- It can push again only after the signal clears and re-arms
|
||||
- Cooldown still applies at city level
|
||||
|
||||
- **Reality-Anchored μ**: When actual max temperature is significantly below forecasts during/after the peak window (forecast bust), μ anchors on the observed max instead of failed predictions. Otherwise, uses a weighted average of DEB/multi-model median (70%) and ensemble median (30%).
|
||||
- **Standard Deviation σ — Three-Layer Pipeline**:
|
||||
1. **Ensemble Base**: σ = (P90-P10) / 2.56
|
||||
2. **MAE Floor**: Uses DEB's historical MAE as σ minimum—prevents ensembles from underestimating true uncertainty
|
||||
3. **Shock Score Amplifier**: σ × (1 + 0.5 × shock_score) when weather is changing rapidly
|
||||
- **Time Decay**: Before peak σ×1.0 → During peak σ×0.7 → After peak σ×0.3
|
||||
- **Observed Floor**: Temperatures below the current METAR max WU value are excluded
|
||||
- **Dead Market Override**: When a dead market is confirmed, probability collapses to 100% at the settled value
|
||||
## Data Semantics
|
||||
|
||||
#### 💥 Shock Score: Weather Disruption Soft Scorer (0~1)
|
||||
Alert message fields:
|
||||
|
||||
Evaluates environmental stability from the last 4 METAR observations. Higher = more unstable = wider σ:
|
||||
- `实测 / Now`
|
||||
- Uses `METAR current.temp` first
|
||||
- Falls back to `MGM current.temp` if METAR current temperature is unavailable
|
||||
- `时间 / Time`
|
||||
- `local`: city local clock time
|
||||
- `observed`: observation time attached to the current reading
|
||||
|
||||
| Component | Weight | Trigger |
|
||||
| :-------------------- | :----- | :---------------------------------------------------------------- |
|
||||
| Wind Direction Change | 0~0.4 | Angle difference × wind speed amplifier (weak winds downweighted) |
|
||||
| Cloud Cover Jump | 0~0.35 | Cloud code escalation (FEW→BKN, etc.) |
|
||||
| Pressure Change | 0~0.25 | >2hPa change within 2 hours |
|
||||
## Deployment
|
||||
|
||||
### 4. 🤖 AI Deep Analysis (Groq LLaMA 3.3 70B)
|
||||
### Backend / bot on VPS
|
||||
|
||||
Feeds all weather data into LLaMA 70B, analyzed via a **P0→P4 Priority Chain**:
|
||||
Requirements:
|
||||
|
||||
- **P0 Forecast Bust Detection** (highest priority): Graded severity (light/medium/heavy) when actual temps diverge from forecasts. Requires slope + wind/cloud verification before declaring settlement locked. "Bust ≠ locked" — still checks for second-wave warming.
|
||||
- **P1 Real-Time Rhythm**: 2 consecutive METAR highs → still warming; 2 non-highs with slope ≤ 0 → dead market. Low-radiation warming → multi-factor (advection/mixing layer/heat island), no single-factor attribution.
|
||||
- **P2 Inhibitors** (city-aware): Precipitation → strong suppression. High humidity + thick clouds sustained 2+ reports → possible suppression, but thresholds vary by city type (maritime vs. continental). Single factor insufficient.
|
||||
- **P3 Probability Cross-Check**: References settlement probability for consistency check with P1. Contradictions explained with deviation rationale.
|
||||
- **P4 Forecast Background**: DEB/forecasts for ceiling estimation; silenced when actuals significantly deviate.
|
||||
- **Single Source of Truth**: Both web and Telegram bot share the same `analyze_weather_trend` function and `get_ai_analysis` prompt — identical context, identical decisions.
|
||||
- **High Availability**: Auto-retry + fallback model degradation (70B → 8B). Proxy support for restricted networks.
|
||||
- Docker
|
||||
- Docker Compose
|
||||
- `.env`
|
||||
|
||||
### 5. ⏱️ Real-time Airport Observations (Zero-Cache METAR)
|
||||
|
||||
- **Precise Timing**: Extracts actual observation time from raw METAR text (`rawOb`), not the API's rounded `reportTime`. Accurate to the minute.
|
||||
- **Live Passthrough**: Bypasses CDN caching via dynamic headers and randomized timestamps to obtain first-hand METAR/MGM reports.
|
||||
- **Settlement Warning**: Automatically calculates the rounding boundary for integer-based settlement (X.5 line).
|
||||
- **MGM Primary (Ankara)**: For Turkish cities like Ankara, PolyWeather uses official MGM data as a primary source for both real-time observations and 5-day hourly forecasts, ensuring maximum local accuracy.
|
||||
- **Anomaly Filtering**: Automatically filters out -9999 sentinel values to prevent garbage data in output.
|
||||
|
||||
### 6. 📈 Historical Data Collection
|
||||
|
||||
- Includes `fetch_history.py` to retrieve up to 3 years of hourly historical weather data (temperature, humidity, radiation, pressure, 10+ dimensions), providing data foundation for future ML models (XGBoost/MOS).
|
||||
|
||||
---
|
||||
|
||||
## ⚡ Deployment
|
||||
|
||||
### Requirements
|
||||
|
||||
- **Python 3.11+** or **Docker & Docker Compose**
|
||||
- **Environment Variables**: Set parameters in your `.env` file (copy from `.env.example`).
|
||||
|
||||
### 🐳 Docker Deployment (Recommended)
|
||||
|
||||
The easiest and most stable way to deploy without system dependency conflicts.
|
||||
|
||||
1. **Clone and configure**
|
||||
```bash
|
||||
git clone https://github.com/yangyuan-zhen/PolyWeather.git
|
||||
cd PolyWeather
|
||||
cp .env.example .env
|
||||
# Edit .env to add TELEGRAM_BOT_TOKEN, GROQ_API_KEY, etc.
|
||||
nano .env
|
||||
```
|
||||
2. **Start the service in the background**
|
||||
```bash
|
||||
docker-compose up -d --build
|
||||
```
|
||||
3. **View live logs**
|
||||
```bash
|
||||
docker-compose logs -f
|
||||
```
|
||||
|
||||
### 💻 Traditional VPS Deployment
|
||||
|
||||
1. Install dependencies: `pip install -r requirements.txt`
|
||||
2. Configure your `.env` file.
|
||||
3. Use the included `update.sh` script for one-click updates and restarts for both the Telegram Bot and the Web Map:
|
||||
|
||||
```bash
|
||||
# Run the script to update code and restart both services in the background
|
||||
./update.sh
|
||||
```
|
||||
|
||||
_(Note: The `update.sh` script automatically fetches the latest code, kills old processes, clears ports, and launches both `bot_listener.py` and `web/app.py` via `nohup`.)_
|
||||
|
||||
---
|
||||
|
||||
## 🕹️ Bot Commands
|
||||
|
||||
| Command | Description |
|
||||
| :------------------ | :---------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `/city [city_name]` | Get weather analysis, settlement probabilities, METAR tracking, and AI insights. (Includes "Bölge/Center" detail for Ankara). |
|
||||
| `/deb [city_name]` | View DEB accuracy: daily hit/miss breakdown, bias analysis (underestimate/overestimate), model MAE comparison, trading suggestions. |
|
||||
| `/id` | View the Chat ID of the current conversation. |
|
||||
| `/help` | Display help information. |
|
||||
|
||||
### Supported Cities
|
||||
|
||||
`lon` (London), `par` (Paris), `ank` (Ankara), `nyc` (New York), `chi` (Chicago), `dal` (Dallas), `mia` (Miami), `atl` (Atlanta), `sea` (Seattle), `tor` (Toronto), `sel` (Seoul), `ba` (Buenos Aires), `wel` (Wellington), etc.
|
||||
|
||||
---
|
||||
|
||||
## 🏗️ Architecture
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
User[User] -->|Query| Bot["bot_listener.py (Core Scheduler)"]
|
||||
User -->|Browser| Web["web/app.py (FastAPI)"]
|
||||
|
||||
subgraph Data Acquisition
|
||||
Bot --> Collector[WeatherDataCollector]
|
||||
Web --> Collector
|
||||
Collector --> OM[Open-Meteo Forecast/Ensemble]
|
||||
Collector --> MM[Multi-Model ECMWF/GFS/ICON/GEM/JMA]
|
||||
Collector --> METAR["Live Airport METAR (rawOb)"]
|
||||
Collector --> MGM["MGM Official (Ankara)"]
|
||||
end
|
||||
|
||||
subgraph Algorithm Layer
|
||||
Collector --> Peak[Peak Hour Prediction]
|
||||
Collector --> DEB[DEB Dynamic Weighting]
|
||||
DEB --> DB[(daily_records Database)]
|
||||
Peak --> Prob["Probability Engine (Reality-Anchored μ)"]
|
||||
Collector --> Prob
|
||||
METAR --> Shock[Shock Score]
|
||||
Shock --> Prob
|
||||
Collector --> Logic["Settlement Boundary / Dead Market"]
|
||||
end
|
||||
|
||||
subgraph Shared Analysis
|
||||
Bot --> ATF["analyze_weather_trend()"]
|
||||
Web --> ATF
|
||||
ATF --> AI["Groq LLaMA 70B (P0→P4)"]
|
||||
end
|
||||
|
||||
AI -->|Market Call + Logic + Confidence| Bot
|
||||
AI -->|Market Call + Logic + Confidence| Web
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 💡 Trading Tips
|
||||
|
||||
1. **Real-time Rhythm First**: AI analysis follows P0→P4 priority. If live METAR trends (P1) conflict with math probabilities (P3), always prioritize the live trend.
|
||||
2. **Watch Settlement Probabilities**: Based on Gaussian models, direction is most certain when a temperature has > 70% probability while P1 rhythm is flat.
|
||||
3. **Reference DEB Bias**: Use `/deb` to check for systematic bias. If a city is consistently "underestimated," habitually bid one WU notch higher.
|
||||
4. **Identify Dead Market Signals**: When the system declares a "Dead Market," probability collapses to 100% at the settled value. Warming power is exhausted.
|
||||
5. **Mind the Boundaries**: When the observed high is near X.5 (e.g., 7.50°C), be wary of rounding up due to tiny fluctuations.
|
||||
6. **Forecast Bust Awareness**: When the AI reports a forecast bust (especially medium/heavy grade), all model predictions have lost reference value. Focus exclusively on METAR actuals.
|
||||
|
||||
---
|
||||
|
||||
## 🛠️ Development & Testing
|
||||
|
||||
Run unit tests for the core trend engine and probability models:
|
||||
|
||||
```bash
|
||||
python -m pytest tests/test_trend_engine.py -v
|
||||
```
|
||||
|
||||
Deploying updates to the server:
|
||||
Deploy:
|
||||
|
||||
```bash
|
||||
git pull
|
||||
./update.sh
|
||||
docker-compose up -d --build
|
||||
```
|
||||
|
||||
---
|
||||
Main services:
|
||||
|
||||
_Updated 2026-03-05_
|
||||
- `polyweather_bot`
|
||||
- `polyweather_web`
|
||||
|
||||
The FastAPI service is now API-only. It does not serve a static website.
|
||||
|
||||
### Frontend on Vercel
|
||||
|
||||
The Vercel project uses the `frontend` directory as root.
|
||||
|
||||
After pushing to Git, Vercel deploys automatically.
|
||||
|
||||
## Environment Variables
|
||||
|
||||
Minimum practical set:
|
||||
|
||||
```env
|
||||
TELEGRAM_BOT_TOKEN=...
|
||||
TELEGRAM_CHAT_ID=...
|
||||
GROQ_API_KEY=...
|
||||
POLYWEATHER_MAP_URL=https://polyweather-pro.vercel.app/
|
||||
WEB_CORS_ORIGINS=http://localhost:3000,http://127.0.0.1:3000,https://polyweather-pro.vercel.app
|
||||
```
|
||||
|
||||
Push tuning:
|
||||
|
||||
```env
|
||||
TELEGRAM_ALERT_PUSH_ENABLED=true
|
||||
TELEGRAM_ALERT_PUSH_INTERVAL_SEC=300
|
||||
TELEGRAM_ALERT_PUSH_COOLDOWN_SEC=3600
|
||||
TELEGRAM_ALERT_MIN_TRIGGER_COUNT=2
|
||||
TELEGRAM_ALERT_MIN_SEVERITY=medium
|
||||
TELEGRAM_ALERT_CITIES=ankara,london,paris,seoul,toronto,buenos aires,wellington,new york,chicago,dallas,miami,atlanta,seattle,lucknow,sao paulo,munich
|
||||
```
|
||||
|
||||
Recommended:
|
||||
|
||||
- Use `3600` seconds cooldown for production paid groups unless you explicitly want more aggressive alerting
|
||||
|
||||
## Bot Commands
|
||||
|
||||
Supported user commands:
|
||||
|
||||
- `/city [city]`
|
||||
- `/deb [city]`
|
||||
- `/id`
|
||||
- `/help`
|
||||
|
||||
`/tradealert` has been removed. Alerts are proactive push only.
|
||||
|
||||
## Architecture
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
User[Telegram User] --> Bot[bot_listener.py]
|
||||
User2[Web User] --> Vercel[Next.js on Vercel]
|
||||
Vercel --> API[FastAPI API on VPS]
|
||||
Bot --> API
|
||||
API --> Collector[WeatherDataCollector]
|
||||
Collector --> OM[Open-Meteo]
|
||||
Collector --> METAR[METAR]
|
||||
Collector --> MGM[MGM]
|
||||
Collector --> MM[Multi-model sources]
|
||||
API --> DEB[DEB blending]
|
||||
API --> Alerts[Alert engine]
|
||||
Alerts --> Bot
|
||||
```
|
||||
|
||||
## Testing
|
||||
|
||||
Quick checks used in development:
|
||||
|
||||
```bash
|
||||
python -m py_compile src/analysis/market_alert_engine.py src/utils/telegram_push.py web/app.py bot_listener.py
|
||||
node --check frontend/public/static/app.js
|
||||
npm run build --prefix frontend
|
||||
```
|
||||
|
||||
If you want to run pytest, install it first.
|
||||
|
||||
## Status
|
||||
|
||||
Last updated: 2026-03-06
|
||||
|
||||
+148
-184
@@ -1,10 +1,14 @@
|
||||
# 🌡️ PolyWeather: 智能天气量化分析机器人
|
||||
# PolyWeather
|
||||
|
||||
[](https://www.python.org/downloads/)
|
||||
[](https://opensource.org/licenses/MIT)
|
||||
[](https://deepwiki.com/yangyuan-zhen/PolyWeather)
|
||||
PolyWeather 是一套围绕实时机场观测、多模型预报、DEB 融合和 Telegram 主动推送构建的天气情报系统。
|
||||
|
||||
PolyWeather 是一款多模型气象分析与量化工具。它通过聚合高精度气象预报、实时机场 METAR 观测,并引入数学概率模型与 AI 决策支持,为气象风险评估和数据驱动的交易决策提供深度洞察。
|
||||
当前生产架构:
|
||||
|
||||
- 前端:Vercel 上的 Next.js
|
||||
- 后端 API:VPS 上的 FastAPI
|
||||
- 机器人与预警循环:VPS 上的 Telegram Bot
|
||||
|
||||
FastAPI 旧静态网页已经移除。Vercel 是唯一网页入口。
|
||||
|
||||
<p align="center">
|
||||
<img src="docs/images/demo_ankara.png" alt="PolyWeather 效果展示 - 安卡拉实时分析" width="420">
|
||||
@@ -18,204 +22,164 @@ PolyWeather 是一款多模型气象分析与量化工具。它通过聚合高
|
||||
<em>🗺️ 交互式网页地图:全球城市实时监控与丰富的数据可视化</em>
|
||||
</p>
|
||||
|
||||
---
|
||||
## 当前功能
|
||||
|
||||
## ✨ 核心功能
|
||||
- 多源天气采集
|
||||
- Open-Meteo
|
||||
- METAR 实时观测
|
||||
- 安卡拉官方 MGM 数据
|
||||
- ECMWF / GFS / ICON / GEM / JMA 等多模型最高温
|
||||
- DEB 融合预报
|
||||
- 基于近期误差动态调权
|
||||
- 网页仪表盘
|
||||
- 全球监控城市列表
|
||||
- 城市详情面板
|
||||
- 周边站点地图标记
|
||||
- 今日趋势图
|
||||
- 多模型对比
|
||||
- 多日预报表
|
||||
- Telegram 主动预警
|
||||
- Ankara Center 达到 DEB
|
||||
- 动量突变
|
||||
- 预测突破
|
||||
- 暖平流 / 周边站联动
|
||||
- 晚盘压制逻辑
|
||||
- 当地高温大概率已经兑现且开始回落时,预警降级为状态快照,不主动推送
|
||||
|
||||
### 1. 🌐 交互式网页地图面板
|
||||
## 预警规则
|
||||
|
||||
- **全球纵览**:基于 Leaflet 的暗黑全屏实时地图,直接采用官方结算机场经纬度进行追踪与显示。
|
||||
- **渐进式数据流加载**:进图后智能在后台无感知拉取,不触发 API 频率限制。
|
||||
- **数据可视化**:Chart.js 温度走势图叠加 METAR 实测散点,多模型对比条形图,高斯概率分布条,实时风险等级色彩系统。
|
||||
- **智能缩放过滤**:地图会根据缩放等级自动隐藏次要城市(如亚特兰大、安卡拉)和局部观测点标签,以保持全局视野清晰,仅在放大时显示细节。
|
||||
- **内置技术指南**:新增交互式技术手册面板,详细解释 DEB 预测曲线、概率区间及各类风险因子。
|
||||
- **镜头与日期联动**:点击城市平滑飞入面板。**多模型预报区域**会根据“逐日预报”选中的日期自动刷新,支持查看未来 5 天各模型的历史表现与融合预测值。
|
||||
- **强制同步与缓存控制**:针对安卡拉等重点区域,Web 端支持 60 秒极速缓存 TTL,并提供手动“强制刷新”按钮,可穿透全局缓存获取最及时的 MGM/METAR 实测数据。
|
||||
- **周边测站热力图**:不仅追踪目标机场,还能并发抓取目标城市周边 20~50 公里内的所有气象站实测。通过地图上的“微型标签”可视化城市热岛效应与锋面推进,辅助判断冷空气过境的时间差。
|
||||
- **双引擎共生**:FastAPI 后端与 Telegram Bot 共享同一份分析逻辑(`analyze_weather_trend`)和 AI Prompt 管线。
|
||||
当前启用的规则:
|
||||
|
||||
### 2. 🧬 动态权重集合预报 (DEB 算法)
|
||||
- `ankara_center_deb_hit`
|
||||
- 只使用 `Ankara (Bolge/Center)` 站点,`istNo=17130`
|
||||
- 这是安卡拉 Center 信号唯一认可的官方站点
|
||||
- `momentum_spike`
|
||||
- 30 分钟温度斜率超过阈值
|
||||
- `forecast_breakthrough`
|
||||
- 当前实测温度高于主流模型最高值,并超过安全边际
|
||||
- `advection`
|
||||
- 周边站领先升温,且风向与暖平流传播方向匹配
|
||||
|
||||
系统会自动追踪各个气象模型(ECMWF, GFS, ICON, GEM, JMA)在特定城市的历史表现:
|
||||
压制规则:
|
||||
|
||||
- **误差加权**:根据过去 7 天的平均绝对误差(MAE),动态调整各模型的权重。误差越小的模型,话语权越大。
|
||||
- **融合预报**:给出经过历史偏差修正后的"DEB 融合最高温"建议值。
|
||||
- **多源训练集成**:将区域性官方数据源(如土耳其 MGM)同步纳入 DEB 训练管线,与 ECMWF、GFS 等国际模型共同参与权重博弈。
|
||||
- **准确率追踪**:通过 `/deb` 命令查看 DEB 融合预测的历史结算命中率和 MAE,并与各个单一模型对比。
|
||||
- **自动清理**:只保留最近 14 天的记录,防止数据无限增长。
|
||||
- `peak_passed_guard`
|
||||
- 当地高点已经过去、间隔足够长、且温度已从日内高点明显回落时,不再主动推送
|
||||
|
||||
### 3. 🎲 数学概率引擎 (Settlement Probability)
|
||||
去重规则:
|
||||
|
||||
基于集合预报的正态分布拟合,自动计算每个结算整数温度的概率:
|
||||
- 同一城市、同一 trigger type,只会在激活时推送一次
|
||||
- 只有信号先解除,再重新触发,才允许再次推送
|
||||
- 同时仍保留城市级 cooldown
|
||||
|
||||
- **实况锚定 μ**:当实测最高温在峰值窗口期间/之后显著低于预报中位数(预报崩盘),μ 直接锚定在实测值上,而非失败的预报。正常情况下使用 DEB/多模型中位数(70%)和集合中位数(30%)的加权平均。
|
||||
- **标准差 σ 三层修正管线**:
|
||||
1. **集合基础**:σ = (P90-P10) / 2.56
|
||||
2. **MAE 兜底**:用 DEB 历史 MAE 作为 σ 下限——防止集合预报低估真实不确定性
|
||||
3. **Shock Score 放宽**:σ × (1 + 0.5 × shock_score),气象突变时自动加宽
|
||||
- **时间衰减**:峰值前 σ×1.0 → 峰值窗口 σ×0.7 → 峰值后 σ×0.3
|
||||
- **实测过滤**:已实测 WU 值以下的候选自动排除
|
||||
- **死盘覆盖**:确认死盘后,概率直接坍缩为结算值 100%
|
||||
## 数据语义
|
||||
|
||||
#### 💥 Shock Score:气象突变软评分 (0~1)
|
||||
预警文案中的字段:
|
||||
|
||||
用近 4 条 METAR 报文的风向/云量/气压变化评估环境稳定性,越高 = 越不稳定 = σ 放宽:
|
||||
- `实测`
|
||||
- 优先使用 `METAR current.temp`
|
||||
- 如果 METAR 当前温度不可用,再退回 `MGM current.temp`
|
||||
- `时间`
|
||||
- `当地`:城市本地当前时间
|
||||
- `观测`:这条实测温度对应的观测时间
|
||||
|
||||
| 分项 | 权重 | 触发条件 |
|
||||
| :------- | :----- | :------------------------------------ |
|
||||
| 风向变化 | 0~0.4 | 角度差 × 风速放大系数(弱风降权避噪) |
|
||||
| 云量阶跃 | 0~0.35 | FEW→BKN 等云码跳变 |
|
||||
| 气压变化 | 0~0.25 | 2h 内气压差 > 2hPa |
|
||||
## 部署
|
||||
|
||||
### 4. 🤖 AI 深度分析 (Groq LLaMA 3.3 70B)
|
||||
### VPS 后端 / 机器人
|
||||
|
||||
将全部气象数据投喂给 LLaMA 70B,按 **P0→P4 分析框架** 决策:
|
||||
要求:
|
||||
|
||||
- **P0 预报失准检测**(最高优先级):分级失准(轻/中/重),根据偏差幅度自动标记。"失准 ≠ 已定局"——还需检查斜率 + 风云条件。支持二次抬升判断。
|
||||
- **P1 实况节奏**:连续 2 报创新高 → 升温未止;连续 2 报未创新高且斜率 ≤ 0 → 偏死盘。低辐射升温 → 可能多因子叠加(平流/混合层/热岛),不做单因子归因。
|
||||
- **P2 阻碍因子**(需结合城市特性判断):降水 → 强压温。高湿度 + 厚云层持续 2 报以上 → 可能压温,但阈值因城市类型(海洋 vs 大陆)而异。单因子不足以断定。
|
||||
- **P3 概率与一致性校验**:参考结算概率分布,与 P1 实况做交叉检查。矛盾时以实况为准并说明偏离原因。
|
||||
- **P4 预报背景**(最低优先级):可参考 DEB/预报做上沿评估。实测显著偏离时禁止引用。
|
||||
- **统一分析源**:Web 和 Telegram Bot 共用同一个 `analyze_weather_trend` 函数和 `get_ai_analysis` 提示词——完全相同的上下文,完全相同的决策。
|
||||
- **高可用保障**:自动重试 + 备用模型降级(70B → 8B)。支持代理配置。
|
||||
- Docker
|
||||
- Docker Compose
|
||||
- `.env`
|
||||
|
||||
### 5. ⏱️ 实时机场观测 (Zero-Cache METAR)
|
||||
|
||||
- **精确时间**:从 METAR 原始报文 (`rawOb`) 中提取真实观测时间,精确到分钟。
|
||||
- **实时穿透**:通过动态请求头和随机时间戳绕过 CDN 缓存,获取机场第一手 METAR/MGM 报文。
|
||||
- **结算预警**:自动计算结算边界(X.5 进位线),提醒潜在波动。
|
||||
- **MGM 官方直连 (安卡拉)**:针对安卡拉,PolyWeather 已将 MGM 提升为一级数据源,同步采集实时观测数据与 5 天逐小时预报,确保本地精度最大化。
|
||||
- **异常过滤**:自动过滤 -9999 等哨兵值,避免垃圾数据污染输出。
|
||||
|
||||
### 6. 📈 历史数据采集
|
||||
|
||||
- 提供 `fetch_history.py` 脚本,可一键获取各城市过去 3 年的小时级历史气象数据(温度、湿度、辐射、气压等 10+ 维度),为后续机器学习模型(XGBoost/MOS)提供数据基础。
|
||||
|
||||
---
|
||||
|
||||
## ⚡ 部署说明
|
||||
|
||||
### 环境要求
|
||||
|
||||
- **Python 3.11+** 或 **Docker & Docker Compose**
|
||||
- **环境变量**: 在 `.env` 中设置关键参数(参考 `.env.example`)。
|
||||
|
||||
### 🐳 Docker 部署 (推荐)
|
||||
|
||||
最简单、稳定的部署方式,避免系统依赖冲突。
|
||||
|
||||
1. **克隆项目并配置环境**
|
||||
```bash
|
||||
git clone https://github.com/yangyuan-zhen/PolyWeather.git
|
||||
cd PolyWeather
|
||||
cp .env.example .env
|
||||
# 编辑 .env 文件填入 TELEGRAM_BOT_TOKEN 和 GROQ_API_KEY 等
|
||||
nano .env
|
||||
```
|
||||
2. **后台一键启动服务**
|
||||
```bash
|
||||
docker-compose up -d --build
|
||||
```
|
||||
3. **查看实时日志**
|
||||
```bash
|
||||
docker-compose logs -f
|
||||
```
|
||||
|
||||
### 💻 传统 VPS 部署方案
|
||||
|
||||
1. 安装依赖: `pip install -r requirements.txt`
|
||||
2. 配置 `.env` 文件。
|
||||
3. 利用项目中已包含的 `update.sh` 实现机器人和网站的双轨后台一键重启:
|
||||
|
||||
```bash
|
||||
# 每次代码变更后,只需在 VPS 执行此命令
|
||||
./update.sh
|
||||
```
|
||||
|
||||
_(该脚本将自动执行 git 抓取、杀僵尸进程、解绑端口、并分别利用 nohup 重新唤醒 bot_listener.py 和 FastAPI app.py 服务。)_
|
||||
|
||||
---
|
||||
|
||||
## 🕹️ 机器人指令
|
||||
|
||||
| 指令 | 说明 |
|
||||
| :--------------- | :--------------------------------------------------------------------------------------- |
|
||||
| `/city [城市名]` | 获取深度气象分析、结算概率、实测追踪及 AI 决策建议。(安卡拉支持显示市区 Center 细节)。 |
|
||||
| `/deb [城市名]` | 查看 DEB 准确率:逐日命中明细、偏差分析(低估/高估)、模型 MAE 对比、交易建议。 |
|
||||
| `/id` | 查看当前对话的 Chat ID。 |
|
||||
| `/help` | 显示说明信息。 |
|
||||
|
||||
### 支持城市示例
|
||||
|
||||
`lon`(伦敦)、`par`(巴黎)、`ank`(安卡拉)、`nyc`(纽约)、`chi`(芝加哥)、`dal`(达拉斯)、`mia`(迈阿密)、`atl`(亚特兰大)、`sea`(西雅图)、`tor`(多伦多)、`sel`(首尔)、`ba`(布宜诺斯艾利斯)、`wel`(惠灵顿) 等。
|
||||
|
||||
---
|
||||
|
||||
## 🏗️ 系统架构
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
User[用户] -->|查询指令| Bot["bot_listener.py (核心调度器)"]
|
||||
User -->|浏览器| Web["web/app.py (FastAPI)"]
|
||||
|
||||
subgraph 数据获取层
|
||||
Bot --> Collector[WeatherDataCollector]
|
||||
Web --> Collector
|
||||
Collector --> OM[Open-Meteo 预报/集合]
|
||||
Collector --> MM[多模型 ECMWF/GFS/ICON/GEM/JMA]
|
||||
Collector --> METAR["机场实时 METAR (rawOb)"]
|
||||
Collector --> MGM["MGM 官方直连 (安卡拉)"]
|
||||
end
|
||||
|
||||
subgraph 算法层
|
||||
Collector --> Peak[峰值时段预测]
|
||||
Collector --> DEB[DEB 动态权重融合]
|
||||
DEB --> DB[(每日记录数据库)]
|
||||
Peak --> Prob["概率引擎 (实况锚定μ)"]
|
||||
Collector --> Prob
|
||||
METAR --> Shock[Shock Score 突变评分]
|
||||
Shock --> Prob
|
||||
Collector --> Logic["结算边界 / 死盘检测"]
|
||||
end
|
||||
|
||||
subgraph 共享分析层
|
||||
Bot --> ATF["analyze_weather_trend()"]
|
||||
Web --> ATF
|
||||
ATF --> AI["Groq LLaMA 70B (P0→P4)"]
|
||||
end
|
||||
|
||||
AI -->|盘口 + 逻辑 + 置信度| Bot
|
||||
AI -->|盘口 + 逻辑 + 置信度| Web
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 💡 交易提示
|
||||
|
||||
1. **实况节奏优先**:AI 分析遵循 P0→P4 优先级。如果实况趋势(P1)与数学概率(P3)冲突,以实况走势为准。
|
||||
2. **紧盯结算概率**:概率引擎基于数学模型,当某个温度概率 > 70% 且 P1 节奏持平时,方向最为明确。
|
||||
3. **参考 DEB 偏差**:通过 `/deb` 查看城市的系统性偏差。如果某个城市经常"低估",交易时应看高 1 个 WU 档位。
|
||||
4. **识别死盘信号**:系统判定"死盘"时,概率会直接坍缩为结算值 100%。升温动力彻底枯竭。
|
||||
5. **注意结算边界**:实测最高温接近 X.5 时,微小波动可能导致进位,需防范"偷鸡"。
|
||||
6. **预报崩盘意识**:当 AI 标记预报失准(尤其中/重级),所有模型预测已失去参考价值,需专注 METAR 实测。
|
||||
|
||||
---
|
||||
|
||||
## 🛠️ 开发与测试
|
||||
|
||||
运行核心分析引擎和概率模型的单元测试:
|
||||
|
||||
```bash
|
||||
python -m pytest tests/test_trend_engine.py -v
|
||||
```
|
||||
|
||||
部署代码更新到服务器:
|
||||
部署命令:
|
||||
|
||||
```bash
|
||||
git pull
|
||||
./update.sh
|
||||
docker-compose up -d --build
|
||||
```
|
||||
|
||||
---
|
||||
主要服务:
|
||||
|
||||
_更新于 2026-03-05_
|
||||
- `polyweather_bot`
|
||||
- `polyweather_web`
|
||||
|
||||
现在的 FastAPI 只提供 API,不再承载网页静态资源。
|
||||
|
||||
### Vercel 前端
|
||||
|
||||
Vercel 项目根目录使用 `frontend`。
|
||||
|
||||
代码推送后,Vercel 会自动部署。
|
||||
|
||||
## 环境变量
|
||||
|
||||
最小可用集合:
|
||||
|
||||
```env
|
||||
TELEGRAM_BOT_TOKEN=...
|
||||
TELEGRAM_CHAT_ID=...
|
||||
GROQ_API_KEY=...
|
||||
POLYWEATHER_MAP_URL=https://polyweather-pro.vercel.app/
|
||||
WEB_CORS_ORIGINS=http://localhost:3000,http://127.0.0.1:3000,https://polyweather-pro.vercel.app
|
||||
```
|
||||
|
||||
预警推送调优:
|
||||
|
||||
```env
|
||||
TELEGRAM_ALERT_PUSH_ENABLED=true
|
||||
TELEGRAM_ALERT_PUSH_INTERVAL_SEC=300
|
||||
TELEGRAM_ALERT_PUSH_COOLDOWN_SEC=3600
|
||||
TELEGRAM_ALERT_MIN_TRIGGER_COUNT=2
|
||||
TELEGRAM_ALERT_MIN_SEVERITY=medium
|
||||
TELEGRAM_ALERT_CITIES=ankara,london,paris,seoul,toronto,buenos aires,wellington,new york,chicago,dallas,miami,atlanta,seattle,lucknow,sao paulo,munich
|
||||
```
|
||||
|
||||
生产环境建议:
|
||||
|
||||
- 付费群默认使用 `3600` 秒 cooldown,避免同一城市短时间内刷屏
|
||||
|
||||
## 机器人命令
|
||||
|
||||
当前保留的命令:
|
||||
|
||||
- `/city [city]`
|
||||
- `/deb [city]`
|
||||
- `/id`
|
||||
- `/help`
|
||||
|
||||
`/tradealert` 已移除。预警只支持主动推送。
|
||||
|
||||
## 架构
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
User[Telegram 用户] --> Bot[bot_listener.py]
|
||||
User2[网页用户] --> Vercel[Next.js on Vercel]
|
||||
Vercel --> API[FastAPI API on VPS]
|
||||
Bot --> API
|
||||
API --> Collector[WeatherDataCollector]
|
||||
Collector --> OM[Open-Meteo]
|
||||
Collector --> METAR[METAR]
|
||||
Collector --> MGM[MGM]
|
||||
Collector --> MM[多模型数据源]
|
||||
API --> DEB[DEB 融合]
|
||||
API --> Alerts[预警引擎]
|
||||
Alerts --> Bot
|
||||
```
|
||||
|
||||
## 测试
|
||||
|
||||
开发时常用快速检查:
|
||||
|
||||
```bash
|
||||
python -m py_compile src/analysis/market_alert_engine.py src/utils/telegram_push.py web/app.py bot_listener.py
|
||||
node --check frontend/public/static/app.js
|
||||
npm run build --prefix frontend
|
||||
```
|
||||
|
||||
如果要跑 pytest,请先安装 pytest。
|
||||
|
||||
## 状态
|
||||
|
||||
最后更新:2026-03-06
|
||||
|
||||
+41
-1
@@ -14,6 +14,7 @@ from src.utils.telegram_push import start_trade_alert_push_loop # type: ignore
|
||||
from src.data_collection.weather_sources import WeatherDataCollector # type: ignore # noqa: E402
|
||||
from src.data_collection.city_risk_profiles import get_city_risk_profile # type: ignore # noqa: E402
|
||||
from src.analysis.deb_algorithm import calculate_dynamic_weights, update_daily_record # noqa: E402
|
||||
from src.database.db_manager import DBManager
|
||||
|
||||
|
||||
def analyze_weather_trend(weather_data, temp_symbol, city_name=None):
|
||||
@@ -31,6 +32,7 @@ def start_bot():
|
||||
return
|
||||
|
||||
bot = telebot.TeleBot(token)
|
||||
db = DBManager()
|
||||
weather = WeatherDataCollector(config)
|
||||
start_trade_alert_push_loop(bot, config)
|
||||
|
||||
@@ -41,8 +43,10 @@ def start_bot():
|
||||
"可用指令:\n"
|
||||
"/city [城市名] - 查询城市天气预测与实测\n"
|
||||
"/deb [城市名] - 查看 DEB 融合预测准确率\n"
|
||||
"/points - 查看你的积分与排行榜\n"
|
||||
"/id - 获取当前聊天的 Chat ID\n\n"
|
||||
"示例: <code>/city 伦敦</code>"
|
||||
"示例: <code>/city 伦敦</code>\n"
|
||||
"💡 <i>提示: 在群内发言可获得积分,积分可用于后续解锁高级版。</i>"
|
||||
)
|
||||
bot.reply_to(message, welcome_text, parse_mode="HTML")
|
||||
|
||||
@@ -54,6 +58,29 @@ def start_bot():
|
||||
parse_mode="HTML",
|
||||
)
|
||||
|
||||
@bot.message_handler(commands=["points", "rank", "top"])
|
||||
def show_points(message):
|
||||
"""显示当前用户的积分及排行榜"""
|
||||
user = message.from_user
|
||||
user_info = db.get_user(user.id)
|
||||
|
||||
leaderboard = db.get_leaderboard(limit=5)
|
||||
rank_text = "🏆 <b>PolyWeather 活跃度排行榜</b>\n"
|
||||
rank_text += "────────────────────\n"
|
||||
for i, entry in enumerate(leaderboard):
|
||||
medal = ["🥇", "🥈", "🥉", " ", " "][i] if i < 5 else " "
|
||||
rank_text += f"{medal} {entry['username'][:12]}: <b>{entry['points']}</b> 点\n"
|
||||
|
||||
if user_info:
|
||||
rank_text += "────────────────────\n"
|
||||
rank_text += (
|
||||
f"👤 <b>我的状态:</b>\n"
|
||||
f"└ 积分: <code>{user_info['points']}</code>\n"
|
||||
f"└ 发言: <code>{user_info['message_count']}</code> 次"
|
||||
)
|
||||
|
||||
bot.send_message(message.chat.id, rank_text, parse_mode="HTML")
|
||||
|
||||
@bot.message_handler(commands=["deb"])
|
||||
def deb_accuracy(message):
|
||||
"""查询 DEB 融合预测的历史准确率"""
|
||||
@@ -705,6 +732,19 @@ def start_bot():
|
||||
logger.error(f"查询失败: {e}\n{traceback.format_exc()}")
|
||||
bot.reply_to(message, f"❌ 查询失败: {e}")
|
||||
|
||||
@bot.message_handler(func=lambda message: True, content_types=['text'])
|
||||
def track_activity(message):
|
||||
"""全量监听消息,用于记录群内发言积分(非指令消息)"""
|
||||
if message.text.startswith('/'):
|
||||
return
|
||||
|
||||
user = message.from_user
|
||||
username = user.username or user.first_name or f"User_{user.id}"
|
||||
db.upsert_user(user.id, username)
|
||||
|
||||
# 增加积分 (5秒冷却防刷屏,每个自然发言给 1 分)
|
||||
db.add_message_activity(user.id, points_to_add=1)
|
||||
|
||||
logger.info("🤖 Bot 启动中...")
|
||||
bot.infinity_polling()
|
||||
|
||||
|
||||
+128
-22
@@ -1,35 +1,141 @@
|
||||
# PolyWeather 商业化技术升级草案
|
||||
# Commercialization Plan
|
||||
|
||||
## 1. 核心目标
|
||||
## Product Direction
|
||||
|
||||
将 PolyWeather 从单人工具转型为支持多用户的 SaaS 产品。
|
||||
PolyWeather is being positioned as a paid weather intelligence product built around:
|
||||
- Web dashboard subscription
|
||||
- Telegram paid group subscription
|
||||
- Fast, rules-based weather alerting
|
||||
- High-confidence Ankara specialization
|
||||
|
||||
## 2. 架构调整 (Architecture Upgrade)
|
||||
Current pricing target:
|
||||
- Web dashboard: $5 / month
|
||||
- Telegram paid group: $1 / month
|
||||
|
||||
### 2.1 用户与订阅系统 (Auth & Sub)
|
||||
Current payment direction under discussion:
|
||||
- Polygon / USDC
|
||||
|
||||
- **前端**: 增加 Login 模态框,支持 Telegram 一键登录。
|
||||
- **后端 (FastAPI)**: 增加用户数据库 (`users` 表),存储 `telegram_id`, `subscription_status`, `expiry_date`。
|
||||
- **权限中间件**: 拦截未经授权的实时 API 请求。
|
||||
Important current state:
|
||||
- Polymarket market-price integration has been removed from the codebase
|
||||
- The current product focuses on weather intelligence, not exchange/orderbook execution data
|
||||
|
||||
### 2.2 网页功能增强 (Web Premium)
|
||||
## Production Architecture
|
||||
|
||||
- **实时性**: 付费用户 30s 刷新一次,免费用户 15min 刷新。
|
||||
- **专业视图**: 增加各模型历史 MAE (平均绝对误差) 实时排行榜,让用户知道安卡拉今天该信 MGM 还是 GFS。
|
||||
- **推送配置**: 允许用户在网页端订阅特定城市的“突破预警”。
|
||||
### Web
|
||||
- Next.js frontend on Vercel
|
||||
- Public URL: `https://polyweather-pro.vercel.app/`
|
||||
- FastAPI backend serves API only
|
||||
|
||||
### 2.3 电报机器人深度集成 (Bot Monitization)
|
||||
### Backend
|
||||
- FastAPI on VPS
|
||||
- Shared analysis layer for web and bot
|
||||
- City data cache in-process
|
||||
|
||||
- **邀请管理**: 自动生成独一无二的支付链接或入群链接。
|
||||
- **私人简报**: 每小时向 $1 订阅用户私聊发送其关注城市的“结算风险报告”。
|
||||
### Telegram
|
||||
- Bot runs on VPS
|
||||
- Paid group receives proactive alerts
|
||||
- Push engine includes dedupe, cooldown, and late-day suppression
|
||||
|
||||
## 3. 支付方案 (Payment Integration)
|
||||
## Alert Product Strategy
|
||||
|
||||
- **Polygon (USDC)**: 完美契合 Polymarket 生态。
|
||||
- **逻辑**: 用户转账 -> Webhook 回调 -> 自动激活账户权限。
|
||||
Current alert strategy is weather-first:
|
||||
- Ankara Center reached DEB
|
||||
- Momentum spike
|
||||
- Forecast breakthrough
|
||||
- Advection / nearby lead station
|
||||
|
||||
## 4. 商业化阶段
|
||||
Operational controls already implemented:
|
||||
- Same city + same trigger type only pushes once while active
|
||||
- City-level cooldown
|
||||
- Peak-passed suppression for late-day rollover
|
||||
|
||||
- **Phase 1 (Beta)**: 邀请制内测,验证安卡拉等重点城市的数据准确性。
|
||||
- **Phase 2 (MVP)**: 上线手动支付激活模式(人工进群)。
|
||||
- **Phase 3 (Full)**: 全自动 Web3 登录 + USDC 支付 + 自动入群。
|
||||
Ankara special handling:
|
||||
- Center signal only uses `Ankara (Bolge/Center)` / `17130`
|
||||
- This should remain a product differentiator and be documented clearly in sales copy
|
||||
|
||||
## Recommended Subscription Structure
|
||||
|
||||
### Tier A: Telegram Group
|
||||
- Price: $1 / month
|
||||
- Value proposition:
|
||||
- Real-time proactive weather alerts
|
||||
- Fast anomaly delivery
|
||||
- Focused operational signal, minimal clutter
|
||||
- Suggested restrictions:
|
||||
- No raw API access
|
||||
- No historical analytics export
|
||||
- No advanced chart controls
|
||||
|
||||
### Tier B: Web Dashboard
|
||||
- Price: $5 / month
|
||||
- Value proposition:
|
||||
- Full city dashboard
|
||||
- Trend and nearby-station visualization
|
||||
- Multi-model comparison
|
||||
- Historical view
|
||||
- Suggested restrictions:
|
||||
- View-only unless future premium tools are added
|
||||
|
||||
### Bundle Option
|
||||
- Optional future bundle: Web + Group
|
||||
- Use only if conversion data shows users want both together
|
||||
|
||||
## Payment Roadmap
|
||||
|
||||
### Phase 1: Manual Ops
|
||||
- User pays manually
|
||||
- Operator manually activates web access / Telegram access
|
||||
- Lowest engineering cost, fastest launch
|
||||
|
||||
### Phase 2: Polygon / USDC Automation
|
||||
- Generate unique deposit address or payment intent
|
||||
- Confirm on-chain payment
|
||||
- Activate subscription automatically
|
||||
- Telegram bot issues one-time group invite link
|
||||
|
||||
### Phase 3: Full Subscription Management
|
||||
- Renewal reminders
|
||||
- Grace period handling
|
||||
- Automatic expiry / revocation
|
||||
- Self-serve billing status page
|
||||
|
||||
## Recommended Near-Term Roadmap
|
||||
|
||||
### Step 1: Stabilize Current Product
|
||||
- Finish cleaning docs and deployment flow
|
||||
- Keep Vercel as the only web entry point
|
||||
- Keep backend API-only
|
||||
- Tune Telegram cooldown and trigger quality
|
||||
|
||||
### Step 2: Launch Manual Paid Beta
|
||||
- Start with a small paid Telegram group
|
||||
- Start web dashboard on invite basis
|
||||
- Track which alert types users actually value
|
||||
|
||||
### Step 3: Add Access Control
|
||||
- Web login and session layer
|
||||
- Subscription table in backend
|
||||
- Telegram membership verification
|
||||
|
||||
### Step 4: Add Polygon / USDC Collection
|
||||
- Payment detection
|
||||
- Subscription activation
|
||||
- One-time Telegram invite issuance
|
||||
|
||||
## Metrics To Track
|
||||
|
||||
Minimum metrics before scaling:
|
||||
- Alert-to-action usefulness feedback
|
||||
- Daily active dashboard users
|
||||
- Telegram retention after first payment cycle
|
||||
- Most valuable cities by engagement
|
||||
- False-positive complaint rate for alerts
|
||||
|
||||
## Constraints To Keep In Mind
|
||||
|
||||
- The current system is strongest in weather intelligence, not execution plumbing
|
||||
- Ankara is a differentiated niche and should be treated as premium signal inventory
|
||||
- Over-pushing alerts will destroy paid-group value faster than under-pushing
|
||||
- Payment automation should come after alert quality is operationally stable
|
||||
|
||||
Last updated: 2026-03-06
|
||||
|
||||
+82
-83
@@ -1,116 +1,115 @@
|
||||
# PolyWeather 技术债与演进路线
|
||||
# Technical Debt
|
||||
|
||||
> 最后更新:2026-03-05
|
||||
Last updated: 2026-03-06
|
||||
|
||||
---
|
||||
## Current State
|
||||
|
||||
## 一、当前完成度:约 65%
|
||||
Overall system status: usable and deployable.
|
||||
|
||||
### ✅ 已经可用
|
||||
Stable pieces:
|
||||
- Multi-source weather collection
|
||||
- DEB forecast blending
|
||||
- Web dashboard on Vercel
|
||||
- FastAPI API backend
|
||||
- Telegram proactive push loop
|
||||
- Alert dedupe and cooldown
|
||||
- Late-day peak suppression
|
||||
|
||||
| 模块 | 状态 | 说明 |
|
||||
| ---------------- | ------------ | -------------------------------------------------------------- |
|
||||
| 多源数据采集 | **可用** | Open-Meteo / ECMWF / GFS / ICON / GEM / JMA / METAR / MGM |
|
||||
| DEB 动态融合预报 | **可用** | 误差加权 + 自学习 + 冷启动处理 |
|
||||
| 概率引擎 | **基本可用** | Gaussian 拟合 + Shock Score + 时间衰减 + 实况锚定 μ + 死盘覆盖 |
|
||||
| AI 决策 | **基本可用** | P0→P4 分级框架 + 预报失准分级 + 高可用降级 |
|
||||
| Telegram Bot | **稳定运行** | 当前最成熟的交互端 |
|
||||
| Web 仪表盘 | **基本可用** | 全功能地图 + 面板 + 图表,支持 5rd/多模型联动与强制刷新 |
|
||||
| 部署 | **可用** | Docker + 传统 VPS 双通道,`update.sh` 一键部署 |
|
||||
Recently removed:
|
||||
- Old FastAPI static web page
|
||||
- Polymarket market-price integration
|
||||
- `/tradealert` preview command
|
||||
|
||||
### ⚠️ 真实能力边界
|
||||
## High-Priority Debt
|
||||
|
||||
1. **概率引擎的 μ 是手工规则(非统计学习的)**。70/30 加权 + 实况锚定的逻辑在多数情况下"看起来合理",但没有经过回测校准,在极端天气下的准确性无统计保障。
|
||||
2. **AI 决策是"结构化的猜测"**。Prompt 再精巧,底层仍是 LLM 概率续写。AI 有时自相矛盾,置信度是自评的,不代表真实概率。
|
||||
3. **Shock Score 是启发式指标**。风向/云量/气压权重(0.4/0.35/0.25)未经回归验证。
|
||||
4. **DEB 自学习窗口只有 7 天**,无法捕捉季节性趋势。
|
||||
5. **Web 端图表已对齐实测**。利用 MGM 逐小时预报和实测数据,安卡拉等重点城市的日内曲线已实现预报与实况的实时拟合叠加。
|
||||
### 1. Bot orchestration is still too centralized
|
||||
`bot_listener.py` is operational, but too much runtime behavior is still coordinated from a single entrypoint.
|
||||
|
||||
---
|
||||
Impact:
|
||||
- Harder to test
|
||||
- Harder to evolve subscription logic
|
||||
- Harder to isolate push bugs
|
||||
|
||||
## 二、技术债
|
||||
Suggested direction:
|
||||
- Keep moving push and analysis concerns into `src/utils` and `src/analysis`
|
||||
|
||||
### 🔴 高优先级 (✅ 本期已全部清理)
|
||||
### 2. Alert transparency needs better operator visibility
|
||||
The system now pushes the correct trigger types more conservatively, but group operators still need better evidence lines.
|
||||
|
||||
| 问题 | 影响 | 状态 |
|
||||
| -------------------------- | ------------------------------------------------------------------------ | --------------------------------------------------------------------------- |
|
||||
| `bot_listener.py` 过于臃肿 | 单文件 1200 行,混杂数据处理、概率计算、趋势分析、AI 调用。可维护性极差 | ✅ **已拆分**:提取近 500 行核心逻辑至 `src/analysis/trend_engine.py` |
|
||||
| Web 与 Bot 概率引擎重复 | 两端各有独立的概率计算代码。AI 上下文已统一,但概率分布仍各算各的 | ✅ **已统一**:Web 端已完全删除自己的引擎,直接复用 `trend_engine` 输出结果 |
|
||||
| 无测试覆盖 | 概率引擎、DEB 算法、趋势分析等核心逻辑没有单元测试,任何改动只能人肉验证 | ✅ **已覆盖**:建立 `pytest` 机制,编写 15 个用例完全覆盖核心引擎逻辑 |
|
||||
Impact:
|
||||
- Hard to audit why a message fired
|
||||
- Hard to distinguish strong vs weak advection calls
|
||||
|
||||
### 🟡 中优先级
|
||||
Suggested direction:
|
||||
- Add a compact `依据 / Evidence` line to alert messages
|
||||
- Expose raw trigger metrics in a debug API or operator log
|
||||
|
||||
| 问题 | 影响 | 建议 |
|
||||
| ------------------ | --------------------------------------------------------------------------- | -------------------------------------------------------------------------------- |
|
||||
| 无回测框架 | 无法用历史数据验证算法改动是否真的提升了准确率,改代码全凭直觉 | 用 `fetch_history.py` 的数据搭回测管线 |
|
||||
| 硬编码阈值散落各处 | 死盘 (3°C/1.5°C)、forecast bust (2°C)、Shock Score 权重等直接写在业务代码里 | 提取到配置文件或 `constants.py` |
|
||||
| MGM 数据源不稳定 | 经常 403,数据频率受限 | ✅ **已解决**:采用自定义 Header + 随机时间戳 + 5级 API 遍历抓取,稳定性大幅提升 |
|
||||
### 3. No persistent application store for subscriptions
|
||||
Current architecture is ready for commercialization planning, but there is no real subscription state model yet.
|
||||
|
||||
### 🟢 低优先级
|
||||
Impact:
|
||||
- No paid access enforcement
|
||||
- No renewal logic
|
||||
- No expiry / access revocation
|
||||
|
||||
| 问题 | 影响 | 建议 |
|
||||
| ----------------- | --------------------------------------------------- | -------------------------- |
|
||||
| 缓存策略粗糙 | Web 端用简单 dict + 过期时间,无 LRU 或容量限制 | 引入 `cachetools` 或 Redis |
|
||||
| 日志没有结构化 | loguru 直接 print,上线后难做分析和报警 | 改用 JSON 格式 + 集中收集 |
|
||||
| CI badge 链接失效 | 已移除 GitHub Actions 但 README 之前还留着 CI badge | 已在本次文档更新中修复 |
|
||||
Suggested direction:
|
||||
- Add a database-backed subscription table before automating billing
|
||||
|
||||
---
|
||||
## Medium-Priority Debt
|
||||
|
||||
## 三、未完成功能
|
||||
### 4. Backtesting is still missing
|
||||
The system has live rules, but no proper replay framework for validating whether rule changes improve quality.
|
||||
|
||||
| # | 功能 | 说明 |
|
||||
| --- | ------------------- | ---------------------------------------------------------------- |
|
||||
| 1 | 历史数据消费 | `fetch_history.py` 可采集 3 年数据,但没有任何模型在使用 |
|
||||
| 2 | 结算自动对账 | 系统已支持通过 `/deb` 查看命中率,但尚未实现自动生成昨日总结推送 |
|
||||
| 3 | 交易信号输出 | 系统只给分析建议,不输出可执行的交易信号 |
|
||||
| 4 | Web 身份认证 | 任何人都可以访问 Web 面板 |
|
||||
| 5 | 主动推送 | 预报崩盘或结算边界预警时不会主动通知用户 |
|
||||
| 6 | 完整日内 METAR 走势 | `trend.recent` 只保留最近 4 条,无法展示完整日内观测曲线 |
|
||||
Impact:
|
||||
- Rule changes are hard to evaluate objectively
|
||||
- Alert tuning is still partly manual
|
||||
|
||||
---
|
||||
Suggested direction:
|
||||
- Build a replay harness from stored observations and forecasts
|
||||
|
||||
## 四、演进路线
|
||||
### 5. Thresholds remain code-defined
|
||||
Important thresholds are still embedded in Python.
|
||||
|
||||
### 短期(1-2 周)— 偿还核心债务
|
||||
Examples:
|
||||
- Momentum slope threshold
|
||||
- Peak-passed rollback threshold
|
||||
- Advection lead delta threshold
|
||||
- Cooldown defaults
|
||||
|
||||
1. **拆分 `bot_listener.py`**
|
||||
- 将 `analyze_weather_trend` 移到 `src/analysis/trend_engine.py`
|
||||
- 将概率引擎移到 `src/analysis/probability.py`
|
||||
- `bot_listener.py` 只保留 Telegram 交互逻辑
|
||||
Suggested direction:
|
||||
- Extract to constants or structured config
|
||||
|
||||
2. **概率引擎统一**
|
||||
- Web 端概率计算应直接调用共享模块的结果
|
||||
- 消除两份独立实现
|
||||
### 6. Frontend still uses a legacy shell inside Next
|
||||
The production frontend is on Vercel, but the page is still driven by `public/legacy/index.html` plus static scripts.
|
||||
|
||||
3. **核心单元测试**
|
||||
- 测试范围:μ/σ 计算、死盘判定、forecast bust 检测、DEB 权重计算
|
||||
- 不追求覆盖率,追求"改代码时有安全网"
|
||||
Impact:
|
||||
- Slower UI evolution
|
||||
- Harder component-level reuse
|
||||
- Harder design-system integration
|
||||
|
||||
### 中期(1-2 月)— 建立校验能力
|
||||
Suggested direction:
|
||||
- Migrate the legacy dashboard into native Next components incrementally
|
||||
|
||||
4. **回测框架**
|
||||
- 用历史数据跑"过去 90 天每天的 μ 偏差是多少"
|
||||
- 这是证明概率引擎有效的唯一方式
|
||||
## Low-Priority Debt
|
||||
|
||||
5. **结算自动对账**
|
||||
- 每天自动拉取合约实际结算结果
|
||||
- 与系统前一天的预测做比对,自动生成准确率报告
|
||||
### 7. Caching is simple in-process cache only
|
||||
Current cache is sufficient for the current deployment size, but not ideal long term.
|
||||
|
||||
6. **推送机制**
|
||||
- 检测到 forecast bust 或结算边界预警时主动推送 Telegram 通知
|
||||
Suggested direction:
|
||||
- Move to Redis or another shared cache if multi-instance deployment is needed
|
||||
|
||||
### 长期(3+ 月)— 从规则到模型
|
||||
### 8. Test tooling is not fully provisioned everywhere
|
||||
The repository has tests, but some environments still do not have `pytest` installed.
|
||||
|
||||
7. **MOS/XGBoost 替代手工 μ**
|
||||
- 用历史 METAR + 模型预报训练后处理模型
|
||||
- 概率引擎从"合理的猜测"升级到"可校验的预测"
|
||||
Impact:
|
||||
- Harder to run full verification on every host
|
||||
|
||||
8. **多市场适配**
|
||||
- 当前只针对温度合约
|
||||
- 扩展到降水、风速等需要重构分析框架
|
||||
Suggested direction:
|
||||
- Standardize test dependencies in deployment and CI environments
|
||||
|
||||
---
|
||||
## Immediate Next Steps
|
||||
|
||||
## 五、一句话总结
|
||||
|
||||
> PolyWeather 目前最大的价值是**信息聚合和格式化**——把分散在多个 API 的气象数据整合成可快速消化的仪表盘。至于"预测准不准",诚实的回答是:**不知道,因为还没有建立衡量准确率的机制**。
|
||||
1. Add evidence lines to Telegram alerts
|
||||
2. Finish cleaning backend naming after removal of old static web flow
|
||||
3. Design subscription storage for commercialization
|
||||
4. Start replay/backtest tooling for alert-quality tuning
|
||||
|
||||
+40
-22
@@ -1,14 +1,27 @@
|
||||
# PolyWeather Frontend (Next.js)
|
||||
# PolyWeather Frontend
|
||||
|
||||
Standalone web frontend for `polyweather.vercel.app`.
|
||||
This directory is the only web frontend in production.
|
||||
|
||||
Production URL:
|
||||
- https://polyweather-pro.vercel.app/
|
||||
|
||||
## Stack
|
||||
|
||||
- Next.js 14+ (App Router)
|
||||
- Next.js App Router
|
||||
- Tailwind CSS
|
||||
- Lucide React
|
||||
- shadcn/ui base components
|
||||
- Leaflet (react-leaflet)
|
||||
- shadcn/ui base layer
|
||||
- Legacy dashboard shell loaded from `public/legacy/index.html`
|
||||
|
||||
## Production Model
|
||||
|
||||
- Vercel serves the web UI
|
||||
- FastAPI on VPS serves API only
|
||||
- The old FastAPI static website has been removed
|
||||
|
||||
Current request flow:
|
||||
- Browser -> Vercel frontend
|
||||
- Vercel route handlers -> FastAPI API
|
||||
|
||||
## Local Development
|
||||
|
||||
@@ -19,32 +32,37 @@ npm install
|
||||
npm run dev
|
||||
```
|
||||
|
||||
Default frontend URL: `http://localhost:3000`
|
||||
Default local URL:
|
||||
- http://localhost:3000
|
||||
|
||||
## Backend API
|
||||
## Required Environment Variable
|
||||
|
||||
Set `POLYWEATHER_API_BASE_URL` to your FastAPI service URL.
|
||||
|
||||
Example:
|
||||
|
||||
```bash
|
||||
POLYWEATHER_API_BASE_URL=https://api.yourdomain.com
|
||||
```env
|
||||
POLYWEATHER_API_BASE_URL=https://<your-fastapi-host>
|
||||
```
|
||||
|
||||
The frontend uses Next Route Handlers as a thin BFF layer:
|
||||
Examples:
|
||||
- `http://38.54.27.70:8000`
|
||||
- `https://api.example.com`
|
||||
|
||||
## Route Handlers
|
||||
|
||||
Thin BFF routes currently exposed by Next:
|
||||
- `GET /api/cities`
|
||||
- `GET /api/city/:name`
|
||||
- `GET /api/city/[name]`
|
||||
- `GET /api/history/[name]`
|
||||
|
||||
## Vercel Deployment
|
||||
|
||||
1. Import this repo in Vercel.
|
||||
2. Set **Root Directory** to `frontend`.
|
||||
3. Add environment variable:
|
||||
- `POLYWEATHER_API_BASE_URL=https://<your-fastapi-host>`
|
||||
4. Deploy.
|
||||
1. Import the repo into Vercel
|
||||
2. Set Root Directory to `frontend`
|
||||
3. Set `POLYWEATHER_API_BASE_URL`
|
||||
4. Deploy
|
||||
|
||||
## Notes
|
||||
|
||||
- Backend CORS must allow `https://polyweather.vercel.app`.
|
||||
- This is phase-1 split: map + city list + detail panel are migrated first.
|
||||
- Backend CORS must allow `https://polyweather-pro.vercel.app`
|
||||
- The page shell currently embeds the legacy dashboard HTML from `public/legacy/index.html`
|
||||
- If you change files under `public/static`, deploy to Vercel to make them live
|
||||
|
||||
Last updated: 2026-03-06
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
import sqlite3
|
||||
import os
|
||||
from datetime import datetime, timedelta
|
||||
from typing import Optional, Dict, Any
|
||||
from loguru import logger
|
||||
|
||||
class DBManager:
|
||||
def __init__(self, db_path: str = "polyweather.db"):
|
||||
self.db_path = db_path
|
||||
self._init_db()
|
||||
|
||||
def _get_connection(self):
|
||||
return sqlite3.connect(self.db_path)
|
||||
|
||||
def _init_db(self):
|
||||
"""Create tables if they don't exist."""
|
||||
# Ensure directory exists
|
||||
os.makedirs(os.path.dirname(self.db_path), exist_ok=True)
|
||||
with self._get_connection() as conn:
|
||||
conn.execute("""
|
||||
CREATE TABLE IF NOT EXISTS users (
|
||||
telegram_id INTEGER PRIMARY KEY,
|
||||
username TEXT,
|
||||
is_web_premium BOOLEAN DEFAULT 0,
|
||||
web_expiry TIMESTAMP,
|
||||
is_group_premium BOOLEAN DEFAULT 0,
|
||||
group_expiry TIMESTAMP,
|
||||
points INTEGER DEFAULT 0,
|
||||
message_count INTEGER DEFAULT 0,
|
||||
last_message_at TIMESTAMP,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
)
|
||||
""")
|
||||
conn.commit()
|
||||
logger.info("Database initialized successfully.")
|
||||
|
||||
def get_user(self, telegram_id: int) -> Optional[Dict[str, Any]]:
|
||||
with self._get_connection() as conn:
|
||||
conn.row_factory = sqlite3.Row
|
||||
cursor = conn.execute("SELECT * FROM users WHERE telegram_id = ?", (telegram_id,))
|
||||
row = cursor.fetchone()
|
||||
if row:
|
||||
user = dict(row)
|
||||
now = datetime.now()
|
||||
if user['web_expiry']:
|
||||
expiry = datetime.fromisoformat(user['web_expiry'])
|
||||
if expiry < now:
|
||||
user['is_web_premium'] = False
|
||||
if user['group_expiry']:
|
||||
expiry = datetime.fromisoformat(user['group_expiry'])
|
||||
if expiry < now:
|
||||
user['is_group_premium'] = False
|
||||
return user
|
||||
return None
|
||||
|
||||
def upsert_user(self, telegram_id: int, username: str):
|
||||
with self._get_connection() as conn:
|
||||
conn.execute("""
|
||||
INSERT INTO users (telegram_id, username)
|
||||
VALUES (?, ?)
|
||||
ON CONFLICT(telegram_id) DO UPDATE SET
|
||||
username = excluded.username
|
||||
""", (telegram_id, username))
|
||||
conn.commit()
|
||||
|
||||
def add_message_activity(self, telegram_id: int, points_to_add: int = 1):
|
||||
"""Update message count and add points with simple anti-spam logic."""
|
||||
now = datetime.now()
|
||||
with self._get_connection() as conn:
|
||||
cursor = conn.execute("SELECT last_message_at FROM users WHERE telegram_id = ?", (telegram_id,))
|
||||
row = cursor.fetchone()
|
||||
if row and row[0]:
|
||||
last_at = datetime.fromisoformat(row[0])
|
||||
if (now - last_at).total_seconds() < 5: # 5 second cooldown
|
||||
return False
|
||||
|
||||
conn.execute("""
|
||||
UPDATE users
|
||||
SET message_count = message_count + 1,
|
||||
points = points + ?,
|
||||
last_message_at = ?
|
||||
WHERE telegram_id = ?
|
||||
""", (points_to_add, now.isoformat(), telegram_id))
|
||||
conn.commit()
|
||||
return True
|
||||
|
||||
def set_premium(self, telegram_id: int, plan: str, months: int = 1):
|
||||
expiry = datetime.now() + timedelta(days=30 * months)
|
||||
col_is = f"is_{plan}_premium"
|
||||
col_expiry = f"{plan}_expiry"
|
||||
with self._get_connection() as conn:
|
||||
conn.execute(f"""
|
||||
UPDATE users
|
||||
SET {col_is} = 1, {col_expiry} = ?
|
||||
WHERE telegram_id = ?
|
||||
""", (expiry.isoformat(), telegram_id))
|
||||
conn.commit()
|
||||
logger.info(f"User {telegram_id} upgraded to {plan} premium until {expiry}")
|
||||
|
||||
def get_leaderboard(self, limit: int = 10):
|
||||
with self._get_connection() as conn:
|
||||
conn.row_factory = sqlite3.Row
|
||||
cursor = conn.execute("""
|
||||
SELECT username, points, message_count
|
||||
FROM users
|
||||
ORDER BY points DESC
|
||||
LIMIT ?
|
||||
""", (limit,))
|
||||
return [dict(row) for row in cursor.fetchall()]
|
||||
Reference in New Issue
Block a user