模板策略解析

新手专区
标签: #<Tag:0x00007f20c95ff7f8>

(XiaoyuDu) #1

大家好,我是一个bigquant新手用户,但我相信模板策略流程图的复杂并不会让我们新手朋友望而却步,在阅读了模板策略背后代码和逻辑后,我对BigQuant模板策略的进行解析,希望大家觉得有用:


如何解读流程图和基本机器学习概念

流程图解读与概览

程序运行的本质是数据的传递与操作。流程图中的每一个节点,都是一个对数据进行操作的模块,而节点之间的连线上,流动的是数据。我们模板策略的流程图,自上而下就是原始数据一步步流动,变形和运算的过程,就像化工厂里的化学原料互相反应,最后生成产品。

基本机器学习概念

机器学习分为有监督的学习和无监督的学习,对于有监督的学习,在模型建立前,你就已经知道数据将被划分的类别,而无监督的机器学习则会根据一定的准则自动的给数据分类。人的学习就是人的塑造过程,机器的学习就是塑造模型和估计参数的过程。
对模型进行评价,就是利用大量历史数据对其表现进行统计上的检验的过程,这里有两个很关键的条件:

(1)

训练模型的数据和测试评价模型的数据得是完全不同的,这样我们才能认为模型的评价是公正的,因为数据既是模型的塑造者,也是模型的评价者,一个运动员教练不可能同时也做自己运动员比赛的裁判,于是在这个基础的模板策略里面,我们的测试集用的是2015-2017的数据,训练集用的是2010-2015的数据;

(2)

我们进行历史数据训练并验证模型的本质是我们假设过去发生的逻辑在未来依然存在并不断生效,也就是说,A股在过去的走势服从某个内涵的规律,而未来它依然会服从该规律,如果未来和过去没有关联,环境大不相同,那么我们通过历史训练的模型将失去效果。


左分支,训练集数据预处理

图中的m1,m2… 代表了数据的演化,而v1,v2…代表这平台不同的版本;
需要注意的是,这里的m往往不是真实的数据,而是存储了真实数据性质和位置的一个对象

m1->原始测试数据

m1 代表我们能从数据字典中直接取出的数据,也就是原始数据,包括股票名称,和时间起始终止点;
时间范围取为2010-2015
image (该截图不完整)

(有兴趣看代码的用户可以阅读以下内容)


点击查看
m1 = M.instruments.v2(
    start_date='2010-01-01',
    end_date='2015-01-01',
    market='CN_STOCK_A',
    instrument_list='',
    max_count=0
)

我们可以看见,m1实际上是我们创建的一个数据对象,里面存储了数据索引的信息(起止日,股票名等等)


m2->对原始测试数据的分类

数据的标注,也就是根据数据的特征进行分类的过程,我们这里是有监督的学习,我们根据一定的规则计算股票的收益率,并按收益率的大小,将全部股票集合排序并划分为20个子集。
image 如图,m2里存储了市场行情价格的同时,还存储了对该股票某一时段的标签(收益率评分)

(有兴趣看代码的用户可以阅读以下内容)


点击查看
m2 = M.advanced_auto_labeler.v2(
    instruments=m1.data,
    label_expr="""# #号开始的表示注释
# 0. 每行一个,顺序执行,从第二个开始,可以使用label字段
# 1. 可用数据字段见 https://bigquant.com/docs/data_history_data.html
#   添加benchmark_前缀,可使用对应的benchmark数据
# 2. 可用操作符和函数见 `表达式引擎 <https://bigquant.com/docs/big_expr.html>`_

# 计算收益:5日收盘价(作为卖出价格)除以明日开盘价(作为买入价格)
shift(close, -5) / shift(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)
""",
    start_date='',
    end_date='',
    benchmark='000300.SHA',
    drop_na_label=True,
    cast_label_int=True
)

数据m2是数据m1经过加工而成的,具体的操作流程包括:
用未来五天的收盘价比上未来一天的开盘价代表收益率,这里的参数可以调整,取决于我们想要的交易频率;
去除最高的收益和最差的收益,极值往往是脱离了统计模型的异常点,对他们的丢弃将有益于模型的准确性;
在一字涨停中我们无法进行交易,因此将它过滤掉
我们根据之前计算的收益率将股票分类到不同的收益区间
到此为止,打标签的过程结束;


m3->特征

我们根据股票收益率将股票分类,这是因为我们关心的股票收益率,股票收益率是我们渴望解释的,而m3是我们用于解释该收益率的特征,比如交易量的变动趋势,10日收益率等等;

(有兴趣看代码的用户可以阅读以下内容)


