Backtrader教程:策略 - 信號

  |  

操作 backtrader 也是可能的,而無需編寫策略。雖然這是首選方式,但由於構成機器的對象層次結構,使用信號也是可能的。

快速摘要:

  • 而不是編寫策略類,實例化指標,編寫買入/賣出邏輯...

  • 最終使用者添加信號(無論如何指標),其餘部分在後台完成

簡單範例:

import backtrader as bt

data = bt.feeds.OneOfTheFeeds(dataname='mydataname')
cerebro.adddata(data)

cerebro.add_signal(bt.SIGNAL_LONGSHORT, MySignal)
cerebro.run()

Et voilá!.

當然,信號本身是缺失的。讓我們定義一個非常愚蠢的信號,它產生:

  • Long 指示價格是否 close 高於簡單移動平均線

  • Short 指示價格是否 close 低於簡單移動平均線

定義:

class MySignal(bt.Indicator):
    lines = ('signal',)
    params = (('period', 30),)

    def __init__(self):
        self.lines.signal = self.data - bt.indicators.SMA(period=self.p.period)

現在它真的完成了。當run 執行時, Cerebro 將負責實例化一個特殊的策略實例,該實例知道如何處理信號。

初始常見問題

  • 如何確定買入/賣出操作 volume

    cerebro實例會自動FixedSize向策略添加sizer。最終使用者可以更改sizer以更改策略cerebro.addsizer

  • 訂單如何執行?

    執行類型為Market “有效”,直到“取消”為止

信號技術細節

從技術和理論的角度來看,可以這樣描述:

  • 一個可調用物件,在調用時返回另一個物件(僅一次)

    在大多數情況下,這是類的實例化,但不得是

  • __getitem__支援介面。唯一請求的鍵/索引將是0

從實際的角度來看,看看上面的例子,一個信號是:

  • 來自backtrader生態系統的lines物件,主要是指標

    這在使用其他指標時很有説明,例如在示例中使用簡單移動平均線時。

信號指示

信號在查詢signal[0] 時提供指示,含義為:

  • > 0 -> long indication

  • < 0 -> short indication

  • == 0 -> 無適應症

該範例使用self.data - SMA 和執行簡單的算術運算:

  • 問題 along indication 當 高於dataSMA

  • 問題 ashort indicationdata 低於 SMA

注意

當 沒有為data 指示特定價格欄位時 close ,價格就是參考價格。

信號類型

下面指示的常量(如上面的示例所示)可直接從主 backtrader 模塊獲得,如下所示:

import backtrader as bt

bt.SIGNAL_LONG

有5種類型的信號,分為2組。

主要組

  • LONGSHORT:兩者都 longshort 這個信號中獲取指示

  • LONG:

    • long 適應症需要做多

    • short 指示用於 close 多頭頭寸。但:

    • 如果系統中存在LONGEXIT (見下文)信號,它將用於退出多頭

    • 如果信號SHORT可用而無LONGEXIT可用,它將用於在打開 a 之前closelongshort

  • SHORT:

    • short 適應症被採取短路

    • long 指示用於 close 空頭頭寸。但:

    • 如果系統中存在SHORTEXIT (見下文)信號,它將用於退出空頭

    • 如果信號LONG可用而無SHORTEXIT可用,它將用於在打開之前closeshortlong

離開群組

這 2 個信號旨在覆蓋其他信號,併為退出 along / short 倉位提供標準

  • LONGEXITshort 指示用於退出 long 倉位

  • SHORTEXITlong 指示用於退出 short 倉位

累積和訂單併發

上面顯示的示例信號將持續發出長短指示,因為它只是從價格中SMAclose減去值,這將始終是和> 0 < 00在數學上是可能的,但不太可能真正發生)

這將導致連續生成訂單,從而產生 2 種情況:

  • Accumulation:即使已經在市場上,信號也會產生新的訂單,這將增加市場的可能性

  • Concurrency:新訂單將在不等待其他訂單執行的情況下生成

為避免這種情況,預設行為為:

  • 不累積

  • 不允許併發

如果希望這兩種行為中的任何一種,可以通過以下方式進行控制cerebro

  • cerebro.signal_accumulate(True) (或 False 重新禁用它)

  • cerebro.signal_concurrency(True) (或 False 重新禁用它)

示例

backtrader源包含用於測試功能的範例。

要使用的主信號。

class SMACloseSignal(bt.Indicator):
    lines = ('signal',)
    params = (('period', 30),)

    def __init__(self):
        self.lines.signal = self.data - bt.indicators.SMA(period=self.p.period)

如果指定了該選項,則退出信號。

class SMAExitSignal(bt.Indicator):
    lines = ('signal',)
    params = (('p1', 5), ('p2', 30),)

    def __init__(self):
        sma1 = bt.indicators.SMA(period=self.p.p1)
        sma2 = bt.indicators.SMA(period=self.p.p2)
        self.lines.signal = sma1 - sma2

