利用TabNet模型进行股票长线预测

提示:本篇文章只提供一个思路,因本人是金融小白,搭建模型时所参考的股票指标并不完善,所以结果准确性无法保证,各位不要将结果作为投资参考!!!

文章目录

  • 利用TabNet模型进行股票长线预测
  • 前言
  • 一、TabNet框架介绍及下载
    • 1.TabNet介绍
      • 为何使用TabNet?
    • 2.TabNet的Pytorch版下载
  • 二、从Tushare提取股票数据
    • 1.Tushare是什么?
    • 2.如何预测股票的长线情况?
      • 股票类型
      • 预测目标
      • 应用的股票指标
    • 3.从Tushare提取股票数据代码
  • 三、用TabNet训练数据
  • 四、测试数据并进行对比
    • 1.损失函数显示误差
    • 2.手动测试计算准确率
  • 六、总结
    • 1.误差分析
    • 2.未来展望

前言

重要的事情需要再次强调:本人是金融小白,人工智能初学者,第一次搭建股票预测模型,参考的股票指标并不全面,因此预测结果与真实值有较大误差,准确性无法保证,不要将预测结果作为投资的参考依据。
股票各指标均使用Tushare大数据开放社区提取,我的TushareID:423626。Tushare大数据社区网址:https://waditu.com/

一、TabNet框架介绍及下载

1.TabNet介绍

TabNet是一种具有可解释性的可以对表格数据进行高效分类和回归的模型。
论文题目: TabNet: Attentive Interpretable Tabular Learning
论文地址: https://arxiv.org/abs/1908.07442

为何使用TabNet?

目前决策树在处理表格数据上占据主导地位,其原因是:
1.表格数据存在近似的超平面边界,而决策树处理起来非常有效率。
2.在跟踪决策节点上,决策树具有高解释性。
3.决策树可以快速训练数据。
4.预先提出的DNN不适用于表格数据,因为传统DNN是基于多个传统层或多层感知,这会导致过参数化,使DNN找不到解决表格数据的最佳方法。

TabNet的优势:
1.与基于树的方法不同,TabNet可以输入未加工的数据,并且不需要任何特征处理。
2.TabNet在决策的每一步,使用序列注意力来选择特征进行推理。具有可解释性。
3.TabNet使用了非监督预训练来预测masked特征,该模型是第一个对表格数据进行自监督学习的。

2.TabNet的Pytorch版下载

Pytorch版下载: https://github.com/dreamquark-ai/tabnet
我使用的是Pycharm来运行TabNet,根据下载文件中的README_md文件完成库的安装。

二、从Tushare提取股票数据

1.Tushare是什么?

TuShare是一个免费、开源的python财经数据接口包。主要实现对股票等金融数据从数据采集、清洗加工 到 数据存储的过程,能够为金融分析人员提供快速、整洁、和多样的便于分析的数据,为他们在数据获取方面极大地减轻工作量,使他们更加专注于策略和模型的研究与实现上。
在Tushare 旧版运行了3年后,Tushare Pro在大家的期待下,终于要跟大家见面了。可以略显激动地说,Pro版数据更稳定质量更好了,但Pro依然是个开放的,免费的平台,不带任何商业性质和目的。
Tushare运行三年多以来,数据从广度和深度都得到了提升,Pro版正是在此基础上做了更大的改进。数据内容将扩大到包含股票、基金、期货、债券、外汇、行业大数据,同时包括了数字货币行情等区块链数据的全数据品类的金融大数据平台,为各类金融投资和研究人员提供适用的数据和工具。
Tushare官方网站:https://waditu.com/

2.如何预测股票的长线情况?

股票类型

为了减小游资操控股票这一因素的影响,此次预测的目标为市值大于50亿的股票。

预测目标

预测目标为某一年(下方例子为2020年)市值大于50亿的股票当年最大涨幅。

应用的股票指标

作为直接输入的特征的股票指标有:
市盈率、市净率、净资产收益率、销售毛利率、每股现金流、每股未分配利润、每股营业收入、每股资本公积。

