Pandas动态行基股票计算

3 投票
1 回答
519 浏览
提问于 2025-04-18 12:03

我一直在绞尽脑汁,想弄清楚这个问题的最佳解决办法。我在Excel中有一个运行很慢的回测工具,现在想把它转到pandas上。我原以为可以利用Python的强大功能,而不仅仅是把Excel的功能重新做一遍,但我现在卡住了!

主要的挑战在于如何计算投资组合的盈亏,这涉及到多个不断变化的投资工具。例如,根据某些标准,我想在前N个时间段内购买A和C这两个工具。接着在接下来的N个时间段内使用B和C。以此类推。我想根据当前的资金比例购买每个工具,而不是每次都买100股之类的。

在Excel中,行基础的函数首先根据初始资金计算股票数量,然后根据“上一行”的可用资金进行计算。大致是这样的:IF(RebalancePeriod = TRUE, EquityFromPrevRow / CurrentSharePrice, PreviousRowShares)

我尝试把它转到pandas上。这是一些输入示例:

import datetime as dt
import pandas as pd
from pandas import *

dates = date_range('1/1/2000', periods=6)
index=dates
data = {'A': pd.Series([20, 30, 10, 0, 0, 0], index=index)
    , 'B': pd.Series([0, 0, 0, 50, 51, 52], index=index)
    , 'C': pd.Series([11, 12, 20, 18, 17, 19], index=index)}

initial_capital = 5000.0

prices = pd.DataFrame(data, index=dates)

这并没有帮助太多,但这是我想要的输出结果。在这个例子中,我想在第4行,也就是2000年1月4日时,通过从A换到B来重新平衡投资工具,此后A的数量为0。

Prices          
            A   B   C
2000-01-01  20  0   11
2000-01-02  30  0   12
2000-01-03  10  0   20
2000-01-04  0   50  18
2000-01-05  0   51  17
2000-01-06  0   52  19

Shares (initial or current equity / price)          
            A       B       C
2000-01-01  250.0   0.0     454.5
2000-01-02  250.0   0.0     454.5
2000-01-03  250.0   0.0     454.5
2000-01-04  0.0     115.9   322.0
2000-01-05  0.0     115.9   322.0
2000-01-06  0.0     115.9   322.0


Equity (shares * price)             
            A       B       C       Total
2000-01-01  5,000.0 0.0     5,000.0 10,000.0
2000-01-02  7,500.0 0.0     5,454.5 12,954.5
2000-01-03  2,500.0 0.0     9,090.9 11,590.9
2000-01-04  0.0     5,795.5 5,795.5 11,590.9
2000-01-05  0.0     5,911.4 5,473.5 11,384.8
2000-01-06  0.0     6,027.3 6,117.4 12,144.7

我意识到这个问题涉及的内容很多。非常感谢任何帮助。谢谢!

1 个回答

1

只需遵循你在 Excel 中使用的相同思路,唯一的区别是,现在应用于每一行的 excel 函数 被表示为一个循环:

In [113]:

print prices
             A   B   C
2000-01-01  20   0  11
2000-01-02  30   0  12
2000-01-03  10   0  20
2000-01-04   0  50  18
2000-01-05   0  51  17
2000-01-06   0  52  19
In [114]:
swap=pd.Series([False,]*len(dates),index=dates, name='sawp')
swap[3]=True
total=pd.DataFrame({'A':0, 'B':0, 'C':0},index=dates)
total.ix[0]=[5000,5000,5000]
shares=total/prices
shares['swap']=swap
In [115]:
#the loop
for idx in range(1, len(shares)):
    if shares.ix[idx, 'swap']:
        shares.ix[idx, ['A','B','C']]=(shares.ix[idx-1, ['A','B','C']]*prices.ix[idx-1]).sum()/2/prices.ix[idx]
    else:
        shares.ix[idx, ['A','B','C']]=shares.ix[idx-1, ['A','B','C']]
In [116]:
#Get rid of the infinite numbers
shares[shares==np.inf]=0
In [117]:

print shares
              A           B           C   swap
2000-01-01  250    0.000000  454.545455  False
2000-01-02  250    0.000000  454.545455  False
2000-01-03  250    0.000000  454.545455  False
2000-01-04    0  115.909091  321.969697   True
2000-01-05    0  115.909091  321.969697  False
2000-01-06    0  115.909091  321.969697  False
In [118]:

print shares*prices
               A            B            C  swap
2000-01-01  5000     0.000000  5000.000000   NaN
2000-01-02  7500     0.000000  5454.545455   NaN
2000-01-03  2500     0.000000  9090.909091   NaN
2000-01-04     0  5795.454545  5795.454545   NaN
2000-01-05     0  5911.363636  5473.484848   NaN
2000-01-06     0  6027.272727  6117.424242   NaN
In [119]:
#Total asserts
print (shares*prices).sum(1)
2000-01-01    10000.000000
2000-01-02    12954.545455
2000-01-03    11590.909091
2000-01-04    11590.909091
2000-01-05    11384.848485
2000-01-06    12144.696970
Freq: D, dtype: float64

撰写回答