Backtrader 教程:訂單 - 目標訂單

  |  

1.8.10.96版本之前,可以使用反向交易者通過策略方法進行智能質押: buysell 。這一切都是為了在負責賭注大小的等式中添加一個Sizer

Sizer不能做的是決定操作是買入還是賣出。這意味著需要一個新概念,在其中添加一個小的智能層來做出這樣的決定。

這是 Strategy 中的order_target_xxx方法家族發揮作用的地方。受zipline中的啟發,這些方法提供了簡單地指定最終目標的機會,成為目標:

  • size -> 特定資產投資組合中的股份數量、合約數量

  • value -> 投資組合中資產的貨幣單位價值

  • percent -> 當前投資組合中資產的百分比(來自當前投資組合)

筆記

這些方法的參考可以在策略中找到。總結是這些方法使用與buysell相同的簽名,除了參數size被參數target替換

在這種情況下,一切都與指定最終目標有關,並且該方法決定操作是買入還是賣出。相同的邏輯適用於 3 種方法。讓我們從order_target_size

  • 如果目標大於發出買入的頭寸,則差異target - position_size

    例子:

    • 位置: 0 ,目標: 7 -> 購買(尺寸=7 - 0)-> 購買(尺寸=7)

    • 位置: 3 ,目標: 7 -> 購買(尺寸=7 - 3)-> 購買(尺寸=4)

    • 位置: -3 ,目標: 7 -> 購買(尺寸=7 - -3)-> 購買(尺寸=10)

    • 位置: -3 ,目標: -2 -> 購買(尺寸=-2 - -3)-> 購買(尺寸=1)

  • 如果目標小於頭寸,則發出賣出,差異為position_size - target

    例子:

    • 位置: 0 ,目標: -7 -> 銷售(大小=0 - -7) -> 銷售(大小=7)

    • 職位: 3 ,目標: -7 -> 出售(大小=3 - -7)-> 出售(大小=10)

    • 位置: -3 ,目標: -7 -> 出售(尺寸=-3 - -7)-> 出售(尺寸=4)

    • 職位: 3 ,目標: 2 -> 銷售(大小=3 - 2) -> 銷售(大小=1)

當使用order_target_value一個值時,投資組合中資產的當前價值和頭寸規模都被考慮在內,以決定最終的基礎操作是什麼。推理:

  • 如果頭寸規模為負(空頭)並且目標值必須大於當前值,這意味著:賣出更多

因此,邏輯工作如下:

  • 如果target > valuesize >=0 -> 購買

  • 如果target > valuesize < 0 -> 賣出

  • 如果target < valuesize >= 0 -> 賣出

  • 如果target < valuesize < 0 -> 購買

order_target_value的邏輯與order_target_percent的邏輯相同。該方法僅考慮投資組合的當前總價值來確定資產的目標價值。

樣本

backtrader嘗試為每個新功能提供一個示例,這也不例外。沒有花里胡哨的東西,只是測試一下結果是否符合預期。這個在示例中的order_target目錄下。

示例中的邏輯相當愚蠢,僅用於測試:

  • 在奇數月(一月、三月、...),使用天作為目標(在order_target_value將天乘以1000的情況下)

    這模仿了一個不斷增加的目標

  • 在偶數月(2 月、4 月……)使用31 - day作為目標

    這模擬了一個遞減的目標

order_target_size

讓我們看看 1 月和 2 月會發生什麼。

$ ./order_target.py --target-size -- plot
0001 - 2005-01-03 - Position Size:     00 - Value 1000000.00
0001 - 2005-01-03 - Order Target Size: 03
0002 - 2005-01-04 - Position Size:     03 - Value 999994.39
0002 - 2005-01-04 - Order Target Size: 04
0003 - 2005-01-05 - Position Size:     04 - Value 999992.48
0003 - 2005-01-05 - Order Target Size: 05
0004 - 2005-01-06 - Position Size:     05 - Value 999988.79
...
0020 - 2005-01-31 - Position Size:     28 - Value 999968.70
0020 - 2005-01-31 - Order Target Size: 31
0021 - 2005-02-01 - Position Size:     31 - Value 999954.68
0021 - 2005-02-01 - Order Target Size: 30
0022 - 2005-02-02 - Position Size:     30 - Value 999979.65
0022 - 2005-02-02 - Order Target Size: 29
0023 - 2005-02-03 - Position Size:     29 - Value 999966.33
0023 - 2005-02-03 - Order Target Size: 28
...

1 月,目標從3點開始,從一年中的第一個交易日開始,然後增加。頭寸大小最初從0移動到3 ,然後以1為增量。

1 月結束時,最後一個order_target 為31 ,並且在進入 2 月 1時報告倉位大小,此時新的目標方被要求為30 ,並且隨著倉位的遞減“1”而變化。

order_target_value

預計目標值會出現類似的行為

$ ./order_target.py --target-value --plot
0001 - 2005-01-03 - Position Size:     00 - Value 1000000.00
0001 - 2005-01-03 - data value 0.00
0001 - 2005-01-03 - Order Target Value: 3000.00
0002 - 2005-01-04 - Position Size:     78 - Value 999854.14
0002 - 2005-01-04 - data value 2853.24
0002 - 2005-01-04 - Order Target Value: 4000.00
0003 - 2005-01-05 - Position Size:     109 - Value 999801.68
0003 - 2005-01-05 - data value 3938.17
0003 - 2005-01-05 - Order Target Value: 5000.00
0004 - 2005-01-06 - Position Size:     138 - Value 999699.57
...
0020 - 2005-01-31 - Position Size:     808 - Value 999206.37
0020 - 2005-01-31 - data value 28449.68
0020 - 2005-01-31 - Order Target Value: 31000.00
0021 - 2005-02-01 - Position Size:     880 - Value 998807.33
0021 - 2005-02-01 - data value 30580.00
0021 - 2005-02-01 - Order Target Value: 30000.00
0022 - 2005-02-02 - Position Size:     864 - Value 999510.21
0022 - 2005-02-02 - data value 30706.56
0022 - 2005-02-02 - Order Target Value: 29000.00
0023 - 2005-02-03 - Position Size:     816 - Value 999130.05
0023 - 2005-02-03 - data value 28633.44
0023 - 2005-02-03 - Order Target Value: 28000.00
...

有一條額外的信息說明實際數據值(在投資組合中)是什麼。這有助於找出是否已達到目標值。

初始目標是3000.0 ,報告的初始值為2853.24 。這裡的問題是這是否足夠接近。答案是肯定的

  • 該示例使用每日柱結束時的Market單和最後可用價格來計算滿足目標值的目標大小

  • 然後執行使用第二天的open ,這不太可能是前一個close

以任何其他方式這樣做都意味著一個人在欺騙他/她自己。

下一個目標值和最終值更接近: 40003938.17

當更改為二月時,目標值開始從31000減少到3000029000 。從30580.0030706.56再到28633.44的數據值也是如此。等待:

  • 30580 -> 30706.56是一個積極的變化

    的確。在這種情況下,目標值的計算大小滿足開盤價,將值推高至30706.56

如何避免這種影響:

  • 示例對訂單使用Market類型執行,這種影響無法避免

  • order_target_xxx方法允許指定執行類型和價格。

    可以將Limit指定為執行訂單,並將價格設為收盤價(如果沒有提供其他信息,則由方法選擇)甚至提供具體定價

order_target_percent

在這種情況下,它只是當前投資組合價值的百分比。

