复制链接
克隆策略

卡夫曼自适应移动均线-分钟

交易规则

  • 我们最终的卡夫曼自适应移动均线AMA如下定义:AMAt=AMAt−1+c⋅(p–AMAt−1)
  • 过滤器被定义为AMA变化的一个小的百分数:filter=percentage⋅std(AMAt−AMAt−1,n)其中,std(series, n)是滑动标准差函数。

策略构建步骤

确定股票池和回测时间

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

确定买卖原则

  • 当AMA - min(AMA, n) > filter,买入;
  • 当max(AMA, n) – AMA > filter,卖出。

回测

  • 通过 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":"2018-04-20","type":"Literal","bound_global_parameter":null},{"name":"end_date","value":"2018-05-30","type":"Literal","bound_global_parameter":null},{"name":"market","value":"CN_FUTURE","type":"Literal","bound_global_parameter":null},{"name":"instrument_list","value":"RB1901.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 # 设置手续费,买入时万3,卖出是千分之1.3,不足5元以5元计\n context.set_commission(futures_commission=PerContract(cost={'RB':(0.000045, 0.000045, 0.000045)}))\n context.set_margin('RB', 0.07)\n context.index = 1 #日期记录\n context.window = 60","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":"#平仓\ndef close_orders(context,data):\n #获取当前时间\n cur_date = data.current_dt.strftime('%Y-%m-%d')\n\n for ins in context.instruments:\n # 分别获取多头持仓和空头持仓\n position_long = context.get_position(ins, Direction.LONG)\n position_short = context.get_position(ins, Direction.SHORT)\n price = data.current(ins,\"close\")\n if(position_long.current_qty != 0):\n context.sell_close(ins, position_long.avail_qty, price, order_type=OrderType.MARKET)\n\n if(position_short.current_qty != 0):\n context.buy_close(ins, position_short.avail_qty, price, order_type=OrderType.MARKET)\n \ndef order_target(context,data,instrument,lots,price,order_type_ = OrderType.MARKET):\n #获取多空持仓情况\n position_long = context.get_position(instrument, Direction.LONG)\n position_short = context.get_position(instrument, Direction.SHORT)\n # ------------------------------------------------------\n if lots > 0:\n if position_long.avail_qty > 0:\n if position_long.avail_qty > lots:\n context.sell_close(instrument, position_long.avail_qty - lots, price, order_type=order_type_) \n elif position_long.avail_qty < lots:\n context.buy_open(instrument, lots - position_long.avail_qty, price, order_type=order_type_)\n elif position_short.avail_qty > 0:\n context.buy_close(instrument, position_short.avail_qty, price, order_type=order_type_)\n context.buy_open(instrument, lots, price, order_type=order_type_)\n elif (position_long.avail_qty + position_short.avail_qty) == 0:\n context.buy_open(instrument, lots, price, order_type=order_type_)\n elif lots < 0:\n if position_long.avail_qty > 0:\n context.sell_close(instrument, position_long.avail_qty, price, order_type=order_type_)\n context.sell_open(instrument, abs(lots), price, order_type=order_type_)\n elif position_short.avail_qty > 0:\n if position_short.avail_qty > abs(lots):\n context.buy_close(instrument, position_short.avail_qty - abs(lots) , price, order_type=order_type_)\n elif position_short.avail_qty < abs(lots):\n context.sell_open(instrument, abs(lots) - position_short.avail_qty, price, order_type=order_type_)\n elif (position_long.avail_qty + position_short.avail_qty) == 0:\n context.sell_open(instrument, abs(lots), price, order_type=order_type_) \n elif lots == 0:\n if(position_long.current_qty != 0):\n context.sell_close(instrument, position_long.avail_qty, price, order_type=order_type_)\n\n if(position_short.current_qty != 0):\n context.buy_close(instrument, position_short.avail_qty, price, order_type=order_type_)\n# 交易引擎:bar数据处理函数,每个时间单位执行一次\ndef bigquant_run(context, data):\n import talib as ta\n today = data.current_dt#.strftime('%Y-%m-%d-%H-%M')\n if context.index < context.window: # 在形成均线后才开始交易\n context.index+=1\n return\n if today.hour > 15:\n return\n instrument = context.future_symbol(context.instruments[0]) # 交易标的\n curr_position = context.portfolio.positions[instrument].amount # 持仓数量\n prices = data.history(instrument, 'close', context.window, '1m') # 历史价格\n\n if np.any(np.isnan(prices)):\n return\n n=40\n kama = ta.KAMA(prices, timeperiod=n)\n ft = 0.8*np.std((kama-kama.shift(1))[-n:])\n \n if kama[-1] - np.min(kama[-n:]) > ft:\n order_target(context,data,instrument = context.instruments[0] ,lots = 2,price = prices[-1],order_type_ = OrderType.MARKET)\n if np.max(kama[-n:]) - kama[-1] > ft:\n order_target(context,data,instrument = context.instruments[0],lots = -2,price = prices[-1],order_type_ = OrderType.MARKET)\n","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":"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='23.25421142578125,234,200,200'/></node_postions>"},"nodes_readonly":false,"studio_version":"v2"}
    In [4]:
    # 本代码由可视化策略环境自动生成 2021年12月10日 15:38
    # 本代码单元只能在可视化模式下编辑。您也可以拷贝代码,粘贴到新建的代码单元或者策略,然后修改。
    
    
    # 交易引擎:初始化函数,只执行一次
    def m2_initialize_bigquant_run(context):
        # 加载预测数据
         # 设置手续费,买入时万3,卖出是千分之1.3,不足5元以5元计
        context.set_commission(futures_commission=PerContract(cost={'RB':(0.000045, 0.000045, 0.000045)}))
        context.set_margin('RB', 0.07)
        context.index = 1              #日期记录
        context.window = 60
    # 交易引擎:每个单位时间开盘前调用一次。
    def m2_before_trading_start_bigquant_run(context, data):
        pass
    
    # 交易引擎:tick数据处理函数,每个tick执行一次
    def m2_handle_tick_bigquant_run(context, data):
        pass
    
    #平仓
    def close_orders(context,data):
        #获取当前时间
        cur_date = data.current_dt.strftime('%Y-%m-%d')
    
        for ins in context.instruments:
            # 分别获取多头持仓和空头持仓
            position_long = context.get_position(ins, Direction.LONG)
            position_short = context.get_position(ins, Direction.SHORT)
            price = data.current(ins,"close")
            if(position_long.current_qty != 0):
                context.sell_close(ins, position_long.avail_qty, price, order_type=OrderType.MARKET)
    
            if(position_short.current_qty != 0):
                context.buy_close(ins, position_short.avail_qty, price, order_type=OrderType.MARKET)
                 
    def order_target(context,data,instrument,lots,price,order_type_ = OrderType.MARKET):
        #获取多空持仓情况
        position_long = context.get_position(instrument, Direction.LONG)
        position_short = context.get_position(instrument, Direction.SHORT)
        #          ------------------------------------------------------
        if lots > 0:
            if position_long.avail_qty > 0:
                if position_long.avail_qty  > lots:
                    context.sell_close(instrument, position_long.avail_qty - lots, price, order_type=order_type_)            
                elif position_long.avail_qty  < lots:
                    context.buy_open(instrument, lots - position_long.avail_qty, price, order_type=order_type_)
            elif position_short.avail_qty  > 0:
                context.buy_close(instrument, position_short.avail_qty, price, order_type=order_type_)
                context.buy_open(instrument, lots, price, order_type=order_type_)
            elif (position_long.avail_qty + position_short.avail_qty) == 0:
                context.buy_open(instrument, lots, price, order_type=order_type_)
        elif lots < 0:
            if position_long.avail_qty > 0:
                context.sell_close(instrument, position_long.avail_qty, price, order_type=order_type_)
                context.sell_open(instrument, abs(lots), price, order_type=order_type_)
            elif position_short.avail_qty  > 0:
                if position_short.avail_qty  > abs(lots):
                    context.buy_close(instrument, position_short.avail_qty - abs(lots) , price, order_type=order_type_)
                elif position_short.avail_qty  < abs(lots):
                    context.sell_open(instrument, abs(lots) - position_short.avail_qty, price, order_type=order_type_)
            elif (position_long.avail_qty + position_short.avail_qty) == 0:
                context.sell_open(instrument, abs(lots), price, order_type=order_type_) 
        elif lots == 0:
            if(position_long.current_qty != 0):
                context.sell_close(instrument, position_long.avail_qty, price, order_type=order_type_)
    
            if(position_short.current_qty != 0):
                context.buy_close(instrument, position_short.avail_qty, price, order_type=order_type_)
    # 交易引擎:bar数据处理函数,每个时间单位执行一次
    def m2_handle_data_bigquant_run(context, data):
        import talib as ta
        today = data.current_dt#.strftime('%Y-%m-%d-%H-%M')
        if context.index < context.window: # 在形成均线后才开始交易
            context.index+=1
            return
        if today.hour > 15:
            return
        instrument = context.future_symbol(context.instruments[0]) # 交易标的
        curr_position = context.portfolio.positions[instrument].amount # 持仓数量
        prices = data.history(instrument, 'close', context.window, '1m') # 历史价格
    
        if np.any(np.isnan(prices)):
            return
        n=40
        kama = ta.KAMA(prices, timeperiod=n)
        ft = 0.8*np.std((kama-kama.shift(1))[-n:])
        
        if kama[-1] - np.min(kama[-n:]) > ft:
            order_target(context,data,instrument = context.instruments[0] ,lots = 2,price = prices[-1],order_type_ = OrderType.MARKET)
        if np.max(kama[-n:]) - kama[-1] > ft:
            order_target(context,data,instrument = context.instruments[0],lots = -2,price = prices[-1],order_type_ = OrderType.MARKET)
    
    # 交易引擎:成交回报处理函数,每个成交发生时执行一次
    def m2_handle_trade_bigquant_run(context, data):
        pass
    
    # 交易引擎:委托回报处理函数,每个委托变化时执行一次
    def m2_handle_order_bigquant_run(context, data):
        pass
    
    # 交易引擎:盘后处理函数,每日盘后执行一次
    def m2_after_trading_bigquant_run(context, data):
        pass
    
    
    m1 = M.instruments.v2(
        start_date='2018-04-20',
        end_date='2018-05-30',
        market='CN_FUTURE',
        instrument_list='RB1901.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=1000000,
        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
    )
    
    • 收益率-1.41%
    • 年化收益率-12.4%
    • 基准收益率-1.0%
    • 阿尔法-0.15
    • 贝塔0.01
    • 夏普比率-17.15
    • 胜率0.18
    • 盈亏比0.96
    • 收益波动率0.94%
    • 最大回撤1.41%
    bigcharts-data-start/{"__type":"tabs","__id":"bigchart-66f9e863aebc4c61bfde9ede69cfed4f"}/bigcharts-data-end