量化研究---可转债量化交易系统上线快速服务器
现在可转债交易系统使用的人多,服务器比较小,今天对服务器进行了升级,提供快速的数据支持,同时我也给了服务器的源代码,支持自定义服务器数据支持,不通过我服务器,可以挂在服务器上面24小时快速交易,文章https://mp.weixin.qq.com/s/vmDorXu6ZbgazhJCS-JPSg
服务器24小时运行
配合高频量化模块
同时我也提供了大qmt版本
知识星球有全部直接下载就可以
高速服务器网页http://101.34.65.108:8023/
默认因子数据
合成因子
策略表现
我实盘的表现不错,可转债网页http://120.78.132.143:8888/
比如可转债5因子策略
点击选股数据
持股数据
交易报告
实盘设置点击可转债高速服务器策略
输入账户
支持自定义框架
源代码很多1000行可以研究
点击运行测试数据
选股数据
和网页一样的
挂模型实盘交易
源代码我全部上传了知识星球可以下载使用研究实盘框架,我也给了miniqmt版本
不懂的问我就可以,加我备注人群可以加入量化群
部分源代码,完整的1000多行太长了
#encoding:gbk
'''
小果可转债5因子轮动策略2,换了一个高速服务器
小果可转债5因子轮动策略高速服务器
作者:小果
微信:15117320079
时间:20250226
输入自己的账户就可以
"账户":"111111",
建议使用综合交易模型,miniqmt,配合实时脉冲,网格,止盈止损交易
先小资金测试熟悉,支持融资融券
支持自定义服务器数据
下单的价格编码
数值 描述
-1 无效(只对于algo_passorder起作用)
0 卖5价
1 卖4价
2 卖3价
3 卖2价
4 卖1价
5 最新价
6 买1价
7 买2价(组合不支持)
8 买3价(组合不支持)
9 买4价(组合不支持)
10 买5价(组合不支持)
'''
import pandas as pd
import talib
import time
from datetime import datetime
import math
import json
import requests
text={
"账户":"",
"账户支持融资融券":"账户支持融资融券,账户类型STOCK/CREDIT",
"账户类型":"STOCK",
"买入价格编码":5,
"卖出价格编码":5,
"是否测试":"否",
"测试时间":'20250303',
"黑名单":['600031.SH'],
"是否隔离策略":"是",
"交易模式说明":"金额/数量",
"交易模式":"金额",
"固定交易金额":2000,
"固定交易数量":100,
"特殊交易标的设置":"特殊交易标的设置",
"特殊交易标的":[],
"特殊交易标的固定交易金额":15000,
"特殊交易标的固定交易数量":100,
"小果可转债自定义因子轮动策略": "小果可转债服务器提供实时因子数据支持",
"服务器数据源设置": "服务器数据源设置********",
"服务器": "http://101.34.65.108",
"端口": "8023",
"服务器编码":"5071dc6e12cd478aa2ab511bbb96abce1f6c0a05a17df9112582acfb29cc3216",
"授权码": "123456",
"时间设置":"时间设置********",
"交易时间段":8,
"交易开始时间":9,
"交易结束时间":24,
"是否参加集合竞价":"否",
"开始交易分钟":0,
"可转债自定义因子计算": "可转债自定义因子计算************,基于默认因子表计算,df是因子表名称",
"是否开启默认因子计算": "是",
"默认因子计算": {
"三要素评分": "df['溢价率']*100+df['剩余年限']-df['到期税前收益']*100"
},
"强制赎回设置": "************************",
"是否剔除强制赎回": "是",
"满足强制赎回天数": 10,
"排除上市天数": 3,
"是否排除ST": "是",
"排除市场": [],
"行业说明": "查询行业表**********,混合排除不区分一二三级行业",
"排除行业": [],
"排除企业类型": [],
"排除地域": [],
"排除外部评级": [],
"排除三方评级": [],
"添加排除因子": "排除因子设置************************",
"因子计算符号说明": "大于,小于,大于排名%,小于排名%,空值,排除是相反的,大于是小于",
"排除因子": [
"双低",
"双低",
"剩余规模(亿)",
"剩余规模(亿)",
"剩余年限",
"溢价率",
"溢价率",
"价格",
"价格",
"正股年化波动率",
"涨幅",
"换手率"
],
"因子计算符号": [
"大于",
"小于",
"大于",
"小于",
"小于",
"大于",
"小于",
"大于",
"小于",
"小于",
"小于",
"小于"
],
"因子值": [
170,
100,
8,
1,
1,
70,
-1,
150,
100,
60,
0,
5
],
"打分因子设置": "*************************************************",
"打分因子说明": "正相关:因子值越大得分越高;负相关:因子值越大得分越低,",
"打分因子": [
"5日斜率",
"正股年化波动率"
],
"因子相关性": [
"正相关",
"正相关"
],
"因子权重": [
1
],
"持有限制": 10,
"持股限制": 10,
"轮动规则设置": "轮动规则设置88888888**********排名",
"买入排名前N": 10,
"持有排名前N": 10,
"跌出排名卖出N": 10,
"买入前N": 10,
}
class A():
pass
a=A()
def init(c):
#账户
c.account=text['账户']
#账户类型
c.account_type=text['账户类型']
#交易股票池
hold_limit=text['持有限制']
if c.account_type=='stock' or c.account_type=='STOCK':
c.buy_code=23
c.sell_code=24
else:
#融资融券
c.buy_code=33
c.sell_code=34
c.buy_price_code=text['买入价格编码']
c.sell_price_code=text['卖出价格编码']
c.del_trader_list=text['黑名单']
#可以考虑一天轮动2次
c.run_time("run_tarder_func","1nDay","2024-07-25 10:30:00")
c.run_time("run_tarder_func","1nDay","2024-07-25 14:25:00")
#30分钟一次
#c.run_time("run_tarder_func","1800nSecond","2024-07-25 13:20:00")
c.run_time("trader_info","3nSecond","2024-07-25 13:20:00")
print(get_account(c,c.account,c.account_type))
print(get_position(c,c.account,c.account_type))
print(run_tarder_func(c))
def handlebar(c):
#run_tarder_func(c)
pass
def trader_info(c):
if check_is_trader_date_1():
print('{} 等待程序调仓'.format(datetime.now()))
else:
print('{} 不是交易时间等待程序调仓'.format(datetime.now()))
def get_price(c,stock):
'''
获取最新价格
'''
tick=c.get_full_tick(stock_code=[stock])
tick=tick[stock]
price=tick['lastPrice']
return price
def get_trader_data(c):
'''
小果可转债5因子轮动策略
'''
url=text['服务器']
port=text['端口']
url_code=text['服务器编码']
password=text['授权码']
test=text['是否测试']
test_date=text['测试时间']
if test=='是':
print('开启测试模式实盘记得关闭********************')
date=test_date
else:
date=''.join(str(datetime.now())[:10].split('-'))
#date='20250229'
print('小果服务器提供数据支持***************************')
print('服务器{} 端口{} 授权码{}'.format(url,port,password))
models=small_fruit_custom_factor_selection_system(url=url,
port=port,
url_code=url_code,
password=password,
text=text,
date=date,
limit=30)
stats,df=models.get_select_result()
if stats==True:
print('可转债数据获取成功,开始轮动分析')
print('选股结果*********************')
print(df)
df['更新时间']=datetime.now()
hold_limit=text['持股限制']
buy_rank=text['持有排名前N']
hold_stock=get_position(c,c.account,c.account_type)
if hold_stock.shape[0]>0:
hold_stock=hold_stock[hold_stock['持仓量']>=10]
if hold_stock.shape[0]>0:
hold_stock['证券代码']=hold_stock['证券代码'].astype(str)
hold_stock_list=hold_stock['证券代码'].tolist()
hold_amount=hold_stock.shape[0]
else:
hold_stock_list=[]
hold_amount=0
else:
hold_stock_list=[]
hold_amount=0
df=df
if df.shape[0]>0:
df['可转债代码']=df['可转债代码'].astype(str)
df['可转债代码']=df['可转债代码'].apply(lambda x:adjust_stock(x))
all_stock_list=df['可转债代码'].tolist()
buy_stock_list=df['可转债代码'].tolist()[:buy_rank]
else:
all_stock_list=[]
buy_stock_list=[]
#轮动卖出
sell_stock_list=[]
for stock in hold_stock_list:
if stock not in buy_stock_list:
print('卖出 {} 不在买入前{} 排名{}'.format(stock,buy_rank,buy_stock_list))
sell_stock_list.append(str(stock))
else:
print('持有 {} 在买入前{} 排名{}'.format(stock,buy_rank,buy_stock_list.index(stock)))
#轮动买入
buy_stock_list_1=[]
for stock in buy_stock_list:
if stock in hold_stock_list:
print('已经持有 {} 在买入前{} 排名{}'.format(stock,buy_rank,buy_stock_list.index(stock)))
else:
print('买入 {} 在买入前{} 排名{}'.format(stock,buy_rank,buy_stock_list.index(stock)))
buy_stock_list_1.append(stock)
sell_df=pd.DataFrame()
sell_df['证券代码']=sell_stock_list
sell_df['交易状态']='卖'
sell_amount=sell_df.shape[0]
av_buy=(hold_limit-hold_amount)+sell_amount
if av_buy>=hold_limit:
av_buy=hold_limit
else:
av_buy=av_buy
buy_df=pd.DataFrame()
buy_df['证券代码']=buy_stock_list_1[:av_buy]
buy_df['交易状态']='买'
if sell_df.shape[0]>0:
sell_df['名称']=sell_df['证券代码']
else:
sell_df['名称']=None
if buy_df.shape[0]>0:
buy_df['证券代码']=buy_df['证券代码'].astype(str)
buy_df['名称']=buy_df['证券代码']
else:
buy_df['名称']=None
buy_df['交易时间']=datetime.now()
print('买入股票****************')
print(buy_df)
print('卖出股票*****************')
print(sell_df)
if hold_stock.shape[0]>0:
hold_stock=hold_stock[hold_stock['持仓量']>=10]
if hold_stock.shape[0]>0:
hold_stock['证券代码']=hold_stock['证券代码'].astype(str)
hold_stock['卖出']=hold_stock['证券代码'].apply(lambda x: '是' if x in sell_stock_list else '不是')
sell_df=hold_stock[hold_stock['卖出']=='是']
else:
sell_df=pd.DataFrame()
else:
sell_df=pd.DataFrame()
return buy_df,sell_df
else:
print('可转债数据获取失败,等待服务器更新')
buy_df=pd.DataFrame()
sell_df=pd.DataFrame()
return buy_df,sell_df
def run_tarder_func(c):
'''
运行交易函数
'''
trader_models=text['交易模式']
fix_value=text['固定交易金额']
fix_amount=text['固定交易金额']
sep_fix_value=text['特殊交易标的固定交易金额']
sep_fix_amount=text['特殊交易标的固定交易数量']
sep_stock_list=text['特殊交易标的']
if check_is_trader_date_1():
#先卖在买入
buy_df,sell_df=get_trader_data(c)
if sell_df.shape[0]>0:
for stock,hold_amount,av_amount in zip(sell_df['证券代码'],sell_df['持仓量'],sell_df['可用数量']):
if stock not in c.del_trader_list:
print('{} 标的不在黑名单卖出'.format(stock))
try:
if av_amount>=10:
print('{} 持有数量{} 可以数量{}大于0 卖出数量{}'.format(stock,hold_amount,av_amount,av_amount))
passorder(c.sell_code, 1101,c.account, stock, c.sell_price_code, 0, av_amount, '',1,'',c)
else:
print('{} 持有数量{} 可以数量{}等于0 卖出数量{} 不交易'.format(stock,hold_amount,av_amount,av_amount))
except:
print('{}卖出有问题'.format(stock))
else:
print('{} 标的在黑名单不卖出'.format(stock))
else:
print('没有卖出的数据')
#买入
if buy_df.shape[0]>0:
for stock in buy_df['证券代码'].tolist():
if stock not in c.del_trader_list:
print('{} 标的不在黑名单买入'.format(stock))
try:
if stock in sep_stock_list:
print('{}在特殊标的里面*********'.format(stock))
fix_value=sep_fix_value
volume=sep_fix_amount
else:
fix_value=text['固定交易金额']
volume=fix_amount
print(stock,fix_value)
if trader_models=='金额':
print('{}金额交易模式*******'.format(stock))
tader_type,amount,price=order_stock_value(c,c.account,c.account_type,stock,fix_value,'buy')
print(tader_type,amount,price)
if tader_type=='buy' and amount>=10 :
passorder(c.buy_code, 1101, c.account, str(stock), c.buy_price_code, 0, amount, '',1,'',c)
#passorder(23, 1101, c.account, str('513100.SH'), 5, 0, 100, '',1,'',c)
print('{} 最新价格 买入{} 元'.format(stock,fix_value))
else:
print('{}金额交易模式买入不了*******'.format(stock))
else:
print('{}数量交易模式*******'.format(stock))
passorder(23, 1101, c.account, str(stock), 5, 0, volume, '',1,'',c)
print('{} 最新价格 买入{} 数量'.format(stock,volume))
except Exception as e:
print(e,'{}买入有问题'.format(stock))
else:
print('{} 标的在黑名单不买入'.format(stock))
else:
print('没有买入数据')
else:
print('{} 目前不少交易时间'.format(datetime.now()))
class xg_bond_factor_data:
'''
小果可转债因子数据库
http://124.220.32.224:8023/
'''
def __init__(self,url='http://124.220.32.224',
port='8023',
url_code='5071dc6e12cd478aa2ab511bbb96abce1f6c0a05a17df9112582acfb29cc3216',
password='123456'):
'''
小果可转债因子数据库
url服务器网页
port端口
password授权码
'''
self.url=url
self.port=port
self.url_code=url_code
self.password=password
def xg_bond_factor_data(self,date_type='实时数据',date='2024-09-09'):
'''
小果可转债因子数据库
date_type=实时数据/全部默认因子/合成因子
'''
url='{}:{}/_dash-update-component'.format(self.url,self.port)
headers={'Content-Type':'application/json'}
data={
"output":"xg_bond_data_maker_table.data@{}".format(self.url_code),
"outputs":{"id":"xg_bond_data_maker_table","property":"data@{}".format(self.url_code)},
"inputs":[{"id":"password","property":"value","value":self.password},
{"id":"xg_bond_data_data_type","property":"value","value":date_type},
{"id":"xg_bond_data_end_date","property":"date","value":date},
{"id":"xg_bond_data_run","property":"value","value":"运行"},
{"id":"xg_bond_data_down_data","property":"value","value":"不下载数据"}],
"changedPropIds":["xg_bond_data_run.value"],
"parsedChangedPropsIds":["xg_bond_data_run.value"]}
res=requests.post(url=url,data=json.dumps(data),headers=headers)
text=res.json()
df=pd.DataFrame(text['response']['xg_bond_data_maker_table']['data'])
return df
class small_fruit_custom_factor_selection_system:
def __init__(self,url='http://124.220.32.224',
port='8023',
url_code='5071dc6e12cd478aa2ab511bbb96abce1f6c0a05a17df9112582acfb29cc3216',
password='xg123456',
text={},
date='20250114',
limit=30):
print('小果可转债自定义因子选择系统 ')
print('作者:小果')
print('作者微信:15117320079,开实盘qmt可以联系我,开户也可以')
print('作者微信公众号:数据分析与运用')
print('公众号链接:https://mp.weixin.qq.com/s/rxGJpZYxdUIHitjvI-US1A')
print("作者知识星球:金融量化交易研究院 https://t.zsxq.com/19VzjjXNi")
self.url=url
self.port=port
self.url_code=url_code
self.password=password
self.text=text
self.xg_data=xg_bond_factor_data(url=self.url,port=self.port,url_code=self.url_code,password=self.password)
self.date=date
self.limit=limit
self.stats=False
def select_bond_cov(self,x):
'''
选择证券代码
'''
if x[:3] in ['110','113','123','127','128','111'] or x[:2] in ['11','12']:
return '是'
else:
return '不是'
def get_all_factor_data(self):
'''
获取可转债全部数据
'''
print("获取可转债全部数据************")
text=self.text
now_date=self.date
df=self.xg_data.xg_bond_factor_data(date_type='合成因子',date=now_date)
stats=df['数据状态'].tolist()[-1]
try:
if stats==True or stats=='True' or stats=='true':
df=df
print('可转债获取成功***********')
self.stats=True
else:
print(df)
df=pd.DataFrame()
self.stats=False
except Exception as e:
df=pd.DataFrame()
self.stats=False
return df
def get_cacal_factor_base_table(self):
'''
计算默认因子
'''
print('计算默认因子***********************')
text=self.text
is_open=text['是否开启默认因子计算']
df=self.get_all_factor_data()
if df.shape[0]>0:
factor=text['默认因子计算']
if is_open=='是':
print('开启计算默认因子***********************')
factor_name=list(factor.keys())
if len(factor_name)>0:
for name in factor_name:
try:
print(name,'因子计算完成')
func=factor[name]
df[name]=eval(func)
except Exception as e:
print(e,name,'因子计算有问题')
else:
print('没有默认因子需要计算')
else:
print('不开启计算默认因子***********************')
else:
df=pd.DataFrame()
return df
def get_del_qzsh_data(self):
'''
剔除强制赎回
'''
print('剔除强制赎回')
text=self.text
del_select=text['是否剔除强制赎回']
n=text['满足强制赎回天数']
df=self.get_cacal_factor_base_table()
if df.shape[0]>0:
select_list=['公告要强赎','已公告']
df['强赎']=df['强赎天计数'].apply(lambda x : '是' if '公告要强赎' in x or '已公告' in x else '不是')
df1=df[df['强赎']=='是']
df2=df[df['强赎']=='不是']
df2['强赎天计数']=df2['强赎天计数'].apply(lambda x: '0/15 | 30' if str(x)[:4]=='暂不强赎' or '不强赎' in x else x)
df2['强赎天数']=df2['强赎天计数'].apply(lambda x: int(str(x).split('/')[0]))
df2=df2[df2['强赎天数']<=n]
else:
df2=pd.DataFrame()
return df2
def days_excluded_from_market(self):
'''
排除上市天数
'''
print('排除上市天数')
text=self.text
df=self.get_del_qzsh_data()
if df.shape[0]>0:
n=text['排除上市天数']
try:
df['上市天数']=df['上市天数'].apply(lambda x: float(str(x).split('days')[0]))
df=df[df['上市天数']>=n]
except:
df=df
else:
df=pd.DataFrame()
return df
def st_exclusion(self):
'''
排除st
'''
print('排除st')
text=self.text
is_del=text['是否排除ST']
df=self.days_excluded_from_market()
if df.shape[0]>0:
if is_del=='是':
def_list=['ST','st','*ST','*st']
df['ST']=df['正股名称'].apply(lambda x: '是' if 'st' in x or 'ST' in x or '*st' in x or '*ST' in x else '不是' )
df=df[df['ST']=='不是']
else:
df=df
else:
df=pd.DataFrame()
return df
def exclusion_of_market(self):
'''
排除市场
'''
print("排除市场")
text=self.text
exclusion_market_list = []
del_stock_list=text['排除市场']
for exclusion_market in del_stock_list:
if exclusion_market == '沪市主板':
exclusion_market_list.append(['110','113'])
elif exclusion_market == '深市主板':
exclusion_market_list.append(['127','128'])
elif exclusion_market == '创业板':
exclusion_market_list.append('123')
elif exclusion_market == '科创板':
exclusion_market_list.append('118')
else:
pass
df=self.st_exclusion()
if df.shape[0]>0:
df['market'] = df['转债代码'].apply(lambda x: '排除' if str(x)[:3] in exclusion_market_list else '不排除')
df = df[df['market'] == '不排除']
else:
df=pd.DataFrame()
return df