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

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

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

带有更新的输出:

===============================================================================
Id,2006-day-001,len,datetime,open,high,low,close,volume,openinterest,LongShortStrategy,len,Broker,len,cash,value,Buy
Sell,len,buy,sell,Trades,len,pnlplus,pnlminus
1,2006-day-001,1,2006-01-02 23:59:59+00:00,3578.73,3605.95,3578.73,3604.33,0.0,0.0,LongShortStrategy,1,Broker,1,1000
00.0,100000.0,BuySell,1,,,Trades,1,,
2,2006-day-001,2,2006-01-03 23:59:59+00:00,3604.08,3638.42,3601.84,3614.34,0.0,0.0,LongShortStrategy,2,Broker,2,1000
00.0,100000.0,BuySell,2,,,Trades,2,,
...
...
...
255,2006-day-001,255,2006-12-29 23:59:59+00:00,4130.12,4142.01,4119.94,4119.94,0.0,0.0,LongShortStrategy,255,Broker,255,100795.0,102795.0,BuySell,255,,,Trades,255,,
===============================================================================
Cerebro:
  -----------------------------------------------------------------------------
...
...

我们可以跳过大部分的 CSV 流和已经看过的摘要。CSV 流已经打印出以下内容

  • 一个部分线分隔符在开头
  • 一个标题行
  • 相应的数据

注意每个对象的“长度”是如何被打印出来的。虽然在这种情况下它并没有提供太多信息,但如果使用了多时间框数据或者数据被重播,它将提供信息。

writer 的默认设置如下:

  • 没有指标被打印出来(既没有简单移动平均线也没有交叉点)
  • 观察者被打印出来

让我们运行脚本并附加一个参数,将 CrossOver 指示器添加到 CSV 流中:

$ ./writer-test.py --onlylong --writercsv --csvcross

输出:

===============================================================================
Id,2006-day-001,len,datetime,open,high,low,close,volume,openinterest,LongShortStrategy,len,CrossOver,len,crossover,B
roker,len,cash,value,BuySell,len,buy,sell,Trades,len,pnlplus,pnlminus
1,2006-day-001,1,2006-01-02 23:59:59+00:00,3578.73,3605.95,3578.73,3604.33,0.0,0.0,LongShortStrategy,1,CrossOver,1,,
Broker,1,100000.0,100000.0,BuySell,1,,,Trades,1,,
...
...

这展示了写入器的一些功能。该类的进一步文档仍然是一个待办事项。

与此同时是执行可能性和用于示例的代码。

用法:

$ ./writer-test.py --help
usage: writer-test.py [-h] [--data DATA] [--fromdate FROMDATE]
                      [--todate TODATE] [--period PERIOD] [--onlylong]
                      [--writercsv] [--csvcross] [--cash CASH] [--comm COMM]
                      [--mult MULT] [--margin MARGIN] [--stake STAKE] [--plot]
                      [--numfigs NUMFIGS]
MultiData Strategy
optional arguments:
  -h, --help            show this help message and exit
  --data DATA, -d DATA  data to add to the system
  --fromdate FROMDATE, -f FROMDATE
                        Starting date in YYYY-MM-DD format
  --todate TODATE, -t TODATE
                        Starting date in YYYY-MM-DD format
  --period PERIOD       Period to apply to the Simple Moving Average
  --onlylong, -ol       Do only long operations
  --writercsv, -wcsv    Tell the writer to produce a csv stream
  --csvcross            Output the CrossOver signals to CSV
  --cash CASH           Starting Cash
  --comm COMM           Commission for operation
  --mult MULT           Multiplier for futures
  --margin MARGIN       Margin for each future
  --stake STAKE         Stake to apply in each operation
  --plot, -p            Plot the read data
  --numfigs NUMFIGS, -n NUMFIGS
                        Plot using numfigs figures

和测试脚本。

from __future__ import (absolute_import, division, print_function,
                        unicode_literals)
