zipline中benchmarks源码分析
1 benchmark 基准数据
zipline默认使用的回测基准数据是美国的标普500,可以通过两种方式来设置:
A、在初始化TradingEnvironment的时候使用bm_symbol参数来设置,基准数据的数据源通过csv获取;
B、在策略代码里通过 set_benchmark函数设置,基准数据直接使用本地的数据。
国内的基准数据要使用国内市场的指数,如上交所要使用上证综指。
注意,zipline在运行时对数据的要求比较严格,特别是基准数据,不能缺失,否则可能会导致异常。
我们打开data/benchmarks.py文件,跳过头部的授权信息和依赖项。
2 get_benchmark_returns_from_file 从文件中获取基准数据
get_benchmark_returns_from_file 从文件中获取基准数据,文件是包含基准数据的csv文件,格式为【时间】【基准数据】。
csv文件内容示例如下:
date,return
2020-01-02 00:00:00+00:00,0.01
2020-01-03 00:00:00+00:00,-0.02
def get_benchmark_returns_from_file(filelike):
"""
Get a Series of benchmark returns from a file
Parameters
----------
filelike : str or file-like object
Path to the benchmark file.
expected csv file format:
date,return
2020-01-02 00:00:00+00:00,0.01
2020-01-03 00:00:00+00:00,-0.02
"""
log.info("Reading benchmark returns from {}", filelike)
df = pd.read_csv( # 读取csv文件
filelike, # csv文件
index_col=['date'], # 索引列
parse_dates=['date'], # 指定date列为时间类型
).tz_localize('utc')
if 'return' not in df.columns: # 检查return列数据
raise ValueError("The column 'return' not found in the "
"benchmark file \n"
"Expected benchmark file format :\n"
"date, return\n"
"2020-01-02 00:00:00+00:00,0.01\n"
"2020-01-03 00:00:00+00:00,-0.02\n")
return df['return'].sort_index() # 按时间列排序,返回基准数据的时序回报数据
3 BenchmarkSpec 基准数据操作类
我们在utils/run_algo.py的class BenchmarkSpec(object):中找到了对get_benchmark_returns_from_file的调用。BenchmarkSpec 类提供了对基准数据的操作
class BenchmarkSpec(object):
3.1 init 初始化
"""
Helper for different ways we can get benchmark data for the Zipline CLI and
zipline.utils.run_algo.run_algorithm.
Parameters
----------
benchmark_returns : pd.Series, optional
Series of returns to use as the benchmark.
benchmark_file : str or file
File containing a csv with `date` and `return` columns, to be read as
the benchmark.
benchmark_sid : int, optional
Sid of the asset to use as a benchmark.
benchmark_symbol : str, optional
Symbol of the asset to use as a benchmark. Symbol will be looked up as
of the end date of the backtest.
no_benchmark : bool
Flag indicating that no benchmark is configured. Benchmark-dependent
metrics will be calculated using a dummy benchmark of all-zero returns.
"""
def __init__(self,
benchmark_returns,
benchmark_file,
benchmark_sid,
benchmark_symbol,
no_benchmark):
初始化,代码中的参数有详细说明,我们来理解下:
参数 | 类型 | 可选必选 | 说明 |
---|---|---|---|
benchmark_returns | pd.Series | 可选 | 时序基准回报数据 |
benchmark_file | 文件 | 必选 | 包含 date 和 return 字段的csv基准文件 |
benchmark_sid | 整型 | 可选 | |
benchmark_symbol 字符型 | 可选 | 股票代码 | |
no_benchmark | 布尔型 | 必选 | 未配置基准数据的标志。依赖基准数据的指标将采用0回报基准来进行计算 |
self.benchmark_returns = benchmark_returns
self.benchmark_file = benchmark_file
self.benchmark_sid = benchmark_sid
self.benchmark_symbol = benchmark_symbol
self.no_benchmark = no_benchmark
3.2 from_cli_params 从Cli参数获取cls
从Cli参数获取cls,不设置基准回报数据:
@classmethod
def from_cli_params(cls,
benchmark_sid,
benchmark_symbol,
benchmark_file,
no_benchmark):
return cls(
benchmark_returns=None,
benchmark_sid=benchmark_sid,
benchmark_symbol=benchmark_symbol,
benchmark_file=benchmark_file,
no_benchmark=no_benchmark,
)
3.3 from_returns 从置基准回报数据获取cls
从置基准回报数据获取cls,只设置基准回报数据和未配置基准数据的标志:
@classmethod
def from_returns(cls, benchmark_returns):
return cls(
benchmark_returns=benchmark_returns,
benchmark_file=None,
benchmark_sid=None,
benchmark_symbol=None,
no_benchmark=benchmark_returns is not None,
)
3.4 resolve 获取回报数据
resolve,根据TradingAlgorithm传递过来的股票信息、时序起始时间,返回基准数据对应的股票ID和回报数据。
def resolve(self, asset_finder, start_date, end_date):
"""
Resolve inputs into values to be passed to TradingAlgorithm.
Returns a pair of ``(benchmark_sid, benchmark_returns)`` with at most
one non-None value. Both values may be None if no benchmark source has
been configured.
Parameters
----------
asset_finder : zipline.assets.AssetFinder
Asset finder for the algorithm to be run.
start_date : pd.Timestamp
Start date of the algorithm to be run.
end_date : pd.Timestamp
End date of the algorithm to be run.
Returns
-------
benchmark_sid : int
Sid to use as benchmark.
benchmark_returns : pd.Series
Series of returns to use as benchmark.
"""
if self.benchmark_returns is not None: # 有基准回报数据
benchmark_sid = None
benchmark_returns = self.benchmark_returns
elif self.benchmark_file is not None: # 没有基准回报数据,有基准数据文件
benchmark_sid = None
# 从基准数据文件中读取基准回报数据
benchmark_returns = get_benchmark_returns_from_file(
self.benchmark_file,
)
elif self.benchmark_sid is not None: # 有基准数据股票ID
benchmark_sid = self.benchmark_sid
benchmark_returns = None
elif self.benchmark_symbol is not None: # 有基准数据股票代码
try:
# 从股票信息中根据股票代码查找对应的股票ID
asset = asset_finder.lookup_symbol(
self.benchmark_symbol,
as_of_date=end_date,
)
benchmark_sid = asset.sid
benchmark_returns = None
except SymbolNotFound:
raise _RunAlgoError(
"Symbol %s as a benchmark not found in this bundle."
)
elif self.no_benchmark: # 没有基准数据
benchmark_sid = None
benchmark_returns = self._zero_benchmark_returns(
start_date=start_date,
end_date=end_date,
)
else:
# 警告日志:未配置基准数据,可以通过algorithm调用set_benchmark函数设置
log.warn(
"No benchmark configured. "
"Assuming algorithm calls set_benchmark."
)
# 警告日志:基准数据回报需要设置基准数据对应的股票ID、股票代码、数据文件
log.warn(
"Pass --benchmark-sid, --benchmark-symbol, or"
" --benchmark-file to set a source of benchmark returns."
)
# 警告日志:基准数据零回报需要设置no-benchmark
log.warn(
"Pass --no-benchmark to use a dummy benchmark "
"of zero returns.",
)
benchmark_sid = None
benchmark_returns = None
return benchmark_sid, benchmark_returns
上面代码中的参数有详细说明,我们来理解下:
参数 | 类型 | 说明 |
---|---|---|
asset_finder | zipline.assets.AssetFinder | algorithm 运行时需要使用的股票信息 |
start_date | date | algorithm 运行时的时序开始时间 |
end_date | date | algorithm 运行时的时序结束时间 |
上面代码中的返回信息有详细说明,我们来理解下:
返回信息 | 说明 |
---|---|
benchmark_sid | 基准数据对应的股票ID |
benchmark_returns | 基准数据对应的股票的回报数据 |
3.5 _zero_benchmark_returns 获取零基准数据回报
@staticmethod
def _zero_benchmark_returns(start_date, end_date):
return pd.Series(
index=pd.date_range(start_date, end_date, tz='utc'),
data=0.0,
)