回测

回测

Ptrade回测模式下获取实时的分钟数据:只能使用handle_data,数据不能用get_snapshot

Ptrade李魔佛 发表了文章 • 0 个评论 • 596 次浏览 • 2024-09-21 17:32 • 来自相关话题

好久没有使用Ptrade做分钟级别的回测了。
发现有点蛋疼,记录一下。
 
因为回测模式下,不能使用run_interval 函数;
 
而run_daily模式,只能在固定时间运行,无法分钟级别。
 
所以只能使用 handle_data
而在handle_data 里面获取当前的分钟价格数据,也无法使用 get_snapshot ,get_gear_price,函数。
 
所以只能使用handle_data(Context,data) 里面的data里。
 
而handle_data 里面的data数据,使用方法如下:

 

import datetime

target_list = [
'600000.SS',
'000333.SZ'
]

def execution(context, data):
now = context.current_dt.strftime('%H:%M')
for code in target_list:
tick_info = data[code]
price = tick_info['price']
print('now: {} code : {} price:{}'.format(now,code ,price))




# 标准
def initialize(context):
log.info("公众号:可转债量化分析 ---- start ----")


def handle_data(context, data):
execution(context, data)

 

获取数据结果:2024-09-20 14:42:00 - INFO - now: 14:42 code : 000333.SZ price:66.22
2024-09-20 14:43:00 - INFO - now: 14:43 code : 000333.SZ price:66.26
2024-09-20 14:44:00 - INFO - now: 14:44 code : 000333.SZ price:66.19
2024-09-20 14:45:00 - INFO - now: 14:45 code : 000333.SZ price:66.2
2024-09-20 14:46:00 - INFO - now: 14:46 code : 000333.SZ price:66.19
2024-09-20 14:47:00 - INFO - now: 14:47 code : 000333.SZ price:66.18
2024-09-20 14:48:00 - INFO - now: 14:48 code : 000333.SZ price:66.14
2024-09-20 14:49:00 - INFO - now: 14:49 code : 000333.SZ price:66.25
2024-09-20 14:50:00 - INFO - now: 14:50 code : 000333.SZ price:66.19
2024-09-20 14:51:00 - INFO - now: 14:51 code : 000333.SZ price:66.18
2024-09-20 14:52:00 - INFO - now: 14:52 code : 000333.SZ price:66.19
2024-09-20 14:53:00 - INFO - now: 14:53 code : 000333.SZ price:66.2
2024-09-20 14:54:00 - INFO - now: 14:54 code : 000333.SZ price:66.19
2024-09-20 14:55:00 - INFO - now: 14:55 code : 000333.SZ price:66.25
2024-09-20 14:56:00 - INFO - now: 14:56 code : 000333.SZ price:66.27
2024-09-20 14:57:00 - INFO - now: 14:57 code : 000333.SZ price:66.28
2024-09-20 14:58:00 - INFO - now: 14:58 code : 000333.SZ price:66.28
2024-09-20 14:59:00 - INFO - now: 14:59 code : 000333.SZ price:66.28
2024-09-20 15:00:00 - INFO - now: 15:00 code : 000333.SZ price:66.06
 用同花顺,对了一下结果,是满足的了。
 

  查看全部
好久没有使用Ptrade做分钟级别的回测了。
发现有点蛋疼,记录一下。
 
因为回测模式下,不能使用run_interval 函数;
 
而run_daily模式,只能在固定时间运行,无法分钟级别。
 
所以只能使用 handle_data
而在handle_data 里面获取当前的分钟价格数据,也无法使用 get_snapshot ,get_gear_price,函数。
 
所以只能使用handle_data(Context,data) 里面的data里。
 
而handle_data 里面的data数据,使用方法如下:

 


import datetime

target_list = [
'600000.SS',
'000333.SZ'
]

def execution(context, data):
now = context.current_dt.strftime('%H:%M')
for code in target_list:
tick_info = data[code]
price = tick_info['price']
print('now: {} code : {} price:{}'.format(now,code ,price))




# 标准
def initialize(context):
log.info("公众号:可转债量化分析 ---- start ----")


def handle_data(context, data):
execution(context, data)

 

