返回列表 发布新帖

聚宽策略迁移至QMT,提供源代码

2522 0
发表于 2023-12-25 12:56:38 | 显示全部楼层 阅读模式
今天在官网看到一个例子,聚宽策略迁移至QMT,我很久没有上官网了最近在学习大qmt,我一般用miniqmt,自己建立了一个系统,使用方便qmt和聚宽代码结构非常的相同,聚宽代码和zipline基本一样,使用简单刚刚运行了一个qmt行业轮动的策略,软件默认的大概的回测结构
image.png
image.png
我们登录聚宽看代码格式默认的策略,简单的均线策略
image.png
  1. # 导入函数库
  2. from jqdata import *

  3. # 初始化函数,设定基准等等
  4. def initialize(context):
  5.     # 设定沪深300作为基准
  6.     set_benchmark('000300.XSHG')
  7.     # 开启动态复权模式(真实价格)
  8.     set_option('use_real_price', True)
  9.     # 输出内容到日志 log.info()
  10.     log.info('初始函数开始运行且全局只运行一次')
  11.     # 过滤掉order系列API产生的比error级别低的log
  12.     # log.set_level('order', 'error')

  13.     ### 股票相关设定 ###
  14.     # 股票类每笔交易时的手续费是:买入时佣金万分之三,卖出时佣金万分之三加千分之一印花税, 每笔交易佣金最低扣5块钱
  15.     set_order_cost(OrderCost(close_tax=0.001, open_commission=0.0003, close_commission=0.0003, min_commission=5), type='stock')

  16.     ## 运行函数(reference_security为运行时间的参考标的;传入的标的只做种类区分,因此传入'000300.XSHG'或'510300.XSHG'是一样的)
  17.       # 开盘前运行
  18.     run_daily(before_market_open, time='before_open', reference_security='000300.XSHG')
  19.       # 开盘时运行
  20.     run_daily(market_open, time='open', reference_security='000300.XSHG')
  21.       # 收盘后运行
  22.     run_daily(after_market_close, time='after_close', reference_security='000300.XSHG')

  23. ## 开盘前运行函数
  24. def before_market_open(context):
  25.     # 输出运行时间
  26.     log.info('函数运行时间(before_market_open):'+str(context.current_dt.time()))

  27.     # 给微信发送消息(添加模拟交易,并绑定微信生效)
  28.     # send_message('美好的一天~')

  29.     # 要操作的股票:平安银行(g.为全局变量)
  30.     g.security = '000001.XSHE'

  31. ## 开盘时运行函数
  32. def market_open(context):
  33.     log.info('函数运行时间(market_open):'+str(context.current_dt.time()))
  34.     security = g.security
  35.     # 获取股票的收盘价
  36.     close_data = get_bars(security, count=5, unit='1d', fields=['close'])
  37.     # 取得过去五天的平均价格
  38.     MA5 = close_data['close'].mean()
  39.     # 取得上一时间点价格
  40.     current_price = close_data['close'][-1]
  41.     # 取得当前的现金
  42.     cash = context.portfolio.available_cash

  43.     # 如果上一时间点价格高出五天平均价1%, 则全仓买入
  44.     if (current_price > 1.01*MA5) and (cash > 0):
  45.         # 记录这次买入
  46.         log.info("价格高于均价 1%%, 买入 %s" % (security))
  47.         # 用所有 cash 买入股票
  48.         order_value(security, cash)
  49.     # 如果上一时间点价格低于五天平均价, 则空仓卖出
  50.     elif current_price < MA5 and context.portfolio.positions[security].closeable_amount > 0:
  51.         # 记录这次卖出
  52.         log.info("价格低于均价, 卖出 %s" % (security))
  53.         # 卖出所有股票,使这只股票的最终持有量为0
  54.         order_target(security, 0)

  55. ## 收盘后运行函数
  56. def after_market_close(context):
  57.     log.info(str('函数运行时间(after_market_close):'+str(context.current_dt.time())))
  58.     #得到当天所有成交记录
  59.     trades = get_trades()
  60.     for _trade in trades.values():
  61.         log.info('成交记录:'+str(_trade))
  62.     log.info('一天结束')
  63.     log.info('##############################################################')
