复制链接
克隆策略

使用深度学习技术预测股票价格

版本 v1.0

目录

  • ### 深度学习策略的交易规则

  • ### 策略构建步骤

  • ### 策略的实现

正文

一、深度学习策略的交易规则

  • 买入条件:预测的上涨概率>0.5,则买入或保持已有持仓。
  • 卖出条件 :预测的上涨概率<0.5,则卖出已有股票。

二、策略构建步骤

1、确定股票池和数据起止时间

  • 在证券代码列表m24和m28模块中输入要回测的单只股票,以及数据的起止日期(分别为训练集和验证集)。

2、确定因子

  • 在输入特征列表m8模块中输入用于预测的N个因子表达式。

3、获取基础数据

  • 通过基础特征数据抽取模块m22和m16获取指定股票池的基础数据,如收盘价等字段。

4、确定并计算模型标注

  • 通过自动标注股票模块m21计算需要的标注指标,本例中首先计算未来10天收益,然后根据其正负来给每日数据标注1或0,来标识涨跌。

5、抽取因子数据

  • 通过衍生数据抽取模块m23和m26计算因子数据。

6、合并标注与因子数据

  • 通过连接数据m17模块合并因子数据和标注数据。

7、生成序列窗口滚动数据集

  • 通过序列窗口滚动(深度学习)模块m25和m27将训练集和预测集的数据生成固定窗口长度的数据序列,为后续模型训练和预测做准备。

8、构建LSTM + CNN模型构架

  • 在画布左侧模块列表中依次拖入输入层模块、Reshape层模块、Conv2D层模块、Reshape层模块、LSTM层模块、Dropout层模块和全连接层模块(两组),构成深度学习网络构架,

    最后通过“构建(深度学习)”模块组装各层。这里需要注意:

    输入层的shape参数是 窗口滚动数据集的大小 X 因子数量 , 本例为 50 行 X 5个因子

    ReShape层的参数是 窗口滚动数据集的大小 X 因子数量 X 1 ,本例为 50 行 X 5个因子 X1

    Conv2D层中的 kernel_size参数是滑动窗口的尺寸,本例中使用 3行 X 5列 的窗口, 每次滑动的步长为 1行 X 1列 , 卷积核数目为32,这里的窗口设置决定了后面ReShape层的参数

    ReShape层中的target_shape 参数,这是由 窗口滚动数据集 X 因子数量 和 Conv2D层中设置的窗口尺寸以及步长决定的。本例中 50行 X 5因子 的输入数据,使用 3行 X5列 的窗口滑动取数据,

    每次移动1行,共计可以得到48次数据(即可以通过滑动3行 X 5列的窗口48次来获取完整的数据),因此target_shape= 48 X 卷积核数32

    LSTM层的输出空间维度设置为卷积核数32,并设置激活函数

    Dropout层是防止过度拟合采用的主动裁剪数据技术,这里设置rate 为0.8

    全连接层共两层,第一层的输出空间维度与LSTM的输出维度保持一致为32,第二层将第一层的32维数据转变为1维数据输出,即获取预测的label值,此例为0到1之间的连续值,可以认为是上涨的概率。

9、训练深度学习模型

  • 在画布左侧模块列表中拖入“训练(深度学习)”模块m6,设置属性中的优化器、目标函数、评估指标、每次训练的数据量batch_size、迭代次数epochs和GPU的数量以及日志输出频率。

10、使用深度学习模型预测

  • 在画布左侧模块列表中拖入“预测(深度学习)”模块m7,并将“训练(深度学习)”模块m6的模型输出和验证集的序列窗口滚动数据集传给预测模块,通过预测模块即根据股票验证集的数据预测上涨的概率。

11、将预测结果与时间拼接

  • 通过自定义模块m2将预测的每个滚动序列窗口的最后一个值最为当日的预测结果,并与预测集数据的时间列拼接,形成最终的每日预测结果。

12、根据模型预测结果构建策略

  • 如果当日预测的上涨概率大于0.5,则保持持仓或买入

  • 如果当日预测的上涨概率小于0.5,则卖出股票或保持空仓。

13、模拟回测

  • 通过 trade 模块中的初始化函数定义交易手续费和滑点,通过 context.prediction 获取每日的上涨概率预测结果;

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

三、策略的实现

