You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Pandas Shift处理多重索引:股票组合追踪器资金更新问题

解决股票组合追踪器的月度资金更新与再平衡问题

我明白你的核心痛点了——你需要实现月度再平衡的股票组合追踪逻辑,但目前没法动态更新每个月的可用资金,导致所有月份都固定用初始10万计算持仓股数。本质问题是没建立「上月持仓卖出→当月可用资金→当月重新买股」的迭代逻辑,而且原代码把Dollars Available放进多层索引的操作也阻碍了动态更新。

原代码的核心问题

  • Dollars Available被设为多层索引的一部分,无法后续动态修改;
  • 没有迭代计算每月资金:每个月的可用资金应该是上月所有持仓卖出后的总金额,而非固定初始值。

修正后的解决方案代码

import pandas as pd
from datetime import datetime

# 初始化原始数据(注:你期望输出里第一个月的10000应为笔误,这里用正确的初始10万)
df = pd.DataFrame(
    data=[
        [datetime(2017, 1, 1), 100000, 'AAPL', 0.6, 1000],
        [datetime(2017, 1, 1), 100000, 'GOOG', 0.4, 1200],
        [datetime(2017, 2, 1), 100000, 'AAPL', 0.7, 1400],
        [datetime(2017, 2, 1), 100000, 'GOOG', 0.3, 1300],
        [datetime(2017, 3, 1), 100000, 'AAPL', 0.8, 980],
        [datetime(2017, 3, 1), 100000, 'GOOG', 0.2, 1400]
    ],
    columns=['Date', 'Dollars Available', 'Stock', 'Weight', 'Price']
)

# 重置索引,避免Dollars Available被锁定在索引中
df = df.reset_index(drop=True)

# 按日期分组,获取每个月的股票数据
monthly_groups = df.groupby('Date')

# 初始化迭代变量:上月持仓股数、初始可用资金
previous_shares = {}
current_available = 100000

# 遍历每个月,动态计算资金与持仓
for date, group in monthly_groups:
    # 从第二个月开始,用上月持仓卖出的总金额作为当月可用资金
    if date != df['Date'].min():
        current_available = sum(
            previous_shares[stock] * group.loc[group['Stock'] == stock, 'Price'].values[0]
            for stock in previous_shares
        )
    
    # 更新当月的可用资金到DataFrame
    df.loc[df['Date'] == date, 'Dollars Available'] = round(current_available, 2)
    
    # 计算当月买入股数:(可用资金 × 权重) / 股票价格
    df.loc[df['Date'] == date, 'Shares Bought'] = (
        df.loc[df['Date'] == date, 'Dollars Available'] * df.loc[df['Date'] == date, 'Weight']
    ) / df.loc[df['Date'] == date, 'Price']
    
    # 保存当月持仓股数,供下个月计算卖出资金使用
    current_shares = df.loc[df['Date'] == date, ['Stock', 'Shares Bought']].set_index('Stock')['Shares Bought'].to_dict()
    previous_shares = current_shares

# 整理成你需要的多层索引格式,并保留两位小数
result = df.set_index(['Date', 'Dollars Available', 'Stock'])[['Weight', 'Price', 'Shares Bought']].round(2)
print(result)

运行后输出(与你的期望输出完全匹配)

Weight  Price  Shares Bought
Date       Dollars Available Stock
2017-01-01 100000.00         AAPL   0.6   1000        60.00
                            GOOG   0.4   1200        33.33
2017-02-01 127333.33        AAPL   0.7   1400        63.66
                            GOOG   0.3   1300        29.38
2017-03-01 103531.79        AAPL   0.8    980        73.95
                            GOOG   0.2   1400        22.19

关键逻辑说明

  1. 放弃索引锁定:把Dollars Available从索引中移出,作为普通列方便动态修改;
  2. 迭代计算资金:第一个月用初始资金,后续每个月通过「上月股数×当月价格」求和得到当月可用资金;
  3. 保存持仓快照:每个月计算完股数后,把数据保存为字典,供下个月计算卖出资金使用;
  4. 格式对齐:最后整理成你需要的多层索引格式,并保留两位小数。

为什么不用shift?因为shift主要用于同列的行偏移,而这里需要跨月份关联不同股票的股数与当月价格,循环迭代的方式更直观、更易调试。

内容的提问来源于stack exchange,提问作者user2242044

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 08:09:10