获取数据结果:
2024-09-20 14:42:00 - INFO - now: 14:42 code : 000333.SZ price:66.22
2024-09-20 14:43:00 - INFO - now: 14:43 code : 000333.SZ price:66.26
2024-09-20 14:44:00 - INFO - now: 14:44 code : 000333.SZ price:66.19
2024-09-20 14:45:00 - INFO - now: 14:45 code : 000333.SZ price:66.2
2024-09-20 14:46:00 - INFO - now: 14:46 code : 000333.SZ price:66.19
2024-09-20 14:47:00 - INFO - now: 14:47 code : 000333.SZ price:66.18
2024-09-20 14:48:00 - INFO - now: 14:48 code : 000333.SZ price:66.14
2024-09-20 14:49:00 - INFO - now: 14:49 code : 000333.SZ price:66.25
2024-09-20 14:50:00 - INFO - now: 14:50 code : 000333.SZ price:66.19
2024-09-20 14:51:00 - INFO - now: 14:51 code : 000333.SZ price:66.18
2024-09-20 14:52:00 - INFO - now: 14:52 code : 000333.SZ price:66.19
2024-09-20 14:53:00 - INFO - now: 14:53 code : 000333.SZ price:66.2
2024-09-20 14:54:00 - INFO - now: 14:54 code : 000333.SZ price:66.19
2024-09-20 14:55:00 - INFO - now: 14:55 code : 000333.SZ price:66.25
2024-09-20 14:56:00 - INFO - now: 14:56 code : 000333.SZ price:66.27
2024-09-20 14:57:00 - INFO - now: 14:57 code : 000333.SZ price:66.28
2024-09-20 14:58:00 - INFO - now: 14:58 code : 000333.SZ price:66.28
2024-09-20 14:59:00 - INFO - now: 14:59 code : 000333.SZ price:66.28
2024-09-20 15:00:00 - INFO - now: 15:00 code : 000333.SZ price:66.06

 用同花顺,对了一下结果,是满足的了。
 

 

优矿的回测引擎运行在python2.7,汗

量化交易李魔佛 发表了文章 • 0 个评论 • 665 次浏览 • 2024-07-22 11:59 • 来自相关话题

之前看到优矿的报错提示如下:

回测引擎运行在 Python2.7 之上,请您使用 Python2.7 的写法进行策略编写。
 
居然回测引擎还在2.7,怪不得目前性能比较拉跨了呢。。。
 
不过话说,自从它的可转债数据收费之后,我就一直没有再使用优矿进行回测了。
 
  查看全部
之前看到优矿的报错提示如下:

回测引擎运行在 Python2.7 之上,请您使用 Python2.7 的写法进行策略编写。
 
居然回测引擎还在2.7,怪不得目前性能比较拉跨了呢。。。
 
不过话说,自从它的可转债数据收费之后,我就一直没有再使用优矿进行回测了。
 
 

可转债到期收益率因子回测 YTM回测 vs 双低 低溢价 低价策略

可转债李魔佛 发表了文章 • 0 个评论 • 1794 次浏览 • 2022-11-26 16:51 • 来自相关话题

最近看到有人发的一些可转债高YTM的回测结果图,说高YTM轮动收益达到年化20%。嗯?高TYM实际上大部分是和低价转债是重叠的,理论和实际收益率都应该不会有这么高的。

自从优矿转为收费后,基本就没有登录过了。现在的回测在本地进行了,宁稳网的可转债数据上有YTM这因子数据,所以这次使用宁稳网的数据回测。也不使用什么第三方框架了,直接手写回测,模拟交易过程。
 
逻辑就是按照交易日期,读取所有excel数据。保存到一个dataframe里面,然后按照日期对YTM排名。 选出排名N名的进行买入,掉出N名的进行卖出。
 
数据源
 
采用宁稳的全表数据,里面有YTM因子





 





 
YTM收益率曲线
本地使用python编写回测代码,纯手工,不使用第三方框架。 平时我也多次力荐大家手写,别依赖那些第三方框架,什么vnpy,backtrade,一是特别难用,数据要适配,二是不好调试,除非你对它们的源码特别熟悉。本回测代码和宁稳数据放在个人知识星球,大部分人其实只关心回测结果就够了。

下图是2022年1月1日至11月25日的回测数据。持有10个标的,红色的是1天调仓,蓝色的是5天调仓
 





 
5天轮动,2022年的收益率为4.29%,最大回撤6.98% 。

1天轮动,2022年的收益率为9.33%,最大回撤5.32% 。

1天轮动的整体收益率要比5天轮动的高5个点,并且最大回撤也小一点。

持仓日志
 






从持仓以及调仓日志来看,买入的大部分是低价转债,且部分也是之前有瑕疵,爆过雷的转债。
 
高YTM轮动 vs 双低,低溢价,低价

接着对比一下几个常规的转债策略,双低,低溢价,低价。

回测条件相同,起始时间2022-01-01,结束时间2022-11-25。

