#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ CYB50市场状态识别 - 每日邮件发送脚本 通过本地SMTP服务器(直接投递模式)发送邮件 """ import sys sys.path.insert(0, '/root/.openclaw/workspace/market-regime-identifier') import numpy as np import pandas as pd from cyb50_market_classifier import fetch_cyb50_data, calculate_features, define_market_regime from sklearn.ensemble import RandomForestClassifier import smtplib from email.mime.text import MIMEText from email.mime.multipart import MIMEMultipart from email.header import Header from datetime import datetime import os import warnings warnings.filterwarnings('ignore') # SMTP配置 SMTP_SERVER = os.getenv('SMTP_SERVER', 'localhost') SMTP_PORT = int(os.getenv('SMTP_PORT', '25')) SENDER = os.getenv('SMTP_SENDER', 'kalman@erwin.wang') RECEIVER = '380880504@qq.com' print("="*60) print(f"CYB50每日市场状态报告 - {datetime.now().strftime('%Y-%m-%d %H:%M')}") print(f"SMTP: {SMTP_SERVER}:{SMTP_PORT}") print("="*60) # 获取数据 df = fetch_cyb50_data('2024-01-01', '2026-12-31') if df is None: print("数据获取失败") exit(1) # 计算特征和标签 features = calculate_features(df) labels = define_market_regime(df, lookback=10) # 训练模型 valid_idx = ~np.isnan(labels) X = features[valid_idx] y = labels[valid_idx] clf = RandomForestClassifier( n_estimators=100, max_depth=10, min_samples_split=20, min_samples_leaf=10, random_state=42, class_weight='balanced' ) clf.fit(X, y) # 预测所有数据 states = clf.predict(X) probs = clf.predict_proba(X) # 对齐数据 df_aligned = df.iloc[-len(states):].copy() df_aligned['state'] = states df_aligned['prob_ranging'] = probs[:, 0] df_aligned['prob_trend'] = probs[:, 1] df_aligned['prob_reversal'] = probs[:, 2] # 获取最新数据 today = df_aligned.iloc[-1] yesterday = df_aligned.iloc[-2] if len(df_aligned) > 1 else today state_names = ['震荡', '趋势', '反转'] colors = ['#2196F3', '#4CAF50', '#FF5722'] state_name = state_names[int(today['state'])] state_color = colors[int(today['state'])] # 计算涨跌 daily_change = today['close'] - yesterday['close'] daily_change_pct = daily_change / yesterday['close'] * 100 # 获取最近30天 last_30 = df_aligned.tail(30).copy() # 生成HTML表格 html_rows = "" for idx, row in last_30.iterrows(): s = int(row['state']) html_rows += f""" {idx.strftime('%m-%d')} {row['close']:.2f} {state_names[s]} {row['prob_ranging']:.1%} {row['prob_trend']:.1%} {row['prob_reversal']:.1%} """ # 邮件内容 html = f"""

CYB50每日市场状态报告

今日状态 ({df_aligned.index[-1].strftime('%Y-%m-%d')})

收盘价: {today['close']:.2f}

日涨跌: {daily_change:+.2f} ({daily_change_pct:+.2f}%)

市场状态: {state_name}

状态概率: 震荡 {today['prob_ranging']:.1%} / 趋势 {today['prob_trend']:.1%} / 反转 {today['prob_reversal']:.1%}

最近30天数据

{html_rows}
日期 收盘价 状态 震荡概率 趋势概率 反转概率

生成时间: {datetime.now().strftime('%Y-%m-%d %H:%M')}
数据更新至: {df_aligned.index[-1].strftime('%Y-%m-%d')}
模型准确率: 72.10% | 创业板50指数 (sz399673)

""" # 发送邮件 msg = MIMEMultipart('related') msg['Subject'] = Header(f"CYB50-Regime每日报告 [{df_aligned.index[-1].strftime('%m-%d')}] 当前{state_name}", 'utf-8') msg['From'] = f"regime <{SENDER}>" msg['To'] = RECEIVER msg.attach(MIMEText(html, 'html', 'utf-8')) try: with smtplib.SMTP(SMTP_SERVER, SMTP_PORT, timeout=10) as server: server.sendmail(SENDER, RECEIVER, msg.as_string()) print(f"[OK] 邮件发送成功! [{df_aligned.index[-1].strftime('%Y-%m-%d')}] 当前状态: {state_name}") except Exception as e: print(f"[ERROR] 邮件发送失败: {e}") print(f"请确保SMTP服务器已启动: python smtp_relay_server.py --direct") print("="*60)