A股实践 :图神经网络与新闻共现矩阵手段(附代码)
发布时间:2023-02-24
基于Qlib的方法论系统性
Qlib是开发者技术开发的开源AI取样基本概念。该平台以机器求讲授在取样数据系统性的运用为当前,整合了类似数据下载、类似数据预处理、机器求讲授外推及回测和方针高度评价的均方式则上。Qlib基本概念之前有很多仍然充分利用的机器求讲授静态,其之前就包含GATs静态。该静态的基本基本概念如下:
可用类似数据:为某股份池(后续方法论运用于沪深300成分股)每个股份现在158个技术量化的历史文化星期脱氧核糖核酸作为并不相同之处类似数据。这158个技术量化是Qlib外设的常用的技术量化。每个专业训练的比对为一只股份158个并不相同之处现在N天的历史文化类似数据上有的等价。
一个batch的上述星期脱氧核糖核酸类似数据首先可用到LSTM静态给予 ,即LSTM在最后一个时刻T的隐藏状态并不相同之处。这一层主要运用于LSTM捕捉脱氧核糖核酸曾一度不确定性,求讲授股份的星期脱氧核糖核酸并不相同之处。
GAT层:GAT层的当前是建起可以说明了股份在在关联人关系的静态,Qlib之前充分利用的GAT引入有序自视线必要,这种方式则不必需借助于详述了的股份人关系由此可知,而是对每个路由推算是其与其他所有路由的益处,日后基准生成其他路由的并不相同之处。在上一层LSTM求讲授到每个股份的星期脱氧核糖核酸并不相同之处后,这些并不相同之处作为这个由此可知之前每个路由的类型,并通过视线必要生成其他路由的类型,并可用到非新线性介导层,从而达到求讲授整个由此可知结构设计的便是比如说。
得出最大限度:在Qlib充分利用的GATs静态之前,得出最大限度为t+2日与t+1日定价推算是的利息率,而巨大损失变量则搭配的最非常简单的MSE变量。
以上为Qlib之前充分利用的基于由此可知视线网络服务GAT充分利用的股份利息外推,其在借助于由此可知网络服务的处理过程之前,并没有考量股份在在的显性人关系。在最早提议GAT的科讲授论文之前,作者只考量了有详述了由此可知人关系的路由在在通告的传递,这样的方式则称为Masked Self-Attention,即只推算是南边路由在在的视线下式。基于这个语义,我们在Qlib已充分利用的GATs静态之前过渡到基于新闻网共现的详述了由此可知人关系,并测试在之后方针运用技术性详述了由此可知人关系过渡到后静态真实感是否有提升。
借助于新闻网共现等价
我们基于数库科技提供的SmarTag新闻网系统性类似数据借助于新闻网共现等价,这个等价作为南边阶等价传布GAT静态之前。我们运用于SmarTag类似数据之前的股份ID同上(news_compnay_label同上),新闻网类似数据的跨度为2017年1翌年1日至2022年3翌年1日,其类似数据结构设计如下由此可知ID类似除此以外简述:
我们首先以每个停牌下午早先为整块星期,把收盘后的新闻网算是好好下一停牌的新闻网,这样就可以把年历日映射到停牌,然后在基于一般而言字符串推算是每个停牌的股份共现等价:
importpandas aspd
fromjoblib importParallel
defget_coc_dt(news_data, dt):
temp = news_data.query( "trade_date==@dt").reset_index(drop= True)
temp[ 'cnt'] = 1
coc_df = temp.pivot_table(index= 'news_id', columns= 'sec_code', values= 'cnt').fillna( 0)
coc_mat, coc_codes = coc_df.values, coc_df.columns.tolist
adj_mat = coc_mat.T.dot(coc_mat)
adj_df = pd.DataFrame(data=adj_mat, index=coc_codes , columns=coc_codes ).replace( 0, np.nan).unstack.dropna
return(dt, adj_df)
defget_coc_all(news_data):
all_dts_str = [str(dt) fordt innews_data[ 'trade_date'].dt.date.unique]
coc_all_lst = Parallel(n_jobs= 5)(delayed(get_coc_dt)(com_senti_fil, dt) fordt intqdm(all_dts_str))
returncoc_all_lst
由于共现等价非常均匀分布,如果直接留有等价将浪费大量空在在与效率,所以我们运用于多重书目的Series留有每日的股份共现类似数据,并删除空值记录。
每日的股份共现情况下转变现在频繁,我们对每日的共现等价推算是20日的净资产基准回转概率分布,这样既能一个系统凸显共现人关系的推移,也能使类似数据转变平稳。由于我们仅必需沪深300的共现等价,所以必需从原先均A的记录之前软性出沪深300的每日共现等价,然后推算是回转概率分布:
fromcollections importOrderDict
# 一般而言字符串之前csi300_sec_code为沪深300所有历史文化成分股的字符串列同上
coc_all_lst = get_coc_all(news_data)
fordt, coc_mat incoc_all_lst:
temp = coc_mat.unstack.reindex(csi300_sec_code).T.reindex(csi300_sec_code)
csi300_coc_dct[dt] = temp.unstack.dropna
# 推算是共现等价回转概率分布(净资产基准,半衰为10),以{dt: Series}的PDF留有,
# 一般而言字符串只是作为示例,我们之后是在GATs当前充分利用的
df_csi300 = pd.concat(csi300_coc_dct.values, keys=csi300_coc_dct.keys, axis= 1).fillna( 0)
coc_ewa_csi300 = df_csi300.ewm(halflife= 10, min_periods= 1, axis= 1).mean
coc_ewa_csi300 = coc_ewa_csi300.where(coc_ewa_csi300>= 0.25, np.nan) # 软性共现短时间概率分布极小0.25的记录
coc_ewa_csi300_dct = OrderedDict
forcol incoc_ewa_csi300:
coc_ewa_csi300_dct[col] = coc_ewa_csi300[col].dropna
一般而言就是共现等价的示例类似数据,总结借助于处理过程就是基于日度新闻网之前股份共现的类似数据,按10日半衰推算是净资产漂移概率分布,并软性上来数值极小0.25的记录:
简化Qlib外设GATs字符串,过渡到新闻网共现等价
Qlib外设的GATs静态在一般而言梯度:qlib.contrib.model.pytorch_gats_ts之前的GATModel,这个静态之前没有运用于显性的由此可知结构设计类似数据,我们必需好好以简化,主要分一般而言两个流程:
1、在GATModel之前过渡到南边接等价,简化后的字符串如下,主要推移在cal_attention变量里,在47行attenion_out经非新线性介导变量leaky_relu介导后,并没有直接可用到softmax展开均值归一,而是运用于南边接等价adj将adj之前记录总和0的路由的视线均值软性上来(新设零),然后在经softmax展开均值归一。
2、我们还过渡到了由此可知结构设计之前的dropout层,给定为gat_dropout,用于对由此可知视线之前的均值随机dropout,提升静态稳健性。
classGATModel(nn.Module):
def短时init短时(self, d_feat= 6, hidden_size= 64, num_layers= 2, lstm_dropout= 0.0, gat_dropout= 0.0, base_model= "GRU") :
super.短时init短时
ifbase_model == "GRU":
self.rnn = nn.GRU(
input_size=d_feat,
hidden_size=hidden_size,
num_layers=num_layers,
batch_first= True,
dropout=lstm_dropout,
)
elifbase_model == "LSTM":
self.rnn = nn.LSTM(
input_size=d_feat,
hidden_size=hidden_size,
num_layers=num_layers,
batch_first= True,
dropout=lstm_dropout,
)
else:
raiseValueError( "unknown base model name MLT-%sMLT-"% base_model)
self.hidden_size = hidden_size
self.d_feat = d_feat
self.transformation = nn.Linear(self.hidden_size, self.hidden_size)
self.a = nn.Parameter(torch.randn(self.hidden_size * 2, 1))
self.a.requires_grad = True
self.fc = nn.Linear(self.hidden_size, self.hidden_size)
self.fc_out = nn.Linear(hidden_size, 1)
self.leaky_relu = nn.LeakyReLU
self.softmax = nn.Softmax(dim= 1)
self.dropout = nn.Dropout(gat_dropout)
defcal_attention(self, x, y, adj):
x = self.transformation(x)
y = self.transformation(y)
sample_num = x.shape[ 0]
dim = x.shape[ 1]
e_x = x.expand(sample_num, sample_num, dim)
e_y = torch.transpose(e_x, 0, 1)
attention_in = torch.cat((e_x, e_y), 2).view( -1, dim * 2)
self.a_t = torch.t(self.a)
attention_out = self.a_t.mm(torch.t(attention_in)).view(sample_num, sample_num)
attention_out = self.leaky_relu(attention_out)
zero_vec = -9e15*torch.ones_like(attention_out)
attention_out = torch.where(adj> 0, attention_out, zero_vec)
att_weight = self.softmax(attention_out)
att_weight = self.dropout(att_weight)
returnatt_weight
defforward(self, x, adj):
out, _ = self.rnn(x)
hidden = out[:, -1, :]
att_weight = self.cal_attention(hidden, hidden, adj)
hidden = att_weight.mm(hidden) + hidden
hidden = self.fc(hidden)
hidden = self.leaky_relu(hidden)
returnself.fc_out(hidden).squeeze
那么我们运用于数库Smartag推算是的详述了由此可知人关系(新闻网共现等价)怎么以给定adj传布GATModel的forward变量之前呢?GATModel是在GATs类的fit系统性方法之前被调用,所以我们只要在GATs初始化的处理过程之前唯取均部历史文化的新闻网共现类似数据,然后在专业训练处理过程之前按照应于和当期的成分股字符串展开唯取即可,简略字符串如下,主要改动的偏远地区有:
1、初始化时唯取均部新闻网共现的历史文化类似数据,load_adj_data变量根据可用的半衰adj_hf和阈值adj_th,推算是净资产漂移基准的新闻网共现等价
2、get_adj_matrix根据给定dt和codes,来到指定应于某两组股份的共现等价,这里有个显然必需注意是,我们把对角等价都用1可用,因为GAT在通告生成时必需再加自身路由的并不相同之处。
3、如何在train的处理过程之前知道当前专业训练类似数据的应于和金融集团?我们可以看到在train_epoch和test_epoch之前我们通过dataloader.dataset.get_index获得了所有专业训练应于及金融集团,这样每次for循序内,我们就可以知道当前专业训练类似数据的应于和金融集团。
classGATs(Model):
adj_path = './csi300_coc_dct.pkl'
"""GATs Model
Parameters
---------------
lr : float
learning rate
d_feat : int
input dimensions for each time step
metric : str
the evaluate metric used in early stop
optimizer : str
optimizer name
GPU : int
the GPU ID used for training
"""
def短时init短时(
self,
adj_hf= 10,
adj_th= 0.2,
d_feat= 20,
hidden_size= 64,
num_layers= 2,
lstm_dropout= 0.0,
gat_dropout= 0.0,
n_epochs= 200,
lr= 0.001,
metric= "",
early_stop= 20,
loss= "mse",
base_model= "GRU",
model_path=None,
optimizer= "adam",
GPU= 0,
n_jobs= 10,
seed=None,
**kwargs
) :
# Set logger.
self.logger = get_module_logger( "GATs")
self.logger.info( "GATs pytorch version...")
# Adj Matirx
self.adj = self.load_adj_data(self.adj_path, adj_hf, adj_th)
# set hyper-parameters.
self.d_feat = d_feat
self.hidden_size = hidden_size
self.num_layers = num_layers
self.lstm_dropout = lstm_dropout
self.gat_dropout = gat_dropout
self.n_epochs = n_epochs
self.lr = lr
self.metric = metric
self.early_stop = early_stop
self.optimizer = optimizer.lower
self.loss = loss
self.base_model = base_model
self.model_path = model_path
self.device = torch.device( "cuda:%d"% (GPU) iftorch.cuda.is_available andGPU>= 0else"cpu")
self.n_jobs = n_jobs
self.seed = seed
self.logger.info(
"GATs parameters setting:"
"d_feat : {}"
"hidden_size : {}"
"num_layers : {}"
"lstm_dropout : {}"
"gat_dropout : {}"
"n_epochs : {}"
"lr : {}"
"metric : {}"
"early_stop : {}"
"optimizer : {}"
"loss_type : {}"
"base_model : {}"
"model_path : {}"
"visible_GPU : {}"
"use_GPU : {}"
"seed : {}".format(
d_feat,
hidden_size,
num_layers,
lstm_dropout,
gat_dropout,
n_epochs,
lr,
metric,
early_stop,
optimizer.lower,
loss,
base_model,
model_path,
GPU,
self.use_gpu,
seed,
)
)
ifself.seed isnotNone:
np.random.seed(self.seed)
torch.manual_seed(self.seed)
self.GAT_model = GATModel(
d_feat=self.d_feat,
hidden_size=self.hidden_size,
num_layers=self.num_layers,
lstm_dropout=self.lstm_dropout,
gat_dropout=self.gat_dropout,
base_model=self.base_model,
)
self.logger.info( "model:{:}".format(self.GAT_model))
self.logger.info( "model size: {:.4f} MB".format(count_parameters(self.GAT_model)))
ifoptimizer.lower == "adam":
self.train_optimizer = optim.Adam(self.GAT_model.parameters, lr=self.lr)
elifoptimizer.lower == "gd":
self.train_optimizer = optim.SGD(self.GAT_model.parameters, lr=self.lr)
else:
raiseNotImplementedError( "optimizer {} is not supported!".format(optimizer))
self.fitted = False
self.GAT_model.to(self.device)
defload_adj_data(self, adj_path, adj_hf, adj_th):
withopen( './csi_coc_mat.pkl', 'rb') asf:
csi300_coc_dct = pickle.load(f)
df_csi300 = pd.concat(csi300_coc_dct.values, keys=csi300_coc_dct.keys, axis= 1).fillna( 0)
coc_ewa_csi300 = df_csi300.ewm(halflife=adj_hf, min_periods= 1, axis= 1).mean
coc_ewa_csi300 = coc_ewa_csi300.where(coc_ewa_csi300>=adj_th, np.nan)
coc_ewa_csi300_dct = OrderedDict
forcol incoc_ewa_csi300:
coc_ewa_csi300_dct[col] = coc_ewa_csi300[col].dropna
returncoc_ewa_csi300_dct
@property
defuse_gpu(self):
returnself.device != torch.device( "cpu")
defmse(self, pred, label):
loss = (pred - label) ** 2
returntorch.mean(loss)
defloss_fn(self, pred, label):
mask = ~torch.isnan(label)
ifself.loss == "mse":
returnself.mse(pred[mask], label[mask])
raiseValueError( "unknown loss MLT-%sMLT-"% self.loss)
defmetric_fn(self, pred, label):
mask = torch.isfinite(label)
ifself.metric in( "", "loss"):
return-self.loss_fn(pred[mask], label[mask])
raiseValueError( "unknown metric MLT-%sMLT-"% self.metric)
defget_daily_inter(self, df, shuffle=False):
# organize the train data into daily batches
daily_count = df.groupby(level= 0).size.values
daily_index = np.roll(np.cumsum(daily_count), 1)
daily_index[ 0] = 0
ifshuffle:
# shuffle data
daily_shuffle = list(zip(daily_index, daily_count))
np.random.shuffle(daily_shuffle)
daily_index, daily_count = zip(*daily_shuffle)
returndaily_index, daily_count
defget_adj_matrix(self, dt, codes):
ifnotisinstance(dt, str):
dt_str = str(dt.date)
else:
dt_str = dt
res = self.adj.get(dt_str).unstack
res = res.reindex(codes).T.reindex(codes)
fill_df = pd.DataFrame(np.diag(np.ones(len(res))[np.newaxis:]), index=res.index, columns=res.columns)
res = res.combine_first(fill_df)
adj = torch.FloatTensor(res.values)
returnadj.to(self.device)
deftrain_epoch(self, data_loader):
self.GAT_model.train
idx = data_loader.dataset.get_index
dts = idx.get_level_values( 0).unique.tolist
codes_idx = idx.get_level_values( 1)
i = 0
fordata indata_loader:
codes = codes_idx[idx.get_loc(dts[i])].tolist
adj = self.get_adj_matrix(dts[i], codes)
data = data.squeeze
feature = data[:, :, 0: -1].to(self.device)
label = data[:, -1, -1].to(self.device)
pred = self.GAT_model(feature.float, adj)
loss = self.loss_fn(pred, label)
self.train_optimizer.zero_grad
loss.backward
torch.nn.utils.clip_grad_value_(self.GAT_model.parameters, 3.0)
self.train_optimizer.step
i += 1
deftest_epoch(self, data_loader):
self.GAT_model.eval
scores = []
losses = []
idx = data_loader.dataset.get_index
dts = idx.get_level_values( 0).unique.tolist
codes_idx = idx.get_level_values( 1)
i = 0
fordata indata_loader:
codes = codes_idx[idx.get_loc(dts[i])].tolist
adj = self.get_adj_matrix(dts[i], codes)
data = data.squeeze
feature = data[:, :, 0: -1].to(self.device)
# feature[torch.isnan(feature)] = 0
label = data[:, -1, -1].to(self.device)
pred = self.GAT_model(feature.float, adj)
loss = self.loss_fn(pred, label)
losses.append(loss.item)
score = self.metric_fn(pred, label)
scores.append(score.item)
i += 1
returnnp.mean(losses), np.mean(scores)
deffit(
self,
dataset,
evals_result=dict ,
save_path=None,
) :
dl_train = dataset.prepare( "train", col_set=[ "feature", "label"], data_key=DataHandlerLP.DK_L)
dl_valid = dataset.prepare( "valid", col_set=[ "feature", "label"], data_key=DataHandlerLP.DK_L)
ifdl_train.empty ordl_valid.empty:
raiseValueError( "Empty data from dataset, please check your dataset config.")
dl_train.config(fillna_type= "ffill+bfill") # process nan brought by dataloader
dl_valid.config(fillna_type= "ffill+bfill") # process nan brought by dataloader
sampler_train = DailyBatchSampler(dl_train)
sampler_valid = DailyBatchSampler(dl_valid)
train_loader = DataLoader(dl_train, sampler=sampler_train, num_workers=self.n_jobs, drop_last= True)
valid_loader = DataLoader(dl_valid, sampler=sampler_valid, num_workers=self.n_jobs, drop_last= True)
save_path = get_or_create_path(save_path)
stop_steps = 0
train_loss = 0
best_score = -np.inf
best_epoch = 0
evals_result[ "train"] = []
evals_result[ "valid"] = []
# load pretrained base_model
ifself.base_model == "LSTM":
pretrained_model = LSTMModel(d_feat=self.d_feat, hidden_size=self.hidden_size, num_layers=self.num_layers)
elifself.base_model == "GRU":
pretrained_model = GRUModel(d_feat=self.d_feat, hidden_size=self.hidden_size, num_layers=self.num_layers)
else:
raiseValueError( "unknown base model name MLT-%sMLT-"% self.base_model)
ifself.model_path isnotNone:
self.logger.info( "Loading pretrained model...")
pretrained_model.load_state_dict(torch.load(self.model_path, map_location=self.device))
model_dict = self.GAT_model.state_dict
pretrained_dict = {
k: v fork, v inpretrained_model.state_dict.items ifk inmodel_dict # pylint: disable=E1135
}
model_dict.update(pretrained_dict)
self.GAT_model.load_state_dict(model_dict)
self.logger.info( "Loading pretrained model Done...")
# train
self.logger.info( "training...")
self.fitted = True
forstep inrange(self.n_epochs):
self.logger.info( "Epoch%d:", step)
self.logger.info( "training...")
self.train_epoch(train_loader)
self.logger.info( "evaluating...")
train_loss, train_score = self.test_epoch(train_loader)
val_loss, val_score = self.test_epoch(valid_loader)
self.logger.info( "train %.6f, valid %.6f"% (train_score, val_score))
evals_result[ "train"].append(train_score)
evals_result[ "valid"].append(val_score)
ifval_score> best_score:
best_score = val_score
stop_steps = 0
best_epoch = step
best_param = copy.deepcopy(self.GAT_model.state_dict)
else:
stop_steps += 1
ifstop_steps>= self.early_stop:
self.logger.info( "early stop")
break
self.logger.info( "best score: %.6lf @ %d"% (best_score, best_epoch))
self.GAT_model.load_state_dict(best_param)
torch.save(best_param, save_path)
ifself.use_gpu:
torch.cuda.empty_cache
defpredict(self, dataset):
ifnotself.fitted:
raiseValueError( "model is not fitted yet!")
dl_test = dataset.prepare( "test", col_set=[ "feature", "label"], data_key=DataHandlerLP.DK_I)
dl_test.config(fillna_type= "ffill+bfill")
sampler_test = DailyBatchSampler(dl_test)
test_loader = DataLoader(dl_test, sampler=sampler_test, num_workers=self.n_jobs)
self.GAT_model.eval
preds = []
idx = test_loader.dataset.get_index
dts = idx.get_level_values( 0).unique.tolist
codes_idx = idx.get_level_values( 1)
i = 0
fordata intest_loader:
codes = codes_idx[idx.get_loc(dts[i])].tolist
adj = self.get_adj_matrix(dts[i], codes)
data = data.squeeze
feature = data[:, :, 0: -1].to(self.device)
withtorch.no_grad:
pred = self.GAT_model(feature.float, adj).detach.cpu.numpy
preds.append(pred)
i += 1
returnpd.Series(np.concatenate(preds), index=dl_test.get_index)
之后我们在展开一系列装配后(字符串如下),其之前专业训练区在在为2017年1翌年1日至2019年12翌年31日,解析集为2020年1翌年1日至2020年12翌年31日,测试集为2021年1翌年1日至2022年3翌年1日。运用于3090的DirectX展开专业训练,每个epoch大概必需5分钟,共有200epoch,专业训练星期在15个小时左右。
importos
importqlib
importpandas aspd
fromqlib.constant importREG_CN
fromqlib.utils importexists_qlib_data, init_instance_by_config
fromqlib.workflow importR
fromqlib.workflow.record_temp importSignalRecord, PortAnaRecord
fromqlib.utils importflatten_dict
provider_uri = "~/qlib_data/cn_data/"# target_dir
qlib.init(provider_uri=provider_uri, region=REG_CN)
market = "sh000300"
benchmark = "SH000300"
#### 1. 匆忙Dataset
data_handler_config = {
'start_time': "2017-01-01",
'end_time': "2022-03-01",
'fit_start_time': "2017-01-01",
'fit_end_time': "2019-12-31",
'instruments': market,
'infer_processors': [
{ 'class': 'RobustZScoreNorm',
'kwargs': { 'fields_group': 'feature', 'clip_outlier': True}},
{ 'class': 'Fillna', 'kwargs': { 'fields_group': 'feature'}}],
'learn_processors': [{ 'class': 'DropnaLabel'},
{ 'class': 'CSRankNorm', 'kwargs': { 'fields_group': 'label'}}],
'label': [ 'Ref($open, -2) / Ref($open, -1) - 1']}
dataset_config = {
"class": "TSDatasetH",
"module_path": "qlib.data.dataset",
"kwargs": {
"handler": {
"class": "Alpha158",
"module_path": "qlib.contrib.data.handler",
"kwargs": data_handler_config
},
"segments": {
"train": ( "2017-01-01", "2019-12-31"),
"valid": ( "2020-01-01", "2020-12-31"),
"test": ( "2021-01-01", "2022-03-01")
},
"step_len": 40
}
}
dataset = init_instance_by_config(dataset_config)
#### 2. 装配静态
importgat_model
gat_kwargs = {
'd_feat': 158,
'hidden_size': 64,
'num_layers': 2,
'lstm_dropout': 0.7,
'gat_dropout': 0.5,
'n_epochs': 200,
'lr': 1e-4,
'early_stop': 20,
'metric': 'loss',
'loss': 'mse',
'GPU': 0
}
model = gat_model.GATs(**gat_kwargs)
# 开始专业训练静态
withR.start(experiment_name= "train_model_gat_coc_csi300", resume= True):
R.log_params(**flatten_dict(gat_kwargs))
model.fit(dataset)
R.save_objects(trained_model=model)
其他方法论处理过程之前遇见的关键问题
1、每次专业训练的类似数据结构设计
静态每个可用的Batch类似数据为每个应于截面积上所有沪深300恒生指数的并不相同之处类似数据,借来华泰证券在调查结果《由此可知人工神经网络服务选股与Qlib实践》之前的示意由此可知,我们可以清楚看到每次专业训练每个Batch的类似数据结构设计:
2、外设类似数据的质量关键问题
Qlib外设默认下载的类似数据唯在来得多的缺陷,比如成分股类似数据不非常简单,科创刷字符串就其深交所等关键问题。所以本文实践之前均运用于其他第三方商业类似数据库。把每个股份的后复权的K新线类似数据唯为一个元数据,并以金融集团重新命名这个csv元数据。把所有元数据放在一个元数据夹,运用于qlib之前dump_all的命令就可以将类似数据元数据改以qlib运用于的binPDF:
python qlib/s/dump_bin.py dump_all ---csv_path ~/.qlib/csv_data/my_data ---qlib_dir ~/.qlib/qlib_data/my_data ---include_fields open,close,high,low,volume,factor
方法论结果
基于静态的得出,我们引入qlib外设的Topkdropout方针展开回测。如下由此可知简述,即在最开始的时候根据得出排名顺序,买入得出值最高的TopK个股份,后面每个停牌,把得出最低的N个股份卖出,替换上得出最高的N个股份重新借助于复合。
我们对比了Qlib类似的GAT静态(GAT_baseline)、投身新闻网共现的GAT静态(GAT_news_coccurrence)及沪深300净资产(CSI300),结果如下:
两个静态比起沪深300其所利息统计如下:
后续
本文方法论数据系统性新闻网共现等价作为显性由此可知人关系比有序自视线必要的由此可知人工神经网络服务,在方针充分利用之前能获得更加高的其所利息率。但本文还有未经商议,下一步简化会从一般而言几方面着手:
过渡到多层GAT静态 相反巨大损失变量,过渡到股份在在的先后顺序作为处罚因素 解析集之前,以qIC作为解析量化其他用户阅读原文,认识到更加多
SmarTag新闻网系统性类似数据
。什么药能缓解关节僵硬辽宁男科医院
咸阳白癜风正规的医院
吉林男科医院哪里好
北京哪家专科医院做人流好
-
比被领导更悲伤的是:我似乎了职场友谊
很多人都想要有一个知时时熟人。有句老话:熟人多,路多,弱点多,墙也多。这意味着多了一个熟人,多了一个简便的方式;有多少弱点拦阻他们就有多少弱点。熟人越多,越易于占有,弱点就越难占有。
- 2024-02-10新冠接踵而来,又来查缺补漏,我的大哥躲过了三年,这次被带走了
- 2024-02-10USDA份文件带动油脂油料大涨
- 2024-02-10男生最不敢渴望的5种女生类型!
- 2024-02-10民间故事:小伙一碗粥救了女乞丐,母亲闻了大喜说:这是你媳妇啊
- 2024-02-10(芝加哥期市)CBOT豆油飙升,加权期约收高2.07%
- 2024-02-10男人月薪9千,6千还房贷2千孝敬母女1千养孩子,妻子怒了:别过了
- 2024-02-102016我,90后女博士,大学教师,一条视频400万重播量,成网红
- 2024-02-10(芝加哥期市)CBOT大豆连续第二日收涨,独自消化利多的播种数据
- 2024-02-10奶奶把150万存款全给儿子,买完大三居后,儿媳就把奶奶赶出了门
- 2024-02-10闻君有两意