持有10只,5天轮动。
 





 
在今年的可转债偏弱的行情下,高YTM轮动在这4个策略里面的收益率是最高的。

低溢价一如既然的高波动,一会ICU,一会蹦迪。但笔者觉得跌到前期最大回撤的位置,低溢价可以考虑介入的。
 





 
YTM和低价格的今年回测收益率接近,YTM高了一个点左右,最大回撤接近。 而低溢价还在回撤的途中,目前今年的收益率为-25%,如果轮动频率高一些,低溢价收益率会高一些,强赎的转债基本会被轮入低溢价标的,因为最近半年强赎后的转债像进入了死亡螺旋一样,正股转债一起跌;因此排除强赎转债会对低溢价收益率有不少的提升。
 
完整代码以及数据请开通星球查收。




 
 
 
 
  查看全部
最近看到有人发的一些可转债高YTM的回测结果图,说高YTM轮动收益达到年化20%。嗯?高TYM实际上大部分是和低价转债是重叠的,理论和实际收益率都应该不会有这么高的。

自从优矿转为收费后,基本就没有登录过了。现在的回测在本地进行了,宁稳网的可转债数据上有YTM这因子数据,所以这次使用宁稳网的数据回测。也不使用什么第三方框架了,直接手写回测,模拟交易过程。
 
逻辑就是按照交易日期,读取所有excel数据。保存到一个dataframe里面,然后按照日期对YTM排名。 选出排名N名的进行买入,掉出N名的进行卖出。
 
数据源
 
采用宁稳的全表数据,里面有YTM因子

20221126001.jpg

 
20221126002.jpg


 
YTM收益率曲线
本地使用python编写回测代码,纯手工,不使用第三方框架。 平时我也多次力荐大家手写,别依赖那些第三方框架,什么vnpy,backtrade,一是特别难用,数据要适配,二是不好调试,除非你对它们的源码特别熟悉。本回测代码和宁稳数据放在个人知识星球,大部分人其实只关心回测结果就够了。

下图是2022年1月1日至11月25日的回测数据。持有10个标的,红色的是1天调仓,蓝色的是5天调仓
 

20221126006.jpg

 
5天轮动,2022年的收益率为4.29%,最大回撤6.98% 。

1天轮动,2022年的收益率为9.33%,最大回撤5.32% 。

1天轮动的整体收益率要比5天轮动的高5个点,并且最大回撤也小一点。

持仓日志
 

20221126009.jpg


从持仓以及调仓日志来看,买入的大部分是低价转债,且部分也是之前有瑕疵,爆过雷的转债。
 
高YTM轮动 vs 双低,低溢价,低价

接着对比一下几个常规的转债策略,双低,低溢价,低价。

回测条件相同,起始时间2022-01-01,结束时间2022-11-25。

持有10只,5天轮动。
 

20221126005.jpg

 
在今年的可转债偏弱的行情下,高YTM轮动在这4个策略里面的收益率是最高的。

低溢价一如既然的高波动,一会ICU,一会蹦迪。但笔者觉得跌到前期最大回撤的位置,低溢价可以考虑介入的。
 

20221126010.jpg

 
YTM和低价格的今年回测收益率接近,YTM高了一个点左右,最大回撤接近。 而低溢价还在回撤的途中,目前今年的收益率为-25%,如果轮动频率高一些,低溢价收益率会高一些,强赎的转债基本会被轮入低溢价标的,因为最近半年强赎后的转债像进入了死亡螺旋一样,正股转债一起跌;因此排除强赎转债会对低溢价收益率有不少的提升。
 
完整代码以及数据请开通星球查收。
f088492c7da0ce8b90cbdb7aafe3b191.png

 
 
 
 
 

从零开始 手撸一个回测框架 (以可转债双低,低溢价为例)

量化交易-Ptrade-QMT李魔佛 发表了文章 • 0 个评论 • 2423 次浏览 • 2022-09-01 18:39 • 来自相关话题

因为优矿大部分可转债接口开始收费了,之前星球上分享的回测代码基本也跑不了。不过在关停转收费之前,已经把所需的数据下载下来,而最近的数据通过集思录补充既可。
 




Mysql 数据

 下面是代码主框架,目前通过之前优矿的导出的csv数据 ,计算 各个因子。 通过不同权重评分,进行轮动。class DataFeed:
