Backtrader - sizer

以下内容皆参考 Backtrader 官网

之前有介绍过,如果我们下单除了股价以外,还有一个很重要的因素就是要买几股,有些时候,我们的策略可能会需要不同的买入数量,Backtrader 也有一个物件 sizer 可以提供相关的弹性,如果预设的没有合适的,也可以自订义一个,以下先介绍内建的一些 sizer

FixedSize

顾名思义就是固定的数量
参数:

  • stake { default 1 }: 固定数量的股数
  • tranches { default 1 }: 只执行 stake 的几分之一
    最後的数量 = stake / tranches
cerebro.addsizer(bt.sizers.SizerFix, stake = 1000)

FixedReverser

一样是固定数量,只是在卖的时候,会卖出 2 倍的库存,也就是把正的库存卖成负的库存
参数:

  • stake { default 1 } 固定的股数
cerebro.addsizer(bt.sizers.FixedRevert, stake = 1000)

PercentSizer

使用一定比例的帐户余额去买进
参数:

  • percents { default 20 }: 20%
cerebro.addsizer(bt.sizers.PercentSizer, percents = 80)

AllInSizer

基本上和 PercentSizer 一样,只是预设是 100% 的帐户余额去买进股票,另一个差别就是 All in 听起来比较霸气。
这里有一个要注意的是,AllIn 是以当天的收盘价去算要买的股数,可是在执行买入的时候,是隔天的开盘价,所以隔天是涨的话,就会造成余额不足,买入失败喔

cerebro.addsizer(bt.sizers.AllInSizer)

其它

PercentSizerInt, AllInSizerInt,这两个看说明是说在回传数量的时候会转成整数,不过我真正去执行的结果,两个都是一样的,所以暂时看不出差别

自订义 sizer

要自订义 sizer 也很简单

  • 订义一个 sizer 的 class 继承 backtrader.Sizer
    继承後可以使用 self.strategy 和 self.broker 来取得相关资料

    • 取得库存 self.strategy.getposition(data)
    • 取得目前净值 self.broker.getvalue() (或是 self.stratgy.broker.getvalue())
  • 覆写 _getsizing(self, comminfo, cash, data, isbuy)

    • comminfo: 手续费相关资讯
    • cash:目前帐户余额
    • data: 目前的操作(买入/卖出)资料
    • isbuy: 是否为买入(True)

例如:改写 percent 变成可以买的最大的张数 ( 1000 股 )

import backtrader as bt
import math
class PercentBoardSizer(bt.Sizer):
    params = (
        ('percents', 20),
    )

    def _getsizing(self, comminfo, cash, data, isbuy):
        position = self.broker.getposition(data)
        if not position:
            size = cash / data.close[0] * (self.p.percents / 100)
            
            if size < 1000:
                # 小於 1000 股,就不买
                size = 0
            else:
                size = math.floor(size / 1000) * 1000
        else:
            size = position.size

        size = int(size)
        
        return size

class AllInBoardSizer(PercentBoardSizer):
    params = (
        ('percents', 100),
    )

使用方法

  • 在 strategy 中:

    • def setsizer(self, sizer): 可以取得已经初始化的 sizer
    • def getsizer(self): 回传目前使用的 sizer
    • sizer 属性可以直接进行 get/set (前几天的范例就是使用这个)
  • 使用 cerebro:
    目前看来,如果 strategy 和 cerebro 都有设定的话,会以 cerebro 为主,cerebro 有两个方法可以设定

    • addsizer(sizerClass, *args, **kwargs): 指定所有的 strategy 使用的 sizer
    • addsizer_byidx(idx, sizerClass, *args, **kwargs): 根据不同的 strategy inx 来使用不同的 sizer
      ex:
    cerebro = bt.Cerebro()
    # 预设的 sizer
    cerebro.addsizer(bt.sizers.SizerFix, stake = 1000)
    
    # 这样就可以针对不同的 strategy 来设定不同的 sizer
    idx = cerebro.addstrategy(TestStrategy)
    cerebro.addsizer_byidx(idx, bt.sizers.SizerFix, stake = 5)
    

<<:  30-24 之从集中式架构到微服务的难点 - DDD 的诞生

>>:  【PHP Telegram Bot】Day30 - 社群按赞机器人(2):将按钮设成单选并且计数

[iT铁人赛Day11]JAVA回圈

这次要来细讲回圈了 上次说到回圈有分成:1. for回圈,2. while回圈以及3. do whi...

鬼故事 - 这东西真烂

鬼故事 - 这东西真烂 Credit: Corentin Penloup 灵感来源:https://...

从零开始学游戏开发:入门程序实作 Part.7 重新计分

这是 Roblox 从零开始系列,入门章节的第十三个单元,我们的游戏出现Bug了,那就是死亡後分数还...

30.unity输出

终於迎来铁人赛的最後一天!!好兴奋呀!! 最後一天要让游戏离开游戏引擎,成为能自己运作的应用程序! ...

Day 04:金鱼记忆力太短暂,交给外挂记吧!autosuggestions 与 substring-search

更新 我把从第一天到现在每天的 Home 目录都放上 GitHub 了,README.md 里面有...