作者:chen_h
微訊號 & QQ:862251340
微信公眾號:coderpai
我的部落格:請點選這裡
本文的程式碼請點選這裡。Talk is cheap, show me the code.
在過去的幾個月中,我對深度學習非常著迷,特別是它在自然語言處理中的應用。我的大部分職業生涯都是在金融領域度過的,特別是在演算法交易和交易資料替換方面。
我寫這篇文章的想法直接來自我的工作經驗。我作為一名“深度學習”的愛好者時,對於深度學習我沒有很深入的瞭解。但是我希望我的理解可以表達到位,並且可以幫助到你。
為什麼股票預測與 NLP 存在關聯性?
在很多的 NLP 問題中,我們最終會把序列編碼成一個固定大小的表示,然後將這個編碼再解碼成另一個序列。例如,我們可能會在文字中進行實體標記,從英文翻譯成法語,或將音訊轉換成文字。在這些領域都出現了大量的工作,並且很多成果都取得了最先進的表現。
在我看來,NLP 與金融資料分析之間的最大不同在於,語言有一定的結構性,雖然這個結構性比較模糊難懂。另一方面,金融市場資料可能是沒有任何結構可以學習的。
在這個文章中,我們假設金融市場資料是存在結構性的,當然這個假設可能是不成立的,我們這個文章可能也會直接推翻這個假設。我們按照 NLP 的語義編碼模型來類比這個市場結構,如果你覺得這個想法沒有意義,那麼請閱讀下去,我相信你會覺得會有意義的。
詞向量
詞向量的模型有很多的,Richard Socher 的講座是一個非常好的教程。簡而言之,我們可以用語言模型來描述所有的單詞,並且在座標圖中進行顯示,並且利用幾何圖形來捕捉單詞之間的關聯性。有一個經典的例子是 “King - man + woman = Queen” ,或者類似別的例子。
詞嵌入是非常酷的一個應用,因為我們可以利用一個很濃縮的方式來表示一個詞資訊。比較傳統的詞嵌入方法是構建一個包含所有單詞的詞表,如果當前詞是查詢詞,那麼該位置設定為 1 ,其餘設定為 0 。但是這不是一個有效的方法,而且也沒有任何詞關聯意義。但是通過詞嵌入,我們用一個固定維度的向量來表示一個單詞,然後利用更高維度的幾何特性來尋找詞之間的關聯性。
下圖展示了一個例子。詞向量的模型是需要一個大型的語料庫進行訓練。經過幾天的高密度訓練,每個詞都會得到一個高維度的詞向量。這個“空間”向量會有類似於“距離”的概念,所以我們可以計算哪些詞是互相接近的。該方法的作者舉了一個例子(就是下圖),用來計算跟
但是除了詞,我們對別的事物也可以進行高維度的編碼,比如我們接下來要介紹的金融市場資料。
Market2Vec
第一個我聽說的詞嵌入演算法是 word2vec 。我想在金融市場資料上面得到相同的效果,雖然我會使用一些比較不同於 word2vec 的演算法。我的輸入資料是 csv 格式的。第一類表示日期,另外的 4*1000 列對應於 1000 只股票的高低開倉價。那麼,我們的輸入向量就是 4000 維度的,這個維度太大了。所以,我們第一件事就是把這個高維度的向量壓縮到一個低維度的向量,比如說 300 維度(因為我們喜歡這個電影 ^_^)。
如果你覺得把一個 4000 維度的向量壓縮到 300 維度是一件很難的事,那麼你就大錯特錯了。其實這很簡單,我們只需要乘以一個矩陣,矩陣就相當於一個巨大的 excel 表格,每個單元格中都會有一個數字,並且不存在任何的格式。想象一下,我們有一個 4000 列和 300 行的 excel 表格,我們把這個表格與上面的 4000 維度向量進行相乘,那麼我們就可以得到一個 300 維度的向量。這個就是最基礎的線性代數知識,你肯定能明白。
那麼,現在的難點就是如何去設定這個巨大的表格矩陣,“深度學習” 就是用在這個矩陣的初始化和更新上面。最終,這個電子表格矩陣將會是一個不錯的轉移矩陣,可以將我們的 4000 維度向量轉換成一個簡潔的 300 維度向量。
接下來,我們要做一些比較神奇的事,那就是啟用函式。我們要給每一個值加上一個啟用函式。將這個啟用函式新增到每一個值上面,將每個值的大小歸到 0 到 1 之間。那麼,為什麼這樣做可以使得我們的向量更加特別,可以學習和理解更加複雜的事。你可以點選這裡進行學習。
那麼接下來我們需要處理的重要的事就是如何去找到這個轉移矩陣,使得我們可以損失更少的資訊,將高維的股票向量轉換成低維的股票向量。我們希望能利用這個向量來挖掘各個股票之間的相關性,也許我們會發現當某個行業下滑時,另一個行業的股票也會下滑。當然,我們可能也會發現一些別的特徵,我認為這對我們將來的研究會非常有用。
初步接觸神經網路
讓我們先把股票向量放在一邊,來談談語言模型。Andrej Karpathy 寫了一篇很流行的文章
。如果我們學習莎士比亞的作品,然後一個字一個字的進行學習。那麼我們可以深度學習來學習一種語言模型。
在這種情況下,語言模型是一個魔術盒。你可以提供一句話的前面幾個字元,模型就會告訴你下一個字元是什麼。
如果我們把語言模型的預測結果重新輸入到語言模型,那麼我們模型將永遠執行下去。
然後這個模型會產生一大堆看起來像莎士比亞風格的文字。然後,我們也可以將這個思想用在 Linux 原始碼上面,然後程式來產生程式碼。或者,我們可以用在幾何代數課本上面,讓程式來產生內容。
這個魔術盒的實現機制我們會在後續進行介紹,但是讓我們先來假想一下,Karpathy 是利用前面的一些字元來預測下一個字元,那麼我們是否可以根據之前的市場向量,來預測下一個市場表現、市場向量或者別的東西,而這個預測模型就是這個魔術盒。我們還沒有決定我們想要預測的是什麼,但是沒有關係,因為我們不會將我們的輸出反饋到我們的輸入中。
更加深入分析
我想指出,從現在開始我們要開始深入的去分析深度學習。到目前為止,我們只是使用單層網路進行學習,也就是隻是使用我們上面設計的按個 4000 * 300 的轉移矩陣。接下來,我們會新增更多的層次,來設計一個深層的神經網路來設計這個市場向量,這就是深度學習。
所以,Karpathy 向我們介紹了一些 Linux 例子的輸出,下面的程式碼就是魔術盒的內容:
static void action_new_function(struct s_stat_info *wb)
{
unsigned long flags;
int lel_idx_bit = e->edd, *sys & ~((unsigned long) *FIRST_COMPAT);
buf[0] = 0xFFFFFFFF & (bit << 4);
min(inc, slist->bytes);
printk(KERN_WARNING "Memory allocated %02x/%02x, "
"original MLL instead\n"),
min(min(multi_run - s->len, max) * num_data_in),
frame_pos, sz + first_seg);
div_u64_w(val, inb_p);
spin_unlock(&disk->queue_lock);
mutex_unlock(&s->sock->mutex);
mutex_unlock(&func->mutex);
return disassemble(info->pending_bh);
}複製程式碼
請注意,該魔術盒可以知道如何去開啟和關閉括號,並且能遵守程式的縮排約定,也就是函式程式碼的正確縮排,多行 printk 語句也具有正確的內部縮排。這也就意味著這個魔術盒可以理解程式碼的遠端依賴關係,即魔術盒可以聯絡到前面的程式碼進行分析推敲。當它預測在 print 語句中時,它會知道它在一個 print 語句中,並且會記住它是在一個函式中(或者至少記住是在另一個縮排範圍)中。太好了,這就很容易理解,具有捕捉細節和記住長期依賴關係的演算法是非常有用的,因為我們也是希望能在市場上找到長期的依賴關係。
深入探索魔術盒
那麼這個神奇的魔術盒裡面有什麼呢?它是一種被稱為 LSTM 的迴圈神經網路(RNN)。RNN 是一種深度學習演算法,它擅長的是對序列進行操作(如字元序列)。在每一步,它對會對下一個字元進行預測,並且使用一個矩陣記性表示,就像我們之前看到的那樣。因為 RNN 有一些內部的記憶,所以它可以記住一些以前看到的東西。它會使用這個內部記憶來決定下一次輸入中應該如何操作。使用該記憶體記憶,RNN 可以記住它在一定範圍內的內容,這就是我們為什麼可以對輸入文字進行預測處理。
RNN 有一個很好的變體稱為 LSTM,LSTM 巧妙的設計了 RNN 內部的記憶單元,這個單元可以做以下事:
可以選擇性的記住一些東西;
可以選擇性的去忘記一些東西;
選擇應該輸出多少記憶記憶體;
所以,當一個 LSTM 看到一個 “{” ,並且對自己說“這個非常重要,我應該把它記住” 。而當它這樣做時,它基本上就記住了這是一個巢狀的範圍。一旦看到相應的 “}” ,它就會決定忘記原來的大括號,因此忘記它在一個巢狀的範圍內。
我們可以將幾個 LSTM 堆疊在一起,這樣 LSTM 可以學習到更多的抽象概念。現在,前一個 LSTM 的輸出變成了下一個 LSTM 的輸入,每個 LSTM 會學習到更加抽象的資料。在上面的例子中(這個只是說明性的猜測解釋),第一層的 LSTM 可能會學習由空格分割的字元,下一層可能會學習像(static void action_new_function)這樣的字元型別,下一層可能會學習函式的概念以及引數等等。雖然 Karpathy 在部落格中已經有非常好的說明例子了,但是要清楚的說明每一層的具體任務還是非常苦難的。
Market2Vec 與 LSTMs 的結合
你可能會注意到,Karpathy 使用字元作為他模型的輸入,而不是詞嵌入(技術上是使用 0-1 編碼)。但是,Lars Eidnes 在
文章中使用詞嵌入來處理。上圖顯示了他使用的網路。我們先不考慮 softmax 部分(這部分我們後續介紹),先來看看 LSTM 堆疊和模型的輸入部分。我們發現模型的底部輸入是一系列的單詞向量(記住,一個詞向量表示的是一個單詞的語義)。Lars 輸入一個字向量序列,其中每一個作用如下:
影響第一個 LSTM;
前一個 LSTM 的中間輸出作為下一個 LSTM 的輸入;
前一個 LSTM 輸出的下一個字作為下一個 LSTM 的輸入;
雖然我們要做同樣的事情,但是可能有一點小小的區別,我們不是把字向量作為輸入,而是我們的 Market2Vec ,這個市場向量就是我們之前描述出來的。我們來回顧一下,對於給定的時間點,我們的 MarketVectors 應該包含在這個時間點發生的市場情況的總和。通過 LSTM 的序列化,我們希望能夠捕捉到市場上發生的一個長期依賴關係。通過幾個 LSTM 的堆疊,我們希望可以得到更高層次的市場行為抽象資料。
我們來談談股票
在 Karpathy 的例子中,LSTM 的輸出是抽象的表示下一個字元的預測向量。在 Eidnes 的例子中,LSTM 是輸出下一個字元向量。這兩種情況的下一步都是將一個抽象的事物表示成一個概率向量,這是一個概率列表,說明每個字元或者單詞在下一個位置出現的可能性。這裡則是 softmax 函式在工作了,一旦我們擁有了這個概率列表,我們則需要選擇出最有可能出現的單詞或者字元。
當我們處理“市場預測”的問題時,我們需要問自己,我們真正想要預測的是市場的什麼情況?我這裡有一些自己的想法,大家可以參考一下:
預測 1000 支股票中每一支股票接下來的價格變化;
預測在接下來的 n 分鐘內,一些指標(S&P,VIX等等)的變化;
預測在接下來的 n 分鐘內,哪些股票的價格將上漲超過 x%;
(我個人最喜歡的)預測哪些股票在接下來的 n 分鐘內,上漲/下跌 2x%,而這段時間內不會下跌/上漲超過 x% ;
(本文將會介紹的)預測在接下來的 n 分鐘,VIX 的值上漲/下跌 2x %,而這段時間內不會下跌/上漲超過 x%;
第一和第二個就是迴歸問題,我們必須預測的是一個實際的數字而不是一個特定事件的概率(比如字元 n 出現或者市場上漲)。這個非常準確,但是不是我想做的事。
第三和第四是兩個非常相似的問題,他們都要求預測一個事件(技術術語,就是一個類標籤)。這個事件可能是接下來出現字母是 n ,或者接下來10分鐘內某隻股票是否會上升 5%,而不會下降超過 3%。第三和第四之間的權衡關係是,第三個問題更加常見,因此更容易學習到,而第四個問題更加有價值,它不但對利潤有預測,而且對風險也有一定的約束。
第五個問題是我們在這篇文章需要解決的,這個問題跟第三個和第四個問題非常類似,但是它更加容易一些,因為我們有一些機制可以遵循。VIX 指數被稱為恐怖指數,它代表了 S&P 500 指數的股票波動。它是通過觀察指數中每個股票的隱含波動率得出來的。
為什麼預測 VIX 指數?
那麼我們為什麼會去預測 VIX 這個指數呢?原因主要如下:
這只是一個數字,而不是 1000 支股票,這就使得我們在演算法設計上會更加簡單,計算成本也會降低很多;
這是多個股票的總結,所以跟大多數股票是相關的;
它不是單純的對我們的輸入資料進行線性組合。隱含的波動率是從一個非常複雜的非線性公式中計算出來的,而 VIX 是基於這個波動率再進行推導得出來的。如果我們可以進行預測,那麼這將是一件非常酷的事。
這個是直接可以用來指導交易的額,如果我們真的可以設計出一個有價值的網路,那麼我們就可以直接線上上使用它。
繼續討論 LSTM 和 softmax 函式
在未來幾分鐘內,我們如何使用之前的資料來預測 VIX 的變化呢?對於我們資料集中的每一個點,我會在 5 分鐘後再次看到該資料點的 VIX 變化。如果在那段時間內上升了超過 1%,但是沒有超過 0.5%。那麼,我們的模型將輸出 1,否則就是輸出 0。然後我們會得到如下一系列的標籤:
0,0,0,0,0,1,1,0,0,0,1,1,0,0,0,0,1,1,1,0,0,0,0,0 ….複製程式碼
我們想利用之前壓縮的市場向量,然後輸入到 LSTM 模型中得出最終的概率結果,從技術上來分析,因為我們最終只要輸出一個標籤,我們也可以使用 sigmoid 函式,但是如果我們做二分類結果,還是建議使用 softmax 函式。
所以,在我們深入分析這個演算法應用之前,讓我們先來回顧一下我們已經學習了哪些內容:
我們以 1000 支股票的價格作為輸入資料;
資料序列中的每一個時間點都是市場的一個快照反饋。我們使用一個壓縮網路,將輸入的 4000 維度壓縮到 300 維度;
現在我們有一系列的股票市場向量,我們把這些股票向量輸入堆疊 LSTM 中,然後按照每個時間步驟來進行學習。LSTM 會記住一些市場之前的有效資訊,這些資訊會影響後續的市場反饋;
我們將第一層 LSTM 的輸出傳遞到另外的 LSTM 結構。這些結構會記住一些更高層次的抽象資訊;
最後,我們會根據堆疊 LSTM 的最後輸出,利用 softmax 函式來得到VIX 在接下來5分鐘內上漲 1%,而不下降 0.5%的具體股票;
這個過程是如何選擇的?
現在是最有趣的部分。我們現在所做的一切都可以被稱為是一個前向的過程。當我們訓練演算法時,我們也會去做以上的那些步驟,然後部署到生產環境中使用它。現在我們需要討論的是一個反饋的過程,這個反饋是我們需要在演算法中進行學習的過程。
在訓練的過程中,我們不僅準備了數年的歷史訓練資料,還手動準備了一系列的預測目標,0 和 1 都是我們對歷史資料進行打的標籤。
為了學習,我們需要將市場資料輸入我們的神經網路,並且將網路的輸出結果和我們的標籤資料進行對比,最後得到一個損失值,這個對比函式就是一個損失函式。在我們的例子中這個對比比較簡單,我們可以將我們的損失函式設計如下:
ERROR = (1/2)*(((precomputed)— (predicted probability))² )複製程式碼
這就是一個損失函式。也就是說,我們可以去計算出深度學習模型的輸出值與準確值之間的誤差有多大。根據這些誤差,我們可以利用一些更新函式來更新一整個網路的權重,從而得到一個比較好的模型。
該更新過程會一直更新到模型的開始,所以模型會不斷的調整我們的 MarketVectors 向量,以便我們的 MarketVectors 可以表示更多的資訊。
LSTM 模型可以選擇去記住哪些內容和忘記哪些內容,以便模型可以分析那些與我們任務最相關的量。
LSTM 模型還可以學習資料的更加抽象表示,以便模型學習資料更多的特徵。
這一點是非常讓我吃驚的,因為深度學習可以學習那麼多負責和抽象的東西。我們從前都沒有接觸過這種模型。
一些想法
對於這個專案我還有一些更加深入的想法,一些我可能還會嘗試的想法,並且我認為這些想法對實際專案時有用的。
市場流動性和資金的有效利用
一般來說,特定市場的流動性越高資金的利用效率越高。我認為這是一個雞與蛋之前的迴圈,而市場變得更加的流動,它能夠吸收更多的資本交易,並且資本收到的損害最小。隨著市場變得更加流動,更多的資本可以在市場中使用,你會發現更多複雜的交易玩家會進入市場。
一個快速的推論是,在一個比較不流動的市場中,競爭並不是那麼複雜,所以這樣的機制可能會帶來機會,我會在這樣的市場嘗試交易。
股票市場的新應用
這些演算法的知識和架構對計算機領域是比較陳舊的,但是在股票金融領域的應用是一個全新的應用。我們假設一些頂級玩家已經在使用這些技術進行套利,並且可能已經很長一段時間了。但是正如我前面提到的,他們可能是在一個流動性很大的市場進行套利工作,他們需要很大的市場資金規模,這樣才能去平攤他們的運營成本。我認為,下一次的市場應用會在那些流動性比較小的市場,這些市場還沒有被開發完全,存在很大的套利空間。
多個時間幀
雖然我在上面提到的是輸入一個單通道的資料流,但我認為一個更加有效的訓練方法是在多個時間通道上面對市場資料進行訓練。也就是說,我目前採用的是 30 秒取樣一次,我希望網路可以解決幾個小時的資料依賴關係。
我不知道這個想法是否有意義,但是我認為如果我們可以將計算成本降低到一定程度,那麼我們可以把多個時間點進行融合訓練。這個融合模型的訓練我還在思考中,目前有點困難。
MarketVectors
當我們在自然語言處理中,使用的詞向量模型都是在一個預訓練模型之上進行微調的。但是在我們的情況下,沒有一個預訓練好的市場向量可以使用,也沒有一個明確的演算法去進行訓練。
我原來的想法是使用一個自動編碼器來進行訓練,就好像這篇論文,但是端到端的訓練好像看起來更加酷。
更重要的考慮是,端到端的序列模型在機器翻譯領域已經比較成熟了,也就是說我們可以把一些文字編碼成一個向量,並且進行解碼。在這種觀點下,我所描述的整個架構本質上就是一個編碼器,但是我還沒有真正的設計出一個解碼器。
但是,對於網路的第一層,我想設計一個特殊層,即我們需要把輸入的 4000 維度向量降維到一個 300 維度的向量。通過這些低維度的向量,我們需要去找到各個股票之間的一些關聯度。
另一個替代的方向是對每個 LSTM 輸入一個資料,然後編碼成一個輸出向量。但我認為這個可能是無效的,因為各個資料模型之間的相關度會下降很多,並且這種方法會需要 10 倍的計算資源,比較浪費。但是從另一方面來說,這種架構可以多個 GPU 進行訓練,可以提高一點速度。
CNNs
最近,字元級的機器翻譯方面出現了很多的論文。這篇論文帶給了我很多的啟發,因為這篇文章試圖採用 CNN 來解決長距離的依賴關係,而不是 RNN 。我還沒有深入的去閱讀這篇論文,但是我們可以假想一下,我們把每個股票當做一個通道(類似於 RGB影象的三個通道),然後把每個通道輸入卷積模型中進行卷積操作,從而來捕捉市場的長期依賴資訊。這種方法跟他們從字元級別上進行語義編碼的方式是相同的。
演算法社群直播課:請點選這裡
CoderPai 是一個專注於演算法實戰的平臺,從基礎的演算法到人工智慧演算法都有設計。如果你對演算法實戰感興趣,請快快關注我們吧。加入AI實戰微信群,AI實戰QQ群,ACM演算法微信群,ACM演算法QQ群。詳情請關注 “CoderPai” 微訊號(coderpai)。