代码如下
import akshare as ak
import pandas as pd
import yagmail
import os
from datetime import datetime, timedelta
# ETF代码与名称的映射
etf_names = {
'510300': '300ETF',
'159915': '创业板',
'513050': '中概互联网ETF',
'159941': '纳指ETF',
'518880': '黄金ETF',
'511090': '30年国债ETF'
}
# 获取ETF历史数据的函数
def fetch_etf_data(symbol, start_date, end_date):
df = ak.fund_etf_hist_em(symbol=symbol, period="daily", start_date=start_date, end_date=end_date, adjust='qfq')
df['日期'] = pd.to_datetime(df['日期'])
df.set_index('日期', inplace=True)
df.rename(columns={
'开盘': 'Open',
'最高': 'High',
'最低': 'Low',
'收盘': 'Close',
'成交量': 'Volume'
}, inplace=True)
return df
# 计算涨跌幅的函数
def calculate_price_change(df, current_price):
if df.empty:
return None, None
last_year_high = df['High'].max()
last_year_low = df['Low'].min()
fall_from_high = ((last_year_high - current_price) / last_year_high) * 100 if last_year_high > 0 else None
rise_from_low = ((current_price - last_year_low) / last_year_low) * 100 if last_year_low > 0 else None
return fall_from_high, rise_from_low
# 发送邮件的函数
def send_email(html_content, today):
try:
subject = f"ETF涨跌幅分析报告({today})"
yag = yagmail.SMTP(user=os.getenv('from_email'), password=os.getenv('password'), host='smtp.qq.com', port=465, smtp_ssl=True)
yag.send(to=os.getenv('to_email'), subject=subject, contents=[html_content])
print("邮件发送成功")
except Exception as e:
print(f"邮件发送失败: {e}")
# 主程序
if __name__ == "__main__":
today = datetime.today()
last_year_today = (today - timedelta(days=365)).strftime('%Y%m%d')
today_str = today.strftime('%Y%m%d')
results = []
for symbol, name in etf_names.items():
print(f"正在处理 {name} ({symbol})...")
df = fetch_etf_data(symbol, start_date=last_year_today, end_date=today_str)
current_price = df['Close'].iloc[-1] if not df.empty else None
if current_price is not None:
fall_from_high, rise_from_low = calculate_price_change(df, current_price)
results.append({
'ETF名称': name,
'代码': symbol,
'当前价格': round(current_price, 2),
'相比去年最高点跌幅 (%)': round(fall_from_high, 2) if fall_from_high is not None else "N/A",
'相比去年最低点涨幅 (%)': round(rise_from_low, 2) if rise_from_low is not None else "N/A"
})
else:
print(f"未获取到 {name} ({symbol}) 的数据。")
# 将结果转换为DataFrame
results_df = pd.DataFrame(results)
# 仅按“相比去年最低点涨幅 (%)”降序排列
results_df.sort_values(by=['相比去年最低点涨幅 (%)'], ascending=False, inplace=True)
# 生成简单的HTML表格
html_content = f"""
<html>
<body>
<h1>ETF涨跌幅分析报告</h1>
<p>报告日期:{today.strftime('%Y-%m-%d')}</p>
<table border="1">
<tr>
<th>ETF名称</th>
<th>代码</th>
<th>当前价格</th>
<th>相比去年最高点跌幅 (%)</th>
<th>相比去年最低点涨幅 (%)</th>
</tr>
"""
for _, row in results_df.iterrows():
# 设置颜色:涨幅为红色,跌幅为蓝色
fall_color = "blue" if isinstance(row['相比去年最高点跌幅 (%)'], (int, float)) and row['相比去年最高点跌幅 (%)'] < 0 else "black"
rise_color = "red" if isinstance(row['相比去年最低点涨幅 (%)'], (int, float)) and row['相比去年最低点涨幅 (%)'] > 0 else "black"
html_content += f"""
<tr>
<td>{row['ETF名称']}</td>
<td>{row['代码']}</td>
<td>{row['当前价格']}</td>
<td style="color:{fall_color}">{row['相比去年最高点跌幅 (%)']}</td>
<td style="color:{rise_color}">{row['相比去年最低点涨幅 (%)']}</td>
</tr>
"""
html_content += """
</table>
</body>
</html>
"""
# 发送邮件
send_email(html_content, today.strftime('%Y-%m-%d'))