def __init__(self):
self.csv_path = CSV_PATH
self.position = {}
self.HighValue = 0
self.Start_Cash = 1000000 # 初始资金
self.MyCash = self.Start_Cash
self.Withdraw = 0
self.daily_netvalue =
self.current_day = 0
self.PosValue = 0
self.threshold = 0 # 阈值
self.HighValue = self.Start_Cash
self.date_list, self.source = self.feed()
self.day_count = 0

def unpossibile(self, df, date):
# 剔除当日涨停的转债,买不入
raise_limited_dict = {
'2022-04-08': ['127057', ],
'2022-07-27': ['127065', ],
'2022-07-28': ['127065', ],
}
target_list = raise_limited_dict.get(date, None)
if target_list is None:
return df

return df.drop(index=target_list, axis=1)

def feed(self):
df = pd.read_csv(self.csv_path,
encoding='utf8',
dtype={'tickerEqu': str, 'tickerBond': str, 'secID_x': str},
)
del df['Unnamed: 0']
df['tradeDate'] = pd.to_datetime(df['tradeDate'], format='%Y-%m-%d')
df = df.set_index('tradeDate')
date_set = set(df.index.tolist())
date_list = list(map(lambda x: x.strftime('%Y-%m-%d'), date_set))
date_list.sort()
return date_list, df

def filters(self, df, today):
# 过滤条件,可添加多个条件
df = self.unpossibile(df, today)
return df

def logprint(self, current):
log.info('当前日期{}'.format(current))

def run(self):
for current in self.date_list:

if current < START_DATE or current > END_DATE:
continue

if self.day_count % FREQ != 0:
self.get_daily_netvalue(current)
else:
self.handle_data(current)

self.day_count += 1

self.after_trade()
 
双低和低溢价选债轮动:





 
上面是主要框架代码, 根据数据来驱动交易。 可以根据不同的时间日期进行回测交易。不同持有个数,不同轮动功能天数。【完整代码可以常见 知识星球】
 
运行: python main.py
 





运行后会自动保存一个excel文件:
 
并且可以生成收益率曲线图:
 






完整代码与数据可以参考星球代码:





  查看全部
因为优矿大部分可转债接口开始收费了,之前星球上分享的回测代码基本也跑不了。不过在关停转收费之前,已经把所需的数据下载下来,而最近的数据通过集思录补充既可。
 

20220901004.png
Mysql 数据

 下面是代码主框架,目前通过之前优矿的导出的csv数据 ,计算 各个因子。 通过不同权重评分,进行轮动。
class DataFeed:
def __init__(self):
self.csv_path = CSV_PATH
self.position = {}
self.HighValue = 0
self.Start_Cash = 1000000 # 初始资金
self.MyCash = self.Start_Cash
self.Withdraw = 0
self.daily_netvalue =
self.current_day = 0
self.PosValue = 0
self.threshold = 0 # 阈值
self.HighValue = self.Start_Cash
self.date_list, self.source = self.feed()
self.day_count = 0

def unpossibile(self, df, date):
# 剔除当日涨停的转债,买不入
raise_limited_dict = {
'2022-04-08': ['127057', ],
'2022-07-27': ['127065', ],
'2022-07-28': ['127065', ],
}
target_list = raise_limited_dict.get(date, None)
if target_list is None:
return df

return df.drop(index=target_list, axis=1)

def feed(self):
df = pd.read_csv(self.csv_path,
encoding='utf8',
dtype={'tickerEqu': str, 'tickerBond': str, 'secID_x': str},
)
del df['Unnamed: 0']
df['tradeDate'] = pd.to_datetime(df['tradeDate'], format='%Y-%m-%d')
df = df.set_index('tradeDate')
date_set = set(df.index.tolist())
date_list = list(map(lambda x: x.strftime('%Y-%m-%d'), date_set))
date_list.sort()
return date_list, df

def filters(self, df, today):
# 过滤条件,可添加多个条件
df = self.unpossibile(df, today)
return df

def logprint(self, current):
log.info('当前日期{}'.format(current))

def run(self):
for current in self.date_list:

if current < START_DATE or current > END_DATE:
continue

if self.day_count % FREQ != 0:
self.get_daily_netvalue(current)
else:
self.handle_data(current)

self.day_count += 1

self.after_trade()

 
双低和低溢价选债轮动:

20220901005.png

 
上面是主要框架代码, 根据数据来驱动交易。 可以根据不同的时间日期进行回测交易。不同持有个数,不同轮动功能天数。【完整代码可以常见 知识星球】
 
运行: python main.py
 
20220901001.png


运行后会自动保存一个excel文件:
 
并且可以生成收益率曲线图:
 

20220901003.png


完整代码与数据可以参考星球代码:

星球.png

 

Ptrade回测模式下获取实时的分钟数据:只能使用handle_data,数据不能用get_snapshot

Ptrade李魔佛 发表了文章 • 0 个评论 • 596 次浏览 • 2024-09-21 17:32 • 来自相关话题

好久没有使用Ptrade做分钟级别的回测了。
发现有点蛋疼,记录一下。
 
因为回测模式下,不能使用run_interval 函数;
 
而run_daily模式,只能在固定时间运行,无法分钟级别。
 
所以只能使用 handle_data
而在handle_data 里面获取当前的分钟价格数据,也无法使用 get_snapshot ,get_gear_price,函数。
 
所以只能使用handle_data(Context,data) 里面的data里。
 
而handle_data 里面的data数据,使用方法如下:

 

import datetime

target_list = [
'600000.SS',
'000333.SZ'
]

def execution(context, data):
now = context.current_dt.strftime('%H:%M')
for code in target_list:
tick_info = data[code]
price = tick_info['price']
print('now: {} code : {} price:{}'.format(now,code ,price))




# 标准
def initialize(context):
log.info("公众号:可转债量化分析 ---- start ----")


def handle_data(context, data):
execution(context, data)

 

获取数据结果:2024-09-20 14:42:00 - INFO - now: 14:42 code : 000333.SZ price:66.22
2024-09-20 14:43:00 - INFO - now: 14:43 code : 000333.SZ price:66.26
2024-09-20 14:44:00 - INFO - now: 14:44 code : 000333.SZ price:66.19
2024-09-20 14:45:00 - INFO - now: 14:45 code : 000333.SZ price:66.2
2024-09-20 14:46:00 - INFO - now: 14:46 code : 000333.SZ price:66.19
2024-09-20 14:47:00 - INFO - now: 14:47 code : 000333.SZ price:66.18
2024-09-20 14:48:00 - INFO - now: 14:48 code : 000333.SZ price:66.14
2024-09-20 14:49:00 - INFO - now: 14:49 code : 000333.SZ price:66.25
2024-09-20 14:50:00 - INFO - now: 14:50 code : 000333.SZ price:66.19
2024-09-20 14:51:00 - INFO - now: 14:51 code : 000333.SZ price:66.18
2024-09-20 14:52:00 - INFO - now: 14:52 code : 000333.SZ price:66.19
2024-09-20 14:53:00 - INFO - now: 14:53 code : 000333.SZ price:66.2
2024-09-20 14:54:00 - INFO - now: 14:54 code : 000333.SZ price:66.19
2024-09-20 14:55:00 - INFO - now: 14:55 code : 000333.SZ price:66.25
2024-09-20 14:56:00 - INFO - now: 14:56 code : 000333.SZ price:66.27
2024-09-20 14:57:00 - INFO - now: 14:57 code : 000333.SZ price:66.28
2024-09-20 14:58:00 - INFO - now: 14:58 code : 000333.SZ price:66.28
2024-09-20 14:59:00 - INFO - now: 14:59 code : 000333.SZ price:66.28
2024-09-20 15:00:00 - INFO - now: 15:00 code : 000333.SZ price:66.06
 用同花顺,对了一下结果,是满足的了。
 

  查看全部
好久没有使用Ptrade做分钟级别的回测了。
发现有点蛋疼,记录一下。
 
因为回测模式下,不能使用run_interval 函数;
 
而run_daily模式,只能在固定时间运行,无法分钟级别。
 
所以只能使用 handle_data
而在handle_data 里面获取当前的分钟价格数据,也无法使用 get_snapshot ,get_gear_price,函数。
 
所以只能使用handle_data(Context,data) 里面的data里。
 
而handle_data 里面的data数据,使用方法如下:

 


import datetime

target_list = [
'600000.SS',
'000333.SZ'
]

def execution(context, data):
now = context.current_dt.strftime('%H:%M')
for code in target_list:
tick_info = data[code]
price = tick_info['price']
print('now: {} code : {} price:{}'.format(now,code ,price))




# 标准
def initialize(context):
log.info("公众号:可转债量化分析 ---- start ----")


def handle_data(context, data):
execution(context, data)

 

