feat: Add a multi-source weather data collection module with integrations for OpenWeatherMap, Visual Crossing, and Open-Meteo.

This commit is contained in:
2569718930@qq.com
2026-02-07 01:13:59 +08:00
parent 592db31ee7
commit cff008b2a5
2 changed files with 44 additions and 11 deletions
+21 -5
View File
@@ -240,7 +240,7 @@ def main():
)
temp_symbol = "°F" if temp_unit == "fahrenheit" else "°C"
logger.info(
f"☁️ {city} 当前气温: {consensus['average_temp']}{temp_symbol} | 监控合约: {len(city_markets)}"
f"☁️ {city} 当前气温: {consensus['average_temp']}{temp_symbol} (unit={temp_unit}) | 监控合约: {len(city_markets)}"
)
# --- 本城市汇总预警缓存 ---
@@ -364,6 +364,10 @@ def main():
}
)
# 获取温度符号(在此处定义以便后续使用)
temp_unit = weather_data.get("open-meteo", {}).get("unit", "celsius")
temp_symbol = "°F" if temp_unit == "fahrenheit" else "°C"
# 预测偏差分析
if ref_temp:
city_pred_high = ref_temp # 记录到城市概览
@@ -378,7 +382,7 @@ def main():
else low_b
)
diff = ref_temp - ((low_b + high_b) / 2)
msg += f"\n📐 预测偏差: {diff:+.1f}{temp_symbol} (预测 {ref_temp}{temp_symbol})"
# 偏差信息将在后面构建 msg 时统一添加
# 生成策略建议:仅保留模型一致提示
if abs(diff) < 2 and current_prob > 0.7:
@@ -386,6 +390,7 @@ def main():
f"预测温度{ref_temp}{temp_symbol}落在{question}区间,市场与模型一致"
)
# 模拟下单 - 使用 Ask 价格(实际可成交价格)
if buy_yes_price and buy_yes_price > 0.5:
trigger_side = "Buy Yes"
@@ -398,6 +403,13 @@ def main():
else int((1 - current_prob) * 100)
)
# 构建预测文本
forecast_text = f"{ref_temp}{temp_symbol}" if ref_temp else "N/A"
# 构建简约版消息
side_display = "Buy No" if trigger_side == "Buy No" else "Buy Yes"
msg = f"{question} ({target_date}): {side_display} {trigger_price}¢ | 预测:{forecast_text}"
success = paper_trader.open_position(
market_id=market_id,
city=city,
@@ -408,6 +420,10 @@ def main():
target_date=target_date,
predicted_temp=ref_temp,
)
# 添加模拟交易标签
if success:
msg += " [🛒 $5.0 💡试探]"
city_alerts.append(
{
@@ -415,7 +431,7 @@ def main():
"msg": msg,
"bought": success,
"amount": 5.0,
"confidence": "动态",
"confidence": "💡试探",
}
)
pushed_signals[alert_key] = time.time()
@@ -476,8 +492,8 @@ def main():
all_markets_cache[market_id] = cache_entry
continue
# 2. 过滤已过期日期 (对比当前日期: 2026-02-06)
current_today = "2026-02-06"
# 2. 过滤已过期日期 (动态获取当前日期)
current_today = datetime.now().strftime("%Y-%m-%d")
if target_date and target_date < current_today:
cache_entry["rationale"] = "EXPIRED"
all_markets_cache[market_id] = cache_entry
+23 -6
View File
@@ -209,7 +209,7 @@ class WeatherDataCollector:
current = data.get("current_weather", {})
utc_offset = data.get("utc_offset_seconds", 0)
timezone_name = data.get("timezone", "UTC")
# 计算精确的当地时间而不是气象站 bucket 时间
now_utc = datetime.utcnow()
local_now = now_utc + timedelta(seconds=utc_offset)
@@ -287,7 +287,7 @@ class WeatherDataCollector:
normalized_city = city.lower().strip()
if normalized_city in static_coords:
return static_coords[normalized_city]
# 模糊匹配映射 (针对包含城市名的情况)
for key in static_coords:
if key in normalized_city:
@@ -368,7 +368,7 @@ class WeatherDataCollector:
results = {}
# 判断是否为美国市场(使用华氏度)
us_cities = [
us_cities = {
"dallas",
"nyc",
"new york",
@@ -383,9 +383,26 @@ class WeatherDataCollector:
"houston",
"phoenix",
"philadelphia",
]
city_lower = city.lower()
use_fahrenheit = any(uc in city_lower for uc in us_cities)
"new york's central park",
"portland",
"denver",
"austin",
"san diego",
"detroit",
"cleveland",
"minneapolis",
"st. louis",
}
city_lower = city.lower().strip()
# 检查城市名是否在美国城市列表中(支持完全匹配或包含关系)
use_fahrenheit = city_lower in us_cities or any(
us_city in city_lower for us_city in us_cities
)
if use_fahrenheit:
logger.info(f"🌡️ {city} 使用华氏度 (°F)")
else:
logger.info(f"🌡️ {city} 使用摄氏度 (°C)")
# Open-Meteo (Primary Free Source - No Key)
if lat and lon: