用 Python 做策略回測,耗時很長,有什麼加速辦法?
用python 做策略回測,耗時很長。40萬條數據花了快一個小時。
想問下,通常50萬數量級的數據的回測用時多少?(簡單策略,一支股票一年的tick差不多40萬) 有什麼加速辦法?-----------------------------------------------------------------------------------------分割線首先真誠感謝各位幫助。回饋知乎,附上我最後的處理方法。本人最後使用了cython 來處理python 中for loop 的部分, 運行時間縮短顯著。建議無法對數據實行整列計算,而只能選擇loop, 逐個數據遞推,來生成一列數據的情況。可以使用cython處理loop部分。
直接上圖,下面是一個生成列的小測試,分別計算兩種方法效率。用時相差2個數量級。
少用for,盡量用numpy/pandas的向量化方法。
少用自己寫的python方法,先看看numpy /pandas是不是已有現成的功能。有幾個numpy 的加速包,比如numexpr.安裝Intel MKL.最後,可以講關鍵部分用c/c++實現。
如果無法避開python的for,建議使用Numba來提速,理想情況下可以達到和numpy向量化差不多的速度。我只能幫你到這裡了||-_-太慢了, 我逐tick(也就是不使用向量化,完全和實盤一樣推送tick)python 回測40w數據大概也是幾分鐘這個級別。我還沒用cython, 只是用numpy。如果向量化回測 只需要十幾秒。
一點小經驗,逐tick的時候不要用pandas,比numpy慢兩個量級。
當然這個速度要做參數優化遍l歷還是夠嗆,目前我是向量化回測找參數,再翻譯成逐tick策略。不過這樣一個策略要寫幾套代碼。容易出bug。
下一步優化考慮一下幾個方案備選, 希望聽聽大家意見:
1.把策略引擎用c++實現 boost.python封裝成python library2. c++引擎調用python策略層
3. cython
如果樓主長期做類似工作,且不是專業碼農,最低成本的辦法還是:
1.升級高頻CPU(假設樓主你就簡單寫寫,不做並行計算,python畢竟全局解釋鎖)2.原代碼大量用資料庫就上SSD/內存表,大量讀磁碟就用RAMDISK,如果原代碼就已經一次性載入內存就忽視這一條。3.用pypy,cython等不修改代碼的優化方式。總結:先根據先有代碼優化硬體,然後使用不需要修改(少修改)代碼的優化方式。一般來說,硬體比人工便宜。如果這還不能解決問題,再用各種奇淫巧技。2016.4.19做的回測,80萬條數據用了3分半跑完(四進程)。用python想降低回測時延,可以從下面幾個角度下功夫:1.有幾個cpu核開幾個進程,記得不是線程是進程。2.在數據結構和演算法上下功夫。
3.在CPU cache命中率上下功夫,loop時操作的數據儘可能在內存上緊湊,不要在loop里遍歷pandas的列,因為這會導致cache命中率大幅降低。而CPU訪問內存的時延遠在訪問cache之上。樓主回測時延高問題應該就出在這裡。可以把pandas的列轉換成list再在loop中使用。
我們目前正在開發的回測引擎使用的也是python,近期也在進行性能方面的優化,以下建議供參考:
1. 在動手優化之前,先profile看看,程序時間都花在哪些地方了:python -m cProfile -o output.prof your_program
跑完之後,會生成一個output.profile文件。接下來需要對這個文件進行分析,這方面的工具我推薦SnakeViz,神器。安裝非常簡單,pip install snakeviz 即可。
snakeviz output.prof
運行之後,會打開一個瀏覽器窗口,好好看看,哪些函數耗時最多,耗時是因為調用次數太多呢,還是因為單次調用耗時長,明確優化重點;
2. 減少重複計算,緩存計算結果。看看 functools.lru_cache。
3. 能用list comprehension的地方,不要用for;能用numpy的地方,不要手寫循環,不要用pandas;
4. 看你的回測,40w個tick的話,數據量不算大,應該是直接load到內存里的吧?
5. 還是慢的話,上Numba — Numba,就是安裝麻煩一些,使用起來非常方便,速度提高一兩個數量級沒問題;
6. 如果你用的包PyPy都支持的話,試試pypy;
7. Cython、c module,上面的都沒效果的話,這個是最後的候選方案了。
----------------廣告時間:我們目前正在招人,歡迎各位投條:Ricequant - Beta一般來說,如果不是做tick級別的portfolio統計套利,大部分的單腿或者兩三腿的策略邏輯都可以通過numpy或者pandas的rolling函數及其他矩陣的操作實現。
無法矩陣化操作的內容較為常見的有如下一些內容:滑動止損/止盈/時間出場,EMA之類的路徑依賴指標,rolling的回歸等等。較為複雜的可能包括一些tick級別的模擬成交回測,當年我還在純用python硬懟的時候回測真是懟的眼淚都掉下來。
然而當我痛下決心花了倆晚上在所有使用tick級別的for循環的地方用c++重寫,然後用swig、 boost.python神馬的一wrap,嘿,腰不酸了,腿不疼了。一口氣測幾年不喘氣了。所以,有什麼可糾結的呢?投入c++大法寫幾個函數,轉眼就超生。numpy,talib為什麼快?因為人家就是用c寫的啊!你這代碼寫得有問題,如果是技術指標,不是每個tick都要從頭到腳運行,如計算MA在100分鐘tick計算是從0-100來遍歷,在200分鐘用0-200來遍歷,不是這樣的,這種方法如tick一多這樣計算到後面是指數增長,再高級的伺服器也hold不住。正確方法是用窗口函數來計算技術指標,只計算窗口有效值,再append到已經計算好的值中去,如計算200tick的MA,根據周期如20,只需要計算過去20個tick,遍歷20次,這樣計算量不會出現指數增長,而是一個窗口計算複雜度*tick長度n。
窗口計算方法和整個遍歷計算不太一樣,需要轉換,talib是一種遍歷方法,你可以一次算完存儲後再使用,但沒有窗口計演算法高效,因為窗口計演算法可以根據條件來判斷計算還是不計算。窗口函數計算方法,可以用於實時分秒策略,來了一個tick,就很快分析出,高頻交易時可以搶到時間。你的大蟒是不是太慢了???
給你的python加速。Cython(語法要改) Numba(兼容性不好,不用改)我覺得多少是你的演算法有問題。在排除演算法問題後可以用PyPy嘗試加速一下。
樓主做的tick級的回測,一次幾隻股票回測幾年?
哈哈,大家都聊的很完整了,
1)其實計算邏輯還是比較重要的,有時候分析你真正需要計算的東西,理清演算法比找工具靠譜
2)計算需要準備的東西是否已經提前在內存準備好(我已默許大家不需要load數據了啊),零星計算歸納為批量計算
如果覺得自己load數據太麻煩,花了90%時間處理數據,可以看看我這篇 "量化策略一般用什麼平台回測?分別有什麼優劣勢? - 鐳礦Raquant 的回答 - 知乎"
太快了,你的想法跟不上......這個數量級,一般十秒左右。
spark hadoop 用nodejs比python快30%
比起計算,主要還是從資料庫里調數據花費的時間最長,我大部分的優化都是集中在如何減少調數據的次數上。講真,CPU關係並不大,ssd硬碟才是王道。
沒代碼,沒演算法,沒數據,沒profile談什麼優化
樓主第一個例子在我電腦上只要372 ms per loop。最簡單的還是升級一下電腦?
多進程去做,然後再合起來處理結論,類似map-reduce的過程,不過需要自己控制好協作過程。
這樣用numpy不太好。建議要麼純numpy, 要麼純native python。
可以考慮先用更大的barsize,再優化你的程序,各種加速等等。
現在我用C#寫的回測程序,每天5個不同股票,7年,分鐘級別回測,大概需要8秒左右,其中7秒都是從資料庫里載入歷史數據,如果第一次載入完,內存里改策略參數大概只需要一秒,tick級估計會慢幾秒不會太多主要沒那麼大ssd硬碟只能存分鐘數據。
比較耗時的從歷史7年數據中選出過去7年每天需要交易的股票,需要3分鐘。就是選股慢,本質就是資料庫里各種組合條件查詢,不知道如何更快。
我的策略都是用狀態機寫的,就是走到那一步才會計算數值,不會提前計算,符合就全部break了。6-7個策略組合算。還有一個是用了多線程,因為資金量沒到幾百上千萬的地步,所以沒必要考慮成交量的問題,也就是買賣點和你有多少資金無關,那麼每隻股票就可以並發算出買賣點,最後再一起用賬戶資金加滑點算收益。推薦閱讀: