BigQuant AI策略详解

宽客学院
标签: #<Tag:0x00007f5be90dfbf0>

(iQuant) #1

导语:AI策略和传统的量化策略有很大差异,本文根据策略背后代码详细讲解AI策略,了解AI策略运行机制。


作者: bigquant
阅读时间:10分钟
本文由BigQuant宽客学院推出,难度标签:☆☆☆

前面我们通过可视化策略模板或者策略生成器,可以快速开发出一个AI策略,我们来详细解读一下策略的代码。

看看下面这个简单的AI策略抽象流程示意图,将帮助我们来理解AI策略代码。

一.基础配置

这些配置将在后续用到:

  1. start_date 和 end_date 确定了我们要用数据段
    其中 [start_date, split_date) 区间的数据,用于模型训练
    [split_date, end_date] 区间的数据,用户模型回测

  2. instruments:股票池,D.instruments(start_date, split_date) 取A股给定时间段内所有出现过的股票。

  3. label_expr,用户标注的函数,更多说明见下面关于 M.advanced_auto_labeler的介绍。

  4. hold_days:持仓时间,用于数据标注和回测,具体见下面相关模块使用

  5. features:特征 (因子),具体见下面相关模块使用

class conf:
    start_date = '2014-01-01'
    end_date='2017-07-17'
    split_date = '2015-01-01'
    instruments = D.instruments(start_date, end_date)
    hold_days = 5
    features = [
        'close_5/close_0',  # 5日收益
        'close_10/close_0',  # 10日收益
        'close_20/close_0',  # 20日收益
        'avg_amount_0/avg_amount_5',  # 当日/5日平均交易额
        'avg_amount_5/avg_amount_20',  # 5日/20日平均交易额
        'rank_avg_amount_0/rank_avg_amount_5',  # 当日/5日平均交易额排名
        'rank_avg_amount_5/rank_avg_amount_10',  # 5日/10日平均交易额排名
        'rank_return_0',  # 当日收益
        'rank_return_5',  # 5日收益
        'rank_return_10',  # 10日收益
        'rank_return_0/rank_return_5',  # 当日/5日收益排名
        'rank_return_5/rank_return_10',  # 5日/10日收益排名
        'pe_ttm_0',  # 市盈率TTM
    ]
    # 数据标注
    label_expr = [
    # 计算未来一段时间(hold_days)的相对收益
    'shift(close, -5) / shift(open, -1) - shift(benchmark_close, -5) / shift(benchmark_open, -1)',
    # 极值处理:用1%和99%分位的值做clip
    'clip(label, all_quantile(label, 0.01), all_quantile(label, 0.99))',
    # 将分数映射到分类,这里使用20个分类,这里采取等宽离散化
    'all_wbins(label, 20)',
    # 过滤掉一字涨停的情况 (设置label为NaN,在后续处理和训练中会忽略NaN的label)
    'where(shift(high, -1) == shift(low, -1), NaN, label)'
    ]

示例解读:

  1. shift(close, -5) / shift(open, -1) - shift(benchmark_close, -5) / shift(benchmark_open, -1):未来5天的相对收益率(股票收益率减去基准收益率),其中shift(close,-5)为未来5天的收盘价,shift(open,-1)为明天的开盘价,基准同理。
  2. clip:clip用于极值处理,上面的例子就是将1%分位数和99%分位数以外的数据进行裁剪
  3. all_wbins:对连续性的标注数据进行离散化,上面的例子是将标注数据分为20类。详情请参考:表达式引擎
  4. where(shift(high, -1) == shift(low, -1), NaN, label):过滤掉一字涨停的情形

二.数据标注

之前采取的是M.fast_auto_labeler进行数据标注,但如果要使用表达式引擎构建因子、数据标注,建议使用功能更为强大的M.advanced_auto_labeler进行数据标注。

