如何修复 pyfolio的报错 ?
AttributeError: 'numpy.int64' object has no attribute 'to_pydatetime'
最近使用Python跑回测,环境是Python+backtrader+pandas+pyfolio
Python 3.11.2
Name: pandas
Version: 2.0.0
Name: pyfolio
Version: 0.9.2
Name: backtrader
Version: 1.9.76.123
是如何引发报错的?
在执行以下语句的时候报错,位置是timeseries.py:1008
import pyfolio as pf
pf.create_full_tear_sheet(returns)
File ~\PycharmProjects\pythonProject\venv\Lib\site-packages\pyfolio\timeseries.py:1008, in gen_drawdown_table(returns, top)
1003 df_drawdowns.loc[i, 'Duration'] = len(pd.date_range(peak,
1004 recovery,
1005 freq='B'))
1006 df_drawdowns.loc[i, 'Peak date'] = (peak.to_pydatetime()
1007 .strftime('%Y-%m-%d'))
-> 1008 df_drawdowns.loc[i, 'Valley date'] = (valley.to_pydatetime()
1009 .strftime('%Y-%m-%d'))
1010 if isinstance(recovery, float):
1011 df_drawdowns.loc[i, 'Recovery date'] = recovery
AttributeError: 'numpy.int64' object has no attribute 'to_pydatetime'
报了什么错?
报错是因为valley是一个numpy.int64的类型,没有to_pydatetime的属性,但是peak是有该属性的,
因此追踪该属性出现的方法:pyfolio.timeseries.get_max_drawdown_underwater
借助new bing 翻译该方法含义
def get_max_drawdown_underwater(underwater):
"""
Determines peak, valley, and recovery dates given an 'underwater'
DataFrame.
An underwater DataFrame is a DataFrame that has precomputed
rolling drawdown.
Parameters
----------
underwater : pd.Series
Underwater returns (rolling drawdown) of a strategy.
Returns
-------
peak : datetime
The maximum drawdown's peak.
valley : datetime
The maximum drawdown's valley.
recovery : datetime
The maximum drawdown's recovery.
"""
valley = np.argmin(underwater) # end of the period # 找到 underwater 中最小值的索引,表示回撤期间的最低点,并赋值给 valley
# Find first 0
peak = underwater[:valley][underwater[:valley] == 0].index[-1] # 找到 underwater 从开始到 valley 索引的部分数据中第一个等于 0 的元素的索引,表示回撤期间的最高点,并赋值给 peak
# Find last 0
try:
recovery = underwater[valley:][underwater[valley:] == 0].index[0] # 尝试找到 underwater 从 valley 索引开始的部分数据中第一个等于 0 的元素的索引,表示回撤期间的恢复点,并赋值给 recovery
except IndexError: # 如果没有找到这样的元素,就抛出 IndexError 异常
recovery = np.nan # drawdown not recovered # 把 recovery 赋值为 np.nan,表示回撤没有恢复
return peak, valley, recovery # 返回 peak, valley, recovery 这三个变量的值
通过debug发现,peak、recovery
,分别都获取到了 underwater : pd.Series
的索引,是一个日期datetime
格式。
只有valley
是获取了underwater : pd.Series
索引对应的值,是一个numpy.int64
的格式。
pd.Series
是什么?
[Series 是 Python 中的一种数据结构,它是 pandas 库中提供的一种带标签的一维数组,可以存储任意数据类型,如整数、浮点数、字符串、Python 对象等] (zhuanlan.zhihu.com/p/131553804… 的每个元素都有一个索引,可以是默认的从 0 开始的整数,也可以是自定义的标签](zhuanlan.zhihu.com/p/131553804… 可以用于数据分析和处理,提供了很多方便的方法和属性](pandas.pydata.org/pandas-docs…
通过newbing的解释结合debug,可以获知: underwater : pd.Series
索引是datetime
日期,元素是numpy.int64
而该方法注释里说明了: valley : datetime The maximum drawdown's valley.
他的期望是一个datetime
,实际却是一个numpy.int64
,答案已经呼之欲出。
应该如何修改?
如何获取series某个下标的索引?
通过newbing 学习到
有两种方法可以获取 series 某个下标的索引:
- 使用 index 属性,它返回一个包含所有索引值的列表,然后用下标访问列表中的元素。例如,如果 s 是一个 series 对象,那么 s.index [0] 就表示第一个索引值,s.index [-1] 就表示最后一个索引值。
- 使用 iloc 属性,它返回一个索引器对象,可以用下标访问 series 中的元素。然后用 name 属性,可以获取元素对应的索引值。例如,如果 s 是一个 series 对象,那么 s.iloc [0].name 就表示第一个元素的索引值,s.iloc [-1].name 就表示最后一个元素的索引值。
valley的索引可以通过如下代码获取:
underwater.index[valley]
那么,只需要把最后一行的返回值修改一下就可以了:
def get_max_drawdown_underwater(underwater):
valley = np.argmin(underwater) # end of the period
# Find first 0
peak = underwater[:valley][underwater[:valley] == 0].index[-1]
# Find last 0
try:
recovery = underwater[valley:][underwater[valley:] == 0].index[0]
except IndexError:
recovery = np.nan # drawdown not recovered
return peak, underwater.index[valley], recovery
声明:
我的原来的技术栈是Android那块的,
Python跑回测是最近萌生的想法,连语法都不懂,学习中,
如果有不对的地方欢迎批评指正。
原文链接:https://juejin.cn/post/7228071726205763641 作者:Wesley3414