给自己搭个量化投资系统之六——基于传染病模型的新高买入策略探索
2020年11月28日,周教授情报中心原创发布了《关注这一类标的!》,提出了一个简单的量化思路。具体如下:
周教授指出这个策略从2020年第一个交易日到2020年10月30日的回测收益率为64.28%。
今天,我们来探索一下,这一类新高策略在当前这种变态的环境下是否仍有一定的超额收益。
1. 明确几个问题
1.1. 关于买入条件
周教授的买入条件实际上是上市120交易日以上,创出历史新高的股票。这里有一个拍脑袋的参数,120;还有一个隐藏的参数,历史新高,它也可以是252天新高或60天新高等等。
1.2. 关于仓位分布
周教授假设仓位是每天滚动在所有符合条件的股票之间平均分布。这一条实际上是做不到的。为了便于后续将新高策略纳入我的量化投资系统,我这里假设每个股票的买入都有一个限额。比如,可以假设每次买入总额不少于10000元、不超过20000元。
1.3. 回测时间
同样遵循我目前用的时间框架,只回测最近一年。
1.4. 初始金额
假设初始金额为150000。
2. 股票池及传递规则
这个量化不同于现在很火的机器学习模型,这里其实有点类似于传染病模型,所以我们需要建立几个股票池,类似传染病模型里的不同人群:正常人群、易感人群、感染人群、康复人群等。同时,我们需要定义不同池子之间的传导规则,当然这里的传导规则跟传染病模型几乎是完全不一样的。
2.1. 未持有股票池(正常人群)
这里,初始的未持有股票池就是所有A股。它的流出是满足买入条件的股票;它的流入是新股的发行,以及符合卖出条件的股票。
2.2. 应该持有股票池(感染人群)
应该要持有的股票的集合作为应该持有股票池。它的流出是满足卖出条件的股票,它们将流入到未持有股票池;流入是满足买入条件的未持有股票,它们将从未持有股票池流入到本池。
2.3. 可用资金池
即模拟可用资金,这里假设初始资金是150000元。它的流出是买入股票,它的流入是卖出股票。同时,买入和卖出需要支付一定的手续费。
2.4. 实际持有股票池(治疗人群)
实际持有的股票的集合作为实际持有股票池,它是应该持有股票池的一部分。这是因为实际投资时,资金是有限的,并不是所有应该持有的股票都有资金买入。它的流出跟应该持有股票池是一样的,由于它的流向也跟应该持有股票池重合,所以不用重复计量。它的流入是满足买入条件和可用资金需求的未持有股票,当资金不足以买入所有股票时,这里按股票代码顺序排列。
3. 代码实际
3.1. 明确交易日历
这里我们以最近一年为回测周期。
import data_operate as do
trade_dates = do.sql2pd("select format(trade_date, '%Y-%m-%d') from SSEC where trade_date>20210508 order by trade_date")
print(trade_dates)
显然,这个日期数据还需要一点小处理
trade_dates[0] = trade_dates[0].apply(lambda x: x.replace(',', '')[:8])
3.2. 未持有股票池的实现
nonhold_stocks = do.sql2pd("select ts_code from daily where trade_date=%d" % trade_dates[0][0])
3.3. 应该持有股票池的实现
应该持有股票池的初始化
should_hold_stocks = pd.DataFrame(columns=[0, 1, 2])
应该持有股票池的流入
temp_stocks = do.sql2pd("select a.ts_code, a.high, a.trade_date from daily as a inner join (select ts_code, max(high) as mh from daily where trade_date<%d group by ts_code having count(high)>120) as b on a.ts_code=b.ts_code where a.high>b.mh and a.trade_date=%d" % (int(trade_date), int(trade_date)))
temp_stocks = temp_stocks[~ temp_stocks[0].isin(should_hold_stocks[0].to_list())]
should_hold_stocks = should_hold_stocks.append(temp_stocks).reset_index()
应该持有股票池的流出
i = 0
while i in should_hold_stocks.index:
low = do.sql2pd("select low from daily where trade_date=%d and ts_code='%s'" % (int(trade_date), should_hold_stocks[0][i]))
if len(low):
if low[0][0] / should_hold_stocks[1][i] < 0.9:
should_hold_stocks.drop(i, inplace=True)
continue
last5th = do.sql2pd("select trade_date, high from daily where ts_code='%s' and trade_date<%d order by trade_date desc limit 4, 1" % (int(trade_date), should_hold_stocks[0][i]))
if should_hold_stocks[2][i] <= last5th[0][0]:
if last5th[1][0] >= do.sql2pd("select max(high) from (select high from daily where trade_date<=%d and ts_code='%s' order by trade_date desc limit 0, 5) as a" % (int(trade_date), should_hold_stocks[0][i]))[0][0]:
should_hold_stocks.drop(i, inplace=True)
continue
i += 1
3.4. 资金池与实际持有股票池的实现
先是资金池和实际持有股票池的初始化
hold_stocks = pd.DataFrame(columns=[0, 1, 2, 3])
currency = 150000
判断资金是否充足,并尝试买入
def buy_stocks(currency, should_buy_stocks, hold_stocks):
for i in should_buy_stocks.index:
if should_buy_stocks[1][i] < price_limit:
buy_num = buy_limit // should_buy_stocks[1][i] + 1
buy_amount = buy_num * 100 * should_buy_stocks[1][i] * 1.0001
if currency >= buy_amount:
currency -= buy_amount
hold_stocks.loc[len(hold_stocks), ] = should_buy_stocks.loc[i, ] + [buy_num, ]
return currency, hold_stocks
currency, hold_stocks = buy_stocks(currency, should_hold_stocks, hold_stocks)
currency, hold_stocks = buy_stocks(currency, temp_stocks, hold_stocks)
卖出股票
def sale_stocks(currency, ts_code, price, hold_stocks):
hold_i = hold_stocks[hold_stocks[0] == ts_code].index[0]
currency += hold_stocks[3][hold_i] * price * 100 * 0.9999
hold_stocks.drop(hold_i, inplace=True)
return currency, hold_stocks
currency, hold_stocks = sale_stocks(currency, should_hold_stocks[0][i], low[0][0], hold_stocks)
currency, hold_stocks = sale_stocks(currency, should_hold_stocks[0][i], current_price, hold_stocks)
4. 总结
经过一年的回测,发现如果是最近一年的话效果非常差,150000元初始资金,一年后仅留下了39602元,收益率是-74%。
我们可以看一些案例,有些买入就开始亏(K线图画法可参见给自己搭个量化投资系统之三——用pthon画K线图)
有些是先赚,最后又亏了
我们也可以尝试一些不同的参数
比如把最低买入量改成5万元,结果一年后只剩下36817元,跟前面的结果差不多。
- 点赞
- 收藏
- 关注作者
评论(0)