openclaw-home-pc/workspace/skills/stock-monitor-skill/scripts/tl_monitor.py
2026-03-21 15:31:06 +08:00

199 lines
5.7 KiB
Python
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
"""
铜陵有色专项监控 - 实时股价监控
使用腾讯财经接口,确保数据准确性
"""
import requests
import json
import time
import os
from datetime import datetime
from pathlib import Path
# ============ 配置 ============
WATCHLIST = [
{
"code": "000630",
"name": "铜陵有色",
"market": "sz",
"alerts": {
"change_pct_above": 5.0, # 涨超 5% 预警
"change_pct_below": -5.0, # 跌超 5% 预警
}
}
]
# 企业微信配置
WECOM_BOT_ID = "aibwl3AhnzfRPRTEZvBVwlB-vRD33yJdUVX"
WECOM_SECRET = "1eUB2yd2R7bll6VjBQ5OGptJj2YiwutMUmACe9UGC7k"
ALLOW_USERS = ["HouHuan", "WanMeiShengHuo", "XinNingXianGuoNaiChaKaFeiZhaJiHa"]
# ============ 核心功能 ============
def fetch_tencent_price(stock):
"""腾讯财经接口获取实时股价"""
code = f"{stock['market']}{stock['code']}"
url = f"http://qt.gtimg.cn/q={code}"
try:
resp = requests.get(url, timeout=5)
resp.encoding = 'gbk'
data = resp.text.strip()
# 解析v_sz000630="51~名称~代码~现价~昨收~今开~...
if '="' not in data:
return None
parts = data.strip('"').split('~')
# 找到前缀位置
start_idx = 0
for i, p in enumerate(parts):
if p.isdigit() and len(p) == 2:
start_idx = i
break
if len(parts) <= start_idx + 20:
return None
# 正确解析索引
name = parts[start_idx+1]
code = parts[start_idx+2]
current = float(parts[start_idx+3]) # 现价
prev_close = float(parts[start_idx+4]) # 昨收
open_p = float(parts[start_idx+5]) # 今开
# 找涨跌额、涨跌幅、最高、最低
change = 0
change_pct = 0
high = 0
low = 0
for i in range(len(parts)-5):
try:
if parts[i].startswith('-') and '.' in parts[i]:
v1 = float(parts[i])
v2 = float(parts[i+1])
if -10 < v2 < 10: # 涨跌幅一般在 -10~10 之间
change = v1
change_pct = v2
high = float(parts[i+2])
low = float(parts[i+3])
break
except:
continue
return {
'name': name,
'code': code,
'price': current,
'prev_close': prev_close,
'open': open_p,
'high': high,
'low': low,
'change': change,
'change_pct': change_pct,
'time': datetime.now().strftime('%Y-%m-%d %H:%M:%S')
}
except Exception as e:
print(f"❌ 数据获取失败:{e}")
return None
def check_alerts(stock, data):
"""检查是否触发预警"""
alerts = []
cfg = stock.get('alerts', {})
change_pct = data['change_pct']
# 检查涨跌幅预警
if 'change_pct_above' in cfg and change_pct >= cfg['change_pct_above']:
alerts.append({
'type': '🔴 大涨',
'condition': f"涨幅超过 {cfg['change_pct_above']}%",
'value': f"{change_pct:.2f}%"
})
if 'change_pct_below' in cfg and change_pct <= cfg['change_pct_below']:
alerts.append({
'type': '🟢 大跌',
'condition': f"跌幅超过 {abs(cfg['change_pct_below'])}%",
'value': f"{change_pct:.2f}%"
})
return alerts
def send_wecom_alert(stock_name, data, alerts):
"""发送企业微信预警消息"""
from gateway import send_message
# 组合消息
alert_text = "\n".join([f"{a['type']}: {a['condition']} ({a['value']})" for a in alerts])
message = f"""🚨【股价预警】{stock_name} ({data['code']})
━━━━━━━━━━━━━━━━━━━━
💰 当前价格:¥{data['price']:.2f} ({data['change_pct']:+.2f}%)
🎯 触发预警:
{alert_text}
📊 详细数据:
• 昨收:¥{data['prev_close']:.2f}
• 今开:¥{data['open']:.2f}
• 最高:¥{data['high']:.2f}
• 最低:¥{data['low']:.2f}
⏰ 数据时间:{data['time']}
💡 建议关注后续走势,注意风险控制。
"""
# 发送给所有允许的用户
for user in ALLOW_USERS:
try:
send_message(
channel="wecom",
target=user,
message=message
)
print(f"✅ 预警已发送给用户:{user}")
except Exception as e:
print(f"❌ 发送失败 {user}: {e}")
def monitor_once():
"""执行一次监控"""
print(f"\n{'='*60}")
print(f"📊 铜陵有色监控 - {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
print(f"{'='*60}")
for stock in WATCHLIST:
data = fetch_tencent_price(stock)
if not data:
print(f"{stock['name']} 数据获取失败")
continue
print(f"{stock['name']} ({stock['code']})")
print(f" 现价:¥{data['price']:.2f} ({data['change_pct']:+.2f}%)")
print(f" 昨收:¥{data['prev_close']:.2f}")
print(f" 涨跌:¥{data['change']:.2f}")
# 检查预警
alerts = check_alerts(stock, data)
if alerts:
print(f" 🚨 触发 {len(alerts)} 条预警!")
send_wecom_alert(stock['name'], data, alerts)
else:
print(f" ✅ 正常波动范围")
print(f"{'='*60}\n")
# ============ 主程序 ============
if __name__ == "__main__":
# 单次执行
monitor_once()