Backtrader策略選擇

  |  

最初的策略選擇方法使用兩個策略,手動註冊和一個簡單的[0, 1]列表來決定哪個是策略的目標。

因為 Python 為元類提供了許多自省的可能性,所以實際上可以自動化該方法。讓我們使用decorator方法來完成,這在這種情況下可能是侵入性最小的(無需為策略定義元類)

現在的工廠:

  • 在策略之前聲明

  • 有一個空的_STRATS類屬性(它之前有返回的策略)

  • 有一個register類方法,它將用作裝飾器並接受將添加到_STRATS的參數

  • 有一個COUNT類方法,它將返回一個迭代器(實際上是一個range ),其中包含要優化的可用策略的計數

  • 對實際工廠方法沒有任何更改: __new__ ,它繼續使用idx參數返回給定索引處的_STRATS類屬性中的任何內容

class StFetcher(object):
    _STRATS = []

    @classmethod
    def register(cls, target):
        cls._STRATS.append(target)

    @classmethod
    def COUNT(cls):
        return range(len(cls._STRATS))

    def __new__(cls, *args, **kwargs):
        idx = kwargs.pop('idx')

        obj = cls._STRATS[idx](*args, **kwargs)
        return obj

像這樣:

  • StFetcher策略工廠本身不再包含任何硬編碼的策略

示例中的策略不需要重新設計。使用StFetcherregister方法進行裝飾足以將它們添加到選擇組合中。

@StFetcher.register
class St0(bt.SignalStrategy):

@StFetcher.register
class St1(bt.SignalStrategy):

過去使用optstrategy將策略工廠添加到系統時的手動[0, 1]列表可以完全替換為對StFetcher.COUNT()的透明調用。硬編碼結束了。

    cerebro.optstrategy(StFetcher, idx=StFetcher.COUNT())

示例運行

$ ./stselection-revisited.py --optreturn
Strat 0 Name OptReturn:
  - analyzer: OrderedDict([(u'rtot', 0.04847392369449283), (u'ravg', 9.467563221580632e-05), (u'rnorm', 0.02414514457151587), (u'rnorm100', 2.414514457151587)])

Strat 1 Name OptReturn:
  - analyzer: OrderedDict([(u'rtot', 0.05124714332260593), (u'ravg', 0.00010009207680196471), (u'rnorm', 0.025543999840699633), (u'rnorm100', 2.5543999840699634)])

我們的 2 個策略已經運行並交付(如預期)不同的結果。

筆記

該示例很小,但已在所有可用 CPU 上運行。使用--maxpcpus=1執行它會更快。對於更複雜的場景,使用所有 CPU 將很有用。

結論

選擇已完全自動化。和以前一樣,可以設想像查詢數據庫以獲取可用策略的數量,然後一一獲取策略。

示例使用

$ ./stselection-revisited.py --help
usage: strategy-selection.py [-h] [--data DATA] [--maxcpus MAXCPUS]
                             [--optreturn]

Sample for strategy selection

optional arguments:
  -h, --help         show this help message and exit
  --data DATA        Data to be read in (default:
                     ../../datas/2005-2006-day-001.txt)
  --maxcpus MAXCPUS  Limit the numer of CPUs to use (default: None)
  --optreturn        Return reduced/mocked strategy object (default: False)

編碼

已包含在backtrader的來源中

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

import argparse

import backtrader as bt
from backtrader.utils.py3 import range


class StFetcher(object):
    _STRATS = []

    @classmethod
    def register(cls, target):
        cls._STRATS.append(target)

    @classmethod
    def COUNT(cls):
        return range(len(cls._STRATS))

    def __new__(cls, *args, **kwargs):
        idx = kwargs.pop('idx')

        obj = cls._STRATS[idx](*args, **kwargs)
        return obj


@StFetcher.register
class St0(bt.SignalStrategy):
    def __init__(self):
        sma1, sma2 = bt.ind.SMA(period=10), bt.ind.SMA(period=30)
        crossover = bt.ind.CrossOver(sma1, sma2)
        self.signal_add(bt.SIGNAL_LONG, crossover)


