BackTrader 中文文档(二十八)(2)

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

BackTrader 中文文档(二十八)(1)https://developer.aliyun.com/article/1505486

执行类型:止损限价

设置了信号价格上涨 1%的止损价。但限价设置在信号(收盘)价格上涨 0.5%,这可以解释为:等待力量展现,但不要买入高峰。等待下跌。

有效期限制为 20(日历)天

elif self.p.exectype == 'StopLimit':
                price = self.data.close * (1.0 + self.p.perc1 / 100.0)
                plimit = self.data.close * (1.0 + self.p.perc2 / 100.0)
                self.buy(exectype=bt.Order.StopLimit, price=price, valid=valid,
                         plimit=plimit)
                if self.p.valid:
                    txt = ('BUY CREATE, exectype StopLimit, price %.2f,'
                           ' valid: %s, pricelimit: %.2f')
                    self.log(txt % (price, valid.strftime('%Y-%m-%d'), plimit))
                else:
                    txt = ('BUY CREATE, exectype StopLimit, price %.2f,'
                           ' pricelimit: %.2f')
                    self.log(txt % (price, plimit))

输出图表。

命令行和输出:

$ ./order-execution-samples.py --exectype StopLimit --perc1 1 --perc2 0.5 --valid 20
2006-01-26T23:59:59+00:00, BUY CREATE, exectype StopLimit, price 3677.83, valid: 2006-02-15, pricelimit: 3659.63
2006-01-26T23:59:59+00:00, ORDER ACCEPTED/SUBMITTED
2006-02-03T23:59:59+00:00, BUY EXECUTED, Price: 3659.63, Cost: 3659.63, Comm 0.00
2006-03-02T23:59:59+00:00, SELL CREATE, 3763.73
2006-03-02T23:59:59+00:00, ORDER ACCEPTED/SUBMITTED
2006-03-03T23:59:59+00:00, SELL EXECUTED, Price: 3763.95, Cost: 3763.95, Comm 0.00
2006-03-10T23:59:59+00:00, BUY CREATE, exectype StopLimit, price 3836.44, valid: 2006-03-30, pricelimit: 3817.45
2006-03-10T23:59:59+00:00, ORDER ACCEPTED/SUBMITTED
2006-03-21T23:59:59+00:00, BUY EXECUTED, Price: 3817.45, Cost: 3817.45, Comm 0.00
2006-03-28T23:59:59+00:00, SELL CREATE, 3811.45
2006-03-28T23:59:59+00:00, ORDER ACCEPTED/SUBMITTED
2006-03-29T23:59:59+00:00, SELL EXECUTED, Price: 3811.85, Cost: 3811.85, Comm 0.00
2006-03-30T23:59:59+00:00, BUY CREATE, exectype StopLimit, price 3913.36, valid: 2006-04-19, pricelimit: 3893.98
2006-03-30T23:59:59+00:00, ORDER ACCEPTED/SUBMITTED
2006-04-19T23:59:59+00:00, BUY EXPIRED
...
...
2006-12-11T23:59:59+00:00, BUY CREATE, exectype StopLimit, price 4093.42, valid: 2006-12-31, pricelimit: 4073.15
2006-12-11T23:59:59+00:00, ORDER ACCEPTED/SUBMITTED
2006-12-22T23:59:59+00:00, BUY EXECUTED, Price: 4073.15, Cost: 4073.15, Comm 0.00

测试脚本执行

在命令行的help中详细说明:

$ ./order-execution-samples.py --help
usage: order-execution-samples.py [-h] [--infile INFILE]
                                  [--csvformat {bt,visualchart,sierrachart,yahoo,yahoo_unreversed}]
                                  [--fromdate FROMDATE] [--todate TODATE]
                                  [--plot] [--plotstyle {bar,line,candle}]
                                  [--numfigs NUMFIGS] [--smaperiod SMAPERIOD]
                                  [--exectype EXECTYPE] [--valid VALID]
                                  [--perc1 PERC1] [--perc2 PERC2]
Showcase for Order Execution Types
optional arguments:
  -h, --help            show this help message and exit
  --infile INFILE, -i INFILE
                        File to be read in
  --csvformat {bt,visualchart,sierrachart,yahoo,yahoo_unreversed},
  -c {bt,visualchart,sierrachart,yahoo,yahoo_unreversed}
                        CSV Format
  --fromdate FROMDATE, -f FROMDATE
                        Starting date in YYYY-MM-DD format
  --todate TODATE, -t TODATE
                        Ending date in YYYY-MM-DD format
  --plot, -p            Plot the read data
  --plotstyle {bar,line,candle}, -ps {bar,line,candle}
                        Plot the read data
  --numfigs NUMFIGS, -n NUMFIGS
                        Plot using n figures
  --smaperiod SMAPERIOD, -s SMAPERIOD
                      Simple Moving Average Period
  --exectype EXECTYPE, -e EXECTYPE
                        Execution Type: Market (default), Close, Limit,
                        Stop, StopLimit
  --valid VALID, -v VALID
                        Validity for Limit sample: default 0 days
  --perc1 PERC1, -p1 PERC1
                        % distance from close price at order creation time for
                        the limit/trigger price in Limit/Stop orders
  --perc2 PERC2, -p2 PERC2
                        % distance from close price at order creation time for
                        the limit price in StopLimit orders

完整代码

from __future__ import (absolute_import, division, print_function,
                        unicode_literals)
import argparse
import datetime
import os.path
import time
import sys
import backtrader as bt
import backtrader.feeds as btfeeds
import backtrader.indicators as btind
class OrderExecutionStrategy(bt.Strategy):
    params = (
        ('smaperiod', 15),
        ('exectype', 'Market'),
        ('perc1', 3),
        ('perc2', 1),
        ('valid', 4),
    )
    def log(self, txt, dt=None):
        ''' Logging function fot this strategy'''
        dt = dt or self.data.datetime[0]
        if isinstance(dt, float):
            dt = bt.num2date(dt)
        print('%s, %s' % (dt.isoformat(), txt))
    def notify_order(self, order):
        if order.status in [order.Submitted, order.Accepted]:
            # Buy/Sell order submitted/accepted to/by broker - Nothing to do
            self.log('ORDER ACCEPTED/SUBMITTED', dt=order.created.dt)
            self.order = order
            return
        if order.status in [order.Expired]:
            self.log('BUY EXPIRED')
        elif order.status in [order.Completed]:
            if order.isbuy():
                self.log(
                    'BUY EXECUTED, Price: %.2f, Cost: %.2f, Comm %.2f' %
                    (order.executed.price,
                     order.executed.value,
                     order.executed.comm))
            else:  # Sell
                self.log('SELL EXECUTED, Price: %.2f, Cost: %.2f, Comm %.2f' %
                         (order.executed.price,
                          order.executed.value,
                          order.executed.comm))
        # Sentinel to None: new orders allowed
        self.order = None
    def __init__(self):
        # SimpleMovingAverage on main data
        # Equivalent to -> sma = btind.SMA(self.data, period=self.p.smaperiod)
        sma = btind.SMA(period=self.p.smaperiod)
        # CrossOver (1: up, -1: down) close / sma
        self.buysell = btind.CrossOver(self.data.close, sma, plot=True)
        # Sentinel to None: new ordersa allowed
        self.order = None
    def next(self):
        if self.order:
            # An order is pending ... nothing can be done
            return
        # Check if we are in the market
        if self.position:
            # In the maerket - check if it's the time to sell
            if self.buysell < 0:
                self.log('SELL CREATE, %.2f' % self.data.close[0])
                self.sell()
        elif self.buysell > 0:
            if self.p.valid:
                valid = self.data.datetime.date(0) + \
                        datetime.timedelta(days=self.p.valid)
            else:
                valid = None
            # Not in the market and signal to buy
            if self.p.exectype == 'Market':
                self.buy(exectype=bt.Order.Market)  # default if not given
                self.log('BUY CREATE, exectype Market, price %.2f' %
                         self.data.close[0])
            elif self.p.exectype == 'Close':
                self.buy(exectype=bt.Order.Close)
                self.log('BUY CREATE, exectype Close, price %.2f' %
                         self.data.close[0])
            elif self.p.exectype == 'Limit':
                price = self.data.close * (1.0 - self.p.perc1 / 100.0)
                self.buy(exectype=bt.Order.Limit, price=price, valid=valid)
                if self.p.valid:
                    txt = 'BUY CREATE, exectype Limit, price %.2f, valid: %s'
                    self.log(txt % (price, valid.strftime('%Y-%m-%d')))
                else:
                    txt = 'BUY CREATE, exectype Limit, price %.2f'
                    self.log(txt % price)
            elif self.p.exectype == 'Stop':
                price = self.data.close * (1.0 + self.p.perc1 / 100.0)
                self.buy(exectype=bt.Order.Stop, price=price, valid=valid)
                if self.p.valid:
                    txt = 'BUY CREATE, exectype Stop, price %.2f, valid: %s'
                    self.log(txt % (price, valid.strftime('%Y-%m-%d')))
                else:
                    txt = 'BUY CREATE, exectype Stop, price %.2f'
                    self.log(txt % price)
            elif self.p.exectype == 'StopLimit':
                price = self.data.close * (1.0 + self.p.perc1 / 100.0)
                plimit = self.data.close * (1.0 + self.p.perc2 / 100.0)
                self.buy(exectype=bt.Order.StopLimit, price=price, valid=valid,
                         plimit=plimit)
                if self.p.valid:
                    txt = ('BUY CREATE, exectype StopLimit, price %.2f,'
                           ' valid: %s, pricelimit: %.2f')
                    self.log(txt % (price, valid.strftime('%Y-%m-%d'), plimit))
                else:
                    txt = ('BUY CREATE, exectype StopLimit, price %.2f,'
                           ' pricelimit: %.2f')
                    self.log(txt % (price, plimit))
