假期终于有时间更新一波。因为文章更新并不频繁,微信并不会把最新的公众号文章及时推送在读者最新的列表中,可以将公众号设为星标,这样就能第一时间收到笔者的最新文章啦。
在写公众号初期就想着写一篇折价策略收益率的回测。因为拖延症原因,一直没有行文着手写,趁假期休闲时间把它写了。
[h2]策略说明:[/h2]顾名思义,折价策略,就是选择折价率最高的10只可转债,在一个时间范围里面轮动。如果到了下一个时间节点(比如一周后),重新获取10只折价率最高的可转债,那么就把上一批可转债掉出前10名的卖掉,买入最新一批进入前十的折价可转债。周而复此,不断轮动,中途记录每笔买卖,计算最大回撤与收益率。
[h2]回测条件:[/h2]笔者把回测开始时间设定在2018年1月1日,可转债信用申购新规后,可转债容量开始扩容。
回测终止时间为2021年4月30日,也就是当前时间的最后一个交易日,时间跨度为3年4个月。
买入标的为可转债债,不包含可交换债和纯债。
回测平台使用优矿,如果动手能力强,也可以在本地使用python配置相应的量化回测平台。
回测资金使用100W。
[h2]代码实现:[/h2]部分代码可以复用之前公众号里面文章里面的,比如获取所有可转债代码,并且过滤纯债,EB可交换债。可转债历史连续最多跌多少周?
核心代码如下:
- 1MyCash = 1000000 #现金
- 2Start_Cash= 1000000
- 3HighValue = MyCash #最高市值
- 4Withdraw = 0 #最大回撤
- 5HoldRank = 10 #排名多少之后卖出
- 6HoldNum = 10 #持债支数
复制代码 上面的的参数看个人喜好而定,有人喜欢折价策略摊大饼的,那么可以把持债个数设为20,30等等,可以看看转债分散程度对最大回撤和收益的影响。
- handle_data: 周期运行,设定为5个交易日(一周)运行一次,可以使用更长周期或更短周期,1天或者1个月。
- 1freq = 'd' # 策略类型,'d'表示日间策略使用日线回测,'m'表示日内策略使用分钟线回测
- 2refresh_rate = 5 # 调仓频率,表示执行handle_data的时间间隔,若freq = 'd' 时间间隔的单位为交易日,取盘前数据,若freq = 'm' 时间间隔为分钟
复制代码 - 周期运行的函数handle_data: 这个是优矿固定的函数,会在每个周期执行一遍,里面也就是核心计算函数代码。因为优矿不支持可转债的模拟买卖,所以需要自己写一个模拟买卖的交易数据与仓位。
- 1def handle_data(context):
- 2 global MyPosition, HighValue, MyCash, Withdraw, HoldRank, HoldNum,Start_Cash
- 3 previous_date = context.previous_date.strftime('%Y%m%d')
- 4 today_date = context.now.strftime('%Y%m%d')
- 5
- 6 #每天重新计算双低排名
- 7 ticker_list=bonds(today_date,today_date)
- 8 df = DataAPI.MktConsBondPerfGet(beginDate=today_date,endDate=today_date,secID='',tickerBond=ticker_list,
- 9 tickerEqu=u"",field=u"secID,closePriceBond,bondPremRatio,secShortNameBond",pandas="1")
- 10 df.set_index('secID',inplace=True)
- 11 df = df.sort_values(by="bondPremRatio" , ascending=True)
- 12 PosValue = MyCash
- 13
- 14 for stock in MyPosition:
- 15 try:
- 16 CurPrice = df.loc[stock]['closePriceBond']
- 17 except:
- 18 NoPrice = DataAPI.MktConsBondPerfGet(beginDate=previous_date,endDate=previous_date,secID=stock,tickerBond=u"",tickerEqu=u"",field=u"closePriceBond",pandas="1")
- 19 if len(NoPrice)==0:
- 20 last_date = (context.now + datetime.timedelta(days=-7)).strftime('%Y%m%d')
- 21 CurPrice=get_last_price(stock,last_date,today_date)
- 22
- 23 else:
- 24 CurPrice = NoPrice.closePriceBond[0]
- 25
- 26 PosValue += MyPosition[stock] * CurPrice * 10
- 27
- 28 if stock not in df.index[:HoldRank]:
- 29 MyCash += MyPosition[stock] * CurPrice * 10
- 30 try:
- 31 name=df.loc[stock]['secShortNameBond']
- 32 except:
- 33 name = stock
- 34 log.info('{} 卖出{},{},价格:{}'.format(today_date,stock,name,CurPrice))
- 35 del MyPosition[stock]
- 36
- 37 if PosValue > HighValue:HighValue = PosValue
- 38 if (HighValue - PosValue) / HighValue > Withdraw:Withdraw = (HighValue - PosValue) / HighValue
- 39
- 40 #买入排在HoldRank内的,总持有数量HoldNum
- 41 for i in range(HoldRank):
- 42 if len(MyPosition) == HoldNum or len(data.index) < HoldNum:break
- 43 if df.index[i] not in MyPosition.keys():
- 44 name=df.loc[df.index[i]]['secShortNameBond']
- 45 price=df.loc[df.index[i]]['closePriceBond']
- 46 log.info('{} 买入{}, {}, 价格{}, 折价{}'.format(today_date,df.index[i],name,price,cb_ration))
- 47 MyPosition[df.index[i]] = int(MyCash / (HoldNum - len(MyPosition)) / df['closePriceBond'][i] / 10)
- 48 MyCash -= MyPosition[df.index[i]] * df['closePriceBond'][i] * 10
- 49
- 50 ratio = (PosValue-Start_Cash)/Start_Cash*100
- 51
- 52 log.info(today_date + ': 最高市值 ' + str(HighValue) + ' , 当前市值 ' + str(PosValue) + '收益率 : '
- 53 +str(ratio)+'% , 最大回撤 ' + str(round(Withdraw*100,2))+'%')
复制代码 代码中有些异常处理要注意的,比如上周买入的折价已经被强赎了,下一周的时候需要按照强赎日的收盘价卖出,不然但交易日当天会找不到被强赎的转债数据。
[h2]回测运行结果:[/h2]截取部分中间执行结果,文末有获取所有交易记录的方法。
2018年开始执行的中间数据
2018年开始执行的中间数据,跑到2018年8月,折价策略勉强保本,最大回撤有11%。
中间因为篇幅省略若干,基本每周都会发生交易。
直接跳到最后:
最后一次调仓记录是2021年4月27日,当初的100W现在已经变成了510W,当前的收益率为410%!最大回撤值为18%。
换算为年化收益,年化收益率达到了64%。这个收益率与最大回撤比很多优秀的基金经理都要优秀,回撤也控制的很好。
同时也大幅跑赢沪深300
沪深300基准年化7收益率为7.7%。
根据日志输出的收益率绘制收益率曲线。
折价策略收益率曲线
最大回撤发生在2019年6月(数字在上图不好看得出来,因为曲线被后期收益率拉伸后,前半段显得很窄的跌幅)。
从数据日志中可以得到的:
因为上一个最大回撤是17.19%,后面的最大回撤就保持在18.59%。
如果从收益分布来看,其实绝大部分的收益从2020年贡献的,因为从数据得到,截至2019年10月份,折价策略的总收益为32%,经过2020年的抱团行情和疫情收益股,才把总体收益率拉伸到410%。所以笔者认为折价策略是一个优秀的策略,但同时有一丝丝的不确定的担忧,因为对于脱离债底的高价折价可转债(转债价格大于180以上),其实质和买入正股差不多(排除像英科转债这种高价高分红导致转股价大幅下调的个例),因为从回测数据中,2018年的熊市中,对于折价可转债而言,虽然有一定回撤,但是因为本身转债价格不高,在面值附近折价,有债底的保护,即使遇到暴跌行情亏损也不会太大。
对于激进投资者,买入高价折价转债等同于买入正股,可以采用转债套利策略,买入的高价折价转债后转股,股票可卖后继续买回其折价转债,因为本质都是看好正股继续涨。
目前还没大面积发生高价折价转债的正股进入漫长熊市,从而让转债也跟随大幅下跌,即使轮到到其他折价的转债,在普跌行情下轮动后转债也跟随下跌,这种情形下的回撤应该会非常大,虽然还没发生,但转债行情多变,每年都有新花样,就像突破3000元的英科转债,溢价率400%多,其价格也能维持在400多的横河转债。所以对比高价折价转债,笔者还是比较慎重,大仓位选择的是双底策略,降低波动,但策略并无对错,只是个人投资的偏好风格使然。本来想把双低策略的回测也一同分析下,由于篇幅有限就放在下一篇了,就代码而言,改动不多,改一行就可以的了,对该策略的读者朋友敬请留意哦。
如果需要获取文中每次轮动的交易数据,可以后台留言:折价交易数据
|
|