获取连续下跌股票策略

策略分享
标签: #<Tag:0x00007f728302b2d0>

(njchenxin) #1

克隆策略
In [ ]:
# 1. 策略基本参数
#抓取数据
df=D.history_data(D.instruments(),start_date='2015-01-01', end_date='2017-05-05', fields=['open', 'high', 'low', 'close'])
df.set_index('date', inplace=True)

# 回测起始时间
start_date = '2015-01-01'
# 回测结束时间
end_date = '2017-05-05'
# 策略比较参考标准,以沪深300为例
benchmark = '000300.INDX'
# 证券池 以贵州茅台为例
instruments =  D.instruments()
# 起始资金
capital_base = 100000

def resample(df):
# https://pandas-docs.github.io/pandas-docs-travis/timeseries.html#offset-aliases
# 周 W、月 M、季度 Q、10天 10D、2周 2W
    period = 'Q'

    year_df = df.resample(period, how='last')
    year_df['open'] = df['open'].resample(period, how='first')
    year_df['high'] = df['high'].resample(period, how='max')
    year_df['low'] = df['low'].resample(period, how='min')
    year_df['close'] = df['close'].resample(period, how='last')
    # 去除空的数据(没有交易的周)
    year_df = year_df[year_df.instrument.notnull()]
    year_df.reset_index(inplace=True)
    return year_df


def seek_stock(df):
    df['pre_open'] = df['open'].shift()
    df['condi_0'] = df['high'] < df['pre_open']
    df['condi_1'] = df['condi_0'].shift(1)
    df['condi_2'] = df['condi_0'].shift(2)
    df['condi_3'] = df['condi_0'].shift(3)
    df['condi_4'] = df['condi_0'].shift(4)
    return df[(df['condi_0'] == True) & (df['condi_1'] == True) & (df['condi_2'] == True) &(df['condi_3'] == True) &(df['condi_4'] == True)]



# 2. 策略主体函数
def initialize(context):
    
    # 设置手续费,买入时万3,卖出是千分之1.3,不足5元以5元计
    context.set_commission(PerOrder(buy_cost=0.0003, sell_cost=0.0013, min_cost=5))
    context.hold_periods = 40 # 持有40天,固定持仓期
    context.stock_max_num = 10 # 最大持仓数量
    context.hold_days = {}
    

# 策略交易逻辑,每个交易日运行一次
def handle_data(context, data):
 
    #筛选股票列表
    year_df = df.groupby('instrument').apply(resample)
    year_df = year_df.reset_index(drop=True, inplace=True)
    stock_seeked = year_df.groupby('instrument').apply(seek_stock)
    stock_seeked = stock_seeked.reset_index(drop=True, inplace=True)
    context.daily_buy_stock = list(stock_seeked['instrument'])

    #买股列表
    stock_can_buy_num = context.stock_max_num 
    stock_to_buy = context.daily_buy_stock
    
    weight =  1 / len(stock_to_buy)

    for stock in stock_to_buy:
        if data.can_trade(context.symbol(stock)):
            curr_position =  context.portfolio.positions['instrument'].amount
            if curr_position == 0:
                # 买入10W股票
                context.order_target_percent(context.symbol(stock), weight)
        

# 3. 启动回测

# 策略回测接口: https://bigquant.com/docs/strategy_backtest.html
m = M.backtest.v5(
    instruments=instruments,
    start_date=start_date,
    end_date=end_date,
    initialize=initialize,
    handle_data=handle_data,
    # 买入订单以开盘价成交
    order_price_field_buy='open',
    # 卖出订单以开盘价成交
    order_price_field_sell='open',
    capital_base=capital_base,
    benchmark=benchmark,
)
[2017-05-10 18:43:25.579287] INFO: bigquant: backtest.v5 start ..
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-1-dea12fbcba43> in <module>()
     90     order_price_field_sell='open',
     91     capital_base=capital_base,
---> 92     benchmark=benchmark,
     93 )