首次運行:長跑和短跑

$ ./signals-strategy.py --plot --signal longshort

輸出

要注意:

  • 繪製信號。這是正常的,因為它只是一個指標,並且它的繪圖規則適用

  • 策略是真的longshort.這可以看出,因為現金水平永遠不會回到價值水準。

  • 附注:即使是一個愚蠢的想法...(並且沒有傭金)該策略沒有損失金錢...

第二次運行:僅長

$ ./signals-strategy.py --plot --signal longonly

輸出

要注意:

  • 在這裡,現金水準回到每次賣出后的價值水準,這意味著策略已經退出市場。

  • 附注:再次沒有錢損失...

第三次運行:僅短運行

$ ./signals-strategy.py --plot --signal shortonly

輸出

要注意:

  • 第 1 操作是預期的賣出,並且比上述 2 個示例中的第 1 操作晚。直到低於 closeSMA 簡單減法 產生一個負數

  • 在這裡,現金水準回到每次買入后的價值水準,這意味著策略已經退出市場。

  • 附注:最後系統賠錢

第四次運行:長+長輸出

$ ./signals-strategy.py --plot --signal longonly --exitsignal longexit

輸出

要注意:

  • 許多交易是相同的,但有些交易被提前中斷,因為退出信號中的快速移動平均線穿過慢速移動平均線到下行

  • 該系統顯示其長期屬性,現金成為每筆交易結束時的價值

  • 附注:再次賺錢...即使有一些修改的交易

用法

$ ./signals-strategy.py --help
usage: signals-strategy.py [-h] [--data DATA] [--fromdate FROMDATE]
                           [--todate TODATE] [--cash CASH]
                           [--smaperiod SMAPERIOD] [--exitperiod EXITPERIOD]
                           [--signal {longshort,longonly,shortonly}]
                           [--exitsignal {longexit,shortexit}]
                           [--plot [kwargs]]

Sample for Signal concepts

optional arguments:
  -h, --help            show this help message and exit
  --data DATA           Specific data to be read in (default:
                        ../../datas/2005-2006-day-001.txt)
  --fromdate FROMDATE   Starting date in YYYY-MM-DD format (default: None)
  --todate TODATE       Ending date in YYYY-MM-DD format (default: None)
  --cash CASH           Cash to start with (default: 50000)
  --smaperiod SMAPERIOD
                        Period for the moving average (default: 30)
  --exitperiod EXITPERIOD
                        Period for the exit control SMA (default: 5)
  --signal {longshort,longonly,shortonly}
                        Signal type to use for the main signal (default:
                        longshort)
  --exitsignal {longexit,shortexit}
                        Signal type to use for the exit signal (default: None)
  --plot [kwargs], -p [kwargs]
                        Plot the read data applying any kwargs passed For
                        example: --plot style="candle" (to plot candles)
                        (default: None)

代碼

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

import argparse
import collections
import datetime

import backtrader as bt

MAINSIGNALS = collections.OrderedDict(
    (('longshort', bt.SIGNAL_LONGSHORT),
     ('longonly', bt.SIGNAL_LONG),
     ('shortonly', bt.SIGNAL_SHORT),)
)


EXITSIGNALS = {
    'longexit': bt.SIGNAL_LONGEXIT,
    'shortexit': bt.SIGNAL_LONGEXIT,
}


class SMACloseSignal(bt.Indicator):
    lines = ('signal',)
    params = (('period', 30),)

    def __init__(self):
        self.lines.signal = self.data - bt.indicators.SMA(period=self.p.period)


class SMAExitSignal(bt.Indicator):
    lines = ('signal',)
    params = (('p1', 5), ('p2', 30),)

    def __init__(self):
        sma1 = bt.indicators.SMA(period=self.p.p1)
        sma2 = bt.indicators.SMA(period=self.p.p2)
        self.lines.signal = sma1 - sma2


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

    cerebro = bt.Cerebro()
    cerebro.broker.set_cash(args.cash)

    dkwargs = dict()
    if args.fromdate is not None:
        fromdate = datetime.datetime.strptime(args.fromdate, '%Y-%m-%d')
        dkwargs['fromdate'] = fromdate

    if args.todate is not None:
        todate = datetime.datetime.strptime(args.todate, '%Y-%m-%d')
        dkwargs['todate'] = todate

    # if dataset is None, args.data has been given
    data = bt.feeds.BacktraderCSVData(dataname=args.data, **dkwargs)
    cerebro.adddata(data)

    cerebro.add_signal(MAINSIGNALS[args.signal],
                       SMACloseSignal, period=args.smaperiod)

    if args.exitsignal is not None:
        cerebro.add_signal(EXITSIGNALS[args.exitsignal],
                           SMAExitSignal,
                           p1=args.exitperiod,
                           p2=args.smaperiod)

    cerebro.run()
    if args.plot:
        pkwargs = dict(style='bar')
        if args.plot is not True:  # evals to True but is not True
            npkwargs = eval('dict(' + args.plot + ')')  # args were passed
            pkwargs.update(npkwargs)

        cerebro.plot(**pkwargs)