获取数据结果:
2024-09-20 14:42:00 - INFO - now: 14:42 code : 000333.SZ price:66.22
2024-09-20 14:43:00 - INFO - now: 14:43 code : 000333.SZ price:66.26
2024-09-20 14:44:00 - INFO - now: 14:44 code : 000333.SZ price:66.19
2024-09-20 14:45:00 - INFO - now: 14:45 code : 000333.SZ price:66.2
2024-09-20 14:46:00 - INFO - now: 14:46 code : 000333.SZ price:66.19
2024-09-20 14:47:00 - INFO - now: 14:47 code : 000333.SZ price:66.18
2024-09-20 14:48:00 - INFO - now: 14:48 code : 000333.SZ price:66.14
2024-09-20 14:49:00 - INFO - now: 14:49 code : 000333.SZ price:66.25
2024-09-20 14:50:00 - INFO - now: 14:50 code : 000333.SZ price:66.19
2024-09-20 14:51:00 - INFO - now: 14:51 code : 000333.SZ price:66.18
2024-09-20 14:52:00 - INFO - now: 14:52 code : 000333.SZ price:66.19
2024-09-20 14:53:00 - INFO - now: 14:53 code : 000333.SZ price:66.2
2024-09-20 14:54:00 - INFO - now: 14:54 code : 000333.SZ price:66.19
2024-09-20 14:55:00 - INFO - now: 14:55 code : 000333.SZ price:66.25
2024-09-20 14:56:00 - INFO - now: 14:56 code : 000333.SZ price:66.27
2024-09-20 14:57:00 - INFO - now: 14:57 code : 000333.SZ price:66.28
2024-09-20 14:58:00 - INFO - now: 14:58 code : 000333.SZ price:66.28
2024-09-20 14:59:00 - INFO - now: 14:59 code : 000333.SZ price:66.28
2024-09-20 15:00:00 - INFO - now: 15:00 code : 000333.SZ price:66.06

 用同花顺,对了一下结果,是满足的了。
 

 

优矿的回测引擎运行在python2.7,汗

量化交易李魔佛 发表了文章 • 0 个评论 • 665 次浏览 • 2024-07-22 11:59 • 来自相关话题

之前看到优矿的报错提示如下:

回测引擎运行在 Python2.7 之上,请您使用 Python2.7 的写法进行策略编写。
 
居然回测引擎还在2.7,怪不得目前性能比较拉跨了呢。。。
 
不过话说,自从它的可转债数据收费之后,我就一直没有再使用优矿进行回测了。
 
  查看全部
之前看到优矿的报错提示如下:

回测引擎运行在 Python2.7 之上,请您使用 Python2.7 的写法进行策略编写。
 
居然回测引擎还在2.7,怪不得目前性能比较拉跨了呢。。。
 
不过话说,自从它的可转债数据收费之后,我就一直没有再使用优矿进行回测了。
 
 

可转债到期收益率因子回测 YTM回测 vs 双低 低溢价 低价策略

可转债李魔佛 发表了文章 • 0 个评论 • 1794 次浏览 • 2022-11-26 16:51 • 来自相关话题

最近看到有人发的一些可转债高YTM的回测结果图,说高YTM轮动收益达到年化20%。嗯?高TYM实际上大部分是和低价转债是重叠的,理论和实际收益率都应该不会有这么高的。

自从优矿转为收费后,基本就没有登录过了。现在的回测在本地进行了,宁稳网的可转债数据上有YTM这因子数据,所以这次使用宁稳网的数据回测。也不使用什么第三方框架了,直接手写回测,模拟交易过程。
 
逻辑就是按照交易日期,读取所有excel数据。保存到一个dataframe里面,然后按照日期对YTM排名。 选出排名N名的进行买入,掉出N名的进行卖出。
 
数据源
 
采用宁稳的全表数据,里面有YTM因子





 





 
YTM收益率曲线
本地使用python编写回测代码,纯手工,不使用第三方框架。 平时我也多次力荐大家手写,别依赖那些第三方框架,什么vnpy,backtrade,一是特别难用,数据要适配,二是不好调试,除非你对它们的源码特别熟悉。本回测代码和宁稳数据放在个人知识星球,大部分人其实只关心回测结果就够了。

下图是2022年1月1日至11月25日的回测数据。持有10个标的,红色的是1天调仓,蓝色的是5天调仓
 





 
5天轮动,2022年的收益率为4.29%,最大回撤6.98% 。

1天轮动,2022年的收益率为9.33%,最大回撤5.32% 。

1天轮动的整体收益率要比5天轮动的高5个点,并且最大回撤也小一点。

持仓日志
 






从持仓以及调仓日志来看,买入的大部分是低价转债,且部分也是之前有瑕疵,爆过雷的转债。
 
高YTM轮动 vs 双低,低溢价,低价

接着对比一下几个常规的转债策略,双低,低溢价,低价。

回测条件相同,起始时间2022-01-01,结束时间2022-11-25。

