利用神經網絡預測股票價格走勢

股價趨勢預測模型構建

(一)建立模型

神經網絡模型圖
讀取10天的數據進行歸一化處理變成[-1,1]區間的特徵數據,中間經過4個全連接的神經網絡層得到一個預測的開盤價輸出,最後根據真實開盤價與預測開盤價的梯度更新權重。

(二)數據準備

Tushare是一個基於python的、免費的、開源的財經數據接口包。本文的金融數據來源將使用Tushare的API。所採用的訓練集股票數據來自上證50指數,股票代碼是從600000-603808中抽取了833只股票。時間區間爲2016年9月19日至2019年3月18日這三年的日K線數據。所採用的測試集股票數據來自滬深300指數的兩隻股票:000538.(雲南白藥)、000858(五糧液)近三年的數據作爲測試集對模型進行驗證。數據的維度包括:開盤價、最高價、收盤價、最低價、成交量、成交金額,將這六個交易信息作爲特徵提取。
數據預處理採用最大最小歸一化的方法,將所有數據全部映射到[-1,1]的區間。這樣就可以避免不同的股票因爲價格相差大而導致預測趨勢產生的巨大波動。

(三)訓練過程

模型說明
1.輸入層一共有6個維度的數據,每次訓練會輸入10天的數據,一共有60個神經元
2.隱藏層一共設置了4層,每一層的神經元個數分別設置爲8、 8、 3、 2。激活函數統一使用relu
3.輸出層的神經元設置爲1個,且不使用激活函數。輸出數據爲-1,至1之間的浮點數值,表示未來一天的價格。
4.初始化權重w0和b0,w0是呈正態分佈的隨機值,b0則統一設初始值爲0
開始訓練
1.在數據輸入之前先對數據進行歸一化的處理,在下面的歸一化公式中:X_Scaled表示歸一化之後的數據,X_input表示輸入數據集中的每一個數據,X_min表示輸入數據集中的最小值,X_max表示輸入數據集中的最大值。
公式1
2.對於輸入數據來說,做的工作主要就是加權求和,輸入數據經過處理之後跟原來的數據維度保持一致,但是數值會隨着權重和偏置值的變化而變化。
公式2
3.在上一步的數據計算完成之後得到結果hidden,再使用激活函數對數據進行處理,這裏選用relu作爲激活函數,將hidden中爲負數的值變成0,這樣可以形成神經網絡的稀疏性,減少參數間的依賴關係。最後將結果作爲下一層的輸出
公式3
其中relu函數的數學公式爲:
公式4
4.對於輸出層來說就不需要加上激活函數了,加權求和就可以得到結果即表示未來一天的開盤價。

pred = out * wi + b

5.這時候就得到了預測的開盤價pred,與真實的開盤價Y,進行平方差均值計算就可以得到loss
公式6
6.得到loss之後就可以通過TensorFlow中的優化器來更新權重,其內部實現細節中包含的梯度下降法和反向傳播算法已經在上文給出這裏不再贅述。

實驗結果數據分析

模型剛開始訓練時loss值在0-0.35之間波動(如圖5.1、5.2所示),而且很不穩定預測的價格趨勢與真實的趨勢相差非常大,當訓練數據達到400之後模型纔開始慢慢收斂至0.15左右。
loss趨勢(1)
上圖顯示的是股票代碼爲600000的loss的變化過程,橫軸表示訓練批次,縱軸表示loss值。
預測趨勢與真實趨勢對比(1)
在上圖中顯示的是股票代碼爲600000的真實開盤價走勢和神經網絡擬合的開盤價走勢,橫軸表示歸一化之後的開盤價;縱軸表示訓練的數據,每一批數據共有6*10個,對應輸入層的神經元個數。(下同)
當模型訓練到八萬次時,loss值的波動開始趨於穩定(如圖5.3所示)。正常情況下可以保持在0-0.1之間。也就是在大多數情況下預測的趨勢的準確的,但是一些重大的利好或利空消息也會讓模型的預測出現偏差。
loss趨勢(2)
loss趨勢(2)
預測趨勢與真實趨勢對比(2)

通過上圖可以很直觀得看到預測趨勢與真實趨勢已經非常接近了,雖然也有一些誤差,但是不像剛開始訓練時的誤差那麼明顯。
以上的圖片都是在訓練集的預測效果,現使用股票000538.(雲南白藥)、000858(五糧液)近三年的數據作爲測試集進行預測。這兩隻股票是從來沒有在訓練集中出現過的,可以保證測試集數據跟訓練集數據完全獨立。
預測結果1
預測結果2

通過上述實驗可知,模型誤差最終爲0.1以內,且沒有出現過擬合的現象。在測試集上的表現也比較良好,說明該模型是有一定投資參考價值的。

代碼

下載股票數據代碼

import tushare as ts
import os
stocklist = [str(i) for i in range(600599, 602000)]
if not os.path.exists('stocks1'):
    os.mkdir("stocks1")
for stock in stocklist:
    df = ts.get_hist_data(stock)
    if df is not None:
        print(df.__len__())
        # if  df.__len__() == 607:
        df.to_csv('./stocks1/'+stock + '.csv', columns=['open', 'high', 'low', 'close', 'volume'])

核心代碼

import tensorflow as tf
import numpy as np
import pandas as pd
import  copy
from sklearn.preprocessing import MinMaxScaler
from sklearn.preprocessing import StandardScaler
import matplotlib.pyplot as plt
import os


def read_process_data(csv='600000.csv', isca=True, look_back=10):
    data = pd.read_csv('stocks/'+csv)
    data = data.drop(['date'], 1)
    data.astype('float32')
    data = data.values
    if isca:
        scaler = MinMaxScaler(feature_range=(-1, 1))
        scaler.fit(data)
        data = scaler.transform(data)
    dataX, dataY = [], []
    for i in range(len(data) - look_back):
        a = data[i:(i + look_back), 1:]
        dataX.append(a)
        dataY.append(data[i:(i + look_back), 0][-1])
    # dataX.shape = (n,look_back,4)
    dataX = np.array(dataX)
    dataY = np.array(dataY)
    dataY.reshape(-1, 1)
    return data




def hidden_layer(layer_input, output_depth, scope):
    input_depth = layer_input.shape[-1]
    with tf.name_scope('hidden'+str(scope)):
        w = tf.get_variable(initializer=tf.random_uniform_initializer(minval=-0.1, maxval=0.1),
                            shape=(input_depth, output_depth),
                            dtype=tf.float32,
                            name='weights'+str(scope))
        b = tf.get_variable(initializer=tf.zeros_initializer(),
                            shape=(output_depth),
                            dtype=tf.float32,
                            name='bias'+str(scope))
        net = tf.matmul(layer_input, w) + b
        tf.summary.histogram('w'+str(scope), w)
        tf.summary.histogram('b'+str(scope), b)
        return net


def dnn(x, output_depths, fncs):
    net = x
    i = 1
    for output_depth, fnc in zip(output_depths, fncs):
        net = hidden_layer(net, output_depth, scope=i)
        net = fnc(net)
        i += 1
    net = hidden_layer(net, 1, scope=0)
    return net


def train_moel(data, neurons, fncs, batch_size=16, epochs=1):
    with tf.name_scope('input_data'):
        X = tf.placeholder(dtype=tf.float32, shape=[None, (data.shape[-1]-1)], name='X')
        Y = tf.placeholder(dtype=tf.float32, shape=[1, 1], name='Y')
    out = dnn(X, neurons, fncs)
    out = tf.identity(out, name='out')
    with tf.name_scope('loss'):
        loss = tf.reduce_mean(tf.squared_difference(out, Y), name='loss')
        tf.summary.scalar('loss', loss)
    with tf.name_scope('opt'):
        opt = tf.train.AdamOptimizer(name='opt').minimize(loss)
    sess = tf.Session()
    merged = tf.summary.merge_all()
    writer = tf.summary.FileWriter("logs/", sess.graph)

    sess.run(tf.global_variables_initializer())
    look_back = 10
    losses =[]
    saver = tf.train.Saver()
    sess.graph.finalize()
    for e in range(epochs):
        for i in range(0, len(data)-look_back):
            sess.run(opt,
                     feed_dict={X: data[i:(i+look_back), 1:],
                                Y: np.array(data[i:(i+look_back), 0][-1])
                                .reshape(1, 1)})
            rs = sess.run(merged,
                          feed_dict={X: data[i:(i+look_back), 1:],
                                     Y: np.array(data[i:(i+look_back), 0][-1])
                                     .reshape(1, 1)})
            writer.add_summary(rs, i)
            if np.mod(i, 50) == 0:
                losses.append(sess.run(loss,
                         feed_dict={X: data[i:(i + look_back), 1:],
                                    Y: np.array(data[i:(i + look_back), 0][-1])
                                    .reshape(1, 1)}))
                print('loss:'+str(losses[-1]))
        y_num = sess.run(out, feed_dict={X: data[:, 1:]})
    saver.save(sess, 'ckpt/stock.ckpt', global_step=epochs)
    sess.close()
    return y_num, losses


def restore_test_model(data):
    graph = tf.Graph()
    with graph.as_default():
        model_file = tf.train.latest_checkpoint('ckpt/')
        saver = tf.train.import_meta_graph(str(model_file) + '.meta')
        with tf.Session() as sess:
            sess.graph.finalize()
            saver.restore(sess, model_file)
            graph = tf.get_default_graph()
            out = graph.get_tensor_by_name("out:0")
            X = graph.get_tensor_by_name("input_data/X:0")
            y_num = sess.run(out, feed_dict={X: data[:, 1:]})
            return y_num


def restore_train_model(data, epochs=1):
    graph = tf.Graph()
    with graph.as_default():
        model_file = tf.train.latest_checkpoint('ckpt/')
        saver = tf.train.import_meta_graph(str(model_file) + '.meta')
        with tf.Session() as sess:
            sess.graph.finalize()
            saver.restore(sess, model_file)
            graph = tf.get_default_graph()
            loss = graph.get_tensor_by_name("loss/loss:0")
            X = graph.get_tensor_by_name("input_data/X:0")
            Y = graph.get_tensor_by_name("input_data/Y:0")
            out = graph.get_tensor_by_name("out:0")
            opt = graph.get_operation_by_name('opt/opt')
            look_back = 10
            losses = []
            for i in range(epochs):
                for i in range(0, len(data) - look_back):
                    sess.run(opt,
                             feed_dict={X: data[i:(i + look_back), 1:],
                                        Y: np.array(data[i:(i + look_back), 0][-1])
                                        .reshape(1, 1)})
                    lossnum = sess.run(loss,
                             feed_dict={X: data[i:(i + look_back), 1:],
                                        Y: np.array(data[i:(i + look_back), 0][-1])
                             .reshape(1, 1)})
                    if np.mod(i, 50) == 0:
                        losses.append(lossnum)
                        print(lossnum)
            saver.save(sess, 'ckpt/stock.ckpt', global_step=epochs+1)
            y_num = sess.run(out, feed_dict={X: data[:, 1:]})
    return y_num, losses


def main():
    data = read_process_data()
    neurons = [1024, 512, 256, 128]
    fncs = [tf.nn.relu, tf.nn.relu, tf.nn.relu, tf.nn.relu]
    y_pred, losses = train_moel(data, neurons, fncs)
    testN()
    pass
def trainN():
    stocklist = [i for i in os.listdir('stocks') if i.endswith('csv') and i.startswith('6')]
    for i in stocklist:
        test_data = read_process_data(csv=i)
        y_pred, losses = restore_train_model(test_data)
        plt.plot(test_data[0:, 0], label='real')
        plt.plot(y_pred, label='pred')
        plt.title(i+'_stock data')
        plt.legend()
        plt.savefig("pred-"+str(i)+".png")
        plt.clf()
        plt.plot(losses, label='loss')
        plt.title(i + 'loss')
        plt.legend()
        plt.savefig("loss-" + str(i)+".png")
        plt.clf()


def testN():
    test_data = read_process_data('000538.csv')
    y_test_pred = restore_test_model(test_data)
    plt.plot(test_data[0:, 0], label='real')
    plt.plot(y_test_pred, label='pred')
    plt.title('000538_stock data')
    plt.legend()
    plt.savefig("test-000538.png")
    plt.clf()

if __name__ == '__main__':
    main()


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章