def parse_args(pargs=None):

    parser = argparse.ArgumentParser(
        formatter_class=argparse.ArgumentDefaultsHelpFormatter,
        description='Sample for Signal concepts')

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

    parser.add_argument('--fromdate', required=False, default=None,
                        help='Starting date in YYYY-MM-DD format')

    parser.add_argument('--todate', required=False, default=None,
                        help='Ending date in YYYY-MM-DD format')

    parser.add_argument('--cash', required=False, action='store',
                        type=float, default=50000,
                        help=('Cash to start with'))

    parser.add_argument('--smaperiod', required=False, action='store',
                        type=int, default=30,
                        help=('Period for the moving average'))

    parser.add_argument('--exitperiod', required=False, action='store',
                        type=int, default=5,
                        help=('Period for the exit control SMA'))

    parser.add_argument('--signal', required=False, action='store',
                        default=MAINSIGNALS.keys()[0], choices=MAINSIGNALS,
                        help=('Signal type to use for the main signal'))

    parser.add_argument('--exitsignal', required=False, action='store',
                        default=None, choices=EXITSIGNALS,
                        help=('Signal type to use for the exit signal'))

    # Plot options
    parser.add_argument('--plot', '-p', nargs='?', required=False,
                        metavar='kwargs', const=True,
                        help=('Plot the read data applying any kwargs passed\n'
                              '\n'
                              'For example:\n'
                              '\n'
                              '  --plot style="candle" (to plot candles)\n'))

    if pargs is not None:
        return parser.parse_args(pargs)

    return parser.parse_args()


if __name__ == '__main__':
    runstrat()

推薦閱讀

相關文章

Backtrader教程:分析儀

無論是回溯測試還是交易,能夠分析交易系統的性能是瞭解是否不僅獲得了利潤,而且是否在風險太大的情況下實現了利潤,或者與參考資產(或無風險資產)相比,是否真的值得付出努力的關鍵。 這就是物件家族的用武之Analyzer 地:提供對所發生事件甚至實際發生的事情的分析。

Backtrader股票篩選

在尋找其他一些東西時,我在StackOverlow家族網站之一上遇到了一個問題:Quantitative Finance aka Quant StackExchange。問題: 它被標記為Python,因此值得一看的是 backtrader 是否能夠勝任這項任務。 分析儀本身 該問題似乎適合用於簡單的分析器。

Backtrader教程:觀察者 - 基準測試

工單 #89 是關於針對資產添加基準測試的。明智的是,人們實際上可能有一個策略,即使積極,也低於簡單地跟蹤資產所能提供的策略。

Backtrader回溯

在一些關於改進的ShapeRatio的提示之後, backtrader 已將此分析儀添加到其武器庫中。 文獻位於: 從對數回報的好處開始,並遵循在SharpeRatio方程的分母中具有標準偏差的副作用,本文檔開發了該分析儀的公式和期望。

Backtrader教程:篩檢程式

此功能是 backtrader 的相對較新的補充,必須安裝到已經存在的內部結構中。這使得它不像希望的那樣靈活且100%功能齊全,但在許多情況下它仍然可以達到目的。 儘管該實現試圖允許隨插即用的篩檢程式連結,但預先存在的內部結構使得很難確保始終可以實現。因此,某些篩選器可能是連結的,而其他一些篩選器可能不是。

Backtrader條形同步

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

Backtrader教程:傭金計劃 - 信貸利息

在某些情況下,真實經紀人的現金金額可能會減少,因為資產操作包括利率。例子: 賣空股票 交易所買賣基金包括多頭和空頭 該費用直接與經紀人帳戶中的現金餘額挂鉤。但它仍然可以被視為傭金計劃的一部分。因此,它已被建模為 backtrader。

Backtrader卡爾曼等

注意 對以下指令的支援從提交開始 發佈1.9.30.x 將是包含它的第1個版本 。 backtrader的原始目標之一是成為純python,即:僅使用標準發行版中可用的軟體包。只有一個例外是matplotlib在沒有重新發明輪子的情況下進行繪圖。

Backtrader開場作弊

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

Backtrader熊貓數據饋送

在一些小的增強功能和一些OrderDict調整中,以獲得更好的Python 2.6支援, backtrader 的最新版本增加了對分析Pandas Dataframe或Time Series數據的支援。