用 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 library

2. 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個策略組合算。

還有一個是用了多線程,因為資金量沒到幾百上千萬的地步,所以沒必要考慮成交量的問題,也就是買賣點和你有多少資金無關,那麼每隻股票就可以並發算出買賣點,最後再一起用賬戶資金加滑點算收益。


推薦閱讀:

怎麼看待最近 Python 變成 Web 開發語言排行第二?
ruby和python該學那一個?

TAG:Python | 寬客Quant | 量化交易 |