Backtrader目標訂單

  |  

1.8.10.96版本之前,可以使用反向交易者通過策略方法進行智能質押:買入和賣出。這一切都是為了在負責賭注大小的等式中添加一個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

更改為 2 月時,目標值開始從31000減少到3000029000\ 。從 30580.00 to 30706.56 and then to 28633.44 的*數據值*也是如此。等待:

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

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

如何避免這種影響:

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

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

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

order_target_value

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

$ ./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傭金計劃

backtrader 的誕生是出於必要。我自己的...有一種感覺,我控制著自己的回溯測試平臺,可以嘗試新的想法。但是,在這樣做並且從一開始就完全 open 採購它時,很明顯它必須有一種方法來滿足他人的需求和願望。 作為未來的交易者,我本可以選擇基於點的計算和每輪傭金的固定價格,但這將是一個錯誤。

Backtrader教程:經紀人 - 開倉作弊

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

BacktraderPython Hidden Powers 2

讓我們進一步討論一下Python的隱藏功能如何在 backtrader 中使用,以及如何實現它以嘗試實現主要目標:易用性 這些定義是什麼? 例如指標: import backtrader as bt class MyIndicator(bt.

Backtrader教程:指標 - 開發

如果必須開發任何東西(除了一個或多個獲勝策略之外),那麼這個東西就是一個自定義指標。 根據作者的說法,平臺內的這種開發很容易。 需要滿足以下條件: 從指標派生的類(直接或從現有的子類派生) 定義它將保持lines 指標必須至少具有 1 line。

Backtrader 教程:繪圖 - 同一軸

上一篇future-spot 將原始數據和稍微(隨機)修改的數據繪製在同一空間上,但不在同一軸上。從該帖子中恢復第一張圖片。有人能看見:圖表左右兩側有不同的刻度當查看在原始數據周圍振盪+- 50點的擺動紅線(隨機數據)時,這一點最為明顯。在圖表上,視覺印像是這些隨機數據大多總是高於原始數據。

Backtrader股票篩選

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

Backtrader交叉回溯測試陷阱

在backtrader 社區中 ,傾向於重複的事情是,用戶解釋了複製在例如 TradingView 中獲得的回溯測試結果的意願,這些天非常流行,或者其他一些回溯測試平臺。

Backtrader教程:數據饋送 - 雅虎

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

Backtrader卡爾曼等

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

Backtrader多數據範例

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