量化投资研究服务平台提供了相应的因子构建模块。因子构建是多因子模型的基石,是否能够准确、快速、方便的构建出因子决定了多因子研究的效率和准确性。
因子,可以看做股票的一种特征,这种特征可能预示着股价未来的涨势。 举个简单的小例子,如果想猜测明天的天气如何,我们可以看看云彩的形状,如果万里无云,我们可以大概率认为明天就是晴天,如果现在风非常大,那么接下来的几个小时或者明天非常有可能下雨。
比如一个企业的利润其实也是一种非常强的特征,如果利润非常高,那么我们一般会认为利润高的股票会有更多人来买,那么股票供不应求,价格自然上涨。但是这里存在一个问题,如果一个市值100亿的公司和市值1000亿的公司利润都是10个亿,那么仅仅凭借利润这个绝对值我们很难区分,一般我们会除以他们的市值做个scale。
所以不严谨的总结就是:因子就是股票的特征,这种特征主要用来预测收益,并进行选股。
理论上所有跟股票相关的数据都可以做成因子。但是常见的主要有:
目前可以通过QuoteFeed这个类获取成交量和行情价格的数据,通过FinancialFeed获取财务数据相关的数据
因子的构建需要自己创建一个类,改类需要继承平台提供的BaseFactor类。
factor_name
: 因子的名字。factor_direction
: 因子的方向, 1为升序,即因子值越小,因子排名越靠前。factor_parameters
: 因子需要的其他的参数,python dict类型tickers
: list类型的股票代码列表,如[‘000001.SZ’, ‘600000.SH’]用户自己仅仅需要写下面两个函数即可完成因子的定义:
这个函数主要用于因子计算前的数据准备,begin_day和end_day为string类型的日期。
Attention:
某些因子需要将begin_day向前扩展。例如:如果计算20170601~20170701这一个月期间的60日价格动量。那么begin_day应该向前移动60天,实际开始时间应该为20170401.
因子核心的计算逻辑都在这个函数里实现,这个函数默认所有需要的数据都已经准备好了。
传入的参数为某个交易日,返回的是该交易日的因子数据。
返回数据类型是pandas.series,indx为ticker,value为因子值。
当前面的代码逻辑都已经写好了,那么就可以调用基类BaseFactor中的generate_factor_and_store(from_dt, to_dt)方法来生成因子了。from_dt代表开始日期,to_dt代表结束日期。都是string类型,如“20170101”。
下面是60日动量的一个简单示例,计算全A股20170501~20170929之间的60日动量。
from smartbeta.factorbase import BaseFactor
from data_provider.datafeed.quote_feed import QuoteFeed
import pandas as pd
from data_provider.nestlib.trading_cal import TradeCal
from data_provider.datafeed.universe import Universe
from datetime import datetime
class Momentum(BaseFactor):
def __init__(
self,
factor_name="Momentum",
factor_direction=-1,
factor_parameters={"lagTradeDays": 60},
tickers=None,
):
super(Momentum, self).__init__(
factor_name=factor_name,
factor_direction=factor_direction,
factor_parameters=factor_parameters,
tickers=tickers,
)
def _prepare_data(self, begin_date, end_date):
begin_day = TradeCal().shift_date(
str(begin_date), self._factor_param["lagTradeDays"]
) # 多取一些数据做填充
freq = Frequency.DAY
qt_feed = QuoteFeed(
self.tickers, begin_day, end_date, freq, "forward", columns=["close"]
)
qt_feed.load_feed()
quote_panel = qt_feed.getBarPanel()
self.quote_panel = quote_panel.close.fillna(method="ffill")
def _generate_factor(self, end_day):
"""
计算增量因子数据
:param end_day:因子生产的日期
这里需要生成一个series类型的结构,indx为ticker,value为因子值
"""
begin_day = TradeCal().shift_date(
str(end_day), self._factor_param["lagTradeDays"]
) # 需要交易日历相关的函数的支持
close_df = self.quote_panel[
(self.quote_panel.index >= str(begin_day))
& (self.quote_panel.index <= str(end_day))
]
ret = close_df.tail(1).squeeze() / close_df.head(1).squeeze() - 1.0
return ret
if __name__ == "__main__":
from_dt = "20170501"
to_dt = "20170929"
allAShare = Universe().get_a_share_in_period(from_dt, to_dt) # 获取该区间段中所有的A股股票列表
momentum_60M = Momentum(
factor_name="Momentum_60M",
factor_direction=1,
factor_parameters={"lagTradeDays": 60},
tickers=allAShare,
)
momentum_60M.generate_factor_and_store(from_dt, to_dt)
# momentum_60M.del_factor() # 从数据库中清空因子
当因子创建一段时间后,该因子的相关信息基本会很容易忘记。这里强烈建议调用add_factor_definition对这个因子加入因子定义。
主要包含以下信息:
param category
: 因子大类param create_by
: 创建者param description
: 描述param cal_alg
: 计算方法param create_time
: 创建时间,如果为None值,就填充为当前时间因为因子定义的时候已经含有名字和因子的方向,所以调用上面这个接口后,也会将因子名和方向加入数据库中。
如果已创建的因子描述信息有误,可以调用del_factor_definition将这个因子的定义删除。
momentum_60M.add_factor_definition(
category="Momentum",
create_by="idwzx",
description="60日动量,测试只用",
cal_alg="这里是计算方法,忽略",
)
因子的基类提供了一个load方法,从数据库中读取因子数据:
factor_name
: 因子的名称begin_day
: 开始日期,int类型YYYYMMDD, 也可以是datetime/strend_day
: 结束日期,int类型YYYYMMDD, 也可以是datetime/strticker
: 股票代码。如果没有传入ticker的list,默认取出所有股票的因子值use_cache
: 是否使用缓存,default False 使用缓存数据将极大加快因子读取速度,但是当因子数值发生改变时,使用缓存会导致数据不一致,建议对于平台提供的因子或是完成开发的因子使用缓存,而对于用户正在开发的因子和可能频繁发生改变的因子,建议不要使用缓存。通过del_factor()可以删除全部因子数据以及相应缓存。momentum_60M.load(from_dt, to_dt)
在因子写完计算存入数据库后,投研平台提供了几种工具来使用因子
微信扫码分享本页