首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >【Python技术】统计各类ETF在历年月份表现

【Python技术】统计各类ETF在历年月份表现

作者头像
子晓聊技术
发布2026-04-23 14:00:22
发布2026-04-23 14:00:22
1650
举报
文章被收录于专栏:子晓AI量化子晓AI量化

星球群一些同学喜欢做ETF,这里写一篇相关ETF的文章。 之前写过一篇统计上证指数历年表现, 大家都知道1月、3月、4月等行情不好,我们就不玩了么? 大家都知道银行ETF在大盘不好的时候表现还可以, 那么我们写个程序测试下实际情况。

这里的ETF指数代码我改成了灵活配置,选择ETF, 不管是银行ETF、 还是黄金ETF、亦或者其他ETF,下拉选择就可以看到历年月份表现了。

这是不是可以辅助ETF投资, 比所谓的日内ETF做T自动交易简单多了。 网上那些鼓吹赚钱的 网格交易、动量交易日内做T真的更赚钱? 我相信他们赚钱了。 我个人认为,量化分析是为了赚钱,不是为了炫技术有多厉害的。

有人问我为啥不写QMT或者Ptrade相关文章。这里说明下, 不是自己不会,而是官方文档和例子写得够好,具体文档我在交流群已经放了, 需要的可以进群交流。 市面上各种例子,再加上平时用MAC, 家里的windows电脑家里人在用, 太麻烦我就懒得写了。我也不想天天复制一些自己没跑过没营养的例子。

题外话

这可能是五一前最后一篇技术文, 写完这篇文章,我可能在愉快的过五一了。 如果微信消息我没有回复,请见谅。 除了股票和技术, 还有诗和远方。 读万卷书,不如走万里路。 每到节假日,带着小朋友去外地各大名胜景点走走。 后续有时间发点人头风景照大家欣赏。独乐乐不如总乐乐。

最后完整代码如下,需要的自取。代码中的数组列举的ETF可以改成你自己想了解的。 备注:如果发现格式有多余的特殊字符,用普通浏览器打开复制应该没问题。

代码语言:javascript
复制
import streamlit as st
import akshare as ak
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
import matplotlib.colors as mcolors
from datetime import datetime
# 设置全局样式
plt.rcParams['font.sans-serif'] = ['STHeiti']  # 苹果系统字体
plt.rcParams['axes.unicode_minus'] = False
# 自定义双色系
dual_colors = ['#4CB050', '#FF3333']  # 绿跌红涨
cmap = mcolors.ListedColormap(dual_colors)
bounds = [-100, 0, 100]
norm = mcolors.BoundaryNorm(bounds, cmap.N)
# 常见ETF映射表
ETF_MAP = {
    '上证指数':('000001.SH', '上证指数'),
    '银行ETF': ('512800.SH', '华宝中证银行ETF'),
    '人工智能ETF': ('515980.SH', '华富中证人工智能产业ETF'),
    '电力ETF': ('561560.SH', '华泰柏瑞中证电力公用事业ETF'),
    '沪深300ETF': ('510300.SH', '华泰柏瑞沪深300ETF'),
    '黄金ETF': ('518880.SH', '华安黄金易ETF')
}
# 数据获取
@st.cache_data(ttl=3600)
def get_etf_data(symbol):
    try:
        df = ak.fund_etf_fund_info_em(fund=symbol[:6])  # 提取纯数字代码
        df = df.rename(columns={
            '净值日期': 'date',
            '单位净值': 'close',
            '日增长率': 'change'
        })
        df['date'] = pd.to_datetime(df['date'])
        df['year'] = df['date'].dt.year
        df['month'] = df['date'].dt.month
        return df.sort_values('date')
    except Exception as e:
        st.error(f"数据获取失败:{str(e)}")
        return pd.DataFrame()
# 构建月度数据(增加容错机制)
def build_monthly_table(df):
    monthly = []
    for y in range(2015, 2025):
        row = {'年份': y}
        for m in range(1, 13):
            sub = df[(df['year'] == y) & (df['month'] == m)]
            if len(sub) >= 3:
                try:
                    chg = (sub.iloc[-1]['close'] / sub.iloc[0]['close'] - 1) * 100
                    row[f'{m}月'] = round(chg, 2)
                except KeyError:
                    row[f'{m}月'] = None
            else:
                row[f'{m}月'] = None
        monthly.append(row)
    return pd.DataFrame(monthly).set_index('年份')
# 生成热力图
def plot_heatmap(data):
    fig, ax = plt.subplots(figsize=(16, 6))
    sns.heatmap(data,
                cmap=cmap,
                norm=norm,
                annot=True,
                fmt=".1f",
                linewidths=0.5,
                cbar=False,
                annot_kws={'color': 'white', 'weight': 'bold'})
    ax.set_xticklabels(['1月', '2月', '3月', '4月', '5月', '6月',
                        '7月', '8月', '9月', '10月', '11月', '12月'])
    plt.title('月度涨跌幅分布', fontsize=14, pad=20)
    plt.tight_layout()
    return fig
def app():
    # 页面配置
    st.title("📊 行业ETF历史数据分析")
    st.subheader("参数设置")
    selected_name = st.selectbox(
        "选择行业ETF",
        options=list(ETF_MAP.keys()),
        index=0,
        help="选择要分析的行业ETF品种"
    )
    symbol, full_name = ETF_MAP[selected_name]
    # 显示基本信息
    st.markdown(f"""
    **ETF详情**  
    ▸ 代码:`{symbol}`  
    ▸ 全称:{full_name}  
    ▸ 数据范围:2015-2024年
    """)
    # 数据加载与处理
    df = get_etf_data(symbol)
    if not df.empty:
        # 展示关键指标
        col1, col2, col3 = st.columns(3)
        with col1:
            st.metric("最新净值", f"{df.iloc[-1]['close']:.3f}")
        with col2:
            st.metric("历史最高", f"{df['close'].max():.3f}")
        with col3:
            st.metric("数据日期", df['date'].max().strftime("%Y-%m-%d"))
        monthly_df = build_monthly_table(df)
        # 数据表格样式优化
        styled_df = monthly_df.style.format('{:.1f}%', na_rep="-").applymap(
            lambda val: f'background-color: {dual_colors[1] if val >= 0 else dual_colors[0]}; color: white'
        )
        st.dataframe(
            styled_df,
            height=600,
            use_container_width=True,
            column_config={
                "年份": st.column_config.NumberColumn(format="%d")
            }
        )
    else:
        st.warning("未获取到有效数据,请检查ETF代码或网络连接")
if __name__ == "__main__":
    app()

如果我的分享对您有所帮助,欢迎点赞转发。 您的支持和鼓励是我写作的动力。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2025-04-28,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 子晓聊技术 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档