【量化课堂】简单市值轮动策略
> 学习内容:
> - 学会使用run_daily进行周期循环
> - 学会取用市值数据、持仓数据、指数成分股数据
> - 学会写小市值策略
1 确定策略内容
简单小市值轮动策略内容是这样的:
> 每隔若干个交易日,等金额持有市值排名最小的前几只股票,卖出其他股票。
进一步明确下,把量确定,例如这样:
> 每隔10个交易日,等金额持有市值排名最小的前5只股票,卖出其他股票。
接下来,进行初始化和周期循环。
2 初始化
确定轮动频率,即每隔多少个交易日进行买卖。比如就是10个交易日。
确定持有最小市值股票数,即持有市值排名最小的前多少只股票。比如就是前5只。
则初始化部分代码为:
> 答疑与延伸:
>- 这也是多股票策略,怎么不确定股票范围了?股票范围我们希望是能在全市场,但它是变化的,有新股上市,也有退市的,所以股票范围不能事先确定好不变,所以要在周期循环的部分不断更新并确定股票范围。
3 周期循环的另一种写法--run_daily
那么用run_daily的我们的初始化-周期循环的策略框架怎么写呢?
我们的新套路如下:
首先,可以看出run_daily要写在initialize里。
其次,需要知道的是,你把什么函数替换掉daily,谁就会像原来的handle_data一样进行周期循环。虽然名字不一定是daily,可以自己改,但不能很聚宽回测引擎已经有的函数重名,比如不能叫handle_data、initialize。
> 答疑与延伸:
>-time='every_bar'是什么意思?time这个参数控制循环行为的,当time=’every_bar‘时,循环的行为就和handle_data一样,按天回测时就每天开盘时运行,按分钟回测时就每分钟开始时运行。当然time还可以为别的,从而循环的行为会有所不同,从而实现一些handle_data做不到的事,具体见API原文:定时运行
>-推荐以后都用run_daily来进行周期循环,聚宽系统上handle_data将会弃用。
4 开始写周期循环部分
按之前的设定,我们希望策略每十天进行一次循环,进行判断,买入卖出等,即轮动频率为10天。但策略回测只提供了基本的每分钟循环和每日循环,要做到每10天进行一次循环需要写代码编程解决。
怎么编呢?想法很简单,就每日循环好了,第一天正常进行判断买入卖出,之后九天什么都不做,然后,第十一天再正常判断买入卖出,再闲九天,这不就搞定了。
因此,我们需要一个变量,记着现在是策略进行第几天了,如果能被轮动频率10整除余1就干活,进行买卖。否则,就闲着,什么都不做。
所以,至此我们的代码应当是这样写的:
> 答疑与延伸:
>-g.days=1为什么要写到initialize里?因为g.days需要独立在周期循环之外来记录策略运行天数,而且还要在周期循环中使用,所以需要在initialize里设置为全局变量并赋予初值1。如果写在周期循环里,每次循环都将被重置为1,无法记录运行天数。
>-g.days % g.period什么意思?意为求g.days整除g.period后的余数,“%”是取余运算。例如,那么12%10就是等于2,因为12整除10得1余2,更多的,3%10等于3,3%5等于3。
>-pass什么意思?在python里就是什么也不做的意思。
接下来,我们关注点将在“写进行选股、判断、买入卖出等代码”这个关键代码,其余代码暂时放到视野外。
5 找出全市场上市值最小的5只股票
用context结构获取策略回测数据中的当前时间;用get_index_stocks获取指数成分股,从而确定股票范围;用get_fundamentals来使用财务数据中的市值数据,同时也能获取到相应股票代码。
代码如下:
get_fundamentals可用来获取财务数据,用法复杂而强大,但常用的基本可以套用这个公式:(可对比上文代码理解)
其中,数据表.数据项怎么找呢?到导航栏-数据-财务数据中找,比如数据表valuation,数据项market_cap,如下图:
get_index_stocks的用法就比较简单,就是在导航栏-数据-指数数据中找到要用的指数,之后放到括号里。返回的是指数成分股list,所以获取多个指数成分股list后用“+”连接起来。具体看文档API文档 get_index_stocks。
> 答疑与延伸:
>- 使用更复杂的条件筛选财务数据?get_fundamentals中的与或非
>-get_fundamentals的更多介绍API文档 get_fundamentals。
>-list(df['code'][:g.stocksnum])什么意思?df是取出的按市值从小到大排好序的股票代码,是个dataframe,df['code']就是选取df中的code列,即股票代码。df['code'][:g.stocksnum]就是取df中的code列中的前g.stocksnum个。最后list()是把df['code'][:g.stocksnum]转成将会用到的list的数据类型。dataframe的用法详情请见:dataframe 专题指南,pandas库之数据查看、选择
6 分配资金进行买卖交易
要买的股票已经选好放在buylist里了,只要将资金分好,相应的买入就好了,如果看过之前那篇多股票策略的话,应该很好理解。
特别的是,存在这样的情况,某股票市值是最小前五的而被选入buylist,而且也买入持有了,但过了一段时间,其股票市值不是最小前五了,从而不再当下的buylist里,这时我们应当卖出这个股票。因为我们的策略就是10天为周期地持有市场上市值最小的五只股票。
代码如下:
> 答疑与延伸:
>- context.portfolio.positions什么意思? 是当前策略的持有股票数据是个dict,不妨自己输出看看,参考内容: 回测账户数据——context、Python入门- 数据类型之字典。
7 策略完成,进行回测
至此,我们的策略都已经用代码实现好了,完整代码如下:
进行回测,回测结果如图:
自测与自学
1、是否学会使用run_daily进行周期循环
2、是否学会取用市值数据、持仓数据、指数成分股数据
3、是否学会编写简单小市值轮动策略
4、调整下策略,比如轮动频率,持仓股票数,回测看看效果如何?
5、思考此文中,虽然每次都等资金的买入,为何5只股票的持仓总价值其实还是不同,而且可能越差越大?