import argparse
import datetime
# The above could be sent to an independent module
import backtrader as bt
import backtrader.feeds as btfeeds
import backtrader.indicators as btind
from backtrader.analyzers import SQN
class LongShortStrategy(bt.Strategy):
    '''This strategy buys/sells upong the close price crossing
    upwards/downwards a Simple Moving Average.
    It can be a long-only strategy by setting the param "onlylong" to True
    '''
    params = dict(
        period=15,
        stake=1,
        printout=False,
        onlylong=False,
        csvcross=False,
    )
    def start(self):
        pass
    def stop(self):
        pass
    def log(self, txt, dt=None):
        if self.p.printout:
            dt = dt or self.data.datetime[0]
            dt = bt.num2date(dt)
            print('%s, %s' % (dt.isoformat(), txt))
    def __init__(self):
        # To control operation entries
        self.orderid = None
        # Create SMA on 2nd data
        sma = btind.MovAv.SMA(self.data, period=self.p.period)
        # Create a CrossOver Signal from close an moving average
        self.signal = btind.CrossOver(self.data.close, sma)
        self.signal.csv = self.p.csvcross
    def next(self):
        if self.orderid:
            return  # if an order is active, no new orders are allowed
        if self.signal > 0.0:  # cross upwards
            if self.position:
                self.log('CLOSE SHORT , %.2f' % self.data.close[0])
                self.close()
            self.log('BUY CREATE , %.2f' % self.data.close[0])
            self.buy(size=self.p.stake)
        elif self.signal < 0.0:
            if self.position:
                self.log('CLOSE LONG , %.2f' % self.data.close[0])
                self.close()
            if not self.p.onlylong:
                self.log('SELL CREATE , %.2f' % self.data.close[0])
                self.sell(size=self.p.stake)
    def notify_order(self, order):
        if order.status in [bt.Order.Submitted, bt.Order.Accepted]:
            return  # Await further notifications
        if order.status == order.Completed:
            if order.isbuy():
                buytxt = 'BUY COMPLETE, %.2f' % order.executed.price
                self.log(buytxt, order.executed.dt)
            else:
                selltxt = 'SELL COMPLETE, %.2f' % order.executed.price
                self.log(selltxt, order.executed.dt)
        elif order.status in [order.Expired, order.Canceled, order.Margin]:
            self.log('%s ,' % order.Status[order.status])
            pass  # Simply log
        # Allow new orders
        self.orderid = None
    def notify_trade(self, trade):
        if trade.isclosed:
            self.log('TRADE PROFIT, GROSS %.2f, NET %.2f' %
                     (trade.pnl, trade.pnlcomm))
        elif trade.justopened:
            self.log('TRADE OPENED, SIZE %2d' % trade.size)
def runstrategy():
    args = parse_args()
    # Create a cerebro
    cerebro = bt.Cerebro()
    # Get the dates from the args
    fromdate = datetime.datetime.strptime(args.fromdate, '%Y-%m-%d')
    todate = datetime.datetime.strptime(args.todate, '%Y-%m-%d')
    # Create the 1st data
    data = btfeeds.BacktraderCSVData(
        dataname=args.data,
        fromdate=fromdate,
        todate=todate)
    # Add the 1st data to cerebro
    cerebro.adddata(data)
    # Add the strategy
    cerebro.addstrategy(LongShortStrategy,
                        period=args.period,
                        onlylong=args.onlylong,
                        csvcross=args.csvcross,
                        stake=args.stake)
    # Add the commission - only stocks like a for each operation
    cerebro.broker.setcash(args.cash)
    # Add the commission - only stocks like a for each operation
    cerebro.broker.setcommission(commission=args.comm,
                                 mult=args.mult,
                                 margin=args.margin)
    cerebro.addanalyzer(SQN)
    cerebro.addwriter(bt.WriterFile, csv=args.writercsv, rounding=2)
    # And run it
    cerebro.run()
    # Plot if requested
    if args.plot:
        cerebro.plot(numfigs=args.numfigs, volume=False, zdown=False)
