|
@@ -59,9 +59,9 @@ df_aligned['prob_ranging'] = probs[:, 0]
|
|
|
df_aligned['prob_trend'] = probs[:, 1]
|
|
df_aligned['prob_trend'] = probs[:, 1]
|
|
|
df_aligned['prob_reversal'] = probs[:, 2]
|
|
df_aligned['prob_reversal'] = probs[:, 2]
|
|
|
|
|
|
|
|
-# 获取最近60天
|
|
|
|
|
-last_60 = df_aligned.tail(60).copy()
|
|
|
|
|
-last_60['change'] = last_60['close'].pct_change() * 100
|
|
|
|
|
|
|
+# 获取最近365天
|
|
|
|
|
+last_365 = df_aligned.tail(365).copy()
|
|
|
|
|
+last_365['change'] = last_365['close'].pct_change() * 100
|
|
|
|
|
|
|
|
# 获取最新数据
|
|
# 获取最新数据
|
|
|
today = df_aligned.iloc[-1]
|
|
today = df_aligned.iloc[-1]
|
|
@@ -72,9 +72,9 @@ colors = ['#2196F3', '#4CAF50', '#FF5722']
|
|
|
state_name = state_names[int(today['state'])]
|
|
state_name = state_names[int(today['state'])]
|
|
|
state_color = colors[int(today['state'])]
|
|
state_color = colors[int(today['state'])]
|
|
|
|
|
|
|
|
-# 生成60天详细数据表格
|
|
|
|
|
|
|
+# 生成365天详细数据表格
|
|
|
html_rows = ""
|
|
html_rows = ""
|
|
|
-for idx, row in last_60.iterrows():
|
|
|
|
|
|
|
+for idx, row in last_365.iterrows():
|
|
|
s = int(row['state'])
|
|
s = int(row['state'])
|
|
|
change = row['change'] if not pd.isna(row['change']) else 0
|
|
change = row['change'] if not pd.isna(row['change']) else 0
|
|
|
change_str = f"{change:+.2f}%" if change != 0 else "-"
|
|
change_str = f"{change:+.2f}%" if change != 0 else "-"
|
|
@@ -85,7 +85,7 @@ for idx, row in last_60.iterrows():
|
|
|
|
|
|
|
|
html_rows += f"""
|
|
html_rows += f"""
|
|
|
<tr {highlight}>
|
|
<tr {highlight}>
|
|
|
- <td>{idx.strftime('%m-%d')}</td>
|
|
|
|
|
|
|
+ <td>{idx.strftime('%y-%m-%d')}</td>
|
|
|
<td>{row['close']:.2f}</td>
|
|
<td>{row['close']:.2f}</td>
|
|
|
<td style="color: {colors[s]}; font-weight: bold;">{state_names[s]}</td>
|
|
<td style="color: {colors[s]}; font-weight: bold;">{state_names[s]}</td>
|
|
|
<td>{row['prob_ranging']:.1%}</td>
|
|
<td>{row['prob_ranging']:.1%}</td>
|
|
@@ -100,7 +100,7 @@ daily_change = today['close'] - yesterday['close']
|
|
|
daily_change_pct = daily_change / yesterday['close'] * 100
|
|
daily_change_pct = daily_change / yesterday['close'] * 100
|
|
|
|
|
|
|
|
# 计算区间涨跌
|
|
# 计算区间涨跌
|
|
|
-range_change_pct = (today['close'] / last_60['close'].iloc[0] - 1) * 100
|
|
|
|
|
|
|
+range_change_pct = (today['close'] / last_365['close'].iloc[0] - 1) * 100
|
|
|
|
|
|
|
|
# 邮件内容
|
|
# 邮件内容
|
|
|
html = f"""
|
|
html = f"""
|
|
@@ -135,15 +135,15 @@ html = f"""
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
<div class="summary">
|
|
<div class="summary">
|
|
|
- <h2>📊 最近60天统计 (2024-至今)</h2>
|
|
|
|
|
- <p><strong>60天前价格:</strong> {last_60['close'].iloc[0]:.2f}</p>
|
|
|
|
|
|
|
+ <h2>📊 最近365天统计 (2024-至今)</h2>
|
|
|
|
|
+ <p><strong>365天前价格:</strong> {last_365['close'].iloc[0]:.2f}</p>
|
|
|
<p><strong>区间涨跌:</strong> <span style="color: {'green' if range_change_pct >= 0 else 'red'};">{range_change_pct:+.2f}%</span></p>
|
|
<p><strong>区间涨跌:</strong> <span style="color: {'green' if range_change_pct >= 0 else 'red'};">{range_change_pct:+.2f}%</span></p>
|
|
|
- <p><strong>最高价:</strong> {last_60['close'].max():.2f} ({last_60['close'].idxmax().strftime('%m-%d')}) / <strong>最低价:</strong> {last_60['close'].min():.2f} ({last_60['close'].idxmin().strftime('%m-%d')})</p>
|
|
|
|
|
|
|
+ <p><strong>最高价:</strong> {last_365['close'].max():.2f} ({last_365['close'].idxmax().strftime('%m-%d')}) / <strong>最低价:</strong> {last_365['close'].min():.2f} ({last_365['close'].idxmin().strftime('%m-%d')})</p>
|
|
|
<br>
|
|
<br>
|
|
|
- <p><strong>状态分布:</strong> 🟦 震荡 {(last_60['state']==0).sum()}天 / 🟩 趋势 {(last_60['state']==1).sum()}天 / 🟧 反转 {(last_60['state']==2).sum()}天</p>
|
|
|
|
|
|
|
+ <p><strong>状态分布:</strong> 🟦 震荡 {(last_365['state']==0).sum()}天 / 🟩 趋势 {(last_365['state']==1).sum()}天 / 🟧 反转 {(last_365['state']==2).sum()}天</p>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
- <h2>📋 最近60天详细数据</h2>
|
|
|
|
|
|
|
+ <h2>📋 最近365天详细数据</h2>
|
|
|
<p class="legend">
|
|
<p class="legend">
|
|
|
<span>🟦 震荡</span>
|
|
<span>🟦 震荡</span>
|
|
|
<span>🟩 趋势</span>
|
|
<span>🟩 趋势</span>
|
|
@@ -186,7 +186,7 @@ EMAIL_CONFIG = {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
msg = MIMEMultipart('related')
|
|
msg = MIMEMultipart('related')
|
|
|
-msg['Subject'] = Header(f"📊 CYB50每日市场状态报告 [{df_aligned.index[-1].strftime('%m-%d')}] 当前{state_name}", 'utf-8')
|
|
|
|
|
|
|
+msg['Subject'] = Header(f"📊 CYB50-Regime每日市场状态报告 [{df_aligned.index[-1].strftime('%m-%d')}] 当前{state_name}", 'utf-8')
|
|
|
msg['From'] = "regime <regime@openclaw.local>"
|
|
msg['From'] = "regime <regime@openclaw.local>"
|
|
|
msg['To'] = EMAIL_CONFIG['receiver_email']
|
|
msg['To'] = EMAIL_CONFIG['receiver_email']
|
|
|
msg.attach(MIMEText(html, 'html', 'utf-8'))
|
|
msg.attach(MIMEText(html, 'html', 'utf-8'))
|