@StFetcher.register
class St1(bt.SignalStrategy):
    def __init__(self):
        sma1 = bt.ind.SMA(period=10)
        crossover = bt.ind.CrossOver(self.data.close, sma1)
        self.signal_add(bt.SIGNAL_LONG, crossover)


def runstrat(pargs=None):
    args = parse_args(pargs)

    cerebro = bt.Cerebro()
    data = bt.feeds.BacktraderCSVData(dataname=args.data)
    cerebro.adddata(data)

    cerebro.addanalyzer(bt.analyzers.Returns)
    cerebro.optstrategy(StFetcher, idx=StFetcher.COUNT())
    results = cerebro.run(maxcpus=args.maxcpus, optreturn=args.optreturn)

    strats = [x[0] for x in results]  # flatten the result
    for i, strat in enumerate(strats):
        rets = strat.analyzers.returns.get_analysis()
        print('Strat {} Name {}:\n  - analyzer: {}\n'.format(
            i, strat.__class__.__name__, rets))


def parse_args(pargs=None):

    parser = argparse.ArgumentParser(
        formatter_class=argparse.ArgumentDefaultsHelpFormatter,
        description='Sample for strategy selection')

    parser.add_argument('--data', required=False,
                        default='../../datas/2005-2006-day-001.txt',
                        help='Data to be read in')

    parser.add_argument('--maxcpus', required=False, action='store',
                        default=None, type=int,
                        help='Limit the numer of CPUs to use')

    parser.add_argument('--optreturn', required=False, action='store_true',
                        help='Return reduced/mocked strategy object')

    return parser.parse_args(pargs)


if __name__ == '__main__':
    runstrat()

推薦閱讀

相關文章

Backtrader擴展數據饋送

GitHub 中的問題實際上是在推動文檔部分的完成,或者説明我瞭解 backtrader 是否具有我從最初時刻就設想的易用性和靈活性以及在此過程中做出的決定。 在本例中為問題 #9。

Backtrader數據多時間幀

有時投資決策是使用不同的時間框架做出的: 每周評估趨勢 每天執行條目 或者5分鐘對60分鐘。 這意味著需要將多個時間幀的數據組合在 backtrader 中以支援此類組合。 對它的本機支持已經內置。

Backtrader條形同步

文獻和/或行業中缺乏標準公式不是問題,因為問題實際上可以總結為: 條形同步 工單 #23 提出了一些問題,即是否可以 backtrader 考慮計算 相對體積 指標。 請求者需要將給定時刻的 volume 與前一個交易日的相同時刻進行比較。

Backtrader節省記憶體

1.3.1.92版本已經重新設計並完全實現了以前到位的記憶體節省方案,儘管沒有太多的吹捧和使用。

Backtrader 教程:數據饋送 - 開發 - CSV

backtrader已經提供了通用 CSV數據提要和一些特定的 CSV數據提要。

Backtrader教程:經紀商

經紀商模擬器該類比支援不同的訂單類型,根據當前現金檢查提交的訂單現金需求,跟蹤每次反覆運算的cerebro 現金和價值,並在不同數據上保持當前位置。

Backtrader教程:尺寸調整器

智慧質押 策略提供了交易方法,即:buy和 sell close。

Backtrader擴展佣金計劃

佣金和相關功能由單個類 CommissionInfo 管理,該類主要通過調用 broker.setcommission 進行實例化。有一些帖子討論了這種行為。佣金:股票與期貨提高佣金:股票與期貨該概念僅限於具有保證金和每份合約固定佣金的期貨以及具有基於價格/規模百分比的佣金的股票。

Backtrader開場作弊

“發佈”1.9.44.116 添加了對 Cheat-On-Open的支援。這似乎是那些全力以赴的人的需求功能,他們在酒吧 close 后進行了計算,但希望與 open 價格相匹配。 當開盤價跳空(上漲或下跌,取決於是否buysell有效)並且現金不足以進行全面運營時,這樣的用例就會失敗。這將強制代理拒絕該操作。

Backtrader動量策略

在另一篇偉大的文章中,泰迪·科克(Teddy Koker)再次展示了演算法交易策略的發展之路: 研究優先應用 pandas 回溯測試,然後使用 backtrader 榮譽!!! 該帖子可以在以下位置找到: 泰迪·科克(Teddy Koker)給我留言,問我是否可以評論 backtrader的用法。