ETF波动率计算

代码如下

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_annualized_volatility(df, trading_days):
    if df.empty:
        return None

    # 计算收益率
    df['收益率'] = df['Close'].pct_change()

    # 计算年化波动率
    volatility = df['收益率'].std() * (trading_days ** 0.5)

    return round(volatility * 100, 2)  # 转换为百分比格式

# 发送邮件的函数
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)

        if not df.empty:
            # 计算过去一年、过去一个月和过去一周的年化波动率
            volatility_1y = calculate_annualized_volatility(df, trading_days=252)  # 过去一年
            volatility_1m = calculate_annualized_volatility(df.iloc[-21:], trading_days=252)  # 过去一个月
            volatility_1w = calculate_annualized_volatility(df.iloc[-5:], trading_days=252)  # 过去一周

            # 判断波动率的变化方向,并添加颜色
            trend_1m_color = "red" if volatility_1m > volatility_1y else "green" if volatility_1m < volatility_1y else "gray"
            trend_1m_arrow = "↑" if volatility_1m > volatility_1y else "↓" if volatility_1m < volatility_1y else "-"
            trend_1w_color = "red" if volatility_1w > volatility_1m else "green" if volatility_1w < volatility_1m else "gray"
            trend_1w_arrow = "↑" if volatility_1w > volatility_1m else "↓" if volatility_1w < volatility_1m else "-"

            results.append({
                'ETF名称': name,
                '代码': symbol,
                '过去一年年化波动率 (%)': volatility_1y,
                '过去一月年化波动率 (%)': f"{volatility_1m} <span style='color:{trend_1m_color}'>{trend_1m_arrow}</span>",
                '过去一周年化波动率 (%)': f"{volatility_1w} <span style='color:{trend_1w_color}'>{trend_1w_arrow}</span>"
            })
        else:
            print(f"未获取到 {name} ({symbol}) 的数据。")

    # 将结果转换为DataFrame
    results_df = pd.DataFrame(results)

    # 生成简单的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():
        html_content += f"""
        <tr>
            <td>{row['ETF名称']}</td>
            <td>{row['代码']}</td>
            <td>{row['过去一年年化波动率 (%)']}</td>
            <td>{row['过去一月年化波动率 (%)']}</td>
            <td>{row['过去一周年化波动率 (%)']}</td>
        </tr>
        """

    html_content += """
    </table>
    </body>
    </html>
    """

    # 发送邮件
    send_email(html_content, today.strftime('%Y-%m-%d'))
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

鸭梨山大哎

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值