$ ./order_target.py --target-percent --plot
0001 - 2005-01-03 - Position Size:     00 - Value 1000000.00
0001 - 2005-01-03 - data percent 0.00
0001 - 2005-01-03 - Order Target Percent: 0.03
0002 - 2005-01-04 - Position Size:     785 - Value 998532.05
0002 - 2005-01-04 - data percent 0.03
0002 - 2005-01-04 - Order Target Percent: 0.04
0003 - 2005-01-05 - Position Size:     1091 - Value 998007.44
0003 - 2005-01-05 - data percent 0.04
0003 - 2005-01-05 - Order Target Percent: 0.05
0004 - 2005-01-06 - Position Size:     1381 - Value 996985.64
...
0020 - 2005-01-31 - Position Size:     7985 - Value 991966.28
0020 - 2005-01-31 - data percent 0.28
0020 - 2005-01-31 - Order Target Percent: 0.31
0021 - 2005-02-01 - Position Size:     8733 - Value 988008.94
0021 - 2005-02-01 - data percent 0.31
0021 - 2005-02-01 - Order Target Percent: 0.30
0022 - 2005-02-02 - Position Size:     8530 - Value 995005.45
0022 - 2005-02-02 - data percent 0.30
0022 - 2005-02-02 - Order Target Percent: 0.29
0023 - 2005-02-03 - Position Size:     8120 - Value 991240.75
0023 - 2005-02-03 - data percent 0.29
0023 - 2005-02-03 - Order Target Percent: 0.28
...

並且信息已更改以查看數據在投資組合中代表的%

示例使用

$ ./order_target.py --help
usage: order_target.py [-h] [--data DATA] [--fromdate FROMDATE]
                       [--todate TODATE] [--cash CASH]
                       (--target-size | --target-value | --target-percent)
                       [--plot [kwargs]]

Sample for Order Target

optional arguments:
  -h, --help            show this help message and exit
  --data DATA           Specific data to be read in (default:
                        ../../datas/yhoo-1996-2015.txt)
  --fromdate FROMDATE   Starting date in YYYY-MM-DD format (default:
                        2005-01-01)
  --todate TODATE       Ending date in YYYY-MM-DD format (default: 2006-12-31)
  --cash CASH           Ending date in YYYY-MM-DD format (default: 1000000)
  --target-size         Use order_target_size (default: False)
  --target-value        Use order_target_value (default: False)
  --target-percent      Use order_target_percent (default: False)
  --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
from datetime import datetime

import backtrader as bt