# 给数据做标注:给每一行数据(样本)打分,一般分数越高表示越好
m1 = M.advanced_auto_labeler.v1(
                               instruments=conf.instruments, start_date=conf.start_date, end_date=conf.split_date,
                               label_expr=conf.label_expr, benchmark='000300.SHA', cast_label_int=True)

示例解读:

  1. label_expr:表示通过conf类中的标注语句进行数据标注
  2. benchmark:对数据进行标注的时候,偶尔会用到基准数据,因此需要制定基准
  3. cast_label_int:标注结果是否转换为整数;默认值是True

三.基础特征抽取

机器学习算法很大程度上依赖于特征工程,AI策略同样如此,特征抽取地好,对收益率的预测将更加准确。 有些因子的基础因子,直接可以抽取。

m2 = M.general_feature_extractor.v5(
    instruments=conf.instruments, start_date=conf.start_date, end_date=conf.end_date,
    features=conf.features)

详情请参考文档:基础特征抽取

四.衍生特征抽取

很多AI策略的特征并不是简单的基础特征,而是由基础特征衍生计算出来的衍生特征。

# 计算衍生特征
m2_1 = M.derived_feature_extractor.v1(data=m2.data, features=conf.features)

详情请参考文档:衍生特征抽取

五.数据转换

如果你采用的模型是StockRanker,该算法需要对输入的特征作相应转换。如果你使用的是随机森林、线性SGD模型等,这一步可以省略。

m3 = M.transform.v2(data=m2_1.data, transforms=None, drop_null=True)

当然,在之前我们的AI策略是采取的 M.fast_auto_labeler进行数据标注,详解请点击展开。

点击查看代码

基础配置

这些配置将在后续用到:

  1. start_date 和 end_date 确定了我们要用数据段
    其中 [start_date, split_date) 区间的数据,用于模型训练
    [split_date, end_date] 区间的数据,用户模型回测

  2. instruments:股票池,D.instruments(start_date, split_date) 取A股给定时间段内所有出现过的股票。

  3. label_expr,用户标注的函数,更多说明见下面关于 M.fast_auto_labeler的介绍。

  4. hold_days:持仓时间,用于数据标注和回测,具体见下面相关模块使用

  5. features:特征 (因子),具体见下面相关模块使用


class conf:
    start_date = '2010-01-01'
    end_date='2017-01-01'
    # split_date 之前的数据用于训练,之后的数据用作效果评估
    split_date = '2015-01-01'
    # D.instruments: https://bigquant.com/docs/data_instruments.html
    instruments = D.instruments(start_date, split_date)

    # 机器学习目标标注函数
    # 如下标注函数等价于 min(max((持有期间的收益 * 100), -20), 20) + 20 (后面的M.fast_auto_labeler会做取整操作)
    # 说明:max/min这里将标注分数限定在区间[-20, 20],+20将分数变为非负数 (StockRanker要求标注分数非负整数)
    label_expr = ['return * 100', 'where(label > {0}, {0}, where(label < -{0}, -{0}, label)) + {0}'.format(20)]
    # 持有天数,用于计算label_expr中的return值(收益)
    hold_days = 5

    # 特征 https://bigquant.com/docs/#/datasource?id=%E5%9B%A0%E5%AD%90%E5%BA%93,你可以通过表达式构造任何特征
    features = [
        'close_5/close_0',  # 5日收益
        'close_10/close_0',  # 10日收益
        'close_20/close_0',  # 20日收益
        'avg_amount_0/avg_amount_5',  # 当日/5日平均交易额
        'avg_amount_5/avg_amount_20',  # 5日/20日平均交易额
        'rank_avg_amount_0/rank_avg_amount_5',  # 当日/5日平均交易额排名
        'rank_avg_amount_5/rank_avg_amount_10',  # 5日/10日平均交易额排名
        'rank_return_0',  # 当日收益
        'rank_return_5',  # 5日收益
        'rank_return_10',  # 10日收益
        'rank_return_0/rank_return_5',  # 当日/5日收益排名
        'rank_return_5/rank_return_10',  # 5日/10日收益排名
        'pe_ttm_0',  # 市盈率TTM
    ]

