神經網絡預測股票市場

摘要: 股票跌跌不休?用神經網絡預測一波啊!

機器學習和深度學習已經成爲定量對衝基金爲了實現最大化利潤而通常使用的新的有效策略。作爲一個人工智能和金融愛好者,這是一個令人興奮的消息,因爲神經網絡結合了我感興趣的兩個領域。本文將介紹如何使用神經網絡預測股票市場,特別是股票(或指數)的價格。這篇文章基於我GitHub上的python項目,在項目中可以找到完整的python代碼以及如何運行這個程序。另外,要了解更多類似的內容,請查看我自己的頁面:Engineer Quant

金融是高度非線性的而且有時股票價格數據甚至看起來完全隨機的。如ARIMA和GARCH模型這些傳統的時間序列方法,只有在序列是靜止的情況下才有效,這是一種需要對序列進行日誌返回(或其他轉換)預處理的限制假設。然而,在實時交易系統中實現這些模型時出現的主要問題是,隨着新數據的添加,無法保證序列的靜止。

這是通過使用不需要任何平穩性的神經網絡來解決的。此外,神經網絡天生就能有效地發現數據之間的關係,並利用它來預測(或分類)新數據。

一個典型的全堆棧數據科學項目有以下工作流程:

1、數據採集——這爲我們提供了特徵;

2、數據預處理——這是使數據可用的一個常見且必要的步驟;

3、開發和實現模型-選擇神經網絡的類型和參數;

4、回溯模型——在任何交易策略中都是非常關鍵的一步;

5、優化——找到合適的參數;

神經網絡的輸入數據是過去十天的股價數據,我們用它來預測第二天的股價數據。

數據採集

幸運的是,這個項目所需的股價數據很容易通過使用它們的Python API,即get_yahoo_data(ticker, start_date, end_date)在Yahoo Finance中得到,或直接從它們的網站獲取。

數據預處理

在我們的例子中,我們需要將數據分解成過去10天股價和第二天價格的訓練集。我通過定義一個preprocessing類,將其分解爲訓練和測試數據,並定義一個方法get_train(self, seq_len),該方法返回訓練數據(輸入和輸出)爲numpy數組,給定一個特定的窗口長度(在例子中是10)。完整代碼如下:

def gen_train(self, seq_len):
 """
 Generates training data
 :param seq_len: length of window
 :return: X_train and Y_train
 """
 for i in range((len(self.stock_train)//seq_len)*seq_len - seq_len - 1):
 x = np.array(self.stock_train.iloc[i: i + seq_len, 1])
 y = np.array([self.stock_train.iloc[i + seq_len + 1, 1]], np.float64)
 self.input_train.append(x)
 self.output_train.append(y)
 self.X_train = np.array(self.input_train)
 self.Y_train = np.array(self.output_train)

類似的,對於測試數據,我定義了一個方法返回X_test和Y_test。

神經網絡模型

對於這個項目,我使用了兩種神經網絡模型:多層感知器(MLP)和長短期記憶網絡模型(LSTM)。我將簡要介紹這些模型的工作原理,但如果需要了解MLPs的工作原理,請查閱本文

MLPs是最簡單的神經網絡形式,從模型中輸入,並使用特定的權重,這些值通過隱藏層被向前輸入以產生輸出。通過隱藏層的反向傳播來改變每個神經元之間的權值並由此進行學習。MLPs的一個問題是缺乏“記憶”,不清楚在以前的訓練數據中發生了什麼,以及這將如何影響新的訓練數據。在我們的模型上下文中,一個數據集中十天股價的數據與另一個數據集中十天股價的數據之間的差異可能很重要(例如),但是MLPs沒有能力分析這些關係。

這就是LSTMs或遞歸神經網絡(RNNs)出現的地方。RNNs能夠存儲關於數據的特定信息以供以後使用,這擴展了網絡分析股票價格數據之間複雜結構的能力RNNs的一個問題是梯度消失問題。這是由於當層數增加時,學習率被乘以若干次,這導致梯度繼續下降。LSTMs對此進行了優化,使其更加有效。

模型實現

爲了實現這些模型,我選擇了keras,因爲它向網絡添加層而不是一次性定義整個網絡。這使我們能夠快速改變層的數量和層的類型,這在優化網絡時非常方便。

使用股票價格數據的一個重要步驟是對數據進行規一化。這通常意味着減去平均值除以標準差,但在例子中,我們想要在一段時間內的實時交易中使用這個系統,因此,利用統計矩可能不是使數據歸一化的最精確方法。因此,我只是將整個數據除以200(一個任意的數字,使一切都變得很小)。雖然歸一化似乎是憑空捏造出來的,但它仍然有效地確保神經網絡中的權重不會變大。

讓我們從簡單的MLP開始。在keras中,這是通過創建序列模型並在上面添加全連接層來實現的。完整代碼如下:

model = tf.keras.models.Sequential()
model.add(tf.keras.layers.Dense(100, activation=tf.nn.relu))
model.add(tf.keras.layers.Dense(100, activation=tf.nn.relu))
model.add(tf.keras.layers.Dense(1, activation=tf.nn.relu))

model.compile(optimizer="adam", loss="mean_squared_error")

這就是keras的優雅之處。僅用這五行代碼,我們就創建了一個帶有兩個隱藏層的MLP,每個層都有100個神經元。與傳統的隨機梯度下降法相比,Adam優化器是一種更有效的優化算法,因此在機器學習領域越來越受歡迎。通過觀察隨機梯度下降法的另外兩個擴展的優點,我們可以更好地理解這些優點:

自適應梯度算法(AdaGrad),保持每個參數的學習速率,提高了稀疏梯度問題(例如自然語言和計算機視覺問題)的性能。

均方根傳播(RMSProp)也保持每個參數的學習速率,這些學習速率是根據最近權重梯度的平均值(例如變化的速度)來調整的。這意味着該算法可以很好地處理在線和非平穩問題(如噪聲)。

可以認爲Adam結合了上述擴展的優點,這就是爲什麼我選擇使用Adam作爲我的優化器。

現在我們需要將模型與我們的訓練數據相匹配。同樣,keras使它變得簡單,只需要以下代碼:

model.fit(X_train, Y_train, epochs=100)

一旦擬合了我們的模型,我們需要根據測試數據來評估它的性能,這是由下列代碼完成

model.evaluate(X_test, Y_test)

你可以使用評估中的信息來評估模型預測股票價格的能力。

對於LSTM模型,過程是類似的,因此我將貼出下面的代碼以供你理解:

model = tf.keras.Sequential()

model.add(tf.keras.layers.LSTM(20, input_shape=(10, 1), return_sequences=True))

model.add(tf.keras.layers.LSTM(20))

model.compile(optimizer="adam", loss="mean_squared_error")

model.add(tf.keras.layers.Dense(1, activation=tf.nn.relu))

model.evaluate(X_test, Y_test)

model.fit(X_train, Y_train, epochs=50)

很重要的一點是keras要求輸入數據具有特定的由模型決定的維度,使用numpy重塑數據非常重要。

回測模型

現在,我們已經使用訓練數據對模型進行了擬合,並使用測試數據對其進行了評估,我們可以通過在新數據上對模型進行回測來進一步進行評估。由下列代碼實現:

def back_test(strategy, seq_len, ticker, start_date, end_date, dim):
 """
 A simple back test for a given date period
 :param strategy: the chosen strategy. Note to have already formed the model, and fitted with training data.
 :param seq_len: length of the days used for prediction
 :param ticker: company ticker
 :param start_date: starting date
 :type start_date: "YYYY-mm-dd"
 :param end_date: ending date
 :type end_date: "YYYY-mm-dd"
 :param dim: dimension required for strategy: 3dim for LSTM and 2dim for MLP
 :type dim: tuple
 :return: Percentage errors array that gives the errors for every test in the given date range
 """
 data = pdr.get_data_yahoo(ticker, start_date, end_date)
 stock_data = data["Adj Close"]
 errors = []
 for i in range((len(stock_data)//10)*10 - seq_len - 1):
 x = np.array(stock_data.iloc[i: i + seq_len, 1]).reshape(dim) / 200
 y = np.array(stock_data.iloc[i + seq_len + 1, 1]) / 200
 predict = strategy.predict(x)
 while predict == 0:
 predict = strategy.predict(x)
 error = (predict - y) / 100
 errors.append(error)
 total_error = np.array(errors)
 print(f"Average error = {total_error.mean()}")

然而,這個回測是一個簡化版本,而不是一個完整的回測系統。對於完整的回測系統,還需要考慮倖存者偏差、前視偏誤、市場機制變化和交易成本等因素。因爲這只是一個教育項目,一個簡單的測試就足夠了。但是,如果你對建立完整的回測系統有任何疑問,請隨時與我聯繫。

以下是我的LSTM模型在預測2月份蘋果股票價格時的表現:

對於一個沒有優化的簡單LSTM模型,這已經是一個很好的預測。它向我們展示了神經網絡的魯棒性和機器學習模型在參數間複雜關係建模中的作用。

超參數調試

在樣本外測試中,優化神經網絡模型對提高模型的性能具有重要意義。我還沒有在項目的開放源碼版本中包含調優,因爲我希望它對那些閱讀它的人來說是一個挑戰,以便繼續進行並嘗試優化模型以使其性能更好。對於那些不知道優化的人來說,它涉及到找到最大化模型性能的超參數。有幾種方法可以搜索這些理想超參數,從網格搜索到隨機方法。我強烈地感覺到,學習優化模型可以把你的機器學習知識提升到一個新的水平,因此,希望你提出一個優化模型,超過我的表現,如上圖所示。

結論

機器學習是不斷更新的,每天都有新的方法被開發出來。我們必須不斷更新知識,最好的方法就是爲一些有趣的項目建立模型,比如股票價格預測。雖然上面的LSTM模型還不足以用於實時交易,但是通過開發這樣一個模型所建立的基礎可以幫助我們建立更好的模型,有一天我們的交易系統可能會用到這些模型。

本文作者:【方向】

閱讀原文

本文爲雲棲社區原創內容,未經允許不得轉載。

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