复制代码

我直接利用跟单程序跟单简单,支持成交模式,持股模式
77db0904e8e071bdcaca92b41826cbef.png
可以获取组合数据

image.png
成交模式跟单,支持同qmt


  1. def get_simultaneous_transaction_models(self):
  2.         '''
  3.         交易模式2,同步成交,不会同步目前的持股
  4.         '''
  5.         trader_time_list=self.stock_data.get_trader_date_list()
  6.         now_date=trader_time_list[-1]
  7.         #now_date='2023-11-02'
  8.         hold_stock=pd.read_excel(r'持股数据\持股数据.xlsx',dtype='object')
  9.         account=pd.read_excel(r'账户数据\账户数据.xlsx')
  10.         joinquant_trader=self.joinquant_data.get_backtrader_trader_log(date=now_date)
  11.         joinquant_hold=self.joinquant_data.get_position(date=now_date)
  12.         #账户可用数量
  13.         if joinquant_trader.shape[0]>0:
  14.             for stock,amount,transaction in zip(joinquant_trader['证券代码'],joinquant_trader['amount'],joinquant_trader['transaction']):
  15.                 try:
  16.                     hold=hold_stock[hold_stock['证券代码']==stock]
  17.                     if hold.shape[0]>0:
  18.                         av_amount=hold['可用余额'].tolist()[-1]
  19.                     else:
  20.                         av_amount=0
  21.                     #可用金额
  22.                     av_money=account['可用金额'].tolist()[-1]
  23.                     amount=amount*self.ratio
  24.                     
  25.                     data_type=self.trader.select_data_type(stock=stock)
  26.                     amount=self.trader.adjust_amount(stock=stock,amount=amount)
  27.                     if data_type in ['stock','fund'] and amount<100:
  28.                         amount=100
  29.                     elif data_type=='bond' and amount<10:
  30.                         amount=10
  31.                     else:
  32.                         amount=amount
  33.                     try:
  34.                         price=self.data.get_spot_data(stock=stock)['最新价']
  35.                     except:
  36.                         try:
  37.                             price=self.tdx_data.get_security_quotes_none(stock=stock)['price'].tolist()[-1]
  38.                         except:
  39.                             try:
  40.                                 price=self.data.get_spot_trader_data(stock=stock)['价格'].tolist()[-1]
  41.                             except:
  42.                                 price=self.data.get_hist_data_em(stock=stock)['close'].tolist()[-1]
  43.                     #买入的价值
  44.                     value=amount*price
  45.                     joinquant_hold_amount=joinquant_hold[joinquant_hold['证券代码']==stock]
  46.                     if joinquant_hold_amount.shape[0]>0:
  47.                         joinquant_amount=joinquant_hold_amount['amount'].tolist()[-1]
  48.                     else:
  49.                         joinquant_amount=0
  50.                     #账户持股数量
  51.                     hold=hold_stock[hold_stock['证券代码']==stock]
  52.                     if hold.shape[0]>0:
  53.                         hold_amount=hold['股票余额'].tolist()[-1]
  54.                     else:
  55.                         hold_amount=0
  56.                     if transaction=='卖':
  57.                         #如果账户可用持股大于聚宽下单,直接卖
  58.                         if joinquant_amount==hold_amount:
  59.                             print('聚宽跟单{}已经卖出'.format(stock))
  60.                         else:
  61.                             if av_amount>0:
  62.                                 if av_amount>=amount:
  63.                                     self.trader.sell(security=stock,amount=amount,price=price)
  64.                                     text1='聚宽跟单卖出代码{} 价格{} 数量{}'.format(stock,price,amount)
  65.                                     self.base_func.adjust_hold_data(stock=stock,trader_type='sell',price=price,amount=amount)
  66.                                     self.base_func.adjust_account_cash(stock=stock,trader_type='sell',price=price,amount=amount)
  67.                                     self.base_func.seed_trader_info(text=text1)
  68.                                 #持股数量小于下单数据直接卖出全部可用卖出的
  69.                                 else:
  70.                                     amount=av_amount
  71.                                     self.trader.sell(security=stock,amount=amount,price=price)
  72.                                     text1='聚宽跟单卖出代码{} 价格{} 数量{}'.format(stock,price,amount)
  73.                                     self.base_func.adjust_hold_data(stock=stock,trader_type='sell',price=price,amount=amount)
  74.                                     self.base_func.adjust_account_cash(stock=stock,trader_type='sell',price=price,amount=amount)
  75.                                     self.base_func.seed_trader_info(text=text1)
  76.                             else:
  77.                                 print('聚宽跟单{}已经卖出'.format(stock))
  78.                     #买入的情况
  79.                     else:
  80.                         #
  81.                         if joinquant_amount==hold_amount:
  82.                             print('聚宽跟单{}已经买入'.format(stock))
  83.                         else:
  84.                             #可用资金大于下单价值
  85.                             if av_money>value:
  86.                                 self.trader.buy(security=stock,amount=amount,price=price)
  87.                                 text1='聚宽跟单买入代码{} 价格{} 数量{}'.format(stock,price,amount)
  88.                                 print(text1)
  89.                                 self.base_func.adjust_hold_data(stock=stock,trader_type='buy',price=price,amount=amount)
  90.                                 self.base_func.adjust_account_cash(stock=stock,trader_type='buy',price=price,amount=amount)
  91.                                 self.base_func.seed_trader_info(text=text1)
  92.                             else:
  93.                                 text1='聚宽跟单买入代码失败可用资金{}不足'.format(av_money)
  94.                 except Exception as e:
  95.                         print('错误',e)
  96.         else:
  97.             print('{}没有成交'.format(now_date))
