版本 v1.0
### 深度学习策略的交易规则
### 策略构建步骤
### 策略的实现
在画布左侧模块列表中依次拖入输入层模块、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之间的连续值,可以认为是上涨的概率。
如果当日预测的上涨概率大于0.5,则保持持仓或买入
如果当日预测的上涨概率小于0.5,则卖出股票或保持空仓。
通过 trade 模块中的初始化函数定义交易手续费和滑点,通过 context.prediction 获取每日的上涨概率预测结果;
通过 trade 模块中的主函数(handle函数)查看每日的买卖交易信号,按照买卖原则执行相应的买入/卖出操作。
可视化策略实现如下:
# 本代码由可视化策略环境自动生成 2022年6月3日 10:48
# 本代码单元只能在可视化模式下编辑。您也可以拷贝代码,粘贴到新建的代码单元或者策略,然后修改。
# 用户的自定义层需要写到字典中,比如
# {
# "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):
test_data = input_2.read_pickle()
pred_label = input_1.read_pickle()
pred_result = pred_label.reshape(pred_label.shape[0])
dt = input_3.read_df()['date'][-1*len(pred_result):]
pred_df = pd.Series(pred_result, index=dt)
ds = DataSource.write_df(pred_df)
return Outputs(data_1=ds)
# 后处理函数,可选。输入是主函数的输出,可以在这里对数据做处理,或者返回更友好的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[data.current_dt.strftime('%Y-%m-%d')]
except KeyError as e:
return
instrument = context.instruments[0]
sid = context.symbol(instrument)
cur_position = context.portfolio.positions[sid].amount
#获取当日日期
today = data.current_dt.strftime('%Y-%m-%d')
stock_hold_now = [equity.symbol for equity in context.portfolio.positions ]
#大盘风控模块,读取风控数据
benckmark_risk=context.benckmark_risk[today]
context.symbol
#当risk为1时,市场有风险,全部平仓,不再执行其它操作
if benckmark_risk > 0:
for instrument in stock_hold_now:
context.order_target(symbol(instrument), 0)
print(today,'大盘风控止损触发,全仓卖出')
return
# 交易逻辑
if prediction > 0.52:
context.order_target_percent(context.symbol(instrument), 1)
print(data.current_dt, '买入!')
elif prediction < 0.48 and cur_position > 0:
context.order_target_percent(context.symbol(instrument), 0)
print(data.current_dt, '卖出!')
# 回测引擎:准备数据,只执行一次
def m1_prepare_bigquant_run(context):
#在数据准备函数中一次性计算每日的大盘风控条件相比于在handle中每日计算风控条件可以提高回测速度
# 多取50天的数据便于计算均值(保证回测的第一天均值不为Nan值),其中context.start_date和context.end_date是回测指定的起始时间和终止时间
start_date= (pd.to_datetime(context.start_date) - datetime.timedelta(days=50)).strftime('%Y-%m-%d')
df=DataSource('bar1d_index_CN_STOCK_A').read(start_date=start_date,end_date=context.end_date,fields=['close'])
benckmark_data=df[df.instrument=='000001.HIX']
#计算上证指数5日涨幅
benckmark_data['ret5']=benckmark_data['close']/benckmark_data['close'].shift(5)-1
#计算大盘风控条件,如果5日涨幅小于-4%则设置风险状态risk为1,否则为0
benckmark_data['risk'] = np.where(benckmark_data['ret5']<-0.04,1,0)
#修改日期格式为字符串(便于在handle中使用字符串日期索引来查看每日的风险状态)
benckmark_data['date']=benckmark_data['date'].apply(lambda x:x.strftime('%Y-%m-%d'))
#设置日期为索引
benckmark_data.set_index('date',inplace=True)
#把风控序列输出给全局变量context.benckmark_risk
context.benckmark_risk=benckmark_data['risk']
# 回测引擎:每个单位时间开始前调用一次,即每日开盘前调用一次。
def m1_before_trading_start_bigquant_run(context, data):
pass
m3 = M.dl_layer_input.v1(
shape='50,5',
batch_shape='',
dtype='float32',
sparse=False,
name=''
)
m13 = M.dl_layer_reshape.v1(
inputs=m3.data,
target_shape='50,5,1',
name=''
)
m14 = M.dl_layer_conv2d.v1(
inputs=m13.data,
filters=32,
kernel_size='3,5',
strides='1,1',
padding='valid',
data_format='channels_last',
dilation_rate='1,1',
activation='relu',
use_bias=True,
kernel_initializer='glorot_uniform',
bias_initializer='Zeros',
kernel_regularizer='L1L2',
kernel_regularizer_l1=0,
kernel_regularizer_l2=0,
bias_regularizer='L1L2',
bias_regularizer_l1=0,
bias_regularizer_l2=0,
activity_regularizer='L1L2',
activity_regularizer_l1=0,
activity_regularizer_l2=0,
kernel_constraint='min_max_norm',
bias_constraint='min_max_norm',
name=''
)
m15 = M.dl_layer_reshape.v1(
inputs=m14.data,
target_shape='48,32',
name=''
)
m4 = M.dl_layer_lstm.v1(
inputs=m15.data,
units=32,
activation='tanh',
recurrent_activation='hard_sigmoid',
use_bias=True,
kernel_initializer='glorot_uniform',
recurrent_initializer='Orthogonal',
bias_initializer='Ones',
unit_forget_bias=True,
kernel_regularizer='None',
kernel_regularizer_l1=0,
kernel_regularizer_l2=0,
recurrent_regularizer='None',
recurrent_regularizer_l1=0,
recurrent_regularizer_l2=0,
bias_regularizer='None',
bias_regularizer_l1=0,
bias_regularizer_l2=0,
activity_regularizer='None',
activity_regularizer_l1=0,
activity_regularizer_l2=0,
kernel_constraint='None',
recurrent_constraint='None',
bias_constraint='None',
dropout=0,
recurrent_dropout=0,
return_sequences=False,
implementation='2',
name=''
)
m11 = M.dl_layer_dropout.v1(
inputs=m4.data,
rate=0.3,
noise_shape='',
name=''
)
m10 = M.dl_layer_dense.v1(
inputs=m11.data,
units=32,
activation='tanh',
use_bias=True,
kernel_initializer='glorot_uniform',
bias_initializer='Zeros',
kernel_regularizer='None',
kernel_regularizer_l1=0,
kernel_regularizer_l2=0,
bias_regularizer='None',
bias_regularizer_l1=0,
bias_regularizer_l2=0,
activity_regularizer='None',
activity_regularizer_l1=0,
activity_regularizer_l2=0,
kernel_constraint='None',
bias_constraint='None',
name=''
)
m12 = M.dl_layer_dropout.v1(
inputs=m10.data,
rate=0.3,
noise_shape='',
name=''
)
m9 = M.dl_layer_dense.v1(
inputs=m12.data,
units=1,
activation='sigmoid',
use_bias=True,
kernel_initializer='glorot_uniform',
bias_initializer='Zeros',
kernel_regularizer='None',
kernel_regularizer_l1=0,
kernel_regularizer_l2=0,
bias_regularizer='None',
bias_regularizer_l1=0,
bias_regularizer_l2=0,
activity_regularizer='None',
activity_regularizer_l1=0,
activity_regularizer_l2=0,
kernel_constraint='None',
bias_constraint='None',
name=''
)
m5 = M.dl_model_init.v1(
inputs=m3.data,
outputs=m9.data
)
m8 = M.input_features.v1(
features="""(close_0/close_1-1)*10
(high_0/high_1-1)*10
(low_0/low_1-1)*10
low_1
low_0
(open_0/open_1-1)*10
(volume_0/volume_1-1)*10
fs_fixed_assets_0
industry_sw_level1_0
fs_fixed_assets_disp_0
market_cap_float_0"""
)
m28 = M.instruments.v2(
start_date=T.live_run_param('trading_date', '2019-06-02'),
end_date=T.live_run_param('trading_date', '2022-06-02'),
market='CN_STOCK_A',
instrument_list='',
max_count=0
)
m16 = M.general_feature_extractor.v7(
instruments=m28.data,
features=m8.data,
start_date='',
end_date='',
before_start_days=0
)
m26 = M.derived_feature_extractor.v3(
input_data=m16.data,
features=m8.data,
date_col='date',
instrument_col='instrument',
drop_na=True,
remove_extra_columns=True,
user_functions={}
)
m29 = M.chinaa_stock_filter.v1(
input_data=m26.data,
index_constituent_cond=['全部'],
board_cond=['全部'],
industry_cond=['全部'],
st_cond=['正常'],
delist_cond=['非退市'],
output_left_data=True
)
m31 = M.winsorize.v6(
input_data=m29.data,
columns_input='fs_fixed_assets_0',
median_deviate=3
)
m33 = M.standardlize.v9(
input_1=m31.data,
standard_func='ZScoreNorm',
columns_input='fs_fixed_assets_0'
)
m37 = M.filter.v3(
input_data=m33.data,
expr='fs_fixed_assets_0-fs_fixed_assets_disp_0>0',
output_left_data=True
)
m20 = M.dropnan.v1(
input_data=m37.data
)
m27 = M.dl_convert_to_bin.v2(
input_data=m20.data,
features=m8.data,
window_size=50,
feature_clip=5,
flatten=False,
window_along_col=''
)
m24 = M.instruments.v2(
start_date='2013-01-01',
end_date='2019-06-2',
market='CN_STOCK_A',
instrument_list='',
max_count=0
)
m22 = M.general_feature_extractor.v7(
instruments=m24.data,
features=m8.data,
start_date='',
end_date='',
before_start_days=0
)
m23 = M.derived_feature_extractor.v3(
input_data=m22.data,
features=m8.data,
date_col='date',
instrument_col='instrument',
drop_na=True,
remove_extra_columns=True,
user_functions={}
)
m19 = M.chinaa_stock_filter.v1(
input_data=m23.data,
index_constituent_cond=['全部'],
board_cond=['全部'],
industry_cond=['全部'],
st_cond=['正常'],
delist_cond=['非退市'],
output_left_data=True
)
m30 = M.winsorize.v6(
input_data=m19.data,
columns_input='fs_fixed_assets_0',
median_deviate=3
)
m32 = M.standardlize.v9(
input_1=m30.data,
standard_func='ZScoreNorm',
columns_input='fs_fixed_assets_0'
)
m34 = M.neutralize.v12(
input_1=m32.data,
market_value_key=False,
industry_output_key=False,
market_col_name='market_cap_float_0',
industry_sw_col_name='industry_sw_level1_0'
)
m36 = M.filter.v3(
input_data=m34.data,
expr='fs_fixed_assets_0-fs_fixed_assets_disp_0>0',
output_left_data=True
)
m18 = M.dropnan.v1(
input_data=m36.data
)
m25 = M.dl_convert_to_bin.v2(
input_data=m18.data,
features=m8.data,
window_size=50,
feature_clip=5,
flatten=False,
window_along_col=''
)
m6 = M.dl_model_train.v1(
input_model=m5.data,
training_data=m25.data,
optimizer='Adam',
loss='binary_crossentropy',
metrics='accuracy',
batch_size=2048,
epochs=50,
custom_objects=m6_custom_objects_bigquant_run,
n_gpus=1,
verbose='2:每个epoch输出一行记录'
)
m7 = M.dl_model_predict.v1(
trained_model=m6.data,
input_data=m27.data,
batch_size=10240,
n_gpus=0,
verbose='1:输出进度条记录'
)
m2 = M.cached.v3(
input_1=m7.data,
input_2=m27.data,
input_3=m20.data,
run=m2_run_bigquant_run,
post_run=m2_post_run_bigquant_run,
input_ports='',
params='{}',
output_ports=''
)
m1 = M.trade.v4(
instruments=m28.data,
options_data=m2.data_1,
start_date='',
end_date='',
initialize=m1_initialize_bigquant_run,
handle_data=m1_handle_data_bigquant_run,
prepare=m1_prepare_bigquant_run,
before_trading_start=m1_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'
)
[2022-06-03 10:40:52.686983] INFO: moduleinvoker: dl_layer_input.v1 运行完成[0.061819s].
[2022-06-03 10:40:52.910105] INFO: moduleinvoker: dl_layer_reshape.v1 运行完成[0.119771s].
[2022-06-03 10:40:53.015958] INFO: moduleinvoker: dl_layer_conv2d.v1 运行完成[0.074482s].
[2022-06-03 10:40:53.127428] INFO: moduleinvoker: dl_layer_reshape.v1 运行完成[0.078536s].
[2022-06-03 10:40:53.618760] INFO: moduleinvoker: dl_layer_lstm.v1 运行完成[0.415089s].
[2022-06-03 10:40:53.690747] INFO: moduleinvoker: dl_layer_dropout.v1 运行完成[0.008547s].
[2022-06-03 10:40:53.744546] INFO: moduleinvoker: dl_layer_dense.v1 运行完成[0.031965s].
[2022-06-03 10:40:53.775738] INFO: moduleinvoker: dl_layer_dropout.v1 运行完成[0.008652s].
[2022-06-03 10:40:53.826627] INFO: moduleinvoker: dl_layer_dense.v1 运行完成[0.02349s].
[2022-06-03 10:40:53.976668] INFO: moduleinvoker: cached.v3 开始运行..
[2022-06-03 10:40:54.070732] INFO: moduleinvoker: cached.v3 运行完成[0.094082s].
[2022-06-03 10:40:54.076851] INFO: moduleinvoker: dl_model_init.v1 运行完成[0.236257s].
[2022-06-03 10:40:54.103223] INFO: moduleinvoker: input_features.v1 开始运行..
[2022-06-03 10:40:54.112454] INFO: moduleinvoker: 命中缓存
[2022-06-03 10:40:54.115908] INFO: moduleinvoker: input_features.v1 运行完成[0.012689s].
[2022-06-03 10:40:54.130197] INFO: moduleinvoker: instruments.v2 开始运行..
[2022-06-03 10:40:54.162035] INFO: moduleinvoker: 命中缓存
[2022-06-03 10:40:54.167076] INFO: moduleinvoker: instruments.v2 运行完成[0.036895s].
[2022-06-03 10:40:54.260828] INFO: moduleinvoker: general_feature_extractor.v7 开始运行..
[2022-06-03 10:40:54.307064] INFO: moduleinvoker: 命中缓存
[2022-06-03 10:40:54.309443] INFO: moduleinvoker: general_feature_extractor.v7 运行完成[0.048885s].
[2022-06-03 10:40:54.364092] INFO: moduleinvoker: derived_feature_extractor.v3 开始运行..
[2022-06-03 10:40:54.381157] INFO: moduleinvoker: 命中缓存
[2022-06-03 10:40:54.383936] INFO: moduleinvoker: derived_feature_extractor.v3 运行完成[0.019858s].
[2022-06-03 10:40:54.411370] INFO: moduleinvoker: chinaa_stock_filter.v1 开始运行..
[2022-06-03 10:40:54.440799] INFO: moduleinvoker: 命中缓存
[2022-06-03 10:40:54.445365] INFO: moduleinvoker: chinaa_stock_filter.v1 运行完成[0.033991s].
[2022-06-03 10:40:54.477495] INFO: moduleinvoker: winsorize.v6 开始运行..
[2022-06-03 10:40:54.503009] INFO: moduleinvoker: 命中缓存
[2022-06-03 10:40:54.505905] INFO: moduleinvoker: winsorize.v6 运行完成[0.028399s].
[2022-06-03 10:40:54.572094] INFO: moduleinvoker: standardlize.v9 开始运行..
[2022-06-03 10:40:54.587933] INFO: moduleinvoker: 命中缓存
[2022-06-03 10:40:54.591477] INFO: moduleinvoker: standardlize.v9 运行完成[0.019382s].
[2022-06-03 10:40:54.660084] INFO: moduleinvoker: filter.v3 开始运行..
[2022-06-03 10:40:54.681759] INFO: moduleinvoker: 命中缓存
[2022-06-03 10:40:54.684058] INFO: moduleinvoker: filter.v3 运行完成[0.023982s].
[2022-06-03 10:40:54.778251] INFO: moduleinvoker: dropnan.v1 开始运行..
[2022-06-03 10:40:54.796767] INFO: moduleinvoker: 命中缓存
[2022-06-03 10:40:54.811945] INFO: moduleinvoker: dropnan.v1 运行完成[0.033684s].
[2022-06-03 10:40:54.943207] INFO: moduleinvoker: dl_convert_to_bin.v2 开始运行..
[2022-06-03 10:40:55.061589] INFO: moduleinvoker: 命中缓存
[2022-06-03 10:40:55.068384] INFO: moduleinvoker: dl_convert_to_bin.v2 运行完成[0.125192s].
[2022-06-03 10:40:55.089051] INFO: moduleinvoker: instruments.v2 开始运行..
[2022-06-03 10:40:55.100690] INFO: moduleinvoker: 命中缓存
[2022-06-03 10:40:55.103182] INFO: moduleinvoker: instruments.v2 运行完成[0.014108s].
[2022-06-03 10:40:55.187526] INFO: moduleinvoker: general_feature_extractor.v7 开始运行..
[2022-06-03 10:40:55.207389] INFO: moduleinvoker: 命中缓存
[2022-06-03 10:40:55.218881] INFO: moduleinvoker: general_feature_extractor.v7 运行完成[0.03134s].
[2022-06-03 10:40:55.256822] INFO: moduleinvoker: derived_feature_extractor.v3 开始运行..
[2022-06-03 10:40:55.276413] INFO: moduleinvoker: 命中缓存
[2022-06-03 10:40:55.278782] INFO: moduleinvoker: derived_feature_extractor.v3 运行完成[0.021964s].
[2022-06-03 10:40:55.375794] INFO: moduleinvoker: chinaa_stock_filter.v1 开始运行..
[2022-06-03 10:40:55.419650] INFO: moduleinvoker: 命中缓存
[2022-06-03 10:40:55.422840] INFO: moduleinvoker: chinaa_stock_filter.v1 运行完成[0.047097s].
[2022-06-03 10:40:55.482226] INFO: moduleinvoker: winsorize.v6 开始运行..
[2022-06-03 10:40:55.495401] INFO: moduleinvoker: 命中缓存
[2022-06-03 10:40:55.497903] INFO: moduleinvoker: winsorize.v6 运行完成[0.015673s].
[2022-06-03 10:40:55.545508] INFO: moduleinvoker: standardlize.v9 开始运行..
[2022-06-03 10:40:55.578285] INFO: moduleinvoker: 命中缓存
[2022-06-03 10:40:55.581832] INFO: moduleinvoker: standardlize.v9 运行完成[0.036198s].
[2022-06-03 10:40:55.663177] INFO: moduleinvoker: filter.v3 开始运行..
[2022-06-03 10:40:55.804090] INFO: filter: 使用表达式 fs_fixed_assets_0-fs_fixed_assets_disp_0>0 过滤
[2022-06-03 10:40:59.638763] INFO: filter: 过滤 /data, 35240/431507/466747
[2022-06-03 10:40:59.707706] INFO: moduleinvoker: filter.v3 运行完成[4.0445s].
[2022-06-03 10:40:59.723373] INFO: moduleinvoker: dropnan.v1 开始运行..
[2022-06-03 10:41:00.253530] INFO: dropnan: /data, 35240/35240
[2022-06-03 10:41:00.423353] INFO: dropnan: 行数: 35240/35240
[2022-06-03 10:41:00.443897] INFO: moduleinvoker: dropnan.v1 运行完成[0.720513s].
[2022-06-03 10:41:00.489725] INFO: moduleinvoker: dl_convert_to_bin.v2 开始运行..
[2022-06-03 10:41:30.698696] INFO: moduleinvoker: dl_convert_to_bin.v2 运行完成[30.208972s].
[2022-06-03 10:41:30.934153] INFO: moduleinvoker: dl_model_train.v1 开始运行..
[2022-06-03 10:41:32.237715] INFO: dl_model_train: 准备训练,训练样本个数:35240,迭代次数:50
[2022-06-03 10:41:32.247048] ERROR: moduleinvoker: module name: dl_model_train, module version: v1, trackeback: KeyError: 'y'