点击查看
m3 = M.input_features.v1(
    features="""# #号开始的表示注释
# 多个特征,每行一个,可以包含基础特征和衍生特征
return_5
return_10
return_20
avg_amount_0/avg_amount_5
avg_amount_5/avg_amount_20
rank_avg_amount_0/rank_avg_amount_5
rank_avg_amount_5/rank_avg_amount_10
rank_return_0
rank_return_5
rank_return_10
rank_return_0/rank_return_5
rank_return_5/rank_return_10
pe_ttm_0
"""
)

我们可以看见,m3实际上是我们创建的一个特征对象,里面存储了我们认为对收益率可能存在解释能力的特征;包括五日,十日,二十日回报,交易量变化趋势,当日,五日,十日回报排名等等。


m15 & m16 -> 特征+数据的运算

简言之,m15和m16就是给定了特征后,我们根据现有的数据将特征值计算出来后,所产生的数据集。



第一张图是m15,也就是基础特征提取,实际上是根据行情数据去计算了一些基础特征;
第二张图是m16,m16不仅仅包括了m15,作为衍生特征提取,同时根据基础特征去计算了其余的衍生特征;

m7 & m13 -> 数据的连接和缺失值处理

将我们根据特征算出来的特征值与原始数据相匹配,我们就获得了一个完整的数据集合,而在运算时遇到异常情况,比如停牌等,我们就会生成缺失数据,这些缺失的数据将在这个节点统一丢弃处理。

(有兴趣看代码的用户可以阅读以下内容)


点击查看
m7 = M.join.v3(
    data1=m2.data,
    data2=m16.data,
    on='date,instrument',
    how='inner',
    sort=False
)

m7是由原始数据和我们生成的特征值进行内连接join生成的;



右分支,测试集数据预处理

右分支的数据处理流程和左分支完全一致,唯一的不同就是右分支的数据和左分支的数据是完全不同的两组数据,在本模型中,右分支的测试集数据的时间范围趣味2015-2017,与左分支的时间错开。


下半部分,模型的训练和测试

现在,我们手上已经有了两部分数据,左分支的训练集数据m13与右分支的测试集数据m14。
我们利用训练数据训练模型,并在测试数据上评价模型的表现;
从模型名字,我们可以理解我们的模型框架是打分排序模型,stockranker,模型的具体解析在下面的代码部分;

训练模型阶段

(有兴趣看代码的用户可以阅读以下内容)


点击查看
m6 = M.stock_ranker_train.v5(
    training_ds=m13.data,
    features=m3.data,
    learning_algorithm='排序',
    number_of_leaves=30,
    minimum_docs_per_leaf=1000,
    number_of_trees=20,
    learning_rate=0.1,
    max_bins=1023,
    feature_fraction=1,
    m_lazy_run=False
)

stock_ranker是基于决策树算法,我们在这里简单的介绍一下该算法:
决策树中最核心的问题就是根据怎样的标准将股票进行分类表现最好。 衡量分类表现的标准就是能够将已经标记了的数据的准确的分到他的标记中去;而反过来选取怎样的标签进行分类,这就是一个模型的核心。
从上面的代码我们看到,训练集数据是m13,特征是m3,每一颗树的叶子(分类规则)为30,总共用了20棵分类树;


模型预测阶段


如上图,我们对2015年开始的测试数据集里的股票根据已经训练出来的决策树模型进行分类判断;
上图是我们的分类结果的截图;m8就是经过分类的预测结果,预测什么?预测2015-2017年间股票的走势;
注意,为什么我们拿2015-2017年的历史数据进行模型的预测?因为相对于在2010-2015年间的数据训练出来的模型而言,我们2015-2017年的数据是预测数据

回测与交易阶段

于是m19就是我们根据训练好的模型进行打分并模拟回测交易的一系列过程。

(有兴趣看代码的用户可以阅读以下内容)


点击查看
m19 = M.trade.v4(
    instruments=m9.data,
    options_data=m8.predictions,
    start_date='',
    end_date='',
    handle_data=m19_handle_data_bigquant_run,
    prepare=m19_prepare_bigquant_run,
    initialize=m19_initialize_bigquant_run,
    volume_limit=0.025,
    order_price_field_buy='open',
    order_price_field_sell='close',
    capital_base=1000000,
    auto_cancel_non_tradable_orders=True,
    data_frequency='daily',
    price_type='后复权',
    product_type='股票',
    plot_charts=True,
    backtest_only=False
)

从代码中看到,
我们用于回测的数据就是测试数据m9,交易的方法是根据我们的预测结果m7;
随后我们通过一系列已经封装好的函数进行模拟交易;


模拟交易的思路是:、确定持仓时间holddays是五天(预先设置参数)
每天执行一次交易,用模型打分,判断哪些股票需要买入哪些需要卖出,并在holddays后才开始卖出,采用1/holdays份的资金进行买入(这里还有更细节的考虑holddays存在买入误差)。


以上是我对模板交易策略的分析,希望大家喜欢~~


(iQuant) #2

用心了,加油哈~