复制代码

我们继续看qmt的代码格式和聚合宽一个框架的格式


  1. #encoding:gbk
  2. '''
  3. 本策略事先设定好交易的股票篮子,然后根据指数的CCI指标来判断超买和超卖
  4. 当有超买和超卖发生时,交易事先设定好的股票篮子
  5. '''
  6. import pandas as pd
  7. import numpy as np
  8. import talib

  9. def init(ContextInfo):
  10.   #hs300成分股中sh和sz市场各自流通市值最大的前3只股票
  11.   ContextInfo.trade_code_list=['601398.SH','601857.SH','601288.SH','000333.SZ','002415.SZ','000002.SZ']
  12.   ContextInfo.set_universe(ContextInfo.trade_code_list)
  13.   ContextInfo.accID = '6000000058'
  14.   ContextInfo.buy = True
  15.   ContextInfo.sell = False
  16.   
  17. def handlebar(ContextInfo):
  18.   #计算当前主图的cci
  19.   mkdict = ContextInfo.get_market_data(['high','low','close'],count=int(period)+1)
  20.   highs = np.array(mkdict['high'])
  21.   lows = np.array(mkdict['low'])
  22.   closes = np.array(mkdict['close'])
  23.   cci_list =  talib.CCI(highs,lows,closes,timeperiod=int(period))
  24.   now_cci = cci_list[-1]
  25.   ContextInfo.paint("CCI",now_cci,-1,0,'noaxis')
  26.   
  27.   #交易策略
  28.   if len(cci_list)<2:
  29.     return
  30.   
  31.   #买入条件:指数CCI进入超卖区间时触发买入信号,过滤连续超卖导致的买入信号
  32.   buy_condition = cci_list[-2]<buy_value<=now_cci and ContextInfo.buy
  33.   #卖出条件:指数CCI进入超买区间时触发卖出信号,过滤连续超买导致的卖出信号
  34.   sell_condition = cci_list[-2]>sell_value>=now_cci and ContextInfo.sell
  35.   
  36.   if buy_condition:
  37.     ContextInfo.buy = False
  38.     ContextInfo.sell = True
  39.     #列表中股票分别下单买入10手
  40.     for stockcode in ContextInfo.trade_code_list:
  41.       order_lots(stockcode,10,ContextInfo,ContextInfo.accID)
  42.   elif sell_condition:
  43.     ContextInfo.buy = True
  44.     ContextInfo.sell = False
  45.     #列表中股票分别下单卖出10手
  46.     for stockcode in ContextInfo.trade_code_list:
  47.       order_lots(stockcode,-10,ContextInfo,ContextInfo.accID)
  48.       
  49.   #可买或可卖状态
  50.   ContextInfo.draw_text(bool(buy_condition),float(now_cci),'buy') #绘制买点
  51.   ContextInfo.draw_text(bool(sell_condition),float(now_cci),'sell') #绘制卖点
  52.   ContextInfo.paint('can_buy',ContextInfo.buy,-1,0,'nodraw')
  53.   ContextInfo.paint('can_sell',ContextInfo.sell,-1,0,'nodraw')
