第一件事是把日期列转成datetime格式,不然没法按时间做排序。她的数据跨度大概两年多,每个月定投一笔。我看了下金额,每月两千,买的是沪深300和中证500的那些场外联接基金。 df = pd.read_csv('fund_data.csv', encoding='utf-8')
df['date'] = pd.to_datetime(df['date'])
df.sort_values('date', inplace=True)
跑完基础清洗,我开始算累计收益率。她用手机对着屏幕拍了好几张图,说你这些数字跳来跳去的。我没直接给她看图表,而是先算了个最关键的指标——年化收益率。用np.power函数把总收益率按时间年化一下,结果出来是4.6%。她看了说,比银行理财高一点啊。我说你等等,波动率还没算呢。
算夏普比率的时候她突然安静了
波动率用的是日收益率的标准差,乘以sqrt(252)换算成年化。沪深300近两年的年化波动率大概在18%左右,她的组合稍微低一些,因为中证500那部分仓位不是很高。算完波动率,下一步就是夏普比率。无风险利率我取的十年期国债收益率,大概2.8%。
公式很直接:(年化收益率 - 无风险利率) / 年化波动率。算出来0.1,也就是跑赢无风险利率不多,承担的风险几乎没换来超额收益。她说你这个比率具体啥意思。我用喝水杯比划了一下,好比一杯水加了半杯糖,夏普比率就是糖和水的比例。她听完点了点头,说懂了。
这时候她靠过来看屏幕,头发捎带蹭到我手背。我赶紧把注意力拉回代码上。接下来画了个净值曲线,用matplotlib画的一条蓝线,上面标注了几个大跌的节点,比如2024年1月底的那波调整。她指着那个深坑说,那天晚上她差点赎回。我说还好你没动,后面三个月涨回来不少。 fig, ax = plt.subplots(figsize=(12, 5))
ax.plot(df['date'], df['cumulative_return'], color='2878B5', linewidth=1.5)
ax.fill_between(df['date'], 0, df['cumulative_return']100, alpha=0.1, color='2878B5')
ax.set_ylabel('累计收益率 (%)')
ax.axhline(y=0, color='black', linewidth=0.5)
她说这图比支付宝那种小卡片好看多了。我说那是因为我把坐标轴调了,把零线加粗了,还把上涨区间做了填充。她让我教她怎么画,我说你可以装个anaconda。她说哎呀我不学,你帮我跑就行。我就笑了笑,继续往下写代码。
最大回撤算出来她笑了
最大回撤是用滑动窗口算的。我把净值曲线从最高点往下溜坡,找到那个最深的坑。参数设成252个交易日,不算太严格。结果出来是9.3%,也就是她这两年最高从净值顶点亏了不到10%。她说还好还好,比我同事那亏20%的好多了。我说那是因为你定投,摊平了成本,而且中间没瞎操作。
她又问,那我现在该不该卖。我没有直接回答,而是用数据说话。算了个mar比率,就是年化收益率除以最大回撤。0.49,不算差,但也谈不上优秀。我说你要是急着用钱就卖,不急就放着。她说不急。我就把代码输出里的建议行改成了“建议继续持有,可考虑加大定投频率”。她看着那句话笑了。
最后一步,我生成了一个PDF报告,里面有收益曲线、回撤区间、夏普比率和持仓分布。她把PDF发到手机上,看了好一会儿,然后抬头说,你下午有空吗,请你喝奶茶。我说我不喝奶茶,喝咖啡吧。后来就是一起去公司楼下的瑞幸,她聊她之前自己做基金回测用的什么excel,结果VBA写崩了两次。我说你下次直接找我,用Python半小时搞定。她说好,那我以后天天找你。我低头喝了一口美式,心想这算不算套路。
现在她是我女朋友,偶尔还会发过来一堆基金数据让我跑跑。上周末她问我能不能做个定投计算器,我说行,加个菜单栏界面,用Tkinter写。她说你这人怎么什么都会。我说你教会了我怎么能看懂女人的话。
技术分享如果有用,你们也可以试试帮身边的朋友分析分析基金数据。说不定哪天就跟我一样,从分析数据变成了人生合伙人的关系。当然这事也有风险——要是算出来收益是负的,你可能会被拉黑。
后记:整段代码大概110行,核心逻辑就是数据处理+风险指标计算+可视化。没有用任何复杂的模型,都是最基础的金融分析。你要是感兴趣,可以把数据脱敏后发给我,我帮你跑一份看看。