复制链接
克隆策略
In [ ]:
# <b>StockRanker多因子选股策略</b>
In [7]:
 
In [8]:
param_grid
Out[8]:
{'m14.params': ['{"stock_count": 3, "hold_days": 3}',
  '{"stock_count": 4, "hold_days": 4}',
  '{"stock_count": 3, "hold_days": 1}',
  '{"stock_count": 4, "hold_days": 2}'],
 'm3.features': ['\ndouble_low = close + bond_prem_ratio\nremain_size\nrank_swing_volatility_5 = nanstd((high-low)/pre_close, 5)*sqrt(200)*100\n',
  '\ndouble_low = close + bond_prem_ratio\nremain_size\nrank_swing_volatility_5 = nanstd((high-low)/pre_close, 20)*sqrt(200)*100\n',
  '\ndouble_low = close + bond_prem_ratio\nremain_size\nrank_swing_volatility_5 = nanstd((high-low)/pre_close, 60)*sqrt(200)*100\n',
  '\ndouble_low = close + bond_prem_ratio\nremain_size\nrank_swing_volatility_5 = nanstd((high-low)/pre_close, 100)*sqrt(200)*100\n',
  '\ndouble_low = close + bond_prem_ratio\nremain_size\nrank_swing_volatility_5 = nanstd((high-low)/pre_close, 120)*sqrt(200)*100\n']}
In [7]:
def bigquant_run(context, data):
    # 按日期过滤得到今日的预测数据
    #time == data.current_dt.strftime('%Y-%m-%d%H%M%S')
    now = context.now()
    print(now)
    if str(now) == '14:33:30' :
        context.order_target('000001', 0.05)
        context.order_target('110041.HCB', 0.05)
In [5]:

In [7]:
# 回测引擎:每日数据处理函数,每天执行一次
def bigquant_run(context, data):
    print(context.trading_day_index)
    try:
        print('处理data',data)
        context.ranker_prediction = context.options.get('data').read()['data']
        # 相隔几天(hold_days)进行一下换仓
        if context.trading_day_index % context.hold_days != 0:
            return 

        # 按日期过滤得到今日的预测数据
        ranker_prediction = context.ranker_prediction[
            context.ranker_prediction.date == data.current_dt.strftime('%Y-%m-%d')]
        # 目前持仓
        positions = {e: p.amount * p.last_sale_price for e, p in context.portfolio.positions.items()}
        # 权重
        buy_cash_weights = context.stock_weights
        print("buy_cash_weights",buy_cash_weights)
        # 今日买入股票列表
        stock_to_buy = list(ranker_prediction.instrument[:len(buy_cash_weights)])
        # 持仓上限
        max_cash_per_instrument = context.portfolio.portfolio_value * context.max_cash_per_instrument
        print("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<")
        # 通过positions对象,使用列表生成式的方法获取目前持仓的股票列表
        stock_hold_now = [equity for equity in context.portfolio.positions ]
        # 继续持有的股票:调仓时,如果买入的股票已经存在于目前的持仓里,那么应继续持有
        no_need_to_sell = [i for i in stock_hold_now if i in stock_to_buy]
        # 需要卖出的股票
        stock_to_sell = [i for i in stock_hold_now if i not in no_need_to_sell]

        # 卖出
        for stock in stock_to_sell:
            # 如果该股票停牌,则没法成交。因此需要用can_trade方法检查下该股票的状态
            # 如果返回真值,则可以正常下单,否则会出错
            # 因为stock是字符串格式,我们用symbol方法将其转化成平台可以接受的形式:Equity格式
            if data.can_trade(context.symbol(stock)):
                # order_target_percent是平台的一个下单接口,表明下单使得该股票的权重为0,
                #   即卖出全部股票,可参考回测文档
                if context.order_target_percent(context.symbol(stock), 0) != 0:
                    print('sell_context.symbol',context.symbol(stock))

        # 如果当天没有买入的股票,就返回
        if len(stock_to_buy) == 0:
            return

        # 买入
        for i, instrument in enumerate(stock_to_buy):
            cash = context.portfolio.portfolio_value * buy_cash_weights[i]
            if cash > max_cash_per_instrument - positions.get(instrument, 0):
                # 确保股票持仓量不会超过每次股票最大的占用资金量
                cash = max_cash_per_instrument - positions.get(instrument, 0)
            if cash > 500:
                if context.order_value(context.symbol(instrument), cash) !=0:
                    print('fail_order_value',cash)            
    except Exception as e:
        print('抛出异常',e)
        logger.exception("限价单下买单失败%s,%s",context,e)
                        
Out[7]:
{'m14.params': ['{"stock_count": 3, "hold_days": 3}',
  '{"stock_count": 4, "hold_days": 4}'],
 'm3.features': ['\ndouble_low = close + bond_prem_ratio\nremain_size\nrank_swing_volatility_5 = nanstd((high-low)/pre_close, 5)*sqrt(200)*100\n',
  '\ndouble_low = close + bond_prem_ratio\nremain_size\nrank_swing_volatility_5 = nanstd((high-low)/pre_close, 6)*sqrt(200)*100\n',
  '\ndouble_low = close + bond_prem_ratio\nremain_size\nrank_swing_volatility_5 = nanstd((high-low)/pre_close, 120)*sqrt(200)*100\n']}
In [4]:
context.order_value(context.symbol('128143'), 180.22)  
---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
KeyError: ('128143', '')

During handling of the above exception, another exception occurred:

SymbolNotFound                            Traceback (most recent call last)
<ipython-input-4-bc156661722d> in <module>
----> 1 context.order_value(context.symbol('128143'), 180.22)

SymbolNotFound: Symbol '128143' was not found.
In [148]:
#m7.data.read_df().columns
#m17.predictions.read_df()
#m8.predictions.read_df().head(100)
#m8.predictions.read_df().tail(100)
#m2.data_2.read_df()
#m23.data_1.read_df()
#m23.data_2.read_df()
m1.data_2.read_df()
Out[148]:
remain_size instrument equ_trading_code conversion_chg_pct date conversion_price name_x trading_code trigger_cond_item_desc conversion_chg_pct_week ... high low deal_number volume amount accrued_interest yield_to_maturity vwap gross_close net_close
0 2.450000 128143.ZCB 002931.SZA 0.010510 2021-06-30 12.730000 锋龙转债 128143 nan -0.037720 ... 113.370003 110.880997 2376 159034 1.779515e+07 0.238356 NaN 111.894997 112.300003 112.061646
1 13.999382 128141.ZCB 002034.SZA -0.005866 2021-06-30 15.970000 旺能转债 128141 在本次发行的可转债转股期内,当下述两种情形的任意一种出现时,公司有权决定\n按照债券面值加当... 0.000536 ... 111.059998 110.033997 1018 141360 1.565561e+07 0.161096 NaN 110.750000 110.165001 110.003906
2 1.665203 123042.ZCB 300619.SZA -0.018182 2021-06-30 24.379999 银河转债 123042 在本次发行的可转债转股期内,如果公司股票连续三十个交易日中至少有\n十五个交易日的收盘价不低... -0.028078 ... 137.770004 134.100006 17070 1268620 1.714824e+08 0.368219 NaN 135.171997 135.000000 134.631775
3 4.998169 123082.ZCB 300016.SZA 0.004045 2021-06-30 8.810000 北陆转债 123082 在本次发行的可转债转股期内,当下述情形的任意一种出现时,公司有权决定按照债\n券面值加当期应... -0.022396 ... 111.377998 110.599998 1103 153957 1.707730e+07 0.282192 NaN 110.922997 110.958000 110.675812
4 10.248929 123113.ZCB 300791.SZA -0.000897 2021-06-30 56.919998 仙乐转债 123113 nan 0.038048 ... 125.000000 120.300003 3372 191166 2.338253e+07 0.080000 NaN 122.315002 122.500000 122.419998
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
361 0.411376 113580.HCB 603665.SHA -0.008848 2021-06-30 15.510000 康隆转债 113580 2)有条件赎回条款\n在本次发行的可转债转股期内,如果公司 A 股股票连续三十个交易日中至\... -0.039733 ... 252.000000 247.960007 2085 94110 2.346723e+07 0.151233 NaN 249.360001 248.690002 248.538773
362 5.438477 128075.ZCB 002406.SZA -0.010150 2021-06-30 5.540000 远东转债 128075 转股期内,当下述两种情形的任意一种出现时,公司有权决定按照债券面值\n加当期应计利息的价格赎... 0.001107 ... 120.599998 117.879997 2340 292623 3.465271e+07 0.461918 NaN 118.420998 118.489998 118.028084
363 4.797715 128066.ZCB 002811.SZA 0.004884 2021-06-30 9.270000 亚泰转债 128066 在本次发行的可转换公司债券转股期内,当下述两种情形的任意一种出现时,公司董事会有权决定按照债... 0.005050 ... 103.500000 101.862999 1107 79185 8.131397e+06 0.246575 NaN 102.689003 103.499001 103.252426
364 6.028369 128037.ZCB 002542.SZA 0.006359 2021-06-30 3.130000 岩土转债 128037 转股期内,当下述两种情形的任意一种出现时,公司有权决定按照债券面值加当期应计利息的价格赎回全... 0.034069 ... 108.169998 107.001999 2461 178113 1.921180e+07 0.443836 NaN 107.862999 107.780998 107.337166
365 6.827154 128074.ZCB 002174.SZA -0.013923 2021-06-30 16.969999 游族转债 128074 在本次发行的可转换公司债券转股期内,当下述两种情形的任意一种出现时,公司董事会有权决定按照债... 0.000685 ... 118.779999 116.860001 4179 353840 4.174239e+07 0.461918 NaN 117.970001 116.860001 116.398079

