复制链接
克隆策略

    {"description":"实验创建于2021/12/2","graph":{"edges":[{"to_node_id":"-74:input_1","from_node_id":"-5:data"},{"to_node_id":"-62:features","from_node_id":"-13:data"},{"to_node_id":"-97:input_data","from_node_id":"-62:data"},{"to_node_id":"-2990:input_ds","from_node_id":"-71:data"},{"to_node_id":"-3809:options_data","from_node_id":"-97:data"},{"to_node_id":"-3809:instruments","from_node_id":"-74:data_1"},{"to_node_id":"-71:instruments","from_node_id":"-74:data_2"},{"to_node_id":"-62:input_data","from_node_id":"-2990:sorted_data"}],"nodes":[{"node_id":"-5","module_id":"BigQuantSpace.instruments.instruments-v2","parameters":[{"name":"start_date","value":"2010-01-01","type":"Literal","bound_global_parameter":"交易日期"},{"name":"end_date","value":"2022-08-31","type":"Literal","bound_global_parameter":"交易日期"},{"name":"market","value":"CN_FUTURE","type":"Literal","bound_global_parameter":null},{"name":"instrument_list","value":"","type":"Literal","bound_global_parameter":null},{"name":"max_count","value":0,"type":"Literal","bound_global_parameter":null}],"input_ports":[{"name":"rolling_conf","node_id":"-5"}],"output_ports":[{"name":"data","node_id":"-5"}],"cacheable":true,"seq_num":1,"comment":"","comment_collapsed":true},{"node_id":"-13","module_id":"BigQuantSpace.input_features.input_features-v1","parameters":[{"name":"features","value":"# #号开始的表示注释,注释需单独一行\n# 多个特征,每行一个,可以包含基础特征和衍生特征,特征须为本平台特征\n# bbands_up = ta_bbands_u(close, 20)\n# bbands = ta_bbands_m(close, 20)\n# bbands_low = ta_bbands_l(close, 20)\nbbands_std = std(close, 30)\nbbands = mean(close, 30)\nbbands_up = mean(close, 30) + 1 * bbands_std\nbbands_low = mean(close, 30) - 1 * bbands_std\n\nATR = ta_atr(high, low, close, 30)\nLev_ATR = clip(((0.05 / ATR) * close), 0.01, 5)\n\nOI_short = mean(open_intl, 10)\nOI_long = mean(open_intl, 20)\nOI_pct = OI_short / OI_long\n\nprice_diff = close - shift(close, 1)\ntrend_strength = (close - shift(close, 252)) / sum(abs(price_diff), 252)\n\n","type":"Literal","bound_global_parameter":null}],"input_ports":[{"name":"features_ds","node_id":"-13"}],"output_ports":[{"name":"data","node_id":"-13"}],"cacheable":true,"seq_num":2,"comment":"","comment_collapsed":true},{"node_id":"-62","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":"True","type":"Literal","bound_global_parameter":null},{"name":"user_functions","value":"{}","type":"Literal","bound_global_parameter":null}],"input_ports":[{"name":"input_data","node_id":"-62"},{"name":"features","node_id":"-62"}],"output_ports":[{"name":"data","node_id":"-62"}],"cacheable":true,"seq_num":4,"comment":"","comment_collapsed":true},{"node_id":"-71","module_id":"BigQuantSpace.use_datasource.use_datasource-v1","parameters":[{"name":"datasource_id","value":"bar1d_CN_FUTURE","type":"Literal","bound_global_parameter":null},{"name":"start_date","value":"","type":"Literal","bound_global_parameter":null},{"name":"end_date","value":"","type":"Literal","bound_global_parameter":null}],"input_ports":[{"name":"instruments","node_id":"-71"},{"name":"features","node_id":"-71"}],"output_ports":[{"name":"data","node_id":"-71"}],"cacheable":true,"seq_num":5,"comment":"","comment_collapsed":true},{"node_id":"-97","module_id":"BigQuantSpace.dropnan.dropnan-v2","parameters":[],"input_ports":[{"name":"input_data","node_id":"-97"},{"name":"features","node_id":"-97"}],"output_ports":[{"name":"data","node_id":"-97"}],"cacheable":true,"seq_num":3,"comment":"","comment_collapsed":true},{"node_id":"-3809","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":"def bigquant_run(context):\n msg = \"initialize:\" \n context.PRINT = 1\n context.write_log(msg, stdout=context.PRINT)\n print(\"initializing:\")\n context.all_data = context.options[\"data\"].read()\n context.all_data.set_index(\"instrument\", inplace=True)\n context.atr = pd.DataFrame()\n \n context.returns = []\n context.order_num = {}\n \n context.num_contract = 5 # 最终选取标的数量\n context.adjust_vol = False # 是否进行波动率调整\n context.oi_adjust = False # 是否进行持仓量调整\n context.expected_vol = 0.2 # 预期策略波动率(决定杠杆系数)\n context.adjust_volatility_period = 22 # 波动率调整周期\n context.vol_window = 126\n context.adjust_contract_period = 126 # 合约标的筛选周期\n\n# context.set_commission(equities_commission=PerOrder(buy_cost=0.0003, sell_cost=0.0003, min_cost=5.0))\n context.set_slippage_value(slippage_value=0.001)\n \n# context.cash_per_constract = context.portfolio.portfolio_value / context.num_contract\n# context.cash_per_constract = 10000000","type":"Literal","bound_global_parameter":null},{"name":"before_trading_start","value":"def bigquant_run(context, data):\n context.today = data.trading_day_dt.strftime('%Y-%m-%d')\n# print(\"check date, \", context.today)\n context.today_data = context.all_data[context.all_data.date==context.today]\n\n if context.trading_day_index % context.adjust_contract_period == 0:\n # print(f\"{context.today}进行合约筛选\")\n r1 = context.today_data\n r1.sort_values(by=[\"trend_strength\"], ascending=False, inplace=True)\n context.ins = sorted(r1.index[:context.num_contract].tolist())\n context.ins_dominant = sorted(context.get_dominant(context.ins))\n if context.trading_day_index == 0:\n context.extension.pre_ins_dominant = context.ins_dominant\n else:\n context.ins = sorted(context.extension.pre_ins) # 8888\n context.ins_dominant = sorted(context.get_dominant(context.ins))\n \n subscribe_list = list(set(context.ins_dominant).union(set(context.extension.pre_ins_dominant)))\n # print(context.today, context.ins, context.ins_dominant)\n context.subscribe(subscribe_list) # 订阅主力合约\n \n context.cash_per_constract = context.portfolio.portfolio_value / context.num_contract","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":"def bigquant_run(context, data):\n import pandas as pd\n import empyrical\n\n ##--------- 已实现波动率调整 ---------##\n if context.adjust_vol:\n if context.trading_day_index % context.adjust_volatility_period == 0 and context.trading_day_index != 0:\n raw_perf = context.get_perf_datas() # 读取累计策略绩效表现\n context.returns = []\n for d in raw_perf:\n context.returns.append(d[\"returns\"])\n if empyrical.annual_volatility(pd.Series(context.returns[-context.vol_window:])) != 0:\n context.extension.mul_vol = context.expected_vol / (empyrical.annual_volatility(pd.Series(context.returns[-context.vol_window:])))\n else:\n context.extension.mul_vol = 1\n elif context.trading_day_index == 0:\n context.extension.mul_vol = 1\n else:\n context.extension.mul_vol = 1\n ##--------- 已实现波动率调整 ---------##\n \n all_data = context.today_data\n atr_data = all_data[[\"Lev_ATR\", \"date\"]]\n atr_data[\"Lev_ATR\"] = atr_data[\"Lev_ATR\"] * context.extension.mul_vol\n all_data = pd.DataFrame(all_data)\n atr_data = pd.DataFrame(atr_data)\n \n if len(all_data) == 0:\n return\n \n ##--------- 对调整标的池之后未在标的池中的合约进行平仓处理 ---------##\n if len(context.get_account_positions()) > 0:\n ins_pc = [i.split(\".\")[0][:-4] for i in context.ins]\n for instrument, _ in context.get_account_positions().items():\n pc = instrument.split(\".\")[0][:-4]\n if pc not in ins_pc:\n price = data.current(instrument, \"close\")\n long_position = context.get_account_position(instrument, direction=Direction.LONG).avail_qty\n short_position = context.get_account_position(instrument, direction=Direction.SHORT).avail_qty\n if long_position > 0:\n # print(context.today, \"合约调整, 平多, for \", instrument)\n rv = context.order_target(instrument, 0, price, order_type=OrderType.MARKET)\n # msg = \"{} 合约调整 for {} 下单函数返回={}\".format(str(context.today), instrument, str(rv))\n # context.write_log(msg, stdout=1)\n if short_position > 0:\n # print(context.today, \"合约调整, 平空, for \", instrument)\n rv = context.order_target(instrument, 0, price, order_type=OrderType.MARKET)\n # msg = \"{} 合约调整 for {} 下单函数返回={}\".format(str(context.today), instrument, str(rv))\n # context.write_log(msg, stdout=1)\n ##--------- 对调整标的池之后未在标的池中的合约进行平仓处理: ---------##\n \n ## 遍历交易标的进行交易逻辑\n for instrument in context.ins:\n if instrument not in set(all_data.index):\n continue\n pc = instrument.split(\".\")[0][:-4]\n dominant_code = [i for i in context.ins_dominant if pc == i.split(\".\")[0][:-4]][0]\n\n pre_dominant_list = [i for i in context.extension.pre_ins_dominant if pc == i.split(\".\")[0][:-4]]\n if not len(pre_dominant_list):\n pre_dominant_code = dominant_code\n else:\n pre_dominant_code = pre_dominant_list[0]\n\n high_line = all_data['bbands_up'].loc[instrument]\n low_line = all_data['bbands_low'].loc[instrument]\n ma_line = all_data['bbands'].loc[instrument]\n OI_pct = all_data[\"OI_pct\"].loc[instrument]\n ma_std = all_data['bbands_std'].loc[instrument]\n n = 3 # 止盈通道线系数 n*std(close)\n Lev_ATR = atr_data[\"Lev_ATR\"].loc[instrument]\n context.long_stop_line = ma_line + n * ma_std\n context.short_stop_line = ma_line - n * ma_std\n \n price = data.current(instrument, \"close\") # 合约价格\n multiplier = context.get_contract(instrument).multiplier # 合约乘数\n long_position = context.get_account_position(pre_dominant_code, direction=Direction.LONG).avail_qty # 多头持仓\n short_position = context.get_account_position(pre_dominant_code, direction=Direction.SHORT).avail_qty # 空头持仓\n curr_position = short_position + long_position # 总持仓\n \n order_num = int(Lev_ATR * (context.cash_per_constract // (price * multiplier)))\n \n # 持仓量调整\n if context.oi_adjust:\n if order_num >= 2 and OI_pct < 1:\n order_num = math.ceil(0.5 * order_num)\n\n if curr_position==0:\n if price > high_line:\n # print(context.today, \"无仓位, 开多, for \", dominant_code)\n rv1 = context.order_target(dominant_code, order_num, price, order_type=OrderType.MARKET)\n # msg1 = \"{} 开多 for {} 下单函数返回={}\".format(str(context.today), dominant_code, str(rv1))\n # context.write_log(msg1, stdout=1)\n elif price < low_line:\n # print(context.today, \"无仓位, 开空, for \", dominant_code)\n rv1 = context.order_target(dominant_code, -order_num, price, order_type=OrderType.MARKET)\n # msg1 = \"{} 开空 for {} 下单函数返回={}\".format(str(context.today), dominant_code, str(rv1))\n # context.write_log(msg1, stdout=1)\n else:\n if short_position > 0:\n if price > ma_line:# or price <= context.short_stop_line:\n # print(context.today, \"平空, for \", pre_dominant_code)\n rv1 = context.order_target(pre_dominant_code, 0, price, order_type=OrderType.MARKET)\n # msg1 = \"{} 平空 for {} 下单函数返回={}\".format(str(context.today), pre_dominant_code, str(rv1))\n # context.write_log(msg1, stdout=1)\n else:\n if dominant_code != pre_dominant_code:\n # print(context.today, \"未触发平空仓信号, 但需移仓换月, for \", pre_dominant_code, dominant_code)\n rv1 = context.order_target(pre_dominant_code, 0, price, order_type=OrderType.MARKET)\n # msg1 = \"{} 平旧主力合约 for {} 下单函数返回={}\".format(str(context.today), pre_dominant_code, str(rv1))\n # context.write_log(msg1, stdout=1)\n rv2 = context.order_target(dominant_code, -short_position, price, order_type=OrderType.MARKET)\n # msg2 = \"{} 开新主力合约 for {} 下单函数返回={}\".format(str(context.today), dominant_code, str(rv2))\n # context.write_log(msg2, stdout=1)\n\n elif long_position > 0:\n if price < ma_line:# or price >= context.long_stop_line:\n # print(context.today, \"平多, for \", pre_dominant_code)\n rv1 = context.order_target(pre_dominant_code, 0, price, order_type=OrderType.MARKET)\n # msg1 = \"{} 平多 for {} 下单函数返回={}\".format(str(context.today), pre_dominant_code, str(rv1))\n # context.write_log(msg1, stdout=1)\n else:\n if dominant_code != pre_dominant_code:\n # print(context.today, \"未触发平多仓信号, 但需移仓换月, for \", pre_dominant_code, dominant_code)\n rv1 = context.order_target(pre_dominant_code, 0, price, order_type=OrderType.MARKET)\n # msg1 = \"{} 平旧主力合约 for {} 下单函数返回={}\".format(str(context.today), pre_dominant_code, str(rv1))\n # context.write_log(msg1, stdout=1)\n rv2 = context.order_target(dominant_code, long_position, price, order_type=OrderType.MARKET)\n # msg2 = \"{} 开新主力合约 for {} 下单函数返回={}\".format(str(context.today), dominant_code, str(rv2))\n # context.write_log(msg2, stdout=1)","type":"Literal","bound_global_parameter":null},{"name":"handle_trade","value":"# 交易引擎:成交回报处理函数,每个成交发生时执行一次\ndef bigquant_run(context, data):\n# msg = \"handle_trade data:{}\".format(data.log_str())\n# context.write_log(msg, stdout=context.PRINT)\n pass\n","type":"Literal","bound_global_parameter":null},{"name":"handle_order","value":"# 交易引擎:委托回报处理函数,每个委托变化时执行一次\ndef bigquant_run(context, data):\n# msg = \"handle_order data:{}\".format(data.log_str())\n# context.write_log(msg, stdout=context.PRINT)\n pass\n","type":"Literal","bound_global_parameter":null},{"name":"after_trading","value":"# 交易引擎:盘后处理函数,每日盘后执行一次\ndef bigquant_run(context, data):\n context.extension.pre_ins = context.ins\n context.extension.pre_ins_dominant = context.ins_dominant\n","type":"Literal","bound_global_parameter":null},{"name":"capital_base","value":"100000000","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":"0","type":"Literal","bound_global_parameter":null},{"name":"volume_limit","value":1,"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":"open","type":"Literal","bound_global_parameter":null},{"name":"benchmark","value":"","type":"Literal","bound_global_parameter":null},{"name":"plot_charts","value":"True","type":"Literal","bound_global_parameter":null},{"name":"disable_cache","value":"True","type":"Literal","bound_global_parameter":null},{"name":"replay_bdb","value":"False","type":"Literal","bound_global_parameter":null},{"name":"show_debug_info","value":"False","type":"Literal","bound_global_parameter":null},{"name":"backtest_only","value":"False","type":"Literal","bound_global_parameter":null}],"input_ports":[{"name":"instruments","node_id":"-3809"},{"name":"options_data","node_id":"-3809"},{"name":"history_ds","node_id":"-3809"},{"name":"benchmark_ds","node_id":"-3809"}],"output_ports":[{"name":"raw_perf","node_id":"-3809"}],"cacheable":false,"seq_num":8,"comment":"","comment_collapsed":true},{"node_id":"-74","module_id":"BigQuantSpace.futures_forward_extractor.futures_forward_extractor-v9","parameters":[{"name":"before_days","value":"252","type":"Literal","bound_global_parameter":null},{"name":"product_filter","value":"[\"BB\", \"LR\", \"JR\", \"FB\", \"RI\", \"WR\", \"RS\", \"PM\", \"WT\", \"TC\", \"RO\", \"ER\", \"WS\", \"B\", \"FU\", \"LU\", \"SC\", \"L\", \"ME\", \"WH\"]","type":"Literal","bound_global_parameter":null},{"name":"if_CFX","value":"True","type":"Literal","bound_global_parameter":null},{"name":"set_enable_trade","value":"False","type":"Literal","bound_global_parameter":null}],"input_ports":[{"name":"input_1","node_id":"-74"}],"output_ports":[{"name":"data_1","node_id":"-74"},{"name":"data_2","node_id":"-74"},{"name":"data_3","node_id":"-74"}],"cacheable":true,"seq_num":7,"comment":"","comment_collapsed":true},{"node_id":"-2990","module_id":"BigQuantSpace.sort.sort-v5","parameters":[{"name":"sort_by","value":"date","type":"Literal","bound_global_parameter":null},{"name":"group_by","value":"--","type":"Literal","bound_global_parameter":null},{"name":"keep_columns","value":"--","type":"Literal","bound_global_parameter":null},{"name":"ascending","value":"True","type":"Literal","bound_global_parameter":null}],"input_ports":[{"name":"input_ds","node_id":"-2990"},{"name":"sort_by_ds","node_id":"-2990"}],"output_ports":[{"name":"sorted_data","node_id":"-2990"}],"cacheable":true,"seq_num":6,"comment":"","comment_collapsed":true}],"node_layout":"<node_postions><node_position Node='-5' Position='206,-27,200,200'/><node_position Node='-13' Position='627.1610717773438,30,200,200'/><node_position Node='-62' Position='414,290,200,200'/><node_position Node='-71' Position='414,139,200,200'/><node_position Node='-97' Position='415,359,200,200'/><node_position Node='-3809' Position='341,433,200,200'/><node_position Node='-74' Position='210,35.16108703613281,200,200'/><node_position Node='-2990' Position='416,213,200,200'/></node_postions>"},"nodes_readonly":false,"studio_version":"v2"}
    In [36]:
    # 本代码由可视化策略环境自动生成 2022年9月15日 23:20
    # 本代码单元只能在可视化模式下编辑。您也可以拷贝代码,粘贴到新建的代码单元或者策略,然后修改。
    
    
    def m8_initialize_bigquant_run(context):
        msg = "initialize:" 
        context.PRINT = 1
        context.write_log(msg, stdout=context.PRINT)
        print("initializing:")
        context.all_data = context.options["data"].read()
        context.all_data.set_index("instrument", inplace=True)
        context.atr = pd.DataFrame()
        
        context.returns = []
        context.order_num = {}
        
        context.num_contract = 5  # 最终选取标的数量
        context.adjust_vol = False  # 是否进行波动率调整
        context.oi_adjust = False  # 是否进行持仓量调整
        context.expected_vol = 0.2  # 预期策略波动率(决定杠杆系数)
        context.adjust_volatility_period = 22  # 波动率调整周期
        context.vol_window = 126
        context.adjust_contract_period = 126  # 合约标的筛选周期
    
    #     context.set_commission(equities_commission=PerOrder(buy_cost=0.0003, sell_cost=0.0003, min_cost=5.0))
        context.set_slippage_value(slippage_value=0.001)
        
    #     context.cash_per_constract = context.portfolio.portfolio_value / context.num_contract
    #     context.cash_per_constract = 10000000
    def m8_before_trading_start_bigquant_run(context, data):
        context.today = data.trading_day_dt.strftime('%Y-%m-%d')
    #     print("check date, ", context.today)
        context.today_data = context.all_data[context.all_data.date==context.today]
    
        if context.trading_day_index % context.adjust_contract_period == 0:
            # print(f"{context.today}进行合约筛选")
            r1 = context.today_data
            r1.sort_values(by=["trend_strength"], ascending=False, inplace=True)
            context.ins = sorted(r1.index[:context.num_contract].tolist())
            context.ins_dominant = sorted(context.get_dominant(context.ins))
            if context.trading_day_index == 0:
                context.extension.pre_ins_dominant = context.ins_dominant
        else:
            context.ins = sorted(context.extension.pre_ins) # 8888
            context.ins_dominant = sorted(context.get_dominant(context.ins))
            
        subscribe_list = list(set(context.ins_dominant).union(set(context.extension.pre_ins_dominant)))
        # print(context.today, context.ins, context.ins_dominant)
        context.subscribe(subscribe_list)  # 订阅主力合约
        
        context.cash_per_constract = context.portfolio.portfolio_value / context.num_contract
    # 交易引擎:tick数据处理函数,每个tick执行一次
    def m8_handle_tick_bigquant_run(context, tick):
        pass
    
    def m8_handle_data_bigquant_run(context, data):
        import pandas as pd
        import empyrical
    
        ##--------- 已实现波动率调整 ---------##
        if context.adjust_vol:
            if context.trading_day_index % context.adjust_volatility_period == 0 and context.trading_day_index != 0:
                raw_perf = context.get_perf_datas()  # 读取累计策略绩效表现
                context.returns = []
                for d in raw_perf:
                    context.returns.append(d["returns"])
                if empyrical.annual_volatility(pd.Series(context.returns[-context.vol_window:])) != 0:
                    context.extension.mul_vol = context.expected_vol / (empyrical.annual_volatility(pd.Series(context.returns[-context.vol_window:])))
                else:
                    context.extension.mul_vol = 1
            elif context.trading_day_index == 0:
                context.extension.mul_vol = 1
        else:
            context.extension.mul_vol = 1
        ##--------- 已实现波动率调整 ---------##
        
        all_data = context.today_data
        atr_data = all_data[["Lev_ATR", "date"]]
        atr_data["Lev_ATR"] = atr_data["Lev_ATR"] * context.extension.mul_vol
        all_data = pd.DataFrame(all_data)
        atr_data = pd.DataFrame(atr_data)
        
        if len(all_data) == 0:
            return
        
        ##--------- 对调整标的池之后未在标的池中的合约进行平仓处理 ---------##
        if len(context.get_account_positions()) > 0:
            ins_pc = [i.split(".")[0][:-4] for i in context.ins]
            for instrument, _ in context.get_account_positions().items():
                pc = instrument.split(".")[0][:-4]
                if pc not in ins_pc:
                    price = data.current(instrument, "close")
                    long_position = context.get_account_position(instrument, direction=Direction.LONG).avail_qty
                    short_position = context.get_account_position(instrument, direction=Direction.SHORT).avail_qty
                    if long_position > 0:
                        # print(context.today, "合约调整, 平多, for ", instrument)
                        rv = context.order_target(instrument, 0, price, order_type=OrderType.MARKET)
                        # msg = "{} 合约调整 for {} 下单函数返回={}".format(str(context.today), instrument, str(rv))
                        # context.write_log(msg, stdout=1)
                    if short_position > 0:
                        # print(context.today, "合约调整, 平空, for ", instrument)
                        rv = context.order_target(instrument, 0, price, order_type=OrderType.MARKET)
                        # msg = "{} 合约调整 for {} 下单函数返回={}".format(str(context.today), instrument, str(rv))
                        # context.write_log(msg, stdout=1)
        ##--------- 对调整标的池之后未在标的池中的合约进行平仓处理: ---------##
        
        ## 遍历交易标的进行交易逻辑
        for instrument in context.ins:
            if instrument not in set(all_data.index):
                continue
            pc = instrument.split(".")[0][:-4]
            dominant_code = [i for i in context.ins_dominant if pc == i.split(".")[0][:-4]][0]
    
            pre_dominant_list = [i for i in context.extension.pre_ins_dominant if pc == i.split(".")[0][:-4]]
            if not len(pre_dominant_list):
                pre_dominant_code = dominant_code
            else:
                pre_dominant_code = pre_dominant_list[0]
    
            high_line = all_data['bbands_up'].loc[instrument]
            low_line = all_data['bbands_low'].loc[instrument]
            ma_line = all_data['bbands'].loc[instrument]
            OI_pct = all_data["OI_pct"].loc[instrument]
            ma_std = all_data['bbands_std'].loc[instrument]
            n = 3                                             # 止盈通道线系数 n*std(close)
            Lev_ATR = atr_data["Lev_ATR"].loc[instrument]
            context.long_stop_line = ma_line + n * ma_std
            context.short_stop_line = ma_line - n * ma_std
            
            price = data.current(instrument, "close")  # 合约价格
            multiplier = context.get_contract(instrument).multiplier  # 合约乘数
            long_position = context.get_account_position(pre_dominant_code, direction=Direction.LONG).avail_qty  # 多头持仓
            short_position = context.get_account_position(pre_dominant_code, direction=Direction.SHORT).avail_qty  # 空头持仓
            curr_position = short_position + long_position  # 总持仓
            
            order_num = int(Lev_ATR * (context.cash_per_constract // (price * multiplier)))
            
            # 持仓量调整
            if context.oi_adjust:
                if order_num >= 2 and OI_pct < 1:
                    order_num = math.ceil(0.5 * order_num)
    
            if curr_position==0:
                if price > high_line:
                    # print(context.today, "无仓位, 开多, for ", dominant_code)
                    rv1 = context.order_target(dominant_code, order_num, price, order_type=OrderType.MARKET)
                    # msg1 = "{} 开多 for {} 下单函数返回={}".format(str(context.today), dominant_code, str(rv1))
                    # context.write_log(msg1, stdout=1)
                elif price < low_line:
                    # print(context.today, "无仓位, 开空, for ", dominant_code)
                    rv1 = context.order_target(dominant_code, -order_num, price, order_type=OrderType.MARKET)
                    # msg1 = "{} 开空 for {} 下单函数返回={}".format(str(context.today), dominant_code, str(rv1))
                    # context.write_log(msg1, stdout=1)
            else:
                if short_position > 0:
                    if price > ma_line:# or price <= context.short_stop_line:
                        # print(context.today, "平空, for ", pre_dominant_code)
                        rv1 = context.order_target(pre_dominant_code, 0, price, order_type=OrderType.MARKET)
                        # msg1 = "{} 平空 for {} 下单函数返回={}".format(str(context.today), pre_dominant_code, str(rv1))
                        # context.write_log(msg1, stdout=1)
                    else:
                        if dominant_code != pre_dominant_code:
                            # print(context.today, "未触发平空仓信号, 但需移仓换月, for ", pre_dominant_code, dominant_code)
                            rv1 = context.order_target(pre_dominant_code, 0, price, order_type=OrderType.MARKET)
                            # msg1 = "{} 平旧主力合约 for {} 下单函数返回={}".format(str(context.today), pre_dominant_code, str(rv1))
                            # context.write_log(msg1, stdout=1)
                            rv2 = context.order_target(dominant_code, -short_position, price, order_type=OrderType.MARKET)
                            # msg2 = "{} 开新主力合约 for {} 下单函数返回={}".format(str(context.today), dominant_code, str(rv2))
                            # context.write_log(msg2, stdout=1)
    
                elif long_position > 0:
                    if price < ma_line:# or price >= context.long_stop_line:
                        # print(context.today, "平多, for ", pre_dominant_code)
                        rv1 = context.order_target(pre_dominant_code, 0, price, order_type=OrderType.MARKET)
                        # msg1 = "{} 平多 for {} 下单函数返回={}".format(str(context.today), pre_dominant_code, str(rv1))
                        # context.write_log(msg1, stdout=1)
                    else:
                        if dominant_code != pre_dominant_code:
                            # print(context.today, "未触发平多仓信号, 但需移仓换月, for ", pre_dominant_code, dominant_code)
                            rv1 = context.order_target(pre_dominant_code, 0, price, order_type=OrderType.MARKET)
                            # msg1 = "{} 平旧主力合约 for {} 下单函数返回={}".format(str(context.today), pre_dominant_code, str(rv1))
                            # context.write_log(msg1, stdout=1)
                            rv2 = context.order_target(dominant_code, long_position, price, order_type=OrderType.MARKET)
                            # msg2 = "{} 开新主力合约 for {} 下单函数返回={}".format(str(context.today), dominant_code, str(rv2))
                            # context.write_log(msg2, stdout=1)
    # 交易引擎:成交回报处理函数,每个成交发生时执行一次
    def m8_handle_trade_bigquant_run(context, data):
    #     msg = "handle_trade data:{}".format(data.log_str())
    #     context.write_log(msg, stdout=context.PRINT)
        pass
    
    # 交易引擎:委托回报处理函数,每个委托变化时执行一次
    def m8_handle_order_bigquant_run(context, data):
    #     msg = "handle_order data:{}".format(data.log_str())
    #     context.write_log(msg, stdout=context.PRINT)
        pass
    
    # 交易引擎:盘后处理函数,每日盘后执行一次
    def m8_after_trading_bigquant_run(context, data):
        context.extension.pre_ins = context.ins
        context.extension.pre_ins_dominant = context.ins_dominant
    
    
    m1 = M.instruments.v2(
        start_date=T.live_run_param('trading_date', '2010-01-01'),
        end_date=T.live_run_param('trading_date', '2022-08-31'),
        market='CN_FUTURE',
        instrument_list='',
        max_count=0
    )
    
    m7 = M.futures_forward_extractor.v9(
        input_1=m1.data,
        before_days=252,
        product_filter=["BB", "LR", "JR", "FB", "RI", "WR", "RS", "PM", "WT", "TC", "RO", "ER", "WS", "B", "FU", "LU", "SC", "L", "ME", "WH"],
        if_CFX=True,
        set_enable_trade=False
    )
    
    m5 = M.use_datasource.v1(
        instruments=m7.data_2,
        datasource_id='bar1d_CN_FUTURE',
        start_date='',
        end_date=''
    )
    
    m6 = M.sort.v5(
        input_ds=m5.data,
        sort_by='date',
        group_by='--',
        keep_columns='--',
        ascending=True
    )
    
    m2 = M.input_features.v1(
        features="""# #号开始的表示注释,注释需单独一行
    # 多个特征,每行一个,可以包含基础特征和衍生特征,特征须为本平台特征
    # bbands_up = ta_bbands_u(close, 20)
    # bbands = ta_bbands_m(close, 20)
    # bbands_low = ta_bbands_l(close, 20)
    bbands_std = std(close, 30)
    bbands = mean(close, 30)
    bbands_up = mean(close, 30) + 1 * bbands_std
    bbands_low = mean(close, 30) - 1 * bbands_std
    
    ATR = ta_atr(high, low, close, 30)
    Lev_ATR = clip(((0.05 / ATR) * close), 0.01, 5)
    
    OI_short = mean(open_intl, 10)
    OI_long = mean(open_intl, 20)
    OI_pct = OI_short / OI_long
    
    price_diff = close - shift(close, 1)
    trend_strength = (close - shift(close, 252)) / sum(abs(price_diff), 252)
    
    """
    )
    
    m4 = M.derived_feature_extractor.v3(
        input_data=m6.sorted_data,
        features=m2.data,
        date_col='date',
        instrument_col='instrument',
        drop_na=False,
        remove_extra_columns=True,
        user_functions={}
    )
    
    m3 = M.dropnan.v2(
        input_data=m4.data
    )
    
    m8 = M.hftrade.v2(
        instruments=m7.data_1,
        options_data=m3.data,
        start_date='',
        end_date='',
        initialize=m8_initialize_bigquant_run,
        before_trading_start=m8_before_trading_start_bigquant_run,
        handle_tick=m8_handle_tick_bigquant_run,
        handle_data=m8_handle_data_bigquant_run,
        handle_trade=m8_handle_trade_bigquant_run,
        handle_order=m8_handle_order_bigquant_run,
        after_trading=m8_after_trading_bigquant_run,
        capital_base=100000000,
        frequency='daily',
        price_type='真实价格',
        product_type='期货',
        before_start_days='0',
        volume_limit=1,
        order_price_field_buy='open',
        order_price_field_sell='open',
        benchmark='',
        plot_charts=True,
        disable_cache=True,
        replay_bdb=False,
        show_debug_info=False,
        backtest_only=False
    )
    
    2022-09-15 23:16:51.102341 strategy(bktfut,): initialize: 
    initializing:
    
    • 收益率867.7%
    • 年化收益率19.54%
    • 基准收益率0.0%
    • 阿尔法nan
    • 贝塔nan
    • 夏普比率0.71
    • 胜率0.42
    • 盈亏比1.29
    • 收益波动率27.52%
    • 最大回撤38.43%
    bigcharts-data-start/{"__type":"tabs","__id":"bigchart-54a0c891d3a741c6aef59d93871340e7"}/bigcharts-data-end
    In [37]:
    import empyrical
    start_date = ['2010-01-01', '2011-01-01', '2012-01-01', '2013-01-01', '2014-01-01', '2015-01-01', '2016-01-01', '2017-01-01', '2018-01-01', '2019-01-01', '2020-01-01', '2021-01-01', '2022-01-01']
    end_date = ['2010-12-31', '2011-12-31', '2012-12-31', '2013-12-31', '2014-12-31', '2015-12-31', '2016-12-31', '2017-12-31', '2018-12-31', '2019-12-31', '2020-12-31', '2021-12-31', '2022-08-31']
    raw_perf = m8.raw_perf.read()
    dic = {}
    sp = []
    calm = []
    rt = []
    md = []
    v = []
    for sd, ed in zip(start_date, end_date):
        df = raw_perf[raw_perf.date.between(sd, ed)]
        sharpe = empyrical.sharpe_ratio(df.returns)
        calmar = empyrical.calmar_ratio(df.returns)
        rts = df.portfolio_value.iloc[-1] / df.portfolio_value.iloc[0] - 1
        max_drawdown = empyrical.max_drawdown(df.returns)
        vol = empyrical.annual_volatility(df.returns)
        sp.append(sharpe)
        calm.append(calmar)
        rt.append(rts)
        md.append(max_drawdown)
        v.append(vol)
    #     print(f"date between {sd} and {ed}, the sharpe is {sharpe}, calmar ratio is {calmar}")
        print(f"date between {sd} and {ed}, the returns is {rts}, max_drawdown is {max_drawdown}, the sharpe is {sharpe}, calmar ratio is {calmar}, annual_volatility is {vol}")
    
    date between 2010-01-01 and 2010-12-31, the returns is 0.4028877460936331, max_drawdown is -0.30660243149977917, the sharpe is 1.106753289018349, calmar ratio is 1.3784971977369616, annual_volatility is 0.3852831016784801
    date between 2011-01-01 and 2011-12-31, the returns is 0.08760615509682834, max_drawdown is -0.20955968639383293, the sharpe is 0.42338026102556864, calmar ratio is 0.42477477386160534, annual_volatility is 0.32793493755879677
    date between 2012-01-01 and 2012-12-31, the returns is 0.18436978290162198, max_drawdown is -0.11999792287745015, the sharpe is 0.741774301050189, calmar ratio is 1.4633120530637032, annual_volatility is 0.26496886276108383
    date between 2013-01-01 and 2013-12-31, the returns is 0.04724144585234691, max_drawdown is -0.14198165684660088, the sharpe is 0.3782295637998466, calmar ratio is 0.44048009529706306, annual_volatility is 0.22880023017942971
    date between 2014-01-01 and 2014-12-31, the returns is 0.5772702710972213, max_drawdown is -0.14697882927375172, the sharpe is 2.132017645996741, calmar ratio is 3.991980624533788, annual_volatility is 0.22893917766364102
    date between 2015-01-01 and 2015-12-31, the returns is 0.10884652213121737, max_drawdown is -0.1618438206084768, the sharpe is 0.6171209169699925, calmar ratio is 0.7798618208458395, annual_volatility is 0.23886786614553648
    date between 2016-01-01 and 2016-12-31, the returns is 0.34690895157445567, max_drawdown is -0.23929622491643548, the sharpe is 1.1195947870398775, calmar ratio is 1.4325001172996241, annual_volatility is 0.3044351717479223
    date between 2017-01-01 and 2017-12-31, the returns is -0.12318713409593207, max_drawdown is -0.22162745872222264, the sharpe is -0.3903889320733456, calmar ratio is -0.4310017517446373, annual_volatility is 0.2041071631263471
    date between 2018-01-01 and 2018-12-31, the returns is 0.13942927283951945, max_drawdown is -0.14091705909200772, the sharpe is 0.6428248821723245, calmar ratio is 0.9828317019426395, annual_volatility is 0.25065953566537535
    date between 2019-01-01 and 2019-12-31, the returns is 0.5370147160501741, max_drawdown is -0.12058886729113008, the sharpe is 2.1416565736106623, calmar ratio is 4.9503999991539525, annual_volatility is 0.23115110593735888
    date between 2020-01-01 and 2020-12-31, the returns is 0.5487577576072331, max_drawdown is -0.1973792631510433, the sharpe is 1.556606648586716, calmar ratio is 2.86708559149759, annual_volatility is 0.32103889734299207
    date between 2021-01-01 and 2021-12-31, the returns is -0.23703512326376697, max_drawdown is -0.3505245562678033, the sharpe is -0.9720787950393871, calmar ratio is -0.6583804336122538, annual_volatility is 0.2402472205873162
    date between 2022-01-01 and 2022-08-31, the returns is 0.1124329332123093, max_drawdown is -0.19700339588806068, the sharpe is 0.7999161516524566, calmar ratio is 1.101575288375545, annual_volatility is 0.3030282488671844
    
    In [38]:
    dic["sharpe_ratio"] = sp
    dic["calmar_ratio"] = calm
    dic["returns"] = rt
    dic["max_drawdown"] = md
    dic["annual_volatility"] = v
    
    In [39]:
    pd.DataFrame(dic)
    
    Out[39]:
    sharpe_ratio calmar_ratio returns max_drawdown annual_volatility
    0 1.106753 1.378497 0.402888 -0.306602 0.385283
    1 0.423380 0.424775 0.087606 -0.209560 0.327935
    2 0.741774 1.463312 0.184370 -0.119998 0.264969
    3 0.378230 0.440480 0.047241 -0.141982 0.228800
    4 2.132018 3.991981 0.577270 -0.146979 0.228939
    5 0.617121 0.779862 0.108847 -0.161844 0.238868
    6 1.119595 1.432500 0.346909 -0.239296 0.304435
    7 -0.390389 -0.431002 -0.123187 -0.221627 0.204107
    8 0.642825 0.982832 0.139429 -0.140917 0.250660
    9 2.141657 4.950400 0.537015 -0.120589 0.231151
    10 1.556607 2.867086 0.548758 -0.197379 0.321039
    11 -0.972079 -0.658380 -0.237035 -0.350525 0.240247
    12 0.799916 1.101575 0.112433 -0.197003 0.303028
    In [40]:
    empyrical.calmar_ratio(raw_perf.returns)
    
    Out[40]:
    0.5313595698361405
    In [ ]: