量化研究---年化25%西蒙斯全市场可转债趋势增强策略4.0回测
策略我全部上传了,可以结合自己的选股改源代码,后面我会对接选股模块,先自定义选股因子,在做趋势增强交易,这样会比较安全,剔除有问题的可转债,可以参考可转债5因子的自定义算法框架。文章声明:本内容为个人的业余研究,和任何单位,机构没有关系,文章出现的股票代码,全部只是测试例子,不做投资参考,投资有风险,代码学习使用,不做商业用途。:均线代表不同时间周期的市场平均成本,短周期均线反映短期趋势,长周期均
文章声明:本内容为个人的业余研究,和任何单位,机构没有关系,文章出现的股票代码,全部只是测试例子,不做投资参考,投资有风险,代码学习使用,不做商业用途
今天把蒙斯全市场可转债趋势增强策略4.0做了一些回测,当然大qmt的版本也是上线了,明天给详细的使用教程
1700多行源代码,真正的实盘细节很复杂
下面是我服务器的仿真交易数据全市场趋势增强模型
可转债趋势增强
仿真交易数据
持股数据
策略原理
全市场可转债趋势增强策略参数原理与逻辑分析
1. 策略核心逻辑概述
该策略是一个多因子趋势增强型可转债策略,核心思路是:
-
趋势跟踪(均线系统+趋势强度指标)
-
动量增强(短期收益筛选)
-
波段交易(六脉神剑信号+小水果波段模型)
-
动态调仓(持股限制+买卖金额控制)
策略通过量化指标筛选可转债,在趋势确立时买入,在趋势转弱或反转时卖出,以增强收益并控制回撤。
2. 关键参数与原理分析
(1)均线系统参数
3日、5日、10日、15日、20日均线
-
原理:均线代表不同时间周期的市场平均成本,短周期均线反映短期趋势,长周期均线反映长期趋势。
-
策略作用:
-
趋势确认:短期均线(3日、5日)上穿长期均线(10日、15日、20日)表明趋势增强。
-
支撑/阻力:价格站上5日均线(
df['站上均线']
)表明短期趋势向上,跌破则可能转弱。
-
站上/跌破5日均线信号
-
买入条件:
df['站上均线'] == True
-
逻辑:价格高于5日均线,短期趋势看涨。
-
-
卖出条件:
df['跌破均线'] == True
-
逻辑:价格低于5日均线,短期趋势可能转弱。
-
(2)趋势强度指标(df['趋势强度']
)
计算方式
-
通过均线排列顺序计算得分:
-
3日 ≥ 5日 → +25分
-
5日 ≥ 10日 → +25分
-
10日 ≥ 15日 → +25分
-
15日 ≥ 20日 → +25分
-
满分100分,代表均线呈完美多头排列。
-
策略作用
-
买入条件:
趋势强度 ≥ 75
-
逻辑:短期均线明显强于长期均线,趋势强劲。
-
-
卖出条件:
趋势强度 ≤ 50
-
逻辑:均线排列混乱或空头排列,趋势可能结束。
-
(3)动量指标(短期收益筛选)
5日累计收益(df['N日收益']
)
-
计算方式:最近5日涨跌幅之和。
-
买入条件:
3% ≤ N日收益 ≤ 20%
-
下限3%:避免买入弱势转债(动量不足)。
-
上限20%:避免追高短期暴涨品种(防止回调风险)。
-
逻辑:
-
前一日收益(df['前N天收益']
)
-
计算方式:前1日涨跌幅。
-
买入条件:
0% ≤ 前N天收益 ≤ 7%
-
下限0%:避免买入当日下跌的转债(短期弱势)。
-
上限7%:避免追高单日暴涨品种(可能回调)。
-
逻辑:
-
(4)六脉神剑日周期信号(df['六脉神剑日周期']
)
原理
-
该信号可能基于技术形态或波动率指标(如MACD、RSI、布林带等组合),用于判断短期趋势强度。
-
买入条件:
六脉神剑日周期 ≥ 4
-
逻辑:短期趋势信号较强,适合进场。
-
-
卖出条件:
六脉神剑日周期 ≤ 3
-
逻辑:短期趋势信号减弱,可能反转。
-
连续六脉神剑数量(df['连续六脉神剑数量']
)
-
用于排序买入优先级,连续信号越多,趋势越稳定。
(5)小水果波段交易模型(df['波段状态']
)
原理
-
该模型可能基于价格波动区间或超买超卖指标(如KDJ、CCI),判断当前处于"买"或"卖"波段。
-
买入条件:
波段状态 == '买'
-
逻辑:当前处于适合买入的波段低位。
-
-
卖出条件:
波段状态 == '卖'
-
逻辑:当前处于适合卖出的波段高位。
-
(6)资金管理与风险控制参数
持股限制(self.hold_limit = 20
)
-
逻辑:分散持仓,降低单只转债风险,避免过度集中。
单笔买入金额(self.buy_value = 10000
)
-
逻辑:固定金额买入,控制单只转债仓位,避免过度暴露。
单笔卖出金额(self.sell_value = 20000
)
-
逻辑:卖出金额大于买入金额,可能用于动态止盈或加速调仓。
3. 策略优势与适用场景
优势
-
趋势跟随:避免逆势交易,只在趋势明确时进场。
-
动量过滤:筛选近期表现较好的转债,提高胜率。
-
多因子验证:均线、趋势强度、波段信号等多指标综合判断,减少误判。
-
严格风控:持股分散+动态调仓,降低单一标的风险。
适用市场环境
-
趋势市(单边上涨或下跌):均线系统+趋势强度有效。
-
震荡市(波段行情):小水果波段模型+六脉神剑信号辅助判断。
-
不适合极端波动市(如暴涨暴跌):短期收益限制可能错过极端行情。
看趋势模型选股出来的数据,股票池可以优化结合选个股模板算法,选择全市场趋势强的可转债交易
回测的数据,默认持股20,提高盈亏比
策略我全部上传了,可以结合自己的选股改源代码,后面我会对接选股模块,先自定义选股因子,在做趋势增强交易,这样会比较安全,剔除有问题的可转债,可以参考可转债5因子的自定义算法框架量化研究---推出年华化30%西蒙斯可转债5因子策略2.0版本https://mp.weixin.qq.com/s?__biz=MzI5NTE5NTExMw==&mid=2247494690&idx=1&sn=7977e7c1f7f702cfdf2a4d4bb74f68ab&scene=21#wechat_redirect
不懂的问我就可以,加我备注入群可以加入量化
全部的回测代码,我自研的回测算法框架,回测几百万的数据没有问题
from xms_quant_backtrader import xms_quant_backtrader
from tdx_strategy_models.small_fruit_band_trading import small_fruit_band_trading
from tdx_strategy_models.six_pulse_excalibur_hist import six_pulse_excalibur_hist
import pandas as pd
from xg_tdx_func.xg_tdx_func import *
class xms_quant_backtrader_zz100:
def __init__(self,
trader_tool='qmt',
data_api='qmt',
data_type='D',
stock_list=[],
start_date='20200101',
end_date='20500101',
total_cash=200000,
st_name='西蒙斯全市场可转债趋势增强策略'
):
'''
西蒙斯量化回测系统3.0
作者:西蒙斯量化
微信:xg_quant
数据源data_api选择qmt,需要先打开miniqmt登录,选择dfcf就不需要,建议使用qmt
'''
self.trader_tool=trader_tool
self.data_api=data_api
self.data_type=data_type
self.stock_list=stock_list
self.start_date=start_date
self.end_date=end_date
self.total_cash=total_cash
self.trader=xms_quant_backtrader(
trader_tool=self.trader_tool,
data_api=self.data_api,
data_type=self.data_type,
stock_list=self.stock_list,
start_date=self.start_date,
end_date=self.end_date,
total_cash=self.total_cash,
st_name=st_name)
self.hold_limit=20
self.buy_value=10000
self.sell_value=20000
def get_all_hist_data(self):
'''
获取全部历史数据
'''
stock_list=self.trader.get_read_tdx_data(r'QBKZZ.blk')['证券代码'].tolist()
self.trader.re_trader_stock(stock_list=stock_list)
self.trader.get_hist_data()
hist=self.trader.data.get_hist_data()
hist=hist.sort_values(by='date')
hist.to_csv(r'全部历史数据.csv')
return hist
def get_all_user_hist_data(self):
'''
加载本地历史数据
'''
stock_list=self.trader.get_read_tdx_data(r'ZZA100.blk')['证券代码'].tolist()
self.trader.re_trader_stock(stock_list=stock_list)
df=pd.read_csv(r'全部历史数据.csv')
self.trader.get_user_hist_data(df)
hist=self.trader.data.get_hist_data()
return hist
def cacal_stock_score(self,x1,x2,x3,x4,x5):
'''
计算分数
'''
score=0
if x1>=x2:
score+=25
if x2>=x3:
score+=25
if x3>=x4:
score+=25
if x4>=x5:
score+=25
return score
def cacal_all_stock_indicator(self):
'''
计算全部的指标
'''
data=pd.DataFrame()
#hist=self.get_all_user_hist_data()
hist=self.get_all_hist_data()
stock_list=self.trader.get_trader_stock()
for stock in stock_list:
df=hist[hist['stock']==stock]
df=df.sort_values(by='date')
if df.shape[0]>0:
df['3日均线']=df['close'].rolling(3).mean()
df['5日均线']=df['close'].rolling(5).mean()
df['10日均线']=df['close'].rolling(10).mean()
df['15日均线']=df['close'].rolling(15).mean()
df['20日均线']=df['close'].rolling(20).mean()
df['站上均线']=df['close']>=df['5日均线']
df['跌破均线']=df['close']<df['5日均线']
df['涨跌幅']=df['close'].pct_change()*100
df['N日收益']=df['涨跌幅'].rolling(5).sum()
df['前N天收益']=df['涨跌幅'].shift(1)
df['趋势强度'] = df.apply(lambda row: self.cacal_stock_score(row['3日均线'], row['5日均线'], row['10日均线'], row['15日均线'], row['20日均线']), axis=1).tolist()
models=six_pulse_excalibur_hist(df=df)
result=models.six_pulse_excalibur_hist()
stats=result['signal'].tolist()
df['六脉神剑日周期']=stats
df['六脉神剑日周期数量']= df['六脉神剑日周期'].rolling(5).sum()
df.reset_index(drop=True, inplace=True)
df['连续六脉神剑数量']= BARSLASTCOUNT(df['六脉神剑日周期']>=5)
models=small_fruit_band_trading(df=df)
result=models.small_fruit_band_trading()
stats=result['stats'].tolist()
df['波段状态']=stats
df.reset_index(drop=True, inplace=True)
df['买的波段数量'] = BARSLASTCOUNT(df['波段状态']=='买')
data=pd.concat([data,df],ignore_index=False)
print(data)
data.to_excel(r'全部因子数据.xlsx')
return data
def get_buy_sell_data(self):
'''
获取买卖数据
'''
df=self.cacal_all_stock_indicator()
print('获取买卖数据**********')
buy_condi = (
(df['趋势强度'] >= 75) &
(df['站上均线']==True) &
(df['涨跌幅'] >= 0) &
(df['涨跌幅'] <= 5) &
(df['六脉神剑日周期'] >= 4) &
(df['N日收益']>=3) &
(df['N日收益']<=20) &
(df['前N天收益']>=0) &
(df['前N天收益'] <=7) &
(df['波段状态']=='买')
)
sell_condi = (
(df['趋势强度'] <= 50) |
(df['跌破均线']==True) |
(df['六脉神剑日周期'] <= 3) |
(df['波段状态']=='卖')
)
df['buy']=buy_condi
df['sell']=sell_condi
buy_df=df[df['buy']==True]
sell_df=df[df['sell']==True]
return buy_df,sell_df
def run_backtrader(self):
'''
运行回测
'''
print('运行回测')
st_buy_df,st_sell_df=self.get_buy_sell_data()
trader_date_list=self.trader.get_trader_date_list()
for date in trader_date_list:
if st_buy_df.shape[0]>0:
buy_df=st_buy_df[st_buy_df['date']==date]
#排序因子
buy_df=buy_df.sort_values(by=[
"买的波段数量",
"N日收益",
"连续六脉神剑数量",
"趋势强度"],
ascending=False)
else:
buy_df=pd.DataFrame()
if st_sell_df.shape[0]>0:
sell_df=st_sell_df[st_sell_df['date']==date]
else:
sell_df=pd.DataFrame()
position=self.trader.position.get_position_data()
if position.shape[0]>0:
position=position[position['股票余额']>=10]
if position.shape[0]>0:
position=position
hold_amount=position.shape[0]
hold_stock_list=position['证券代码'].tolist()
else:
position=pd.DataFrame()
hold_amount=0
hold_stock_list=[]
else:
position=pd.DataFrame()
hold_amount=0
hold_stock_list=[]
if position.shape[0]>0:
if sell_df.shape[0]>0:
sell_stock_list=sell_df['stock'].tolist()
else:
sell_stock_list=[]
position['卖出']=position['证券代码'].apply(lambda x: '是' if x in sell_stock_list else '不是')
sell_df=position[position['卖出']=='是']
sell_amount=sell_df.shape[0]
else:
sell_df=pd.DataFrame()
sell_amount=0
av_amount=(self.hold_limit-hold_amount)+sell_amount
if av_amount<0:
print(date,'达到持股限制不买入')
av_amount=0
else:
av_amount=av_amount
print('***************************')
print('{} 持股限制{} 持有数量{} 卖出数量{} 可以买入数量{}'.format(date,self.hold_limit,hold_amount,sell_amount,av_amount))
if buy_df.shape[0]>0:
buy_df['持股']=buy_df['stock'].apply(lambda x: '是' if x in hold_stock_list else '不是')
buy_df=buy_df[buy_df['持股']=='不是']
else:
buy_df=buy_df
buy_df=buy_df[:av_amount]
print('持有的股票*****************')
print(position)
print('卖出股票***********')
print(sell_df)
print('买入股票************')
print(buy_df)
#先卖出在买入
if sell_df.shape[0]>0:
for stock in sell_df['证券代码'].tolist():
price=self.trader.get_price(date=date,stock=stock)
trader_type,amount,price=self.trader.order_value(
date=date,
stock=stock,
value=self.sell_value,
price=price,
trader_type='sell'
)
if trader_type=='sell' and amount>=10:
self.trader.sell(
date=date,
stock=stock,
amount=amount,
price=price,
maker='卖出成功')
else:
print(date,stock,'买入失败')
else:
print(date,'卖出没有持股数据')
#买入
if buy_df.shape[0]>0:
for stock in buy_df['stock'].tolist():
price=self.trader.get_open_price(date=date,stock=stock)
trader_type,amount,price=self.trader.order_value(
date=date,
stock=stock,
value=self.buy_value,
price=price,
trader_type='buy'
)
if trader_type=='buy' and amount>=10:
self.trader.buy(
date=date,
stock=stock,
amount=amount,
price=price,
maker='买入成功')
else:
print(date,stock,'买入失败')
else:
print(date,'买入没有持股数据')
#结算
self.trader.settlement_data(date=date)
def get_backtrader_result(self):
'''
获取回测结果
'''
self.trader.generate_strategy_report()
self.trader.get_all_trader_data()
if __name__=='__main__':
trader=xms_quant_backtrader_zz100()
df=trader.run_backtrader()
trader.get_backtrader_result()
更多推荐
所有评论(0)