作为需要二次计算的股票指标有:
当前股价、前六个月股价、前六个月流通股本、前六个月净流入、当年每月的最高股价。

历史高低位系数(自定义):(当前股价 - 前六个月股价平均值)/ 当前股价
放缩量系数(自定义):前六个月净流入总和 / 前六个月流通股本总和
当年股价最高位:Max(当年每月最高股价)
当年股票最大涨幅:当年股价最高位 / 当前股价

3.从Tushare提取股票数据代码

以下代码用于下载2020年市值大于50亿股票数据。
代码如下:

# -*-encoding:utf-8-*-
import tushare as ts
import pandas as pd
import numpy as np
import timepro = ts.pro_api(token='***')
ts.set_token('***')# 所有股票列表。 返回值1:股票代码、名字、行业,有表头索引。 返回值2:所有股票代码,有表头索引
def all_code():stock_list = pro.stock_basic(exchange='', list_status='L', fields='ts_code,name,industry')code_list = stock_list['ts_code']return stock_list, code_list# 总市值大于50亿的股票。 输入值:所有股票代码,开年开盘日期。返回值:股票代码、市值、市盈率、市净率,有表头索引。
def stock_over50(code_list, date):over50_list = pd.DataFrame()for code in code_list:total_mv_list = pro.daily_basic(ts_code=code, trade_date=date, fields='ts_code, total_mv, pe, pb')time.sleep(0.1)try:if total_mv_list.iloc[0, 3] == None:time.sleep(0.2)elif total_mv_list.iloc[0, 3] > 500000:over50_list = pd.concat([over50_list, total_mv_list], axis=0)print(over50_list)time.sleep(0.2)else:time.sleep(0.2)except:passcontinueprint(over50_list)over50_list.to_csv('./over50_list_2020.csv', encoding='utf-8')return over50_list# 市盈率市净率。输入值:大于50亿股票。输出值:市盈率市净率列表。有表头索引:'pe', 'pb'
def pepb_list(over50_list):pepb = over50_list[['ts_code', 'pe', 'pb']]return pepb# 前一年的年报数据。输入值1:大于50亿列表。输入值2:去年年报时间,如20191231。输出值,年报数值,有表头索引
def year_news_list(code_list, date_lastyear):year_news1 = pro.fina_indicator(ts_code=code_list, period=date_lastyear)year_news2 = pd.DataFrame(year_news1).iloc[0:1, :]year_news3 = year_news2[['ts_code', 'roe', 'grossprofit_margin', 'cfps', 'undist_profit_ps', 'revenue_ps', 'capital_rese_ps']]time.sleep(0.1)# print(year_news3, 'years_news complete')return year_news3def history(code_over50):now = pro.monthly(ts_code=code_over50, start_date='20200201', end_date='20200228', fields='ts_code,trade_date,open')now = pd.DataFrame(now)time.sleep(0.1)avg6 = pro.monthly(ts_code=code_over50, start_date='20190801', end_date='20200131',fields='ts_code,trade_date,open')time.sleep(0.1)list_his = float(0)for i in avg6['open']:list_his = list_his + ihistory1 = list_his / 6history = (now['open'].at[0] - history1) / now['open'].at[0]history = '{:.2f}'.format(history)history = pd.DataFrame(list([history]), columns=['history_level'])# ts_code = now['ts_code']# all_history = pd.concat([ts_code, history], axis=1)# print(history)return history# 量:输入值:50亿以上股票。输出值:股票代码,量。有表头
def Vol(code_over50):mf_vol = pro.moneyflow(ts_code=code_over50, start_date='20191001', end_date='20200301')['net_mf_vol']time.sleep(0.1)float_share_get = pro.daily_basic(ts_code=code_over50, start_date='20191001', end_date='20200301',fields='ts_code, float_share')time.sleep(0.1)float_share = float_share_get['float_share']mf_vol_sum = sum(mf_vol)float_share_sum = sum(float_share)Vol = mf_vol_sum / float_share_sumVol_all = pd.DataFrame(list([Vol]), columns=['Vol'])# ts_code = pd.DataFrame(float_share_get['ts_code'])# list_all = pd.concat([ts_code.iloc[0:1, 0], Vol_all], axis=1)# print(Vol_all)return Vol_all# 计算一年内最高涨幅和最低跌幅。输入值:大于50亿股票代码。输出值1:股票代码,最大涨幅。输出值2:股票代码,最低跌幅。有表头
def Max_Min(code_over50):All_data = pro.monthly(ts_code=code_over50, start_date='20200301', end_date='20210101',fields='ts_code, open, trade_date, high, low')time.sleep(0.1)Max_data = max(All_data['high'])Min_data = min(All_data['low'])Open = pd.DataFrame(All_data).iloc[-1, 2]Max_vol = 100 * (Max_data - Open) / OpenMin_vol = 100 * (Min_data - Open) / OpenMax_pd = pd.DataFrame(list([Max_vol]), columns=['Max_vol'])Min_pd = pd.DataFrame(list([Min_vol]), columns=['Min_vol'])# ts_code = pd.DataFrame(All_data).iloc[0, 0]# ts_code = pd.DataFrame(list([ts_code]), columns=['ts_code'])# Max_list = pd.concat([ts_code, Max_pd], axis=1)# Min_list = pd.concat([ts_code, Min_pd], axis=1)return Max_pd, Min_pdstock_list, code_list = all_code()date = '20200301'
over50_list = stock_over50(code_list, date)
over50_list.to_csv('./over50_list_2020.csv')
over50_list = pd.read_csv('./over50_list_2020.csv')
code_over50 = over50_list['ts_code']
print(code_over50)pepb = pepb_list(over50_list)
print(pepb)list_value = pd.DataFrame()
count = 0
for code in code_over50:try:new_list = year_news_list(code, '20191231')history_list = history(code)VOL = Vol(code)Max_final, Min_final = Max_Min(code)list1 = pd.concat([new_list, history_list, VOL, Max_final], axis=1)list1.index = [count]list_value = pd.concat([list_value, list1])count += 1if count % 10 == 0:print('step:', count)print(list_value)except:count += 1passcontinuelist_value.to_csv('./list_value_2020.csv', encoding='utf-8')
Final_list = pd.concat([pepb, list_value], axis=1)
# Final_list = pd.concat([pepb, new_list, history, VOL, Max_final], axis=1)
# print(Final_list)
#
Final_list.to_csv('./Final_list_2020.csv', encoding='utf-8')
print('all complete')