数据标注

为了使用有监督的机器学习算法,我们需要对数据做标注。M.fast_auto_labeler 是一个自动标注模块,具体使用说明见文档

# 给数据做标注:给每一行数据(样本)打分,一般分数越高表示越好
m1 = M.fast_auto_labeler.v8(
    instruments=conf.instruments, start_date=conf.start_date, end_date=conf.split_date,
    label_expr=conf.label_expr, hold_days=conf.hold_days,
    benchmark='000300.SHA', sell_at='open', buy_at='open')

示例解读:

  1. return * 100:表示将收益 * 100,比如某只股票,今天的收盘价是10元,5天后的收盘价是11.32元,则return = 13.2%,return * 100 = 13.2
  2. ‘where(label > {0}, {0}, where(label < -{0}, -{0}, label)) + {0}’.format(20):这个表达式,20带入之后是
    where(label > 20, 20, where(label < -20, -20, label)) + 20
    第一部分:where(label > 20, 20, where(label < -20, -20, label)),将数据裁剪到[-20, 20],即小于-20的用-20替换,大于20的用20替换
    第二部分:+20,则将整个值的范围变换到[0, 40]
 label_expr = ['return * 100', 'where(label > {0}, {0}, where(label < -{0}, -{0}, label)) + {0}'.format(20)]

特征抽取

机器学习算法很大程度上依赖于特征工程,AI策略同样如此,特征构建地好,对收益率的预测将更加准确。

# 计算特征数据
m2 = M.general_feature_extractor.v5(
    instruments=conf.instruments, start_date=conf.start_date, end_date=conf.split_date,
    features=conf.features)

示例解读:

  1. 特征抽取也可以称作因子抽取或者特征数据计算,接口的介绍参考 模块和API概览:特征抽取
  2. instruments=conf.instruments:表示计算哪些股票的特征数据。
  3. start_date=conf.start_date, end_date=conf.split_date :表示对什么时间段的股票数据计算特征。该时间段和训练集的时间段是一致的。
  4. features=conf.features:表示抽取哪些特征。

数据预处理

从上一步 特征抽取中,我们可以将特征数据抽取出来,但是计算出来的特征数据不一定满足机器学习算法的需要。StockRanker算法要求数据为正整数,因此需要对数据进行预处理。

m3 = M.transform.v2(
    data=m2.data, transforms=T.get_stock_ranker_default_transforms(),
    drop_null=True, astype='int32', except_columns=['date', 'instrument'],
    clip_lower=0, clip_upper=200000000)