def parse_args():
    parser = argparse.ArgumentParser(description='MultiData Strategy')
    parser.add_argument('--data', '-d',
                        default='../../datas/2006-day-001.txt',
                        help='data to add to the system')
    parser.add_argument('--fromdate', '-f',
                        default='2006-01-01',
                        help='Starting date in YYYY-MM-DD format')
    parser.add_argument('--todate', '-t',
                        default='2006-12-31',
                        help='Starting date in YYYY-MM-DD format')
    parser.add_argument('--period', default=15, type=int,
                        help='Period to apply to the Simple Moving Average')
    parser.add_argument('--onlylong', '-ol', action='store_true',
                        help='Do only long operations')
    parser.add_argument('--writercsv', '-wcsv', action='store_true',
                        help='Tell the writer to produce a csv stream')
    parser.add_argument('--csvcross', action='store_true',
                        help='Output the CrossOver signals to CSV')
    parser.add_argument('--cash', default=100000, type=int,
                        help='Starting Cash')
    parser.add_argument('--comm', default=2, type=float,
                        help='Commission for operation')
    parser.add_argument('--mult', default=10, type=int,
                        help='Multiplier for futures')
    parser.add_argument('--margin', default=2000.0, type=float,
                        help='Margin for each future')
    parser.add_argument('--stake', default=1, type=int,
                        help='Stake to apply in each operation')
    parser.add_argument('--plot', '-p', action='store_true',
                        help='Plot the read data')
    parser.add_argument('--numfigs', '-n', default=1,
                        help='Plot using numfigs figures')
    return parser.parse_args()
if __name__ == '__main__':
    runstrategy()

多数据策略

原文:www.backtrader.com/blog/posts/2015-09-03-multidata-strategy/multidata-strategy/

因为世界上没有任何事物是孤立存在的,很可能购买某项资产的触发因素实际上是另一项资产。

使用不同的分析技术可能会发现两个不同数据之间的相关性。

backtrader 支持同时使用不同数据源,因此在大多数情况下可能会用于此目的。

让我们假设已经发现了以下公司之间的相关性:

  • Oracle
  • Yahoo

人们可以想象,当雅虎公司运营良好时,该公司会从 Oracle 购买更多服务器、更多数据库和更多专业服务,从而推动股价上涨。

因此,经过深入分析后制定了一项策略:

  • 如果Yahoo的收盘价超过简单移动平均线(周期 15)
  • 买入Oracle

退出头寸:

  • 使用收盘价的下穿

订单执行类型:

  • 市场

总结一下使用backtrader设置所需的内容:

  • 创建一个cerebro
  • 加载数据源 1(Oracle)并将其添加到 cerebro
  • 加载数据源 2(Yahoo)并将其添加到 cerebro
  • 加载我们设计的策略

策略的详细信息:

  • 在数据源 2(Yahoo)上创建一个简单移动平均线
  • 使用雅虎��收盘价和移动平均��创建一个 CrossOver 指标

然后按照上述描述在数据源 1(Oracle)上执行买入/卖出订单。

下面的脚本使用以下默认值:

  • Oracle(数据源 1)
  • 雅虎(数据源 2)
  • 现金:10000(系统默认值)
  • 股份:10 股
  • 佣金:每轮 0.5%(表示为 0.005)
  • 周期:15 个交易日
  • 周期:2003 年、2004 年和 2005 年

该脚本可以接受参数以修改上述设置,如帮助文本中所示:

$ ./multidata-strategy.py --help
usage: multidata-strategy.py [-h] [--data0 DATA0] [--data1 DATA1]
                             [--fromdate FROMDATE] [--todate TODATE]
                             [--period PERIOD] [--cash CASH]
                             [--commperc COMMPERC] [--stake STAKE] [--plot]
                             [--numfigs NUMFIGS]
