复制链接
克隆策略

Dual Thrust日内策略-分钟

交易规则

  • 计算前N天的最高价-收盘价的最小值和收盘价的最大值-最低价。然后取其中的较大值,乘以k值。
  • 当价格超过上轨(开盘+触发值)时买入,或者价格低于下轨(开盘-触发值)时卖空。此策略没有止损,为正反手策略。 ## 策略构建步骤

确定股票池和回测时间

  • 通过证券代码列表输入回测的起止日期

确定买卖原则

  • 当价格超过上轨(开盘+触发值)时买入,或者价格低于下轨(开盘-触发值)时卖空。此策略没有止损,为正反手策略。

回测

  • 通过 trade 模块中的初始化函数定义交易手续费和滑点;

  • 通过 trade 模块中的主函数(handle函数)查看每日的买卖交易信号,按照买卖原则执行相应的买入/卖出/调仓操作。

策略详情

    {"description":"实验创建于2021/12/6","graph":{"edges":[{"to_node_id":"-227:instruments","from_node_id":"-216:data"}],"nodes":[{"node_id":"-216","module_id":"BigQuantSpace.instruments.instruments-v2","parameters":[{"name":"start_date","value":"2021-08-21","type":"Literal","bound_global_parameter":null},{"name":"end_date","value":"2021-09-27","type":"Literal","bound_global_parameter":null},{"name":"market","value":"CN_FUTURE","type":"Literal","bound_global_parameter":null},{"name":"instrument_list","value":"RU2201.SHF","type":"Literal","bound_global_parameter":null},{"name":"max_count","value":0,"type":"Literal","bound_global_parameter":null}],"input_ports":[{"name":"rolling_conf","node_id":"-216"}],"output_ports":[{"name":"data","node_id":"-216"}],"cacheable":true,"seq_num":1,"comment":"","comment_collapsed":true},{"node_id":"-227","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 # 加载预测数据\n print(\"initialize\") \n context.ins = context.instruments[0]#从传入参数中获取需要交易的合约\n context.order_num = 2#下单手数\n context.set_universe(context.ins)#设置需要处理的合约\n context.N = 5 #基于N天的历史数据\n context.k1 = 0.2 #上轨参数\n context.k2 = 0.2 #下轨参数\n context.today_open = 0 #当天开盘价\n context.closetime_day = \"14:58\"#日内策略白盘平仓时间,一般14:58\n context.closetime_night = \"22:58\"#日内策略夜盘平仓时间,一般22:58,注意有些商品夜盘收盘时间不一样","type":"Literal","bound_global_parameter":null},{"name":"before_trading_start","value":"# 交易引擎:每个单位时间开盘前调用一次。\ndef bigquant_run(context, data):\n context.subscribe(context.ins) #注册合约\n context.index = 0\n context.flag = 1 #用于获取今开\n # 取历史数据\n hist = data.history(context.ins, [\"open\",\"high\",\"low\",\"close\"], context.N, \"1d\")\n # 计算Dual Thrust 的上下轨\n HH = hist['high'].max()\n HC = hist['close'].max()\n LC = hist['close'].min()\n LL = hist['low'].min()\n context.range = max(HH - LC, HC - LL)","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":"def bigquant_run(context, data):\n from datetime import datetime,timedelta\n #获取当天的开盘价\n if context.flag == 1 :\n history_data = data.history(context.ins, [\"open\"], 1, \"1m\")\n context.today_open = history_data.iloc[-1]['open'] \n context.flag += 1\n \n #获取当前时间\n cur_date = data.current_dt\n cur_hm = cur_date.strftime('%H:%M') \n #计算上下轨\n buy_line = context.today_open + context.range * context.k1 \n sell_line = context.today_open - context.range * context.k2 \n # 分别获取多头持仓和空头持仓\n position_long = context.get_position(context.ins, Direction.LONG)\n position_short = context.get_position(context.ins, Direction.SHORT)\n # 获取当前价格\n price = data.current(context.ins, \"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(context.ins, position_long.avail_qty, price, order_type=OrderType.MARKET)\n msg = \"{} 尾盘平多 for {} 最新价={} 下单函数返回={}\".format(str(data.current_dt),context.ins,str(price),str(rv))\n context.write_log(msg, stdout=1) \n if(position_short.current_qty != 0):\n rv = context.buy_close(context.ins, position_short.avail_qty, price, order_type=OrderType.MARKET)\n msg = \"{} 尾盘平空 for {} 最新价={} 下单函数返回={}\".format(str(data.current_dt),context.ins,str(price),str(rv))\n context.write_log(msg, stdout=1) \n #尾盘不开新仓,直接返回\n return\n \n #交易逻辑\n if price > buy_line:\n if position_long.current_qty != 0:\n return\n else:\n if position_short.current_qty != 0:\n rv = context.buy_close(context.ins, position_short.avail_qty, price, order_type=OrderType.MARKET)\n msg = \"{} 平空 for {} 最新价={} 下单函数返回={}\".format(str(data.current_dt),context.ins,str(price),str(rv))\n context.write_log(msg, stdout=1)\n rv = context.buy_open(context.ins, context.order_num, price, order_type=OrderType.MARKET)\n msg = \"{} 开多 for {} 最新价={} 下单函数返回={}\".format(str(data.current_dt),context.ins,str(price),str(rv))\n context.write_log(msg, stdout=1) \n \n elif price < sell_line:\n if position_short.current_qty != 0:\n return\n else:\n if position_long.current_qty != 0:\n rv = context.sell_close(context.ins, position_long.avail_qty, price, order_type=OrderType.MARKET)\n msg = \"{} 平多 for {} 最新价={} 下单函数返回={}\".format(str(data.current_dt),context.ins,str(price),str(rv))\n context.write_log(msg, stdout=1) \n rv = context.sell_open(context.ins, context.order_num, price, order_type=OrderType.MARKET)\n msg = \"{} 开空 for {} 最新价={} 下单函数返回={}\".format(str(data.current_dt),context.ins,str(price),str(rv))\n context.write_log(msg, 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=1) \n # 分别获取最新的多头持仓和空头持仓\n position_long = context.get_position(data.symbol, Direction.LONG)\n position_short = context.get_position(data.symbol, Direction.SHORT)\n msg = \"当前多头持仓:{} 当前空头持仓:{}\".format(str(position_long),str(position_short))\n context.write_log(msg, stdout=1)\n","type":"Literal","bound_global_parameter":null},{"name":"handle_order","value":"# 交易引擎:委托回报处理函数,每个委托变化时执行一次\ndef bigquant_run(context, data):\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":"50000","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":"0","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":"-227"},{"name":"options_data","node_id":"-227"},{"name":"history_ds","node_id":"-227"},{"name":"benchmark_ds","node_id":"-227"}],"output_ports":[{"name":"raw_perf","node_id":"-227"}],"cacheable":false,"seq_num":2,"comment":"","comment_collapsed":true}],"node_layout":"<node_postions><node_position Node='-216' Position='68,107,200,200'/><node_position Node='-227' Position='18.75,221,200,200'/></node_postions>"},"nodes_readonly":false,"studio_version":"v2"}
    In [2]:
    # 本代码由可视化策略环境自动生成 2021年12月10日 15:54
    # 本代码单元只能在可视化模式下编辑。您也可以拷贝代码,粘贴到新建的代码单元或者策略,然后修改。
    
    
    # 交易引擎:初始化函数,只执行一次
    def m2_initialize_bigquant_run(context):
        # 加载预测数据
        print("initialize")  
        context.ins = context.instruments[0]#从传入参数中获取需要交易的合约
        context.order_num = 2#下单手数
        context.set_universe(context.ins)#设置需要处理的合约
        context.N = 5 #基于N天的历史数据
        context.k1 = 0.2 #上轨参数
        context.k2 = 0.2 #下轨参数
        context.today_open = 0 #当天开盘价
        context.closetime_day = "14:58"#日内策略白盘平仓时间,一般14:58
        context.closetime_night = "22:58"#日内策略夜盘平仓时间,一般22:58,注意有些商品夜盘收盘时间不一样
    # 交易引擎:每个单位时间开盘前调用一次。
    def m2_before_trading_start_bigquant_run(context, data):
        context.subscribe(context.ins) #注册合约
        context.index = 0
        context.flag = 1 #用于获取今开
        # 取历史数据
        hist = data.history(context.ins, ["open","high","low","close"], context.N, "1d")
        # 计算Dual Thrust 的上下轨
        HH = hist['high'].max()
        HC = hist['close'].max()
        LC = hist['close'].min()
        LL = hist['low'].min()
        context.range = max(HH - LC, HC - LL)
    # 交易引擎:tick数据处理函数,每个tick执行一次
    def m2_handle_tick_bigquant_run(context, data):
        pass
    
    def m2_handle_data_bigquant_run(context, data):
        from datetime import datetime,timedelta
        #获取当天的开盘价
        if context.flag == 1 :
            history_data = data.history(context.ins, ["open"], 1, "1m")
            context.today_open = history_data.iloc[-1]['open'] 
            context.flag += 1
        
        #获取当前时间
        cur_date = data.current_dt
        cur_hm = cur_date.strftime('%H:%M') 
        #计算上下轨
        buy_line = context.today_open + context.range * context.k1  
        sell_line = context.today_open - context.range * context.k2 
        # 分别获取多头持仓和空头持仓
        position_long = context.get_position(context.ins, Direction.LONG)
        position_short = context.get_position(context.ins, Direction.SHORT)
        # 获取当前价格
        price = data.current(context.ins, "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(context.ins, position_long.avail_qty, price, order_type=OrderType.MARKET)
                msg = "{} 尾盘平多 for {}  最新价={} 下单函数返回={}".format(str(data.current_dt),context.ins,str(price),str(rv))
                context.write_log(msg, stdout=1) 
            if(position_short.current_qty != 0):
                rv = context.buy_close(context.ins, position_short.avail_qty, price, order_type=OrderType.MARKET)
                msg = "{} 尾盘平空 for {}  最新价={} 下单函数返回={}".format(str(data.current_dt),context.ins,str(price),str(rv))
                context.write_log(msg, stdout=1) 
            #尾盘不开新仓,直接返回
            return
            
        #交易逻辑
        if price > buy_line:
            if position_long.current_qty != 0:
                return
            else:
                if position_short.current_qty != 0:
                    rv = context.buy_close(context.ins, position_short.avail_qty, price, order_type=OrderType.MARKET)
                    msg = "{} 平空 for {}  最新价={} 下单函数返回={}".format(str(data.current_dt),context.ins,str(price),str(rv))
                    context.write_log(msg, stdout=1)
                rv = context.buy_open(context.ins, context.order_num, price, order_type=OrderType.MARKET)
                msg = "{} 开多 for {}  最新价={} 下单函数返回={}".format(str(data.current_dt),context.ins,str(price),str(rv))
                context.write_log(msg, stdout=1) 
       
        elif price < sell_line:
            if position_short.current_qty != 0:
                return
            else:
                if position_long.current_qty != 0:
                    rv = context.sell_close(context.ins, position_long.avail_qty, price, order_type=OrderType.MARKET)
                    msg = "{} 平多 for {}  最新价={} 下单函数返回={}".format(str(data.current_dt),context.ins,str(price),str(rv))
                    context.write_log(msg, stdout=1) 
                rv = context.sell_open(context.ins, context.order_num, price, order_type=OrderType.MARKET)
                msg = "{} 开空 for {}  最新价={} 下单函数返回={}".format(str(data.current_dt),context.ins,str(price),str(rv))
                context.write_log(msg, stdout=1)    
    # 交易引擎:成交回报处理函数,每个成交发生时执行一次
    def m2_handle_trade_bigquant_run(context, data):
        msg = "handle_trade data:{}".format(data.log_str())
        context.write_log(msg, stdout=1) 
        # 分别获取最新的多头持仓和空头持仓
        position_long = context.get_position(data.symbol, Direction.LONG)
        position_short = context.get_position(data.symbol, Direction.SHORT)
        msg = "当前多头持仓:{} 当前空头持仓:{}".format(str(position_long),str(position_short))
        context.write_log(msg, stdout=1)
    
    # 交易引擎:委托回报处理函数,每个委托变化时执行一次
    def m2_handle_order_bigquant_run(context, data):
        pass
    
    # 交易引擎:盘后处理函数,每日盘后执行一次
    def m2_after_trading_bigquant_run(context, data):
        pass
    
    
    m1 = M.instruments.v2(
        start_date='2021-08-21',
        end_date='2021-09-27',
        market='CN_FUTURE',
        instrument_list='RU2201.SHF',
        max_count=0
    )
    
    m2 = M.hftrade.v2(
        instruments=m1.data,
        start_date='',
        end_date='',
        initialize=m2_initialize_bigquant_run,
        before_trading_start=m2_before_trading_start_bigquant_run,
        handle_tick=m2_handle_tick_bigquant_run,
        handle_data=m2_handle_data_bigquant_run,
        handle_trade=m2_handle_trade_bigquant_run,
        handle_order=m2_handle_order_bigquant_run,
        after_trading=m2_after_trading_bigquant_run,
        capital_base=50000,
        frequency='minute',
        price_type='真实价格',
        product_type='期货',
        before_start_days='0',
        benchmark='000300.HIX',
        plot_charts=True,
        disable_cache=False,
        show_debug_info=False,
        backtest_only=False
    )
    
    • 收益率5.69%
    • 年化收益率78.76%
    • 基准收益率0.86%
    • 阿尔法2.09
    • 贝塔-1.61
    • 夏普比率1.12
    • 胜率0.21
    • 盈亏比1.14
    • 收益波动率69.36%
    • 最大回撤20.23%
    bigcharts-data-start/{"__type":"tabs","__id":"bigchart-ceca1510a36c4bfeacaf28956165c5e4"}/bigcharts-data-end