366 rows × 33 columns

    {"description":"实验创建于2017/8/26","graph":{"edges":[{"to_node_id":"-281:features","from_node_id":"287d2cb0-f53c-4101-bdf8-104b137c8601-24:data"},{"to_node_id":"-295:features","from_node_id":"287d2cb0-f53c-4101-bdf8-104b137c8601-24:data"},{"to_node_id":"287d2cb0-f53c-4101-bdf8-104b137c8601-43:features","from_node_id":"287d2cb0-f53c-4101-bdf8-104b137c8601-24:data"},{"to_node_id":"287d2cb0-f53c-4101-bdf8-104b137c8601-60:model","from_node_id":"287d2cb0-f53c-4101-bdf8-104b137c8601-43:model"},{"to_node_id":"-109:input_1","from_node_id":"287d2cb0-f53c-4101-bdf8-104b137c8601-60:predictions"},{"to_node_id":"287d2cb0-f53c-4101-bdf8-104b137c8601-53:data2","from_node_id":"-281:data"},{"to_node_id":"287d2cb0-f53c-4101-bdf8-104b137c8601-60:data","from_node_id":"-295:data"},{"to_node_id":"287d2cb0-f53c-4101-bdf8-104b137c8601-53:data1","from_node_id":"-129:data"},{"to_node_id":"-129:input_data","from_node_id":"-147:data_1"},{"to_node_id":"-228:input_1","from_node_id":"-147:data_2"},{"to_node_id":"-1481:instruments","from_node_id":"-758:instrument_list"},{"to_node_id":"287d2cb0-f53c-4101-bdf8-104b137c8601-43:training_ds","from_node_id":"287d2cb0-f53c-4101-bdf8-104b137c8601-53:data"},{"to_node_id":"-791:training_ds","from_node_id":"287d2cb0-f53c-4101-bdf8-104b137c8601-53:data"},{"to_node_id":"-281:input_data","from_node_id":"-228:data_1"},{"to_node_id":"-295:input_data","from_node_id":"-228:data_2"},{"to_node_id":"-1481:options_data","from_node_id":"-109:data_1"},{"to_node_id":"-109:input_2","from_node_id":"-121:data_1"},{"to_node_id":"-228:input_2","from_node_id":"-221:data_2"},{"to_node_id":"-758:input","from_node_id":"-221:data_2"}],"nodes":[{"node_id":"287d2cb0-f53c-4101-bdf8-104b137c8601-24","module_id":"BigQuantSpace.input_features.input_features-v1","parameters":[{"name":"features","value":"# #号开始的表示注释\n# 多个特征,每行一个,可以包含基础特征和衍生特征\ndouble_low = close + bond_prem_ratio\nremain_size\nrank_swing_volatility_5 = nanstd((high-low)/pre_close, 5)*sqrt(200)*100","type":"Literal","bound_global_parameter":null}],"input_ports":[{"name":"features_ds","node_id":"287d2cb0-f53c-4101-bdf8-104b137c8601-24"}],"output_ports":[{"name":"data","node_id":"287d2cb0-f53c-4101-bdf8-104b137c8601-24"}],"cacheable":true,"seq_num":3,"comment":"","comment_collapsed":true},{"node_id":"287d2cb0-f53c-4101-bdf8-104b137c8601-43","module_id":"BigQuantSpace.stock_ranker_train.stock_ranker_train-v6","parameters":[{"name":"learning_algorithm","value":"排序","type":"Literal","bound_global_parameter":null},{"name":"number_of_leaves","value":"3","type":"Literal","bound_global_parameter":null},{"name":"minimum_docs_per_leaf","value":"100","type":"Literal","bound_global_parameter":null},{"name":"number_of_trees","value":"20","type":"Literal","bound_global_parameter":null},{"name":"learning_rate","value":0.1,"type":"Literal","bound_global_parameter":null},{"name":"max_bins","value":1023,"type":"Literal","bound_global_parameter":null},{"name":"feature_fraction","value":1,"type":"Literal","bound_global_parameter":null},{"name":"data_row_fraction","value":1,"type":"Literal","bound_global_parameter":null},{"name":"plot_charts","value":"True","type":"Literal","bound_global_parameter":null},{"name":"ndcg_discount_base","value":1,"type":"Literal","bound_global_parameter":null},{"name":"m_lazy_run","value":"False","type":"Literal","bound_global_parameter":null}],"input_ports":[{"name":"training_ds","node_id":"287d2cb0-f53c-4101-bdf8-104b137c8601-43"},{"name":"features","node_id":"287d2cb0-f53c-4101-bdf8-104b137c8601-43"},{"name":"test_ds","node_id":"287d2cb0-f53c-4101-bdf8-104b137c8601-43"},{"name":"base_model","node_id":"287d2cb0-f53c-4101-bdf8-104b137c8601-43"}],"output_ports":[{"name":"model","node_id":"287d2cb0-f53c-4101-bdf8-104b137c8601-43"},{"name":"feature_gains","node_id":"287d2cb0-f53c-4101-bdf8-104b137c8601-43"},{"name":"m_lazy_run","node_id":"287d2cb0-f53c-4101-bdf8-104b137c8601-43"}],"cacheable":false,"seq_num":6,"comment":"","comment_collapsed":true},{"node_id":"287d2cb0-f53c-4101-bdf8-104b137c8601-60","module_id":"BigQuantSpace.stock_ranker_predict.stock_ranker_predict-v5","parameters":[{"name":"m_lazy_run","value":"False","type":"Literal","bound_global_parameter":null}],"input_ports":[{"name":"model","node_id":"287d2cb0-f53c-4101-bdf8-104b137c8601-60"},{"name":"data","node_id":"287d2cb0-f53c-4101-bdf8-104b137c8601-60"}],"output_ports":[{"name":"predictions","node_id":"287d2cb0-f53c-4101-bdf8-104b137c8601-60"},{"name":"m_lazy_run","node_id":"287d2cb0-f53c-4101-bdf8-104b137c8601-60"}],"cacheable":true,"seq_num":8,"comment":"","comment_collapsed":true},{"node_id":"-281","module_id":"BigQuantSpace.derived_feature_extractor.derived_feature_extractor-v3","parameters":[{"name":"date_col","value":"date","type":"Literal","bound_global_parameter":null},{"name":"instrument_col","value":"instrument","type":"Literal","bound_global_parameter":null},{"name":"drop_na","value":"False","type":"Literal","bound_global_parameter":null},{"name":"remove_extra_columns","value":"False","type":"Literal","bound_global_parameter":null},{"name":"user_functions","value":"","type":"Literal","bound_global_parameter":null}],"input_ports":[{"name":"input_data","node_id":"-281"},{"name":"features","node_id":"-281"}],"output_ports":[{"name":"data","node_id":"-281"}],"cacheable":true,"seq_num":16,"comment":"","comment_collapsed":true},{"node_id":"-295","module_id":"BigQuantSpace.derived_feature_extractor.derived_feature_extractor-v3","parameters":[{"name":"date_col","value":"date","type":"Literal","bound_global_parameter":null},{"name":"instrument_col","value":"instrument","type":"Literal","bound_global_parameter":null},{"name":"drop_na","value":"False","type":"Literal","bound_global_parameter":null},{"name":"remove_extra_columns","value":"False","type":"Literal","bound_global_parameter":null},{"name":"user_functions","value":"","type":"Literal","bound_global_parameter":null}],"input_ports":[{"name":"input_data","node_id":"-295"},{"name":"features","node_id":"-295"}],"output_ports":[{"name":"data","node_id":"-295"}],"cacheable":true,"seq_num":18,"comment":"","comment_collapsed":true},{"node_id":"-129","module_id":"BigQuantSpace.auto_labeler_on_datasource.auto_labeler_on_datasource-v1","parameters":[{"name":"label_expr","value":"# #号开始的表示注释\n# 0. 每行一个,顺序执行,从第二个开始,可以使用label字段\n# 1. 可用数据字段见 https://bigquant.com/docs/develop/datasource/deprecated/history_data.html\n# 2. 可用操作符和函数见 `表达式引擎 <https://bigquant.com/docs/develop/bigexpr/usage.html>`_\n\n# 计算收益:5日收盘价(作为卖出价格)除以明日开盘价(作为买入价格)\nshift(close, -5) / shift(open, -1)\n\n# 极值处理:用1%和99%分位的值做clip\nclip(label, all_quantile(label, 0.01), all_quantile(label, 0.99))\n\n# 将分数映射到分类,这里使用20个分类\nall_wbins(label, 10)\n\n# 过滤掉一字涨停的情况 (设置label为NaN,在后续处理和训练中会忽略NaN的label)\nwhere(shift(high, -1) == shift(low, -1), NaN, label)\n","type":"Literal","bound_global_parameter":null},{"name":"drop_na_label","value":"True","type":"Literal","bound_global_parameter":null},{"name":"cast_label_int","value":"True","type":"Literal","bound_global_parameter":null},{"name":"date_col","value":"date","type":"Literal","bound_global_parameter":null},{"name":"instrument_col","value":"instrument","type":"Literal","bound_global_parameter":null},{"name":"user_functions","value":"{}","type":"Literal","bound_global_parameter":null}],"input_ports":[{"name":"input_data","node_id":"-129"}],"output_ports":[{"name":"data","node_id":"-129"}],"cacheable":true,"seq_num":10,"comment":"","comment_collapsed":true},{"node_id":"-147","module_id":"BigQuantSpace.cached.cached-v3","parameters":[{"name":"run","value":"# Python 代码入口函数,input_1/2/3 对应三个输入端,data_1/2/3 对应三个输出端\ndef bigquant_run(input_1, input_2, input_3,start_date_input,end_date_input):\n # 示例代码如下。在这里编写您的代码\n df = DataSource(\"bar1d_CN_CONBOND\").read(start_date=start_date_input, end_date=end_date_input)\n df1 = DataSource(\"market_performance_CN_CONBOND\").read(start_date=start_date_input, end_date=end_date_input)\n df2 = df.drop(['close'],axis = 1)\n df3 = pd.merge(df1,df2,on=['date','instrument'],how='inner')\n data_1 = DataSource.write_df(df3)\n data_2 = DataSource.write_df(df3)\n return Outputs(data_1=data_1, data_2=data_2, data_3=None)\n","type":"Literal","bound_global_parameter":null},{"name":"post_run","value":"# 后处理函数,可选。输入是主函数的输出,可以在这里对数据做处理,或者返回更友好的outputs数据格式。此函数输出不会被缓存。\ndef bigquant_run(outputs):\n return outputs\n","type":"Literal","bound_global_parameter":null},{"name":"input_ports","value":"","type":"Literal","bound_global_parameter":null},{"name":"params","value":"{\"start_date_input\":\"2017-06-01\",\n\"end_date_input\":\"2019-11-01\"}","type":"Literal","bound_global_parameter":null},{"name":"output_ports","value":"","type":"Literal","bound_global_parameter":null}],"input_ports":[{"name":"input_1","node_id":"-147"},{"name":"input_2","node_id":"-147"},{"name":"input_3","node_id":"-147"}],"output_ports":[{"name":"data_1","node_id":"-147"},{"name":"data_2","node_id":"-147"},{"name":"data_3","node_id":"-147"}],"cacheable":true,"seq_num":2,"comment":"","comment_collapsed":true},{"node_id":"-758","module_id":"BigQuantSpace.trade_data_generation.trade_data_generation-v1","parameters":[{"name":"category","value":"CN_STOCK","type":"Literal","bound_global_parameter":null}],"input_ports":[{"name":"input","node_id":"-758"}],"output_ports":[{"name":"history_data","node_id":"-758"},{"name":"instrument_list","node_id":"-758"},{"name":"calendar","node_id":"-758"}],"cacheable":false,"seq_num":12,"comment":"","comment_collapsed":true},{"node_id":"-1481","module_id":"BigQuantSpace.hftrade.hftrade-v2","parameters":[{"name":"start_date","value":"","type":"Literal","bound_global_parameter":null},{"name":"end_date","value":"","type":"Literal","bound_global_parameter":null},{"name":"initialize","value":"# 回测引擎:初始化函数,只执行一次\ndef bigquant_run(context):\n print(context.options)\n # 加载预测数据\n context.ranker_prediction = context.options.get('data').read()['data']\n print(context.ranker_prediction)\n context.param = context.options['data'].read()[\"param\"]\n # 系统已经设置了默认的交易手续费和滑点,要修改手续费可使用如下函数\n context.set_commission(PerOrder(buy_cost=0.0003, sell_cost=0.0013, min_cost=5))\n # 预测数据,通过options传入进来,使用 read_df 函数,加载到内存 (DataFrame)\n # 设置买入的股票数量,这里买入预测股票列表排名靠前的5只\n stock_count = context.param[\"stock_count\"]\n # 每只的股票的权重,如下的权重分配会使得靠前的股票分配多一点的资金,[0.339160, 0.213986, 0.169580, ..]\n context.stock_weights = T.norm([1 / math.log(i + 2) for i in range(0, stock_count)])\n # 设置每只股票占用的最大资金比例\n context.max_cash_per_instrument = 0.4\n context.hold_days = context.param[\"hold_days\"]\n","type":"Literal","bound_global_parameter":null},{"name":"before_trading_start","value":"# 交易引擎:每个单位时间开盘前调用一次。\ndef bigquant_run(context, data):\n # 盘前处理,订阅行情等\n pass\n","type":"Literal","bound_global_parameter":null},{"name":"handle_tick","value":"# 交易引擎:tick数据处理函数,每个tick执行一次\ndef bigquant_run(context, tick):\n pass\n","type":"Literal","bound_global_parameter":null},{"name":"handle_data","value":"# 回测引擎:每日数据处理函数,每天执行一次\ndef bigquant_run(context, data):\n print('当前日期data.current_dt',data.current_dt)\n try:\n print('处理data',data)\n context.ranker_prediction = context.options.get('data').read()['data']\n # 相隔几天(hold_days)进行一下换仓\n if context.trading_day_index % context.hold_days != 0:\n return \n\n # 按日期过滤得到今日的预测数据\n ranker_prediction = context.ranker_prediction[\n context.ranker_prediction.date == data.current_dt.strftime('%Y-%m-%d')]\n # 目前持仓\n positions = {e: p.amount * p.last_sale_price for e, p in context.portfolio.positions.items()}\n # 权重\n buy_cash_weights = context.stock_weights\n print(\"buy_cash_weights\",buy_cash_weights)\n # 今日买入股票列表\n stock_to_buy = list(ranker_prediction.instrument[:len(buy_cash_weights)])\n # 持仓上限\n max_cash_per_instrument = context.portfolio.portfolio_value * context.max_cash_per_instrument\n print(\"<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\")\n # 通过positions对象,使用列表生成式的方法获取目前持仓的股票列表\n stock_hold_now = [equity for equity in context.portfolio.positions ]\n # 继续持有的股票:调仓时,如果买入的股票已经存在于目前的持仓里,那么应继续持有\n no_need_to_sell = [i for i in stock_hold_now if i in stock_to_buy]\n # 需要卖出的股票\n stock_to_sell = [i for i in stock_hold_now if i not in no_need_to_sell]\n\n # 卖出\n for stock in stock_to_sell:\n # 如果该股票停牌,则没法成交。因此需要用can_trade方法检查下该股票的状态\n # 如果返回真值,则可以正常下单,否则会出错\n # 因为stock是字符串格式,我们用symbol方法将其转化成平台可以接受的形式:Equity格式\n if data.can_trade(context.symbol(stock)):\n # order_target_percent是平台的一个下单接口,表明下单使得该股票的权重为0,\n # 即卖出全部股票,可参考回测文档\n if context.order_target_percent(context.symbol(stock), 0) != 0:\n print('sell_context.symbol',context.symbol(stock))\n\n # 如果当天没有买入的股票,就返回\n if len(stock_to_buy) == 0:\n return\n\n # 买入\n for i, instrument in enumerate(stock_to_buy):\n cash = context.portfolio.portfolio_value * buy_cash_weights[i]\n if cash > max_cash_per_instrument - positions.get(instrument, 0):\n # 确保股票持仓量不会超过每次股票最大的占用资金量\n cash = max_cash_per_instrument - positions.get(instrument, 0)\n if cash > 500:\n if context.order_value(context.symbol(instrument), cash) !=0:\n print('fail_order_value',cash) \n except Exception as e:\n print('抛出异常',e)\n logger.exception(\"限价单下买单失败%s,%s\",context,e)\n ","type":"Literal","bound_global_parameter":null},{"name":"handle_trade","value":"# 交易引擎:成交回报处理函数,每个成交发生时执行一次\ndef bigquant_run(context, trade):\n pass\n","type":"Literal","bound_global_parameter":null},{"name":"handle_order","value":"# 交易引擎:委托回报处理函数,每个委托变化时执行一次\ndef bigquant_run(context, order):\n pass\n","type":"Literal","bound_global_parameter":null},{"name":"after_trading","value":"# 交易引擎:盘后处理函数,每日盘后执行一次\ndef bigquant_run(context, data):\n pass\n","type":"Literal","bound_global_parameter":null},{"name":"capital_base","value":1000000,"type":"Literal","bound_global_parameter":null},{"name":"frequency","value":"daily","type":"Literal","bound_global_parameter":null},{"name":"price_type","value":"真实价格","type":"Literal","bound_global_parameter":null},{"name":"product_type","value":"可转债","type":"Literal","bound_global_parameter":null},{"name":"before_start_days","value":"8","type":"Literal","bound_global_parameter":null},{"name":"order_price_field_buy","value":"open","type":"Literal","bound_global_parameter":null},{"name":"order_price_field_sell","value":"close","type":"Literal","bound_global_parameter":null},{"name":"benchmark","value":"000300.HIX","type":"Literal","bound_global_parameter":null},{"name":"plot_charts","value":"True","type":"Literal","bound_global_parameter":null},{"name":"disable_cache","value":"False","type":"Literal","bound_global_parameter":null},{"name":"replay_bdb","value":"True","type":"Literal","bound_global_parameter":null},{"name":"show_debug_info","value":"True","type":"Literal","bound_global_parameter":null},{"name":"backtest_only","value":"False","type":"Literal","bound_global_parameter":null}],"input_ports":[{"name":"instruments","node_id":"-1481"},{"name":"options_data","node_id":"-1481"},{"name":"history_ds","node_id":"-1481"},{"name":"benchmark_ds","node_id":"-1481"}],"output_ports":[{"name":"raw_perf","node_id":"-1481"}],"cacheable":false,"seq_num":21,"comment":"","comment_collapsed":true},{"node_id":"287d2cb0-f53c-4101-bdf8-104b137c8601-53","module_id":"BigQuantSpace.join.join-v3","parameters":[{"name":"on","value":"date,instrument","type":"Literal","bound_global_parameter":null},{"name":"how","value":"inner","type":"Literal","bound_global_parameter":null},{"name":"sort","value":"False","type":"Literal","bound_global_parameter":null}],"input_ports":[{"name":"data1","node_id":"287d2cb0-f53c-4101-bdf8-104b137c8601-53"},{"name":"data2","node_id":"287d2cb0-f53c-4101-bdf8-104b137c8601-53"}],"output_ports":[{"name":"data","node_id":"287d2cb0-f53c-4101-bdf8-104b137c8601-53"}],"cacheable":true,"seq_num":7,"comment":"","comment_collapsed":true},{"node_id":"-228","module_id":"BigQuantSpace.cached.cached-v3","parameters":[{"name":"run","value":"def del_input(input_1):\n df = input_1.read_df()\n df = df.drop([\"trigger_cond_item_desc\",'revise_item_desc','trigger_item_desc'],axis=1)\n df = df.dropna(axis=0, how='all', thresh=None, subset=None, inplace=False)\n print(df.columns)\n #df.sort_values(by=['date','double_low'],axis=0,ascending=True,inplace = True)\n df = df.sort_index(axis = 1)\n df = df.reset_index(drop = True)\n df = df.groupby('date').head(10)\n #print(df[['double_low','date']])\n data_1 = DataSource.write_df(df)\n return data_1\n# Python 代码入口函数,input_1/2/3 对应三个输入端,data_1/2/3 对应三个输出端\ndef bigquant_run(input_1, input_2, input_3):\n data_1 = del_input(input_1)\n data_2 = del_input(input_2)\n return Outputs(data_1=data_1, data_2=data_2, data_3=None)","type":"Literal","bound_global_parameter":null},{"name":"post_run","value":"# 后处理函数,可选。输入是主函数的输出,可以在这里对数据做处理,或者返回更友好的outputs数据格式。此函数输出不会被缓存。\ndef bigquant_run(outputs):\n return outputs\n","type":"Literal","bound_global_parameter":null},{"name":"input_ports","value":"","type":"Literal","bound_global_parameter":null},{"name":"params","value":"{}","type":"Literal","bound_global_parameter":null},{"name":"output_ports","value":"","type":"Literal","bound_global_parameter":null}],"input_ports":[{"name":"input_1","node_id":"-228"},{"name":"input_2","node_id":"-228"},{"name":"input_3","node_id":"-228"}],"output_ports":[{"name":"data_1","node_id":"-228"},{"name":"data_2","node_id":"-228"},{"name":"data_3","node_id":"-228"}],"cacheable":false,"seq_num":23,"comment":"","comment_collapsed":true},{"node_id":"-109","module_id":"BigQuantSpace.cached.cached-v3","parameters":[{"name":"run","value":"# Python 代码入口函数,input_1/2/3 对应三个输入端,data_1/2/3 对应三个输出端\ndef bigquant_run(input_1, input_2, input_3):\n # 示例代码如下。在这里编写您的代码\n print('m11.input1',input_1)\n df = input_1.read()\n param = input_2.read()\n \n data = {\n \"param\": param,\n \"data\": df\n }\n data_1 = DataSource.write_pickle(data)\n return Outputs(data_1=data_1, data_2=None, data_3=None)\n","type":"Literal","bound_global_parameter":null},{"name":"post_run","value":"# 后处理函数,可选。输入是主函数的输出,可以在这里对数据做处理,或者返回更友好的outputs数据格式。此函数输出不会被缓存。\ndef bigquant_run(outputs):\n return outputs\n","type":"Literal","bound_global_parameter":null},{"name":"input_ports","value":"","type":"Literal","bound_global_parameter":null},{"name":"params","value":"{}","type":"Literal","bound_global_parameter":null},{"name":"output_ports","value":"","type":"Literal","bound_global_parameter":null}],"input_ports":[{"name":"input_1","node_id":"-109"},{"name":"input_2","node_id":"-109"},{"name":"input_3","node_id":"-109"}],"output_ports":[{"name":"data_1","node_id":"-109"},{"name":"data_2","node_id":"-109"},{"name":"data_3","node_id":"-109"}],"cacheable":true,"seq_num":11,"comment":"合并数据和Trade参数","comment_collapsed":true},{"node_id":"-121","module_id":"BigQuantSpace.cached.cached-v3","parameters":[{"name":"run","value":"# Python 代码入口函数,input_1/2/3 对应三个输入端,data_1/2/3 对应三个输出端\ndef bigquant_run(input_1, input_2, input_3, stock_count, hold_days):\n # 示例代码如下。在这里编写您的代码\n param = {\n \"stock_count\": stock_count,\n \"hold_days\": hold_days\n }\n data_1 = DataSource.write_pickle(param)\n return Outputs(data_1=data_1, data_2=None, data_3=None)\n","type":"Literal","bound_global_parameter":null},{"name":"post_run","value":"# 后处理函数,可选。输入是主函数的输出,可以在这里对数据做处理,或者返回更友好的outputs数据格式。此函数输出不会被缓存。\ndef bigquant_run(outputs):\n return outputs\n","type":"Literal","bound_global_parameter":null},{"name":"input_ports","value":"","type":"Literal","bound_global_parameter":null},{"name":"params","value":"{\n \"stock_count\": 4,\n \"hold_days\": 5 \n}","type":"Literal","bound_global_parameter":null},{"name":"output_ports","value":"","type":"Literal","bound_global_parameter":null}],"input_ports":[{"name":"input_1","node_id":"-121"},{"name":"input_2","node_id":"-121"},{"name":"input_3","node_id":"-121"}],"output_ports":[{"name":"data_1","node_id":"-121"},{"name":"data_2","node_id":"-121"},{"name":"data_3","node_id":"-121"}],"cacheable":true,"seq_num":14,"comment":"暴露Trade的参数","comment_collapsed":true},{"node_id":"-16105","module_id":"BigQuantSpace.hyper_parameter_search.hyper_parameter_search-v1","parameters":[{"name":"param_grid_builder","value":"def bigquant_run():\n import itertools\n param_grid = {}\n \n period_list = [5,6,120] \n \n # 在这里设置需要调优的参数备选\n feature_list = [\n '''\n double_low = close + bond_prem_ratio\n remain_size\n rank_swing_volatility_5 = nanstd((high-low)/pre_close, {0})*sqrt(200)*100\n '''.format(period) for period in period_list\n ]\n param_grid[\"m14.params\"] = [\n \"\"\"{\"stock_count\": 3, \"hold_days\": 3}\"\"\",\n \"\"\"{\"stock_count\": 4, \"hold_days\": 4}\"\"\",\n ]\n param_grid['m3.features'] = feature_list\n return param_grid","type":"Literal","bound_global_parameter":null},{"name":"scoring","value":"def bigquant_run(result):\n # 评分:收益/最大回撤\n score = result.get('m21').read_raw_perf()['sharpe'].tail(1)[0]\n return {'score': score}\n","type":"Literal","bound_global_parameter":null},{"name":"search_algorithm","value":"网格搜索","type":"Literal","bound_global_parameter":null},{"name":"search_iterations","value":10,"type":"Literal","bound_global_parameter":null},{"name":"random_state","value":"","type":"Literal","bound_global_parameter":null},{"name":"workers","value":1,"type":"Literal","bound_global_parameter":null},{"name":"worker_distributed_run","value":"False","type":"Literal","bound_global_parameter":null},{"name":"worker_silent","value":"False","type":"Literal","bound_global_parameter":null},{"name":"run_now","value":"True","type":"Literal","bound_global_parameter":null},{"name":"bq_graph","value":"True","type":"Literal","bound_global_parameter":null}],"input_ports":[{"name":"bq_graph_port","node_id":"-16105"},{"name":"input_1","node_id":"-16105"},{"name":"input_2","node_id":"-16105"},{"name":"input_3","node_id":"-16105"}],"output_ports":[{"name":"result","node_id":"-16105"}],"cacheable":false,"seq_num":9,"comment":"","comment_collapsed":true},{"node_id":"-791","module_id":"BigQuantSpace.svr.svr-v1","parameters":[{"name":"C","value":1,"type":"Literal","bound_global_parameter":null},{"name":"kernel","value":"rbf","type":"Literal","bound_global_parameter":null},{"name":"degree","value":3,"type":"Literal","bound_global_parameter":null},{"name":"gamma","value":-1,"type":"Literal","bound_global_parameter":null},{"name":"coef0","value":0,"type":"Literal","bound_global_parameter":null},{"name":"tol","value":0.001,"type":"Literal","bound_global_parameter":null},{"name":"key_cols","value":"date,instrument","type":"Literal","bound_global_parameter":null},{"name":"other_train_parameters","value":"{}","type":"Literal","bound_global_parameter":null}],"input_ports":[{"name":"training_ds","node_id":"-791"},{"name":"features","node_id":"-791"},{"name":"model","node_id":"-791"},{"name":"predict_ds","node_id":"-791"}],"output_ports":[{"name":"output_model","node_id":"-791"},{"name":"predictions","node_id":"-791"}],"cacheable":true,"seq_num":17,"comment":"","comment_collapsed":true},{"node_id":"-221","module_id":"BigQuantSpace.cached.cached-v3","parameters":[{"name":"run","value":"# Python 代码入口函数,input_1/2/3 对应三个输入端,data_1/2/3 对应三个输出端\ndef bigquant_run(input_1, input_2, input_3,start_date_input,end_date_input):\n # 示例代码如下。在这里编写您的代码\n df = DataSource(\"bar1d_CN_CONBOND\").read(start_date=start_date_input, end_date=end_date_input)\n df1 = DataSource(\"market_performance_CN_CONBOND\").read(start_date=start_date_input, end_date=end_date_input)\n df2 = df.drop(['close'],axis = 1)\n df3 = pd.merge(df1,df2,on=['date','instrument'],how='inner')\n data_1 = DataSource.write_df(df3)\n data_2 = DataSource.write_df(df3)\n return Outputs(data_1=data_1, data_2=data_2, data_3=None)\n","type":"Literal","bound_global_parameter":null},{"name":"post_run","value":"# 后处理函数,可选。输入是主函数的输出,可以在这里对数据做处理,或者返回更友好的outputs数据格式。此函数输出不会被缓存。\ndef bigquant_run(outputs):\n return outputs\n","type":"Literal","bound_global_parameter":null},{"name":"input_ports","value":"","type":"Literal","bound_global_parameter":null},{"name":"params","value":"{\"start_date_input\":\"2021-01-05\",\n\"end_date_input\":\"2021-06-19\"}","type":"Literal","bound_global_parameter":null},{"name":"output_ports","value":"","type":"Literal","bound_global_parameter":null}],"input_ports":[{"name":"input_1","node_id":"-221"},{"name":"input_2","node_id":"-221"},{"name":"input_3","node_id":"-221"}],"output_ports":[{"name":"data_1","node_id":"-221"},{"name":"data_2","node_id":"-221"},{"name":"data_3","node_id":"-221"}],"cacheable":true,"seq_num":1,"comment":"","comment_collapsed":true}],"node_layout":"<node_postions><node_position Node='287d2cb0-f53c-4101-bdf8-104b137c8601-24' Position='672,-151,200,200'/><node_position Node='287d2cb0-f53c-4101-bdf8-104b137c8601-43' Position='558,575,200,200'/><node_position Node='287d2cb0-f53c-4101-bdf8-104b137c8601-60' Position='729,717,200,200'/><node_position Node='-281' Position='369,140,200,200'/><node_position Node='-295' Position='941,147,200,200'/><node_position Node='-129' Position='-5,156,200,200'/><node_position Node='-147' Position='69,-161,200,200'/><node_position Node='-758' Position='1373,160,200,200'/><node_position Node='-1481' Position='1025,791,200,200'/><node_position Node='287d2cb0-f53c-4101-bdf8-104b137c8601-53' Position='117,385,200,200'/><node_position Node='-228' Position='701,-2,200,200'/><node_position Node='-109' Position='1269,643,200,200'/><node_position Node='-121' Position='1577,522,200,200'/><node_position Node='-16105' Position='116,574,200,200'/><node_position Node='-791' Position='434,407,200,200'/><node_position Node='-221' Position='1312,-181,200,200'/></node_postions>"},"nodes_readonly":false,"studio_version":"v2"}
    In [34]:
    # 本代码由可视化策略环境自动生成 2022年6月9日 02:06
    # 本代码单元只能在可视化模式下编辑。您也可以拷贝代码,粘贴到新建的代码单元或者策略,然后修改。
    
    
    # Python 代码入口函数,input_1/2/3 对应三个输入端,data_1/2/3 对应三个输出端
    def m2_run_bigquant_run(input_1, input_2, input_3,start_date_input,end_date_input):
        # 示例代码如下。在这里编写您的代码
        df = DataSource("bar1d_CN_CONBOND").read(start_date=start_date_input, end_date=end_date_input)
        df1 = DataSource("market_performance_CN_CONBOND").read(start_date=start_date_input, end_date=end_date_input)
        df2 = df.drop(['close'],axis = 1)
        df3 = pd.merge(df1,df2,on=['date','instrument'],how='inner')
        data_1 = DataSource.write_df(df3)
        data_2 = DataSource.write_df(df3)
        return Outputs(data_1=data_1, data_2=data_2, data_3=None)
    
    # 后处理函数,可选。输入是主函数的输出,可以在这里对数据做处理,或者返回更友好的outputs数据格式。此函数输出不会被缓存。
    def m2_post_run_bigquant_run(outputs):
        return outputs
    
    # Python 代码入口函数,input_1/2/3 对应三个输入端,data_1/2/3 对应三个输出端
    def m14_run_bigquant_run(input_1, input_2, input_3, stock_count, hold_days):
        # 示例代码如下。在这里编写您的代码
        param = {
            "stock_count": stock_count,
            "hold_days": hold_days
            }
        data_1 = DataSource.write_pickle(param)
        return Outputs(data_1=data_1, data_2=None, data_3=None)
    
    # 后处理函数,可选。输入是主函数的输出,可以在这里对数据做处理,或者返回更友好的outputs数据格式。此函数输出不会被缓存。
    def m14_post_run_bigquant_run(outputs):
        return outputs
    
    # Python 代码入口函数,input_1/2/3 对应三个输入端,data_1/2/3 对应三个输出端
    def m1_run_bigquant_run(input_1, input_2, input_3,start_date_input,end_date_input):
        # 示例代码如下。在这里编写您的代码
        df = DataSource("bar1d_CN_CONBOND").read(start_date=start_date_input, end_date=end_date_input)
        df1 = DataSource("market_performance_CN_CONBOND").read(start_date=start_date_input, end_date=end_date_input)
        df2 = df.drop(['close'],axis = 1)
        df3 = pd.merge(df1,df2,on=['date','instrument'],how='inner')
        data_1 = DataSource.write_df(df3)
        data_2 = DataSource.write_df(df3)
        return Outputs(data_1=data_1, data_2=data_2, data_3=None)
    
    # 后处理函数,可选。输入是主函数的输出,可以在这里对数据做处理,或者返回更友好的outputs数据格式。此函数输出不会被缓存。
    def m1_post_run_bigquant_run(outputs):
        return outputs
    
    def del_input(input_1):
        df = input_1.read_df()
        df = df.drop(["trigger_cond_item_desc",'revise_item_desc','trigger_item_desc'],axis=1)
        df = df.dropna(axis=0, how='all', thresh=None, subset=None, inplace=False)
        print(df.columns)
        #df.sort_values(by=['date','double_low'],axis=0,ascending=True,inplace = True)
        df = df.sort_index(axis = 1)
        df = df.reset_index(drop = True)
        df = df.groupby('date').head(10)
        #print(df[['double_low','date']])
        data_1 = DataSource.write_df(df)
        return data_1
    # Python 代码入口函数,input_1/2/3 对应三个输入端,data_1/2/3 对应三个输出端
    def m23_run_bigquant_run(input_1, input_2, input_3):
        data_1 = del_input(input_1)
        data_2 = del_input(input_2)
        return Outputs(data_1=data_1, data_2=data_2, data_3=None)
    # 后处理函数,可选。输入是主函数的输出,可以在这里对数据做处理,或者返回更友好的outputs数据格式。此函数输出不会被缓存。
    def m23_post_run_bigquant_run(outputs):
        return outputs
    
    # Python 代码入口函数,input_1/2/3 对应三个输入端,data_1/2/3 对应三个输出端
    def m11_run_bigquant_run(input_1, input_2, input_3):
        # 示例代码如下。在这里编写您的代码
        print('m11.input1',input_1)
        df = input_1.read()
        param = input_2.read()
        
        data = {
            "param": param,
            "data": df
        }
        data_1 = DataSource.write_pickle(data)
        return Outputs(data_1=data_1, data_2=None, data_3=None)
    
    # 后处理函数,可选。输入是主函数的输出,可以在这里对数据做处理,或者返回更友好的outputs数据格式。此函数输出不会被缓存。
    def m11_post_run_bigquant_run(outputs):
        return outputs
    
    # 回测引擎:初始化函数,只执行一次
    def m21_initialize_bigquant_run(context):
        print(context.options)
        # 加载预测数据
        context.ranker_prediction = context.options.get('data').read()['data']
        print(context.ranker_prediction)
        context.param = context.options['data'].read()["param"]
        # 系统已经设置了默认的交易手续费和滑点,要修改手续费可使用如下函数
        context.set_commission(PerOrder(buy_cost=0.0003, sell_cost=0.0013, min_cost=5))
        # 预测数据,通过options传入进来,使用 read_df 函数,加载到内存 (DataFrame)
        # 设置买入的股票数量,这里买入预测股票列表排名靠前的5只
        stock_count = context.param["stock_count"]
        # 每只的股票的权重,如下的权重分配会使得靠前的股票分配多一点的资金,[0.339160, 0.213986, 0.169580, ..]
        context.stock_weights = T.norm([1 / math.log(i + 2) for i in range(0, stock_count)])
        # 设置每只股票占用的最大资金比例
        context.max_cash_per_instrument = 0.4
        context.hold_days = context.param["hold_days"]
    
    # 交易引擎:每个单位时间开盘前调用一次。
    def m21_before_trading_start_bigquant_run(context, data):
        # 盘前处理,订阅行情等
        pass
    
    # 交易引擎:tick数据处理函数,每个tick执行一次
    def m21_handle_tick_bigquant_run(context, tick):
        pass
    
    # 回测引擎:每日数据处理函数,每天执行一次
    def m21_handle_data_bigquant_run(context, data):
        print('当前日期data.current_dt',data.current_dt)
        try:
            print('处理data',data)
            context.ranker_prediction = context.options.get('data').read()['data']
            # 相隔几天(hold_days)进行一下换仓
            if context.trading_day_index % context.hold_days != 0:
                return 
    
            # 按日期过滤得到今日的预测数据
            ranker_prediction = context.ranker_prediction[
                context.ranker_prediction.date == data.current_dt.strftime('%Y-%m-%d')]
            # 目前持仓
            positions = {e: p.amount * p.last_sale_price for e, p in context.portfolio.positions.items()}
            # 权重
            buy_cash_weights = context.stock_weights
            print("buy_cash_weights",buy_cash_weights)
            # 今日买入股票列表
            stock_to_buy = list(ranker_prediction.instrument[:len(buy_cash_weights)])
            # 持仓上限
            max_cash_per_instrument = context.portfolio.portfolio_value * context.max_cash_per_instrument
            print("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<")
            # 通过positions对象,使用列表生成式的方法获取目前持仓的股票列表
            stock_hold_now = [equity for equity in context.portfolio.positions ]
            # 继续持有的股票:调仓时,如果买入的股票已经存在于目前的持仓里,那么应继续持有
            no_need_to_sell = [i for i in stock_hold_now if i in stock_to_buy]
            # 需要卖出的股票
            stock_to_sell = [i for i in stock_hold_now if i not in no_need_to_sell]
    
            # 卖出
            for stock in stock_to_sell:
                # 如果该股票停牌,则没法成交。因此需要用can_trade方法检查下该股票的状态
                # 如果返回真值,则可以正常下单,否则会出错
                # 因为stock是字符串格式,我们用symbol方法将其转化成平台可以接受的形式:Equity格式
                if data.can_trade(context.symbol(stock)):
                    # order_target_percent是平台的一个下单接口,表明下单使得该股票的权重为0,
                    #   即卖出全部股票,可参考回测文档
                    if context.order_target_percent(context.symbol(stock), 0) != 0:
                        print('sell_context.symbol',context.symbol(stock))
    
            # 如果当天没有买入的股票,就返回
            if len(stock_to_buy) == 0:
                return
    
            # 买入
            for i, instrument in enumerate(stock_to_buy):
                cash = context.portfolio.portfolio_value * buy_cash_weights[i]
                if cash > max_cash_per_instrument - positions.get(instrument, 0):
                    # 确保股票持仓量不会超过每次股票最大的占用资金量
                    cash = max_cash_per_instrument - positions.get(instrument, 0)
                if cash > 500:
                    if context.order_value(context.symbol(instrument), cash) !=0:
                        print('fail_order_value',cash)            
        except Exception as e:
            print('抛出异常',e)
            logger.exception("限价单下买单失败%s,%s",context,e)
                            
    # 交易引擎:成交回报处理函数,每个成交发生时执行一次
    def m21_handle_trade_bigquant_run(context, trade):
        pass
    
    # 交易引擎:委托回报处理函数,每个委托变化时执行一次
    def m21_handle_order_bigquant_run(context, order):
        pass
    
    # 交易引擎:盘后处理函数,每日盘后执行一次
    def m21_after_trading_bigquant_run(context, data):
        pass
    
    
    g = T.Graph({
    
        'm3': 'M.input_features.v1',
        'm3.features': """# #号开始的表示注释
    # 多个特征,每行一个,可以包含基础特征和衍生特征
    double_low = close + bond_prem_ratio
    remain_size
    rank_swing_volatility_5 = nanstd((high-low)/pre_close, 5)*sqrt(200)*100""",
    
        'm2': 'M.cached.v3',
        'm2.run': m2_run_bigquant_run,
        'm2.post_run': m2_post_run_bigquant_run,
        'm2.input_ports': '',
        'm2.params': """{"start_date_input":"2017-06-01",
    "end_date_input":"2019-11-01"}""",
        'm2.output_ports': '',
    
        'm10': 'M.auto_labeler_on_datasource.v1',
        'm10.input_data': T.Graph.OutputPort('m2.data_1'),
        'm10.label_expr': """# #号开始的表示注释
    # 0. 每行一个,顺序执行,从第二个开始,可以使用label字段
    # 1. 可用数据字段见 https://bigquant.com/docs/develop/datasource/deprecated/history_data.html
    # 2. 可用操作符和函数见 `表达式引擎 <https://bigquant.com/docs/develop/bigexpr/usage.html>`_
    
    # 计算收益:5日收盘价(作为卖出价格)除以明日开盘价(作为买入价格)
    shift(close, -5) / shift(open, -1)
    
    # 极值处理:用1%和99%分位的值做clip
    clip(label, all_quantile(label, 0.01), all_quantile(label, 0.99))
    
    # 将分数映射到分类,这里使用20个分类
    all_wbins(label, 10)
    
    # 过滤掉一字涨停的情况 (设置label为NaN,在后续处理和训练中会忽略NaN的label)
    where(shift(high, -1) == shift(low, -1), NaN, label)
    """,
        'm10.drop_na_label': True,
        'm10.cast_label_int': True,
        'm10.date_col': 'date',
        'm10.instrument_col': 'instrument',
        'm10.user_functions': {},
    
        'm14': 'M.cached.v3',
        'm14.run': m14_run_bigquant_run,
        'm14.post_run': m14_post_run_bigquant_run,
        'm14.input_ports': '',
        'm14.params': """{
        "stock_count": 4,
        "hold_days": 5 
    }""",
        'm14.output_ports': '',
    
        'm1': 'M.cached.v3',
        'm1.run': m1_run_bigquant_run,
        'm1.post_run': m1_post_run_bigquant_run,
        'm1.input_ports': '',
        'm1.params': """{"start_date_input":"2021-01-05",
    "end_date_input":"2021-06-19"}""",
        'm1.output_ports': '',
    
        'm23': 'M.cached.v3',
        'm23.input_1': T.Graph.OutputPort('m2.data_2'),
        'm23.input_2': T.Graph.OutputPort('m1.data_2'),
        'm23.run': m23_run_bigquant_run,
        'm23.post_run': m23_post_run_bigquant_run,
        'm23.input_ports': '',
        'm23.params': '{}',
        'm23.output_ports': '',
        'm23.m_cached': False,
    
        'm16': 'M.derived_feature_extractor.v3',
        'm16.input_data': T.Graph.OutputPort('m23.data_1'),
        'm16.features': T.Graph.OutputPort('m3.data'),
        'm16.date_col': 'date',
        'm16.instrument_col': 'instrument',
        'm16.drop_na': False,
        'm16.remove_extra_columns': False,
    
        'm7': 'M.join.v3',
        'm7.data1': T.Graph.OutputPort('m10.data'),
        'm7.data2': T.Graph.OutputPort('m16.data'),
        'm7.on': 'date,instrument',
        'm7.how': 'inner',
        'm7.sort': False,
    
        'm6': 'M.stock_ranker_train.v6',
        'm6.training_ds': T.Graph.OutputPort('m7.data'),
        'm6.features': T.Graph.OutputPort('m3.data'),
        'm6.learning_algorithm': '排序',
        'm6.number_of_leaves': 3,
        'm6.minimum_docs_per_leaf': 100,
        'm6.number_of_trees': 20,
        'm6.learning_rate': 0.1,
        'm6.max_bins': 1023,
        'm6.feature_fraction': 1,
        'm6.data_row_fraction': 1,
        'm6.plot_charts': True,
        'm6.ndcg_discount_base': 1,
        'm6.m_lazy_run': False,
        'm6.m_cached': False,
    
        'm17': 'M.svr.v1',
        'm17.training_ds': T.Graph.OutputPort('m7.data'),
        'm17.C': 1,
        'm17.kernel': 'rbf',
        'm17.degree': 3,
        'm17.gamma': -1,
        'm17.coef0': 0,
        'm17.tol': 0.001,
        'm17.key_cols': 'date,instrument',
        'm17.other_train_parameters': {},
    
        'm18': 'M.derived_feature_extractor.v3',
        'm18.input_data': T.Graph.OutputPort('m23.data_2'),
        'm18.features': T.Graph.OutputPort('m3.data'),
        'm18.date_col': 'date',
        'm18.instrument_col': 'instrument',
        'm18.drop_na': False,
        'm18.remove_extra_columns': False,
    
        'm8': 'M.stock_ranker_predict.v5',
        'm8.model': T.Graph.OutputPort('m6.model'),
        'm8.data': T.Graph.OutputPort('m18.data'),
        'm8.m_lazy_run': False,
    
        'm11': 'M.cached.v3',
        'm11.input_1': T.Graph.OutputPort('m8.predictions'),
        'm11.input_2': T.Graph.OutputPort('m14.data_1'),
        'm11.run': m11_run_bigquant_run,
        'm11.post_run': m11_post_run_bigquant_run,
        'm11.input_ports': '',
        'm11.params': '{}',
        'm11.output_ports': '',
    
        'm12': 'M.trade_data_generation.v1',
        'm12.input': T.Graph.OutputPort('m1.data_2'),
        'm12.category': 'CN_STOCK',
        'm12.m_cached': False,
    
        'm21': 'M.hftrade.v2',
        'm21.instruments': T.Graph.OutputPort('m12.instrument_list'),
        'm21.options_data': T.Graph.OutputPort('m11.data_1'),
        'm21.start_date': '',
        'm21.end_date': '',
        'm21.initialize': m21_initialize_bigquant_run,
        'm21.before_trading_start': m21_before_trading_start_bigquant_run,
        'm21.handle_tick': m21_handle_tick_bigquant_run,
        'm21.handle_data': m21_handle_data_bigquant_run,
        'm21.handle_trade': m21_handle_trade_bigquant_run,
        'm21.handle_order': m21_handle_order_bigquant_run,
        'm21.after_trading': m21_after_trading_bigquant_run,
        'm21.capital_base': 1000000,
        'm21.frequency': 'daily',
        'm21.price_type': '真实价格',
        'm21.product_type': '可转债',
        'm21.before_start_days': '8',
        'm21.order_price_field_buy': 'open',
        'm21.order_price_field_sell': 'close',
        'm21.benchmark': '000300.HIX',
        'm21.plot_charts': True,
        'm21.disable_cache': False,
        'm21.replay_bdb': True,
        'm21.show_debug_info': True,
        'm21.backtest_only': False,
    })
    
    # g.run({})
    
    
    def m9_param_grid_builder_bigquant_run():
        import itertools
        param_grid = {}
        
        period_list = [5,6,120] 
        
        # 在这里设置需要调优的参数备选
        feature_list = [
        '''
        double_low = close + bond_prem_ratio
        remain_size
        rank_swing_volatility_5 = nanstd((high-low)/pre_close, {0})*sqrt(200)*100
        '''.format(period) for period in period_list
        ]
        param_grid["m14.params"] = [
            """{"stock_count": 3, "hold_days": 3}""",
            """{"stock_count": 4, "hold_days": 4}""",
        ]
        param_grid['m3.features'] = feature_list
        return param_grid
    def m9_scoring_bigquant_run(result):
        # 评分:收益/最大回撤
        score = result.get('m21').read_raw_perf()['sharpe'].tail(1)[0]
        return {'score': score}
    
    
    m9 = M.hyper_parameter_search.v1(
        param_grid_builder=m9_param_grid_builder_bigquant_run,
        scoring=m9_scoring_bigquant_run,
        search_algorithm='网格搜索',
        search_iterations=10,
        workers=1,
        worker_distributed_run=False,
        worker_silent=False,
        run_now=True,
        bq_graph=g
    )
    
    Index(['remain_size', 'instrument', 'equ_trading_code', 'conversion_chg_pct',
           'date', 'conversion_price', 'name_x', 'trading_code',
           'conversion_chg_pct_week', 'bond_prem_ratio', 'equ_name',
           'redemption_price', 'close_equ', 'total_size', 'pure_bond_prem_ratio',
           'pure_bond_ratio', 'close', 'pre_close', 'name_y', 'open', 'high',
           'low', 'deal_number', 'volume', 'amount', 'accrued_interest',
           'yield_to_maturity', 'vwap', 'gross_close', 'net_close'],
          dtype='object')
    Index(['remain_size', 'instrument', 'equ_trading_code', 'conversion_chg_pct',
           'date', 'conversion_price', 'name_x', 'trading_code',
           'conversion_chg_pct_week', 'bond_prem_ratio', 'equ_name',
           'redemption_price', 'close_equ', 'total_size', 'pure_bond_prem_ratio',
           'pure_bond_ratio', 'close', 'pre_close', 'name_y', 'open', 'high',
           'low', 'deal_number', 'volume', 'amount', 'accrued_interest',
           'yield_to_maturity', 'vwap', 'gross_close', 'net_close'],
          dtype='object')
    
    设置评估测试数据集,查看训练曲线
    [视频教程]StockRanker训练曲线
    bigcharts-data-start/{"__type":"tabs","__id":"bigchart-7aa45343a63249dba66034a0d74ee20d"}/bigcharts-data-end
    m11.input1 DataSource(83dd1fb9684f4182820a856f3ca5fa51T)
    
    2022-06-09 02:04:59.885616 init history datas... 
    2022-06-09 02:04:59.887284 init history datas done. 
    2022-06-09 02:04:59.898661 run_backtest() capital_base:1000000, frequency:1d, product_type:conbond, date:2021-01-05 ~ 2021-06-18 
    2022-06-09 02:04:59.899024 run_backtest() running... 
    2022-06-09 02:04:59.909265 initial contracts len=0 
    2022-06-09 02:04:59.909509 backtest inited. 
    {'data': DataSource(8213727976684dfd8d12c5149872ed59T)}
               date  instrument     score  position
    0    2021-01-05  110047.HCB  0.688259         1
    1    2021-01-05  110033.HCB  0.316944         2
    2    2021-01-05  128042.ZCB  0.048017         3
    3    2021-01-05  128129.ZCB -0.094199         4
    4    2021-01-05  128040.ZCB -0.120563         5
    ...         ...         ...       ...       ...
    1085 2021-06-18  110066.HCB -0.136418         6
    1086 2021-06-18  123081.ZCB -0.199051         7
    1087 2021-06-18  127005.ZCB -0.263547         8
    1088 2021-06-18  123034.ZCB -0.359593         9
    1089 2021-06-18  127013.ZCB -0.379047        10
    
    [1090 rows x 4 columns]
    2022-06-09 02:04:59.989247 backtest transforming 1d, bars=1... 
    2022-06-09 02:04:59.989551 transform start_trading_day=2021-01-05 00:00:00, simulation period=2021-01-05 ~ 2021-06-18 
    2022-06-09 02:04:59.989588 transform source=None, before_start_days=8 
    2022-06-09 02:04:59.989621 transform replay_func=<cyfunction BacktestEngine.transform.<locals>.replay_bars_dt at 0x7fc6a8d34040> 
    当前日期data.current_dt 2021-01-05 15:00:00
    处理data BarDatas(current_dt:2021-01-05 15:00:00)
    buy_cash_weights [0.39038004999210163, 0.2463023887407299, 0.19519002499605081, 0.16812753627111746]
    <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
    当前日期data.current_dt 2021-01-06 15:00:00
    处理data BarDatas(current_dt:2021-01-06 15:00:00)
    当前日期data.current_dt 2021-01-07 15:00:00
    处理data BarDatas(current_dt:2021-01-07 15:00:00)
    当前日期data.current_dt 2021-01-08 15:00:00
    处理data BarDatas(current_dt:2021-01-08 15:00:00)
    当前日期data.current_dt 2021-01-11 15:00:00
    处理data BarDatas(current_dt:2021-01-11 15:00:00)
    当前日期data.current_dt 2021-01-12 15:00:00
    处理data BarDatas(current_dt:2021-01-12 15:00:00)
    buy_cash_weights [0.39038004999210163, 0.2463023887407299, 0.19519002499605081, 0.16812753627111746]
    <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
    2022-06-09 02:05:00.340651 market open send order=OrderReq(bkt000,110065.HCB,'1','0',0,124.9499,U,0,strategy,2021-01-12 15:00:00) failed err=-108,委托数量错误 
    2022-06-09 02:05:00.341229 market open send order=OrderReq(bkt000,110034.HCB,'1','0',0,112.29,U,0,strategy,2021-01-12 15:00:00) failed err=-108,委托数量错误 
    2022-06-09 02:05:00.341647 market open send order=OrderReq(bkt000,110051.HCB,'1','0',0,123.0199,U,0,strategy,2021-01-12 15:00:00) failed err=-108,委托数量错误 
    2022-06-09 02:05:00.342076 market open send order=OrderReq(bkt000,110056.HCB,'1','0',0,107.3,U,0,strategy,2021-01-12 15:00:00) failed err=-108,委托数量错误 
    当前日期data.current_dt 2021-01-13 15:00:00
    处理data BarDatas(current_dt:2021-01-13 15:00:00)
    当前日期data.current_dt 2021-01-14 15:00:00
    处理data BarDatas(current_dt:2021-01-14 15:00:00)
    当前日期data.current_dt 2021-01-15 15:00:00
    处理data BarDatas(current_dt:2021-01-15 15:00:00)
    当前日期data.current_dt 2021-01-18 15:00:00
    处理data BarDatas(current_dt:2021-01-18 15:00:00)
    当前日期data.current_dt 2021-01-19 15:00:00
    处理data BarDatas(current_dt:2021-01-19 15:00:00)
    buy_cash_weights [0.39038004999210163, 0.2463023887407299, 0.19519002499605081, 0.16812753627111746]
    <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
    当前日期data.current_dt 2021-01-20 15:00:00
    处理data BarDatas(current_dt:2021-01-20 15:00:00)
    当前日期data.current_dt 2021-01-21 15:00:00
    处理data BarDatas(current_dt:2021-01-21 15:00:00)
    当前日期data.current_dt 2021-01-22 15:00:00
    处理data BarDatas(current_dt:2021-01-22 15:00:00)
    当前日期data.current_dt 2021-01-25 15:00:00
    处理data BarDatas(current_dt:2021-01-25 15:00:00)
    当前日期data.current_dt 2021-01-26 15:00:00
    处理data BarDatas(current_dt:2021-01-26 15:00:00)
    buy_cash_weights [0.39038004999210163, 0.2463023887407299, 0.19519002499605081, 0.16812753627111746]
    <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
    2022-06-09 02:05:00.693207 market open send order=OrderReq(bkt000,110047.HCB,'1','0',0,105.18,U,0,strategy,2021-01-26 15:00:00) failed err=-108,委托数量错误 
    2022-06-09 02:05:00.695059 strategy strategy exception:Traceback (most recent call last):
      File "bigtrader/strategy/engine.py", line 714, in bigtrader2.bigtrader.strategy.engine.StrategyEngine._call_strategy_func
      File "bigtrader/strategy/strategy_base.py", line 2161, in bigtrader2.bigtrader.strategy.strategy_base.StrategyBase.call_handle_market_open
      File "bigtrader/finance/account_engine.py", line 2456, in bigtrader2.bigtrader.finance.account_engine.AccountEngine.send_order
      File "bigtrader/finance/account_engine.py", line 2354, in bigtrader2.bigtrader.finance.account_engine.AccountEngine._check_order_cash_or_adjust
    OverflowError: cannot convert float infinity to integer
     
    
    ---------------------------------------------------------------------------
    OverflowError                             Traceback (most recent call last)
    <ipython-input-34-d140a6185c27> in <module>
        323 )
        324 
    --> 325 m21 = M.hftrade.v2(
        326     instruments=m12.instrument_list,
        327     options_data=m11.data_1,
    
    OverflowError: cannot convert float infinity to integer