复制代码
简单的例子格式宽代码结构

  1. def initialize(context):
  2.     # 定义一个全局变量, 保存要操作的股票,如000001平安银行
  3.     g.security = '000001.XSHE'
  4.     # 运行函数
  5.     run_daily(market_open, time='every_bar')
  6. # 每个单位时间(如果按天回测,则每天调用一次,如果按分钟,则每分钟调用一次)调用一次
  7. def market_open(context):
  8.     if g.security not in context.portfolio.positions:
  9.         order(g.security, 1000)
  10.     else:
  11.         order(g.security, -800)
复制代码
qmt代码框架

  1. #示例说明:本策略,在回测的每个周期买入主图标的
  2. def init(C):
  3.   #init handlebar函数的入参是ContextInfo对象 可以缩写为C
  4.   #设置测试标的为主图品种
  5.   C.stock= C.stockcode + '.' +C.market
  6.   #accountid为测试的ID 回测模式资金账号可以填任意字符串
  7.   C.accountid = "testS"
  8. def handlebar(C):
  9.     # handlebar在回测时,会在回测周期的每根bar被执行一次
  10.     # handlebar在实时行情下,会随着主图tick的更新被调用

  11.     # passorder是QMT的综合下单函数,具体参数字段参考官方文档
  12.     passorder(23, 1101,C.accountid, C.stock, 5, -1, 1, C)
复制代码
聚宽代码移植QMT示例聚宽代码

当价格高于5日均线平均价格1.05时买入,当价格低于5日平均价格0.95时卖出

  1. # 导入函数库
  2. import jqdata

  3. # 初始化函数,设定要操作的股票、基准等等
  4. def initialize(context):
  5.     # 定义一个全局变量, 保存要操作的股票
  6.     # 000001(股票:平安银行)
  7.     g.security = '000001.XSHE'
  8.     # 设定沪深300作为基准
  9.     set_benchmark('000300.XSHG')
  10.     # 开启动态复权模式(真实价格)
  11.     set_option('use_real_price', True)

  12. # 每个单位时间(如果按天回测,则每天调用一次,如果按分钟,则每分钟调用一次)调用一次
  13. def handle_data(context, data):
  14.     security = g.security
  15.     # 获取股票的收盘价
  16.     close_data = attribute_history(security, 5, '1d', ['close'])
  17.     # 取得过去五天的平均价格
  18.     MA5 = close_data['close'].mean()
  19.     # 取得上一时间点价格
  20.     current_price = close_data['close'][-1]
  21.     # 取得当前的现金
  22.     cash = context.portfolio.cash

  23.     # 如果上一时间点价格高出五天平均价5%, 则全仓买入
  24.     if current_price > 1.05*MA5:
  25.         # 用所有 cash 买入股票
  26.         order_value(security, cash)
  27.         # 记录这次买入
  28.         log.info("Buying %s" % (security))
  29.     # 如果上一时间点价格低于五天平均价, 则空仓卖出
  30.     elif current_price < 0.95*MA5 and context.portfolio.positions[security].closeable_amount > 0:
  31.         # 卖出所有股票,使这只股票的最终持有量为0
  32.         order_target(security, 0)
  33.         # 记录这次卖出
  34.         log.info("Selling %s" % (security))
  35.     # 画出上一时间点价格
  36.     record(stock_price=current_price)
