克隆策略

    {"description":"实验创建于9/10/2021","graph":{"edges":[{"to_node_id":"-8:instruments","from_node_id":"-30:data"},{"to_node_id":"-39:instruments","from_node_id":"-30:data"},{"to_node_id":"-8:options_data","from_node_id":"-39:data"}],"nodes":[{"node_id":"-8","module_id":"BigQuantSpace.hftrade.hftrade-v1","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.closetime_day = \"14:58\"\n context.closetime_night = \"22:58\"\n #注册bar处理函数\n context.subscribe_bar(context.instruments, \"1m\", handle_bar)\n #打印控制开关\n context.PRINT = 0\n\n #提前计算开仓需要的均线信息,节省回测时间\n context.mydata = context.options[\"data\"].read()\n def cal_signal(df):\n df = df.sort_values(\"date\")\n df[\"ma\"] = df[\"close\"].rolling(20).mean()\n df[\"signal\"] = np.where((df['close'].shift(1)<df['ma'].shift(1)) & (df['close']>=df['ma']),1,0)\n df[\"signal\"] = np.where((df['close'].shift(1)>df['ma'].shift(1)) & (df['close']<df['ma']),-1,df[\"signal\"])\n return df\n context.mydata = context.mydata.groupby(\"instrument\").apply(cal_signal).reset_index(drop=True)\n \n\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":"handle_tick","value":"# 交易引擎:tick数据处理函数,每个tick执行一次\ndef bigquant_run(context, data):\n pass\n","type":"Literal","bound_global_parameter":null},{"name":"handle_data","value":"from datetime import datetime,timedelta\n# 交易引擎:bar数据处理函数,每个时间单位执行一次\ndef bigquant_run(context, data):\n #此函数是处理handle_data\n pass\n\n#处理handle_bar\ndef handle_bar(context, bar):\n #获取当前时间\n cur_date = bar.datetime\n cur_hm = cur_date.strftime('%H:%M')\n \n # 分别获取多头持仓和空头持仓,主要使用 current_qty 和 avail_qty 两个属性\n position_long = context.get_position(bar.symbol, Direction.LONG)\n position_short = context.get_position(bar.symbol, Direction.SHORT)\n\n # 获取账户资金,主要使用 balance 和 available 两个属性,本策略没有使用到账户信息,在此仅作展示获取方法\n trading_account = context.get_trading_account()\n\n # 获取当前k线最新收盘价格\n price = bar.close\n \n #尾盘平仓\n #部分品种夜盘收盘时间不一样,此时间表示指定的尾盘平仓时间往后偏移30分钟,这段时间内不能开新仓,只能平仓。给30分钟是为了足够的冗余\n closetime_nightshift = (datetime.strptime(context.closetime_night,'%H:%M') + timedelta(minutes = 30)).strftime('%H:%M')\n if((cur_hm>=context.closetime_day and cur_hm<=\"15:00\") or (cur_hm>=context.closetime_night and cur_hm<=closetime_nightshift)):\n if(position_long.current_qty != 0):\n rv = context.sell_close(bar.symbol, position_long.avail_qty, price, order_type=OrderType.MARKET)\n msg = \"{} 尾盘平多 for {} 最新价={} 下单函数返回 {}\".format(str(cur_date),bar.symbol,price,context.get_error_msg(rv))\n context.write_log(msg, stdout=context.PRINT) \n if(position_short.current_qty != 0):\n rv = context.buy_close(bar.symbol, position_short.avail_qty, price, order_type=OrderType.MARKET)\n msg = \"{} 尾盘平空 for {} 最新价={} 下单函数返回 {}\".format(str(cur_date),bar.symbol,price,context.get_error_msg(rv))\n context.write_log(msg, stdout=context.PRINT) \n #尾盘不开新仓,直接返回\n return\n \n #获取历史数据数据\n hist = context.mydata[(context.mydata.instrument==bar.symbol)&(context.mydata.date==cur_date)]\n #没有找到对应数据,直接返回\n if len(hist)==0:\n return\n\n #计算20均线\n hist['ma'] = hist['close'].rolling(20).mean()\n\n #价格向上穿越20均线\n if(hist[\"signal\"].iloc[0]==1):\n #有空单的先平掉\n if (position_short.avail_qty != 0):\n rv = context.buy_close(bar.symbol, position_short.avail_qty, price, order_type=OrderType.MARKET)\n msg = \"{} 平空 for {} 最新价={} 下单函数返回 {}\".format(bar.datetime,bar.symbol,price,context.get_error_msg(rv))\n context.write_log(msg, stdout=context.PRINT)\n #没有多单则开多1手\n if (position_long.current_qty == 0):\n rv = context.buy_open(bar.symbol, 1, price, order_type=OrderType.MARKET)\n msg = \"{} 开多 for {} 最新价={} 下单函数返回 {}\".format(bar.datetime,bar.symbol,price,context.get_error_msg(rv))\n context.write_log(msg, stdout=context.PRINT) \n #价格向下穿越20均线\n if (hist[\"signal\"].iloc[0]==-1):\n #有多单的先平掉\n if (position_long.avail_qty != 0):\n rv = context.sell_close(bar.symbol, position_long.avail_qty, price, order_type=OrderType.MARKET)\n msg = \"{} 平多 for {} 最新价={} 下单函数返回 {}\".format(bar.datetime,bar.symbol,price,context.get_error_msg(rv))\n context.write_log(msg, stdout=context.PRINT)\n #没有空单则开空1手 \n if (position_short.current_qty == 0):\n rv = context.sell_open(bar.symbol, 1, price, order_type=OrderType.MARKET)\n msg = \"{} 开空 for {} 最新价={} 下单函数返回 {}\".format(bar.datetime,bar.symbol,price,context.get_error_msg(rv))\n context.write_log(msg, stdout=context.PRINT) \n","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","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","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":"minute","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":"","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":"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":"-8"},{"name":"history_ds","node_id":"-8"},{"name":"benchmark_ds","node_id":"-8"},{"name":"options_data","node_id":"-8"}],"output_ports":[{"name":"raw_perf","node_id":"-8"}],"cacheable":false,"seq_num":1,"comment":"","comment_collapsed":true},{"node_id":"-30","module_id":"BigQuantSpace.instruments.instruments-v2","parameters":[{"name":"start_date","value":"2021-09-01","type":"Literal","bound_global_parameter":null},{"name":"end_date","value":"2021-09-08","type":"Literal","bound_global_parameter":null},{"name":"market","value":"CN_FUTURE","type":"Literal","bound_global_parameter":null},{"name":"instrument_list","value":"RB2201.SHF\nFG2201.CZC","type":"Literal","bound_global_parameter":null},{"name":"max_count","value":0,"type":"Literal","bound_global_parameter":null}],"input_ports":[{"name":"rolling_conf","node_id":"-30"}],"output_ports":[{"name":"data","node_id":"-30"}],"cacheable":true,"seq_num":2,"comment":"","comment_collapsed":true},{"node_id":"-39","module_id":"BigQuantSpace.use_datasource.use_datasource-v1","parameters":[{"name":"datasource_id","value":"bar1m_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":"-39"},{"name":"features","node_id":"-39"}],"output_ports":[{"name":"data","node_id":"-39"}],"cacheable":false,"seq_num":3,"comment":"","comment_collapsed":true}],"node_layout":"<node_postions><node_position Node='-8' Position='165,362,200,200'/><node_position Node='-30' Position='78,152,200,200'/><node_position Node='-39' Position='297.03350830078125,254.8686981201172,200,200'/></node_postions>"},"nodes_readonly":false,"studio_version":"v2"}
    In [2]:
    # 本代码由可视化策略环境自动生成 2021年10月28日 11:33
    # 本代码单元只能在可视化模式下编辑。您也可以拷贝代码,粘贴到新建的代码单元或者策略,然后修改。
    
    
    # 交易引擎:初始化函数,只执行一次
    def m1_initialize_bigquant_run(context):
        # 加载预测数据
        context.closetime_day = "14:58"
        context.closetime_night = "22:58"
        #注册bar处理函数
        context.subscribe_bar(context.instruments, "1m", handle_bar)
        #打印控制开关
        context.PRINT = 0
    
        #提前计算开仓需要的均线信息,节省回测时间
        context.mydata = context.options["data"].read()
        def cal_signal(df):
            df = df.sort_values("date")
            df["ma"] = df["close"].rolling(20).mean()
            df["signal"] = np.where((df['close'].shift(1)<df['ma'].shift(1)) & (df['close']>=df['ma']),1,0)
            df["signal"] = np.where((df['close'].shift(1)>df['ma'].shift(1)) & (df['close']<df['ma']),-1,df["signal"])
            return df
        context.mydata = context.mydata.groupby("instrument").apply(cal_signal).reset_index(drop=True)
        
    
    
    # 交易引擎:每个单位时间开盘前调用一次。
    def m1_before_trading_start_bigquant_run(context, data):
        pass
    
    # 交易引擎:tick数据处理函数,每个tick执行一次
    def m1_handle_tick_bigquant_run(context, data):
        pass
    
    from datetime import datetime,timedelta
    # 交易引擎:bar数据处理函数,每个时间单位执行一次
    def m1_handle_data_bigquant_run(context, data):
        #此函数是处理handle_data
        pass
    
    #处理handle_bar
    def handle_bar(context, bar):
        #获取当前时间
        cur_date = bar.datetime
        cur_hm = cur_date.strftime('%H:%M')
         
        # 分别获取多头持仓和空头持仓,主要使用 current_qty 和 avail_qty 两个属性
        position_long = context.get_position(bar.symbol, Direction.LONG)
        position_short = context.get_position(bar.symbol, Direction.SHORT)
    
        # 获取账户资金,主要使用 balance 和 available 两个属性,本策略没有使用到账户信息,在此仅作展示获取方法
        trading_account = context.get_trading_account()
    
        # 获取当前k线最新收盘价格
        price = bar.close
        
        #尾盘平仓
        #部分品种夜盘收盘时间不一样,此时间表示指定的尾盘平仓时间往后偏移30分钟,这段时间内不能开新仓,只能平仓。给30分钟是为了足够的冗余
        closetime_nightshift = (datetime.strptime(context.closetime_night,'%H:%M') + timedelta(minutes = 30)).strftime('%H:%M')
        if((cur_hm>=context.closetime_day and cur_hm<="15:00") or (cur_hm>=context.closetime_night and cur_hm<=closetime_nightshift)):
            if(position_long.current_qty != 0):
                rv = context.sell_close(bar.symbol, position_long.avail_qty, price, order_type=OrderType.MARKET)
                msg = "{} 尾盘平多 for {}  最新价={} 下单函数返回 {}".format(str(cur_date),bar.symbol,price,context.get_error_msg(rv))
                context.write_log(msg, stdout=context.PRINT) 
            if(position_short.current_qty != 0):
                rv = context.buy_close(bar.symbol, position_short.avail_qty, price, order_type=OrderType.MARKET)
                msg = "{} 尾盘平空 for {}  最新价={} 下单函数返回 {}".format(str(cur_date),bar.symbol,price,context.get_error_msg(rv))
                context.write_log(msg, stdout=context.PRINT) 
            #尾盘不开新仓,直接返回
            return
        
        #获取历史数据数据
        hist = context.mydata[(context.mydata.instrument==bar.symbol)&(context.mydata.date==cur_date)]
        #没有找到对应数据,直接返回
        if len(hist)==0:
            return
    
        #计算20均线
        hist['ma'] = hist['close'].rolling(20).mean()
    
        #价格向上穿越20均线
        if(hist["signal"].iloc[0]==1):
            #有空单的先平掉
            if (position_short.avail_qty != 0):
                rv = context.buy_close(bar.symbol, position_short.avail_qty, price, order_type=OrderType.MARKET)
                msg = "{} 平空 for {}  最新价={} 下单函数返回 {}".format(bar.datetime,bar.symbol,price,context.get_error_msg(rv))
                context.write_log(msg, stdout=context.PRINT)
            #没有多单则开多1手
            if (position_long.current_qty == 0):
                rv = context.buy_open(bar.symbol, 1, price, order_type=OrderType.MARKET)
                msg = "{} 开多 for {}  最新价={} 下单函数返回 {}".format(bar.datetime,bar.symbol,price,context.get_error_msg(rv))
                context.write_log(msg, stdout=context.PRINT) 
        #价格向下穿越20均线
        if (hist["signal"].iloc[0]==-1):
            #有多单的先平掉
            if (position_long.avail_qty != 0):
                rv = context.sell_close(bar.symbol, position_long.avail_qty, price, order_type=OrderType.MARKET)
                msg = "{} 平多 for {}  最新价={} 下单函数返回 {}".format(bar.datetime,bar.symbol,price,context.get_error_msg(rv))
                context.write_log(msg, stdout=context.PRINT)
            #没有空单则开空1手    
            if (position_short.current_qty == 0):
                rv = context.sell_open(bar.symbol, 1, price, order_type=OrderType.MARKET)
                msg = "{} 开空 for {}  最新价={} 下单函数返回 {}".format(bar.datetime,bar.symbol,price,context.get_error_msg(rv))
                context.write_log(msg, stdout=context.PRINT)  
    
    # 交易引擎:成交回报处理函数,每个成交发生时执行一次
    def m1_handle_trade_bigquant_run(context, data):
        msg = "handle_trade data:{}".format(data.log_str())
        context.write_log(msg, stdout=context.PRINT) 
    
    # 交易引擎:委托回报处理函数,每个委托变化时执行一次
    def m1_handle_order_bigquant_run(context, data):
        msg = "handle_order data:{}".format(data.log_str())
        context.write_log(msg, stdout=context.PRINT) 
    
    # 交易引擎:盘后处理函数,每日盘后执行一次
    def m1_after_trading_bigquant_run(context, data):
        pass
    
    
    m2 = M.instruments.v2(
        start_date='2021-09-01',
        end_date='2021-09-08',
        market='CN_FUTURE',
        instrument_list="""RB2201.SHF
    FG2201.CZC""",
        max_count=0
    )
    
    m3 = M.use_datasource.v1(
        instruments=m2.data,
        datasource_id='bar1m_CN_FUTURE',
        start_date='',
        end_date='',
        m_cached=False
    )
    
    m1 = M.hftrade.v1(
        instruments=m2.data,
        options_data=m3.data,
        start_date='',
        end_date='',
        initialize=m1_initialize_bigquant_run,
        before_trading_start=m1_before_trading_start_bigquant_run,
        handle_tick=m1_handle_tick_bigquant_run,
        handle_data=m1_handle_data_bigquant_run,
        handle_trade=m1_handle_trade_bigquant_run,
        handle_order=m1_handle_order_bigquant_run,
        after_trading=m1_after_trading_bigquant_run,
        capital_base=1000000,
        frequency='minute',
        price_type='真实价格',
        product_type='期货',
        before_start_days='',
        benchmark='000300.HIX',
        plot_charts=True,
        disable_cache=False,
        show_debug_info=False,
        backtest_only=False
    )
    
    2021-09-13 19:31:35.239618 run trading v1.7.8 
    2021-09-13 19:31:35.240254 init history datas... 
    2021-09-13 19:31:35.249282 init trading env... 
    
    • 收益率-0.23%
    • 年化收益率-9.32%
    • 基准收益率2.11%
    • 阿尔法-0.05
    • 贝塔-0.05
    • 夏普比率-7.16
    • 胜率0.12
    • 盈亏比0.95
    • 收益波动率1.78%
    • 最大回撤0.41%
    bigcharts-data-start/{"__type":"tabs","__id":"bigchart-0929ce25e9904ea594039343180987b4"}/bigcharts-data-end