克隆策略

通道突破策略——ATR指标

版本 v1.0

目录

ATR通道突破策略的交易规则

策略构建步骤

策略的实现

正文

一、ATR通道突破策略的交易规则

指标计算:

  • 中轨:收盘价的25日移动平均值
  • 通道宽度:平均真实波幅*2
  • 上轨:中轨+通道宽度 *下轨:中轨-通道宽度
  • 交易规则:当价格突破上轨,进场买入,建多仓,当价格突破下轨,进场卖出,建空仓。

二、策略构建步骤

1、确定股票池和回测时间

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

2、确定买卖原则

  • 当价格突破上轨,进场买入,建多仓,当价格突破下轨,进场卖出,建空仓。 ### 3、回测
  • 通过 trade 模块中的初始化函数定义交易手续费和滑点;
  • 通过 trade 模块中的主函数(handle函数)查看每日的买卖交易信号,按照买卖原则执行相应的买入/卖出/调仓操作。

三、策略的实现

可视化策略实现如下:

    {"description":"实验创建于2021/12/2","graph":{"edges":[{"to_node_id":"-71:instruments","from_node_id":"-5:data"},{"to_node_id":"-127:instruments","from_node_id":"-5:data"},{"to_node_id":"-62:features","from_node_id":"-13:data"},{"to_node_id":"-71:features","from_node_id":"-13:data"},{"to_node_id":"-97:input_data","from_node_id":"-62:data"},{"to_node_id":"-62:input_data","from_node_id":"-71:data"},{"to_node_id":"-127:options_data","from_node_id":"-97:data"}],"nodes":[{"node_id":"-5","module_id":"BigQuantSpace.instruments.instruments-v2","parameters":[{"name":"start_date","value":"2021-02-17","type":"Literal","bound_global_parameter":null},{"name":"end_date","value":"2021-11-26","type":"Literal","bound_global_parameter":null},{"name":"market","value":"CN_FUTURE","type":"Literal","bound_global_parameter":null},{"name":"instrument_list","value":"JM2201.DCE","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# 多个特征,每行一个,可以包含基础特征和衍生特征,特征须为本平台特征\nATR = ta_atr(high, low, close, timeperiod = 25)\nMA25 = mean(close,25)\nhigh_line = MA25 + 2 * ATR # 上轨\nlow_line = MA25 - 2 * ATR # 下轨","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":"False","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":"-127","module_id":"BigQuantSpace.hftrade.hftrade-v1","parameters":[{"name":"start_date","value":"2021-02-14","type":"Literal","bound_global_parameter":null},{"name":"end_date","value":"2021-10-18","type":"Literal","bound_global_parameter":null},{"name":"initialize","value":"# 交易引擎:初始化函数,只执行一次\ndef bigquant_run(context):\n context.all_data = context.options[\"data\"].read()\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":"# 交易引擎:bar数据处理函数,每个时间单位执行一次\ndef bigquant_run(context, data):\n import pandas as pd \n today = data.current_dt.strftime('%Y-%m-%d') # 当前交易日期\n all_data = context.all_data[context.all_data.date == today]\n all_data = pd.DataFrame(all_data)\n if len(all_data) == 0:#过滤没有指标的数据\n return\n \n price = all_data['close'].iloc[0]\n high_line = all_data['high_line'].iloc[0]\n low_line = all_data['low_line'].iloc[0]\n instrument = context.future_symbol(context.instruments[0]) # 交易标的\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 curr_position = short_position + long_position#总持仓\n if short_position > 0:\n if price > high_line:\n context.buy_close(instrument, short_position, price, order_type=OrderType.MARKET)\n context.buy_open(instrument, 4, price, order_type=OrderType.MARKET)\n print(today,'先平空再开多')\n elif long_position > 0:\n if price < low_line:\n context.sell_close(instrument, long_position, price, order_type=OrderType.MARKET)\n context.sell_open(instrument, 4, price, order_type=OrderType.MARKET)\n print(today,'先平多再开空',curr_position)\n elif curr_position==0:\n if price > high_line:\n context.buy_open(instrument, 4, price, order_type=OrderType.MARKET)\n print('空仓开多')\n elif price<low_line:\n context.sell_open(instrument, 4, price, order_type=OrderType.MARKET)\n print('空仓开空')","type":"Literal","bound_global_parameter":null},{"name":"handle_trade","value":"# 交易引擎:成交回报处理函数,每个成交发生时执行一次\ndef bigquant_run(context, data):\n pass\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":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":"","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":"-127"},{"name":"history_ds","node_id":"-127"},{"name":"benchmark_ds","node_id":"-127"},{"name":"options_data","node_id":"-127"}],"output_ports":[{"name":"raw_perf","node_id":"-127"}],"cacheable":false,"seq_num":6,"comment":"","comment_collapsed":true}],"node_layout":"<node_postions><node_position Node='-5' Position='293,113,200,200'/><node_position Node='-13' Position='602,109,200,200'/><node_position Node='-62' Position='420,280,200,200'/><node_position Node='-71' Position='258,194,200,200'/><node_position Node='-97' Position='406,357,200,200'/><node_position Node='-127' Position='350,452,200,200'/></node_postions>"},"nodes_readonly":false,"studio_version":"v2"}
    In [34]:
    # 本代码由可视化策略环境自动生成 2021年12月3日 11:18
    # 本代码单元只能在可视化模式下编辑。您也可以拷贝代码,粘贴到新建的代码单元或者策略,然后修改。
    
    
    # 交易引擎:初始化函数,只执行一次
    def m6_initialize_bigquant_run(context):
        context.all_data = context.options["data"].read()
        
    
    # 交易引擎:每个单位时间开盘前调用一次。
    def m6_before_trading_start_bigquant_run(context, data):
        pass
    
    # 交易引擎:tick数据处理函数,每个tick执行一次
    def m6_handle_tick_bigquant_run(context, data):
        pass
    
    # 交易引擎:bar数据处理函数,每个时间单位执行一次
    def m6_handle_data_bigquant_run(context, data):
        import pandas as pd 
        today = data.current_dt.strftime('%Y-%m-%d') # 当前交易日期
        all_data = context.all_data[context.all_data.date == today]
        all_data = pd.DataFrame(all_data)
        if len(all_data) == 0:#过滤没有指标的数据
            return
        
        price = all_data['close'].iloc[0]
        high_line = all_data['high_line'].iloc[0]
        low_line = all_data['low_line'].iloc[0]
        instrument = context.future_symbol(context.instruments[0]) # 交易标的
        long_position = context.get_account_position(instrument, direction=Direction.LONG).avail_qty#多头持仓
        short_position = context.get_account_position(instrument, direction=Direction.SHORT).avail_qty#空头持仓
        curr_position = short_position + long_position#总持仓
        if short_position > 0:
            if price > high_line:
                context.buy_close(instrument, short_position, price, order_type=OrderType.MARKET)
                context.buy_open(instrument, 4, price, order_type=OrderType.MARKET)
                print(today,'先平空再开多')
        elif long_position > 0:
            if price < low_line:
                context.sell_close(instrument, long_position, price, order_type=OrderType.MARKET)
                context.sell_open(instrument, 4, price, order_type=OrderType.MARKET)
                print(today,'先平多再开空',curr_position)
        elif curr_position==0:
            if price > high_line:
                context.buy_open(instrument, 4, price, order_type=OrderType.MARKET)
                print('空仓开多')
            elif price<low_line:
                context.sell_open(instrument, 4, price, order_type=OrderType.MARKET)
                print('空仓开空')
    # 交易引擎:成交回报处理函数,每个成交发生时执行一次
    def m6_handle_trade_bigquant_run(context, data):
        pass
    
    # 交易引擎:委托回报处理函数,每个委托变化时执行一次
    def m6_handle_order_bigquant_run(context, data):
        pass
    
    # 交易引擎:盘后处理函数,每日盘后执行一次
    def m6_after_trading_bigquant_run(context, data):
        pass
    
    
    m1 = M.instruments.v2(
        start_date='2021-02-17',
        end_date='2021-11-26',
        market='CN_FUTURE',
        instrument_list='JM2201.DCE',
        max_count=0
    )
    
    m2 = M.input_features.v1(
        features="""# #号开始的表示注释,注释需单独一行
    # 多个特征,每行一个,可以包含基础特征和衍生特征,特征须为本平台特征
    ATR = ta_atr(high, low, close, timeperiod = 25)
    MA25 = mean(close,25)
    high_line = MA25 + 2 * ATR # 上轨
    low_line = MA25 - 2 * ATR # 下轨"""
    )
    
    m5 = M.use_datasource.v1(
        instruments=m1.data,
        features=m2.data,
        datasource_id='bar1d_CN_FUTURE',
        start_date='',
        end_date=''
    )
    
    m4 = M.derived_feature_extractor.v3(
        input_data=m5.data,
        features=m2.data,
        date_col='date',
        instrument_col='instrument',
        drop_na=False,
        remove_extra_columns=False,
        user_functions={}
    )
    
    m3 = M.dropnan.v2(
        input_data=m4.data
    )
    
    m6 = M.hftrade.v1(
        instruments=m1.data,
        options_data=m3.data,
        start_date='2021-02-14',
        end_date='2021-10-18',
        initialize=m6_initialize_bigquant_run,
        before_trading_start=m6_before_trading_start_bigquant_run,
        handle_tick=m6_handle_tick_bigquant_run,
        handle_data=m6_handle_data_bigquant_run,
        handle_trade=m6_handle_trade_bigquant_run,
        handle_order=m6_handle_order_bigquant_run,
        after_trading=m6_after_trading_bigquant_run,
        capital_base=1000000,
        frequency='daily',
        price_type='真实价格',
        product_type='期货',
        before_start_days='',
        benchmark='000300.HIX',
        plot_charts=True,
        disable_cache=False,
        show_debug_info=False,
        backtest_only=False
    )
    
    • 收益率81.84%
    • 年化收益率154.96%
    • 基准收益率-15.49%
    • 阿尔法1.76
    • 贝塔0.13
    • 夏普比率2.56
    • 胜率0.17
    • 盈亏比0.26
    • 收益波动率38.21%
    • 最大回撤17.34%
    bigcharts-data-start/{"__type":"tabs","__id":"bigchart-70cd168def4e4b60bf557dc1713da5be"}/bigcharts-data-end