数据集 SH50 给出了上证 50 指数从 2005 年 1 月 1 日至 2019 年 5 月10 日的股价数据,包括日期(date)、开盘价(open)、最高价(high)、最低价(low)、收盘价(close)、成交量(vol)。请建立模型对指数未来 5 日走势进行预测,如果未来五天平均价格变化 ≥ 1.5%,则记为“看涨”;未来五天股票平均价格变化 ≤-1.5%,记为“看跌”;其余情况记为“震荡”。根据历史数据预测未来五天股票价格的走势
import pandas as pd
import numpy as np
import os
import matplotlib.pyplot as plt
df=pd.read_csv('sh50.csv')
close=list(df.close)
plt.plot(close)
def make_label(*x):
labels=[]
for i in range(len(x)-5):
if (sum(x[i+1:i+6])/5.0)/x[i] - 1 > 0.015:
labels.append('看涨')
elif (sum(x[i+1:i+6])/5.0)/x[i] - 1 < -0.015:
labels.append('看跌')
else:
labels.append('震荡')
return labels
labels=make_label(*close)
df=df.iloc[:-5,:]
df['label']=labels
因为最后五天是没有未来五天的数据的,所以构造的标签比总样例少五。所以要将原始数据中最后五天的样例删掉。
收盘价(成交量)相对于移动平均线的偏离的方式将原始数据集转化为训练模型采用的特征,具体做法为:
def make_ma(*x,day):
ma=[]
for i in range(len(x)-day+1):
average=(sum(x[i:i+day]))/int(day)
ma.append(average)
return ma
close=list(df.close)
ma5=make_ma(*close,day=5)
ma10=make_ma(*close,day=10)
ma20=make_ma(*close,day=20)
ma60=make_ma(*close,day=60)
ma120=make_ma(*close,day=120)
bias5=list(np.array(close)[4:]-np.array(ma5))
bias10=list(np.array(close)[9:]-np.array(ma10))
bias20=list(np.array(close)[19:]-np.array(ma20))
bias60=list(np.array(close)[59:]-np.array(ma60))
bias120=list(np.array(close)[119:]-np.array(ma120))
def make_vol(*x,day):
vol=[]
for i in range(len(x)-day+1):
average=(sum(x[i:i+day]))/int(day)
vol.append(average)
return vol
vol=list(df.vol)
vol5=make_vol(*vol,day=5)
vol10=make_vol(*vol,day=10)
vol20=make_vol(*vol,day=20)
lb5=list(np.array(vol)[4:]/np.array(vol5))
lb10=list(np.array(vol)[9:]/np.array(vol10))
lb20=list(np.array(vol)[19:]/np.array(vol20))
新特征中有120天的平均价格,原始数据中的前119天是没有这个数据的,所以要将原始数据中前119天的数据删掉。其他新的属性要需要做对应的删除,保证数据的一致性。
df=df.iloc[119:,:]
df['ma5']=ma5[(len(ma5)-3363):]
df['ma10']=ma10[(len(ma10)-3363):]
df['ma20']=ma20[(len(ma20)-3363):]
df['ma60']=ma60[(len(ma60)-3363):]
df['ma120']=ma120[(len(ma120)-3363):]
df['bias5']=bias5[(len(bias5)-3363):]
df['bias10']=bias10[(len(bias10)-3363):]
df['bias20']=bias20[(len(bias20)-3363):]
df['bias60']=bias60[(len(bias60)-3363):]
df['bias120']=bias120[(len(bias120)-3363):]
df['vol5']=vol5[(len(vol5)-3363):]
df['vol10']=vol10[(len(vol10)-3363):]
df['vol20']=vol20[(len(vol20)-3363):]
df['lb5']=lb5[(len(lb5)-3363):]
df['lb10']=lb10[(len(lb10)-3363):]
df['lb10']=lb20[(len(lb20)-3363):]
df.drop('date',axis=1,inplace=True)
x=df.drop('label',axis=1)
y=df.label
from sklearn.model_selection import train_test_split
x_train,x_test,y_train,y_test = train_test_split(x,y,test_size = 0.2,random_state = 1)
from sklearn.preprocessing import StandardScaler
x_scaler = StandardScaler()
x1=x_scaler.fit_transform(x)
x_train1,x_test1,y_train,y_test = train_test_split(x1,y,test_size = 0.2,random_state = 1)
-训练模型
from sklearn import neural_network as nn
from sklearn.metrics import accuracy_score
mdl_nn=nn.MLPClassifier(solver='adam',
momentum=0.8,
activation='relu',
learning_rate_init=0.0001,
learning_rate='constant',
alpha=0.0001,
hidden_layer_sizes=(50,50,50),
verbose=True,
batch_size=3363,
max_iter=2000,
shuffle=True,
early_stopping=False
)
mdl_nn.fit(x_train,y_train)
yhat=mdl_nn.predict(x_train)
ypred=mdl_nn.predict(x_test)
print(mdl_nn.score(x_train,y_train))
print(mdl_nn.score(x_test,y_test))
训练集精度:0.729
测试集精度:0.536
predict_=mdl_nn.predict(x_test.iloc[:30,:])
true=y_test[:30]
result=pd.DataFrame({'label':true,'predict':predict_})
result_=[]
for i in range(len(true)):
if list(true)[i]==predict_[i]:
result_.append('成功')
else:
result_.append('失败')
result['result']=result_
df.drop('date',axis=1,inplace=True)
x=df.drop(['open','high','low','change','vol','label'],axis=1)
y=df.label
用随机森林对数据进行分析
在不调参的情况下,发现无论在训练集还是测试集,随机森林的分类效果都远高于神经网络模型。
from sklearn.ensemble import RandomForestClassifier
rf=RandomForestClassifier()
rf.fit(x_train,y_train)
rf.score(x_train,y_train)
rf.score(x_test,y_test)
训练集精度:0.989
测试集精度:0.645