克隆策略

    {"description":"实验创建于2021/10/29","graph":{"edges":[{"to_node_id":"-41:input_1","from_node_id":"-558:raw_perf"},{"to_node_id":"-558:instruments","from_node_id":"-589:data_1"},{"to_node_id":"-558:options_data","from_node_id":"-589:data_2"}],"nodes":[{"node_id":"-558","module_id":"BigQuantSpace.trade.trade-v4","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 # 加载预测数据\n context.stock_pools = context.options['data'].read()\n context.show_debug_info = False\n # 系统已经设置了默认的交易手续费和滑点,要修改手续费可使用如下函数\n context.set_commission(PerOrder(buy_cost=0.0001, sell_cost=0.0001, min_cost=5))\n context.options['hold_days'] = 22\n context.stock_count = 200\n context.trade_index = 0\n context.opt = T.PORTFOLIO_OPTIMIZERS(context.stock_pools, context.start_date, context.end_date, model_type='daily', benchmark='000905.HIX')\n","type":"Literal","bound_global_parameter":null},{"name":"handle_data","value":"# 回测引擎:每日数据处理函数,每天执行一次\ndef bigquant_run(context, data):\n context.trade_index += 1 # 交易日历递增1\n today = data.current_dt.strftime(\"%Y-%m-%d\")\n print('current_date is:', today)\n context.stock_pool = context.stock_pools[context.stock_pools.date == today]\n\n if context.trade_index == 1: # 第一天建仓\n try:\n context.opt.get_today_factor_data(context.stock_pool, today) ##当日数据初始化\n tf = context.opt.MinStyleDeviation({\"growth\":1}, if_pred=False, relative=True)\n objective = tf[0]\n cons = tf[1:]\n constraints = [context.opt.TotalWeightsConstraint(upper_limit=1), context.opt.Bounds(lower_limit=0, upper_limit=0.05, relative=True), context.opt.ExcludeStyleConstraint(\"growth\",lower_limit=-0.01,upper_limit=0.01,relative=True)]\n constraints.append(cons)\n weights_data = context.opt.optimize(objective, today, constraints, stock_count=context.stock_count, verbose=False, response=True, hard=False)\n\n def buy_1(df):\n target = df[\"instrument\"]\n weight = df[\"weight\"]\n sid = context.symbol(target)\n if data.can_trade(sid):\n context.order_target_percent(sid, weight)\n else:\n print(f\"{today} {target} 无法交易\")\n weights_data.apply(buy_1, axis=1)\n \n except Exception as e:\n print(today, \"当前日期建仓失败! except:\", e)\n context.trade_index -= 1 # 交易日历索引保持不变,以便当日优化失败后次日接着优化\n\n if context.trade_index % context.options[\"hold_days\"] == 0 and context.trade_index != 1: # 每隔调仓日进行调仓\n positions_weight = {e.symbol: p.amount * p.last_sale_price / context.portfolio.portfolio_value for e, p in context.portfolio.positions.items()} # 持仓权重\n equities = [e.symbol for e, p in context.portfolio.positions.items()] # 持仓股票列表\n w0 = pd.Series(positions_weight, index=equities)\n w0 = pd.DataFrame({'pre_weight': w0.values, 'instrument': w0.index})\n context.stock_pool = pd.merge(context.stock_pool, w0, on=['instrument'], how='left').fillna(0)\n context.opt.get_today_factor_data(context.stock_pool, today)\n\n try:\n tf = context.opt.MinStyleDeviation({\"growth\":1}, if_pred=False, relative=True)\n objective = tf[0]\n cons = tf[1:]\n constraints = [context.opt.TotalWeightsConstraint(upper_limit=1), context.opt.Bounds(lower_limit=0, upper_limit=0.05, relative=True),\n context.opt.ExcludeStyleConstraint(\"growth\",lower_limit=-0.01,upper_limit=0.01,relative=True, priority=1), context.opt.TurnoverConstraint(turnrate=0.5, priority=0)]\n constraints.append(cons)\n weights_data = context.opt.optimize(objective, today, constraints, stock_count=context.stock_count, verbose=False, response=True, hard=False)\n\n # 卖出逻辑\n need_hold_stocks = set(weights_data.instrument)\n for sx in equities:\n if sx not in need_hold_stocks: # 无法交易的持仓、优化股票之外的持仓 直接卖出\n order_target_percent(context.symbol(sx), 0)\n equities.remove(sx)\n positions_weight = {e:p for e, p in positions_weight.items() if e != sx}\n\n # 买入逻辑\n def buy_2(df):\n target = df[\"instrument\"]\n weight = df[\"weight\"]\n sid = context.symbol(target)\n if data.can_trade(sid):\n context.order_target_percent(sid, weight)\n else:\n print(f\"{today} {target} 无法交易\")\n weights_data.apply(buy_2, axis=1)\n \n except Exception as e:\n print(today, \"当前日期调仓失败! except:\", e)\n \n print('----------------------------------------------------------------------------------------date {} over----------------------------------------------------------------------------------------'.format(today))","type":"Literal","bound_global_parameter":null},{"name":"prepare","value":"# 回测引擎:准备数据,只执行一次\ndef bigquant_run(context):\n pass\n","type":"Literal","bound_global_parameter":null},{"name":"before_trading_start","value":"# 回测引擎:每个单位时间开始前调用一次,即每日开盘前调用一次。\ndef bigquant_run(context, data):\n pass\n","type":"Literal","bound_global_parameter":null},{"name":"volume_limit","value":0.025,"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":"capital_base","value":"100000000","type":"Literal","bound_global_parameter":null},{"name":"auto_cancel_non_tradable_orders","value":"True","type":"Literal","bound_global_parameter":null},{"name":"data_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":"plot_charts","value":"True","type":"Literal","bound_global_parameter":null},{"name":"backtest_only","value":"False","type":"Literal","bound_global_parameter":null},{"name":"benchmark","value":"000905.HIX","type":"Literal","bound_global_parameter":null}],"input_ports":[{"name":"instruments","node_id":"-558"},{"name":"options_data","node_id":"-558"},{"name":"history_ds","node_id":"-558"},{"name":"benchmark_ds","node_id":"-558"},{"name":"trading_calendar","node_id":"-558"}],"output_ports":[{"name":"raw_perf","node_id":"-558"}],"cacheable":false,"seq_num":1,"comment":"","comment_collapsed":true},{"node_id":"-589","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 start_date = '2018-01-01'\n end_date = '2021-10-18'\n index_cons = DataSource('index_element_weight').read(start_date=start_date, end_date=end_date)\n pred_data = index_cons[index_cons.instrument_index=='000905.HIX'][['instrument','weight','date']].reset_index(drop=True)\n pred_df = DataSource.write_df(pred_data)\n ## instruments\n ins = {}\n stock_list = pred_data.instrument.unique().tolist()\n ins['instruments'] = [x for x in stock_list if str(x) != 'nan']\n ins['start_date'] = start_date\n ins['end_date'] = end_date\n ins = DataSource.write_pickle(ins)\n return Outputs(data_1=ins, data_2=pred_df, 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":"-589"},{"name":"input_2","node_id":"-589"},{"name":"input_3","node_id":"-589"}],"output_ports":[{"name":"data_1","node_id":"-589"},{"name":"data_2","node_id":"-589"},{"name":"data_3","node_id":"-589"}],"cacheable":true,"seq_num":2,"comment":"","comment_collapsed":true},{"node_id":"-41","module_id":"BigQuantSpace.barra_risk_factor_analysis1.barra_risk_factor_analysis1-v8","parameters":[{"name":"analysis_flag","value":"relative","type":"Literal","bound_global_parameter":null},{"name":"benchmark_index","value":"000905.HIX","type":"Literal","bound_global_parameter":null},{"name":"terms","value":"daily","type":"Literal","bound_global_parameter":null}],"input_ports":[{"name":"input_1","node_id":"-41"}],"output_ports":[{"name":"data_1","node_id":"-41"},{"name":"data_2","node_id":"-41"}],"cacheable":true,"seq_num":3,"comment":"","comment_collapsed":true}],"node_layout":"<node_postions><node_position Node='-558' Position='64,560,200,200'/><node_position Node='-589' Position='63,413,200,200'/><node_position Node='-41' Position='141.30999755859375,661.8947143554688,200,200'/></node_postions>"},"nodes_readonly":false,"studio_version":"v2"}
    In [2]:
    # 本代码由可视化策略环境自动生成 2021年10月29日 14:08
    # 本代码单元只能在可视化模式下编辑。您也可以拷贝代码,粘贴到新建的代码单元或者策略,然后修改。
    
    
    # Python 代码入口函数,input_1/2/3 对应三个输入端,data_1/2/3 对应三个输出端
    def m2_run_bigquant_run(input_1, input_2, input_3):
        start_date = '2018-01-01'
        end_date = '2021-10-18'
        index_cons = DataSource('index_element_weight').read(start_date=start_date, end_date=end_date)
        pred_data = index_cons[index_cons.instrument_index=='000905.HIX'][['instrument','weight','date']].reset_index(drop=True)
        pred_df = DataSource.write_df(pred_data)
        ## instruments
        ins = {}
        stock_list = pred_data.instrument.unique().tolist()
        ins['instruments'] = [x for x in stock_list if str(x) != 'nan']
        ins['start_date'] = start_date
        ins['end_date'] = end_date
        ins = DataSource.write_pickle(ins)
        return Outputs(data_1=ins, data_2=pred_df, data_3=None)
    
    # 后处理函数,可选。输入是主函数的输出,可以在这里对数据做处理,或者返回更友好的outputs数据格式。此函数输出不会被缓存。
    def m2_post_run_bigquant_run(outputs):
        return outputs
    
    # 回测引擎:初始化函数,只执行一次
    def m1_initialize_bigquant_run(context):
        # 加载预测数据
        context.stock_pools = context.options['data'].read()
        context.show_debug_info = False
        # 系统已经设置了默认的交易手续费和滑点,要修改手续费可使用如下函数
        context.set_commission(PerOrder(buy_cost=0.0001, sell_cost=0.0001, min_cost=5))
        context.options['hold_days'] = 22
        context.stock_count = 200
        context.trade_index = 0
        context.opt = T.PORTFOLIO_OPTIMIZERS(context.stock_pools, context.start_date, context.end_date, model_type='daily', benchmark='000905.HIX')
    
    # 回测引擎:每日数据处理函数,每天执行一次
    def m1_handle_data_bigquant_run(context, data):
        context.trade_index += 1  # 交易日历递增1
        today = data.current_dt.strftime("%Y-%m-%d")
        print('current_date is:', today)
        context.stock_pool = context.stock_pools[context.stock_pools.date == today]
    
        if context.trade_index == 1:  # 第一天建仓
            try:
                context.opt.get_today_factor_data(context.stock_pool, today) ##当日数据初始化
                tf = context.opt.MinStyleDeviation({"growth":1}, if_pred=False, relative=True)
                objective = tf[0]
                cons = tf[1:]
                constraints = [context.opt.TotalWeightsConstraint(upper_limit=1), context.opt.Bounds(lower_limit=0, upper_limit=0.05, relative=True), context.opt.ExcludeStyleConstraint("growth",lower_limit=-0.01,upper_limit=0.01,relative=True)]
                constraints.append(cons)
                weights_data = context.opt.optimize(objective, today, constraints, stock_count=context.stock_count, verbose=False, response=True, hard=False)
    
                def buy_1(df):
                    target = df["instrument"]
                    weight = df["weight"]
                    sid = context.symbol(target)
                    if data.can_trade(sid):
                        context.order_target_percent(sid, weight)
                    else:
                        print(f"{today} {target} 无法交易")
                weights_data.apply(buy_1, axis=1)
                
            except Exception as e:
                print(today, "当前日期建仓失败! except:", e)
                context.trade_index -= 1  # 交易日历索引保持不变,以便当日优化失败后次日接着优化
    
        if context.trade_index % context.options["hold_days"] == 0 and context.trade_index != 1:  # 每隔调仓日进行调仓
            positions_weight = {e.symbol: p.amount * p.last_sale_price / context.portfolio.portfolio_value for e, p in context.portfolio.positions.items()} # 持仓权重
            equities = [e.symbol for e, p in context.portfolio.positions.items()]  # 持仓股票列表
            w0 = pd.Series(positions_weight, index=equities)
            w0 = pd.DataFrame({'pre_weight': w0.values, 'instrument': w0.index})
            context.stock_pool = pd.merge(context.stock_pool, w0, on=['instrument'], how='left').fillna(0)
            context.opt.get_today_factor_data(context.stock_pool, today)
    
            try:
                tf = context.opt.MinStyleDeviation({"growth":1}, if_pred=False, relative=True)
                objective = tf[0]
                cons = tf[1:]
                constraints = [context.opt.TotalWeightsConstraint(upper_limit=1), context.opt.Bounds(lower_limit=0, upper_limit=0.05, relative=True),
                               context.opt.ExcludeStyleConstraint("growth",lower_limit=-0.01,upper_limit=0.01,relative=True, priority=1), context.opt.TurnoverConstraint(turnrate=0.5, priority=0)]
                constraints.append(cons)
                weights_data = context.opt.optimize(objective, today, constraints, stock_count=context.stock_count, verbose=False, response=True, hard=False)
    
                # 卖出逻辑
                need_hold_stocks = set(weights_data.instrument)
                for sx in equities:
                    if sx not in need_hold_stocks:  # 无法交易的持仓、优化股票之外的持仓 直接卖出
                        order_target_percent(context.symbol(sx), 0)
                        equities.remove(sx)
                        positions_weight = {e:p for e, p in positions_weight.items() if e != sx}
    
                # 买入逻辑
                def buy_2(df):
                    target = df["instrument"]
                    weight = df["weight"]
                    sid = context.symbol(target)
                    if data.can_trade(sid):
                        context.order_target_percent(sid, weight)
                    else:
                        print(f"{today} {target} 无法交易")
                weights_data.apply(buy_2, axis=1)
                    
            except Exception as e:
                print(today, "当前日期调仓失败! except:", e)
                
            print('----------------------------------------------------------------------------------------date {} over----------------------------------------------------------------------------------------'.format(today))
    # 回测引擎:准备数据,只执行一次
    def m1_prepare_bigquant_run(context):
        pass
    
    # 回测引擎:每个单位时间开始前调用一次,即每日开盘前调用一次。
    def m1_before_trading_start_bigquant_run(context, data):
        pass
    
    
    m2 = M.cached.v3(
        run=m2_run_bigquant_run,
        post_run=m2_post_run_bigquant_run,
        input_ports='',
        params='{}',
        output_ports=''
    )
    
    m1 = M.trade.v4(
        instruments=m2.data_1,
        options_data=m2.data_2,
        start_date='',
        end_date='',
        initialize=m1_initialize_bigquant_run,
        handle_data=m1_handle_data_bigquant_run,
        prepare=m1_prepare_bigquant_run,
        before_trading_start=m1_before_trading_start_bigquant_run,
        volume_limit=0.025,
        order_price_field_buy='open',
        order_price_field_sell='open',
        capital_base=100000000,
        auto_cancel_non_tradable_orders=True,
        data_frequency='daily',
        price_type='真实价格',
        product_type='股票',
        plot_charts=True,
        backtest_only=False,
        benchmark='000905.HIX'
    )
    
    m3 = M.barra_risk_factor_analysis1.v8(
        input_1=m1.raw_perf,
        analysis_flag='relative',
        benchmark_index='000905.HIX',
        terms='daily'
    )
    
    • 收益率47.81%
    • 年化收益率11.31%
    • 基准收益率13.07%
    • 阿尔法0.08
    • 贝塔0.84
    • 夏普比率0.48
    • 胜率0.45
    • 盈亏比1.42
    • 收益波动率20.54%
    • 信息比率0.05
    • 最大回撤27.14%
    bigcharts-data-start/{"__type":"tabs","__id":"bigchart-b144927050384489ba4f1dc033e10359"}/bigcharts-data-end