克隆策略

择时策略——MACD指标 v1.0

版本 v1.0

目录

交易规则

策略构建步骤

策略的实现

正文

一、交易规则

  • 利用收盘价的短期(常用为12日)指数移动平均线与长期(常用为26日)指数移动平均线之间的聚合与分离状况,对买进、卖出时机作出研判的技术指标。
  • 短期EMA: 短期(例如12日)的收盘价指数移动平均值
  • 长期EMA: 长期(例如26日)的收盘价指数移动平均值
  • DIF线:(Difference)短期EMA和长期EMA的离差值
  • MACD线: DIF线与DEA线的差
  • 参数:SHORT(短期)、LONG(长期)、M天数,一般为12、26、9。

二、策略构建步骤

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

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

2、确定买卖原则

  • DIF从下而上穿过DEA,买入开仓;相反,如DIF从上往下穿过DEA,卖出开仓。

3、回测

  • 通过 trade 模块中的初始化函数定义交易手续费和滑点;
  • 通过 trade 模块中的主函数(handle函数)查看每日的买卖交易信号,按照买卖原则执行相应的买入/卖出/调仓操作。

三、策略的实现

可视化策略实现如下:

    {"description":"实验创建于9/13/2021","graph":{"edges":[{"to_node_id":"-1659:instruments","from_node_id":"-1681:data"},{"to_node_id":"-39:instruments","from_node_id":"-1681:data"},{"to_node_id":"-1659:options_data","from_node_id":"-39:data"}],"nodes":[{"node_id":"-1659","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":"def bigquant_run(context):\n import talib\n all_data = context.options[\"data\"].read()\n all_data['DIF'],all_data['DEA'],all_data['macd']=talib.MACD(all_data['settle'], fastperiod=12, slowperiod=26, signalperiod=9)\n \n \n context.signal_data = all_data\n context.order_num = 1\n context.PRINT = 1\n \n ","type":"Literal","bound_global_parameter":null},{"name":"before_trading_start","value":"# 交易引擎:每个单位时间开盘前调用一次。\ndef bigquant_run(context, data):\n # 订阅要交易的合约的行情\n context.subscribe([context.instruments[0]])","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 #获取当前时间\n cur_date = data.current_dt.strftime('%Y-%m-%d')\n \n all_data = context.signal_data\n cur_data = all_data[all_data['date'] == cur_date]\n DIF = cur_data['DIF'].values[0]\n DEA = cur_data['DEA'].values[0]\n context.ins = context.instruments[0]\n \n #print('=======', cur_date, close, ma_close, context.ins)\n position_long = context.get_position(context.ins, Direction.LONG)\n position_short = context.get_position(context.ins, Direction.SHORT)\n \n # 空头\n if position_long.current_qty != -1 and DIF < DEA:\n #平多\n if position_long.current_qty == 1:\n rv = context.sell_close(context.ins, context.order_num, None, order_type=OrderType.MARKET)\n msg = \"{} 平多 for {} 下单函数返回={}\".format(str(data.current_dt), context.ins, str(rv))\n context.write_log(msg, stdout=1) \n # 开空\n if position_short.current_qty == 0:\n rv = context.sell_open(context.ins, context.order_num, None, order_type=OrderType.MARKET)\n msg = \"{} 开空 for {} 下单函数返回={}\".format(str(data.current_dt), context.ins, str(rv))\n context.write_log(msg, stdout=1) \n \n # 多头\n if (position_long.current_qty != 1) and DIF > DEA:\n # 平空\n if position_short.current_qty == 1 :\n rv = context.buy_close(context.ins, context.order_num, None, order_type=OrderType.MARKET)\n msg = \"{} 平空 for {} 下单函数返回={}\".format(str(data.current_dt), context.ins, str(rv))\n context.write_log(msg, stdout=1) \n # 开多\n if position_long.current_qty == 0:\n rv = context.buy_open(context.ins, context.order_num, None, order_type=OrderType.MARKET)\n msg = \"{} 开多 for {} 下单函数返回={}\".format(str(data.current_dt), context.ins, str(rv))\n context.write_log(msg, stdout=1) \n \n\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":"50000","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":"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":"-1659"},{"name":"history_ds","node_id":"-1659"},{"name":"benchmark_ds","node_id":"-1659"},{"name":"options_data","node_id":"-1659"}],"output_ports":[{"name":"raw_perf","node_id":"-1659"}],"cacheable":false,"seq_num":1,"comment":"","comment_collapsed":true},{"node_id":"-1681","module_id":"BigQuantSpace.instruments.instruments-v2","parameters":[{"name":"start_date","value":"2021-05-01","type":"Literal","bound_global_parameter":null},{"name":"end_date","value":"2021-09-20","type":"Literal","bound_global_parameter":null},{"name":"market","value":"CN_FUTURE","type":"Literal","bound_global_parameter":null},{"name":"instrument_list","value":"SF8888.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":"-1681"}],"output_ports":[{"name":"data","node_id":"-1681"}],"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":"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":"-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='-1659' Position='530,280,200,200'/><node_position Node='-1681' Position='404,10,200,200'/><node_position Node='-39' Position='533,120,200,200'/></node_postions>"},"nodes_readonly":false,"studio_version":"v2"}
    In [10]:
    # 本代码由可视化策略环境自动生成 2021年12月3日 19:10
    # 本代码单元只能在可视化模式下编辑。您也可以拷贝代码,粘贴到新建的代码单元或者策略,然后修改。
    
    
    def m1_initialize_bigquant_run(context):
        import talib
        all_data = context.options["data"].read()
        all_data['DIF'],all_data['DEA'],all_data['macd']=talib.MACD(all_data['settle'], fastperiod=12, slowperiod=26, signalperiod=9)
        
        
        context.signal_data =  all_data
        context.order_num = 1
        context.PRINT = 1
        
        
    # 交易引擎:每个单位时间开盘前调用一次。
    def m1_before_trading_start_bigquant_run(context, data):
        # 订阅要交易的合约的行情
        context.subscribe([context.instruments[0]])
    # 交易引擎:tick数据处理函数,每个tick执行一次
    def m1_handle_tick_bigquant_run(context, data):
        pass
    
    def m1_handle_data_bigquant_run(context, data):
        #获取当前时间
        cur_date = data.current_dt.strftime('%Y-%m-%d')
         
        all_data  = context.signal_data
        cur_data = all_data[all_data['date'] == cur_date]
        DIF = cur_data['DIF'].values[0]
        DEA = cur_data['DEA'].values[0]
        context.ins = context.instruments[0]
        
        #print('=======', cur_date, close, ma_close, context.ins)
        position_long = context.get_position(context.ins, Direction.LONG)
        position_short = context.get_position(context.ins, Direction.SHORT)
           
         # 空头
        if position_long.current_qty != -1 and DIF < DEA:
            #平多
            if position_long.current_qty == 1:
                rv = context.sell_close(context.ins, context.order_num, None, order_type=OrderType.MARKET)
                msg = "{} 平多 for {} 下单函数返回={}".format(str(data.current_dt), context.ins, str(rv))
                context.write_log(msg, stdout=1) 
            # 开空
            if position_short.current_qty == 0:
                rv = context.sell_open(context.ins, context.order_num, None, order_type=OrderType.MARKET)
                msg = "{} 开空 for {} 下单函数返回={}".format(str(data.current_dt), context.ins, str(rv))
                context.write_log(msg, stdout=1) 
           
        # 多头
        if (position_long.current_qty != 1) and DIF > DEA:
            # 平空
            if position_short.current_qty == 1 :
                rv = context.buy_close(context.ins, context.order_num, None, order_type=OrderType.MARKET)
                msg = "{} 平空 for {} 下单函数返回={}".format(str(data.current_dt), context.ins, str(rv))
                context.write_log(msg, stdout=1) 
            # 开多
            if position_long.current_qty == 0:
                rv = context.buy_open(context.ins, context.order_num, None, order_type=OrderType.MARKET)
                msg = "{} 开多 for {} 下单函数返回={}".format(str(data.current_dt), context.ins, str(rv))
                context.write_log(msg, stdout=1) 
       
    
     
    # 交易引擎:成交回报处理函数,每个成交发生时执行一次
    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-05-01',
        end_date='2021-09-20',
        market='CN_FUTURE',
        instrument_list='SF8888.CZC',
        max_count=0
    )
    
    m3 = M.use_datasource.v1(
        instruments=m2.data,
        datasource_id='bar1d_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=50000,
        frequency='daily',
        price_type='真实价格',
        product_type='期货',
        before_start_days='0',
        benchmark='000300.HIX',
        plot_charts=True,
        disable_cache=False,
        show_debug_info=False,
        backtest_only=False
    )
    
    2021-11-30 21:00:19.557561 strategy_20211130(bkt999,): 2021-06-23 15:00:00 开空 for SF8888.CZC 下单函数返回=0 
    2021-11-30 21:00:19.573615 strategy_20211130(bkt999,): handle_order data:[bkt999,1,SF8888.CZC,short,open,0,1,8190.0,pending,20210624 08:30:00,1,strategy_20211130] 
    2021-11-30 21:00:19.579850 strategy_20211130(bkt999,): handle_order data:[bkt999,1,SF8888.CZC,short,open,1,1,8190.0,filled,20210624 08:30:00,1,strategy_20211130] 
    2021-11-30 21:00:19.580710 strategy_20211130(bkt999,): handle_trade data:[bkt999,1,SF8888.CZC,short,open,1,8210.0,1,20210624 08:55:00.000000,strategy_20211130] 
    2021-11-30 21:00:19.797868 strategy_20211130(bkt999,): 2021-07-14 15:00:00 平空 for SF8888.CZC 下单函数返回=0 
    2021-11-30 21:00:19.799199 strategy_20211130(bkt999,): 2021-07-14 15:00:00 开多 for SF8888.CZC 下单函数返回=0 
    2021-11-30 21:00:19.809602 strategy_20211130(bkt999,): handle_order data:[bkt999,2,SF8888.CZC,long,close,0,1,8502.0,pending,20210715 08:30:00,2,strategy_20211130] 
    2021-11-30 21:00:19.813814 strategy_20211130(bkt999,): handle_order data:[bkt999,2,SF8888.CZC,long,close,1,1,8502.0,filled,20210715 08:30:00,2,strategy_20211130] 
    2021-11-30 21:00:19.814340 strategy_20211130(bkt999,): handle_trade data:[bkt999,2,SF8888.CZC,long,close,1,8460.0,2,20210715 08:55:00.000000,strategy_20211130] 
    2021-11-30 21:00:19.817795 strategy_20211130(bkt999,): 2021-07-15 15:00:00 开多 for SF8888.CZC 下单函数返回=0 
    2021-11-30 21:00:19.858569 strategy_20211130(bkt999,): handle_order data:[bkt999,3,SF8888.CZC,long,open,0,1,8502.0,pending,20210716 08:30:00,3,strategy_20211130] 
    2021-11-30 21:00:19.862835 strategy_20211130(bkt999,): handle_order data:[bkt999,3,SF8888.CZC,long,open,1,1,8502.0,filled,20210716 08:30:00,3,strategy_20211130] 
    2021-11-30 21:00:19.863984 strategy_20211130(bkt999,): handle_trade data:[bkt999,3,SF8888.CZC,long,open,1,8658.0,3,20210716 08:55:00.000000,strategy_20211130] 
    2021-11-30 21:00:19.876918 strategy_20211130(bkt999,): handle_order data:[bkt999,4,SF8888.CZC,long,open,0,1,8640.0,pending,20210719 08:30:00,4,strategy_20211130] 
    2021-11-30 21:00:19.880407 strategy_20211130(bkt999,): handle_order data:[bkt999,4,SF8888.CZC,long,open,1,1,8640.0,filled,20210719 08:30:00,4,strategy_20211130] 
    2021-11-30 21:00:19.881120 strategy_20211130(bkt999,): handle_trade data:[bkt999,4,SF8888.CZC,long,open,1,8860.0,4,20210719 08:55:00.000000,strategy_20211130] 
    2021-11-30 21:00:20.214970 strategy_20211130(bkt999,): 2021-08-17 15:00:00 开空 for SF8888.CZC 下单函数返回=0 
    2021-11-30 21:00:20.250306 strategy_20211130(bkt999,): handle_order data:[bkt999,5,SF8888.CZC,short,open,0,1,9048.0,pending,20210818 08:30:00,5,strategy_20211130] 
    2021-11-30 21:00:20.255382 strategy_20211130(bkt999,): handle_order data:[bkt999,5,SF8888.CZC,short,open,1,1,9048.0,filled,20210818 08:30:00,5,strategy_20211130] 
    2021-11-30 21:00:20.256223 strategy_20211130(bkt999,): handle_trade data:[bkt999,5,SF8888.CZC,short,open,1,9050.0,5,20210818 08:55:00.000000,strategy_20211130] 
    2021-11-30 21:00:20.295126 strategy_20211130(bkt999,): 2021-08-20 15:00:00 平空 for SF8888.CZC 下单函数返回=0 
    2021-11-30 21:00:20.306481 strategy_20211130(bkt999,): handle_order data:[bkt999,6,SF8888.CZC,long,close,0,1,9494.0,pending,20210823 08:30:00,6,strategy_20211130] 
    2021-11-30 21:00:20.310002 strategy_20211130(bkt999,): handle_order data:[bkt999,6,SF8888.CZC,long,close,1,1,9494.0,filled,20210823 08:30:00,6,strategy_20211130] 
    2021-11-30 21:00:20.310993 strategy_20211130(bkt999,): handle_trade data:[bkt999,6,SF8888.CZC,long,close,1,9376.0,6,20210823 08:55:00.000000,strategy_20211130] 
    
    • 收益率62.84%
    • 年化收益率259.62%
    • 基准收益率-4.05%
    • 阿尔法2.6
    • 贝塔-0.19
    • 夏普比率3.7
    • 胜率0.0
    • 盈亏比0.0
    • 收益波动率35.59%
    • 最大回撤10.59%
    bigcharts-data-start/{"__type":"tabs","__id":"bigchart-94e990b177f9426a957a8b4866cd7097"}/bigcharts-data-end