BackTrader 中文文档(二十二)(3)

简介: BackTrader 中文文档(二十二)

BackTrader 中文文档(二十二)(2)https://developer.aliyun.com/article/1505426

并且代码本身

from __future__ import (absolute_import, division, print_function,
                        unicode_literals)
import argparse
import datetime
import backtrader as bt
import backtrader.indicators as btind
class DayStepsCloseFilter(bt.with_metaclass(bt.MetaParams, object)):
    '''
    Replays a bar in 2 steps:
      - In the 1st step the "Open-High-Low" could be evaluated to decide if to
        act on the close (the close is still there ... should not be evaluated)
      - If a "Close" order has been executed
        In this 1st fragment the "Close" is replaced through the "open" althoug
        other alternatives would be possible like high - low average, or an
        algorithm based on where the "close" ac
      and
      - Open-High-Low-Close
    '''
    params = (
        ('cvol', 0.5),  # 0 -> 1 amount of volume to keep for close
    )
    def __init__(self, data):
        self.pendingbar = None
    def __call__(self, data):
        # Make a copy of the new bar and remove it from stream
        closebar = [data.lines[i][0] for i in range(data.size())]
        datadt = data.datetime.date()  # keep the date
        ohlbar = closebar[:]  # Make an open-high-low bar
        # Adjust volume
        ohlbar[data.Volume] = int(closebar[data.Volume] * (1.0 - self.p.cvol))
        dt = datetime.datetime.combine(datadt, data.p.sessionstart)
        ohlbar[data.DateTime] = data.date2num(dt)
        dt = datetime.datetime.combine(datadt, data.p.sessionend)
        closebar[data.DateTime] = data.date2num(dt)
        # Update stream
        data.backwards()  # remove the copied bar from stream
        # Overwrite the new data bar with our pending data - except start point
        if self.pendingbar is not None:
            data._updatebar(self.pendingbar)
        self.pendingbar = closebar  # update the pending bar to the new bar
        data._add2stack(ohlbar)  # Add the openbar to the stack for processing
        return False  # the length of the stream was not changed
    def last(self, data):
        '''Called when the data is no longer producing bars
        Can be called multiple times. It has the chance to (for example)
        produce extra bars'''
        if self.pendingbar is not None:
            data.backwards()  # remove delivered open bar
            data._add2stack(self.pendingbar)  # add remaining
            self.pendingbar = None  # No further action
            return True  # something delivered
        return False  # nothing delivered here
class DayStepsReplayFilter(bt.with_metaclass(bt.MetaParams, object)):
    '''
    Replays a bar in 2 steps:
      - In the 1st step the "Open-High-Low" could be evaluated to decide if to
        act on the close (the close is still there ... should not be evaluated)
      - If a "Close" order has been executed
        In this 1st fragment the "Close" is replaced through the "open" althoug
        other alternatives would be possible like high - low average, or an
        algorithm based on where the "close" ac
      and
      - Open-High-Low-Close
    '''
    params = (
        ('closevol', 0.5),  # 0 -> 1 amount of volume to keep for close
    )
    # replaying = True
    def __init__(self, data):
        self.lastdt = None
        pass
    def __call__(self, data):
        # Make a copy of the new bar and remove it from stream
        datadt = data.datetime.date()  # keep the date
        if self.lastdt == datadt:
            return False  # skip bars that come again in the filter
        self.lastdt = datadt  # keep ref to last seen bar
        # Make a copy of current data for ohlbar
        ohlbar = [data.lines[i][0] for i in range(data.size())]
        closebar = ohlbar[:]  # Make a copy for the close
        # replace close price with o-h-l average
        ohlprice = ohlbar[data.Open] + ohlbar[data.High] + ohlbar[data.Low]
        ohlbar[data.Close] = ohlprice / 3.0
        vol = ohlbar[data.Volume]  # adjust volume
        ohlbar[data.Volume] = vohl = int(vol * (1.0 - self.p.closevol))
        oi = ohlbar[data.OpenInterest]  # adjust open interst
        ohlbar[data.OpenInterest] = 0
        # Adjust times
        dt = datetime.datetime.combine(datadt, data.p.sessionstart)
        ohlbar[data.DateTime] = data.date2num(dt)
        # Adjust closebar to generate a single tick -> close price
        closebar[data.Open] = cprice = closebar[data.Close]
        closebar[data.High] = cprice
        closebar[data.Low] = cprice
        closebar[data.Volume] = vol - vohl
        ohlbar[data.OpenInterest] = oi
        # Adjust times
        dt = datetime.datetime.combine(datadt, data.p.sessionend)
        closebar[data.DateTime] = data.date2num(dt)
        # Update stream
        data.backwards(force=True)  # remove the copied bar from stream
        data._add2stack(ohlbar)  # add ohlbar to stack
        # Add 2nd part to stash to delay processing to next round
        data._add2stack(closebar, stash=True)
        return False  # the length of the stream was not changed