三、用TabNet训练数据

此次测试运用的是TabNet的Regression做预测。
代码如下:

from pytorch_tabnet.tab_model import TabNetRegressor
from sklearn.preprocessing import LabelEncoder
from sklearn.metrics import mean_squared_error
import pandas as pd
import numpy as np
np.random.seed(0)
import osdataset_name = 'stock'# Load data and splittrain = pd.read_csv('./Final_list_2020.csv')target = 'int'if "Set" not in train.columns:train["Set"] = np.random.choice(["train", "valid", "test"], p=[.8, .1, .1], size=(train.shape[0],))train_indices = train[train.Set == "train"].index
valid_indices = train[train.Set == "valid"].index
test_indices = train[train.Set == "test"].index
print(test_indices)
# Simple preprocessingcategorical_columns = []
categorical_dims = {}
for col in train.columns[train.dtypes == object]:print(col, train[col].nunique())l_enc = LabelEncoder()train[col] = train[col].fillna("VV_likely")train[col] = l_enc.fit_transform(train[col].values)categorical_columns.append(col)categorical_dims[col] = len(l_enc.classes_)for col in train.columns[train.dtypes == 'float64']:train.fillna(train.loc[train_indices, col].mean(), inplace=True)# Define categorical features for categorical embeddingsunused_feat = ['Set', 'Max_vol']features = [col for col in train.columns if col not in unused_feat + [target]]cat_idxs = [i for i, f in enumerate(features) if f in categorical_columns]cat_dims = [categorical_dims[f] for i, f in enumerate(features) if f in categorical_columns]# define your embedding sizes : here just a random choice
# cat_emb_dim = [5, 4, 3, 6, 2, 2, 1, 10]# Network parametersclf = TabNetRegressor(cat_dims=cat_dims, cat_emb_dim=1, cat_idxs=cat_idxs)# TrainingX_train = train[features].values[train_indices]
y_train = train[target].values[train_indices].reshape(-1, 1)X_valid = train[features].values[valid_indices]
y_valid = train[target].values[valid_indices].reshape(-1, 1)X_test = train[features].values[test_indices]
print('X_test', X_test, X_test.shape)
y_test = train[target].values[test_indices].reshape(-1, 1)
print('y_test', y_test, y_test.shape)
max_epochs = 100 if not os.getenv("CI", False) else 2# 训练误差:rmsle:均方根对数误差 mae:平均绝对误差 rmse:均方根误差 mse:均方误差
clf.fit(X_train=X_train, y_train=y_train,eval_set=[(X_train, y_train), (X_valid, y_valid)],eval_name=['train', 'valid'],eval_metric=['rmsle', 'mae', 'rmse', 'mse'],max_epochs=max_epochs,patience=10,batch_size=12800, virtual_batch_size=64,num_workers=0,drop_last=False
)# Deprecated : best model is automatically loaded at end of fit
# clf.load_best_model()preds = clf.predict(X_test)y_true = y_testtest_score = mean_squared_error(y_pred=preds, y_true=y_true)print(f"BEST VALID SCORE FOR {dataset_name} : {clf.best_cost}")
print(f"FINAL TEST SCORE FOR {dataset_name} : {test_score}")# Save model and load# save tabnet model
saving_path_name = "./tabnet_model_test_2020"
saved_filepath = clf.save_model(saving_path_name)
print('saved_filepath', saved_filepath)# define new model with basic parameters and load state dict weights
loaded_clf = TabNetRegressor()
loaded_clf.load_model(saved_filepath)loaded_preds = loaded_clf.predict(X_test)
predict_list = pd.DataFrame(loaded_preds)
ture_list = pd.DataFrame(y_test, columns=['int'])
all_list = pd.concat([predict_list, ture_list], axis=1)
all_list.to_csv('./predict_2020.csv') # 将2020年test数据预测值与真实值导入表格中
loaded_test_mse = mean_squared_error(loaded_preds, y_test)print(f"FINAL TEST SCORE FOR {dataset_name} : {loaded_test_mse}")

