Backtrader 教程:訂單 - StopTrail

  |  

版本1.9.35.116StopTrailStopTrailLimit訂單執行類型添加到回測庫中。

筆記

這僅在回測中實現,還沒有針對實時經紀人的實現

筆記

更新為1.9.36.116版本。盈透證券支持StopTrailStopTrailLimitOCO

  • OCO始終將組中的oco一個訂單指定為參數oco

  • StopTrailLimit :代理模擬和IB代理具有相同的行為。指定: price作為初始止損觸發價格(同時指定trailamount ),然後plimi作為初始限價。兩者的差值將決定limitoffset (限價與止損觸發價之間的距離)

使用模式完全集成到策略實例的標準buysellclose操作方法中。通知:

  • 指示希望使用哪種執行類型,如exectype=bt.Order.StopTrail

  • 以及是否必須使用固定距離或基於百分比的距離計算追踪價格

    • 固定距離: trailamount=10

    • 基於百分比的距離: trailpercent=0.02 (即: 2%

如果一個人通過發出buy進入市場多頭,這就是使用StopTrailtrailamountsell的作用:

  • 如果未指定price ,則使用最新close

  • 從價格中減去trailamount以找到stop (或觸發)價格

  • 經紀人的下一次迭代檢查是否已達到觸發價格

    • 如果:訂單以Market執行類型的方式執行

    • 如果,則使用最新close價並減去trailamount距離重新計算stop

    • 如果新價格上漲,則更新

    • 如果新價格會下降(或根本沒有變化),則將其丟棄

也就是說:追踪止損價格跟隨價格上漲,但如果價格開始下跌,則保持不變,以潛在地獲得利潤。

如果一個人以sell的方式進入市場,那麼使用StopTrail發出buy指令只會做相反的事情,即:價格跟隨向下。

一些使用模式

# For a StopTrail going downwards
# last price will be used as reference
self.buy(size=1, exectype=bt.Order.StopTrail, trailamount=0.25)
# or
self.buy(size=1, exectype=bt.Order.StopTrail, price=10.50, trailamount=0.25)

# For a StopTrail going upwards
# last price will be used as reference
self.sell(size=1, exectype=bt.Order.StopTrail, trailamount=0.25)
# or
self.sell(size=1, exectype=bt.Order.StopTrail, price=10.50, trailamount=0.25)

也可以指定trailpercent而不是trailamount並且到價格的距離將計算為價格的百分比

# For a StopTrail going downwards with 2% distance
# last price will be used as reference
self.buy(size=1, exectype=bt.Order.StopTrail, trailpercent=0.02)
# or
self.buy(size=1, exectype=bt.Order.StopTrail, price=10.50, trailpercent=0.0.02)

# For a StopTrail going upwards with 2% difference
# last price will be used as reference
self.sell(size=1, exectype=bt.Order.StopTrail, trailpercent=0.02)
# or
self.sell(size=1, exectype=bt.Order.StopTrail, price=10.50, trailpercent=0.02)

對於StopTrailLimit

  • 唯一的區別是當追踪止損價格被觸發時會發生什麼。

  • 在這種情況下,訂單作為Limit訂單執行(與StopLimit訂單的行為相同,但在這種情況下具有動態觸發價格)

    注意buysell必須指定plimit=xx ,這將是限價

    注意:限價不會像止損/觸發價格那樣動態變化

一個例子總是值一千字,因此通常的反向交易樣本,

  • 使用移動平均線向上交叉進入市場做多

  • 使用追踪止損退出市場

50點固定價格距離的執行

$ ./trail.py --plot --strat trailamount=50.0

產生以下圖表

以及以下輸出:

**************************************************
2005-02-14,3075.76,3025.76,3025.76
----------
2005-02-15,3086.95,3036.95,3036.95
2005-02-16,3068.55,3036.95,3018.55
2005-02-17,3067.34,3036.95,3017.34
2005-02-18,3072.04,3036.95,3022.04
2005-02-21,3063.64,3036.95,3013.64
...
...
**************************************************
2005-05-19,3051.79,3001.79,3001.79
----------
2005-05-20,3050.45,3001.79,3000.45
2005-05-23,3070.98,3020.98,3020.98
2005-05-24,3066.55,3020.98,3016.55
2005-05-25,3059.84,3020.98,3009.84
2005-05-26,3086.08,3036.08,3036.08
2005-05-27,3084.0,3036.08,3034.0
2005-05-30,3096.54,3046.54,3046.54
2005-05-31,3076.75,3046.54,3026.75
2005-06-01,3125.88,3075.88,3075.88
2005-06-02,3131.03,3081.03,3081.03
2005-06-03,3114.27,3081.03,3064.27
2005-06-06,3099.2,3081.03,3049.2
2005-06-07,3134.82,3084.82,3084.82
2005-06-08,3125.59,3084.82,3075.59
2005-06-09,3122.93,3084.82,3072.93
2005-06-10,3143.85,3093.85,3093.85
2005-06-13,3159.83,3109.83,3109.83
2005-06-14,3162.86,3112.86,3112.86
2005-06-15,3147.55,3112.86,3097.55
2005-06-16,3160.09,3112.86,3110.09
2005-06-17,3178.48,3128.48,3128.48
2005-06-20,3162.14,3128.48,3112.14
2005-06-21,3179.62,3129.62,3129.62
2005-06-22,3182.08,3132.08,3132.08
2005-06-23,3190.8,3140.8,3140.8
2005-06-24,3161.0,3140.8,3111.0
...
...
...
**************************************************
2006-12-19,4100.48,4050.48,4050.48
----------
2006-12-20,4118.54,4068.54,4068.54
2006-12-21,4112.1,4068.54,4062.1
2006-12-22,4073.5,4068.54,4023.5
2006-12-27,4134.86,4084.86,4084.86
2006-12-28,4130.66,4084.86,4080.66
2006-12-29,4119.94,4084.86,4069.94

系統使用追踪止損退出市場,而不是等待通常的交叉向下模式。讓我們以第一次操作為例

  • 做多收盤價: 3075.76

  • 系統計算的追踪止損價格: 3025.76 (距離50單位)

  • 示例計算的追踪止損價格: 3025.76 (每顯示的最後價格)

在第一次計算之後:

  • 收盤價上漲至3086.95 ,止損價調整至3036.95

  • 以下收盤價不超過3086.95且觸發價不變

在其他 2 個操作中可以看到相同的模式。

為了比較,只有30個固定距離點的執行(只是圖表)

$ ./trail.py --plot --strat trailamount=30.0

還有圖表

最後一次執行, trailpercent=0.02

$ ./trail.py --plot --strat trailpercent=0.02

對應的圖表。

樣本用法

$ ./trail.py --help
usage: trail.py [-h] [--data0 DATA0] [--fromdate FROMDATE] [--todate TODATE]
                [--cerebro kwargs] [--broker kwargs] [--sizer kwargs]
                [--strat kwargs] [--plot [kwargs]]

StopTrail Sample

optional arguments:
  -h, --help           show this help message and exit
  --data0 DATA0        Data to read in (default:
                       ../../datas/2005-2006-day-001.txt)
  --fromdate FROMDATE  Date[time] in YYYY-MM-DD[THH:MM:SS] format (default: )
  --todate TODATE      Date[time] in YYYY-MM-DD[THH:MM:SS] format (default: )
  --cerebro kwargs     kwargs in key=value format (default: )
  --broker kwargs      kwargs in key=value format (default: )
  --sizer kwargs       kwargs in key=value format (default: )
  --strat kwargs       kwargs in key=value format (default: )
  --plot [kwargs]      kwargs in key=value format (default: )

示例代碼

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

import argparse
import datetime

import backtrader as bt


class St(bt.Strategy):
    params = dict(
        ma=bt.ind.SMA,
        p1=10,
        p2=30,
        stoptype=bt.Order.StopTrail,
        trailamount=0.0,
        trailpercent=0.0,
    )

    def __init__(self):
        ma1, ma2 = self.p.ma(period=self.p.p1), self.p.ma(period=self.p.p2)
        self.crup = bt.ind.CrossUp(ma1, ma2)
        self.order = None

    def next(self):
        if not self.position:
            if self.crup:
                o = self.buy()
                self.order = None
                print('*' * 50)

        elif self.order is None:
            self.order = self.sell(exectype=self.p.stoptype,
                                   trailamount=self.p.trailamount,
                                   trailpercent=self.p.trailpercent)

            if self.p.trailamount:
                tcheck = self.data.close - self.p.trailamount
            else:
                tcheck = self.data.close * (1.0 - self.p.trailpercent)
            print(','.join(
                map(str, [self.datetime.date(), self.data.close[0],
                          self.order.created.price, tcheck])
                )
            )
            print('-' * 10)
        else:
            if self.p.trailamount:
                tcheck = self.data.close - self.p.trailamount
            else:
                tcheck = self.data.close * (1.0 - self.p.trailpercent)
            print(','.join(
                map(str, [self.datetime.date(), self.data.close[0],
                          self.order.created.price, tcheck])
                )
            )


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

    cerebro = bt.Cerebro()

    # Data feed kwargs
    kwargs = dict()

    # Parse from/to-date
    dtfmt, tmfmt = '%Y-%m-%d', 'T%H:%M:%S'
    for a, d in ((getattr(args, x), x) for x in ['fromdate', 'todate']):
        if a:
            strpfmt = dtfmt + tmfmt * ('T' in a)
            kwargs[d] = datetime.datetime.strptime(a, strpfmt)

    # Data feed
    data0 = bt.feeds.BacktraderCSVData(dataname=args.data0, **kwargs)
    cerebro.adddata(data0)

    # Broker
    cerebro.broker = bt.brokers.BackBroker(**eval('dict(' + args.broker + ')'))

    # Sizer
    cerebro.addsizer(bt.sizers.FixedSize, **eval('dict(' + args.sizer + ')'))

    # Strategy
    cerebro.addstrategy(St, **eval('dict(' + args.strat + ')'))

    # Execute
    cerebro.run(**eval('dict(' + args.cerebro + ')'))

    if args.plot:  # Plot if requested to
        cerebro.plot(**eval('dict(' + args.plot + ')'))


def parse_args(pargs=None):
    parser = argparse.ArgumentParser(
        formatter_class=argparse.ArgumentDefaultsHelpFormatter,
        description=(
            'StopTrail Sample'
        )
    )

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

    # Defaults for dates
    parser.add_argument('--fromdate', required=False, default='',
                        help='Date[time] in YYYY-MM-DD[THH:MM:SS] format')

    parser.add_argument('--todate', required=False, default='',
                        help='Date[time] in YYYY-MM-DD[THH:MM:SS] format')

    parser.add_argument('--cerebro', required=False, default='',
                        metavar='kwargs', help='kwargs in key=value format')

    parser.add_argument('--broker', required=False, default='',
                        metavar='kwargs', help='kwargs in key=value format')

    parser.add_argument('--sizer', required=False, default='',
                        metavar='kwargs', help='kwargs in key=value format')

    parser.add_argument('--strat', required=False, default='',
                        metavar='kwargs', help='kwargs in key=value format')

    parser.add_argument('--plot', required=False, default='',
                        nargs='?', const='{}',
                        metavar='kwargs', help='kwargs in key=value format')

    return parser.parse_args(pargs)


if __name__ == '__main__':
    runstrat()

推薦閱讀

相關文章

Backtrader 教程:指標 - 使用

指標可以在平台的兩個地方使用:內部策略其他指標內部指標在行動指標總是在策略中的__init__期間實例化next使用/檢查指標值(或其派生值)有一個重要的公理需要考慮:在__init__期間聲明的任何Indicator (或其派生值)都將在調用next之前預先計算。讓我們來看看操作模式的差異。

Backtrader寫下來

隨著 1.1.7.88 版本的發布, backtrader有了一個新的補充:作家這可能早就到期了,應該已經存在了,問題 #14中的討論也應該已經開始了開發。但遲到總比沒有好。

Backtrader教程:數據饋送 - 重新取樣

如果數據僅在單個時間範圍內可用,並且必須在不同的時間範圍內進行分析,則是時候進行一些重新採樣了。 “重採樣”實際上應該稱為“上採樣”,因為一個人從源時間幀到更大的時間幀(例如:幾天到幾周) backtrader 內置支持通過篩選器對象傳遞原始數據,從而進行重採樣。

Backtrader期貨補償與現貨補償

版本1.9.32.116 增加了對社區中呈現的有趣用例 的支援 以期貨開始交易,包括實物交割 讓一個指標告訴你一些事情 如果需要, close 現貨價格操作,有效地取消實物交割,無論是為了接收貨物還是為了必須交付貨物(並希望獲利)來頭寸。

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

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

Backtrader數據同步

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

Backtrader跨越數位

《backtrader》的發佈1.9.27.105糾正了一個疏忽。這是一個疏忽,因為拼圖的所有部分都已到位,但啟動並不是在所有角落都進行的。 該機制使用一個名為的屬性_mindatas,因此讓我們將其稱為: mindatas。 社區問了這個問題,答案並不是很到位。

Backtrader策略選擇

最初的策略選擇方法使用兩個策略,手動註冊和一個簡單的[0, 1]列表來決定哪個是策略的目標。因為 Python 為元類提供了許多自省的可能性,所以實際上可以自動化該方法。

Backtrader教程:數據饋送 - 雅虎

2017年5月,雅虎停止了現有的CSV格式歷史數據下載API。 一個新的API(這裡命名v7)很快被標準化並已實現。 這也帶來了實際CSV下載格式的變化。 使用 v7 API/格式 從版本1.9.49.116 開始,這是預設行為。

Backtrader教程:觀察者 - 統計

在內部backtrader 運行的策略主要處理 data feeds 和 指標。 Data feeds 被添加到Cerebro 實例中,並最終成為策略輸入的一部分(解析並用作實例的屬性),而指標則由策略本身聲明和管理。