Quant 如何運算百萬行的數據?
我實際工作中需要用到不少quant的知識~而我只是半路出家的量化交易員~沒有受過系統性的職業訓練~VBA matlab懂點皮毛~C++完全不會~我是遇到問題再去找書本~現在請教一下專業的quant如何解決如下的實際問題..
上百萬行數據進行運算的問題~我用matlab非常慢~問過一些人說是自己用C++編程去運算~我想問一下是否還有專業點的專門處理大量高頻金融時間序列數據的軟體
不知道「行」是一個什麼概念,猜測大概是指CSV文件中的行?假設如此,那麼百萬行實際對應的就是百萬條數據,按照平均每條數據100位元組(相當高估的數值)來估算,也就是總計100MB數據量。這個數據量是什麼概念呢?一塊普通機械磁碟的讀取速度大概有80~100MB/S,就是說一兩秒之內就能讀取完全部數據。如果你做的計算僅僅是一些簡單的查詢或是加減乘除(比如Moving Average),CPU的速度會遠遠快於硬碟訪問,既是說在一台普通的個人電腦上,應該在幾秒內就能完成計算任務。這個數字是頭腦中應該有的正確的估算。有了這個概念,我們再來看看問題該如何解決。
首先,CSV格式是一個很差的存儲格式。CSV按行存儲,每讀入一行都要按照分隔符進行拆分。它的數據全部以文本形式存儲,意味著每讀入一個浮點數比如1.234就要進行字元串到數字的轉換。這些都是完全不必要的開銷,會大大增加任務的處理時間。
其次,有人建議把數據導入到SQL資料庫,這也是個壞主意。SQL資料庫的確可以提供一些遍歷的查詢和索引,但是每次訪問資料庫都需要進行進程間通信,如果你需要逐條訪問,這個通信時間也會非常昂貴,遠遠超出真正計算所需要的時間。
簡言之,以上兩種方案里你的大部分時間都浪費在無意義的I/O上,計算機的使用效率非常低。
下面給出幾種方案建議,可以根據個人情況選擇:
一,使用內存資料庫(如KDB),百萬條數據導入內存資料庫也不過100MB左右的內存佔用,毫無壓力。在此基礎上使用系統支持的語言(比如KDB中的Q)進行演算法開發。這是quant界比較常見的一種方案,應該有成熟社區,容易找到幫助,如果你所在的機構正好有這方面的技術積累,就更方便了。缺點在於,數學計算比較受限於系統,如果你用到一些系統沒提供的演算法,開發成本比較大。KDB的語言本身需要陡峭的學習曲線,甚至很多方面可能非常晦澀,比如一個 ! 就可以根據上下文不同表示多種不同的操作符,從取模到生成列表,對於新手來說入門可能有些困難。
二,python神器:ipython+pandas。ipython提供一整套的類似matlab的計算環境,包含了豐富的數學函數和畫圖工具,示例可參見http://nbviewer.ipython.org。pandas則是專門針對金融類計算設計開發的計算庫(Python Data Analysis Library),底層使用HDF5格式(一種高效的數據存儲格式,對於金融時間序列來說遠遠優於CSV),上層提供很多強大的內建函數(統計類的mean,stddev,類SQL的group by,order by等等),而且本身工作在python環境里,可以直接使用python做編程方面的工作。更值得一提的是HDF5也是matlab支持的存儲格式,所以有必要的時候可以無縫遷移到matlab(如果正好有某個演算法是matlab提供而python沒有的)。需要強調的是python在科學計算方面有巨大的優勢,是統治級的語言,像並行計算,GPU之類都有很好的支持,不用擔心要自己搭框架。
三,其他備選的還有如下一些:
The Julia Language 一個比較新的計算語言,介紹里強調了高性能,具體用起來怎麼樣不清楚所以不評價。
Java/Scala,java本身代表巨大的社區支持(豐富的第三方庫,文檔,優秀的開發環境),scala則提供強大的開發能力,以及像Apache Spark?這樣的大數據處理利器 。java系在各種數學軟體比如Matlab,Mathematica,R都可以直接內嵌,所以可以結合java在數據處理上的性能優勢和數學軟體的數學功能來一起使用。
我談談我用辦公桌上的小破臺式機,跑千萬行級數據的經驗。
我使用MS SQL進行計算,並用如下這些方法,解決大數據時的運算效率問題:
------------------------------------------------------------------- 第一步,優化欄位
- 原始數據導入數據時,對所有欄位進行優化,儘可能地爲每個欄位選用最小的欄位類型
- 字元型欄位,一般導入時默認會是nvarchar型,改爲varchar型節省一半空間。
- 數值型欄位,如果是整數,如果最大可能數小於255,改爲tinyiny,如果最大可能數小於32768,改爲smallint,如果長度小於9位,改爲int。如果帶小數點,精度要求不是非常高的話,改爲real。
- 日期型欄位,如果只需要精確到天的話,改爲date型
- 這樣經過優化之後,該數據所佔的文件尺寸常常能縮小一倍左右。數據查詢的性能會得到一定的提升。
- 第二步,橫向拆分表
- 按照關係數據庫三範式的原則,對原始的數據表進行拆分。一張原始表,一般能拆解成分散開來的十幾張表。通常來說,拆解後的表,會有一張核心的「事實表」,和多張「維度表」組成。
- 大多少情況下說,適當拆表後,這張核心的「事實表」,只會剩下很少的幾個欄位(列),但行數會很多,幾千萬或上億行。而其它的「維度表」,則是欄位(列)很多但行相對很少。
- 舉一個例子,比如說原始的數據表中,有Year,Quarter,Month,Week,Date五個欄位,那麼實際上我們只需要保留Date這個欄位在核心的「事實表」表內即可,其它的Year,Quarter等欄位可以通過拆分出來的日曆表(「維度表」),在需要的時候再匹配回來。
- 經過這第二步優化後,該數據所佔的文件尺寸一般能在前面第一步的基礎上,再縮小數倍。
- 第三步,縱向拆分表
- 在數據量巨大,同時可以按年或季度劃分數據時,將上一步分好的核心「事實表」,再按不同的年份或季度拆分成各個分開的表,能進一步提高數據分析時的查詢速度。
- 縱向拆分出來的表,表結構完全相同,只是用不同的表名存不同年份或季度的數據。
- 不用擔心後期分析時麻煩,後期分析時可以用視圖再把這些表連在一起,所以最後分析數據時,不管前面的步驟拆了多少張表,最後只需要連接使用單獨的一張最終視圖就可以。
- 第四步,建立索引
- 對應所有的表,都應該儘可能的建立主鍵。
- 建立主鍵的第一個好處是,它可以提高「事實表」和「維度表」查詢時的關聯速度,也就是提高最後進行分析運算時的查詢速度。
- 建立主鍵的第二個好處是,它可以預防導入重複的數據,保證數據的正確性。
- 對應有可能經常被用做查詢時作爲過濾篩選條件的欄位,應儘可能都建立索引。但索引會佔據額外的磁盤空間,同時降低寫入新數據和修改數據的速度,所以索引欄位也不宜太多。對於以查詢爲主的表,可以多建一些索引,但對於會大量實時修改的表,則不宜有太多的索引欄位。
- 這第四步的優化,可以使得在後面分析查詢時,數據篩選的效率翻倍的提高。
- 恰當的硬體
- 其實CPU不太重要,如果任何時候如果你在跑SQL數據查詢時發現你CPU負荷100%滿了,那一定是你的查詢代碼寫錯了。
- 下面兩個部件,可以提升數據查詢的速度:
- 第一是內存,能配多大配多大。如果是32Bit的操作系統的話,配到4GB內存(再多的部分32Bit的OS認不了),如果是64Bit的OS的話,配到你主板能支持的極限。(記得打開MS SQL的AWE內存分配功能)
- 第二是硬盤,簡單的說,配個SSD硬盤能讓你的SQL速度倍增。
- (另外記得再多買個硬盤備份,不然數據沒了沒處哭去的……
- 正確的查詢語句
- 簡單地說,就是在寫查詢語句時,要寫成像捲心菜一樣一層一層往外逐步過濾匹配數據。不要寫成一棵大樹一樣一口氣試圖關聯所有數據進行匹配計算,那樣笛卡爾乘效果形成的數據膨脹,能讓你的SQL跑上半天也不理睬你。(CPU 100%負荷就是這麼出來的)
------------------------------------------------------------------
經過這些優化之後,我拿我自己的小破臺式機,跑千萬行級的數據表示毫無壓力,一般一些零碎的小分析都是幾分鐘就完成了。
以上談的,是自己在提高SQL大數據計算速度的一點經驗。謝邀。其實這是一個資料庫部署和演算法優化的問題,只是您的提問方式把它封裝成了一個看似Quant的問題。類似的困境在很多其它領域也有。我這裡把你的問題梳理一下,然後變成一個純計算機問題,並提出我自己的解決方案。同時我相信在我梳理後,知乎上更多的數據處理大牛可以來拓展思路。
我自己曾經接觸過的最大的一個數據是1986年1月1號到2011年12月31號的美國三大市場(NYSE,NASDAQ及AMEX)中所有股票的每日收盤數據,總共有48,796,680條記錄,裸數據大小在2.5GB左右。數據從Wharton Research Data Stream (WRDS)獲得,最開始的格式是CSV。
我當時的研究要對每個月的所有股票進行因子分析(Factor Analysis)來驗證幾個假設,最開始我打算使用R來做,因為一般小規模數據R做起來很方便,R你不熟悉沒有關係,你可以理解為運算速度和編程思想類似Matlab的一個統計專用語言。很快我發現把這些數據全部讀取進來就要花費巨量的時間,更不要說一個月一個月的運算了。當時手頭有別的事情,因此我暫緩了這個研究。
後來有一天跟原來在Lehman Brother做Quant的一個朋友聊天,說到這個挑戰,他建議我用MySQL來部署,然後通過資料庫查詢來加速特定月、特定公司的數據抓取。我當時豁然開朗,之前我使用資料庫很多,但是由於大部分時間研究工作不用這麼大數據,所以完全沒有往這方面考慮。另一個原因是寫資料庫級別的研究代碼要比純R+CSV或者Matlab+CSV/Mat麻煩很多,我心理上迴避這種思路。
之後老闆催得急,我就開始具體化了,最後我使用Python+NumPy+SciPy+SQLite的架構,然後對SQLite進行了大量的索引、緩存等優化,最後使得整個code可以在10個小時內跑完。但是代價就是,我需要自己寫程序計算線性回歸的R Square、t-Stat等在Matlab、R中非常容易實現的任務。最終Python代碼有2000行左右。
這個研究結束後,我又思考了很久這個問題,我覺得有兩個補充的思路:
第一、分解數據:需要根據具體情況分析,比如我的研究,其實可以把大CSV原始數據拆解成每年每個月的(以yyyyMM.csv的格式儲存),那子文件的數據量就可以降一到兩個數量級,這樣就可以用Matlab來處理,同時也間接完成了索引的工作。
第二、如果數據實在是非常巨型(100GB+),我建議採用非關係型資料庫(MonoDB等)來處理。如果你有興趣,可以看伯克利今年開的一門公開課:Big Data,來進一步學習:
UC Berkeley Course Lectures: Analyzing Big Data With Twitter
如何選擇方案應該看你的使用場景和如何使用數據。多用戶高io高並發,資料庫當仁不讓。
作為量化交易而言,金融數據多為時間序列,為了多快好省一般是讀取大塊數據到內存然後進行操作。如果你的使用情景與我上述類似,推薦用hdf5文件存儲。做好索引也可以實現簡單的基於時間或某列的query。
此外還可以使用kdb+q, 4g版本是免費的,就是q語言學習曲線非常陡峭。
以上兩者的數據儲存方式對時間序列的支持非常好。
此外不是特別推薦mongodb作為tick解決方案,除非你多數時候是逐筆回測遍歷為主。原因是monggodb類json的結構導致數據轉化成數組或dataframe會有額外開銷。sql更是不推薦了。
另外一個就是盡量向量化運算。我做二十萬行的回測時間在秒級別。就算是做參數遍歷優化 壓力也不大。很多牛人的認真回復,長了不少知識。談談我的所知,希望對大家有幫助!
@袁浩瀚 提出一個很有趣的問題,這個數據問題到底是quant問題還是純技術問題。我對這個問題敏感的原因是,在一些大團隊,技術部分和業務部分是獨立的體系,相互協作配合間難免扯皮推諉。
對於這個問題我的理解是,這是一個業務需求,與編程語言,數據存儲格式,資料庫選型都有直接或間接關係的技術的問題。
一個針對量化的數據應該具備(大數據的Apache Hadoop就不提了)
數據源服務包括:實時數據,歷史數據,回放支持以及各種指標支持;
-實時行情服務
-支持標準bar和定製bar數據:如7秒,13秒的bar數據
-能靈活自定義衍生指標
-查詢、提取歷史行情api支持
-能支持回放歷史數據,並模擬交易
-行情訂閱方式,支持通配符,支持任意組合
部署:通過內存資料庫+物理庫+數據配適層的方式比較合適quant用
以A股高頻數據為例,以問答方式提出幾個問題:
1、股票數據多少秒存一筆?1天市場存多少條數據?
一般不到6s,介於3-6s之間,考慮到交易股票交易頻率,可能不是實時都有交易,平均下來基本應該在6s左右
一天的量計算公式:一隻股票*(4小時*60分鐘*60秒/6)*股票數
平均下來,2600隻股票計算的話,大致是 6240000 條
2、資料庫存
從我了解的情況來看,
1)、sqlserver應該基本排除,不適合這種大數據處理;
2)、oracle,db2,sybaseIQ供選擇,可以根據具體情況,具體業務查詢方式選擇一個或多個類型。其中db2,sybaseIQ屬於列式存儲數據,在大數據處理方面有優勢;
3)、mango+mysql,mysql可以考慮加上mongo之類的NOSQL資料庫來輔導,一般原始數據放mysql里,再開發一套掃描程序,根據業務需要,生成固定格式數據放到mongo里去。這種方式主要就是程序上繁瑣,性能上應該不比關係型資料庫差多少,有些方面可能應該更好點。
3、存儲方式
1)分散式存儲問題,oracle,db2,mysql都支持分散式部署,mongo也支持,分散式部署對性能有好處,當然對後期維護難度加大很多,比較考驗運維能力;
2)、存儲肯定要分片來,具體可能要按照業務需要來,可以考慮這裡說的,按股票來分,每個股票一張表,單個表再按日期分,這樣對單個股票查詢來說比較快。
就這麼多,有點班門弄斧的感覺,供參考,不對之處請指教。
很多答主提供了不錯的解決辦法和思路。結合自身的經歷,我補充下選擇方案的時候可能需要考慮的問題:
- 是否需要頻繁訪問?
- 是目的明確的數據操作還是exploration?從數據中選取特定樣本還是遍歷所有的數據?比如你需要不斷訪問這些數據去測試不同的模型,驗證一些想法,那麼你可能會需要很多的查詢操作,所以建立關係型資料庫可能是必要的。
- 是否可並行化操作?比如你有明確的想法用這個數據fit一個模型,或者計算一些統計量。你需要遍歷所有的數據,但是你只需要訪問一次或者很少的幾次,那麼通過分割文件,並行處理等選擇一些可以快速解決。雖然未必最優性能的方案,但是能夠幫你快速解決問題。
- 你的數據處理任務是否是time critical的,是RD (比如策略開發等),還是production。Production階段的任務就更需要性能優化。
- 你能夠獲取的計算資源。
TL;DR 語言是Q,資料庫是kdb+,是我知道的投行標配。
趕時髦的說,反對上面的大部分答案。不曉得回答問題中誰有投行的工作經驗,在工作中接觸過Quant。如果沒有的話,不知道為什麼程序員們覺得自己可以回答quant的問題。
在去Google前在新加坡的Merrill Lynch做過一年,主要做處理市場和交易數據,涉及所有亞洲的exchange。語言是Q,資料庫是kdb+: http://kx.com/kdb-plus.php。期間經常需要處理Quant的requirement,基本上是給他們一個KDB的port然後他們自己用q query。 @袁浩瀚 答案里2.5GB的裸數據真是不大,只是不知道他們為什麼不用Q,大概是太貴吧。
Q和KDB在投行外面名聲不顯。一是語法反人類,steep learning curve。二是應用情況有限。三是太他媽貴了。但一幫人沒聽說過Q,然後狂點matlab,python贊的,也挺有意思。python就行了。跑過400多萬數據,3分鐘吧。
@袁浩瀚
a. billion以下的數據mysql就可以了,且大部分統計函數python都有toolkit, 也可以通過python調用R來完成。
b. 分解數據不是太靈活,比如有時要處理某時間段的所有equity,有時要處理所有時間內的某些equity
c. mapreduce/nosqldb對於quant community來說還是fancy了點。
just my two cents.
用kdb. 祝入坑開心。
實際上KDB/Q對Quant/Algo Trading已經基本是標配了,現在各種API也不少,傳統SQL的速度不夠。
另,用Python實現基本的Stats還是很方便的吧。
一樓答案挺好的。。但是對幾百萬行的數據,感覺還是有點大材小用了。。
我在實習的時候,跑過一個月的高頻交易數據,大概83萬行。。和百萬差不太多吧,當時內存還綽綽有餘(個人電腦內存2G),在這個數量級上,感覺matlab還是可以hold住的。。
題主可以考慮從以下幾個方向改進一下:
1. 向量化運算,能不自己遍歷就不要自己遍歷。兩種計算在matlab里真的差太遠了
2. 能調用自帶函數就調用自帶函數,尤其是複雜的計算,比如訓練神經網路,SVM等
3. 將數據切割一下。這個的具體問題具體分析。比如,你可能暫時只需要一支股票的數據,而非所有的。那麼你應該先把這支股票的數據挑出來,然後再計算,而不是一次把所有的數據都放進去。。
轉換成TXT,讀入內存或者資料庫其實非常快,用極其古老如VB都可以很快搞定。我試過用VB操作過所有A股數據,電腦很老,都可以十幾分鐘搞定。
這個問題其實是思路問題,不是什麼大問題。
談一些自己看到的和經驗。
百萬行級別的,資料庫應該就可以解決了,基本上SQL+matlab/R之類的應該不會有太大的問題。當然需要一定的資料庫組織和編程優化的經驗。
金融方面的大數據,我見過的最大的一張表是債券指數成分權重,記錄了指數的每天的權重信息,大概2億多條數據。另外高頻數據也非常可觀,如果是Level2數據一天是2G以上。就算是Level1的tick數據,全市場一天也是百萬級別的。
如果對這些數據處理有兩個辦法,高頻這塊可以考慮KDB+或者OneTick,就是前面提到的Q語言。
另外一個辦法就是內存資料庫,我們曾經做過一個試驗,就是大概是對1年的高頻數據做一個簡單的演算法交易回歸,演算法很簡單,但是會逐筆掃描到所有的高頻數據。使用自己做的內存資料庫,掃一次也就5-20min左右的時間。如果使用普通的辦法估計都需要一整天以上的計算量,如果是百萬級別的數據計算,內存資料庫只需要秒級以內就能搞定了。
「百萬行」如果是處理歷史數據時,一個dataset里有幾百萬個observations的話,用SAS完全不成問題。這個數據量不要用matlab,即便全部實現向量化,還是會慢。而且向量化的過程燒腦,沒必要。
我最近才用過TAQ database里,整個美國股票市場微秒級別的逐筆成交數據。每筆交易是一個observation, 有若干個變數。每個dataset是一個交易日,大概產生三千萬到五千萬筆交易。在雲端用SAS宏命令序貫處理幾年的數據,運行一次大概在20小時以內,效率很高。
給樓主一個案例,是2014年三月用matlab做的一個學生項目,當時的業務需求是利用運營商的基站和通話時間做統計分析,所有的數據量大概是1000萬條。
我的任務是基於不同的id或不同基站的維度下進行統計匯總(統計時長,地區分布等等),然後再做一個關聯規則。因為數據是按時間排序的,所以存在重複的id和基站數的問題,當時一枚大二狗還沒有學過sql,沒辦法直接用資料庫來做。如果直接用循環查找的話,演算法複雜度在n*3,這個很難接受,剛開始我寫了嵌套循環直接處理在i54G內存上跑了12個小時,還是最簡單的匯總任務。
然後問了實驗室的一個大神,教會我用向量化編程的方法,用id索引的方式,加上映射邏輯,整個效率提升非常牛逼,12個小時變成不到兩分鐘。
ps:其實無論是Rmatlabpython,他們都是直接嵌套有向量化編程的,在小型電腦上,他們跑的速度都沒有太大區別,我的經驗是少於10G的都可以考慮在pc上完成,再大就得考慮分散式spark的內存計算了,因為硬碟讀取的速度有極限,GB級別的數據在普通pc上處理還是比較悲催的。
我用julia的SQLite庫的一張表,存了三個月左右的高頻TICK數據,共2222516行,欄位大約Date,Time,Price,Volume等7個,花時情況:
elapsed time: 5.398775057 seconds (659623560 bytes allocated, 19.68% gc time)
這個數據每一次都有一些變化,不過都在5-8秒左右。
如果SSD的話,時間還會少。
如果追求更快的方案,一般不會超過1秒。
真正的問題是,如果數據的行數達到億級,真的考驗才會來。
處理海量數據必然使用SAS,據我所知國家統計局在匯總地區數據時就會用SAS,其他軟體都不夠給力。統計局每年支付給SAS公司的授權費至少數百萬,自然有其道理,銀行等機構也是如此。
我沒接觸過高頻計算,只用SAS處理過60萬元組*10屬性日線數據,簡單運算一般在15s以內,複雜運算也很快(屬性增加基本不影響速度)。我一般只用program,時間序列分析之類的analysis其實SAS特別優化過,應該比市面上其他統計軟體都強。SAS的缺點就是有點複雜,但熟練了都不是事兒,另外運算邏輯與c不同,實現順序的屬性運算效率爆表,但想要實現順逆序結合與迭代之類的演算法要麻煩一點,終究是個為統計而生的軟體。
個人體驗是:SAS在大量數據的處理效率上能甩R、matlab幾條街,在統計軟體中堪稱王者,比stata、spss、eviwes強太多。python沒用過,不清楚其效率,大抵同樣遠比不上SAS。使用SAS幾乎是處理大數據的最高效方式,就算是C語言編程大牛,針對特異性問題也要花很多功夫才可能優化到更高效率,不建議輕易涉足,因為門檻高。matlab是個不錯的計算器,但優勢在於個性化,而非效率,比如大型蒙特卡洛就不是很適合用matlab,否則就等著掛機跑幾天吧。matlab另一個值得稱讚的地方是舍入誤差處理的比較好,無愧於「矩陣實驗室」之名。
最近在做股票數據的回測,遇到的問題的情形和題主比較接近,這裡主要說一下數據儲存的問題。2000-2015年的股票分鐘數據大致有19萬行(5分鐘),95萬行(1分鐘)。考慮到歷史上存在的A股數量大概是2800隻左右(截止2015年),對所有股票進行回測的話,讀取數據花費的時間將相當可觀。由於我現在主要是使用matlab+python+r,所以主要考慮了hdf5,mat,csv三種格式。測試表明,對於19萬行,8列純數字數據,csv寫入需要花費7.45秒,讀入花費1.55秒,文件大小大約是12mb;mat格式寫入花費0.77秒,讀取花費0.11秒,文件大小4,3mb;hdf5格式寫入花費0.033秒,讀取花費0.027秒,文件大小24mb。總的來說csv真的很爛,mat適合小文件,儲存百萬行數據hdf5最合適,而且兼容python和r 。
非常大的資料庫不可用關係型,比如說你的數據是每天的tick data,每天就幾個GB。一般根據自己的需求從線性數據開始構建結構,比較著名的解決方案還是比如說kdb/q和HDF5.他們都不是關係型。
推薦閱讀: