我正在实现一个小型 Python 应用程序来衡量交易策略的返回。计算返回的函数采用以下输入:
- 包含收盘价的 Pandas 数据框
- 代表买入信号的 Pandas 系列 bool 值
- 代表卖出信号的 Pandas 系列 bool 值
- 代表交易费用占初始资本百分比的 float
这是数据的样子:
>>> df.head()
open high low close volume
date
2015-01-02 5.34 5.37 5.11 5.21 108469
2015-01-05 5.21 5.26 4.85 4.87 160089
2015-01-06 4.87 4.87 4.55 4.57 316501
2015-01-07 4.63 4.75 4.60 4.67 151117
2015-01-08 4.69 4.89 4.69 4.81 159294
>>>
>>> buy.head()
2015-01-02 True
2015-01-05 False
2015-01-06 False
2015-01-07 False
2015-01-08 False
dtype: bool
>>>
在不考虑费用的情况下,这是计算比率的公式:
其中 C
是初始资本,ri
是一笔买卖交易的返回。
这可以使用矢量化实现轻松实现:
buy_sell = df[(buy==True)|(sell==True)]
prices = buy_sell.close
diffs = prices - prices.shift()
ratios = diffs / prices.shift()
return ((ratios + 1).product(axis=0))
当考虑到费用时,我最终得出以下公式:
其中 f
是交易费用。
这可以很容易地使用循环来实现,但是有没有办法通过矢量化实现来做到这一点?
我不是数学专家,但也许依赖于求和索引的乘积可以防止这种情况发生?我尝试在网上查看此属性,但似乎找不到任何内容。也许我没有正确地提出问题,因为我缺乏技术术语。
对此有任何想法将不胜感激:)
编辑
根据 DSM 的回答,解决方案是对反转的一系列比率执行“累积乘积”。这给了我以下解决方案:
def compute_return(df, buy, sell, fees=0.):
# Bunch of verifications operation performed on data
buy_sell = df[(buy==True)|(sell==True)]
prices = buy_sell.close
diffs = prices - prices.shift()
ratios = diffs / prices.shift()
cum_prod = (ratios + 1)[1:][::-1].cumprod()
return ((1 - fees) * (ratios + 1).product(axis=0) - fees * cum_prod.sum())
最佳答案
我认为这不是那么糟糕。来自比率
,如
In [95]: ratios
Out[95]:
date
2015-01-02 NaN
2015-01-05 -0.065259
2015-01-06 -0.061602
2015-01-07 0.021882
2015-01-08 0.029979
Name: close, dtype: float64
我们有(这里我们只关注“新的”第二个任期):
def manual(rs):
return sum(np.prod([1+rs.iloc[j] for j in range(i, len(rs))])
for i in range(2, len(rs)))
和
def vectorized(rs):
rev = 1 + rs.iloc[2:].iloc[::-1]
return rev.cumprod().sum()
也就是说,我们需要做的就是从头到尾取相反方向的累积乘积的总和。
这给了我:
In [109]: manual(ratios)
Out[109]: 3.07017466956023
In [110]: vectorized(ratios)
Out[110]: 3.07017466956023
(我没有太在意担心我们应该使用 2 还是 1 作为此处的偏移量,或者放入 f
因子——这些都是简单的更改。)
关于python - 递减范围内的乘积之和,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51640628/