def runstrat():
    args = parse_args()
    cerebro = bt.Cerebro()
    data = getdata(args)
    cerebro.adddata(data)
    cerebro.addstrategy(
        OrderExecutionStrategy,
        exectype=args.exectype,
        perc1=args.perc1,
        perc2=args.perc2,
        valid=args.valid,
        smaperiod=args.smaperiod
    )
    cerebro.run()
    if args.plot:
        cerebro.plot(numfigs=args.numfigs, style=args.plotstyle)
def getdata(args):
    dataformat = dict(
        bt=btfeeds.BacktraderCSVData,
        visualchart=btfeeds.VChartCSVData,
        sierrachart=btfeeds.SierraChartCSVData,
        yahoo=btfeeds.YahooFinanceCSVData,
        yahoo_unreversed=btfeeds.YahooFinanceCSVData
    )
    dfkwargs = dict()
    if args.csvformat == 'yahoo_unreversed':
        dfkwargs['reverse'] = True
    if args.fromdate:
        fromdate = datetime.datetime.strptime(args.fromdate, '%Y-%m-%d')
        dfkwargs['fromdate'] = fromdate
    if args.todate:
        fromdate = datetime.datetime.strptime(args.todate, '%Y-%m-%d')
        dfkwargs['todate'] = todate
    dfkwargs['dataname'] = args.infile
    dfcls = dataformat[args.csvformat]
    return dfcls(**dfkwargs)
def parse_args():
    parser = argparse.ArgumentParser(
        description='Showcase for Order Execution Types')
    parser.add_argument('--infile', '-i', required=False,
                        default='../datas/2006-day-001.txt',
                        help='File to be read in')
    parser.add_argument('--csvformat', '-c', required=False, default='bt',
                        choices=['bt', 'visualchart', 'sierrachart',
                                 'yahoo', 'yahoo_unreversed'],
                        help='CSV Format')
    parser.add_argument('--fromdate', '-f', required=False, default=None,
                        help='Starting date in YYYY-MM-DD format')
    parser.add_argument('--todate', '-t', required=False, default=None,
                        help='Ending date in YYYY-MM-DD format')
    parser.add_argument('--plot', '-p', action='store_false', required=False,
                        help='Plot the read data')
    parser.add_argument('--plotstyle', '-ps', required=False, default='bar',
                        choices=['bar', 'line', 'candle'],
                        help='Plot the read data')
    parser.add_argument('--numfigs', '-n', required=False, default=1,
                        help='Plot using n figures')
    parser.add_argument('--smaperiod', '-s', required=False, default=15,
                        help='Simple Moving Average Period')
    parser.add_argument('--exectype', '-e', required=False, default='Market',
                        help=('Execution Type: Market (default), Close, Limit,'
                              ' Stop, StopLimit'))
    parser.add_argument('--valid', '-v', required=False, default=0, type=int,
                        help='Validity for Limit sample: default 0 days')
    parser.add_argument('--perc1', '-p1', required=False, default=0.0,
                        type=float,
                        help=('%% distance from close price at order creation'
                              ' time for the limit/trigger price in Limit/Stop'
                              ' orders'))
    parser.add_argument('--perc2', '-p2', required=False, default=0.0,
                        type=float,
                        help=('%% distance from close price at order creation'
                              ' time for the limit price in StopLimit orders'))
    return parser.parse_args()
