基于指定日期投资组合及后续交易生成每日投资组合快照方案咨询
Python股票投资组合追踪器实现思路
一、先把数据理清楚
- 用
pandas读取起始组合表和交易记录表,注意处理样例里的索引列(比如读的时候加index_col=0参数) - 把交易记录里的
Date/Time转成日期格式,只保留日期部分(毕竟要的是每日数据,具体交易时间没用),用pd.to_datetime(trades['Date/Time']).dt.date就能快速处理 - 自己指定起始日期,比如样例里最早的交易是2022-06-28,起始日期可以设为2022-06-27
二、搭好每日持仓的时间线
- 确定时间范围:从起始日期到交易记录里的最晚日期,用
pd.date_range生成连续的每日日期序列 - 合并当日同股票交易:把同一天同一股票的交易数量、手续费分别求和,用
groupby(['Date', 'Symbol']).agg就能实现 - 逐日更新持仓:
- 先把起始组合转成字典,比如
{'NVDA':52, 'NFLX':18...} - 遍历每一天:如果当天有交易,对应调整股票持仓量(正数值为买入,负数值为卖出),持仓变0的股票可以直接从字典里移除
- 把每天的持仓状态存下来,最后转成DataFrame格式
- 先把起始组合转成字典,比如
三、拿到每日股票收盘价
- 用
yfinance库批量拉取所有涉及股票(起始组合+交易记录里的全部Symbol)的历史收盘价,直接pip install yfinance就能安装使用 - 如果涉及非USD货币,需要额外获取每日汇率,把非USD的收盘价转换成基准货币(比如USD)
- 把每日持仓和对应日期的收盘价匹配,为后续计算单股票价值做准备
四、计算每日组合总价值
- 单股票当日价值:
持仓数量 × 当日收盘价 - 每日总价值:所有股票当日价值之和,再减去累计的手续费(也可以选择逐日扣除当日手续费)
- 最终生成的表格需包含日期、各股票持仓量、各股票当日价值、当日总价值、当日手续费等字段
五、分析个股对涨跌的影响
- 计算每日组合涨跌幅:
(当日总价值 - 前一日总价值)/前一日总价值 - 计算个股贡献度:可以用
(个股当日价值 - 个股前一日价值)/前一日总价值,或者持仓数量×(当日收盘价-前一日收盘价)/前一日总价值,能直观看出哪只股票拉动了组合涨跌 - 把个股贡献度字段加入每日价值表,方便查看每日涨跌的核心影响个股
关键代码片段
1. 数据读取与预处理
import pandas as pd import yfinance as yf # 读取起始组合表 start_portfolio = pd.read_csv('start_portfolio.csv', index_col=0) # 自定义起始日期 start_date = '2022-06-27' # 读取交易记录表 trades = pd.read_csv('trades.csv', index_col=0) # 提取交易日期部分 trades['Date'] = pd.to_datetime(trades['Date/Time']).dt.date # 按日期和股票合并交易数据 daily_trades = trades.groupby(['Date', 'Symbol']).agg({'Quantity': 'sum', 'Comm/Fee': 'sum'}).reset_index()
2. 构建逐日持仓数据
# 初始化起始持仓字典 current_holdings = start_portfolio.set_index('Symbol')['Quantity'].to_dict() # 确定交易记录的最晚日期 end_date = trades['Date'].max() # 生成连续日期序列 date_range = pd.date_range(start=start_date, end=end_date).date # 存储每日持仓和手续费数据 daily_holdings = [] daily_fees = [] for date in date_range: # 筛选当日交易 day_trades = daily_trades[daily_trades['Date'] == date] total_fee = day_trades['Comm/Fee'].sum() if not day_trades.empty else 0 # 更新持仓 for _, trade in day_trades.iterrows(): symbol = trade['Symbol'] qty_change = trade['Quantity'] if symbol in current_holdings: current_holdings[symbol] += qty_change else: current_holdings[symbol] = qty_change # 持仓为0则移除该股票 if current_holdings[symbol] == 0: del current_holdings[symbol] # 保存当日数据 daily_holdings.append({'Date': date, **current_holdings.copy()}) daily_fees.append({'Date': date, 'Total_Fee': total_fee}) # 转成DataFrame格式 daily_holdings_df = pd.DataFrame(daily_holdings).fillna(0).set_index('Date') daily_fees_df = pd.DataFrame(daily_fees).set_index('Date')
3. 计算每日组合价值与个股贡献度
# 获取所有涉及的股票代码 all_symbols = list(set(start_portfolio['Symbol'].tolist() + trades['Symbol'].tolist())) # 下载历史收盘价数据 price_data = yf.download(all_symbols, start=start_date, end=pd.to_datetime(end_date)+pd.Timedelta(days=1))['Close'] price_data.index = price_data.index.date # 计算单股票每日价值 daily_value_df = daily_holdings_df * price_data # 计算组合总价值(扣除累计手续费) daily_value_df['Total_Value'] = daily_value_df.sum(axis=1) - daily_fees_df['Total_Fee'].cumsum() # 计算每日组合涨跌幅 daily_value_df['Daily_Return'] = daily_value_df['Total_Value'].pct_change() # 计算个股对每日涨跌的贡献度 for symbol in all_symbols: if symbol in daily_value_df.columns: daily_value_df[f'{symbol}_Contribution'] = (daily_value_df[symbol].diff()) / daily_value_df['Total_Value'].shift(1)
内容的提问来源于stack exchange,提问作者trondheim
相关产品推荐
相关产品推荐