可视化策略实现如下:

    {"description":"实验创建于2017/11/15","graph":{"edges":[{"to_node_id":"-281:options_data","from_node_id":"-214:data_1"},{"to_node_id":"-403:inputs","from_node_id":"-210:data"},{"to_node_id":"-293:inputs","from_node_id":"-210:data"},{"to_node_id":"-14834:inputs","from_node_id":"-218:data"},{"to_node_id":"-692:input_data","from_node_id":"-316:data"},{"to_node_id":"-332:trained_model","from_node_id":"-320:data"},{"to_node_id":"-214:input_1","from_node_id":"-332:data"},{"to_node_id":"-692:features","from_node_id":"-2295:data"},{"to_node_id":"-333:features","from_node_id":"-2295:data"},{"to_node_id":"-341:features","from_node_id":"-2295:data"},{"to_node_id":"-300:features","from_node_id":"-2295:data"},{"to_node_id":"-307:features","from_node_id":"-2295:data"},{"to_node_id":"-316:features","from_node_id":"-2295:data"},{"to_node_id":"-293:outputs","from_node_id":"-259:data"},{"to_node_id":"-14841:inputs","from_node_id":"-14806:data"},{"to_node_id":"-14806:inputs","from_node_id":"-14834:data"},{"to_node_id":"-259:inputs","from_node_id":"-14841:data"},{"to_node_id":"-408:inputs","from_node_id":"-403:data"},{"to_node_id":"-446:inputs","from_node_id":"-408:data"},{"to_node_id":"-218:inputs","from_node_id":"-446:data"},{"to_node_id":"-2296:input_data","from_node_id":"-2290:data"},{"to_node_id":"-333:input_data","from_node_id":"-2296:data"},{"to_node_id":"-289:instruments","from_node_id":"-620:data"},{"to_node_id":"-300:instruments","from_node_id":"-620:data"},{"to_node_id":"-330:input_data","from_node_id":"-692:data"},{"to_node_id":"-320:training_data","from_node_id":"-333:data"},{"to_node_id":"-332:input_data","from_node_id":"-341:data"},{"to_node_id":"-2290:data1","from_node_id":"-289:data"},{"to_node_id":"-307:input_data","from_node_id":"-300:data"},{"to_node_id":"-2290:data2","from_node_id":"-307:data"},{"to_node_id":"-316:instruments","from_node_id":"-322:data"},{"to_node_id":"-281:instruments","from_node_id":"-322:data"},{"to_node_id":"-341:input_data","from_node_id":"-330:data"},{"to_node_id":"-214:input_2","from_node_id":"-330:data"},{"to_node_id":"-320:input_model","from_node_id":"-293:data"}],"nodes":[{"node_id":"-214","module_id":"BigQuantSpace.cached.cached-v3","parameters":[{"name":"run","value":"# Python 代码入口函数,input_1/2/3 对应三个输入端,data_1/2/3 对应三个输出端\ndef bigquant_run(input_1, input_2, input_3):\n # 示例代码如下。在这里编写您的代码\n pred_label = input_1.read_pickle()\n df = input_2.read_df()\n df = pd.DataFrame({'pred_label':pred_label[:,0], 'instrument':df.instrument, 'date':df.date})\n df.sort_values(['date','pred_label'],inplace=True, ascending=[True,False])\n return Outputs(data_1=DataSource.write_df(df), data_2=None, data_3=None)\n\n","type":"Literal","bound_global_parameter":null},{"name":"post_run","value":"# 后处理函数,可选。输入是主函数的输出,可以在这里对数据做处理,或者返回更友好的outputs数据格式。此函数输出不会被缓存。\ndef bigquant_run(outputs):\n return outputs\n","type":"Literal","bound_global_parameter":null},{"name":"input_ports","value":"","type":"Literal","bound_global_parameter":null},{"name":"params","value":"{}","type":"Literal","bound_global_parameter":null},{"name":"output_ports","value":"","type":"Literal","bound_global_parameter":null}],"input_ports":[{"name":"input_1","node_id":"-214"},{"name":"input_2","node_id":"-214"},{"name":"input_3","node_id":"-214"}],"output_ports":[{"name":"data_1","node_id":"-214"},{"name":"data_2","node_id":"-214"},{"name":"data_3","node_id":"-214"}],"cacheable":true,"seq_num":2,"comment":"模型预测结果输出","comment_collapsed":false},{"node_id":"-210","module_id":"BigQuantSpace.dl_layer_input.dl_layer_input-v1","parameters":[{"name":"shape","value":"50,5","type":"Literal","bound_global_parameter":null},{"name":"batch_shape","value":"","type":"Literal","bound_global_parameter":null},{"name":"dtype","value":"float32","type":"Literal","bound_global_parameter":null},{"name":"sparse","value":"False","type":"Literal","bound_global_parameter":null},{"name":"name","value":"","type":"Literal","bound_global_parameter":null}],"input_ports":[{"name":"inputs","node_id":"-210"}],"output_ports":[{"name":"data","node_id":"-210"}],"cacheable":false,"seq_num":3,"comment":"","comment_collapsed":true},{"node_id":"-218","module_id":"BigQuantSpace.dl_layer_lstm.dl_layer_lstm-v1","parameters":[{"name":"units","value":"32","type":"Literal","bound_global_parameter":null},{"name":"activation","value":"tanh","type":"Literal","bound_global_parameter":null},{"name":"user_activation","value":"","type":"Literal","bound_global_parameter":null},{"name":"recurrent_activation","value":"hard_sigmoid","type":"Literal","bound_global_parameter":null},{"name":"user_recurrent_activation","value":"","type":"Literal","bound_global_parameter":null},{"name":"use_bias","value":"True","type":"Literal","bound_global_parameter":null},{"name":"kernel_initializer","value":"glorot_uniform","type":"Literal","bound_global_parameter":null},{"name":"user_kernel_initializer","value":"","type":"Literal","bound_global_parameter":null},{"name":"recurrent_initializer","value":"Orthogonal","type":"Literal","bound_global_parameter":null},{"name":"user_recurrent_initializer","value":"","type":"Literal","bound_global_parameter":null},{"name":"bias_initializer","value":"Ones","type":"Literal","bound_global_parameter":null},{"name":"user_bias_initializer","value":"","type":"Literal","bound_global_parameter":null},{"name":"unit_forget_bias","value":"True","type":"Literal","bound_global_parameter":null},{"name":"kernel_regularizer","value":"None","type":"Literal","bound_global_parameter":null},{"name":"kernel_regularizer_l1","value":0,"type":"Literal","bound_global_parameter":null},{"name":"kernel_regularizer_l2","value":0,"type":"Literal","bound_global_parameter":null},{"name":"user_kernel_regularizer","value":"","type":"Literal","bound_global_parameter":null},{"name":"recurrent_regularizer","value":"None","type":"Literal","bound_global_parameter":null},{"name":"recurrent_regularizer_l1","value":0,"type":"Literal","bound_global_parameter":null},{"name":"recurrent_regularizer_l2","value":0,"type":"Literal","bound_global_parameter":null},{"name":"user_recurrent_regularizer","value":"","type":"Literal","bound_global_parameter":null},{"name":"bias_regularizer","value":"None","type":"Literal","bound_global_parameter":null},{"name":"bias_regularizer_l1","value":0,"type":"Literal","bound_global_parameter":null},{"name":"bias_regularizer_l2","value":0,"type":"Literal","bound_global_parameter":null},{"name":"user_bias_regularizer","value":"","type":"Literal","bound_global_parameter":null},{"name":"activity_regularizer","value":"None","type":"Literal","bound_global_parameter":null},{"name":"activity_regularizer_l1","value":0,"type":"Literal","bound_global_parameter":null},{"name":"activity_regularizer_l2","value":0,"type":"Literal","bound_global_parameter":null},{"name":"user_activity_regularizer","value":"","type":"Literal","bound_global_parameter":null},{"name":"kernel_constraint","value":"None","type":"Literal","bound_global_parameter":null},{"name":"user_kernel_constraint","value":"","type":"Literal","bound_global_parameter":null},{"name":"recurrent_constraint","value":"None","type":"Literal","bound_global_parameter":null},{"name":"user_recurrent_constraint","value":"","type":"Literal","bound_global_parameter":null},{"name":"bias_constraint","value":"None","type":"Literal","bound_global_parameter":null},{"name":"user_bias_constraint","value":"","type":"Literal","bound_global_parameter":null},{"name":"dropout","value":"0","type":"Literal","bound_global_parameter":null},{"name":"recurrent_dropout","value":0,"type":"Literal","bound_global_parameter":null},{"name":"return_sequences","value":"False","type":"Literal","bound_global_parameter":null},{"name":"implementation","value":"2","type":"Literal","bound_global_parameter":null},{"name":"name","value":"","type":"Literal","bound_global_parameter":null}],"input_ports":[{"name":"inputs","node_id":"-218"}],"output_ports":[{"name":"data","node_id":"-218"}],"cacheable":false,"seq_num":4,"comment":"","comment_collapsed":true},{"node_id":"-316","module_id":"BigQuantSpace.general_feature_extractor.general_feature_extractor-v7","parameters":[{"name":"start_date","value":"","type":"Literal","bound_global_parameter":null},{"name":"end_date","value":"","type":"Literal","bound_global_parameter":null},{"name":"before_start_days","value":90,"type":"Literal","bound_global_parameter":null}],"input_ports":[{"name":"instruments","node_id":"-316"},{"name":"features","node_id":"-316"}],"output_ports":[{"name":"data","node_id":"-316"}],"cacheable":true,"seq_num":16,"comment":"","comment_collapsed":true},{"node_id":"-320","module_id":"BigQuantSpace.dl_model_train.dl_model_train-v1","parameters":[{"name":"optimizer","value":"Adam","type":"Literal","bound_global_parameter":null},{"name":"user_optimizer","value":"","type":"Literal","bound_global_parameter":null},{"name":"loss","value":"binary_crossentropy","type":"Literal","bound_global_parameter":null},{"name":"user_loss","value":"","type":"Literal","bound_global_parameter":null},{"name":"metrics","value":"accuracy","type":"Literal","bound_global_parameter":null},{"name":"batch_size","value":"2048","type":"Literal","bound_global_parameter":null},{"name":"epochs","value":"10","type":"Literal","bound_global_parameter":null},{"name":"earlystop","value":"","type":"Literal","bound_global_parameter":null},{"name":"custom_objects","value":"# 用户的自定义层需要写到字典中,比如\n# {\n# \"MyLayer\": MyLayer\n# }\nbigquant_run = {\n \n}\n","type":"Literal","bound_global_parameter":null},{"name":"n_gpus","value":"1","type":"Literal","bound_global_parameter":null},{"name":"verbose","value":"1:输出进度条记录","type":"Literal","bound_global_parameter":null}],"input_ports":[{"name":"input_model","node_id":"-320"},{"name":"training_data","node_id":"-320"},{"name":"validation_data","node_id":"-320"}],"output_ports":[{"name":"data","node_id":"-320"}],"cacheable":true,"seq_num":6,"comment":"","comment_collapsed":true},{"node_id":"-332","module_id":"BigQuantSpace.dl_model_predict.dl_model_predict-v1","parameters":[{"name":"batch_size","value":"10240","type":"Literal","bound_global_parameter":null},{"name":"n_gpus","value":"0","type":"Literal","bound_global_parameter":null},{"name":"verbose","value":"2:每个epoch输出一行记录","type":"Literal","bound_global_parameter":null}],"input_ports":[{"name":"trained_model","node_id":"-332"},{"name":"input_data","node_id":"-332"}],"output_ports":[{"name":"data","node_id":"-332"}],"cacheable":true,"seq_num":7,"comment":"","comment_collapsed":true},{"node_id":"-2295","module_id":"BigQuantSpace.input_features.input_features-v1","parameters":[{"name":"features","value":"(close_0/close_1-1)*10\n(high_0/high_1-1)*10\n(low_0/low_1-1)*10\n(open_0/open_1-1)*10\n(volume_0/volume_1-1)*10","type":"Literal","bound_global_parameter":null}],"input_ports":[{"name":"features_ds","node_id":"-2295"}],"output_ports":[{"name":"data","node_id":"-2295"}],"cacheable":true,"seq_num":8,"comment":"","comment_collapsed":true},{"node_id":"-259","module_id":"BigQuantSpace.dl_layer_dense.dl_layer_dense-v1","parameters":[{"name":"units","value":"1","type":"Literal","bound_global_parameter":null},{"name":"activation","value":"sigmoid","type":"Literal","bound_global_parameter":null},{"name":"user_activation","value":"","type":"Literal","bound_global_parameter":null},{"name":"use_bias","value":"True","type":"Literal","bound_global_parameter":null},{"name":"kernel_initializer","value":"glorot_uniform","type":"Literal","bound_global_parameter":null},{"name":"user_kernel_initializer","value":"","type":"Literal","bound_global_parameter":null},{"name":"bias_initializer","value":"Zeros","type":"Literal","bound_global_parameter":null},{"name":"user_bias_initializer","value":"","type":"Literal","bound_global_parameter":null},{"name":"kernel_regularizer","value":"None","type":"Literal","bound_global_parameter":null},{"name":"kernel_regularizer_l1","value":0,"type":"Literal","bound_global_parameter":null},{"name":"kernel_regularizer_l2","value":0,"type":"Literal","bound_global_parameter":null},{"name":"user_kernel_regularizer","value":"","type":"Literal","bound_global_parameter":null},{"name":"bias_regularizer","value":"None","type":"Literal","bound_global_parameter":null},{"name":"bias_regularizer_l1","value":0,"type":"Literal","bound_global_parameter":null},{"name":"bias_regularizer_l2","value":0,"type":"Literal","bound_global_parameter":null},{"name":"user_bias_regularizer","value":"","type":"Literal","bound_global_parameter":null},{"name":"activity_regularizer","value":"None","type":"Literal","bound_global_parameter":null},{"name":"activity_regularizer_l1","value":0,"type":"Literal","bound_global_parameter":null},{"name":"activity_regularizer_l2","value":0,"type":"Literal","bound_global_parameter":null},{"name":"user_activity_regularizer","value":"","type":"Literal","bound_global_parameter":null},{"name":"kernel_constraint","value":"None","type":"Literal","bound_global_parameter":null},{"name":"user_kernel_constraint","value":"","type":"Literal","bound_global_parameter":null},{"name":"bias_constraint","value":"None","type":"Literal","bound_global_parameter":null},{"name":"user_bias_constraint","value":"","type":"Literal","bound_global_parameter":null},{"name":"name","value":"","type":"Literal","bound_global_parameter":null}],"input_ports":[{"name":"inputs","node_id":"-259"}],"output_ports":[{"name":"data","node_id":"-259"}],"cacheable":false,"seq_num":9,"comment":"","comment_collapsed":true},{"node_id":"-14806","module_id":"BigQuantSpace.dl_layer_dense.dl_layer_dense-v1","parameters":[{"name":"units","value":"32","type":"Literal","bound_global_parameter":null},{"name":"activation","value":"tanh","type":"Literal","bound_global_parameter":null},{"name":"user_activation","value":"","type":"Literal","bound_global_parameter":null},{"name":"use_bias","value":"True","type":"Literal","bound_global_parameter":null},{"name":"kernel_initializer","value":"glorot_uniform","type":"Literal","bound_global_parameter":null},{"name":"user_kernel_initializer","value":"","type":"Literal","bound_global_parameter":null},{"name":"bias_initializer","value":"Zeros","type":"Literal","bound_global_parameter":null},{"name":"user_bias_initializer","value":"","type":"Literal","bound_global_parameter":null},{"name":"kernel_regularizer","value":"None","type":"Literal","bound_global_parameter":null},{"name":"kernel_regularizer_l1","value":0,"type":"Literal","bound_global_parameter":null},{"name":"kernel_regularizer_l2","value":0,"type":"Literal","bound_global_parameter":null},{"name":"user_kernel_regularizer","value":"","type":"Literal","bound_global_parameter":null},{"name":"bias_regularizer","value":"None","type":"Literal","bound_global_parameter":null},{"name":"bias_regularizer_l1","value":0,"type":"Literal","bound_global_parameter":null},{"name":"bias_regularizer_l2","value":0,"type":"Literal","bound_global_parameter":null},{"name":"user_bias_regularizer","value":"","type":"Literal","bound_global_parameter":null},{"name":"activity_regularizer","value":"None","type":"Literal","bound_global_parameter":null},{"name":"activity_regularizer_l1","value":0,"type":"Literal","bound_global_parameter":null},{"name":"activity_regularizer_l2","value":0,"type":"Literal","bound_global_parameter":null},{"name":"user_activity_regularizer","value":"","type":"Literal","bound_global_parameter":null},{"name":"kernel_constraint","value":"None","type":"Literal","bound_global_parameter":null},{"name":"user_kernel_constraint","value":"","type":"Literal","bound_global_parameter":null},{"name":"bias_constraint","value":"None","type":"Literal","bound_global_parameter":null},{"name":"user_bias_constraint","value":"","type":"Literal","bound_global_parameter":null},{"name":"name","value":"","type":"Literal","bound_global_parameter":null}],"input_ports":[{"name":"inputs","node_id":"-14806"}],"output_ports":[{"name":"data","node_id":"-14806"}],"cacheable":false,"seq_num":10,"comment":"","comment_collapsed":true},{"node_id":"-14834","module_id":"BigQuantSpace.dl_layer_dropout.dl_layer_dropout-v1","parameters":[{"name":"rate","value":"0.4","type":"Literal","bound_global_parameter":null},{"name":"noise_shape","value":"","type":"Literal","bound_global_parameter":null},{"name":"seed","value":"","type":"Literal","bound_global_parameter":null},{"name":"name","value":"","type":"Literal","bound_global_parameter":null}],"input_ports":[{"name":"inputs","node_id":"-14834"}],"output_ports":[{"name":"data","node_id":"-14834"}],"cacheable":false,"seq_num":11,"comment":"","comment_collapsed":true},{"node_id":"-14841","module_id":"BigQuantSpace.dl_layer_dropout.dl_layer_dropout-v1","parameters":[{"name":"rate","value":"0.8","type":"Literal","bound_global_parameter":null},{"name":"noise_shape","value":"","type":"Literal","bound_global_parameter":null},{"name":"seed","value":"","type":"Literal","bound_global_parameter":null},{"name":"name","value":"","type":"Literal","bound_global_parameter":null}],"input_ports":[{"name":"inputs","node_id":"-14841"}],"output_ports":[{"name":"data","node_id":"-14841"}],"cacheable":false,"seq_num":12,"comment":"","comment_collapsed":true},{"node_id":"-403","module_id":"BigQuantSpace.dl_layer_reshape.dl_layer_reshape-v1","parameters":[{"name":"target_shape","value":"50,5,1","type":"Literal","bound_global_parameter":null},{"name":"name","value":"","type":"Literal","bound_global_parameter":null}],"input_ports":[{"name":"inputs","node_id":"-403"}],"output_ports":[{"name":"data","node_id":"-403"}],"cacheable":false,"seq_num":13,"comment":"","comment_collapsed":true},{"node_id":"-408","module_id":"BigQuantSpace.dl_layer_conv2d.dl_layer_conv2d-v1","parameters":[{"name":"filters","value":"32","type":"Literal","bound_global_parameter":null},{"name":"kernel_size","value":"3,5","type":"Literal","bound_global_parameter":null},{"name":"strides","value":"1,1","type":"Literal","bound_global_parameter":null},{"name":"padding","value":"valid","type":"Literal","bound_global_parameter":null},{"name":"data_format","value":"channels_last","type":"Literal","bound_global_parameter":null},{"name":"dilation_rate","value":"1,1","type":"Literal","bound_global_parameter":null},{"name":"activation","value":"relu","type":"Literal","bound_global_parameter":null},{"name":"user_activation","value":"","type":"Literal","bound_global_parameter":null},{"name":"use_bias","value":"True","type":"Literal","bound_global_parameter":null},{"name":"kernel_initializer","value":"glorot_uniform","type":"Literal","bound_global_parameter":null},{"name":"user_kernel_initializer","value":"","type":"Literal","bound_global_parameter":null},{"name":"bias_initializer","value":"Zeros","type":"Literal","bound_global_parameter":null},{"name":"user_bias_initializer","value":"","type":"Literal","bound_global_parameter":null},{"name":"kernel_regularizer","value":"None","type":"Literal","bound_global_parameter":null},{"name":"kernel_regularizer_l1","value":0,"type":"Literal","bound_global_parameter":null},{"name":"kernel_regularizer_l2","value":0,"type":"Literal","bound_global_parameter":null},{"name":"user_kernel_regularizer","value":"","type":"Literal","bound_global_parameter":null},{"name":"bias_regularizer","value":"None","type":"Literal","bound_global_parameter":null},{"name":"bias_regularizer_l1","value":0,"type":"Literal","bound_global_parameter":null},{"name":"bias_regularizer_l2","value":0,"type":"Literal","bound_global_parameter":null},{"name":"user_bias_regularizer","value":"","type":"Literal","bound_global_parameter":null},{"name":"activity_regularizer","value":"None","type":"Literal","bound_global_parameter":null},{"name":"activity_regularizer_l1","value":0,"type":"Literal","bound_global_parameter":null},{"name":"activity_regularizer_l2","value":0,"type":"Literal","bound_global_parameter":null},{"name":"user_activity_regularizer","value":"","type":"Literal","bound_global_parameter":null},{"name":"kernel_constraint","value":"None","type":"Literal","bound_global_parameter":null},{"name":"user_kernel_constraint","value":"","type":"Literal","bound_global_parameter":null},{"name":"bias_constraint","value":"None","type":"Literal","bound_global_parameter":null},{"name":"user_bias_constraint","value":"","type":"Literal","bound_global_parameter":null},{"name":"name","value":"","type":"Literal","bound_global_parameter":null}],"input_ports":[{"name":"inputs","node_id":"-408"}],"output_ports":[{"name":"data","node_id":"-408"}],"cacheable":false,"seq_num":14,"comment":"","comment_collapsed":true},{"node_id":"-446","module_id":"BigQuantSpace.dl_layer_reshape.dl_layer_reshape-v1","parameters":[{"name":"target_shape","value":"48,32","type":"Literal","bound_global_parameter":null},{"name":"name","value":"","type":"Literal","bound_global_parameter":null}],"input_ports":[{"name":"inputs","node_id":"-446"}],"output_ports":[{"name":"data","node_id":"-446"}],"cacheable":false,"seq_num":15,"comment":"","comment_collapsed":true},{"node_id":"-2290","module_id":"BigQuantSpace.join.join-v3","parameters":[{"name":"on","value":"date","type":"Literal","bound_global_parameter":null},{"name":"how","value":"inner","type":"Literal","bound_global_parameter":null},{"name":"sort","value":"True","type":"Literal","bound_global_parameter":null}],"input_ports":[{"name":"data1","node_id":"-2290"},{"name":"data2","node_id":"-2290"}],"output_ports":[{"name":"data","node_id":"-2290"}],"cacheable":true,"seq_num":17,"comment":"标注特征连接","comment_collapsed":false},{"node_id":"-2296","module_id":"BigQuantSpace.dropnan.dropnan-v1","parameters":[],"input_ports":[{"name":"input_data","node_id":"-2296"}],"output_ports":[{"name":"data","node_id":"-2296"}],"cacheable":true,"seq_num":18,"comment":"去掉为nan的数据","comment_collapsed":true},{"node_id":"-620","module_id":"BigQuantSpace.instruments.instruments-v2","parameters":[{"name":"start_date","value":"2017-06-02","type":"Literal","bound_global_parameter":null},{"name":"end_date","value":"2017-10-30","type":"Literal","bound_global_parameter":null},{"name":"market","value":"CN_STOCK_A","type":"Literal","bound_global_parameter":null},{"name":"instrument_list","value":"600009.SHA","type":"Literal","bound_global_parameter":null},{"name":"max_count","value":0,"type":"Literal","bound_global_parameter":null}],"input_ports":[{"name":"rolling_conf","node_id":"-620"}],"output_ports":[{"name":"data","node_id":"-620"}],"cacheable":true,"seq_num":24,"comment":"","comment_collapsed":true},{"node_id":"-692","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":"-692"},{"name":"features","node_id":"-692"}],"output_ports":[{"name":"data","node_id":"-692"}],"cacheable":true,"seq_num":26,"comment":"","comment_collapsed":true},{"node_id":"-281","module_id":"BigQuantSpace.trade.trade-v4","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 context.prediction = context.options['data'].read_df()\n \n # 系统已经设置了默认的交易手续费和滑点,要修改手续费可使用如下函数\n context.set_commission(PerOrder(buy_cost=0.0003, sell_cost=0.0013, min_cost=5))","type":"Literal","bound_global_parameter":null},{"name":"handle_data","value":"# 回测引擎:每日数据处理函数,每天执行一次\ndef bigquant_run(context, data):\n # 按日期过滤得到今日的预测数据\n try:\n prediction = context.prediction[ context.prediction['date']==data.current_dt.strftime('%Y-%m-%d')].pred_label.values[0]\n except KeyError as e:\n return\n \n instrument = context.instruments[0]\n sid = context.symbol(instrument)\n cur_position = context.portfolio.positions[sid].amount\n \n # 交易逻辑\n if prediction > 0.5 and cur_position == 0:\n context.order_target_percent(context.symbol(instrument), 1)\n print(data.current_dt, '买入!')\n \n elif prediction < 0.5 and cur_position > 0:\n context.order_target_percent(context.symbol(instrument), 0)\n print(data.current_dt, '卖出!')\n ","type":"Literal","bound_global_parameter":null},{"name":"prepare","value":"# 回测引擎:准备数据,只执行一次\ndef bigquant_run(context):\n pass\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":"volume_limit","value":0.025,"type":"Literal","bound_global_parameter":null},{"name":"order_price_field_buy","value":"open","type":"Literal","bound_global_parameter":null},{"name":"order_price_field_sell","value":"close","type":"Literal","bound_global_parameter":null},{"name":"capital_base","value":1000000,"type":"Literal","bound_global_parameter":null},{"name":"auto_cancel_non_tradable_orders","value":"True","type":"Literal","bound_global_parameter":null},{"name":"data_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":"plot_charts","value":"True","type":"Literal","bound_global_parameter":null},{"name":"backtest_only","value":"False","type":"Literal","bound_global_parameter":null},{"name":"benchmark","value":"000300.HIX","type":"Literal","bound_global_parameter":null}],"input_ports":[{"name":"instruments","node_id":"-281"},{"name":"options_data","node_id":"-281"},{"name":"history_ds","node_id":"-281"},{"name":"benchmark_ds","node_id":"-281"},{"name":"trading_calendar","node_id":"-281"}],"output_ports":[{"name":"raw_perf","node_id":"-281"}],"cacheable":false,"seq_num":1,"comment":"","comment_collapsed":true},{"node_id":"-333","module_id":"BigQuantSpace.dl_convert_to_bin.dl_convert_to_bin-v2","parameters":[{"name":"window_size","value":"50","type":"Literal","bound_global_parameter":null},{"name":"feature_clip","value":5,"type":"Literal","bound_global_parameter":null},{"name":"flatten","value":"False","type":"Literal","bound_global_parameter":null},{"name":"window_along_col","value":"","type":"Literal","bound_global_parameter":null}],"input_ports":[{"name":"input_data","node_id":"-333"},{"name":"features","node_id":"-333"}],"output_ports":[{"name":"data","node_id":"-333"}],"cacheable":true,"seq_num":25,"comment":"","comment_collapsed":true},{"node_id":"-341","module_id":"BigQuantSpace.dl_convert_to_bin.dl_convert_to_bin-v2","parameters":[{"name":"window_size","value":"50","type":"Literal","bound_global_parameter":null},{"name":"feature_clip","value":5,"type":"Literal","bound_global_parameter":null},{"name":"flatten","value":"False","type":"Literal","bound_global_parameter":null},{"name":"window_along_col","value":"","type":"Literal","bound_global_parameter":null}],"input_ports":[{"name":"input_data","node_id":"-341"},{"name":"features","node_id":"-341"}],"output_ports":[{"name":"data","node_id":"-341"}],"cacheable":true,"seq_num":27,"comment":"","comment_collapsed":true},{"node_id":"-289","module_id":"BigQuantSpace.advanced_auto_labeler.advanced_auto_labeler-v2","parameters":[{"name":"label_expr","value":"# #号开始的表示注释\n# 0. 每行一个,顺序执行,从第二个开始,可以使用label字段\n# 1. 可用数据字段见 https://bigquant.com/docs/develop/datasource/deprecated/history_data.html\n# 添加benchmark_前缀,可使用对应的benchmark数据\n# 2. 可用操作符和函数见 `表达式引擎 <https://bigquant.com/docs/develop/bigexpr/usage.html>`_\n\n# 计算收益:5日收盘价(作为卖出价格)除以明日开盘价(作为买入价格)\nwhere(shift(close, -10) / close -1>0,1,0)\n\n# 过滤掉一字涨停的情况 (设置label为NaN,在后续处理和训练中会忽略NaN的label)\nwhere(shift(high, -1) == shift(low, -1), NaN, label)\n","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},{"name":"benchmark","value":"000300.SHA","type":"Literal","bound_global_parameter":null},{"name":"drop_na_label","value":"True","type":"Literal","bound_global_parameter":null},{"name":"cast_label_int","value":"True","type":"Literal","bound_global_parameter":null},{"name":"user_functions","value":"{}","type":"Literal","bound_global_parameter":null}],"input_ports":[{"name":"instruments","node_id":"-289"}],"output_ports":[{"name":"data","node_id":"-289"}],"cacheable":true,"seq_num":21,"comment":"","comment_collapsed":true},{"node_id":"-300","module_id":"BigQuantSpace.general_feature_extractor.general_feature_extractor-v7","parameters":[{"name":"start_date","value":"","type":"Literal","bound_global_parameter":null},{"name":"end_date","value":"","type":"Literal","bound_global_parameter":null},{"name":"before_start_days","value":90,"type":"Literal","bound_global_parameter":null}],"input_ports":[{"name":"instruments","node_id":"-300"},{"name":"features","node_id":"-300"}],"output_ports":[{"name":"data","node_id":"-300"}],"cacheable":true,"seq_num":22,"comment":"","comment_collapsed":true},{"node_id":"-307","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":"-307"},{"name":"features","node_id":"-307"}],"output_ports":[{"name":"data","node_id":"-307"}],"cacheable":true,"seq_num":23,"comment":"","comment_collapsed":true},{"node_id":"-322","module_id":"BigQuantSpace.instruments.instruments-v2","parameters":[{"name":"start_date","value":"2019-02-11","type":"Literal","bound_global_parameter":"交易日期"},{"name":"end_date","value":"2019-08-01","type":"Literal","bound_global_parameter":"交易日期"},{"name":"market","value":"CN_STOCK_A","type":"Literal","bound_global_parameter":null},{"name":"instrument_list","value":"600009.SHA","type":"Literal","bound_global_parameter":null},{"name":"max_count","value":0,"type":"Literal","bound_global_parameter":null}],"input_ports":[{"name":"rolling_conf","node_id":"-322"}],"output_ports":[{"name":"data","node_id":"-322"}],"cacheable":true,"seq_num":28,"comment":"","comment_collapsed":true},{"node_id":"-330","module_id":"BigQuantSpace.dropnan.dropnan-v1","parameters":[],"input_ports":[{"name":"input_data","node_id":"-330"}],"output_ports":[{"name":"data","node_id":"-330"}],"cacheable":true,"seq_num":20,"comment":"","comment_collapsed":true},{"node_id":"-293","module_id":"BigQuantSpace.dl_model_init.dl_model_init-v1","parameters":[],"input_ports":[{"name":"inputs","node_id":"-293"},{"name":"outputs","node_id":"-293"}],"output_ports":[{"name":"data","node_id":"-293"}],"cacheable":false,"seq_num":5,"comment":"","comment_collapsed":true},{"node_id":"-352","module_id":"BigQuantSpace.hyper_rolling_train.hyper_rolling_train-v1","parameters":[{"name":"run","value":"def bigquant_run(\n bq_graph,\n inputs,\n trading_days_market='CN', # 使用那个市场的交易日历\n train_instruments_mid='m24', # 训练数据 证券代码列表 模块id\n test_instruments_mid='m28', # 测试数据 证券代码列表 模块id\n predict_mid='m2', # 预测 模块id\n trade_mid='m1', # 回测 模块id\n start_date='2016-01-01', # 数据开始日期\n end_date=T.live_run_param('trading_date', '2018-01-01'), # 数据结束日期\n train_update_days=90, # 更新周期,按交易日计算,每多少天更新一次\n train_update_days_for_live=100, #模拟实盘模式下的更新周期,按交易日计算,每多少天更新一次。如果需要在模拟实盘阶段使用不同的模型更新周期,可以设置这个参数\n train_data_min_days=100, # 最小数据天数,按交易日计算,所以第一个滚动的结束日期是 从开始日期到开始日期+最小数据天数\n train_data_max_days=100, # 最大数据天数,按交易日计算,0,表示没有限制,否则每一个滚动的开始日期=max(此滚动的结束日期-最大数据天数, 开始日期\n rolling_count_for_live=1, #实盘模式下滚动次数,模拟实盘模式下,取最后多少次滚动。一般在模拟实盘模式下,只用到最后一次滚动训练的模型,这里可以设置为1;如果你的滚动训练数据时间段很短,以至于期间可能没有训练数据,这里可以设置大一点。0表示没有限制\n):\n def merge_datasources(input_1):\n df_list = [ds.read_df() for ds in input_1]\n df = pd.concat(df_list)\n instrument_data = {\n 'start_date': df['date'].min().strftime('%Y-%m-%d'),\n 'end_date': df['date'].max().strftime('%Y-%m-%d'),\n 'instruments': list(set(df['instrument'])),\n }\n return Outputs(data=DataSource.write_df(df), instrument_data=DataSource.write_pickle(instrument_data))\n\n def gen_rolling_dates(trading_days_market, start_date, end_date, train_update_days, train_update_days_for_live, train_data_min_days, train_data_max_days, rolling_count_for_live):\n # 是否实盘模式\n tdays = list(D.trading_days(market=trading_days_market, start_date=start_date, end_date=end_date)['date'])\n is_live_run = T.live_run_param('trading_date', None) is not None\n\n if is_live_run and train_update_days_for_live:\n train_update_days = train_update_days_for_live\n\n rollings = []\n train_end_date = train_data_min_days\n while train_end_date < len(tdays):\n if train_data_max_days is not None:\n train_start_date = max(train_end_date - train_data_max_days, 0)\n else:\n train_start_date = start_date\n rollings.append({\n 'train_start_date': tdays[train_start_date].strftime('%Y-%m-%d'),\n 'train_end_date': tdays[train_end_date - 1].strftime('%Y-%m-%d'),\n 'test_start_date': tdays[train_end_date].strftime('%Y-%m-%d'),\n 'test_end_date': tdays[min(train_end_date + train_update_days, len(tdays)) - 1].strftime('%Y-%m-%d'),\n })\n train_end_date += train_update_days\n\n if not rollings:\n raise Exception('没有滚动需要执行,请检查配置')\n\n if is_live_run and rolling_count_for_live:\n rollings = rollings[-rolling_count_for_live:]\n\n return rollings\n\n g = bq_graph\n\n rolling_dates = gen_rolling_dates(\n trading_days_market, start_date, end_date, train_update_days, train_update_days_for_live, train_data_min_days, train_data_max_days, rolling_count_for_live)\n\n # 训练和预测\n results = []\n for rolling in rolling_dates:\n parameters = {}\n # 先禁用回测\n parameters[trade_mid + '.__enabled__'] = False\n parameters[train_instruments_mid + '.start_date'] = rolling['train_start_date']\n parameters[train_instruments_mid + '.end_date'] = rolling['train_end_date']\n parameters[test_instruments_mid + '.start_date'] = rolling['test_start_date']\n parameters[test_instruments_mid + '.end_date'] = rolling['test_end_date']\n # print('------ rolling_train:', parameters)\n results.append(g.run(parameters))\n\n # 合并预测结果并回测\n mx = M.cached.v3(run=merge_datasources, input_1=[result[predict_mid].data_1 for result in results])\n parameters = {}\n parameters['*.__enabled__'] = False\n parameters[trade_mid + '.__enabled__'] = True\n parameters[trade_mid + '.instruments'] = mx.instrument_data\n parameters[trade_mid + '.options_data'] = mx.data\n\n trade = g.run(parameters)\n\n return {'rollings': results, 'trade': trade}","type":"Literal","bound_global_parameter":null},{"name":"run_now","value":"True","type":"Literal","bound_global_parameter":null},{"name":"bq_graph","value":"True","type":"Literal","bound_global_parameter":null}],"input_ports":[{"name":"bq_graph_port","node_id":"-352"},{"name":"input_1","node_id":"-352"},{"name":"input_2","node_id":"-352"},{"name":"input_3","node_id":"-352"}],"output_ports":[{"name":"result","node_id":"-352"}],"cacheable":false,"seq_num":19,"comment":"","comment_collapsed":true}],"node_layout":"<node_postions><node_position Node='-214' Position='1156.6448974609375,704.3570556640625,200,200'/><node_position Node='-210' Position='346,-367,200,200'/><node_position Node='-218' Position='277,69,200,200'/><node_position Node='-316' Position='1330.2513427734375,-86,200,200'/><node_position Node='-320' Position='633,538,200,200'/><node_position Node='-332' Position='816,624.4107666015625,200,200'/><node_position Node='-2295' Position='1006,-264,200,200'/><node_position Node='-259' Position='281,387,200,200'/><node_position Node='-14806' Position='279,211,200,200'/><node_position Node='-14834' Position='279,146,200,200'/><node_position Node='-14841' Position='282,301,200,200'/><node_position Node='-403' Position='279,-194,200,200'/><node_position Node='-408' Position='280,-107,200,200'/><node_position Node='-446' Position='278,-23,200,200'/><node_position Node='-2290' Position='735,138,200,200'/><node_position Node='-2296' Position='734,242,200,200'/><node_position Node='-620' Position='718,-171,200,200'/><node_position Node='-692' Position='1251,58.090121269226074,200,200'/><node_position Node='-281' Position='1141.5701904296875,893.0363159179688,200,200'/><node_position Node='-333' Position='753,329,200,200'/><node_position Node='-341' Position='1013.660400390625,391.91161346435547,200,200'/><node_position Node='-289' Position='596,-12,200,200'/><node_position Node='-300' Position='860,-82,200,200'/><node_position Node='-307' Position='871,10,200,200'/><node_position Node='-322' Position='1492.1282958984375,-200.41075134277344,200,200'/><node_position Node='-330' Position='1221.0709228515625,221.4124755859375,200,200'/><node_position Node='-293' Position='465,466,200,200'/><node_position Node='-352' Position='567,-254,200,200'/></node_postions>"},"nodes_readonly":false,"studio_version":"v2"}
    In [33]:
    # 本代码由可视化策略环境自动生成 2022年9月15日 19:58
    # 本代码单元只能在可视化模式下编辑。您也可以拷贝代码,粘贴到新建的代码单元或者策略,然后修改。
    
    
    # 用户的自定义层需要写到字典中,比如
    # {
    #   "MyLayer": MyLayer
    # }
    m6_custom_objects_bigquant_run = {
        
    }
    
    # Python 代码入口函数,input_1/2/3 对应三个输入端,data_1/2/3 对应三个输出端
    def m2_run_bigquant_run(input_1, input_2, input_3):
        # 示例代码如下。在这里编写您的代码
        pred_label = input_1.read_pickle()
        df = input_2.read_df()
        df = pd.DataFrame({'pred_label':pred_label[:,0], 'instrument':df.instrument, 'date':df.date})
        df.sort_values(['date','pred_label'],inplace=True, ascending=[True,False])
        return Outputs(data_1=DataSource.write_df(df), data_2=None, data_3=None)
    
    
    # 后处理函数,可选。输入是主函数的输出,可以在这里对数据做处理,或者返回更友好的outputs数据格式。此函数输出不会被缓存。
    def m2_post_run_bigquant_run(outputs):
        return outputs
    
    # 回测引擎:初始化函数,只执行一次
    def m1_initialize_bigquant_run(context):
        # 加载预测数据
        context.prediction = context.options['data'].read_df()
        
        # 系统已经设置了默认的交易手续费和滑点,要修改手续费可使用如下函数
        context.set_commission(PerOrder(buy_cost=0.0003, sell_cost=0.0013, min_cost=5))
    # 回测引擎:每日数据处理函数,每天执行一次
    def m1_handle_data_bigquant_run(context, data):
        # 按日期过滤得到今日的预测数据
        try:
            prediction = context.prediction[ context.prediction['date']==data.current_dt.strftime('%Y-%m-%d')].pred_label.values[0]
        except KeyError as e:
            return
        
        instrument = context.instruments[0]
        sid = context.symbol(instrument)
        cur_position = context.portfolio.positions[sid].amount
        
        # 交易逻辑
        if prediction > 0.5 and cur_position == 0:
            context.order_target_percent(context.symbol(instrument), 1)
            print(data.current_dt, '买入!')
            
        elif prediction < 0.5 and cur_position > 0:
            context.order_target_percent(context.symbol(instrument), 0)
            print(data.current_dt, '卖出!')
        
    # 回测引擎:准备数据,只执行一次
    def m1_prepare_bigquant_run(context):
        pass
    
    # 回测引擎:每个单位时间开始前调用一次,即每日开盘前调用一次。
    def m1_before_trading_start_bigquant_run(context, data):
        pass
    
    
    g = T.Graph({
    
        'm3': 'M.dl_layer_input.v1',
        'm3.shape': '50,5',
        'm3.batch_shape': '',
        'm3.dtype': 'float32',
        'm3.sparse': False,
        'm3.name': '',
    
        'm13': 'M.dl_layer_reshape.v1',
        'm13.inputs': T.Graph.OutputPort('m3.data'),
        'm13.target_shape': '50,5,1',
        'm13.name': '',
    
        'm14': 'M.dl_layer_conv2d.v1',
        'm14.inputs': T.Graph.OutputPort('m13.data'),
        'm14.filters': 32,
        'm14.kernel_size': '3,5',
        'm14.strides': '1,1',
        'm14.padding': 'valid',
        'm14.data_format': 'channels_last',
        'm14.dilation_rate': '1,1',
        'm14.activation': 'relu',
        'm14.use_bias': True,
        'm14.kernel_initializer': 'glorot_uniform',
        'm14.bias_initializer': 'Zeros',
        'm14.kernel_regularizer': 'None',
        'm14.kernel_regularizer_l1': 0,
        'm14.kernel_regularizer_l2': 0,
        'm14.bias_regularizer': 'None',
        'm14.bias_regularizer_l1': 0,
        'm14.bias_regularizer_l2': 0,
        'm14.activity_regularizer': 'None',
        'm14.activity_regularizer_l1': 0,
        'm14.activity_regularizer_l2': 0,
        'm14.kernel_constraint': 'None',
        'm14.bias_constraint': 'None',
        'm14.name': '',
    
        'm15': 'M.dl_layer_reshape.v1',
        'm15.inputs': T.Graph.OutputPort('m14.data'),
        'm15.target_shape': '48,32',
        'm15.name': '',
    
        'm4': 'M.dl_layer_lstm.v1',
        'm4.inputs': T.Graph.OutputPort('m15.data'),
        'm4.units': 32,
        'm4.activation': 'tanh',
        'm4.recurrent_activation': 'hard_sigmoid',
        'm4.use_bias': True,
        'm4.kernel_initializer': 'glorot_uniform',
        'm4.recurrent_initializer': 'Orthogonal',
        'm4.bias_initializer': 'Ones',
        'm4.unit_forget_bias': True,
        'm4.kernel_regularizer': 'None',
        'm4.kernel_regularizer_l1': 0,
        'm4.kernel_regularizer_l2': 0,
        'm4.recurrent_regularizer': 'None',
        'm4.recurrent_regularizer_l1': 0,
        'm4.recurrent_regularizer_l2': 0,
        'm4.bias_regularizer': 'None',
        'm4.bias_regularizer_l1': 0,
        'm4.bias_regularizer_l2': 0,
        'm4.activity_regularizer': 'None',
        'm4.activity_regularizer_l1': 0,
        'm4.activity_regularizer_l2': 0,
        'm4.kernel_constraint': 'None',
        'm4.recurrent_constraint': 'None',
        'm4.bias_constraint': 'None',
        'm4.dropout': 0,
        'm4.recurrent_dropout': 0,
        'm4.return_sequences': False,
        'm4.implementation': '2',
        'm4.name': '',
    
        'm11': 'M.dl_layer_dropout.v1',
        'm11.inputs': T.Graph.OutputPort('m4.data'),
        'm11.rate': 0.4,
        'm11.noise_shape': '',
        'm11.name': '',
    
        'm10': 'M.dl_layer_dense.v1',
        'm10.inputs': T.Graph.OutputPort('m11.data'),
        'm10.units': 32,
        'm10.activation': 'tanh',
        'm10.use_bias': True,
        'm10.kernel_initializer': 'glorot_uniform',
        'm10.bias_initializer': 'Zeros',
        'm10.kernel_regularizer': 'None',
        'm10.kernel_regularizer_l1': 0,
        'm10.kernel_regularizer_l2': 0,
        'm10.bias_regularizer': 'None',
        'm10.bias_regularizer_l1': 0,
        'm10.bias_regularizer_l2': 0,
        'm10.activity_regularizer': 'None',
        'm10.activity_regularizer_l1': 0,
        'm10.activity_regularizer_l2': 0,
        'm10.kernel_constraint': 'None',
        'm10.bias_constraint': 'None',
        'm10.name': '',
    
        'm12': 'M.dl_layer_dropout.v1',
        'm12.inputs': T.Graph.OutputPort('m10.data'),
        'm12.rate': 0.8,
        'm12.noise_shape': '',
        'm12.name': '',
    
        'm9': 'M.dl_layer_dense.v1',
        'm9.inputs': T.Graph.OutputPort('m12.data'),
        'm9.units': 1,
        'm9.activation': 'sigmoid',
        'm9.use_bias': True,
        'm9.kernel_initializer': 'glorot_uniform',
        'm9.bias_initializer': 'Zeros',
        'm9.kernel_regularizer': 'None',
        'm9.kernel_regularizer_l1': 0,
        'm9.kernel_regularizer_l2': 0,
        'm9.bias_regularizer': 'None',
        'm9.bias_regularizer_l1': 0,
        'm9.bias_regularizer_l2': 0,
        'm9.activity_regularizer': 'None',
        'm9.activity_regularizer_l1': 0,
        'm9.activity_regularizer_l2': 0,
        'm9.kernel_constraint': 'None',
        'm9.bias_constraint': 'None',
        'm9.name': '',
    
        'm5': 'M.dl_model_init.v1',
        'm5.inputs': T.Graph.OutputPort('m3.data'),
        'm5.outputs': T.Graph.OutputPort('m9.data'),
    
        'm8': 'M.input_features.v1',
        'm8.features': """(close_0/close_1-1)*10
    (high_0/high_1-1)*10
    (low_0/low_1-1)*10
    (open_0/open_1-1)*10
    (volume_0/volume_1-1)*10""",
    
        'm24': 'M.instruments.v2',
        'm24.start_date': '2017-06-02',
        'm24.end_date': '2017-10-30',
        'm24.market': 'CN_STOCK_A',
        'm24.instrument_list': '600009.SHA',
        'm24.max_count': 0,
    
        'm21': 'M.advanced_auto_labeler.v2',
        'm21.instruments': T.Graph.OutputPort('m24.data'),
        'm21.label_expr': """# #号开始的表示注释
    # 0. 每行一个,顺序执行,从第二个开始,可以使用label字段
    # 1. 可用数据字段见 https://bigquant.com/docs/develop/datasource/deprecated/history_data.html
    #   添加benchmark_前缀,可使用对应的benchmark数据
    # 2. 可用操作符和函数见 `表达式引擎 <https://bigquant.com/docs/develop/bigexpr/usage.html>`_
    
    # 计算收益:5日收盘价(作为卖出价格)除以明日开盘价(作为买入价格)
    where(shift(close, -10) / close -1>0,1,0)
    
    # 过滤掉一字涨停的情况 (设置label为NaN,在后续处理和训练中会忽略NaN的label)
    where(shift(high, -1) == shift(low, -1), NaN, label)
    """,
        'm21.start_date': '',
        'm21.end_date': '',
        'm21.benchmark': '000300.SHA',
        'm21.drop_na_label': True,
        'm21.cast_label_int': True,
        'm21.user_functions': {},
    
        'm22': 'M.general_feature_extractor.v7',
        'm22.instruments': T.Graph.OutputPort('m24.data'),
        'm22.features': T.Graph.OutputPort('m8.data'),
        'm22.start_date': '',
        'm22.end_date': '',
        'm22.before_start_days': 90,
    
        'm23': 'M.derived_feature_extractor.v3',
        'm23.input_data': T.Graph.OutputPort('m22.data'),
        'm23.features': T.Graph.OutputPort('m8.data'),
        'm23.date_col': 'date',
        'm23.instrument_col': 'instrument',
        'm23.drop_na': False,
        'm23.remove_extra_columns': False,
        'm23.user_functions': {},
    
        'm17': 'M.join.v3',
        'm17.data1': T.Graph.OutputPort('m21.data'),
        'm17.data2': T.Graph.OutputPort('m23.data'),
        'm17.on': 'date',
        'm17.how': 'inner',
        'm17.sort': True,
    
        'm18': 'M.dropnan.v1',
        'm18.input_data': T.Graph.OutputPort('m17.data'),
    
        'm25': 'M.dl_convert_to_bin.v2',
        'm25.input_data': T.Graph.OutputPort('m18.data'),
        'm25.features': T.Graph.OutputPort('m8.data'),
        'm25.window_size': 50,
        'm25.feature_clip': 5,
        'm25.flatten': False,
        'm25.window_along_col': '',
    
        'm6': 'M.dl_model_train.v1',
        'm6.input_model': T.Graph.OutputPort('m5.data'),
        'm6.training_data': T.Graph.OutputPort('m25.data'),
        'm6.optimizer': 'Adam',
        'm6.loss': 'binary_crossentropy',
        'm6.metrics': 'accuracy',
        'm6.batch_size': 2048,
        'm6.epochs': 10,
        'm6.custom_objects': m6_custom_objects_bigquant_run,
        'm6.n_gpus': 1,
        'm6.verbose': '1:输出进度条记录',
    
        'm28': 'M.instruments.v2',
        'm28.start_date': T.live_run_param('trading_date', '2019-02-11'),
        'm28.end_date': T.live_run_param('trading_date', '2019-08-01'),
        'm28.market': 'CN_STOCK_A',
        'm28.instrument_list': '600009.SHA',
        'm28.max_count': 0,
    
        'm16': 'M.general_feature_extractor.v7',
        'm16.instruments': T.Graph.OutputPort('m28.data'),
        'm16.features': T.Graph.OutputPort('m8.data'),
        'm16.start_date': '',
        'm16.end_date': '',
        'm16.before_start_days': 90,
    
        'm26': 'M.derived_feature_extractor.v3',
        'm26.input_data': T.Graph.OutputPort('m16.data'),
        'm26.features': T.Graph.OutputPort('m8.data'),
        'm26.date_col': 'date',
        'm26.instrument_col': 'instrument',
        'm26.drop_na': False,
        'm26.remove_extra_columns': False,
        'm26.user_functions': {},
    
        'm20': 'M.dropnan.v1',
        'm20.input_data': T.Graph.OutputPort('m26.data'),
    
        'm27': 'M.dl_convert_to_bin.v2',
        'm27.input_data': T.Graph.OutputPort('m20.data'),
        'm27.features': T.Graph.OutputPort('m8.data'),
        'm27.window_size': 50,
        'm27.feature_clip': 5,
        'm27.flatten': False,
        'm27.window_along_col': '',
    
        'm7': 'M.dl_model_predict.v1',
        'm7.trained_model': T.Graph.OutputPort('m6.data'),
        'm7.input_data': T.Graph.OutputPort('m27.data'),
        'm7.batch_size': 10240,
        'm7.n_gpus': 0,
        'm7.verbose': '2:每个epoch输出一行记录',
    
        'm2': 'M.cached.v3',
        'm2.input_1': T.Graph.OutputPort('m7.data'),
        'm2.input_2': T.Graph.OutputPort('m20.data'),
        'm2.run': m2_run_bigquant_run,
        'm2.post_run': m2_post_run_bigquant_run,
        'm2.input_ports': '',
        'm2.params': '{}',
        'm2.output_ports': '',
    
        'm1': 'M.trade.v4',
        'm1.instruments': T.Graph.OutputPort('m28.data'),
        'm1.options_data': T.Graph.OutputPort('m2.data_1'),
        'm1.start_date': '',
        'm1.end_date': '',
        'm1.initialize': m1_initialize_bigquant_run,
        'm1.handle_data': m1_handle_data_bigquant_run,
        'm1.prepare': m1_prepare_bigquant_run,
        'm1.before_trading_start': m1_before_trading_start_bigquant_run,
        'm1.volume_limit': 0.025,
        'm1.order_price_field_buy': 'open',
        'm1.order_price_field_sell': 'close',
        'm1.capital_base': 1000000,
        'm1.auto_cancel_non_tradable_orders': True,
        'm1.data_frequency': 'daily',
        'm1.price_type': '真实价格',
        'm1.product_type': '股票',
        'm1.plot_charts': True,
        'm1.backtest_only': False,
        'm1.benchmark': '000300.HIX',
    })
    
    # g.run({})
    
    
    def m19_run_bigquant_run(
        bq_graph,
        inputs,
        trading_days_market='CN', # 使用那个市场的交易日历
        train_instruments_mid='m24', # 训练数据 证券代码列表 模块id
        test_instruments_mid='m28', # 测试数据 证券代码列表 模块id
        predict_mid='m2', # 预测 模块id
        trade_mid='m1', # 回测 模块id
        start_date='2016-01-01', # 数据开始日期
        end_date=T.live_run_param('trading_date', '2018-01-01'), # 数据结束日期
        train_update_days=90, # 更新周期,按交易日计算,每多少天更新一次
        train_update_days_for_live=100, #模拟实盘模式下的更新周期,按交易日计算,每多少天更新一次。如果需要在模拟实盘阶段使用不同的模型更新周期,可以设置这个参数
        train_data_min_days=100, # 最小数据天数,按交易日计算,所以第一个滚动的结束日期是 从开始日期到开始日期+最小数据天数
        train_data_max_days=100, # 最大数据天数,按交易日计算,0,表示没有限制,否则每一个滚动的开始日期=max(此滚动的结束日期-最大数据天数, 开始日期
        rolling_count_for_live=1, #实盘模式下滚动次数,模拟实盘模式下,取最后多少次滚动。一般在模拟实盘模式下,只用到最后一次滚动训练的模型,这里可以设置为1;如果你的滚动训练数据时间段很短,以至于期间可能没有训练数据,这里可以设置大一点。0表示没有限制
    ):
        def merge_datasources(input_1):
            df_list = [ds.read_df() for ds in input_1]
            df = pd.concat(df_list)
            instrument_data = {
                'start_date': df['date'].min().strftime('%Y-%m-%d'),
                'end_date': df['date'].max().strftime('%Y-%m-%d'),
                'instruments': list(set(df['instrument'])),
            }
            return Outputs(data=DataSource.write_df(df), instrument_data=DataSource.write_pickle(instrument_data))
    
        def gen_rolling_dates(trading_days_market, start_date, end_date, train_update_days, train_update_days_for_live, train_data_min_days, train_data_max_days, rolling_count_for_live):
            # 是否实盘模式
            tdays = list(D.trading_days(market=trading_days_market, start_date=start_date, end_date=end_date)['date'])
            is_live_run = T.live_run_param('trading_date', None) is not None
    
            if is_live_run and train_update_days_for_live:
                train_update_days = train_update_days_for_live
    
            rollings = []
            train_end_date = train_data_min_days
            while train_end_date < len(tdays):
                if train_data_max_days is not None:
                    train_start_date = max(train_end_date - train_data_max_days, 0)
                else:
                    train_start_date = start_date
                rollings.append({
                    'train_start_date': tdays[train_start_date].strftime('%Y-%m-%d'),
                    'train_end_date': tdays[train_end_date - 1].strftime('%Y-%m-%d'),
                    'test_start_date': tdays[train_end_date].strftime('%Y-%m-%d'),
                    'test_end_date': tdays[min(train_end_date + train_update_days, len(tdays)) - 1].strftime('%Y-%m-%d'),
                })
                train_end_date += train_update_days
    
            if not rollings:
                raise Exception('没有滚动需要执行,请检查配置')
    
            if is_live_run and rolling_count_for_live:
                rollings = rollings[-rolling_count_for_live:]
    
            return rollings
    
        g = bq_graph
    
        rolling_dates = gen_rolling_dates(
            trading_days_market, start_date, end_date, train_update_days, train_update_days_for_live, train_data_min_days, train_data_max_days, rolling_count_for_live)
    
        # 训练和预测
        results = []
        for rolling in rolling_dates:
            parameters = {}
            # 先禁用回测
            parameters[trade_mid + '.__enabled__'] = False
            parameters[train_instruments_mid + '.start_date'] = rolling['train_start_date']
            parameters[train_instruments_mid + '.end_date'] = rolling['train_end_date']
            parameters[test_instruments_mid + '.start_date'] = rolling['test_start_date']
            parameters[test_instruments_mid + '.end_date'] = rolling['test_end_date']
            # print('------ rolling_train:', parameters)
            results.append(g.run(parameters))
    
        # 合并预测结果并回测
        mx = M.cached.v3(run=merge_datasources, input_1=[result[predict_mid].data_1 for result in results])
        parameters = {}
        parameters['*.__enabled__'] = False
        parameters[trade_mid + '.__enabled__'] = True
        parameters[trade_mid + '.instruments'] = mx.instrument_data
        parameters[trade_mid + '.options_data'] = mx.data
    
        trade = g.run(parameters)
    
        return {'rollings': results, 'trade': trade}
    
    m19 = M.hyper_rolling_train.v1(
        run=m19_run_bigquant_run,
        run_now=True,
        bq_graph=g
    )
    
    DataSource(4ce1c441fb9d43caac20c9d6c87f9ecbT)
    
    DataSource(65cc6a79ecc34578973f15df22ad78bdT)
    
    Epoch 1/10
    1/1 [==============================] - ETA: 0s - loss: 1.0234 - accuracy: 0.48001/1 [==============================] - 4s 4s/step - loss: 1.0234 - accuracy: 0.4800
    Epoch 2/10
    1/1 [==============================] - ETA: 0s - loss: 1.0514 - accuracy: 0.47001/1 [==============================] - 0s 144ms/step - loss: 1.0514 - accuracy: 0.4700
    Epoch 3/10
    1/1 [==============================] - ETA: 0s - loss: 0.8765 - accuracy: 0.53001/1 [==============================] - 0s 138ms/step - loss: 0.8765 - accuracy: 0.5300
    Epoch 4/10
    1/1 [==============================] - ETA: 0s - loss: 1.0460 - accuracy: 0.44001/1 [==============================] - 0s 142ms/step - loss: 1.0460 - accuracy: 0.4400
    Epoch 5/10
    1/1 [==============================] - ETA: 0s - loss: 1.0117 - accuracy: 0.47001/1 [==============================] - 0s 123ms/step - loss: 1.0117 - accuracy: 0.4700
    Epoch 6/10
    1/1 [==============================] - ETA: 0s - loss: 0.8873 - accuracy: 0.54001/1 [==============================] - 0s 128ms/step - loss: 0.8873 - accuracy: 0.5400
    Epoch 7/10
    1/1 [==============================] - ETA: 0s - loss: 0.8474 - accuracy: 0.57001/1 [==============================] - 0s 118ms/step - loss: 0.8474 - accuracy: 0.5700
    Epoch 8/10
    1/1 [==============================] - ETA: 0s - loss: 0.9562 - accuracy: 0.47001/1 [==============================] - 0s 108ms/step - loss: 0.9562 - accuracy: 0.4700
    Epoch 9/10
    1/1 [==============================] - ETA: 0s - loss: 1.1646 - accuracy: 0.42001/1 [==============================] - 0s 130ms/step - loss: 1.1646 - accuracy: 0.4200
    Epoch 10/10
    1/1 [==============================] - ETA: 0s - loss: 0.9333 - accuracy: 0.49001/1 [==============================] - 0s 144ms/step - loss: 0.9333 - accuracy: 0.4900
    
    1/1 - 0s
    DataSource(86fe2e6f95144daf9b3176c103e1c890T)
    
    DataSource(2fa617758e6d477ca2c786c4db44da15T)
    
    DataSource(970e6085389a4e86bbf46016a4fe2897T)
    
    2017-03-01 15:00:00+00:00 买入!
    
    • 收益率64.9%
    • 年化收益率32.33%
    • 基准收益率32.1%
    • 阿尔法0.27
    • 贝塔0.27
    • 夏普比率1.32
    • 胜率1.0
    • 盈亏比0.0
    • 收益波动率20.5%
    • 信息比率0.04
    • 最大回撤11.53%
    bigcharts-data-start/{"__type":"tabs","__id":"bigchart-56c84c930cf64eeaa3e81d5db6d0c3f2"}/bigcharts-data-end