<ipython-input-1-dea12fbcba43> in handle_data(context, data)
     58     year_df = df.groupby('instrument').apply(resample)
     59     year_df = year_df.reset_index(drop=True, inplace=True)
---> 60     stock_seeked = year_df.groupby('instrument').apply(seek_stock)
     61     stock_seeked = stock_seeked.reset_index(drop=True, inplace=True)
     62     context.daily_buy_stock = list(stock_seeked['instrument'])

AttributeError: 'NoneType' object has no attribute 'groupby'

报错:AttributeError: 'NoneType' object has no attribute 'groupby'
仔细想想我的逻辑没出 错,哪位大神能帮忙看看

(小Q) #2

矩形标记的地方有问题。

这两句代码参数传入有问题 ,year_df = year_df.reset_index(drop=True) 等价于 year_df.reset_index(drop=True, inplace=True)

inplace=True的含义是就地修改变量的意思,如果加了这个参数,就不用再绑定到year_df上了。


(njchenxin) #3

谢谢哦!!!


(smallsnow) #4

那么该如何修改呢,才能不出错


(iQuant) #5

稍等,稍后我们给您一个可视化样例。


(iQuant) #6
克隆策略

    {"Description":"实验创建于2017/8/26","Summary":"","Graph":{"EdgesInternal":[{"DestinationInputPortId":"-265:instruments","SourceOutputPortId":"287d2cb0-f53c-4101-bdf8-104b137c8601-8:data"},{"DestinationInputPortId":"-323:instruments","SourceOutputPortId":"287d2cb0-f53c-4101-bdf8-104b137c8601-8:data"},{"DestinationInputPortId":"-279:input_1","SourceOutputPortId":"-265:data"},{"DestinationInputPortId":"-265:features","SourceOutputPortId":"-271:data"},{"DestinationInputPortId":"-288:input_data","SourceOutputPortId":"-279:data_1"},{"DestinationInputPortId":"-301:input_data","SourceOutputPortId":"-288:data"},{"DestinationInputPortId":"-288:features","SourceOutputPortId":"-296:data"},{"DestinationInputPortId":"-314:input_data","SourceOutputPortId":"-301:data"},{"DestinationInputPortId":"-301:features","SourceOutputPortId":"-309:data"},{"DestinationInputPortId":"-323:options_data","SourceOutputPortId":"-314:data"}],"ModuleNodes":[{"Id":"287d2cb0-f53c-4101-bdf8-104b137c8601-8","ModuleId":"BigQuantSpace.instruments.instruments-v2","ModuleParameters":[{"Name":"start_date","Value":"2015-01-01","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"end_date","Value":"2017-05-05","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"market","Value":"CN_STOCK_A","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"instrument_list","Value":"","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"max_count","Value":"0","ValueType":"Literal","LinkedGlobalParameter":null}],"InputPortsInternal":[{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"rolling_conf","NodeId":"287d2cb0-f53c-4101-bdf8-104b137c8601-8"}],"OutputPortsInternal":[{"Name":"data","NodeId":"287d2cb0-f53c-4101-bdf8-104b137c8601-8","OutputType":null}],"UsePreviousResults":true,"moduleIdForCode":1,"Comment":"","CommentCollapsed":true},{"Id":"-265","ModuleId":"BigQuantSpace.use_datasource.use_datasource-v1","ModuleParameters":[{"Name":"datasource_id","Value":"bar1d_CN_STOCK_A","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"start_date","Value":"","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"end_date","Value":"","ValueType":"Literal","LinkedGlobalParameter":null}],"InputPortsInternal":[{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"instruments","NodeId":"-265"},{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"features","NodeId":"-265"}],"OutputPortsInternal":[{"Name":"data","NodeId":"-265","OutputType":null}],"UsePreviousResults":true,"moduleIdForCode":2,"Comment":"","CommentCollapsed":true},{"Id":"-271","ModuleId":"BigQuantSpace.input_features.input_features-v1","ModuleParameters":[{"Name":"features","Value":"\n# #号开始的表示注释,注释需单独一行\n# 多个特征,每行一个,可以包含基础特征和衍生特征,特征须为本平台特征\nopen\nhigh\nlow\nclose\n","ValueType":"Literal","LinkedGlobalParameter":null}],"InputPortsInternal":[{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"features_ds","NodeId":"-271"}],"OutputPortsInternal":[{"Name":"data","NodeId":"-271","OutputType":null}],"UsePreviousResults":true,"moduleIdForCode":3,"Comment":"","CommentCollapsed":true},{"Id":"-279","ModuleId":"BigQuantSpace.cached.cached-v3","ModuleParameters":[{"Name":"run","Value":"# Python 代码入口函数,input_1/2/3 对应三个输入端,data_1/2/3 对应三个输出端\ndef bigquant_run(input_1, input_2, input_3):\n # 示例代码如下。在这里编写您的代码\n df_input = input_1.read_df()\n \n def resample(df):\n # https://pandas-docs.github.io/pandas-docs-travis/timeseries.html#offset-aliases\n # 周 W、月 M、季度 Q、10天 10D、2周 2W\n period = 'Q'\n resample_df = df.set_index('date').resample(period, how='last')\n resample_df['open'] = resample_df['open'].resample(period, how='first')\n resample_df['high'] = resample_df['high'].resample(period, how='max')\n resample_df['low'] = resample_df['low'].resample(period, how='min')\n resample_df['close'] = resample_df['close'].resample(period, how='last')\n # 去除空的数据(没有交易的周)\n resample_df = resample_df[resample_df.instrument.notnull()]\n resample_df.reset_index(inplace=True)\n return resample_df\n \n resample_df = df_input.groupby('instrument').apply(lambda df:resample(df))\n data_1 = DataSource.write_df(resample_df.reset_index(drop=True))\n return Outputs(data_1=data_1, data_2=None, data_3=None)\n","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"post_run","Value":"# 后处理函数,可选。输入是主函数的输出,可以在这里对数据做处理,或者返回更友好的outputs数据格式。此函数输出不会被缓存。\ndef bigquant_run(outputs):\n return outputs\n","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"input_ports","Value":"","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"params","Value":"{}","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"output_ports","Value":"","ValueType":"Literal","LinkedGlobalParameter":null}],"InputPortsInternal":[{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"input_1","NodeId":"-279"},{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"input_2","NodeId":"-279"},{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"input_3","NodeId":"-279"}],"OutputPortsInternal":[{"Name":"data_1","NodeId":"-279","OutputType":null},{"Name":"data_2","NodeId":"-279","OutputType":null},{"Name":"data_3","NodeId":"-279","OutputType":null}],"UsePreviousResults":true,"moduleIdForCode":6,"Comment":"","CommentCollapsed":true},{"Id":"-288","ModuleId":"BigQuantSpace.derived_feature_extractor.derived_feature_extractor-v3","ModuleParameters":[{"Name":"date_col","Value":"date","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"instrument_col","Value":"instrument","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"drop_na","Value":"False","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"remove_extra_columns","Value":"False","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"user_functions","Value":"{}","ValueType":"Literal","LinkedGlobalParameter":null}],"InputPortsInternal":[{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"input_data","NodeId":"-288"},{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"features","NodeId":"-288"}],"OutputPortsInternal":[{"Name":"data","NodeId":"-288","OutputType":null}],"UsePreviousResults":true,"moduleIdForCode":7,"Comment":"","CommentCollapsed":true},{"Id":"-296","ModuleId":"BigQuantSpace.input_features.input_features-v1","ModuleParameters":[{"Name":"features","Value":"\n# #号开始的表示注释,注释需单独一行\n# 多个特征,每行一个,可以包含基础特征和衍生特征,特征须为本平台特征\ncondi_0=where(high<shift(open, 1),1,0)\n","ValueType":"Literal","LinkedGlobalParameter":null}],"InputPortsInternal":[{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"features_ds","NodeId":"-296"}],"OutputPortsInternal":[{"Name":"data","NodeId":"-296","OutputType":null}],"UsePreviousResults":true,"moduleIdForCode":8,"Comment":"","CommentCollapsed":true},{"Id":"-301","ModuleId":"BigQuantSpace.derived_feature_extractor.derived_feature_extractor-v3","ModuleParameters":[{"Name":"date_col","Value":"date","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"instrument_col","Value":"instrument","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"drop_na","Value":"False","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"remove_extra_columns","Value":"False","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"user_functions","Value":"{}","ValueType":"Literal","LinkedGlobalParameter":null}],"InputPortsInternal":[{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"input_data","NodeId":"-301"},{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"features","NodeId":"-301"}],"OutputPortsInternal":[{"Name":"data","NodeId":"-301","OutputType":null}],"UsePreviousResults":true,"moduleIdForCode":9,"Comment":"","CommentCollapsed":true},{"Id":"-309","ModuleId":"BigQuantSpace.input_features.input_features-v1","ModuleParameters":[{"Name":"features","Value":"\n# #号开始的表示注释,注释需单独一行\n# 多个特征,每行一个,可以包含基础特征和衍生特征,特征须为本平台特征\ncond=(shift(condi_0, 1)>0)&(shift(condi_0, 2)>0)&(shift(condi_0, 3)>0)&(shift(condi_0, 4)>0)","ValueType":"Literal","LinkedGlobalParameter":null}],"InputPortsInternal":[{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"features_ds","NodeId":"-309"}],"OutputPortsInternal":[{"Name":"data","NodeId":"-309","OutputType":null}],"UsePreviousResults":true,"moduleIdForCode":13,"Comment":"","CommentCollapsed":true},{"Id":"-314","ModuleId":"BigQuantSpace.filter.filter-v3","ModuleParameters":[{"Name":"expr","Value":"cond==True","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"output_left_data","Value":"False","ValueType":"Literal","LinkedGlobalParameter":null}],"InputPortsInternal":[{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"input_data","NodeId":"-314"}],"OutputPortsInternal":[{"Name":"data","NodeId":"-314","OutputType":null},{"Name":"left_data","NodeId":"-314","OutputType":null}],"UsePreviousResults":true,"moduleIdForCode":14,"Comment":"","CommentCollapsed":true},{"Id":"-323","ModuleId":"BigQuantSpace.trade.trade-v4","ModuleParameters":[{"Name":"start_date","Value":"","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"end_date","Value":"","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"handle_data","Value":"# 回测引擎:每日数据处理函数,每天执行一次\ndef bigquant_run(context, data):\n date = data.current_dt.strftime('%Y-%m')\n \n # 如果本月已经执行过交易逻辑就返回不再执行\n if date == context.flag:\n return\n\n # 获取买股列表,前几个月可能没有数据\n try:\n stock_to_buy = context.stock_to_buy.ix[date]\n except:\n stock_to_buy = []\n\n # 获取当前持仓\n holds = {e:p for e,p in context.portfolio.positions.items()} \n \n # 卖出股票\n for stock in holds.keys():\n if data.can_trade(stock):\n context.order_target_percent(stock, 0)\n \n # 买入股票\n if stock_to_buy!=[]:\n # 如果日期满足条件就记录在全局变量中,防止本月再次买入 \n context.flag = date\n weight = 1 / len(stock_to_buy)\n for stock in stock_to_buy:\n if data.can_trade(context.symbol(stock)):\n curr_position = context.portfolio.positions['instrument'].amount\n if curr_position == 0:\n # 等比例买入股票\n context.order_target_percent(context.symbol(stock), weight)","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"prepare","Value":"# 回测引擎:准备数据,只执行一次\ndef bigquant_run(context):\n # 加载条件过滤后的数据\n results = context.options['data'].read_df()\n results['date'] = results['date'].apply(lambda x:x.strftime('%Y-%m')) \n \n def daily_buy_cal(df):\n return list(df.instrument)\n \n context.stock_to_buy = results.groupby('date').apply(daily_buy_cal)\n","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"initialize","Value":"# 回测引擎:初始化函数,只执行一次\ndef bigquant_run(context):\n\n # 设置手续费,买入时万3,卖出是千分之1.3,不足5元以5元计\n context.set_commission(PerOrder(buy_cost=0.0003, sell_cost=0.0013, min_cost=5))\n context.hold_periods = 40 # 持有40天,固定持仓期\n context.stock_max_num = 10 # 最大持仓数量\n context.hold_days = {} # 记录持仓天数\n context.flag = '' # 记录买入月份,以防止重复买入\n","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"before_trading_start","Value":"# 回测引擎:每个单位时间开始前调用一次,即每日开盘前调用一次。\ndef bigquant_run(context, data):\n pass\n","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"volume_limit","Value":0.025,"ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"order_price_field_buy","Value":"open","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"order_price_field_sell","Value":"close","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"capital_base","Value":1000000,"ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"auto_cancel_non_tradable_orders","Value":"True","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"data_frequency","Value":"daily","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"price_type","Value":"后复权","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"product_type","Value":"股票","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"plot_charts","Value":"True","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"backtest_only","Value":"False","ValueType":"Literal","LinkedGlobalParameter":null},{"Name":"benchmark","Value":"000300.HIX","ValueType":"Literal","LinkedGlobalParameter":null}],"InputPortsInternal":[{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"instruments","NodeId":"-323"},{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"options_data","NodeId":"-323"},{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"history_ds","NodeId":"-323"},{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"benchmark_ds","NodeId":"-323"},{"DataSourceId":null,"TrainedModelId":null,"TransformModuleId":null,"Name":"trading_calendar","NodeId":"-323"}],"OutputPortsInternal":[{"Name":"raw_perf","NodeId":"-323","OutputType":null}],"UsePreviousResults":false,"moduleIdForCode":15,"Comment":"","CommentCollapsed":true}],"SerializedClientData":"<?xml version='1.0' encoding='utf-16'?><DataV1 xmlns:xsd='http://www.w3.org/2001/XMLSchema' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'><Meta /><NodePositions><NodePosition Node='287d2cb0-f53c-4101-bdf8-104b137c8601-8' Position='72.28683471679688,17.762277603149414,200,200'/><NodePosition Node='-265' Position='254.63760375976562,145.31507873535156,200,200'/><NodePosition Node='-271' Position='457.75335693359375,17.560821533203125,200,200'/><NodePosition Node='-279' Position='267.8531188964844,267.5147399902344,200,200'/><NodePosition Node='-288' Position='366.93389892578125,381.457763671875,200,200'/><NodePosition Node='-296' Position='594.8198852539062,275.1709747314453,200,200'/><NodePosition Node='-301' Position='462.7120361328125,463.4245910644531,200,200'/><NodePosition Node='-309' Position='675.7358703613281,374.2518005371094,200,200'/><NodePosition Node='-314' Position='485.83099365234375,541.0379028320312,200,200'/><NodePosition Node='-323' Position='532.0686340332031,645.6732788085938,200,200'/></NodePositions><NodeGroups /></DataV1>"},"IsDraft":true,"ParentExperimentId":null,"WebService":{"IsWebServiceExperiment":false,"Inputs":[],"Outputs":[],"Parameters":[{"Name":"交易日期","Value":"","ParameterDefinition":{"Name":"交易日期","FriendlyName":"交易日期","DefaultValue":"","ParameterType":"String","HasDefaultValue":true,"IsOptional":true,"ParameterRules":[],"HasRules":false,"MarkupType":0,"CredentialDescriptor":null}}],"WebServiceGroupId":null,"SerializedClientData":"<?xml version='1.0' encoding='utf-16'?><DataV1 xmlns:xsd='http://www.w3.org/2001/XMLSchema' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'><Meta /><NodePositions></NodePositions><NodeGroups /></DataV1>"},"DisableNodesUpdate":false,"Category":"user","Tags":[],"IsPartialRun":true}
    In [60]:
    # 本代码由可视化策略环境自动生成 2019年1月29日 14:35
    # 本代码单元只能在可视化模式下编辑。您也可以拷贝代码,粘贴到新建的代码单元或者策略,然后修改。
    
    
    # Python 代码入口函数,input_1/2/3 对应三个输入端,data_1/2/3 对应三个输出端
    def m6_run_bigquant_run(input_1, input_2, input_3):
        # 示例代码如下。在这里编写您的代码
        df_input = input_1.read_df()
        
        def resample(df):
        # https://pandas-docs.github.io/pandas-docs-travis/timeseries.html#offset-aliases
        # 周 W、月 M、季度 Q、10天 10D、2周 2W
            period = 'Q'
            resample_df = df.set_index('date').resample(period, how='last')
            resample_df['open'] = resample_df['open'].resample(period, how='first')
            resample_df['high'] = resample_df['high'].resample(period, how='max')
            resample_df['low'] = resample_df['low'].resample(period, how='min')
            resample_df['close'] = resample_df['close'].resample(period, how='last')
            # 去除空的数据(没有交易的周)
            resample_df = resample_df[resample_df.instrument.notnull()]
            resample_df.reset_index(inplace=True)
            return resample_df
        
        resample_df = df_input.groupby('instrument').apply(lambda df:resample(df))
        data_1 = DataSource.write_df(resample_df.reset_index(drop=True))
        return Outputs(data_1=data_1, data_2=None, data_3=None)
    
    # 后处理函数,可选。输入是主函数的输出,可以在这里对数据做处理,或者返回更友好的outputs数据格式。此函数输出不会被缓存。
    def m6_post_run_bigquant_run(outputs):
        return outputs
    
    # 回测引擎:每日数据处理函数,每天执行一次
    def m15_handle_data_bigquant_run(context, data):
        date = data.current_dt.strftime('%Y-%m')
        
        # 如果本月已经执行过交易逻辑就返回不再执行
        if date == context.flag:
            return
    
        # 获取买股列表,前几个月可能没有数据
        try:
            stock_to_buy = context.stock_to_buy.ix[date]
        except:
            stock_to_buy = []
    
        # 获取当前持仓
        holds = {e:p for e,p in context.portfolio.positions.items()}   
        
        # 卖出股票
        for stock in holds.keys():
            if data.can_trade(stock):
                context.order_target_percent(stock, 0)
                
        # 买入股票
        if stock_to_buy!=[]:
            # 如果日期满足条件就记录在全局变量中,防止本月再次买入    
            context.flag = date
            weight =  1 / len(stock_to_buy)
            for stock in stock_to_buy:
                if data.can_trade(context.symbol(stock)):
                    curr_position =  context.portfolio.positions['instrument'].amount
                    if curr_position == 0:
                        # 等比例买入股票
                        context.order_target_percent(context.symbol(stock), weight)
    # 回测引擎:准备数据,只执行一次
    def m15_prepare_bigquant_run(context):
        # 加载条件过滤后的数据
        results = context.options['data'].read_df()
        results['date'] =  results['date'].apply(lambda x:x.strftime('%Y-%m'))   
        
        def daily_buy_cal(df):
            return list(df.instrument)
        
        context.stock_to_buy = results.groupby('date').apply(daily_buy_cal)
    
    # 回测引擎:初始化函数,只执行一次
    def m15_initialize_bigquant_run(context):
    
        # 设置手续费,买入时万3,卖出是千分之1.3,不足5元以5元计
        context.set_commission(PerOrder(buy_cost=0.0003, sell_cost=0.0013, min_cost=5))
        context.hold_periods = 40 # 持有40天,固定持仓期
        context.stock_max_num = 10 # 最大持仓数量
        context.hold_days = {} # 记录持仓天数
        context.flag = '' # 记录买入月份,以防止重复买入
    
    # 回测引擎:每个单位时间开始前调用一次,即每日开盘前调用一次。
    def m15_before_trading_start_bigquant_run(context, data):
        pass
    
    
    m1 = M.instruments.v2(
        start_date='2015-01-01',
        end_date='2017-05-05',
        market='CN_STOCK_A',
        instrument_list='',
        max_count=0
    )
    
    m3 = M.input_features.v1(
        features="""
    # #号开始的表示注释,注释需单独一行
    # 多个特征,每行一个,可以包含基础特征和衍生特征,特征须为本平台特征
    open
    high
    low
    close
    """
    )
    
    m2 = M.use_datasource.v1(
        instruments=m1.data,
        features=m3.data,
        datasource_id='bar1d_CN_STOCK_A',
        start_date='',
        end_date=''
    )
    
    m6 = M.cached.v3(
        input_1=m2.data,
        run=m6_run_bigquant_run,
        post_run=m6_post_run_bigquant_run,
        input_ports='',
        params='{}',
        output_ports=''
    )
    
    m8 = M.input_features.v1(
        features="""
    # #号开始的表示注释,注释需单独一行
    # 多个特征,每行一个,可以包含基础特征和衍生特征,特征须为本平台特征
    condi_0=where(high<shift(open, 1),1,0)
    """
    )
    
    m7 = M.derived_feature_extractor.v3(
        input_data=m6.data_1,
        features=m8.data,
        date_col='date',
        instrument_col='instrument',
        drop_na=False,
        remove_extra_columns=False,
        user_functions={}
    )
    
    m13 = M.input_features.v1(
        features="""
    # #号开始的表示注释,注释需单独一行
    # 多个特征,每行一个,可以包含基础特征和衍生特征,特征须为本平台特征
    cond=(shift(condi_0, 1)>0)&(shift(condi_0, 2)>0)&(shift(condi_0, 3)>0)&(shift(condi_0, 4)>0)"""
    )
    
    m9 = M.derived_feature_extractor.v3(
        input_data=m7.data,
        features=m13.data,
        date_col='date',
        instrument_col='instrument',
        drop_na=False,
        remove_extra_columns=False,
        user_functions={}
    )
    
    m14 = M.filter.v3(
        input_data=m9.data,
        expr='cond==True',
        output_left_data=False
    )
    
    m15 = M.trade.v4(
        instruments=m1.data,
        options_data=m14.data,
        start_date='',
        end_date='',
        handle_data=m15_handle_data_bigquant_run,
        prepare=m15_prepare_bigquant_run,
        initialize=m15_initialize_bigquant_run,
        before_trading_start=m15_before_trading_start_bigquant_run,
        volume_limit=0.025,
        order_price_field_buy='open',
        order_price_field_sell='close',
        capital_base=1000000,
        auto_cancel_non_tradable_orders=True,
        data_frequency='daily',
        price_type='后复权',
        product_type='股票',
        plot_charts=True,
        backtest_only=False,
        benchmark='000300.HIX'
    )
    
    [2019-01-29 14:32:56.170951] INFO: bigquant: instruments.v2 开始运行..
    [2019-01-29 14:32:56.176387] INFO: bigquant: 命中缓存
    [2019-01-29 14:32:56.177373] INFO: bigquant: instruments.v2 运行完成[0.006441s].
    [2019-01-29 14:32:56.179983] INFO: bigquant: input_features.v1 开始运行..
    [2019-01-29 14:32:56.184234] INFO: bigquant: 命中缓存
    [2019-01-29 14:32:56.185268] INFO: bigquant: input_features.v1 运行完成[0.005271s].
    [2019-01-29 14:32:56.187291] INFO: bigquant: use_datasource.v1 开始运行..
    [2019-01-29 14:32:56.191356] INFO: bigquant: 命中缓存
    [2019-01-29 14:32:56.192317] INFO: bigquant: use_datasource.v1 运行完成[0.00501s].
    [2019-01-29 14:32:56.196620] INFO: bigquant: cached.v3 开始运行..
    [2019-01-29 14:32:56.209344] INFO: bigquant: 命中缓存
    [2019-01-29 14:32:56.210412] INFO: bigquant: cached.v3 运行完成[0.013787s].
    [2019-01-29 14:32:56.212342] INFO: bigquant: input_features.v1 开始运行..
    [2019-01-29 14:32:56.216494] INFO: bigquant: 命中缓存
    [2019-01-29 14:32:56.217321] INFO: bigquant: input_features.v1 运行完成[0.004964s].
    [2019-01-29 14:32:56.219448] INFO: bigquant: derived_feature_extractor.v3 开始运行..
    [2019-01-29 14:32:56.223166] INFO: bigquant: 命中缓存
    [2019-01-29 14:32:56.224188] INFO: bigquant: derived_feature_extractor.v3 运行完成[0.004731s].
    [2019-01-29 14:32:56.226200] INFO: bigquant: input_features.v1 开始运行..
    [2019-01-29 14:32:56.230617] INFO: bigquant: 命中缓存
    [2019-01-29 14:32:56.231583] INFO: bigquant: input_features.v1 运行完成[0.005378s].
    [2019-01-29 14:32:56.233943] INFO: bigquant: derived_feature_extractor.v3 开始运行..
    [2019-01-29 14:32:56.238119] INFO: bigquant: 命中缓存
    [2019-01-29 14:32:56.238914] INFO: bigquant: derived_feature_extractor.v3 运行完成[0.004949s].
    [2019-01-29 14:32:56.241165] INFO: bigquant: filter.v3 开始运行..
    [2019-01-29 14:32:56.255704] INFO: bigquant: 命中缓存
    [2019-01-29 14:32:56.257259] INFO: bigquant: filter.v3 运行完成[0.016072s].
    [2019-01-29 14:32:56.441592] INFO: bigquant: backtest.v8 开始运行..
    [2019-01-29 14:32:56.450605] INFO: bigquant: biglearning backtest:V8.1.7
    date
    2016-06    [002307.SZA, 300226.SZA, 600208.SHA, 600545.SH...
    2016-09    [000529.SZA, 000672.SZA, 000717.SZA, 000782.SZ...
    2016-12    [002002.SZA, 002238.SZA, 002671.SZA, 300094.SZ...
    2017-03    [000005.SZA, 000008.SZA, 000099.SZA, 000410.SZ...
    2017-06    [000005.SZA, 000008.SZA, 000410.SZA, 000526.SZ...
    dtype: object
    [2019-01-29 14:32:56.486256] INFO: bigquant: product_type:stock by specified
    [2019-01-29 14:33:10.926068] INFO: bigquant: 读取股票行情完成:2243781
    [2019-01-29 14:33:35.103219] INFO: algo: TradingAlgorithm V1.4.5
    [2019-01-29 14:33:46.358439] INFO: algo: trading transform...
    [2019-01-29 14:33:48.808713] INFO: Performance: Simulated 569 trading days out of 569.
    [2019-01-29 14:33:48.809963] INFO: Performance: first open: 2015-01-05 09:30:00+00:00
    [2019-01-29 14:33:48.810738] INFO: Performance: last close: 2017-05-05 15:00:00+00:00
    
    • 收益率-4.71%
    • 年化收益率-2.12%
    • 基准收益率-4.28%
    • 阿尔法-0.05
    • 贝塔0.03
    • 夏普比率-0.8
    • 胜率0.32
    • 盈亏比1.38
    • 收益波动率6.16%
    • 信息比率-0.01
    • 最大回撤9.57%
    [2019-01-29 14:33:52.939950] INFO: bigquant: backtest.v8 运行完成[56.498381s].