class St(bt.Strategy):
    params = (
        ('highperiod', 20),
        ('sellafter', 2),
        ('market', False),
    )
    def __init__(self):
        pass
    def start(self):
        self.callcounter = 0
        txtfields = list()
        txtfields.append('Calls')
        txtfields.append('Len Strat')
        txtfields.append('Len Data')
        txtfields.append('Datetime')
        txtfields.append('Open')
        txtfields.append('High')
        txtfields.append('Low')
        txtfields.append('Close')
        txtfields.append('Volume')
        txtfields.append('OpenInterest')
        print(','.join(txtfields))
        self.lcontrol = 0  # control if 1st or 2nd call
        self.inmarket = 0
        # Get the highest but delayed 1 ... to avoid "today"
        self.highest = btind.Highest(self.data.high,
                                     period=self.p.highperiod,
                                     subplot=False)
    def notify_order(self, order):
        if order.isbuy() and order.status == order.Completed:
            print('-- BUY Completed on:',
                  self.data.num2date(order.executed.dt).strftime('%Y-%m-%d'))
            print('-- BUY Price:', order.executed.price)
    def next(self):
        self.callcounter += 1
        txtfields = list()
        txtfields.append('%04d' % self.callcounter)
        txtfields.append('%04d' % len(self))
        txtfields.append('%04d' % len(self.data0))
        txtfields.append(self.data.datetime.datetime(0).isoformat())
        txtfields.append('%.2f' % self.data0.open[0])
        txtfields.append('%.2f' % self.data0.high[0])
        txtfields.append('%.2f' % self.data0.low[0])
        txtfields.append('%.2f' % self.data0.close[0])
        txtfields.append('%.2f' % self.data0.volume[0])
        txtfields.append('%.2f' % self.data0.openinterest[0])
        print(','.join(txtfields))
        if not self.position:
            if len(self.data) > self.lcontrol:
                if self.data.high == self.highest:  # today is highest!!!
                    print('High %.2f > Highest %.2f' %
                          (self.data.high[0], self.highest[0]))
                    print('LAST 19 highs:',
                          self.data.high.get(size=19, ago=-1))
                    print('-- BUY on date:',
                          self.data.datetime.date().strftime('%Y-%m-%d'))
                    ex = bt.Order.Market if self.p.market else bt.Order.Close
                    self.buy(exectype=ex)
                    self.inmarket = len(self)  # reset period in market
        else:  # in the market
            if (len(self) - self.inmarket) >= self.p.sellafter:
                self.sell()
        self.lcontrol = len(self.data)