持有10只,5天轮动。
 





 
在今年的可转债偏弱的行情下,高YTM轮动在这4个策略里面的收益率是最高的。

低溢价一如既然的高波动,一会ICU,一会蹦迪。但笔者觉得跌到前期最大回撤的位置,低溢价可以考虑介入的。
 





 
YTM和低价格的今年回测收益率接近,YTM高了一个点左右,最大回撤接近。 而低溢价还在回撤的途中,目前今年的收益率为-25%,如果轮动频率高一些,低溢价收益率会高一些,强赎的转债基本会被轮入低溢价标的,因为最近半年强赎后的转债像进入了死亡螺旋一样,正股转债一起跌;因此排除强赎转债会对低溢价收益率有不少的提升。
 
完整代码以及数据请开通星球查收。




 
 
 
 
  查看全部
最近看到有人发的一些可转债高YTM的回测结果图,说高YTM轮动收益达到年化20%。嗯?高TYM实际上大部分是和低价转债是重叠的,理论和实际收益率都应该不会有这么高的。

自从优矿转为收费后,基本就没有登录过了。现在的回测在本地进行了,宁稳网的可转债数据上有YTM这因子数据,所以这次使用宁稳网的数据回测。也不使用什么第三方框架了,直接手写回测,模拟交易过程。
 
逻辑就是按照交易日期,读取所有excel数据。保存到一个dataframe里面,然后按照日期对YTM排名。 选出排名N名的进行买入,掉出N名的进行卖出。
 
数据源
 
采用宁稳的全表数据,里面有YTM因子

20221126001.jpg

 
20221126002.jpg


 
YTM收益率曲线
本地使用python编写回测代码,纯手工,不使用第三方框架。 平时我也多次力荐大家手写,别依赖那些第三方框架,什么vnpy,backtrade,一是特别难用,数据要适配,二是不好调试,除非你对它们的源码特别熟悉。本回测代码和宁稳数据放在个人知识星球,大部分人其实只关心回测结果就够了。

下图是2022年1月1日至11月25日的回测数据。持有10个标的,红色的是1天调仓,蓝色的是5天调仓
 

20221126006.jpg

 
5天轮动,2022年的收益率为4.29%,最大回撤6.98% 。

1天轮动,2022年的收益率为9.33%,最大回撤5.32% 。

1天轮动的整体收益率要比5天轮动的高5个点,并且最大回撤也小一点。

持仓日志
 

20221126009.jpg


从持仓以及调仓日志来看,买入的大部分是低价转债,且部分也是之前有瑕疵,爆过雷的转债。
 
高YTM轮动 vs 双低,低溢价,低价

接着对比一下几个常规的转债策略,双低,低溢价,低价。

回测条件相同,起始时间2022-01-01,结束时间2022-11-25。

持有10只,5天轮动。
 

20221126005.jpg

 
在今年的可转债偏弱的行情下,高YTM轮动在这4个策略里面的收益率是最高的。

低溢价一如既然的高波动,一会ICU,一会蹦迪。但笔者觉得跌到前期最大回撤的位置,低溢价可以考虑介入的。
 

20221126010.jpg

 
YTM和低价格的今年回测收益率接近,YTM高了一个点左右,最大回撤接近。 而低溢价还在回撤的途中,目前今年的收益率为-25%,如果轮动频率高一些,低溢价收益率会高一些,强赎的转债基本会被轮入低溢价标的,因为最近半年强赎后的转债像进入了死亡螺旋一样,正股转债一起跌;因此排除强赎转债会对低溢价收益率有不少的提升。
 
完整代码以及数据请开通星球查收。
f088492c7da0ce8b90cbdb7aafe3b191.png

 
 
 
 
 

从零开始 手撸一个回测框架 (以可转债双低,低溢价为例)

量化交易-Ptrade-QMT李魔佛 发表了文章 • 0 个评论 • 2423 次浏览 • 2022-09-01 18:39 • 来自相关话题

因为优矿大部分可转债接口开始收费了,之前星球上分享的回测代码基本也跑不了。不过在关停转收费之前,已经把所需的数据下载下来,而最近的数据通过集思录补充既可。
 




Mysql 数据

 下面是代码主框架,目前通过之前优矿的导出的csv数据 ,计算 各个因子。 通过不同权重评分,进行轮动。class DataFeed:
def __init__(self):
self.csv_path = CSV_PATH
self.position = {}
self.HighValue = 0
self.Start_Cash = 1000000 # 初始资金
self.MyCash = self.Start_Cash
self.Withdraw = 0
self.daily_netvalue =
self.current_day = 0
self.PosValue = 0
self.threshold = 0 # 阈值
self.HighValue = self.Start_Cash
self.date_list, self.source = self.feed()
self.day_count = 0

def unpossibile(self, df, date):
# 剔除当日涨停的转债,买不入
raise_limited_dict = {
'2022-04-08': ['127057', ],
'2022-07-27': ['127065', ],
'2022-07-28': ['127065', ],
}
target_list = raise_limited_dict.get(date, None)
if target_list is None:
return df

return df.drop(index=target_list, axis=1)

def feed(self):
df = pd.read_csv(self.csv_path,
encoding='utf8',
dtype={'tickerEqu': str, 'tickerBond': str, 'secID_x': str},
)
del df['Unnamed: 0']
df['tradeDate'] = pd.to_datetime(df['tradeDate'], format='%Y-%m-%d')
df = df.set_index('tradeDate')
date_set = set(df.index.tolist())
date_list = list(map(lambda x: x.strftime('%Y-%m-%d'), date_set))
date_list.sort()
return date_list, df

def filters(self, df, today):
# 过滤条件,可添加多个条件
df = self.unpossibile(df, today)
return df

def logprint(self, current):
log.info('当前日期{}'.format(current))

def run(self):
for current in self.date_list:

if current < START_DATE or current > END_DATE:
continue

if self.day_count % FREQ != 0:
self.get_daily_netvalue(current)
else:
self.handle_data(current)

self.day_count += 1

self.after_trade()
 
双低和低溢价选债轮动:





 
上面是主要框架代码, 根据数据来驱动交易。 可以根据不同的时间日期进行回测交易。不同持有个数,不同轮动功能天数。【完整代码可以常见 知识星球】
 
运行: python main.py
 





运行后会自动保存一个excel文件:
 
并且可以生成收益率曲线图:
 






完整代码与数据可以参考星球代码:





  查看全部
因为优矿大部分可转债接口开始收费了,之前星球上分享的回测代码基本也跑不了。不过在关停转收费之前,已经把所需的数据下载下来,而最近的数据通过集思录补充既可。
 

20220901004.png
Mysql 数据

 下面是代码主框架,目前通过之前优矿的导出的csv数据 ,计算 各个因子。 通过不同权重评分,进行轮动。
class DataFeed:
def __init__(self):
self.csv_path = CSV_PATH
self.position = {}
self.HighValue = 0
self.Start_Cash = 1000000 # 初始资金
self.MyCash = self.Start_Cash
self.Withdraw = 0
self.daily_netvalue =
self.current_day = 0
self.PosValue = 0
self.threshold = 0 # 阈值
self.HighValue = self.Start_Cash
self.date_list, self.source = self.feed()
self.day_count = 0

def unpossibile(self, df, date):
# 剔除当日涨停的转债,买不入
raise_limited_dict = {
'2022-04-08': ['127057', ],
'2022-07-27': ['127065', ],
'2022-07-28': ['127065', ],
}
target_list = raise_limited_dict.get(date, None)
if target_list is None:
return df

return df.drop(index=target_list, axis=1)

def feed(self):
df = pd.read_csv(self.csv_path,
encoding='utf8',
dtype={'tickerEqu': str, 'tickerBond': str, 'secID_x': str},
)
del df['Unnamed: 0']
df['tradeDate'] = pd.to_datetime(df['tradeDate'], format='%Y-%m-%d')
df = df.set_index('tradeDate')
date_set = set(df.index.tolist())
date_list = list(map(lambda x: x.strftime('%Y-%m-%d'), date_set))
date_list.sort()
return date_list, df

def filters(self, df, today):
# 过滤条件,可添加多个条件
df = self.unpossibile(df, today)
return df

def logprint(self, current):
log.info('当前日期{}'.format(current))

def run(self):
for current in self.date_list:

if current < START_DATE or current > END_DATE:
continue

if self.day_count % FREQ != 0:
self.get_daily_netvalue(current)
else:
self.handle_data(current)

self.day_count += 1

self.after_trade()

 
双低和低溢价选债轮动:

20220901005.png

 
上面是主要框架代码, 根据数据来驱动交易。 可以根据不同的时间日期进行回测交易。不同持有个数,不同轮动功能天数。【完整代码可以常见 知识星球】
 
运行: python main.py
 
20220901001.png


运行后会自动保存一个excel文件:
 
并且可以生成收益率曲线图:
 

20220901003.png


完整代码与数据可以参考星球代码:

星球.png