if __name__ == '__main__':
    runstrat()

扩展数据源

原文:www.backtrader.com/blog/posts/2015-08-07-extending-a-datafeed/extending-a-datafeed/

GitHub 上的问题实际上正在推动完成文档部分或帮助我了解 backtrader 是否具有我最初设想的易用性和灵活性,并沿途做出的决定。

在这种情况下是问题#9

最终问题似乎归结为:

  • 最终用户是否可以轻松扩展现有机制,以添加额外信息,以行的形式传递到其他现有价格信息点,如openhigh等?

就我理解的问题,答案是:是的

发帖人似乎有这些要求(来自问题#6):

  • 一个被解析为 CSV 格式的数据源
  • 使用GenericCSVData来加载信息
    这种通用的 CSV 支持是为了响应这个问题#6而开发的
  • 一个额外字段,显然包含需要传递到解析的 CSV 数据中的 P/E 信息

让我们在 CSV 数据源开发和通用 CSV 数据源示例帖子的基础上构建。

步骤:

  • 假设 P/E 信息被设置在被解析的 CSV 数据中
  • 使用GenericCSVData作为基类
  • 将现有线(open/high/low/close/volumen/openinterest)扩展为pe
  • 添加一个参数,让调用者确定 P/E 信息的列位置

结果:

from backtrader.feeds import GenericCSVData
class GenericCSV_PE(GenericCSVData):
    # Add a 'pe' line to the inherited ones from the base class
    lines = ('pe',)
    # openinterest in GenericCSVData has index 7 ... add 1
    # add the parameter to the parameters inherited from the base class
    params = (('pe', 8),)

工作完成了…

稍后,在策略中使用这个数据源时:

import backtrader as bt
....
class MyStrategy(bt.Strategy):
    ...
    def next(self):
        if self.data.close > 2000 and self.data.pe < 12:
            # TORA TORA TORA --- Get off this market
            self.sell(stake=1000000, price=0.01, exectype=Order.Limit)
    ...

绘制额外的 P/E 线

显然,在数据源中没有对该额外线的自动绘图支持。

最好的选择是对该线进行简单移动平均,并在单独的轴上绘制它:

import backtrader as bt
import backtrader.indicators as btind
....
class MyStrategy(bt.Strategy):
    def __init__(self):
        # The indicator autoregisters and will plot even if no obvious
        # reference is kept to it in the class
        btind.SMA(self.data.pe, period=1, subplot=False)
    ...
    def next(self):
        if self.data.close > 2000 and self.data.pe < 12:
            # TORA TORA TORA --- Get off this market
            self.sell(stake=1000000, price=0.01, exectype=Order.Limit)
    ...


BackTrader 中文文档(二十八)(3)https://developer.aliyun.com/article/1505488

相关文章
|
Unix 索引 Python
BackTrader 中文文档(一)(2)
BackTrader 中文文档(一)
592 0
|
存储 算法 C++
BackTrader 中文文档(二十八)(3)
BackTrader 中文文档(二十八)
274 0
|
索引
BackTrader 中文文档(九)(2)
BackTrader 中文文档(九)
409 0
|
机器学习/深度学习 算法 机器人
BackTrader 中文文档(一)(1)
BackTrader 中文文档(一)
1110 0
|
索引 Python
BackTrader 中文文档(十二)(2)
BackTrader 中文文档(十二)
392 0
|
存储 编解码 API
BackTrader 中文文档(四)(1)
BackTrader 中文文档(四)
242 1
|
程序员 Python
BackTrader 中文文档(十三)(4)
BackTrader 中文文档(十三)
180 0
|
存储 编解码 算法
BackTrader 中文文档(十一)(3)
BackTrader 中文文档(十一)
398 0
|
存储 编译器 API
BackTrader 中文文档(十)(1)
BackTrader 中文文档(十)
584 0
|
存储 API 索引
BackTrader 中文文档(十一)(2)
BackTrader 中文文档(十一)
297 0