四、测试数据并进行对比

1.损失函数显示误差


这个结果并不能很好的表明预测结果,但系统告诉我们最好的权重是在第35个epoch,所以我们看一看第35个epoch的结果。
epoch 35 | loss: 0.32233 | train_rmsle: 0.09384 | train_mae: 0.40749 | train_rmse: 0.71892 | train_mse: 0.51685 | valid_rmsle: 0.07114 | valid_mae: 0.34773 | valid_rmse: 0.45248 | valid_mse: 0.20474 | 0:00:09s

这里我们关注MAE这个指标:平均绝对误差。该指标是指真实值和预测值的误差平均值。这里预测值valid_mae的值下降到了0.34773,说明预测值和真实值的差距平均大概在±35%以内。也就是说,我们预测当年的最大涨幅的误差大概在±35%,而这个结果就是为什么不能作为参考价值的原因,误差实在是太大了。

2.手动测试计算准确率

因为MAE指标只是显示误差区间,并不能准确的计算我们的投资是否成功,因此我将数据导入csv文件并手动将未参与训练的test部分比较误差。
下面代码是输入测试数据并生成预测值与真实值比较表格:

from pytorch_tabnet.tab_model import TabNetRegressor
from sklearn.metrics import mean_squared_error
import pandas as pd
import numpy as npnp.random.seed(0)dataset_name = "预测误差"
predict = pd.read_csv('Final_predict_test.csv')print(predict)
features = [col for col in predict.columns if col not in ['set', 'int', 'Max_vol']]
X_test = np.array(predict[features])
print(X_test)
y_test = np.array(predict['int']).reshape(-1, 1)
print(y_test)
# define new model with basic parameters and load state dict weightssaving_path_name = "./tabnet_model_test_1.zip"
# saved_filepath = clf.save_model(saving_path_name)loaded_clf = TabNetRegressor()
loaded_clf.load_model(saving_path_name)loaded_preds = loaded_clf.predict(X_test)
print("预测值:", loaded_preds)
loaded_test_mse = mean_squared_error(loaded_preds, y_test)print(f"FINAL TEST SCORE FOR {dataset_name} : {loaded_test_mse}")
predict_list = pd.DataFrame(loaded_preds)
ture_list = predict['int']
all_list = pd.concat([predict_list, ture_list], axis=1)
all_list.to_csv('./predict_all.csv')

这里我一共训练了2017年-2020年四年的数据并生成模型,然后用2020年的test数据作为测试数据生成了预测值与真实值表格:

其中B列为预测值,C列为真实值,D列为比较真实值是否大于预测值。

从上图中可以看出,准确率只有57%

如果我们降低一下要求,真实值如果在预测值以下5%也可以接受的话,那么准确性数值勉强可观一些。

准确率可以提升到65%了!

六、总结

1.误差分析

我的股票预测误差如此之大是在意料之中的,可以分为以下几点讨论:
(1)股票是人操控的,影响股票走势的因素绝不仅仅与其基本面等等表象数据有关,因此对股票预测的准确率本身就不会达到绝对高的精度。
(2)因为我是金融小白,对股票这方面了解甚少,所以采用的输入特征,也就是股票基本面指标,与股票长线的走势关系不大,也有更多有关联的指标我没有用上。我相信股票的走势和基本面数据是存在关联的,但股票预测准确率的提高需要建立在比较完整的数据架构上。
(3)TabNet模型本身是一个比较完善的模型,其在森林覆盖与扑克手数据集预测上都有较好的准确率。但其内部有较多的参数和超参数,对于不同的模型可能需要修改以缩减收敛速度,增加预测准确率。但因为我的个人实力有限,不能将TabNet的效率和准确率发挥到最大。
(4)数据集的特征并不平均,大部分数据真实值都在0-0.4之间,这导致模型为了减小loss,预测值往往比较中庸。
(5)每年的大盘走势都不同,比如2018年股票大跌,2020年股票大涨,因此在预测2018年时,准确率大大下滑,而预测2020年数据的准确率就会比较客观。

2.未来展望

通过这次简单的测试,能看出股票走势与其基本面存在一定的联系,但要真正提高准确率,不仅需要更完善的人工智能处理框架,最重要的是需要一个较为完整的金融体系框架来分析。
如果有这方面经验和兴趣的,可以和我这只菜鸡一起交流。