def runstrat():
    args = parse_args()
    cerebro = bt.Cerebro()
    cerebro.broker.set_cash(args.cash)
    cerebro.broker.set_eosbar(True)
    dkwargs = dict()
    if args.fromdate:
        fromdate = datetime.datetime.strptime(args.fromdate, '%Y-%m-%d')
        dkwargs['fromdate'] = fromdate
    if args.todate:
        todate = datetime.datetime.strptime(args.todate, '%Y-%m-%d')
        dkwargs['todate'] = todate
    if args.no_replay:
        data = bt.feeds.YahooFinanceCSVData(dataname=args.data,
                                            timeframe=bt.TimeFrame.Days,
                                            compression=1,
                                            **dkwargs)
        data.addfilter(DayStepsCloseFilter)
        cerebro.adddata(data)
    else:
        data = bt.feeds.YahooFinanceCSVData(dataname=args.data,
                                            timeframe=bt.TimeFrame.Minutes,
                                            compression=1,
                                            **dkwargs)
        data.addfilter(DayStepsReplayFilter)
        cerebro.replaydata(data, timeframe=bt.TimeFrame.Days, compression=1)
    cerebro.addstrategy(St,
                        sellafter=args.sellafter,
                        highperiod=args.highperiod,
                        market=args.market)
    cerebro.run(runonce=False, preload=False, oldbuysell=args.oldbuysell)
    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 pinkfish challenge')
    parser.add_argument('--data', required=False,
                        default='../../datas/yhoo-1996-2015.txt',
                        help='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=50000,
                        help=('Cash to start with'))
    parser.add_argument('--sellafter', required=False, action='store',
                        type=int, default=2,
                        help=('Sell after so many bars in market'))
    parser.add_argument('--highperiod', required=False, action='store',
                        type=int, default=20,
                        help=('Period to look for the highest'))
    parser.add_argument('--no-replay', required=False, action='store_true',
                        help=('Use Replay + replay filter'))
    parser.add_argument('--market', required=False, action='store_true',
                        help=('Use Market exec instead of Close'))
    parser.add_argument('--oldbuysell', required=False, action='store_true',
                        help=('Old buysell plot behavior - ON THE PRICE'))
    # 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 (escape the quotes if needed):\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()

TA-Lib

原文:www.backtrader.com/blog/posts/2016-07-26-talib-integration/talib-integration/

即使backtrader提供了大量内置指标,并且开发指标主要是定义输入、输出并以自然方式编写公式,一些人还是想使用TA-LIB。一些原因:

  • 指标X在库中而不在backtrader中(作者将很乐意接受请求)
  • TA-LIB的行为是众所周知的,人们信任老牌东西

为了满足每个口味,TA-LIB集成是提供的。

要求

安装详情在GitHub存储库中

使用ta-lib

就像使用backtrader中已经内置的任何指标一样容易。简单移动平均的示例。首先是backtrader的:

import backtrader as bt
class MyStrategy(bt.Strategy):
    params = (('period', 20),)
    def __init__(self):
        self.sma = bt.indicators.SMA(self.data, period=self.p.period)
        ...
...

现在是ta-lib的示例:

import backtrader as bt
class MyStrategy(bt.Strategy):
    params = (('period', 20),)
    def __init__(self):
        self.sma = bt.talib.SMA(self.data, timeperiod=self.p.period)
        ...
...

哦,就这样!当然,ta-lib指标的params由库本身定义,而不是由backtrader定义。在这种情况下,ta-lib中的SMA需要一个名为timeperiod的参数来定义操作窗口的大小。

对于需要多个输入的指标,例如随机指标

import backtrader as bt
class MyStrategy(bt.Strategy):
    params = (('period', 20),)
    def __init__(self):
        self.stoc = bt.talib.STOCH(self.data.high, self.data.low, self.data.close,
                                   fastk_period=14, slowk_period=3, slowd_period=3)
        ...
...

注意highlowclose已经被单独传递。人们总是可以传递open而不是low(或任何其他数据系列)进行实验。

ta-lib指标文档会自动解析并添加到backtrader文档中。您还可以查看ta-lib源代码/文档。或者额外执行:

print(bt.talib.SMA.__doc__)

在这种情况下输出:

SMA([input_arrays], [timeperiod=30])
Simple Moving Average (Overlap Studies)
Inputs:
    price: (any ndarray)
Parameters:
    timeperiod: 30
Outputs:
    real

提供一些信息:

  • 应该期望哪个输入DISREGARD ndarray 评论,因为 backtrader 在后台管理转换)
  • 哪些参数和默认值
  • 哪个线提供了指标的输出

移动平均线和 MA_Type

对于像bt.talib.STOCH这样的指标选择特定的移动平均线,标准ta-lib MA_Type 可以通过bactrader.talib.MA_Type来访问。例如:

import backtrader as bt
print('SMA:', bt.talib.MA_Type.SMA)
print('T3:', bt.talib.MA_Type.T3)

绘制 ta-lib 指标

就像常规使用一样,对于绘制ta-lib指标没有什么特别的要做。

注意

输出CANDLE的指标(所有寻找蜡烛图形式的指标)提供二进制输出:要么是 0,要么是 100。为了避免将subplot添加到图表中,有一个自动绘图转换来在识别模式的时间点上在data上绘制它们。

示例和比较

以下是一些ta-lib指标输出与backtrader中等效内置指标输出的图表比较。要考虑的事项:

  • ta-lib指标在图表上加了一个TA_前缀。这是为了帮助用户区分哪个是哪个
  • 移动平均线(如果两者产生相同的结果)将绘制在其他现有移动平均线的顶部。这两个指标不能分开看,如果是这样,测试就通过了。
  • 所有示例都包括CDLDOJI指标作为参考

KAMA(Kaufman 移动平均)

这是第 1 个示例,因为它是唯一一个(与示例直接进行比较的所有指标中)有差异的示例:

  • 样本的初始值不相同
  • 在某个时间点,值会收敛,两个KAMA实现都会有相同的行为。

分析了ta-lib源代码之后:

  • ta-lib中的实现对KAMA的第 1 个值做出了非行业标准的选择。
    选择可以从源代码中看到(引用源代码):这里使用昨天的价格作为前一天的 KAMA。

backtrader 做了与Stockcharts相同的常规选择:

  • StockCharts 上的 KAMA
    由于我们需要一个初始值来开始计算,第一个 KAMA 只是一个简单的移动平均线

因此有所不同。此外:

  • ta-libKAMA实现不允许指定快速慢速周期来调整Kaufman定义的可缩放常数

示例执行:

$ ./talibtest.py --plot --ind kama

输出

SMA

$ ./talibtest.py --plot --ind sma

输出

EMA

$ ./talibtest.py --plot --ind ema

输出

随机指标

$ ./talibtest.py --plot --ind stoc

输出

RSI

$ ./talibtest.py --plot --ind rsi

输出

MACD

$ ./talibtest.py --plot --ind macd

输出

布林带

$ ./talibtest.py --plot --ind bollinger

输出

AROON

请注意,ta-lib选择将下行线放在前面,当与backtrader内置指标进行比较时,颜色会反转。

$ ./talibtest.py --plot --ind aroon

输出

终极波动率

$ ./talibtest.py --plot --ind ultimate

输出

Trix

$ ./talibtest.py --plot --ind trix

输出

ADXR

在这里,backtrader 提供了ADXADXR线。

$ ./talibtest.py --plot --ind adxr

输出


BackTrader 中文文档(二十二)(4)https://developer.aliyun.com/article/1505430

相关文章
|
8月前
|
存储 测试技术 Python
BackTrader 中文文档(二十二)(2)
BackTrader 中文文档(二十二)
67 0
|
8月前
BackTrader 中文文档(二十二)(1)
BackTrader 中文文档(二十二)
43 0
|
8月前
|
测试技术
BackTrader 中文文档(二十二)(4)
BackTrader 中文文档(二十二)
53 0
|
8月前
BackTrader 中文文档(二十三)(4)
BackTrader 中文文档(二十三)
46 0
|
8月前
|
编解码 API Windows
BackTrader 中文文档(二十三)(3)
BackTrader 中文文档(二十三)
54 0
|
8月前
|
编解码 索引
BackTrader 中文文档(二十三)(2)
BackTrader 中文文档(二十三)
52 0
|
8月前
|
Oracle 测试技术 编译器
BackTrader 中文文档(二十三)(1)
BackTrader 中文文档(二十三)
73 0
|
8月前
|
C++
BackTrader 中文文档(二十五)(3)
BackTrader 中文文档(二十五)
63 0
|
8月前
|
数据可视化
BackTrader 中文文档(二十五)(4)
BackTrader 中文文档(二十五)
66 0
|
8月前
|
数据可视化 API Python
BackTrader 中文文档(二十五)(1)
BackTrader 中文文档(二十五)
63 0