示例解读:

  1. 不同的机器学习算法可能在数据预处理模块有所差异,StockRanker算法的接口的介绍参考 模块和API概览:特征转化
  2. data=m2.data:表示对什么数据进行数据预处理,一般为计算完成的特征数据。
  3. transforms=T.get_stock_ranker_default_transforms():表示进行怎样的数据预处理,具体的数据变换可以通过T.get_stock_ranker_default_transform()接口进行查询,transform是由正则表达式类型的变换函数组成的列表,对于输入数据的每一列,从transforms里依序寻找到匹配的表达式,用对应的变换函数对列数据做处理。
  4. 该接口其他的参数一般采用默认即可,详情请参考 [模块和API概览:特征转化]。(https://bigquant.com/docs/#/develop?id=数据变换)。

六.合并数据

通过数据标注和计算特征数据,我们获得了两个数据,只有同时包含这两部分数据的训练集才能完整地训练一个AI模型,因此需要进行数据合并。

# 合并标注和特征数据
m4 = M.join.v2(data1=m1.data, data2=m3.data, on=['date', 'instrument'], sort=True)

示例解读:

  1. 数据合并也成为数据连接,详情请参考 模块和API:数据连接
  2. data1=m1.data 表示:第一个需要连接的数据,例如标注数据。
  3. data2=m3.data 表示:第二个需要连接的数据,例如计算完成的特征数据。
  4. on=[‘date’, ‘instrument’] 表示:数据合并时使用的主要列。一般使用日期和股票代码就可以对数据进行合并。
  5. sort=True 表示:是否对合并数据的结果按on指定的列进行排序。

七.模型训练

当我们将标注数据和经过数据预处理的特征数据合并以后,此时可以通过机器学习算法训练出一个AI模型。

# StockRanker机器学习训练
m5=M.stock_ranker_train.v5(training_ds=m4.data, features=conf.features)

示例解读:

  1. 机器学习模型训练是必不可少的一步,训练时间依赖于数据量,如果是全市场股票多年数据,时间大概需要3-10分钟。详情请参考 模块和API概览:模型训练
  2. training_ds=m4.data 表示:训练模型时应以什么数据进行输入,输入的数据为上一步合并的数据。
  3. features=conf.features 表示:训练模型时以什么特征或因子参与模型进行训练。
  4. M.stock_ranker_train接口的其他参数一般采用默认值。

八.训练结果

通过上一步的训练模型,我们已经产生出了一个在训练集上表现不错的模型。我们可以这样查询训练结果:

print('模型ID:', m5.model_id)
print('模型因子得分:', m5.feature_gains)
print('模型可视化:', m5.plot_model())

示例解读:

  1. m5.model_id 表示:唯一的模型ID。
  2. m5.feature_gains 表示: 各个特征的得分情况,可以借此判断特征重要性程度。由于输出类型为DataSource,因此可以通过read_df方法查看——m5.feature_gains.read_df()。
  3. m5.plot_model() 表示:可视化查看模型结果,这样就能打开AI算法的‘黑箱’,可以查看算法的每个细节。

九.模型预测

此时,我们已经产生出了一个在训练集上表现不错的模型。现在我们根据该模型来获取在测试集上的预测结果。

# 计算基础数据
n2 = M.general_feature_extractor.v5(
    instruments=conf.instruments, start_date=conf.start_date, end_date=conf.end_date,
    features=conf.features)

# 计算衍生特征
n2_1 = M.derived_feature_extractor.v1(data=n2.data, features=conf.features)

# 将特征数据转换机器学习算法能够接受的数据类型(只有StockRanker算法需要)
n3 = M.transform.v2(data=n2_1.data, transforms=None, drop_null=True)

# 进行预测
n4 = M.stock_ranker_predict.v5(model=m6.model, data=n3.data)

# 查看预测数据
prediction = n4.predictions.read_df()

示例解读:

  1. n1和n2和之前的特征抽取、特征转换完全一样,只是现在传入的时间是测试集的时间段。
  2. 机器学习算法通过模型和特征数据就可以进行预测,因此并不需要标注数据、合并数据。比如当你获得了一个回归模型后,此时传入新的自变量就可以带入模型获得因变量。
  3. n3是模型预测,详情可参看 模块和API概览:模型预测
  4. model_id=context.options[‘model_id’] 表示:用哪个模型进行预测就传入哪个模型ID。
  5. data=n2.data 表示:在什么数据上进行预测就传入什么数据。一般为测试集的特征数据。
  6. n3.predictions.read_df() 表示:模型在测试集上的预测结果为n3.predictions,类型为DataSource,因此需要通过read_df方法查看。

十.策略回测

当我们获得测试集上的预测结果以后,我们就可以通过BigQuant回测机制进行策略回测,验证该策略是否有效。策略回测相关内容请参考 BigQuant回测机制


小结:AI策略其实主要包含训练和预测,然后基于预测的结果开发交易策略来进行验证。本文因为涉及到机器学习算法为监督式学习算法,因此有数据标注这一步。希望通过本文介绍,大家能有更加深入的认识。



M.filter.v2 参数和版本问题
请问为什么总报KEYERROR的错?
BigStudio使用文档介绍(三)
【宽客学院】StockRanker结果解读
[量化学堂-新手专区]熟悉BigQuant策略开发环境
[量化学堂-新手专区]适合小白的AI量化入门方式
(hang12) #2

还是挺详细的,赞一个


(soft05jun) #3

大致看完,和其它平台确实不一样,和传统的确实不一样。
关于过拟现象,未来函数的陷阱,不知道这里是怎么避免的。


关于过拟合:机器学习方法 vs. 传统人工方法
(iQuant) #4

因为平台交易引擎采取事件驱动机制,当日产生的信号,下一日才能成交,因此不会存在未来函数的陷进。
过拟合很难避免,只能一定程度的减少,可以参考:链接


(PAYNE) #5

这个详细,mark一下


(hugo) #6

谢谢 学习了


(hugo) #8

请问如果M.user_feature_extractor.v1(
instruments=conf.instrument, start_date=conf.startdate,end_date=conf.enddate,
history_data_fields=[‘close’, ‘open’], look_back_days=120,
features_by_instrument={
‘u_am20’:lambda x:x.amount.rolling(20).mean()/x.shift(20).amount.rolling(20).mean()
}
)
这里是自定义的因子,在训练时M.stock_ranker_train.v5(training_ds=m4.data,features=这里怎么表达呢)


(PAYNE) #9

真不想吐槽,每次发实例代码或者文档代码都是无法编译通过的,就不能先编译通过之后再发到网上来么……


(hugo) #10

有些api更新了


(iQuant) #11

@PAYNE
您好,平台API有不少更新,这些更新没有及时反映到文档和社区,给您造成了困扰。我们已经在逐步进行修复和更新,希望耐心等候。
另外,当你遇到问题时,你可以直接在社区和qq群、微信群跟我们交流。这样更快捷、迅速。
如何联系我们,请参考:链接


(1899) #13

有个问题还请教:
image
这个可视化策略在执行时,前面的标注方式不是排序标注么,为什么我点二分类和logloss也可以执行?


(神龙斗士) #14

标注和后面的学习方法不是必然依赖的。模板给的标注方法可以用于排序和分类等。


(syauwjl) #15

训练中是以未来5天的收益作为标注(shift(close, -5) / shift(open, -1) - shift(benchmark_close, -5) / shift(benchmark_open, -1)),那么训练时间段后4天的数据标注时岂不产生未来函数?


(小Q) #16

标注就是这样,因为此时使用的数据都是训练集数据,所以没有关系。


(syauwjl) #17

也就是说我在做训练的时候如果训练时间是10 天的话,就只有前1-6 天的数据参与了训练,7-10 d的数据不能被标注,未参与训练。对吗?


(Lingking) #18

看起来清清楚楚,做起来一窍不通。就不能给我一个整体的从头都尾的统一模板,然后我该改哪个自己研究一下。

我发现现在就是粘贴那些文章里的代码 复制黏贴进去也出错,而且我还不知道错在哪里。


(iQuant) #19

你好,这篇帖子是从代码上对AI策略整体进行了一些介绍。
在新建策略的时候,你可以直接通过新建按钮得到模板策略,不需要自己手动编写策略。
此外,你如果复制代码遇到错误,我们建议你把问题直接分享到社区,便于我们帮你解决并更新文档。


(HaydnHsu) #20

进行预测

n4 = M.stock_ranker_predict.v5(model=m6.model, data=n3.data)

Should m6.model be m5.model ?


(lyh802) #21

模块的中间结果能否输出,不知道现象怎么改不清楚。而且只想用到一部分模块


(iQuant) #22

这个是可以的啊,每一个模块的输入、输出都是可以及时查询,并且用在其他地方的。