复制代码
qmt代码迁移

  1. # QMT是一个本地端界面化软件,回测基准,回测手续费,回测起止时间都可在界面右侧栏进行设置


  2. # 初始化函数,设定要操作的股票,参数等
  3. def init(C):
  4.     # 定义一个全局变量,设定要操作的股票
  5.     # C.stock_list = C.get_stock_list_in_sector("沪深300")  # 获取沪深300股票列表
  6.     C.stock_list = ["000001.SZ"]
  7.     # 设定回测初始资金
  8.     C.capital = 1000000
  9.     # 设定回测账号,实盘中账号在交易设置截面选择
  10.     C.account_id = "testaccID"
  11.     # # 关于回测时间,既可以在编辑器右侧栏设置,也可通过代码设置
  12.     C.start = '2017-06-06 00:00:00'
  13.     C.end = '2020-06-06 10:00:00'

  14. def handlebar(C):
  15.     #当前k线日期
  16.     bar_date = timetag_to_datetime(C.get_bar_timetag(C.barpos), '%Y%m%d%H%M%S')
  17.     # 获取市场行情,具体参数释义见文档
  18.     market_data = C.get_market_data_ex(["open", "high", "low", "close"],C.stock_list,period = "1d",end_time = bar_date)

  19.     # 获取当前账户资金
  20.     for i in get_trade_detail_data(C.account_id,"stock","account"):
  21.         cash = i.m_dAvailable

  22.     # 获取当前持仓信息,本示例中的holding_dict结构是{stock_code:lots}
  23.     holding_dict = {obj.m_strInstrumentID+"."+obj.m_strExchangeID : obj.m_nVolume for obj in get_trade_detail_data(C.account_id,"stock","position")}
  24.    
  25.     # 遍历gmd返回的字典数据
  26.     for i in market_data:
  27.         # 获取K线数据
  28.         kline = market_data[i]
  29.         # 获取收盘价序列
  30.         close_data = kline["close"]
  31.         # 计算MA5
  32.         MA5 = close_data.rolling(5).mean()
  33.         # 如果上一时间点价格高出五天平均价5%, 且当前无持仓, 则全仓买入
  34.         if close_data.iloc[-1] > 1.05 * MA5.iloc[-1] and i not in holding_dict.keys():
  35.             # 全仓买入,交易记录会被客户端自动记录在回测结果,此处展示按金额交易的方法
  36.             passorder(23, 1123, C.account_id, i, 5, -1, 1, C)
  37.             print(f"{bar_date}——{i}触发买入")
  38.         elif close_data.iloc[-1] < 0.95 * MA5.iloc[-1] and i in holding_dict.keys():
  39.             # 获取当前持仓数量
  40.             lots = holding_dict[i]
  41.             # 全仓卖出,交易记录会被客户端自动记录在回测结果,此处展示按股数交易的方法
  42.             passorder(24, 1101, C.account_id, i, 5, -1, lots, C)
  43.             print(f"{bar_date}——{i}触发卖出")
复制代码
[color=rgba(0, 0, 0, 0.9)]聚宽跟单代码,支持qmt可以下载







image.png
客服专线

400-080-8112

用思考的速度交易,用真诚的态度合作,我们是认真的!
  • 关注公众号
  • 添加微信客服
Copyright © 2001-2025 迅投QMT社区 版权所有 All Rights Reserved. 蜀ICP备19002686号-2
关灯
扫一扫添加微信客服
QQ客服返回顶部
快速回复 返回顶部 返回列表