利用TabNet进行股票长线预测相关推荐

  1. DL之perceptron:利用perceptron感知机对股票实现预测

    DL之perceptron:利用perceptron感知机对股票实现预测 目录 输出结果 实现代码 输出结果 更新-- 实现代码 import numpy as np import operator ...

  2. 人工智能作业之神经网络股票(预测)系统

    股票(stock),是股份公司发行的所有权凭证,是股份公司为筹集资金而发行给各个股东作为持股凭证并借以取得股息和红利的一种有价证券.每股股票都代表股东对企业拥有一个基本单位的所有权.每家上市公司都会发 ...

  3. Python --相似K线匹配--实现股票走势预测 Tushare

    Python --相似K线匹配–实现股票走势预测 Tushare 前言 同花顺和东方财富都提供了一个免费的功能可以查找相似走势的K线,提供参考.差不多,东方财富可以选择分析的周期,同花顺是固定120日 ...

  4. 如何利用python对股票的走势进行一个判断?

    如何利用python对股票的走势进行一个判断? 一.问题 当我们拿到沪深股票的所有股票的数据的时候,如何对所有股票的走势,做一个模糊的判断? 当然可以通过画出一个股票的走势图来进行判断.但是问题是,我 ...

  5. 利用CNN对股票“图片”进行涨跌分类——一次尝试【附源码】

    首先解释一下标题: CNN:卷积神经网络(Convolutional Neural Network), 在图像处理方面有出色表现,不是被川普怒怼的那个新闻网站: 股票涨跌:大家都懂的,呵呵: 股票图片 ...

  6. keras系列︱迁移学习:利用InceptionV3进行fine-tuning及预测、完美案例(五)

    之前在博客<keras系列︱图像多分类训练与利用bottleneck features进行微调(三)>一直在倒腾VGG16的fine-tuning,然后因为其中的Flatten层一直没有真 ...

  7. ML之kNNC:基于iris莺尾花数据集(PCA处理+三维散点图可视化)利用kNN算法实现分类预测daiding

    ML之kNNC:基于iris莺尾花数据集(PCA处理+三维散点图可视化)利用kNN算法实现分类预测 目录 基于iris莺尾花数据集(PCA处理+三维散点图可视化)利用kNN算法实现分类预测 设计思路 ...

  8. ML之kNNC:基于iris莺尾花数据集(PCA处理+三维散点图可视化)利用kNN算法实现分类预测

    ML之kNNC:基于iris莺尾花数据集(PCA处理+三维散点图可视化)利用kNN算法实现分类预测 目录 基于iris莺尾花数据集(PCA处理+三维散点图可视化)利用kNN算法实现分类预测 设计思路 ...

  9. Matlab之DNN:基于Matlab利用神经网络模型(epochs=10000000)预测勒布朗詹姆斯的2018年总决赛(骑士VS勇士)第一场得分、篮板、助攻

    Matlab之DNN:基于Matlab利用神经网络模型(epochs=10000000)预测勒布朗詹姆斯的2018年总决赛(骑士VS勇士)第一场得分.篮板.助攻 目录 输出结果 预测勒布朗詹姆斯的20 ...

最新文章

  1. mbed列--基于飞思卡尔FRDM KL25Z鼠标设计的高速实现
  2. VC++ 坐标问题总结,控件大小随窗口变化
  3. 计算机主机内部防尘装置,一种计算机主机用防尘装置的制作方法
  4. idea更新maven依赖包
  5. asp.net 运行原理
  6. 【干货】火山视频去水印下载使用介绍
  7. 大数据、数据分析和数据挖掘的区别
  8. python_中位数
  9. CS5218: DP转HDMI 4K30HZ转换方案
  10. chrome 打印布局_Chrome 网页打印中的宽度控制
  11. 如何实现通过扫描二维码下载阿里云文件
  12. Python 自动化办公-玩转 Word
  13. (实战)Node.js 实现抢票小工具短信通知提醒
  14. 华为新人培养计划曝光!(新员工培训就该这么做)
  15. 谷歌学术得到论文被引用信息
  16. 人机交互-11-往年试卷
  17. 嵌入式中SD卡接口电路设计
  18. 一级域名和二级域名的差异
  19. SQL自动备份数据到另一台电脑
  20. 打开cad图纸计算机打不开,电脑上CAD软件为何打不开?打开电脑CAD软件方法!

热门文章

  1. c语言设计学生结构体,c语言程序设计编程题目:请 :编写完成对学生相关信息的要求:1.定义一个结构体类型student,其中包括三个成...
  2. 思想的沉淀,精辟,杨澜如是说
  3. 2022-3-19(洛谷)
  4. RAID5系统架构和扩容
  5. android 当服务器
  6. CF #689(Div. 2) B - Find the Spruce
  7. 【Python】写了一个简单的照片按EXIF日期保存脚本
  8. Spark学习-入门介绍
  9. 在职场要避免这些“潜规则”
  10. Chrome浏览器最常用的快捷键