MultiData Strategy
optional arguments:
  -h, --help            show this help message and exit
  --data0 DATA0, -d0 DATA0
                        1st data into the system
  --data1 DATA1, -d1 DATA1
                        2nd data into the system
  --fromdate FROMDATE, -f FROMDATE
                        Starting date in YYYY-MM-DD format
  --todate TODATE, -t TODATE
                        Starting date in YYYY-MM-DD format
  --period PERIOD       Period to apply to the Simple Moving Average
  --cash CASH           Starting Cash
  --commperc COMMPERC   Percentage commission for operation (0.005 is 0.5%
  --stake STAKE         Stake to apply in each operation
  --plot, -p            Plot the read data
  --numfigs NUMFIGS, -n NUMFIGS
                        Plot using numfigs figures

标准执行结果:

$ ./multidata-strategy.py
2003-02-11T23:59:59+00:00, BUY CREATE , 9.14
2003-02-12T23:59:59+00:00, BUY COMPLETE, 11.14
2003-02-12T23:59:59+00:00, SELL CREATE , 9.09
2003-02-13T23:59:59+00:00, SELL COMPLETE, 10.90
2003-02-14T23:59:59+00:00, BUY CREATE , 9.45
2003-02-18T23:59:59+00:00, BUY COMPLETE, 11.22
2003-03-06T23:59:59+00:00, SELL CREATE , 9.72
2003-03-07T23:59:59+00:00, SELL COMPLETE, 10.32
...
...
2005-12-22T23:59:59+00:00, BUY CREATE , 40.83
2005-12-23T23:59:59+00:00, BUY COMPLETE, 11.68
2005-12-23T23:59:59+00:00, SELL CREATE , 40.63
2005-12-27T23:59:59+00:00, SELL COMPLETE, 11.63
==================================================
Starting Value - 100000.00
Ending   Value - 99959.26
==================================================

经过两年的执行后,该策略:

  • 损失了 40.74 货币单位

至于雅虎和 Oracle 之间的相关性

可视化输出(添加--plot以生成图表)

以及脚本(已添加到backtrader源分发的samples/multidata-strategy目录下。

from __future__ import (absolute_import, division, print_function,
                        unicode_literals)
import argparse
import datetime
# The above could be sent to an independent module
import backtrader as bt
import backtrader.feeds as btfeeds
import backtrader.indicators as btind
class MultiDataStrategy(bt.Strategy):
    '''
    This strategy operates on 2 datas. The expectation is that the 2 datas are
    correlated and the 2nd data is used to generate signals on the 1st
      - Buy/Sell Operationss will be executed on the 1st data
      - The signals are generated using a Simple Moving Average on the 2nd data
        when the close price crosses upwwards/downwards
    The strategy is a long-only strategy
    '''
    params = dict(
        period=15,
        stake=10,
        printout=True,
    )
    def log(self, txt, dt=None):
        if self.p.printout:
            dt = dt or self.data.datetime[0]
            dt = bt.num2date(dt)
            print('%s, %s' % (dt.isoformat(), txt))
    def notify_order(self, order):
        if order.status in [bt.Order.Submitted, bt.Order.Accepted]:
            return  # Await further notifications
        if order.status == order.Completed:
            if order.isbuy():
                buytxt = 'BUY COMPLETE, %.2f' % order.executed.price
                self.log(buytxt, order.executed.dt)
            else:
                selltxt = 'SELL COMPLETE, %.2f' % order.executed.price
                self.log(selltxt, order.executed.dt)
        elif order.status in [order.Expired, order.Canceled, order.Margin]:
            self.log('%s ,' % order.Status[order.status])
            pass  # Simply log
        # Allow new orders
        self.orderid = None
    def __init__(self):
        # To control operation entries
        self.orderid = None
        # Create SMA on 2nd data
        sma = btind.MovAv.SMA(self.data1, period=self.p.period)
        # Create a CrossOver Signal from close an moving average
        self.signal = btind.CrossOver(self.data1.close, sma)
    def next(self):
        if self.orderid:
            return  # if an order is active, no new orders are allowed
        if not self.position:  # not yet in market
            if self.signal > 0.0:  # cross upwards
                self.log('BUY CREATE , %.2f' % self.data1.close[0])
                self.buy(size=self.p.stake)
        else:  # in the market
            if self.signal < 0.0:  # crosss downwards
                self.log('SELL CREATE , %.2f' % self.data1.close[0])
                self.sell(size=self.p.stake)
    def stop(self):
        print('==================================================')
        print('Starting Value - %.2f' % self.broker.startingcash)
        print('Ending   Value - %.2f' % self.broker.getvalue())
        print('==================================================')
def runstrategy():
    args = parse_args()
    # Create a cerebro
    cerebro = bt.Cerebro()
    # Get the dates from the args
    fromdate = datetime.datetime.strptime(args.fromdate, '%Y-%m-%d')
    todate = datetime.datetime.strptime(args.todate, '%Y-%m-%d')
    # Create the 1st data
    data0 = btfeeds.YahooFinanceCSVData(
        dataname=args.data0,
        fromdate=fromdate,
        todate=todate)
    # Add the 1st data to cerebro
    cerebro.adddata(data0)
    # Create the 2nd data
    data1 = btfeeds.YahooFinanceCSVData(
        dataname=args.data1,
        fromdate=fromdate,
        todate=todate)
    # Add the 2nd data to cerebro
    cerebro.adddata(data1)
    # Add the strategy
    cerebro.addstrategy(MultiDataStrategy,
                        period=args.period,
                        stake=args.stake)
    # Add the commission - only stocks like a for each operation
    cerebro.broker.setcash(args.cash)
    # Add the commission - only stocks like a for each operation
    cerebro.broker.setcommission(commission=args.commperc)
    # And run it
    cerebro.run()
    # Plot if requested
    if args.plot:
        cerebro.plot(numfigs=args.numfigs, volume=False, zdown=False)
def parse_args():
    parser = argparse.ArgumentParser(description='MultiData Strategy')
    parser.add_argument('--data0', '-d0',
                        default='../../datas/orcl-1995-2014.txt',
                        help='1st data into the system')
    parser.add_argument('--data1', '-d1',
                        default='../../datas/yhoo-1996-2014.txt',
                        help='2nd data into the system')
    parser.add_argument('--fromdate', '-f',
                        default='2003-01-01',
                        help='Starting date in YYYY-MM-DD format')
    parser.add_argument('--todate', '-t',
                        default='2005-12-31',
                        help='Starting date in YYYY-MM-DD format')
    parser.add_argument('--period', default=15, type=int,
                        help='Period to apply to the Simple Moving Average')
    parser.add_argument('--cash', default=100000, type=int,
                        help='Starting Cash')
    parser.add_argument('--commperc', default=0.005, type=float,
                        help='Percentage commission for operation (0.005 is 0.5%%')
    parser.add_argument('--stake', default=10, type=int,
                        help='Stake to apply in each operation')
    parser.add_argument('--plot', '-p', action='store_true',
                        help='Plot the read data')
    parser.add_argument('--numfigs', '-n', default=1,
                        help='Plot using numfigs figures')
    return parser.parse_args()
if __name__ == '__main__':
    runstrategy()


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

相关文章
|
5天前
|
测试技术
BackTrader 中文文档(二十六)(2)
BackTrader 中文文档(二十六)
10 0
|
5天前
BackTrader 中文文档(二十六)(1)
BackTrader 中文文档(二十六)
12 0
|
5天前
|
数据可视化 测试技术 API
BackTrader 中文文档(二十六)(4)
BackTrader 中文文档(二十六)
10 0
|
5天前
|
数据可视化
BackTrader 中文文档(二十五)(4)
BackTrader 中文文档(二十五)
12 0
|
5天前
BackTrader 中文文档(二十五)(2)
BackTrader 中文文档(二十五)
9 0
|
5天前
|
C++
BackTrader 中文文档(二十五)(3)
BackTrader 中文文档(二十五)
11 0
|
5天前
|
数据可视化 API Python
BackTrader 中文文档(二十五)(1)
BackTrader 中文文档(二十五)
9 0
|
5天前
BackTrader 中文文档(二十七)(1)
BackTrader 中文文档(二十七)
10 0
|
5天前
|
存储 数据库连接 数据库
BackTrader 中文文档(二十七)(4)
BackTrader 中文文档(二十七)
10 0
|
5天前
|
索引
BackTrader 中文文档(二十七)(3)
BackTrader 中文文档(二十七)
10 0