Backtrader多核優化

  |  

利用所有可用的核心是我為反向交易者考慮的事情,但從未完成。支持自然運算,刪除數組符號,包含新指標和 bla, bla, bla。

實際上,我不是優化的忠實擁護者,因此也不是為優化使用所有內核的忠實擁護者。恕我直言,一個好主意值得一百萬次優化。

筆記

最初的多核支持已經存在,並且適用於眾所周知的測試用例集。鑑於pickle表現出的行為,預計其他一些調整可以確保在進行多核優化時所有指標和函數可以在進程之間來回傳遞。

筆記

在 1.0.10.88 版本中已經推送了一些針對多核的額外更正,以使更多“不可挑選”的東西變得可挑選。到目前為止,指標測試沒有顯示任何問題。

但是 BigMikeTrading 論壇中的某個人詢問了該平台與其他平台相比必須提供的功能,我提到了一些功能,例如PyAlgoTrade已經具備(甚至是多機)

完成它所需的小而正確的推動就在那裡。根據過去的經驗,並且因為互聯網上充滿了我已經知道的參考資料:即使是最簡單的多線程(無論 GIL 律師怎麼說)在 Python 中都是不行的,無論版本如何。多線程在 Python 中是假的,因為您有多個線程但沒有並行執行代碼。使用 IO 綁定線程創建抽象和單獨的代碼路徑執行可能很好,但它確實是一個殺手。

然後只剩下一個選擇:模塊multiprocessing或類似的。

展望光明的未來,我決定選擇現代版本: concurrent.futures (後來證明是一個錯誤的選擇)即使這意味著為 Python 2.6/2.7 支持添加外部依賴項。

歷史:

  • Python 的一些動態特性不能很好地在進程之間來回發送數據

  • 酸洗(序列化)諸如未在模塊級別定義的類,lambda,對實例方法的引用和沒有唯一名稱的動態類(即使這些類本身是唯一的)時,所涉及的模塊( pickle )會阻塞

我把這些東西分散在代碼中。然後我從 pathos multiprocess https://pypi.python.org/pypi/multiprocess找到了dill和兄弟姐妹。顯然他們會解決序列化問題,但會增加更多的外部依賴……不,不。

回到繪圖板上,看看是否可以將不可拾取的項目設為可拾取,即使pickle模塊產生了錯誤,這會讓一些老 GCC 開發人員非常高興。

它完成了……還是沒有?

  • 將不可拾取的物品重做為可拾取的東西

  • 使用 Python 2.7.9 運行測試並輕而易舉地運行……使用我機器的 8 個內核流暢而令人耳目一新

  • 使用 Python 3.4.3 運行測試,8 核開始運行,但經過一些優化後,每個後續策略的執行時間會越來越長……直到無法忍受。

    顯然,將結果(一個完整的執行策略)提取到主進程中遇到了與內存分配相關的一些限制(而且我的機器有足夠的可用 RAM……對於幾個小時的並行優化來說綽綽有餘)

一些額外的閱讀讓我考慮簡化我的場景:

  • 使用concurrent.futures似乎是未來的證明

  • 但是標準的multiprocessing模塊已經具備了backtrader需求

聞起來一直在使用矯枉過正,一些很快被重新設計,並且:

  • 測試在 Python 2.7 上運行良好(甚至比以前更快)

  • 測試運行速度與 Python 3.4 一樣快

是時候進行清理,運行完整的測試並執行推送和發布 1.0.9.88。沒有新指標……只是簡單的舊多核優化

閱讀完所有內容……是時候編寫一個關於如何控制優化以使用多個內核的令人耳目一新的腳本了

  • 好消息……無需做任何事情……無需用戶干預即可完成

當用戶希望優化strategy時, Strategy子類被添加到Cerebro實例中,如下所示:

cerebro.optstrategy(StrategyClass, *args, **kwargs)

與將策略傳遞給Cerebro的常規方式相反:

cerebro.addstrategy(StrategyClass, *args, **kwargs)

這一直如此,並沒有改變。背景是:

  • Cerebro需要了解是否要優化策略以正確處理策略的參數,這些參數可能已經是常規策略的可iterables對象

現在……通過optstrategy傳遞給cerebrooptstrategy獲得了使用機器所有可用內核的額外好處。

當然,如果最終用戶希望對使用過的內核進行細粒度控制……這是可能的。創建Cerebro的標準方法:

大腦= bt。 Cerebro () # runonce 是True , preload 是True並且 “new” maxcpus 是 None

maxcpus (此版本的新參數)是控制鍵:

  • maxcpus = None -> 使用所有可用的 CPU

  • maxcpus = 1 -> 不要運行多核

  • maxcpues = 2 … -> 使用指定的核心數

這是一種選擇退出策略,因為多核已經加入。

在具有 16 GB RAM、運行 Windows 8.1 和 Python 64bit 2.7.9 的 4 核(每個核 2x 線程 - 總共 8 個邏輯處理器)機器上進行比較

  • 使用 1 個核心執行:326 秒

  • 8核執行:127秒

不同的測試運行表明,該比率平均約為 2.75:1。

不幸的是,進程的創建/銷毀和對象的來回酸洗具有潛在的好處,但加速仍然很重要。

