返回列表 发布新帖

原生Python_策略回测报错:ErrorMsg: 200005 未找到处理函数

1326 5
发表于 2024-8-21 20:53:01 | 显示全部楼层 阅读模式



此视频 原生Python_策略回测_投研端 | 迅投知识库 (thinktrader.net) 中提供的代码,运行时报以下错误,请大佬指点。

xtquant版本:https://dict.thinktrader.net/packages/xtquant_240613.rar


  1. ../userdata_mini/datadir
  2. ***** xtdata连接成功 *****
  3. 服务信息: {'tag': 'sp3', 'version': '1.0'}
  4. 服务地址: 127.0.0.1:58610
  5. 数据路径: C:\app\gjqmt_sim\bin.x64/../userdata_mini/datadir
  6. 设置xtdata.enable_hello = False可隐藏此消息

  7. Traceback (most recent call last):
  8.   File "C:\quant\codes\learn\backtest.py", line 301, in <module>
  9.     result = run_strategy_file(user_script, param=param)
  10.              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  11.   File "c:\app\Python\Python312\Lib\site-packages\xtquant\qmttools\stgentry.py", line 55, in run_file
  12.     loader.init()
  13.   File "c:\app\Python\Python312\Lib\site-packages\xtquant\qmttools\stgframe.py", line 64, in init
  14.     this.create_formula()
  15.   File "c:\app\Python\Python312\Lib\site-packages\xtquant\qmttools\stgframe.py", line 224, in create_formula
  16.     client.subscribeFormula(C.request_id, _BSON_.BSON.encode(data), callback)
  17. RuntimeError: func:subscribeFormula, error:{ "error" : { "ErrorID" : 200005, "ErrorMsg" : "未找到处理函数" } }
复制代码


代码如下(从上面的链接中复制过来)


  1. # 根据情况指定xtquant的路径
  2. import sys
  3. import numpy as np
  4. import pandas as pd
  5. from xtquant import xtdata
  6. import xtquant
  7. print(xtquant)
  8. print(xtdata.data_dir)
  9. # 指定获取投研端数据(可不指定,默认优先连接投研)
  10. # xtdata.reconnect(port=58613)
  11. # xtdata.download_sector_data()



  12. class G():
  13.     pass


  14. g = G()




  15. def init(C):
  16.     # ------------------------参数设定-----------------------------
  17.     g.his_st = {}

  18.     # g.s = C.get_stock_list_in_sector("沪深A股")  # 获取沪深A股股票列表
  19.     g.s = C.get_stock_list_in_sector("沪深300")  # 获取沪深300股票列表
  20.     # g.s = ['000001.SZ']
  21.     g.day = 0
  22.     g.holdings = {i: 0 for i in g.s}
  23.     g.weight = [0.1] * 10
  24.     g.buypoint = {}
  25.     g.money = 1000000  # C.capital
  26.     g.accid = 'test'
  27.     g.profit = 0
  28.     # 因子权重
  29.     g.buy_num = 10  # 买排名前5的股票,在过滤中会用到
  30.     g.per_money = g.money / g.buy_num * 0.95
  31.    



  32. def after_init(C):
  33.     # ------------------------量价数据获取-----------------------------
  34.     data = xtdata.get_market_data_ex([], g.s, period='1d', dividend_type='front_ratio',
  35.                                            fill_data=True)
  36.     close_df = get_df_ex(data,"close")
  37.     open_df = get_df_ex(data,"open")
  38.     low_df = get_df_ex(data,"low")
  39.     high_df = get_df_ex(data,"high")
  40.     volume_df = get_df_ex(data,"volume")
  41.     amount_df = get_df_ex(data,"amount")
  42.     preclose_df = get_df_ex(data,"preClose")

  43.     # ------------------------基础数据获取-----------------------------
  44.     # 将 g.s 中的全部股票的 TotalVolume 都获取出来,组合成一个 DataFrame
  45.     # 例如 g.s 中有 10 个股票,那么下面的代码就会返回一个 1 行 10 列的 DataFrame
  46.     # 该 DataFrame 的 index 是股票代码,columns 是 TotalVolume
  47.     # 该 DataFrame 的数据是每个股票的 TotalVolume,请给出代码:
  48.     # C.get_instrumentdetail('600000.SH')['TotalVolume']
  49.     # 使用字典推导来获取每个股票的TotalVolume
  50.     total_volumes = {stock: C.get_instrumentdetail(stock)['TotalVolume'] for stock in g.s}
  51.     # 将字典转换为DataFrame,但先转化为一个嵌套字典
  52.     df_total_volume = pd.DataFrame({k: v for k, v in total_volumes.items()}, index=['TotalVolume'])


  53.     # ------------------------财务数据获取-----------------------------

  54.     # ------------------------因子1计算及处理--------------------------------
  55.     # 1. 市值因子: 用市值因子 = 股票收盘价 * 股票总股本,要利用好,要求对应列名相乘
  56.     factor = close_df * df_total_volume.loc['TotalVolume']

  57.     # ------------------------因子2计算及处理--------------------------------
  58.     # 判断 close_df 中的 code 上市时间大于120天
  59.     stock_opendate_filter = filter_opendate_qmt(C, close_df, 120)

  60.     # ------------------------上市日期过滤处理--------------------------------
  61.     # 两个布尔值的 DataFrame 对应相乘过滤掉每个交易日上市不足120天的
  62.     factor *= stock_opendate_filter.astype(int).replace(0, np.nan)

  63.     # ------------------------排序处理-----------------------------------
  64.     # 对 factor 每行在一行内进行排序
  65.     factor_sorted = rank_filter(factor, 10, ascending=True, method='min', na_option='keep')


  66.     # ------------------------因子组合得到布尔值信号--------------------------------

  67.     # 确保没有未来数据的影响,将因子数据向后移动一天
  68.     g.factor_df = factor_sorted.shift(1)  #
  69.     g.close_df = close_df.shift(1)  # 为了计算收益率,将收盘价向后移动一天
  70.     g.open_df = open_df
  71.     g.stock_opendate_filter = stock_opendate_filter


  72. def handlebar(C):
  73.     # 获取当前 K 线位置
  74.     d = C.barpos
  75.     # 获取当前 K 线时间
  76.     backtest_time = timetag_to_datetime(C.get_bar_timetag(C.barpos), "%Y%m%d")
  77.     factor_series = g.factor_df.loc[backtest_time]
  78.     buy_list = daily_filter(factor_series, backtest_time)
  79.     print(backtest_time, buy_list)

  80.     # 获取持仓
  81.     hold = get_holdings(g.accid, 'stock')
  82.     need_sell = [s for s in hold if s not in buy_list]
  83.     print('\t\t\t\t\t\t\t', backtest_time, 'sell list', need_sell)

  84.     # 卖出
  85.     for s in need_sell:
  86.         price = g.open_df.loc[backtest_time, s]
  87.         vol = hold[s]['持仓数量']
  88.         passorder(24, 1101, g.accid, s, 11, price, vol, 1,"backtest","小市值",C)

  89.     # 获取持仓
  90.     hold = get_holdings(g.accid, 'stock')
  91.     asset = get_trade_detail_data(g.accid, 'stock', 'account')
  92.     cash = asset[0].m_dAvailable
  93.     buy_num = g.buy_num - len(hold)
  94.     buy_list = [s for s in buy_list if s not in hold]

  95.     # 买入
  96.     if buy_num > 0 and buy_list:
  97.         buy_list = buy_list[:buy_num]
  98.         # money = cash/buy_num
  99.         print(backtest_time, 'buy list', buy_list)
  100.         for s in buy_list:
  101.             price = g.open_df.loc[backtest_time, s]
  102.             if price > 0:
  103.                 passorder(23, 1102, g.accid, s, 11, float(price), g.per_money,1,"backtest","小市值",C)


  104. def daily_filter(factor_series, backtest_time):
  105.     # 将 factor_series 中值 True 的index,转化成列表
  106.     print(len(factor_series))
  107.     sl = factor_series[factor_series].index.tolist()
  108.     print(len(sl))
  109.     # exit()
  110.     # st过滤
  111.     sl = [s for s in sl if not is_st(s, backtest_time)]
  112.     sl = sorted(sl, key=lambda k: factor_series.loc[k])
  113.     return sl[:g.buy_num]


  114. def is_st(s, date):
  115.     # 判断某日在历史上是不是st *st
  116.     st_dict = g.his_st.get(s, {})
  117.     if not st_dict:
  118.         return False
  119.     else:
  120.         st = st_dict.get('ST', []) + st_dict.get('*ST', [])
  121.         for start, end in st:
  122.             if start <= date <= end:
  123.                 return True


  124. def get_df(dt: dict, df: pd.DataFrame, values_name: str) -> pd.DataFrame:
  125.     '''
  126.     循环从字典里赋值矩阵
  127.     values_name可选字段: ['time', 'stime', 'open', 'high', 'low', 'close', 'volume','amount', 'settelementPrice', 'openInterest', 'preClose', 'suspendFlag']
  128.     '''
  129.     df1 = df.copy()
  130.     df1 = df1.apply(lambda x: dt[x.name][values_name])

  131.     return df1

  132. def get_df_ex(data:dict,field:str) -> pd.DataFrame:

  133.     '''
  134.     ToDo:用于在使用get_market_data_ex的情况下,取到标准df
  135.    
  136.     Args:
  137.         data: get_market_data_ex返回的dict
  138.         field: ['time', 'open', 'high', 'low', 'close', 'volume','amount', 'settelementPrice', 'openInterest', 'preClose', 'suspendFlag']
  139.         
  140.     Return:
  141.         一个以时间为index,标的为columns的df
  142.     '''
  143.    
  144.     _index = data[list(data.keys())[0]].index.tolist()
  145.     _columns = list(data.keys())
  146.     df = pd.DataFrame(index=_index,columns=_columns)
  147.     for i in _columns:
  148.         df[i] = data[i][field]
  149.     return df
  150.         

  151. def rank_filter(df: pd.DataFrame, N: int, axis=1, ascending=False, method="max", na_option="keep") -> pd.DataFrame:
  152.     """
  153.     Args:
  154.         df: 标准数据的df
  155.         N: 判断是否是前N名
  156.         axis: 默认是横向排序
  157.         ascending : 默认是降序排序
  158.         na_option : 默认保留nan值,但不参与排名
  159.     Return:
  160.         pd.DataFrame:一个全是bool值的df
  161.     """
  162.     _df = df.copy()

  163.     _df = _df.rank(axis=axis, ascending=ascending, method=method, na_option=na_option)

  164.     return _df <= N


  165. def filter_opendate_qmt(C, df: pd.DataFrame, n: int) -> pd.DataFrame:
  166.     '''

  167.     ToDo: 判断传入的df.columns中,上市天数是否大于N日,返回的值是一个全是bool值的df

  168.     Args:
  169.         C:contextinfo类
  170.         df:index为时间,columns为stock_code的df,目的是为了和策略中的其他df对齐
  171.         n:用于判断上市天数的参数,如要判断是否上市120天,则填写
  172.     Return:pd.DataFrame

  173.     '''
  174.     local_df = pd.DataFrame(index=df.index, columns=df.columns)
  175.     stock_list = df.columns
  176.     stock_opendate = {i: C.get_instrument_detail(i)["OpenDate"] for i in stock_list}
  177.     # print(type(stock_opendate["000001.SZ"]), stock_opendate["000001.SZ"])
  178.     for stock, date in stock_opendate.items():
  179.         local_df.at[date, stock] = 1
  180.     df_fill = local_df.fillna(method="ffill")

  181.     result = df_fill.expanding().sum() >= n

  182.     return result


  183. def filter_opendate_xt(df: pd.DataFrame, n: int) -> pd.DataFrame:
  184.     '''

  185.     ToDo: 判断传入的df.columns中,上市天数是否大于N日,返回的值是一个全是bool值的df

  186.     Args:
  187.         C:contextinfo类
  188.         df:index为时间,columns为stock_code的df,目的是为了和策略中的其他df对齐
  189.         n:用于判断上市天数的参数,如要判断是否上市120天,则填写
  190.     Return:pd.DataFrame

  191.     '''
  192.     local_df = pd.DataFrame(index=df.index, columns=df.columns)
  193.     stock_list = df.columns
  194.     stock_opendate = {i: xtdata.get_instrument_detail(i)["OpenDate"] for i in stock_list}
  195.     for stock, date in stock_opendate.items():
  196.         local_df.at[date, stock] = 1
  197.     df_fill = local_df.fillna(method="ffill")

  198.     result = df_fill.expanding().sum() >= n

  199.     return result


  200. def get_holdings(accid, datatype):
  201.     '''
  202.     Arg:
  203.         accondid:账户id
  204.         datatype:
  205.             'FUTURE':期货
  206.             'STOCK':股票
  207.             ......
  208.     return:
  209.         {股票名:{'手数':int,"持仓成本":float,'浮动盈亏':float,"可用余额":int}}
  210.     '''
  211.     PositionInfo_dict = {}
  212.     resultlist = get_trade_detail_data(accid, datatype, 'POSITION')
  213.     for obj in resultlist:
  214.         PositionInfo_dict[obj.m_strInstrumentID + "." + obj.m_strExchangeID] = {
  215.             "持仓数量": obj.m_nVolume,
  216.             "持仓成本": obj.m_dOpenPrice,
  217.             "浮动盈亏": obj.m_dFloatProfit,
  218.             "可用余额": obj.m_nCanUseVolume
  219.         }
  220.     return PositionInfo_dict



  221. if __name__ == '__main__':
  222.     import sys
  223.     from xtquant.qmttools import run_strategy_file

  224.     # 参数定义方法一,如果使用方法二定义参数,run_strategy_file的param参数可不传
  225.     param = {
  226.         'stock_code': '000300.SH',  # 驱动handlebar的代码,
  227.         'period': '1d',  # 策略执行周期 即主图周期
  228.         'start_time': '2022-01-01 00:00:00',  # 注意格式,不要写错
  229.         'end_time': '2024-03-01 00:00:00',  # 注意格式,不要写错
  230.         'trade_mode': 'backtest',  # 'backtest':回测
  231.         'quote_mode': 'history',
  232.         # handlebar模式,'realtime':仅实时行情(不调用历史行情的handlebar),'history':仅历史行情, 'all':所有,即history+realtime
  233.     }
  234.     # user_script = os.path.basename(__file__)  # 当前脚本路径,相对路径,绝对路径均可,此处为相对路径的方法
  235.     user_script = sys.argv[0]  # 当前脚本路径,相对路径,绝对路径均可,此处为绝对路径的方法

  236.     print(user_script)
  237.     result = run_strategy_file(user_script, param=param)
  238.     if result:
  239.         print(result.get_backtest_index())
  240.         print(result.get_group_result())

  241.     xtdata.run()
复制代码


评论5

迅投kiki
发表于 2024-8-23 16:22:58 | 显示全部楼层
已经微信回复过,这个策略必须是投研专业版才支持的,因为部分高级函数券商qmt不支持
*******5186楼主
发表于 2024-8-23 16:59:13 | 显示全部楼层
已收到迅投老师回复,券商版的无法使用原生python进行回测
momo_ev0Tv
发表于 2024-8-24 14:04:36 | 显示全部楼层
我也遇到这个报错了,也就是说普通版根本不支持miniqmt吗,但是显示连接成功了,奇怪
image.png
*******1595_g9eHs
发表于 2024-12-23 16:53:50 | 显示全部楼层
迅投kiki 发表于 2024-8-23 16:22
已经微信回复过,这个策略必须是投研专业版才支持的,因为部分高级函数券商qmt不支持 ...

你好 我用的迅投极速交易终端 睿智融科版,但是问题是一样的,
luyuchao
发表于 2025-3-2 22:57:43 | 显示全部楼层
*******1595_g9eHs 发表于 2024-12-23 16:53
你好 我用的迅投极速交易终端 睿智融科版,但是问题是一样的,

同问 迅投极速交易终端 睿智融科版 是专业版吗?试用vip从官网下载的版本

还是说必须正式付费才能下载到投研专业版?

回复

您需要登录后才可以回帖 登录 | 立即注册

客服专线

400-080-8112

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