class TheStrategy(bt.Strategy):
    '''
    This strategy is loosely based on some of the examples from the Van
    K. Tharp book: *Trade Your Way To Financial Freedom*. The logic:

      - Enter the market if:
        - The MACD.macd line crosses the MACD.signal line to the upside
        - The Simple Moving Average has a negative direction in the last x
          periods (actual value below value x periods ago)

     - Set a stop price x times the ATR value away from the close

     - If in the market:

       - Check if the current close has gone below the stop price. If yes,
         exit.
       - If not, update the stop price if the new stop price would be higher
         than the current
    '''

    params = (
        ('use_target_size', False),
        ('use_target_value', False),
        ('use_target_percent', False),
    )

    def notify_order(self, order):
        if order.status == order.Completed:
            pass

        if not order.alive():
            self.order = None  # indicate no order is pending

    def start(self):
        self.order = None  # sentinel to avoid operrations on pending order

    def next(self):
        dt = self.data.datetime.date()

        portfolio_value = self.broker.get_value()
        print('%04d - %s - Position Size:     %02d - Value %.2f' %
              (len(self), dt.isoformat(), self.position.size, portfolio_value))

        data_value = self.broker.get_value([self.data])

        if self.p.use_target_value:
            print('%04d - %s - data value %.2f' %
                  (len(self), dt.isoformat(), data_value))

        elif self.p.use_target_percent:
            port_perc = data_value / portfolio_value
            print('%04d - %s - data percent %.2f' %
                  (len(self), dt.isoformat(), port_perc))

        if self.order:
            return  # pending order execution

        size = dt.day
        if (dt.month % 2) == 0:
            size = 31 - size

        if self.p.use_target_size:
            target = size
            print('%04d - %s - Order Target Size: %02d' %
                  (len(self), dt.isoformat(), size))

            self.order = self.order_target_size(target=size)

        elif self.p.use_target_value:
            value = size * 1000

            print('%04d - %s - Order Target Value: %.2f' %
                  (len(self), dt.isoformat(), value))

            self.order = self.order_target_value(target=value)

        elif self.p.use_target_percent:
            percent = size / 100.0

            print('%04d - %s - Order Target Percent: %.2f' %
                  (len(self), dt.isoformat(), percent))

            self.order = self.order_target_percent(target=percent)


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

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

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

    # data
    data = bt.feeds.YahooFinanceCSVData(dataname=args.data, **dkwargs)
    cerebro.adddata(data)

    # strategy
    cerebro.addstrategy(TheStrategy,
                        use_target_size=args.target_size,
                        use_target_value=args.target_value,
                        use_target_percent=args.target_percent)

    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 Order Target')

    parser.add_argument('--data', required=False,
                        default='../../datas/yhoo-1996-2015.txt',
                        help='Specific data to be read in')

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

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

    parser.add_argument('--cash', required=False, action='store',
                        type=float, default=1000000,
                        help='Ending date in YYYY-MM-DD format')

    pgroup = parser.add_mutually_exclusive_group(required=True)

    pgroup.add_argument('--target-size', required=False, action='store_true',
                        help=('Use order_target_size'))

    pgroup.add_argument('--target-value', required=False, action='store_true',
                        help=('Use order_target_value'))

    pgroup.add_argument('--target-percent', required=False,
                        action='store_true',
                        help=('Use order_target_percent'))

    # 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寫下來

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

Backtrader教程:經紀人 - 體積灌裝 - 灌裝機

backtrader經紀商類比在使用volume執行訂單時具有預設策略: 忽略 volume 這是基於2個前提: 在市場中交易的流動性足以一次性完全吸收買入/賣出訂單 真正的 volume 匹配需要真正的狼 一個簡單的例子是Fill or Kill 訂單。

Backtrader教程:倉位

資產的頭寸通常從策略中檢查: position (財產)或 getposition(data=None, broker=None) 這將返回策略在默認broker狀態下datas[0]的位置,由cerebro 倉位只是指示: 資產被持有size 平均價格price 它作為一種狀態,

Backtrader實際使用方式

最後,似乎已經付出了開發 backtrader是值得的。 在觀察 last 周的歐洲市場時,似乎世界末日了,一位朋友問我是否可以看看我們圖表包中的數據,看看與以前類似情況相比,下跌幅度如何。 當然可以,但我說我可以做的不僅僅是查看圖表,因為我可以快速: 創建一個快速LegDown 指示器來測量跌落的範圍。

Backtrader教程:日誌記錄 - 編寫器

將以下內容寫出到流中: csv 流,

Backtrader教程:數據饋送 - 擴展 (Extending DataFeed)

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

Backtrader跨越數位

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

Backtrader 教程:指標 - 時間框架混合

版本 1.3.0.92提供了混合來自不同時間範圍的數據(來自數據饋送和/或指標)的可能性。背景:指標是智能的啞對象。他們很聰明,因為他們可以進行複雜的計算。他們是愚蠢的,因為他們在不知道哪些來源為計算提供數據的情況下進行操作像這樣:如果提供值的數據源在Cerebro引擎內具有不同的時間範圍、不同的長度,則指標將中斷。

Backtrader開場作弊

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

Backtrader 教程:訂單 - 目標訂單

在1.8.10.96版本之前,可以使用反向交易者通過策略方法進行智能質押: buy和sell 。這一切都是為了在負責賭注大小的等式中添加一個Sizer 。 Sizer不能做的是決定操作是買入還是賣出。這意味著需要一個新概念,在其中添加一個小的智能層來做出這樣的決定。