該圖顯示了正在使用的 8 個內核。

代碼如下。只需將maxcpus參數更改為1即可將測試限制為 1 個核心。

from __future__ import (absolute_import, division, print_function,
                        unicode_literals)

import time

from six.moves import xrange

import backtrader as bt
import backtrader.indicators as btind
import backtrader.feeds as btfeeds


class OptimizeStrategy(bt.Strategy):
    params = (('smaperiod', 15),
              ('macdperiod1', 12),
              ('macdperiod2', 26),
              ('macdperiod3', 9),
              )

    def __init__(self):
        # Add indicators to add load

        btind.SMA(period=self.p.smaperiod)
        btind.MACD(period_me1=self.p.macdperiod1,
                   period_me2=self.p.macdperiod2,
                   period_signal=self.p.macdperiod3)


if __name__ == '__main__':
    # Create a cerebro entity
    cerebro = bt.Cerebro(maxcpus=None)

    # Add a strategy
    cerebro.optstrategy(
        OptimizeStrategy,
        smaperiod=xrange(5, 40),
        macdperiod1=xrange(12, 20),
        macdperiod2=xrange(26, 30),
        macdperiod3=xrange(9, 15),
    )

    # Create a Data Feed
    datapath = ('../datas/2006-day-001.txt')
    data = bt.feeds.BacktraderCSVData(dataname=datapath)

    # Add the Data Feed to Cerebro
    cerebro.adddata(data)

    # clock the start of the process
    tstart = time.clock()

    # Run over everything
    stratruns = cerebro.run()

    # clock the end of the process
    tend = time.clock()

    print('==================================================')
    for stratrun in stratruns:
        print('**************************************************')
        for strat in stratrun:
            print('--------------------------------------------------')
            print(strat.p._getkwargs())
    print('==================================================')

    # print out the result
    print('Time used:', str(tend - tstart))

推薦閱讀

相關文章

Backtrader規範與非規範

這個問題或多或少地出現了幾次:這樣: backtrader如何最好/規範地實現這一點或那樣? 作為 backtrader 的目標之一,可以靈活地 支援盡可能多的情況和用例,答案很簡單:“至少在幾種方式上”。

Backtrader做空現金

從一開始,反向交易者就可以做空任何東西,包括類似股票和類似期貨的工具。當做空時,現金減少,被賣空資產的價值用於總淨清算價值。從一側移除並添加到另一側可以保持平衡。人們似乎更喜歡增加現金,這可能會增加支出。在1.9.7.105版本中,經紀人已將默認行為更改為添加現金和移除價值。

Backtrader改進代碼

時不時地,帶有 backtrader 代碼的示例會在互聯網上彈出。在我看來,有幾個是中國人。最新的一個在這裡: 標題是: backtrader-學習筆記2,這顯然(感謝谷歌)翻譯成 backtrader- 學習筆記2。

Backtrader教程:數據饋送 - 展期交割

並非每個供應商都為可以交易的工具提供連續的未來。有時提供的數據是仍然有效的到期日期的數據,即:仍在交易的日期 這在回溯測試方面並不是很有幫助,因為數據分散在幾個不同的儀器上,這些儀器另外...時間重疊。 能夠正確地將這些儀器的數據從過去連接到連續的流中,可以減輕疼痛。

Backtrader唐鐘斯10天連勝

它已成為新聞。DJI正在創下歷史新高,已經連續10個上漲日和9個歷史高點。例如,請參閱: 當然,許多人已經注意到道瓊斯指數處於這樣的狀態,這篇文章只是告訴我們它正在成為主流。

Backtrader數據同步

在最新版本中,次要編號已從 8 移至 9,以指示即使已考慮相容性,也可能會對行為產生一些影響。 在 1.9.0.99 版中,使用 datetime 同步多個數據的整個機制已經重新設計(適用於下一個和一次模式)。

Backtrader Python隐藏的细节

只有當遇到 backtrader 的真實使用者時,人們才能意識到平臺中使用的抽象和Python功能是否有意義。 在不撇開python的座右銘的情況下, backtrader 試圖為使用者提供盡可能多的控制權,同時通過將Python提供的隱藏功能付諸行動來簡化使用。 第一個示例是系列文章的第一篇。

Backtrader混合時間幀

1.3.0.92版本帶來了混合來自不同時間幀的數據(來自 data feeds 和/或指標)的可能性。 到版本:https://github.com/mementum/backtrader/發佈/標籤/1.3.0.92 背景:指示器是智慧啞物件。 他們很聰明,因為他們可以進行複雜的計算。

Backtrader多數據範例

社區中的幾個主題似乎以如何跟蹤訂單為導向,特別是當幾個data feeds在起作用時,還包括當多個訂單一起工作時,

Backtrader終極振蕩器

backtrader開發啟動時的目標之一是使開發新的指標變得非常容易(至少對作者本人而言),以在數學和視覺上測試想法。 門票#102 是關於將 UltimateOscillator 添加到 backtrader 注意 它將在下一個版本中添加,同時可以使用下面的代碼使用它。 票證中所示的參考: 以及: 無需在這裡重複。