Backtrader Documentation 1.9.58.122 WJ
Backtrader Documentation 1.9.58.122 WJ
122
backtrader’s documentation
Version-1.9.58.122
Edited By Wilson J
https://www.backtrader.com/docu/index.html
Contents:
目录
backtrader’s documentation ....................................................................................................................................... 1
Introduction ................................................................................................................................................. 2
Installation ............................................................................................................................................. 3
Quickstart ................................................................................................................................................. 4
Platform Concepts ..................................................................................................................................... 50
Operating the platform .............................................................................................................................. 66
Exceptions ............................................................................................................................................... 75
Cerebro ...................................................................................................................................................... 76
Cheat On Open .......................................................................................................................................... 90
Strategy ...................................................................................................................................................... 98
Sizers - Smart Staking ............................................................................................................................... 111
Timers ...................................................................................................................................................... 118
Target Orders ........................................................................................................................................... 139
Strategy with Signals ................................................................................................................................ 152
Broker....................................................................................................................................................... 164
Slippage.................................................................................................................................................... 169
Fillers ........................................................................................................................................................ 173
Orders ...................................................................................................................................................... 175
Order Management and Execution.......................................................................................................... 181
OCO orders............................................................................................................................................... 205
StopTrail(Limit) ......................................................................................................................................... 214
Bracket Orders ......................................................................................................................................... 224
Futures and Spot Compensation ............................................................................................................. 239
Data Feeds ............................................................................................................................................... 244
CSV Data Feed Development ................................................................................................................... 249
Binary Datafeed Development................................................................................................................. 252
Extending a Datafeed ............................................................................................................................... 260
Pandas DataFeed Example ....................................................................................................................... 262
Trading Calendar ...................................................................................................................................... 267
Data Resampling ...................................................................................................................................... 288
Data - Multiple Timeframes ..................................................................................................................... 294
Data - Replay ............................................................................................................................................ 303
Rolling over Futures ................................................................................................................................. 311
Filters ....................................................................................................................................................... 325
1
backtrader’s documentation Version-1.9.58.122
Introduction
Features:
2
backtrader’s documentation Version-1.9.58.122
1. Ease of use
2. Go back to 1
• Create a Strategy
o Decide on potential adjustable parameters
o Instantiate the Indicators you need in the Strategy
o Write down the logic for entering/exiting the market
Or alternatively:
And then
o First:
Inject the Strategy
or
And then:
Let’s hope you, the user, find the platform useful and fun to work with.
Installation
• Python 2.7
• Python 3.2/3.3/3.4/3.5
• pypy/pypy3
It may work with previous versions, but this the one used for
development
Note
4
backtrader’s documentation Version-1.9.58.122
Development takes place under Python 2.7 and sometimes under 3.4. Tests are run
locally with both versions.
Again you may prefer (or only have access to ...) easy_install
First downloading a release or the latest tarball from the github site:
• https://github.com/mementum/backtrader
5
backtrader’s documentation Version-1.9.58.122
https://github.com/mementum/backtrader
And then copy the backtrader package directory to your own project. Under a Unix-
like OS for example:
Remember that you would then need to manually install matplotlib for plotting.
Quickstart
Let’s run through a series of examples (from almost an empty one to a fully
fledged strategy) but not without before roughly explaining 2 basic concepts when
working with backtrader
1. Lines
2. Index 0 Approach
6
backtrader’s documentation Version-1.9.58.122
And the “last” output value is accessed with -1. This in line with
Python conventions for iterables (and a line can be iterated and is
therefore an iterable) where index -1 is used to access the “last”
item of the iterable/array.
As such and being index 0 right after -1, it is used to access the
current moment in line.
With that in mind and if we imagine a Strategy featuring a Simple Moving average
created during initialization:
self.sma = SimpleMovingAverage(.....)
The easiest and simplest way to access the current value of this moving average:
av = self.sma[0]
Following pythonic tradition, the “last” output value is accessed using -1:
previous_value = self.sma[-1]
Of course earlier output values can be accessed with -2, -3, ...
Basic Setup
import backtrader as bt
if __name__ == '__main__':
7
backtrader’s documentation Version-1.9.58.122
cerebro = bt.Cerebro()
cerebro.run()
In this example:
Although it doesn’t seem much, let’s point out something explicitly shown:
This behind the scenes broker instantiation is a constant trait in the platform
to simplify the life of the user. If no broker is set by the user, a default one
is put in place.
And 10K monetary units is a usual value with some brokers to begin with.
In the world of finance, for sure only “losers” start with 10k. Let’s change
the cash and run the example again.
import backtrader as bt
if __name__ == '__main__':
cerebro = bt.Cerebro()
8
backtrader’s documentation Version-1.9.58.122
cerebro.broker.setcash(100000.0)
cerebro.run()
Having cash is fun, but the purpose behind all this is to let an automated
strategy multiply the cash without moving a finger by operating on an asset which
we see as a Data Feed
Ergo ... No Data Feed -> No Fun. Let’s add one to the ever growing example.
if __name__ == '__main__':
# Create a cerebro entity
cerebro = bt.Cerebro()
# Datas are in a subfolder of the samples. Need to find where the script is
# because it could have been called from anywhere
modpath = os.path.dirname(os.path.abspath(sys.argv[0]))
datapath = os.path.join(modpath, '../../datas/orcl-1995-2014.txt')
9
backtrader’s documentation Version-1.9.58.122
Aside from that, the Data Feed is created and added to cerebro.
Note
Yahoo Online sends the CSV data in date descending order, which is not the
standard convention. The reversed=True prameter takes into account that the CSV
10
backtrader’s documentation Version-1.9.58.122
data in the file has already been reversed and has the standard expected date
ascending order.
The cash is in the broker and the Data Feed is there. It seems like risky
business is just around the corner.
Let’s put a Strategy into the equation and print the “Close” price of each day
(bar).
DataSeries (the underlying class in Data Feeds) objects have aliases to access
the well known OHLC (Open High Low Close) daily values. This should ease up the
creation of our printing logic.
# Create a Stratey
class TestStrategy(bt.Strategy):
def __init__(self):
# Keep a reference to the "close" line in the data[0] dataseries
self.dataclose = self.datas[0].close
def next(self):
# Simply log the closing price of the series from the reference
self.log('Close, %.2f' % self.dataclose[0])
11
backtrader’s documentation Version-1.9.58.122
if __name__ == '__main__':
# Create a cerebro entity
cerebro = bt.Cerebro()
# Add a strategy
cerebro.addstrategy(TestStrategy)
# Datas are in a subfolder of the samples. Need to find where the script is
# because it could have been called from anywhere
modpath = os.path.dirname(os.path.abspath(sys.argv[0]))
datapath = os.path.join(modpath, '../../datas/orcl-1995-2014.txt')
12
backtrader’s documentation Version-1.9.58.122
...
...
...
2000-12-26T00:00:00, Close, 29.17
2000-12-27T00:00:00, Close, 28.94
2000-12-28T00:00:00, Close, 29.29
2000-12-29T00:00:00, Close, 27.41
Final Portfolio Value: 100000.00
Someone said the stockmarket was risky business, but it doesn’t seem so.
• Upon __init__ being called the strategy already has a list of datas that
are present in the platform
This is a standard Python list and datas can be accessed in the order they
were inserted.
The first data in the list self.datas[0] is the default data for trading
operations and to keep all strategy elements synchronized (it’s the system
clock)
• If the price has been falling 3 sessions in a row ... BUY BUY BUY!!!
import backtrader as bt
# Create a Stratey
class TestStrategy(bt.Strategy):
def __init__(self):
# Keep a reference to the "close" line in the data[0] dataseries
self.dataclose = self.datas[0].close
def next(self):
# Simply log the closing price of the series from the reference
self.log('Close, %.2f' % self.dataclose[0])
if __name__ == '__main__':
# Create a cerebro entity
cerebro = bt.Cerebro()
# Add a strategy
cerebro.addstrategy(TestStrategy)
# Datas are in a subfolder of the samples. Need to find where the script is
# because it could have been called from anywhere
modpath = os.path.dirname(os.path.abspath(sys.argv[0]))
datapath = os.path.join(modpath, '../../datas/orcl-1995-2014.txt')
dataname=datapath,
# Do not pass values before this date
fromdate=datetime.datetime(2000, 1, 1),
# Do not pass values before this date
todate=datetime.datetime(2000, 12, 31),
# Do not pass values after this date
reverse=False)
15
backtrader’s documentation Version-1.9.58.122
Several “BUY” creation orders were issued, our porftolio value was decremented.
A couple of important things are clearly missing.
• The order was created but it is unknown if it was executed, when and at
what price.
The curious reader may ask how many shares are being bought, what asset is being
bought and how are orders being executed. Where possible (and in this case it is)
the platform fills in the gaps:
• self.datas[0] (the main data aka system clock) is the target asset if no other one is specified
• The stake is provided behind the scenes by a position sizer which uses a fixed stake, being the default “1”.
It will be modified in a later example
• The order is executed “At Market”. The broker (shown in previous examples) executes this using the
opening price of the next bar, because that’s the 1st tick after the current under examination bar.
• The order is executed so far without any commission (more on that later)
After knowing how to enter the market (long), an “exit concept” is needed and
also understanding whether the strategy is in the market.
• Luckily a Strategy object offers access to a position attribute for the default data feed
• Methods buy and sell return the created (not yet executed) order
• Changes in orders’ status will be notified to the strategy via a notify method
• Exit after 5 bars (on the 6th bar) have elapsed for good or for worse
Although we know the data source is a daily one, the strategy makes no
assumption about that.
Note
The next method gets no “bar index” passed and therefore it seems obscure how
to understand when 5 bars may have elapsed, but this has been modeled in pythonic
way: call len on an object and it will tell you the length of its lines. Just
write down (save in a variable) at which length in an operation took place and
see if the current length is 5 bars away.
# Create a Stratey
class TestStrategy(bt.Strategy):
def __init__(self):
# Keep a reference to the "close" line in the data[0] dataseries
self.dataclose = self.datas[0].close
17
backtrader’s documentation Version-1.9.58.122
elif order.issell():
self.log('SELL EXECUTED, %.2f' % order.executed.price)
self.bar_executed = len(self)
def next(self):
# Simply log the closing price of the series from the reference
self.log('Close, %.2f' % self.dataclose[0])
else:
if __name__ == '__main__':
# Create a cerebro entity
cerebro = bt.Cerebro()
# Add a strategy
cerebro.addstrategy(TestStrategy)
# Datas are in a subfolder of the samples. Need to find where the script is
# because it could have been called from anywhere
modpath = os.path.dirname(os.path.abspath(sys.argv[0]))
datapath = os.path.join(modpath, '../../datas/orcl-1995-2014.txt')
19
backtrader’s documentation Version-1.9.58.122
Blistering Barnacles!!! The system made money ... something must be wrong
Let’s add a reasonable 0.1% commision rate per operation (both for buying and
selling ... yes the broker is avid ...)
Being experienced with the platform we want to see the profit or loss after a
buy/sell cycle, with and without commission.
# Create a Stratey
class TestStrategy(bt.Strategy):
def __init__(self):
# Keep a reference to the "close" line in the data[0] dataseries
self.dataclose = self.datas[0].close
21
backtrader’s documentation Version-1.9.58.122
order.executed.comm))
self.buyprice = order.executed.price
self.buycomm = order.executed.comm
else: # Sell
self.log('SELL EXECUTED, Price: %.2f, Cost: %.2f, Comm %.2f' %
(order.executed.price,
order.executed.value,
order.executed.comm))
self.bar_executed = len(self)
self.order = None
def next(self):
# Simply log the closing price of the series from the reference
self.log('Close, %.2f' % self.dataclose[0])
else:
if __name__ == '__main__':
# Create a cerebro entity
cerebro = bt.Cerebro()
# Add a strategy
cerebro.addstrategy(TestStrategy)
# Datas are in a subfolder of the samples. Need to find where the script is
# because it could have been called from anywhere
modpath = os.path.dirname(os.path.abspath(sys.argv[0]))
datapath = os.path.join(modpath, '../../datas/orcl-1995-2014.txt')
cerebro.broker.setcommission(commission=0.001)
24
backtrader’s documentation Version-1.9.58.122
Before moving on, let’s notice something by filtering the “OPERATION PROFIT”
lines:
15.83
And obviously 15.83 is not 16.98. There is no error whatsoever. The “NET”
profit of 15.83 is already cash in the bag.
25
backtrader’s documentation Version-1.9.58.122
The “Final Portfolio Value” calculated by the broker takes into account the
“Close” price on 2000-12-29. The actual execution price would have been set on
the next trading day which happened to be 2001-01-02. Extending the Data Feed”
to take into account this day the output is:
Now adding the previous NET profit to the completed operation’s net profit:
It would a bit unpractical to hardcode some of the values in the strategy and
have no chance to change them easily. Parameters come in handy to help.
Being this a standard Python tuple with some tuples inside it, the following may
look more appealling to some:
params = (
('myparam', 27),
('exitbars', 5),
)
With either formatting parametrization of the strategy is allowed when adding the
strategy to the Cerebro engine:
# Add a strategy
cerebro.addstrategy(TestStrategy, myparam=20, exitbars=7)
26
backtrader’s documentation Version-1.9.58.122
Note
The setsizing method below is deprecated. This content is kept here for anyone
looking at old samples of the sources. The sources have been update to use:
cerebro.addsizer(bt.sizers.FixedSize, stake=10)``
Using the parameters in the strategy is easy, as they are stored in a “params”
attribute. If we for example want to set the stake fix, we can pass the stake
parameter to the position sizer like this durint __init__:
We could have also called buy and sell with a stake parameter and
self.params.stake as the value.
# Create a Stratey
class TestStrategy(bt.Strategy):
params = (
('exitbars', 5),
)
27
backtrader’s documentation Version-1.9.58.122
dt = dt or self.datas[0].datetime.date(0)
print('%s, %s' % (dt.isoformat(), txt))
def __init__(self):
# Keep a reference to the "close" line in the data[0] dataseries
self.dataclose = self.datas[0].close
self.buyprice = order.executed.price
self.buycomm = order.executed.comm
else: # Sell
self.log('SELL EXECUTED, Price: %.2f, Cost: %.2f, Comm %.2f' %
(order.executed.price,
order.executed.value,
order.executed.comm))
self.bar_executed = len(self)
self.order = None
return
def next(self):
# Simply log the closing price of the series from the reference
self.log('Close, %.2f' % self.dataclose[0])
else:
if __name__ == '__main__':
# Create a cerebro entity
cerebro = bt.Cerebro()
# Add a strategy
29
backtrader’s documentation Version-1.9.58.122
cerebro.addstrategy(TestStrategy)
# Datas are in a subfolder of the samples. Need to find where the script is
# because it could have been called from anywhere
modpath = os.path.dirname(os.path.abspath(sys.argv[0]))
datapath = os.path.join(modpath, '../../datas/orcl-1995-2014.txt')
30
backtrader’s documentation Version-1.9.58.122
In order to see the difference, the print outputs have also been extended to show
the execution size.
Having multiplied the stake by 10, the obvious has happened: the profit and loss
has been multiplied by 10. Instead of 16.98, the surplus is now 169.80
Adding an indicator
Having heard of indicators, the next thing anyone would add to the strategy is
one of them. For sure they must be much better than a simple “3 lower closes”
strategy.
Inspired in one of the examples from PyAlgoTrade a strategy using a Simple Moving
Average.
Most of the existing code can be kept in place. Let’s add the average during
__init__ and keep a reference to it:
self.sma = bt.indicators.MovingAverageSimple(self.datas[0],
period=self.params.maperiod)
31
backtrader’s documentation Version-1.9.58.122
And of course the logic to enter and exit the market will rely on the Average
values. Look in the code for the logic.
Note
The starting cash will be 1000 monetary units to be in line with the PyAlgoTrade
example and no commission will be applied
# Create a Stratey
class TestStrategy(bt.Strategy):
params = (
('maperiod', 15),
)
def __init__(self):
# Keep a reference to the "close" line in the data[0] dataseries
self.dataclose = self.datas[0].close
self.buyprice = order.executed.price
self.buycomm = order.executed.comm
else: # Sell
self.log('SELL EXECUTED, Price: %.2f, Cost: %.2f, Comm %.2f' %
(order.executed.price,
order.executed.value,
order.executed.comm))
self.bar_executed = len(self)
self.order = None
def next(self):
# Simply log the closing price of the series from the reference
self.log('Close, %.2f' % self.dataclose[0])
if not self.position:
else:
if __name__ == '__main__':
# Create a cerebro entity
cerebro = bt.Cerebro()
# Add a strategy
cerebro.addstrategy(TestStrategy)
# Datas are in a subfolder of the samples. Need to find where the script is
# because it could have been called from anywhere
modpath = os.path.dirname(os.path.abspath(sys.argv[0]))
datapath = os.path.join(modpath, '../../datas/orcl-1995-2014.txt')
cerebro.adddata(data)
Now, before skipping to the next section LOOK CAREFULLY to the first date which
is shown in the log:
• It’ no longer 2000-01-03, the first trading day in the year 2K.
The missing days are not missing. The platform has adapted to the new
circumstances:
The backtrader platform assumes that the Strategy has the indicator in place for
a good reason, to use it in the decision making process. And it makes no sense
to try to make decisions if the indicator is not yet ready and producing values.
• next will be 1st called when all indicators have already reached the minimum needed period to produce a
value
• In the example there is a single indicator, but the strategy could have any number of them.
In the name of the King!!! A winning system turned into a losing one ... and that
with no commission. It may well be that simply adding an indicator is not the
universal panacea.
Note
36
backtrader’s documentation Version-1.9.58.122
The same logic and data with PyAlgoTrade yields a slightly different result
(slightly off). Looking at the entire printout reveals that some operations are
not exactly the same. Being the culprit again the usual suspect: rounding.
PyAlgoTrade does not round the datafeed values when applying the divided
“adjusted close” to the data feed values.
The Yahoo Data Feed provided by backtrader rounds the values down to 2 decimals
after applying the adjusted close. Upon printing the values everything seems the
same, but it’s obvious that sometimes that 5th place decimal plays a role.
Note
The Yahoo Data Feed (starting with version 1.8.11.99 allows to specify if
rounding has to happen and how many decimals)
Note
Once again defaults for plotting are there to assist the platform user. Plotting
is incredibly a 1 line operation:
cerebro.plot()
Being the location for sure after cerebro.run() has been called.
• A 2nd MovingAverage (Exponential) will be added. The defaults will plot it (just like the 1st) with the data.
• A 3rd MovingAverage (Weighted) will be added. Customized to plot in an own plot (even if not sensible)
• A Stochastic (Slow) will be added. No change to the defaults.
• A MACD will be added. No change to the defaults.
• A RSI will be added. No change to the defaults.
37
backtrader’s documentation Version-1.9.58.122
• A MovingAverage (Simple) will be applied to the RSI. No change to the defaults (it will be plotted with the
RSI)
• An AverageTrueRange will be added. Changed defaults to avoid it being plotted.
Note
Even if indicators are not explicitly added to a member variable of the strategy
(like self.sma = MovingAverageSimple...), they will autoregister with the
strategy and will influence the minimum period for next and will be part of the
plotting.
In the example only RSI is added to a temporary variable rsi with the only
intention to create a MovingAverageSmoothed on it.
# Create a Stratey
class TestStrategy(bt.Strategy):
params = (
('maperiod', 15),
)
def __init__(self):
# Keep a reference to the "close" line in the data[0] dataseries
self.dataclose = self.datas[0].close
self.buyprice = order.executed.price
self.buycomm = order.executed.comm
39
backtrader’s documentation Version-1.9.58.122
else: # Sell
self.log('SELL EXECUTED, Price: %.2f, Cost: %.2f, Comm %.2f' %
(order.executed.price,
order.executed.value,
order.executed.comm))
self.bar_executed = len(self)
def next(self):
# Simply log the closing price of the series from the reference
self.log('Close, %.2f' % self.dataclose[0])
else:
if __name__ == '__main__':
# Create a cerebro entity
cerebro = bt.Cerebro()
# Add a strategy
cerebro.addstrategy(TestStrategy)
# Datas are in a subfolder of the samples. Need to find where the script is
# because it could have been called from anywhere
modpath = os.path.dirname(os.path.abspath(sys.argv[0]))
datapath = os.path.join(modpath, '../../datas/orcl-1995-2014.txt')
41
backtrader’s documentation Version-1.9.58.122
Note
As explained before, the platform will first call next when all indicators are
ready to produce a value. In this plotting example (very clear in the chart) the
MACD is the last indicator to be fully ready (all 3 lines producing an output).
The 1st BUY order is no longer scheduled during Jan 2000 but close to the end of
Feb 2000.
The chart:
42
backtrader’s documentation Version-1.9.58.122
Let’s Optimize
Many trading books say each market and each traded stock (or commodity or ..)
have different rythms. That there is no such thing as a one size fits all.
Before the plotting sample, when the strategy started using an indicator the
period default value was 15 bars. It’s a strategy parameter and this can be used
in an optimization to change the value of the parameter and see which one better
fits the market.
Note
There is plenty of literature about Optimization and associated pros and cons.
But the advice will always point in the same direction: do not overoptimize. If a
trading idea is not sound, optimizing may end producing a positive result which
is only valid for the backtested dataset.
43
backtrader’s documentation Version-1.9.58.122
The sample is modified to optimize the period of the Simple Moving Average. For
the sake of clarity any output with regards to Buy/Sell orders has been removed
# Create a Stratey
class TestStrategy(bt.Strategy):
params = (
('maperiod', 15),
('printlog', False),
)
def __init__(self):
# Keep a reference to the "close" line in the data[0] dataseries
self.dataclose = self.datas[0].close
44
backtrader’s documentation Version-1.9.58.122
self.buyprice = order.executed.price
self.buycomm = order.executed.comm
else: # Sell
self.log('SELL EXECUTED, Price: %.2f, Cost: %.2f, Comm %.2f' %
(order.executed.price,
order.executed.value,
order.executed.comm))
self.bar_executed = len(self)
def next(self):
# Simply log the closing price of the series from the reference
self.log('Close, %.2f' % self.dataclose[0])
else:
def stop(self):
self.log('(MA Period %2d) Ending Value %.2f' %
(self.params.maperiod, self.broker.getvalue()), doprint=True)
if __name__ == '__main__':
# Create a cerebro entity
cerebro = bt.Cerebro()
# Add a strategy
strats = cerebro.optstrategy(
TestStrategy,
maperiod=range(10, 31))
# Datas are in a subfolder of the samples. Need to find where the script is
# because it could have been called from anywhere
modpath = os.path.dirname(os.path.abspath(sys.argv[0]))
datapath = os.path.join(modpath, '../../datas/orcl-1995-2014.txt')
One of the “Strategy” hooks is added, the stop method, which will be called
when the data has been exhausted and backtesting is over. It’s used to print the
final net value of the portfolio in the broker (it was done in Cerebro
previously)
The system will execute the strategy for each value of the range. The following
will be output:
Results:
And the winning period for this strategy and the given data set is:
Note
The extra indicators from the plotting example have been removed and the start of
operations is only influenced by the Simple Moving Average which is being
optimized. Hence the slightly different results for period 15
Conclusion
The incremental samples have shown how to go from a barebones script to a fully
working trading system which even plots the results and can be optimized.
• Sizers
48
backtrader’s documentation Version-1.9.58.122
To ensure all the above items can be fully utilized the documentation provides an
insight into them (and other topics)
Look in the table of contents and keep on reading ... and developing.
Best of luck
Platform Concepts
Before Starting
import backtrader as bt
import backtrader.indicators as btind
import backtrader.feeds as btfeeds
Note
import backtrader as bt
And then:
thefeed = bt.feeds.OneOfTheFeeds(...)
theind = bt.indicators.SimpleMovingAverage(...)
The basis of the work with the platform will be done with Strategies. And these
will get passed Data Feeds The platform end user does not need to care about
receiving them:
Data Feeds are automagically provided member variables to the strategy in the form of an array and shortcuts to
the array positions
Quick preview of a Strategy derived class declaration and running the platform:
class MyStrategy(bt.Strategy):
49
backtrader’s documentation Version-1.9.58.122
params = dict(period=20)
def __init__(self):
...
cerebro = bt.Cerebro()
...
data = btfeeds.MyFeed(...)
cerebro.adddata(data)
...
cerebro.addstrategy(MyStrategy, period=30)
...
• No *args or **kwargs are being received by the strategy’s __init__ method (they may still be used)
• A member variable self.datas exists which is array/list/iterable holding at least one item (hopefully or else
an exception will be raised)
So it is. Data Feeds get added to the platform and they will show up inside the
strategy in the sequential order in which they were added to the system.
Note
This also applies to Indicators, should the end user develop his own custom
Indicator or when having a look at the source code for some of the existing
Indicator Reference
The self.datas array items can be directly accessed with additional automatic
member variables:
50
backtrader’s documentation Version-1.9.58.122
class MyStrategy(bt.Strategy):
params = dict(period=20)
def __init__(self):
...
class MyStrategy(bt.Strategy):
params = dict(period=20)
def __init__(self):
sma = btind.SimpleMovingAverage(period=self.params.period)
...
Not only Data Feeds are data and can be passed around. Indicators and results of
Operations are also data.
class MyStrategy(bt.Strategy):
params = dict(period1=20, period2=25, period3=10, period4)
def __init__(self):
...
Basically everything gets transformed into an object which can be used as a data
feed once it has been operated upon.
Parameters
Mostly every other class in the platform supports the notion of parameters.
• Parameters along with default values are declared as a class attribute (tuple of tuples or dict-like object)
• Keywords args (**kwargs) are scanned for matching parameters, removing them from **kwargs if found
and assigning the value to the corresponding parameter
• And parameters can be finally used in instances of the class by accessing the member variable self.params
(shorthand: self.p)
The previous quick Strategy preview already contains a parameters example, but
for the sake of redundancy, again, focusing only on the parameters. Using tuples:
class MyStrategy(bt.Strategy):
params = (('period', 20),)
def __init__(self):
sma = btind.SimpleMovingAverage(self.data, period=self.p.period)
class MyStrategy(bt.Strategy):
52
backtrader’s documentation Version-1.9.58.122
params = dict(period=20)
def __init__(self):
sma = btind.SimpleMovingAverage(self.data, period=self.p.period)
Lines
Again mostly every other object in the platform is a Lines enabled object. From a
end user point of view this means:
• It can hold one of more line series, being a line series an array of values were the values put together in a
chart they would form a line.
A good example of a line (or lineseries) is the line formed by the closing prices
of a stock. This is actually a well-known chart representation of the evolution
of prices (known as Line on Close)
Regular use of the platform is only concerned with accessing lines. The previous
mini-strategy example, lightly extended, comes in handy again:
class MyStrategy(bt.Strategy):
params = dict(period=20)
def __init__(self):
def next(self):
if self.movav.lines.sma[0] > self.data.lines.close[0]:
print('Simple Moving Average is greater than the closing price')
Note
It should be obvious from this, that lines are named. They can also be accessed
sequentially following the declaration order, but this should only be used in
Indicator development
53
backtrader’s documentation Version-1.9.58.122
And both lines, namely close and sma can be queried for a point (index 0) to
compare the values.
But the notation doesn’t make as clear as the previous one if lines are
actually being accessed.
Note
Setting/Assigning the lines with these two later notations is not supported
Lines declaration
If an Indicator is being developed, the lines which the indicator has must be
declared.
Just as with params this takes place as a class attribute this time ONLY as a
tuple. Dictionaries are not supported because they do not store things following
insertion order.
class SimpleMovingAverage(Indicator):
lines = ('sma',)
...
Note
The comma following the declaration is needed in tuples if you pass a single
string to the tuple or else each letter in the string would be interpreted as an
item to be added to the tuple. Possibly one of the few spots where Python’s
syntax got it wrong.
54
backtrader’s documentation Version-1.9.58.122
As seen in the previous example this declaration creates a sma line in the
Indicator that can be later accessed in the Strategy’s logic (and possibly by
other indicators to create more complex indicators)
Had more lines been defined they would be accessed with index 1, 2, and higher.
Inside objects which are receiving datas feeds the lines below these data feeds
can also be quickly accessed by number:
Inside data feeds the lines can also be accessed omitting the lines. This makes
it more natural to work with thinks like close prices.
For example:
data = btfeeds.BacktraderCSVData(dataname='mydata.csv')
...
class MyStrategy(bt.Strategy):
...
def next(self):
55
backtrader’s documentation Version-1.9.58.122
Which seems more natural than the also valid: if self.data.lines.close[0] >
30.0:. The same doesn’t apply to Indicators with the reasoning being:
• An Indicator could have an attribute close which holds an intermediate calculation, which is later
delivered to the actual lines also named close
In the case of Data Feeds, no calculation takes place, because it is only a data
source.
Lines len
Lines have a set of points and grow dynamically during execution, therefore the
length can be measured at any time by invoking the standard Python len function.
• Data Feeds
• Strategies
• Indicators
• Method buflen
The method returns the actual number of bars the Data Feed has available.
If both return the same value, either no data has been preloaded or the
processing of bars has consumed all preloaded bars (and unless the system is
connected to a live feed, this will mean the end of processing)
56
backtrader’s documentation Version-1.9.58.122
Params inheritance
Lines Inheritance
Indexing: 0 and -1
Lines as seen before are line series and have a set of points that conform a line
when drawn together (like when joining all closing prices together along a time
axis)
To access those points in regular code, the choice has been to use a 0 based
approach for the current get/set instant.
From the previous quick strategy example where the next method was briefly seen:
def next(self):
if self.movav.lines.sma[0] > self.data.lines.close[0]:
print('Simple Moving Average is greater than the closing price')
The logic is getting the current value of the moving average and the current
closing price by applying index 0.
Note
Actually for index 0 and when applying logic/arithmetic operators the comparison
can be made directly as in:
57
backtrader’s documentation Version-1.9.58.122
def next(self):
self.line[0] = math.fsum(self.data.get(0, size=self.p.period)) / self.p.period
Accessing previous set points has been modeled following the definition Python
makes for -1 when accessing an array/iterable
The platform consider the last set item (before the current live get/set point)
to be -1.
def next(self):
if self.data.close[0] > self.data.close[-1]:
print('Closing price is higher today')
Of course and logically, prices set before -1 will be accessed with -2, -3, ....
Slicing
backtrader doesn’t support slicing for lines objects and this is a design
decision following the [0] and [-1] indexing scheme. With regular indexable
Python objects you would do things like:
But remember that with the choice for 0 ... it is actually the currently
delivered value, there is nothing after it. Also:
Again ... 0 is the current value and -1 is the latest (previous) delivered value.
That’s why a slice from 0 -> -1 makes no sense in the backtrader ecosystem.
58
backtrader’s documentation Version-1.9.58.122
or:
or:
myslice = self.my_sma[-3:-1] # from last value backwards to the 3rd last value
Getting a slice
An array with the latest values can still be gotten. The syntax:
That would have returned an arry with 1 value (size=1) with the current moment 0
as the staring point to look backwards.
To get 10 values from the current point in time (i.e.: the last 10 values):
Of course the array has the ordering you would expect. The leftmost value is the
oldest one and the rightmost value is the most current (it is a regular python
array and not a lines object)
The [] operator syntax is there to extract individual values during the next
logic phase. Lines objects support an additional notation to address values
through a delayed lines object during the __init__ phase.
Let’s say that the interest in the logic is to compare the previous close value
to the actual value of a simple moving average. Rather than doing it manually in
each next iteration a pre-canned lines object can be generated:
class MyStrategy(bt.Strategy):
params = dict(period=20)
59
backtrader’s documentation Version-1.9.58.122
def __init__(self):
def next(self):
if self.cmpval[0]:
print('Previous close is higher than the moving average')
Lines Coupling
The operator () can be used as shown above with delay value to provide a delayed
version of a lines object.
If the syntax is used WITHOUT providing a delay value, then a LinesCoupler lines
object is returned. This is meant to establish a coupling between indicators that
operate on datas with different timeframes.
Data Feeds with different timeframes have different lengths, and the indicators
operating on them replicate the length of the data. Example:
The reader could imagine a date comparison taking place in the background to find
out a day - week correspondence, but:
They know nothing about the environment, just that if the data provides
enough values, a calculation can take place.
class MyStrategy(bt.Strategy):
params = dict(period=20)
def __init__(self):
def next(self):
if self.buysig[0]:
print('daily sma is greater than weekly sma1')
Here the larger timeframe indicator, sma1 is coupled to the daily timeframe with
sma1(). This returns an object which is compatible with the larger numbers of
bars of sma0 and copies the values produced by sma1, effectively spreading the 52
weekly bars in 250 daily bars
In order to achieve the “ease of use” goal the platform allows (within the
constraints of Python) the use of operators. And to further enhance this goal ,
the use of operators has been broken in two stages.
An example has already been seen even if not explicitly meant for this. During
the initialization phase (__init__ method) of objects like Indicators and
Strategies, operators create objects that can be operated upon, assigned or kept
as reference for later using during the evaluation phase of the Strategy’s
logic.
The code inside the SimpleMovingAverage indicator __init__ could look like:
def __init__(self):
# Sum N period values - datasum is now a *Lines* object
# that when queried with the operator [] and index 0
61
backtrader’s documentation Version-1.9.58.122
av = datasum / self.params.period
self.line.sma = av
class MyStrategy(bt.Strategy):
def __init__(self):
After the above operations have taken place, sell_sig is a Lines object which can
be later used in the logic of the Strategy, indicating if the conditions are met
or not.
62
backtrader’s documentation Version-1.9.58.122
Let’s first remember that a strategy has a next method which is called for every
bar the system processes. This is where operators are actually in the stage 2
mode. Building on the previous example:
class MyStrategy(bt.Strategy):
def __init__(self):
def next(self):
63
backtrader’s documentation Version-1.9.58.122
Not a very useful strategy, just an example. During Stage 2 operators return the
expected values (boolean if testing for truth and floats if comparing them to
floats) and also arithmetic operations do.
Note
Notice that comparisons are actually not using the [] operator. This is meant to
further simplify things.
if self.sma > 30.0: ... compares self.sma[0] to 30.0 (1st line and current value)
Python will not allow overriding everything and thus some functions are provided
to cope with the cases.
Note
Only meant to be used during Stage 1, to create objects which later provide
values.
Operators:
Logic Control:
• if -> If
Functions:
class MyStrategy(bt.Strategy):
def __init__(self):
def next(self):
if self.buysig[0]:
pass # do something here
It is obvious that if the sma1 is higher than the high, it must be higher than
the close. But the point is illustrating the use of bt.And.
Using bt.If:
class MyStrategy(bt.Strategy):
def __init__(self):
Breakdown:
65
backtrader’s documentation Version-1.9.58.122
• The generated bt.If Lines object is then fed to a 2nd SMA which will
sometimes use the low prices and sometimes the high prices for the
calculation
Those functions take also numeric values. The same example with a modification:
class MyStrategy(bt.Strategy):
def __init__(self):
Now the 2nd moving average uses either 30.0 or the high prices to perform the
calculation, depending on the logic status of sma vs close
Note
Line Iterators
To engage into operations, the plaftorm uses the notion of line iterators. They
have been loosely modeled after Python’s iterators but have actually nothing to
do with them.
The key to iteration, just like with regular Python iterators, is:
It will be called for each iteration. The datas array which the line
iterator has and serve as basis for logic/calculations will have already
been moved to the next index by the platform (barring data replay)
66
backtrader’s documentation Version-1.9.58.122
Called when the minimum period for the line iterator has been met. A bit
more on this below.
But because they are not regular iterators, two additional methods exist:
• prenext
Called before the minimum period for the line iterator` has been met.
• nextstart
Called exactly ONCE when the minimum period for the line iterator` has been
met.
The default behavior is to forward the call to next, but can of course be
overriden if needed.
To speed up operations, Indicators support a batch operation mode which has been
termed as runonce. It is not strictly needed (a next method suffices) but it
greatly reduces time.
The runonce methods rules void the get/set point with index 0 and relies on
direct access to the underlying arrays holding the data and being passed the
right indices for each state.
Called when the minimum period has been met. The internal array must be
processed between start and end which are zero based from the start of the
internal array
Called exactly ONCE when the minimum period has been met.
The default behavior is to forward the call to once, but can of course be
overriden if needed.
67
backtrader’s documentation Version-1.9.58.122
Minimum Period
A picture is worth a thousand words and in this case possibly an example too. A
SimpleMovingAverage is capable of explaining it:
class SimpleMovingAverage(Indicator):
lines = ('sma',)
params = dict(period=20)
def __init__(self):
... # Not relevant for the explanation
def prenext(self):
print('prenext:: current period:', len(self))
def nextstart(self):
print('nextstart:: current period:', len(self))
# emulate default behavior ... call next
self.next()
def next(self):
print('next:: current period:', len(self))
Briefly explained:
• Assuming the data passed to the moving average is a standard data feed its default period is 1 that is: the
data feed produces a bar with no initial delay.
• Then the “period=25” instantiated moving average would have its methods called as follows:
o prenext 24 times
o nextstart 1 time (in turn calling next)
o next n additional times until the data feed has been exhausted
The platform is calling next when the system has already processed 44 bars.
The minimum period has been automatically adjusted to the incoming data.
• Only when the automatically calculated minimum period has been reached will next be called (barring the
initial hook call to nextstart)
Note
The same rules apply to preonce, oncestart and once for the runonce batch
operation mode
Note
The minimum period behavior can be manipulated although it’s not recommended.
Should it be wished used the setminperiod(minperiod) method in either Strategies
or Indicators
Up and Running
• A Data feed
• A Strategy (actually a class derived from Strategy)
• A Cerebro (brain in Spanish)
Data Feeds
These objects, obviously, provide the data which will be backtested by applying
calculations (direct and/or with Indicators)
The platform makes no assumption about the content of the data feed such as
timeframe and compression. Those values, together with a name, can be supplied
for informational purposes and advance operations like Data Feed Resampling
(turning a for example a 5 minute Data Feed into a Daily Data Feed)
import backtrader as bt
import backtrader.feeds as btfeeds
...
datapath = 'path/to/your/yahoo/data.csv'
data = btfeeds.YahooFinanceCSVData(
dataname=datapath,
reversed=True)
The optional reversed parameter for Yahoo is shown, because the CSV files
directly downloaded from Yahoo start with the latest date, rather than with the
oldest.
If your data spans a large time range, the actual loaded data can be limited as
follows:
data = btfeeds.YahooFinanceCSVData(
dataname=datapath,
reversed=True
fromdate=datetime.datetime(2014, 1, 1),
todate=datetime.datetime(2014, 12, 31))
Both the fromdate and the todate will be included if present in the data feed.
data = btfeeds.YahooFinanceCSVData(
dataname=datapath,
reversed=True
fromdate=datetime.datetime(2014, 1, 1),
todate=datetime.datetime(2014, 12, 31)
70
backtrader’s documentation Version-1.9.58.122
timeframe=bt.TimeFrame.Days,
compression=1,
name='Yahoo'
)
Note
Before going on and for a more simplified approach, please check the Signals
section of the documentation if subclassing a strategy is not wished.
The goal of anyone using the platform is backtesting the data and this is done
inside a Strategy (derived class).
• __init__
• next
The next method is later called to apply the logic for each and every bar of the
data.
Note
If data feeds of different timeframes (and thus different bar counts) are passed
the next method will be called for the master data (the 1st one passed to
cerebro, see below) which must be the the data with the smaller timeframe
Note
If the Data Replay functionality is used, the next method will be called several
time for the same bar as the development of the bar is replayed.
class MyStrategy(bt.Strategy):
def __init__(self):
71
backtrader’s documentation Version-1.9.58.122
def next(self):
Strategies have other methods (or hook points) which can be overriden:
class MyStrategy(bt.Strategy):
def __init__(self):
def next(self):
def start(self):
print('Backtesting is about to start')
def stop(self):
print('Backtesting is finished')
The start and stop methods should be self-explanatory. As expected and following
the text in the print function, the notify_order method will be called when the
strategy needs a notification. Use case:
72
backtrader’s documentation Version-1.9.58.122
It can for example be used to ensure that no new orders are submitted if an
order is still pending.
The QuickStart guide has a complete and functional example of order management in
the notify_order method.
Use the underlying broker and sizer to send the broker a buy/sell order
The same could be done by manually creating an Order and passing it over to
the broker. But the platform is about making it easy for those using it.
close will get the current market position and close it immediately.
These allow setting/getting the underlying stake Sizer. The same logic can
be checked against Sizers which provide different stakes for the same
situation (fixed size, proportional to capital, exponential)
There is plenty of literature but Van K. Tharp has excellent books on the
subject.
A Strategy is a Lines object and these support parameters, which are collected
using the standard Python kwargs argument:
class MyStrategy(bt.Strategy):
def __init__(self):
self.sma = btind.SimpleMovingAverage(self.data,
period=self.params.period)
73
backtrader’s documentation Version-1.9.58.122
...
...
A Cerebro
Once Data Feeds are available and the Strategy has been defined, a Cerebro
instance is what brings everything together and execute the actions.
Instantiating one is easy:
cerebro = bt.Cerebro()
All indicators must support the runonce mode for full speed. The ones
included in the platform do.
Since a Data feed is already available and a Strategy too (created earlier) the
standard way to put it all together and get it up and running is:
cerebro.adddata(data)
cerebro.addstrategy(MyStrategy, period=25)
cerebro.run()
74
backtrader’s documentation Version-1.9.58.122
The user may add as many Strategies and Data Feeds as wished. How Strategies
communicate with each other to achieve coordination (if wished be) is not
enforced/restricted by the platform.
A custom broker can be set if wished. The actual broker instance can also
be accesed
o numfigs=1
If the plot is too dense it may be broken down into several plots
o plotter=None
• Optimization of strategies.
75
backtrader’s documentation Version-1.9.58.122
The method optstrategy has the same signature as addstrategy but does extra
housekeeping to ensure optimization runs as expected. A strategy could be
expecting a range as a normal parameter for a strategy and addstrategy will
make no assumptions about the passed parameter.
If a more complex strategy is developed with extra parameters they can all
be passed to optstrategy. Parameters which must not undergo optimization
can be passed directly without the end user having to create a dummy
iterable of just one value. Example:
The optstrategy method sees factor and creates (a needed) dummy iterable in
the background for factor which has a single element (in the example 3.5)
Note
76
backtrader’s documentation Version-1.9.58.122
Exceptions
One of the design goals was to quit as early as possible and let the users have
full transparency of what was happening with errors. With the goal to force
oneself to have code that would break on exceptions and forced revisiting the
affected part.
But the time has come and some exceptions may slowly get added to the platform.
Hierarchy
The base class for all exceptions is BacktraderError (which is a direct subclass
of Exception)
Location
Exceptions
StrategySkipError
Requests the platform to skip this strategy for backtesting. To be raised during
the initialization (__init__) phase of the instance
77
backtrader’s documentation Version-1.9.58.122
Cerebro
1. Gathering all inputs (Data Feeds), actors (Stratgegies), spectators (Observers), critics (Analyzers) and
documenters (Writers) ensuring the show still goes on at any moment.
2. Execute the backtesting/or live data feeding/trading
3. Returning the results
4. Giving access to the plotting facilities
Gathering input
Some **kwargs to control execution are supported, see the reference (the
same arguments can be applied later to the run method)
data = bt.BacktraderCSVData(dataname='mypath.days',
timeframe=bt.TimeFrame.Days)
cerebro.adddata(data)
Resampling and Replaying a data is possible and follows the same pattern:
data = bt.BacktraderCSVData(dataname='mypath.min',
timeframe=bt.TimeFrame.Minutes)
cerebro.resampledata(data, timeframe=bt.TimeFrame.Days)
or:
data = bt.BacktraderCSVData(dataname='mypath.min',
timeframe=bt.TimeFrame.Minutes)
cerebro.replaydatadata(data, timeframe=bt.TimeFrame.Days)
The system can accept any number of data feeds, including mixing regular
data with resampled and/or replayed data. Of course some of this
combinationns will for sure make no sense and a restriction apply in order
78
backtrader’s documentation Version-1.9.58.122
4. Add Strategies
Unlike the datas feeds which are already an instance of a class, cerebro
takes directly the Strategy class and the arguments to pass to it. The
rationale behind: in an optimization scenario the class will be
instantiated several times and passed different arguments
Which will run MyStrategy 10 times with myparam1 taking values from 10 to
19 (remember ranges in Python are half-open and 20 will not be reached)
5. Other elements
There are some other elements which can be added to enhance the backtesting
experience. See the appropriate sections for it. The methods are:
o addwriter
o addanalyzer
o addobserver (or addobservermulti)
6. Changing the broker
Cerebro will use the default broker in backtrader, but this can be
overriden:
broker = MyBroker()
cerebro.broker = broker # property using getbroker/setbroker methods
7. Receive notifications
If data feeds and/or brokers send notifications (or a store provider which
creates them) they will be received through the Cerebro.notify_store
method. There are three (3) ways to work with these notifications
79
backtrader’s documentation Version-1.9.58.122
There is a single method to do it, but it supports several options (which can be
also specified when instantiating) to decide how to run:
result = cerebro.run(**kwargs)
Standard Observers
80
backtrader’s documentation Version-1.9.58.122
result = cerebro.run(**kwargs)
The format of result returned by run will vary depending on whether optimization
is used (a strategy was added with optstrategy):
result will be a list of list. Each internal list will contain the
strategies after each optimization run
Note
The default behavior for optimization was changed to only return the analyzers
present in the system, to make message passing across computer cores lighter.
If the complete set of strategies is wished as return value, set the parameter
optreturn to False
cerebro.plot()
Backtesting logic
The 1st data inserted into the system is the datamaster and the system will
wait for it to deliver a tick
The other data feeds are, more or less, slaves to the datamaster and:
o If the next tick to deliver is newer (datetime-wise) than the one delivered by the datamaster it
will not be delivered
o May return without delivering a new tick for a number of reasons
The logic was designed to easily synchronize multiple data feeds and data
feeds with different timeframes
3. Notify the strategy about queued broker notifications of orders, trades and
cash/value
4. Tell the broker to accept queued orders and execute the pending orders with
the new data
5. Call the strategies’ next method to let the strategy evaluate the new data
(and maybe issue orders which are queued in the broker)
Note
In step 1 above when the data feeds deliver the new set of bars, those bars are
closed. This means the data has already happened.
As such, orders issued by the strategy in step 4 cannot be executed with the data
from step 1.
82
backtrader’s documentation Version-1.9.58.122
This means that orders will be executed with the concept of x + 1. Where x is the
bar moment at which the order was executed and x + 1 the next one, which is the
earliest moment in time for a possible order execution
Reference
class backtrader.Cerebro
Params:
Whether to preload the different data feeds passed to cerebro for the
Strategies
If no data has reported itself as live (via the data’s islive method
but the end user still want to run in live mode, this parameter can
be set to true
o False: use the modern behavior in which the buy / sell signals are plotted below / above
the low / high prices respectively to avoid cluttering the plot
o True: use the deprecated behavior in which the buy / sell signals are plotted where the
average price of the order executions for the given moment in time is. This will of course
be on top of an OHLC bar or on a Line on Cloe bar, difficulting the recognition of the plot.
• oldtrades (default: False)
o False: use the modern behavior in which trades for all datas are plotted with different
markers
o True: use the old Trades observer which plots the trades with the same markers,
differentiating only if they are positive or negative
• exactbars (default: False)
With the default value each and every value stored in a line is kept
in memory
Possible values:
84
backtrader’s documentation Version-1.9.58.122
bp = self.data.close - TrueLow(self.data)
tr = TrueRange(self.data) # -> creates another TrueLow(self.data)
Corner cases may happen in which this drives a line object off its
minimum period and breaks things and it is therefore disabled.
If True and optimizing (and the system can preload and use runonce,
data preloading will be done only once in the main process to save
time and resources.
85
backtrader’s documentation Version-1.9.58.122
In most occassions, only the analyzers and with which params are the
things needed to evaluate a the performance of a strategy. If
detailed analysis of the generated values for (for example)
indicators is needed, turn this off
If the old behavior with data0 as the master of the system is wished,
set this parameter to true
• tz (default: None)
o None: in this case the datetime displayed by strategies will be in UTC, which has been
always the standard behavior
o pytz instance. It will be used as such to convert UTC times to the chosen timezone
o string. Instantiating a pytz instance will be attempted.
o integer. Use, for the strategy, the same timezone as the corresponding data in the
self.datas iterable (0 would use the timezone from data0)
• cheat_on_open (default: False)
86
backtrader’s documentation Version-1.9.58.122
This will automatically invoke the set_coo method of the broker with
True to activate cheat_on_open execution. Will only do it if
cheat_on_open is also True
addstorecb(callback)
The actual msg, *args and **kwargs received are implementation defined
(depend entirely on the data/broker/store) but in general one should expect
them to be printable to allow for reception and experimentation.
The actual msg, *args and **kwargs received are implementation defined
(depend entirely on the data/broker/store) but in general one should expect
them to be printable to allow for reception and experimentation.
adddatacb(callback)
87
backtrader’s documentation Version-1.9.58.122
The actual *args and **kwargs received are implementation defined (depend
entirely on the data/broker/store) but in general one should expect them to
be printable to allow for reception and experimentation.
The actual *args and **kwargs received are implementation defined (depend
entirely on the data/broker/store) but in general one should expect them to
be printable to allow for reception and experimentation.
adddata(data, name=None)
If name is not None it will be put into data._name which is meant for
decoration/plotting purposes.
If name is not None it will be put into data._name which is meant for
decoration/plotting purposes.
Any other kwargs like timeframe, compression, todate which are supported by
the resample filter will be passed transparently
If name is not None it will be put into data._name which is meant for
decoration/plotting purposes.
Any other kwargs like timeframe, compression, todate which are supported by
the replay filter will be passed transparently
chaindata(*args, **kwargs)
If name is passed as named argument and is not None it will be put into
data._name which is meant for decoration/plotting purposes.
rolloverdata(*args, **kwargs)
If name is passed as named argument and is not None it will be put into
data._name which is meant for decoration/plotting purposes.
Adds a Strategy class to the mix for a single pass run. Instantiation will
happen during run time.
args and kwargs will be passed to the strategy as they are during
instantiation.
Returns the index with which addition of other objects (like sizers) can be
referenced
args and kwargs MUST BE iterables which hold the values to check.
will execute MyStrategy with period values 15 -> 25 (25 not included,
because ranges are semi-open in Python)
89
backtrader’s documentation Version-1.9.58.122
If a parameter is passed but shall not be optimized the call looks like:
• cerebro.optstrategy(MyStrategy, period=(15,))
• cerebro.optstrategy(MyStrategy, period=15)
optcallback(cb)
Adds a callback to the list of callbacks that will be called with the
optimizations when each of the strategies has been run
Adds an Indicator class to the mix. Instantiation will be done at run time
in the passed strategies
Adds an Observer class to the mix. Instantiation will be done at run time
Adds an Observer class to the mix. Instantiation will be done at run time
It will be added once per “data” in the system. A use case is a buy/sell
observer which observes individual datas.
Adds an Analyzer class to the mix. Instantiation will be done at run time
Adds an Writer class to the mix. Instantiation will be done at run time in
cerebro
90
backtrader’s documentation Version-1.9.58.122
run(**kwargs)
The core method to perform backtesting. Any kwargs passed to it will affect
the value of the standard parameters Cerebro was instantiated with.
If cerebro has not datas the method will immediately bail out.
• For No Optimization: a list contanining instances of the Strategy classes added with addstrategy
• For Optimization: a list of lists which contain instances of the Strategy classes added with
addstrategy
runstop()
setbroker(broker)
Sets a specific broker instance for this strategy, replacing the one
inherited from cerebro.
getbroker()
If plotter is None a default Plot instance is created and kwargs are passed
to it during instantiation.
numfigs split the plot in the indicated number of charts reducing chart
density if wished
use: set it to the name of the desired matplotlib backend. It will take
precedence over iplot
91
backtrader’s documentation Version-1.9.58.122
figfilename: name of the file. Use {j} in the name for the strategy index
to which the figure corresponds and use {i} to insert figure number if
multiple figures are being used per strategy plot
tight: only save actual content and not the frame of the figure
Adds a Sizer class (and args) which is the default sizer for any strategy
added to cerebro
Adds a Sizer class by idx. This idx is a reference compatible to the one
returned by addstrategy. Only the strategy referenced by idx will receive
this size
signal_concurrent(onoff)
If signals are added to the system and the concurrent value is set to True,
concurrent orders will be allowed
signal_accumulate(onoff)
If signals are added to the system and the accumulate value is set to True,
entering the market when already in the market, will be allowed to increase
a position
92
backtrader’s documentation Version-1.9.58.122
addcalendar(cal)
Adds a global trading calendar to the system. Individual data feeds may
have separate calendars which override the global one
addtz(tz)
• None: in this case the datetime displayed by strategies will be in UTC, which has been always the
standard behavior
• pytz instance. It will be used as such to convert UTC times to the chosen timezone
• string. Instantiating a pytz instance will be attempted.
• integer. Use, for the strategy, the same timezone as the corresponding data in the self.datas
iterable (0 would use the timezone from data0)
when (-) –
can be
93
backtrader’s documentation Version-1.9.58.122
Once the timer goes over the end of the session it is reset
to the original value for when
• weekdays: a sorted iterable with integers indicating on which days (iso codes,
Monday is 1, Sunday is 7) the timers can be actually invoked
• weekcarry (default: False). If True and the weekday was not seen (ex: trading
holiday), the timer will be executed on the next day (even if in a new week)
• monthdays: a sorted iterable with integers indicating on which days of the month a
timer has to be executed. For example always on day 15 of the month
• monthcarry (default: True). If the day was not seen (weekend, trading holiday), the
timer will be executed on the next available day.
• allow (default: None). A callback which receives a datetime.date` instance and
returns True if the date is allowed for timers or else returns False
• tzdata which can be either None (default), a pytz instance or a data feed instance.
94
backtrader’s documentation Version-1.9.58.122
Return Value:
Receives a timer notification where timer is the timer which was returned
by add_timer, and when is the calling time. args and kwargs are any
additional arguments passed to add_timer
The actual when time can be later, but the system may have not be able to
call the timer before. This value is the timer value and no the system
time.
add_order_history(orders, notify=True)
datetime ascending
where:
integer - The data with that index (insertion order in Cerebro) will be used
string - a data with that name, assigned for example with cerebro.addata(data,
name=value), will be the target
• notify (default: True)
Cheat On Open
Such a use case fails when the opening price gaps (up or down, depending on
whether buy or sell is in effect) and the cash is not enough for an all-in
operation. This forces the broker to reject the operation.
And although people can try to look into the future with a positive [1] index
approach, this requires preloading data which is not always available.
The pattern:
cerebro = bt.Cerebro(cheat_on_open=True)
This:
• Activates an extra cycle in the system which calls the methods in the
strategy next_open, nextstart_open and prenext_open
The decision to have an additional family of methods has been made to make
a clear separation between the regular methods which operate on the basis
that the prices being examined are no longer available and the future is
unknown and the operation in cheating mode.
• The indicators have not been recalculated and hold the values that were last seen during the previous
cycle in the equivalent xxx regular methods
• The broker has not yet evaluated the pending orders for the new cycle and new orders can be introduced
which will be evaluated if possible.
Notice that:
• Cerebro also has a broker_coo (default: True) parameter which tells cerebro
that if cheat-on-open has been activated, it shall try to activate it also
in the broker if possible.
The simulation broker has a parameter named: coo and a method to set it
named set_coo
Trying cheat-on-open
• If not cheating, the order is issued at the end of the previous day and
will be matched with the next incoming price which is the open price
• If cheating, the order is issued on the same day it is executed. Because
the order is issued before the broker has evaluated orders, it will also be
matched with the next incoming price, the open price.
In both cases
• The current open and close prices will be printed from next.
Regular execution:
...
2005-04-07 next, open 3073.4 close 3090.72
2005-04-08 next, open 3092.07 close 3088.92
Strat Len 68 2005-04-08 Send Buy, fromopen False, close 3088.92
2005-04-11 Buy Executed at price 3088.47
97
backtrader’s documentation Version-1.9.58.122
The order:
Cheating execution:
...
2005-04-07 next, open 3073.4 close 3090.72
2005-04-08 next, open 3092.07 close 3088.92
2005-04-11 Send Buy, fromopen True, close 3080.6
2005-04-11 Buy Executed at price 3088.47
2005-04-11 next, open 3088.47 close 3080.6
98
backtrader’s documentation Version-1.9.58.122
The order:
And the overall result as seen on the chart is also the same.
Conclusion
Cheating on the open allows issuing orders before the open which can for example
allow the exact calculation of stakes for all-in scenarios.
99
backtrader’s documentation Version-1.9.58.122
Sample usage
$ ./cheat-on-open.py --help
usage: cheat-on-open.py [-h] [--data0 DATA0] [--fromdate FROMDATE]
[--todate TODATE] [--cerebro kwargs] [--broker kwargs]
[--sizer kwargs] [--strat kwargs] [--plot [kwargs]]
Cheat-On-Open Sample
optional arguments:
-h, --help show this help message and exit
--data0 DATA0 Data to read in (default:
../../datas/2005-2006-day-001.txt)
--fromdate FROMDATE Date[time] in YYYY-MM-DD[THH:MM:SS] format (default: )
--todate TODATE Date[time] in YYYY-MM-DD[THH:MM:SS] format (default: )
--cerebro kwargs kwargs in key=value format (default: )
--broker kwargs kwargs in key=value format (default: )
--sizer kwargs kwargs in key=value format (default: )
--strat kwargs kwargs in key=value format (default: )
--plot [kwargs] kwargs in key=value format (default: )
Sample source
import argparse
import datetime
import backtrader as bt
class St(bt.Strategy):
params = dict(
periods=[10, 30],
matype=bt.ind.SMA,
)
def __init__(self):
self.cheating = self.cerebro.p.cheat_on_open
mas = [self.p.matype(period=x) for x in self.p.periods]
self.signal = bt.ind.CrossOver(*mas)
100
backtrader’s documentation Version-1.9.58.122
self.order = None
self.order = None
print('{} {} Executed at price {}'.format(
bt.num2date(order.executed.dt).date(),
'Buy' * order.isbuy() or 'Sell', order.executed.price)
)
def next(self):
print('{} next, open {} close {}'.format(
self.data.datetime.date(),
self.data.open[0], self.data.close[0])
)
if self.cheating:
return
self.operate(fromopen=False)
def next_open(self):
if not self.cheating:
return
self.operate(fromopen=True)
def runstrat(args=None):
args = parse_args(args)
101
backtrader’s documentation Version-1.9.58.122
cerebro = bt.Cerebro()
# Parse from/to-date
dtfmt, tmfmt = '%Y-%m-%d', 'T%H:%M:%S'
for a, d in ((getattr(args, x), x) for x in ['fromdate', 'todate']):
if a:
strpfmt = dtfmt + tmfmt * ('T' in a)
kwargs[d] = datetime.datetime.strptime(a, strpfmt)
# Data feed
data0 = bt.feeds.BacktraderCSVData(dataname=args.data0, **kwargs)
cerebro.adddata(data0)
# Broker
cerebro.broker = bt.brokers.BackBroker(**eval('dict(' + args.broker + ')'))
# Sizer
cerebro.addsizer(bt.sizers.FixedSize, **eval('dict(' + args.sizer + ')'))
# Strategy
cerebro.addstrategy(St, **eval('dict(' + args.strat + ')'))
# Execute
cerebro.run(**eval('dict(' + args.cerebro + ')'))
def parse_args(pargs=None):
parser = argparse.ArgumentParser(
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
description=(
'Cheat-On-Open Sample'
)
)
parser.add_argument('--data0', default='../../datas/2005-2006-day-001.txt',
required=False, help='Data to read in')
return parser.parse_args(pargs)
if __name__ == '__main__':
runstrat()
Strategy
1. Conception: __init__
def __init__(self):
self.sma = btind.SimpleMovingAverage(period=15)
Note
103
backtrader’s documentation Version-1.9.58.122
This will avoid going through the strategy during a backtesting. See the
section Exceptions
2. Birth: start
The world (cerebro) tells the strategy is time to start kicking. A default
empty method exists.
3. Childhood: prenext
indicators declared during conception will have put constraints on how long
the strategy needs to mature: this is called the minimum period. Above
__init__ created a SimpleMovingAverage with a period=15.
As long as the syste has seen less than 15 bars, prenext will be called
(there is a default method which is a no-op)
4. Adulthood: next
Once the system has seen 15 bars and the SimpleMovingAverage has a buffer
large enough to start producing values, the strategy is mature enough to
really execute.
5. Reproduction: None
Ok, strategies do not really reproduce. But in a sense they do, because the
system will instantiate them several times if optimizing (with different
parameters)
6. Death: stop
The system tells the strategy the time to come to a reset and put things in
order has come. A default empty method exists.
In most cases and for regular usage patterns this will look like:
class MyStrategy(bt.Strategy):
def __init__(self):
104
backtrader’s documentation Version-1.9.58.122
self.sma = btind.SimpleMovingAverage(period=15)
def next(self):
if self.sma > self.data.close:
# Do something
pass
In this snippet:
Strategies, like a trader in the real world, will get notified when events take
place. Actually once per next cycle in the backtesting process. The strategy
will:
And Strategies also like traders have the chance to operate in the market during
the next method to try to achieve profit with
105
backtrader’s documentation Version-1.9.58.122
How to Buy/Sell/Close
The Buy and Sell methods generate orders. When invoked they return an Order (or
subclass) instance that can be used as a reference. This order has a unique ref
identifier that can be used for comparison
Note
For which data the order has to be created. If None then the first data in
the system, self.datas[0] or self.data0 (aka self.data) will be used
If None the sizer instance retrieved via getsizer will be used to determine
the size.
Price to use (live brokers may place restrictions on the actual format if
it does not comply to minimum tick size requirements)
None is valid for Market and Close orders (the market determines the price)
For Limit, Stop and StopLimit orders this value determines the trigger
point (in the case of Limit the trigger is obviously at which price the
order should be matched)
Only applicable to StopLimit orders. This is the price at which to set the
implicit Limit order, once the Stop has been triggered (for which price has
been used)
Possible values:
106
backtrader’s documentation Version-1.9.58.122
o Order.Market or None. A market order will be executed with the next available price. In
backtesting it will be the opening price of the next bar
o Order.Limit. An order which can only be executed at the given price or better
o Order.Stop. An order which is triggered at price and executed like an Order.Market order
o Order.StopLimit. An order which is triggered at price and executed as an implicit Limit order with
price given by pricelimit
• valid (default: None)
Possible values:
o None: this generates an order that will not expire (aka Good til cancel) and remain in the market
until matched or canceled. In reality brokers tend to impose a temporal limit, but this is usually so
far away in time to consider it as not expiring
o datetime.datetime or datetime.date instance: the date will be used to generate an order valid
until the given datetime (aka good til date)
o Order.DAY or 0 or timedelta(): a day valid until the End of the Session (aka day order) will be
generated
o numeric value: This is assumed to be a value corresponding to a datetime in matplotlib coding
(the one used by backtrader) and will used to generate an order valid until that time (good til
date)
• tradeid (default: 0)
This would override the settings created by backtrader and generate a LIMIT
IF TOUCHED order with a touched price of 9.8 and a limit price of 10.0.
Information Bits:
• A Strategy has a length which is always equal to that of the main data
(datas[0]) and can of course be gotten with len(self)
107
backtrader’s documentation Version-1.9.58.122
Member Attributes:
data feeds can also be accessed by name (see the reference) if one has been
assigned to it
• dnames: an alternative to reach the data feeds by name (either with [name]
or with .name notation)
...
data0 = bt.feeds.YahooFinanceData(datname='YHOO', fromdate=...,
name='days')
cerebro.adddata(data0)
cerebro.resampledata(data0, timeframe=bt.TimeFrame.Weeks, name='weeks')
...
Later in the strategy one can create indicators on each like this:
...
smadays = bt.ind.SMA(self.dnames.days, period=30) # or self.dnames['days']
smaweeks = bt.ind.SMA(self.dnames.weeks, period=10) # or
self.dnames['weeks']
...
108
backtrader’s documentation Version-1.9.58.122
• _orderspending: list of orders which will be notified to the strategy before next is called
• _tradespending: list of trades which will be notified to the strategy before next is called
• _orders: list of order which have been already notified. An order can be several times in the list with
different statuses and different execution bits. The list is menat to keep the history.
• _trades: list of order which have been already notified. A trade can be several times in the list just like an
order.
Note
Bear in mind that prenext, nextstart and next can be called several times for the
same point in time (ticks updating prices for the daily bar, when a daily
timeframe is in use)
Reference: Strategy
next()
This method will be called for all remaining data points when the minimum
period for all datas/indicators have been meet.
nextstart()
This method will be called once, exactly when the minimum period for all
datas/indicators have been meet. The default behavior is to call next
prenext()
start()
stop()
109
backtrader’s documentation Version-1.9.58.122
notify_order(order)
notify_trade(trade)
notify_cashvalue(cash, value)
Receives the current fund value, value status of the strategy’s broker
For which data the order has to be created. If None then the first
data in the system, self.datas[0] or self.data0 (aka self.data) will
be used
None is valid for Market and Close orders (the market determines the
price)
110
backtrader’s documentation Version-1.9.58.122
For Limit, Stop and StopLimit orders this value determines the
trigger point (in the case of Limit the trigger is obviously at which
price the order should be matched)
Possible values:
o Order.Market or None. A market order will be executed with the next available price. In
backtesting it will be the opening price of the next bar
o Order.Limit. An order which can only be executed at the given price or better
o Order.Stop. An order which is triggered at price and executed like an Order.Market order
o Order.StopLimit. An order which is triggered at price and executed as an implicit Limit
order with price given by pricelimit
o Order.Close. An order which can only be executed with the closing price of the session
(usually during a closing auction)
o Order.StopTrail. An order which is triggered at price minus trailamount (or trailpercent)
and which is updated if the price moves away from the stop
o Order.StopTrailLimit. An order which is triggered at price minus trailamount (or
trailpercent) and which is updated if the price moves away from the stop
• valid (default: None)
Possible values:
111
backtrader’s documentation Version-1.9.58.122
o None: this generates an order that will not expire (aka Good till cancel) and remain in the
market until matched or canceled. In reality brokers tend to impose a temporal limit, but
this is usually so far away in time to consider it as not expiring
o datetime.datetime or datetime.date instance: the date will be used to generate an order
valid until the given datetime (aka good till date)
o Order.DAY or 0 or timedelta(): a day valid until the End of the Session (aka day order) will
be generated
o numeric value: This is assumed to be a value corresponding to a datetime in matplotlib
coding (the one used by backtrader) and will used to generate an order valid until that
time (good till date)
• tradeid (default: 0)
Another order instance. This order will become part of an OCO (Order
Cancel Others) group. The execution of one of the orders, immediately
cancels all others in the same group
Note
• size: automatically calculated from the existing position if not provided (default: None) by the
caller
cancel(order)
Create a bracket order group (low side - buy order - high side). The
default behavior is as follows:
For which data the order has to be created. If None then the first
data in the system, self.datas[0] or self.data0 (aka self.data) will
be used
None is valid for Market and Close orders (the market determines the
price)
For Limit, Stop and StopLimit orders this value determines the
trigger point (in the case of Limit the trigger is obviously at which
price the order should be matched)
114
backtrader’s documentation Version-1.9.58.122
• tradeid (default: 0)
Specific keyword arguments (in a dict) to pass to the low side order.
Arguments from the default **kwargs will be applied on top of this.
115
backtrader’s documentation Version-1.9.58.122
Create a bracket order group (low side - buy order - high side). The
default behavior is as follows:
The current position size is taken into account as the start point to
achieve target
It returns either:
or
The current value is taken into account as the start point to achieve
target
It returns either:
or
Example
The current value is taken into account as the start point to achieve
target
• If target > value - buy if pos.size >= 0 (Increase a long position) - sell if pos.size < 0 (Increase a
short position)
• If target < value - sell if pos.size >= 0 (Decrease a long position) - buy if pos.size < 0 (Decrease
a short position)
It returns either:
or
117
backtrader’s documentation Version-1.9.58.122
getsizer()
setsizer(sizer)
getsizing(data=None, isbuy=True)
Return the stake calculated by the sizer instance for the current situation
getposition(data=None, broker=None)
If both are None, the main data and the default broker will be used
getpositionbyname(name=None, broker=None)
If both are None, the main data and the default broker will be used
getpositionsbyname(broker=None)
getdatanames()
getdatabyname(name)
when (-) –
can be
Once the timer goes over the end of the session it is reset
to the original value for when
• weekdays: a sorted iterable with integers indicating on which days (iso codes,
Monday is 1, Sunday is 7) the timers can be actually invoked
• weekcarry (default: False). If True and the weekday was not seen (ex: trading
holiday), the timer will be executed on the next day (even if in a new week)
• monthdays: a sorted iterable with integers indicating on which days of the month a
timer has to be executed. For example always on day 15 of the month
119
backtrader’s documentation Version-1.9.58.122
• monthcarry (default: True). If the day was not seen (weekend, trading holiday), the
timer will be executed on the next available day.
• allow (default: None). A callback which receives a datetime.date` instance and
returns True if the date is allowed for timers or else returns False
• tzdata which can be either None (default), a pytz instance or a data feed instance.
• cheat (default False) if True the timer will be called before the broker has a chance
to evaluate the orders. This opens the chance to issue orders based on opening
price for example right before the session starts
• *args: any extra args will be passed to notify_timer
• **kwargs: any extra kwargs will be passed to notify_timer
Return Value:
Receives a timer notification where timer is the timer which was returned
by add_timer, and when is the calling time. args and kwargs are any
additional arguments passed to add_timer
The actual when time can be later, but the system may have not be able to
call the timer before. This value is the timer value and no the system
time.
120
backtrader’s documentation Version-1.9.58.122
A Strategy offers methods to trade, namely: buy, sell and close. Let’s see the
signature of buy:
Notice that size has a default value of None if the caller does not specify it.
This is where Sizers play an important role:
• size=None requests that the Strategy asks its Sizer for the actual stake
This obviously implies that Strategies have a Sizer: Yes, indeed!. The background
machinery adds a default sizer to a Strategy if the user has not added one. The
default Sizer added to a strategy is SizerFix. The initial lines of the
definition:
class SizerFix(SizerBase):
params = (('stake', 1),)
It is easy to guess that this Sizer simply buys/sells using a stake of 1 units
(be it shares, contracts, ...)
Using Sizers
From Cerebro
Adds a Sizer that will be applied to any strategy added to cerebro. This
is, so to to say, the default Sizer. Example:
cerebro = bt.Cerebro()
cerebro.addsizer(bt.sizers.SizerFix, stake=20) # default sizer for
strategies
cerebro = bt.Cerebro()
cerebro.addsizer(bt.sizers.SizerFix, stake=20) # default sizer for
strategies
cerebro.addstrategy(MyOtherStrategy)
In this example:
o A default Sizer has been added to the system. This one applies to all strategies which don’t have a
specific Sizer assigned
o For MyStrategy and after collecting its insertion idx, a specific sizer (changing the stake param) is
added
o A 2nd strategy, MyOtherStrategy, is added to the system. No specific Sizer is added for it
o This means that:
MyStrategy will finally have an internal specific Sizer
MyOtherStrategy will get the default sizer
Note
default doesn’t mean that that the strategies share a single Sizer
instance. Each strategy receives a different instance of the default sizer
From Strategy
The Strategy class offers an API: setsizer and getsizer (and a property sizer) to
manage the Sizer. The signatures:
122
backtrader’s documentation Version-1.9.58.122
This would for example allow to create a Sizer at the same level as the
cerebro calls are happening and pass it as a parameter to all strategies
that go in the system, which effectevily allows sharing a Sizer
Sizer Development
Doing it is easy:
This method returns the desired size for the buy/sell operation
The returned sign is not relevant, ie: if the operation is a sell operation
(isbuy will be False) the method may return 5 or -5. Only the absolute
value will be used by the sell operation.
Sizer has already gone to the broker and requested the commission
information for the given data, the actual cash level and provides a direct
reference to the data which is the target of the operation
123
backtrader’s documentation Version-1.9.58.122
import backtrader as bt
class FixedSize(bt.Sizer):
params = (('stake', 1),)
This is pretty simple in that the Sizer makes no calculations and the parameters
are just there.
But the mechanism should allow the construction of complex sizing (aka
positioning) systems to manage the stakes when entering/exiting the market.
class FixedRerverser(bt.FixedSize):
This one builds on the existing FixedSize to inherit the params and overrides
_getsizing to:
This would remove the burden from the Strategy to decide if a position has to be
reversed or opened, the Sizer is in control and can at any time be replaced
without affecting the logic.
Wihtout considering complex sizing algorithms, two different sizers can be used
to turn a strategy from Long-Only to Long-Short. Simply by changing the Sizer in
the cerebro execution, the strategy will change behavior. A very simple close
crosses SMA algorithm:
class CloseSMA(bt.Strategy):
124
backtrader’s documentation Version-1.9.58.122
def __init__(self):
sma = bt.indicators.SMA(self.data, period=self.p.period)
self.crossover = bt.indicators.CrossOver(self.data, sma)
def next(self):
if self.crossover > 0:
self.buy()
Notice how the strategy doesn’t consider the current position (by looking at
self.position) to decide whether a buy or sell has to actually be done. Only the
signal from the CrossOver is considered. The Sizers will be in charge of
everything.
This sizer will take care of only returning a non-zero size when selling if a
position is already open:
class LongOnly(bt.Sizer):
params = (('stake', 1),)
# Sell situation
position = self.broker.getposition(data)
if not position.size:
return 0 # do not sell if nothing is open
return self.p.stake
Putting it all together (and assuming backtrader has already been imported and a
data has been added to the system):
...
cerebro.addstrategy(CloseSMA)
cerebro.addsizer(LongOnly)
...
cerebro.run()
...
125
backtrader’s documentation Version-1.9.58.122
The chart (from the sample included in the sources to test this).
The Long-Short version simply changes the Sizer to be the FixedReverser shown
above:
...
cerebro.addstrategy(CloseSMA)
cerebro.addsizer(FixedReverser)
...
cerebro.run()
...
126
backtrader’s documentation Version-1.9.58.122
bt.Sizer Reference
class backtrader.Sizer
This is the base class for Sizers. Any sizer should subclass this and
override the _getsizing method
Member Attribs:
Gives access to the entire api of the strategy, for example if the
actual data position would be needed in _getsizing:
position = self.strategy.getposition(data)
Params:
• comminfo: The CommissionInfo instance that contains information about the commission for the
data and allows calculation of position value, operation cost, commision for the operation
• cash: current available cash in the broker
• data: target of the operation
• isbuy: will be True for buy operations and False for sell operations
The method has to return the actual size (an int) to be executed. If 0 is
returned nothing will be executed.
Timers
Note
Options
• Timer based in absolute time input or with regards to session start/end times
• Timezone specification for the time specification, be it directly or via pytz compatible objects or via data
feed session end times
128
backtrader’s documentation Version-1.9.58.122
Usage pattern
Both in Cerebro and Strategy subclasses the timer callback will be received in
the following method.
The actual ``when`` time can be later, but the system may have not be
able to call the timer before. This value is the timer value and not the
system time.
'''
129
backtrader’s documentation Version-1.9.58.122
Done with the same method and just the addition of the parameter strats. If set
to True the timer will not only be notified to the cerebro, it will also be
notified to all strategies running in the system.
If cheat=False
• After the data feeds have loaded the new values for the current bar
• After the broker has evaluated orders and recalculated the portfolio value
• Before indicators have been recalculated (because this is triggered by the strategies)
• Before any next method of any strategy is called
If cheat=True
• After the data feeds have loaded the new values for the current bar
• Before the broker has evaluated orders and recalculated the portfolio value
• And consequently before indicators have been recalculated and next method of any strategy is called
Which allows for example the following scenario with daily bars:
• Before the new bar is evaluated by the broker the timer is called
• The indicators have the value from the previous day at the close and can be used to generate an
entry/exit signal (or a flag may have been set during the last evaluation of next)
130
backtrader’s documentation Version-1.9.58.122
• Because the new prices are available, the stake can be calculated using the opening price. This assumes
that one is for example getting a good indication about the open from watching the opening auction.
The sample scheduled.py defaults to running with the standard daily bars
available in the backtrader distribution. The parameters to the strategy
class St(bt.Strategy):
params = dict(
when=bt.timer.SESSION_START,
timer=True,
cheat=False,
offset=datetime.timedelta(),
repeat=datetime.timedelta(),
weekdays=[],
)
• start: 09:00
• end: 17:30
$ ./scheduled.py --strat
when='datetime.time(15,30)',offset='datetime.timedelta(minutes=30)'
And the time has changed from 15:30 to 16:00 for the timer. No surprises. Let’s
do the same but referencing the start of the session.
$ ./scheduled.py --strat
when='bt.timer.SESSION_START',offset='datetime.timedelta(minutes=30)'
Et voilá! The time at which the callback is called is 09:30. And the session
start, see above, is 09:00. This gives the ability to simply say that one wants
to execute an action 30 minutes after the start of the session.
$ ./scheduled.py --strat
when='bt.timer.SESSION_START',offset='datetime.timedelta(minutes=30)',repeat='dat
etime.timedelta(minutes=30)'
There is no repetition. The reason being that the resolution of the prices is
daily. The timer is called for the 1st time at 09:30 like in the previous
example. But when the system get the next batch of prices, they are happening on
the next day. And the timer can only, obviously, be called once. A lower
resolution is needed.
But before moving on to a lower resolution, let’s cheat by having the timer
called before the end of the session.
132
backtrader’s documentation Version-1.9.58.122
The strategy adds a 2nd timer with cheat=True. This is added 2nd and will
therefore received the 2nd tid (timer id) which is 1 (see in the above examples
that the assigned tid was 0)
And 1 is called before 0, because that timer is cheating and is being called
before many events in the system happen (see above for the explanation)
Due to the daily resolution of the prices it doesn’t make much of a difference
except that:
• The strategy also issues an order right before the open ... and it is being
matched with the opening price the next day
This, even if cheating by acting before the open, is still the normal
behavior, because cheating-on-open has also not been activated in the
broker.
Effectively like if one had acted on the opening auction price seconds
before the real opening of the market.
The sample scheduled-min.py defaults to running with the standard 5-minute bars
available in the backtrader distribution. The parameters to the strategy are
extended to include monthdays and the carry options
class St(bt.Strategy):
params = dict(
when=bt.timer.SESSION_START,
timer=True,
cheat=False,
offset=datetime.timedelta(),
repeat=datetime.timedelta(),
weekdays=[],
weekcarry=False,
monthdays=[],
monthcarry=True,
)
• start: 09:00
• end: 17:30
The timer kicks in as requested at 15:30. The log shows how it does that during
the 1st two days.
...
74, 2006-01-02 15:10:00, Week 1, Day 1, O 3596.12, H 3596.63, L 3595.92, C
3596.63
75, 2006-01-02 15:15:00, Week 1, Day 1, O 3596.36, H 3596.65, L 3596.19, C
3596.65
76, 2006-01-02 15:20:00, Week 1, Day 1, O 3596.53, H 3599.13, L 3596.12, C 3598.9
77, 2006-01-02 15:25:00, Week 1, Day 1, O 3599.07, H 3599.68, L 3598.47, C
3599.68
strategy notify_timer with tid 0, when 2006-01-02 15:30:00 cheat False
78, 2006-01-02 15:30:00, Week 1, Day 1, O 3599.64, H 3599.73, L 3599.0, C 3599.67
79, 2006-01-02 15:35:00, Week 1, Day 1, O 3599.61, H 3600.29, L 3599.52, C
3599.92
80, 2006-01-02 15:40:00, Week 1, Day 1, O 3599.96, H 3602.06, L 3599.76, C
3602.05
strategy notify_timer with tid 0, when 2006-01-02 15:45:00 cheat False
81, 2006-01-02 15:45:00, Week 1, Day 1, O 3601.97, H 3602.07, L 3601.45, C
3601.83
82, 2006-01-02 15:50:00, Week 1, Day 1, O 3601.74, H 3602.8, L 3601.63, C 3602.8
83, 2006-01-02 15:55:00, Week 1, Day 1, O 3602.53, H 3602.74, L 3602.33, C
3602.61
strategy notify_timer with tid 0, when 2006-01-02 16:00:00 cheat False
84, 2006-01-02 16:00:00, Week 1, Day 1, O 3602.58, H 3602.75, L 3601.81, C
3602.14
85, 2006-01-02 16:05:00, Week 1, Day 1, O 3602.16, H 3602.16, L 3600.86, C
3600.96
86, 2006-01-02 16:10:00, Week 1, Day 1, O 3601.2, H 3601.49, L 3600.94, C 3601.27
...
strategy notify_timer with tid 0, when 2006-01-02 17:15:00 cheat False
99, 2006-01-02 17:15:00, Week 1, Day 1, O 3603.96, H 3603.96, L 3602.89, C
3603.79
135
backtrader’s documentation Version-1.9.58.122
As expected the 1st call is triggered at 15:30 and then starts repeating every 15
minutes until the end of the session at 17:30. When the new session kicks in, the
timer has been reset to 15:30 again.
Order creation is t 09:05:00 and execution at 09:10:00 because the broker is not
in cheat-on-open mode. Let’s set it ...
And the issuing time and execution time are 09:05:00 with the execution price
being the opening price at 09:05:00.
Additional scenarios
Timers allow specifying on which days they have to be executed by passing a list
of days (integers following the iso spec, where Mon=1 and Sun=7) as in
• weekdays=[5] which would ask for the timer to only be valid on Fridays
In case a Friday is a non-trading day and the timer should kick-in on the
next trading day, one can add weekcarry=True
Similar to it, one can decide to act on the 15th day of each month with:
• monthdays=[15]
In case the 15th happens to be non-trading day and the timer should kick-in
on the next trading day, one can add monthcarry=True
There isn’t an implementation for things like: the 3rd Friday of March, June,
September and December (futures/options expirations), but there is a possibility
to implement rules by passing:
class FutOpExp(object):
def __init__(self):
self.fridays = 0
self.curmonth = -1
137
backtrader’s documentation Version-1.9.58.122
if d.month != self.curmonth:
self.curmonth = d.month
self.fridays = 0
This would allow a timer to kick in on the 3rd Friday of those months and
may be close positions before the futures expire.
Parameters to add_timer
• when: can be
o datetime.time instance (see below tzdata)
o bt.timer.SESSION_START to reference a session start
o bt.timer.SESSION_END to reference a session end
Used to offset the value when. It has a meaningful use in combination with
SESSION_START and SESSION_END, to indicated things like a timer being
called 15 minutes after the session start.
Indicates if after a 1st call, further calls will be scheduled within the
same session at the scheduled repeat delta
Once the timer goes over the end of the session it is reset to the original
value for when
138
backtrader’s documentation Version-1.9.58.122
• weekcarry (default: False). If True and the weekday was not seen (ex:
trading holiday), the timer will be executed on the next day (even if in a
new week)
• monthdays: a sorted iterable with integers indicating on which days of the
month a timer has to be executed. For example always on day 15 of the month
• monthcarry (default: True). If the day was not seen (weekend, trading
holiday), the timer will be executed on the next available day.
• allow (default: None). A callback which receives a datetime.date` instance
and returns True if the date is allowed for timers or else returns False
• tzdata which can be either None (default), a pytz instance or a data feed
instance.
SESSION_END and tzdata is None, the 1st data feed in the system (aka
self.data0) will be used as the reference to find out the session times.
$ ./scheduled.py --help
usage: scheduled.py [-h] [--data0 DATA0] [--fromdate FROMDATE]
[--todate TODATE] [--cerebro kwargs] [--broker kwargs]
[--sizer kwargs] [--strat kwargs] [--plot [kwargs]]
Sample Skeleton
139
backtrader’s documentation Version-1.9.58.122
optional arguments:
-h, --help show this help message and exit
--data0 DATA0 Data to read in (default:
../../datas/2005-2006-day-001.txt)
--fromdate FROMDATE Date[time] in YYYY-MM-DD[THH:MM:SS] format (default: )
--todate TODATE Date[time] in YYYY-MM-DD[THH:MM:SS] format (default: )
--cerebro kwargs kwargs in key=value format (default: )
--broker kwargs kwargs in key=value format (default: )
--sizer kwargs kwargs in key=value format (default: )
--strat kwargs kwargs in key=value format (default: )
--plot [kwargs] kwargs in key=value format (default: )
$ ./scheduled-min.py --help
usage: scheduled-min.py [-h] [--data0 DATA0] [--fromdate FROMDATE]
[--todate TODATE] [--cerebro kwargs] [--broker kwargs]
[--sizer kwargs] [--strat kwargs] [--plot [kwargs]]
optional arguments:
-h, --help show this help message and exit
--data0 DATA0 Data to read in (default: ../../datas/2006-min-005.txt)
--fromdate FROMDATE Date[time] in YYYY-MM-DD[THH:MM:SS] format (default: )
--todate TODATE Date[time] in YYYY-MM-DD[THH:MM:SS] format (default: )
--cerebro kwargs kwargs in key=value format (default: )
--broker kwargs kwargs in key=value format (default: )
--sizer kwargs kwargs in key=value format (default: )
--strat kwargs kwargs in key=value format (default: )
--plot [kwargs] kwargs in key=value format (default: )
import argparse
import datetime
import backtrader as bt
140
backtrader’s documentation Version-1.9.58.122
class St(bt.Strategy):
params = dict(
when=bt.timer.SESSION_START,
timer=True,
cheat=False,
offset=datetime.timedelta(),
repeat=datetime.timedelta(),
weekdays=[],
)
def __init__(self):
bt.ind.SMA()
if self.p.timer:
self.add_timer(
when=self.p.when,
offset=self.p.offset,
repeat=self.p.repeat,
weekdays=self.p.weekdays,
)
if self.p.cheat:
self.add_timer(
when=self.p.when,
offset=self.p.offset,
repeat=self.p.repeat,
cheat=True,
)
self.order = None
def prenext(self):
self.next()
def next(self):
_, isowk, isowkday = self.datetime.date().isocalendar()
txt = '{}, {}, Week {}, Day {}, O {}, H {}, L {}, C {}'.format(
len(self), self.datetime.datetime(),
isowk, isowkday,
self.data.open[0], self.data.high[0],
self.data.low[0], self.data.close[0])
print(txt)
def runstrat(args=None):
args = parse_args(args)
cerebro = bt.Cerebro()
# Parse from/to-date
dtfmt, tmfmt = '%Y-%m-%d', 'T%H:%M:%S'
for a, d in ((getattr(args, x), x) for x in ['fromdate', 'todate']):
if a:
strpfmt = dtfmt + tmfmt * ('T' in a)
kwargs[d] = datetime.datetime.strptime(a, strpfmt)
# Data feed
data0 = bt.feeds.BacktraderCSVData(dataname=args.data0, **kwargs)
cerebro.adddata(data0)
# Broker
cerebro.broker = bt.brokers.BackBroker(**eval('dict(' + args.broker + ')'))
# Sizer
cerebro.addsizer(bt.sizers.FixedSize, **eval('dict(' + args.sizer + ')'))
# Strategy
142
backtrader’s documentation Version-1.9.58.122
# Execute
cerebro.run(**eval('dict(' + args.cerebro + ')'))
def parse_args(pargs=None):
parser = argparse.ArgumentParser(
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
description=(
'Sample Skeleton'
)
)
parser.add_argument('--data0', default='../../datas/2005-2006-day-001.txt',
required=False, help='Data to read in')
return parser.parse_args(pargs)
143
backtrader’s documentation Version-1.9.58.122
if __name__ == '__main__':
runstrat()
import argparse
import datetime
import backtrader as bt
class St(bt.Strategy):
params = dict(
when=bt.timer.SESSION_START,
timer=True,
cheat=False,
offset=datetime.timedelta(),
repeat=datetime.timedelta(),
weekdays=[],
weekcarry=False,
monthdays=[],
monthcarry=True,
)
def __init__(self):
bt.ind.SMA()
if self.p.timer:
self.add_timer(
when=self.p.when,
offset=self.p.offset,
repeat=self.p.repeat,
weekdays=self.p.weekdays,
weekcarry=self.p.weekcarry,
monthdays=self.p.monthdays,
monthcarry=self.p.monthcarry,
# tzdata=self.data0,
)
if self.p.cheat:
144
backtrader’s documentation Version-1.9.58.122
self.add_timer(
when=self.p.when,
offset=self.p.offset,
repeat=self.p.repeat,
weekdays=self.p.weekdays,
weekcarry=self.p.weekcarry,
monthdays=self.p.monthdays,
monthcarry=self.p.monthcarry,
# tzdata=self.data0,
cheat=True,
)
self.order = None
def prenext(self):
self.next()
def next(self):
_, isowk, isowkday = self.datetime.date().isocalendar()
txt = '{}, {}, Week {}, Day {}, O {}, H {}, L {}, C {}'.format(
len(self), self.datetime.datetime(),
isowk, isowkday,
self.data.open[0], self.data.high[0],
self.data.low[0], self.data.close[0])
print(txt)
def runstrat(args=None):
args = parse_args(args)
145
backtrader’s documentation Version-1.9.58.122
cerebro = bt.Cerebro()
# Parse from/to-date
dtfmt, tmfmt = '%Y-%m-%d', 'T%H:%M:%S'
for a, d in ((getattr(args, x), x) for x in ['fromdate', 'todate']):
if a:
strpfmt = dtfmt + tmfmt * ('T' in a)
kwargs[d] = datetime.datetime.strptime(a, strpfmt)
# Data feed
data0 = bt.feeds.BacktraderCSVData(dataname=args.data0, **kwargs)
cerebro.adddata(data0)
# Broker
cerebro.broker = bt.brokers.BackBroker(**eval('dict(' + args.broker + ')'))
# Sizer
cerebro.addsizer(bt.sizers.FixedSize, **eval('dict(' + args.sizer + ')'))
# Strategy
cerebro.addstrategy(St, **eval('dict(' + args.strat + ')'))
# Execute
cerebro.run(**eval('dict(' + args.cerebro + ')'))
def parse_args(pargs=None):
parser = argparse.ArgumentParser(
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
description=(
'Timer Test Intraday'
)
)
146
backtrader’s documentation Version-1.9.58.122
parser.add_argument('--data0', default='../../datas/2006-min-005.txt',
required=False, help='Data to read in')
return parser.parse_args(pargs)
if __name__ == '__main__':
runstrat()
Target Orders
Until version 1.8.10.96 smart staking was possible with backtrader over the
Strategy methods: buy and sell. It was all about adding a Sizer to the equation
which is responsible for the size of the stake.
What a Sizer cannot do is decide if the operation has to be a buy or a sell. And
that means that a new concept is needed in which a small intelligence layer is
added to make such decision.
147
backtrader’s documentation Version-1.9.58.122
Here is where the family of order_target_xxx methods in the Strategy come into
play. Inspired by the ones in zipline, the methods offer the chance to simply
specify the final target, be the target:
Note
The reference for the methods can be found in Strategy. The summary is that the
methods use the same signature as buy and sell except for the parameter size
which is replaced by the parameter target
In this case it is all about specifying the final target and the method decides
if an operation will be a buy or a sell. The same logic applies to the 3 methods.
Let’s tart with order_target_size
• If the target is greater than the position a buy is issued, with the
difference target - position_size
Examples:
Examples:
When targetting a value with order_target_value, the current value of the asset
in the portfolio and the position size are both taken into account to decide what
the final underlying operation will be. The reasoning:
• If position size is negative (short) and the target value has to be greater than the current value, this
means: sell more
148
backtrader’s documentation Version-1.9.58.122
The Sample
backtrader tries to have a sample for each new functionality and this is no
exception. No bells and whistles, just something to test the results are as
expected. This one is under the order_target directory in the samples.
The logic in the sample is rather dumb and only meaant for testing:
• During odd months (Jan, Mar, ...), use the day as target (in the case of
order_target_value multiplying the day by 1000)
• During even months (Feb, Apr, ...) use 31 - day as the target
order_target_size
149
backtrader’s documentation Version-1.9.58.122
In Jan the target starts at 3 with the 1st trading day of the year and increases.
And the position size moves initially from 0 to 3 and then in increments of 1.
Finishing Jan the last order_target is for 31 and that position size is reported
when entering the 1st day of Feb, when the new target side is requested to be 30
and goes changing along with the position in decrements of ´1`.
order_target_value
150
backtrader’s documentation Version-1.9.58.122
There is an extra line of information telling what the actual data value (in the
portfolio) is. This helps in finding out if the target value has been reachec.
The initial target is 3000.0 and the reported initial value is 2853.24. The
question here is whether this is close enough. And the answer is Yes
• The sample uses a Market order at the end of a daily bar and the last available price to calculate a target
size which meets the target value
• The execution uses then the open price of the next day and this is unlikely to be the previous close
The next target value and final value are much closer: 4000 and 3938.17.
When changing into Feb the target value starts decreasing from 31000 to 30000 and
29000`. So does the *data value* with from ``30580.00 to 30706.56 and then to
28633.44. Wait:
Indeed. In this case the calculated size for the target value met an
opening price which bumped the value to 30706.56
• The sample uses a Market type execution for the orders and this effect
cannot be avoided
• The methods order_target_xxx allow specifying the execution type and price.
One could specify Limit as the execution order and let the price be the
close price (chosen by the method if nothing else be provided) or even
provide specific pricing
order_target_percent
152
backtrader’s documentation Version-1.9.58.122
And the information has been changed to see the % the data represents in the
portfolio.
153
backtrader’s documentation Version-1.9.58.122
Sample Usage
$ ./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]]
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)
154
backtrader’s documentation Version-1.9.58.122
Sample Code
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:
- 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),
155
backtrader’s documentation Version-1.9.58.122
('use_target_value', False),
('use_target_percent', False),
)
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))
156
backtrader’s documentation Version-1.9.58.122
self.order = self.order_target_size(target=size)
elif self.p.use_target_value:
value = size * 1000
self.order = self.order_target_value(target=value)
elif self.p.use_target_percent:
percent = size / 100.0
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:
157
backtrader’s documentation Version-1.9.58.122
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')
pgroup = parser.add_mutually_exclusive_group(required=True)
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,
158
backtrader’s documentation Version-1.9.58.122
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'))
return parser.parse_args()
if __name__ == '__main__':
runstrat()
Quick summary:
• Instead of writing a Strategy class, instantiating Indicators, writing the buy/sell logic ...
• The end user add Signals (indicators anyhow) and the rest is done in the background
Quick example:
import backtrader as bt
data = bt.feeds.OneOfTheFeeds(dataname='mydataname')
cerebro.adddata(data)
cerebro.add_signal(bt.SIGNAL_LONGSHORT, MySignal)
cerebro.run()
Et voilá!.
Of course the Signal itself is missing. Let’s define a very dumb Signal which
yields:
159
backtrader’s documentation Version-1.9.58.122
The definition:
class MySignal(bt.Indicator):
lines = ('signal',)
params = (('period', 30),)
def __init__(self):
self.lines.signal = self.data - bt.indicators.SMA(period=self.p.period)
And now it is really done. When run is executed Cerebro will take care of
instantiating a special Strategy instance which knows what to do with the
Signals.
Initial FAQ
The execution type is Market and the validity is Good Until Canceled
Signals technicalities
From a practical point of view and looking at the example above a Signal is:
This helps when using other Indicators like when in the example the Simple
Moving Average is used.
160
backtrader’s documentation Version-1.9.58.122
Signals indications
The signals delivers indications when queried with signal[0] and the meaning is:
Note
When no specific price field is indicated for the data, the close price is the
reference price is.
Signals Types
The constants indicated below as seen in the example above, are directly
available from the main backtrader module as in:
import backtrader as bt
bt.SIGNAL_LONG
Main Group:
• LONGSHORT: both long and short indications from this signal are taken
• LONG:
o long indications are taken to go long
o short indications are taken to close the long position. But:
If a LONGEXIT (see below) signal is in the system it will be used to exit the long
If a SHORT signal is available and no LONGEXIT is available , it will be used to close a long
before opening a short
• SHORT:
o short indications are taken to go short
o long indications are taken to close the short position. But:
If a SHORTEXIT (see below) signal is in the system it will be used to exit the short
161
backtrader’s documentation Version-1.9.58.122
Exit Group:
This 2 signals are meant to override others and provide criteria for exitins a
long / short position
The sample Signal shown above will issue long and short indications on a constant
basis, because it simply substracts the SMA value from the close price and this
will always be either > 0 and < 0 ( 0 is mathematically possible, but unlikely to
really happen)
• Accumulation: even if already in the market, the signals would produce new orders which would increase
the possition in the market
• Concurrency: new orders would be generated without waiting for the execution of other orders
• To Not Accumulate
• To Not allow Concurrency
Should any of these two behaviors be wished, this can be controlled via cerebro
with:
The sample
class SMACloseSignal(bt.Indicator):
lines = ('signal',)
162
backtrader’s documentation Version-1.9.58.122
def __init__(self):
self.lines.signal = self.data - bt.indicators.SMA(period=self.p.period)
class SMAExitSignal(bt.Indicator):
lines = ('signal',)
params = (('p1', 5), ('p2', 30),)
def __init__(self):
sma1 = bt.indicators.SMA(period=self.p.p1)
sma2 = bt.indicators.SMA(period=self.p.p2)
self.lines.signal = sma1 - sma2
The output
163
backtrader’s documentation Version-1.9.58.122
To notice:
• The Signal is plotted. This is normal given it is simply an indicator and the plotting rules for it apply
• The strategy is really long and short. This can be seen because the cash level never goes back to be the
value level
• Side note: even for a dumb idea ... (and without commission) the strategy hasn’t lost money ...
The output
164
backtrader’s documentation Version-1.9.58.122
To notice:
• Here the cash level goes back to be the value level after each sell, which means the strategy is out of the
market
• Side note: Again no money has been lost ...
The output
165
backtrader’s documentation Version-1.9.58.122
To notice:
• The 1st operation is a sell as expected and takes place later than the 1st operation in the 2 examples
above. Not until the close is below the SMA and the simple substraction yields a minus
• Here the cash level goes back to be the value level after each buy, which means the strategy is out of the
market
• Side note: Finally the system loses money
The output
166
backtrader’s documentation Version-1.9.58.122
To notice:
• Many of the trades are the same, but some are interrupted earlier because the fast moving average in the
exit signal crosses the slow moving average to the downside
• The system shows its longonly property with the cash becoming the value at the end of each trade
• Side note: Again money is made ... even with some modified trades
Usage
$ ./signals-strategy.py --help
usage: signals-strategy.py [-h] [--data DATA] [--fromdate FROMDATE]
[--todate TODATE] [--cash CASH]
[--smaperiod SMAPERIOD] [--exitperiod EXITPERIOD]
[--signal {longshort,longonly,shortonly}]
[--exitsignal {longexit,shortexit}]
[--plot [kwargs]]
167
backtrader’s documentation Version-1.9.58.122
optional arguments:
-h, --help show this help message and exit
--data DATA Specific data to be read in (default:
../../datas/2005-2006-day-001.txt)
--fromdate FROMDATE Starting date in YYYY-MM-DD format (default: None)
--todate TODATE Ending date in YYYY-MM-DD format (default: None)
--cash CASH Cash to start with (default: 50000)
--smaperiod SMAPERIOD
Period for the moving average (default: 30)
--exitperiod EXITPERIOD
Period for the exit control SMA (default: 5)
--signal {longshort,longonly,shortonly}
Signal type to use for the main signal (default:
longshort)
--exitsignal {longexit,shortexit}
Signal type to use for the exit signal (default: None)
--plot [kwargs], -p [kwargs]
Plot the read data applying any kwargs passed For
example: --plot style="candle" (to plot candles)
(default: None)
The code
import argparse
import collections
import datetime
import backtrader as bt
MAINSIGNALS = collections.OrderedDict(
(('longshort', bt.SIGNAL_LONGSHORT),
('longonly', bt.SIGNAL_LONG),
('shortonly', bt.SIGNAL_SHORT),)
)
EXITSIGNALS = {
'longexit': bt.SIGNAL_LONGEXIT,
168
backtrader’s documentation Version-1.9.58.122
'shortexit': bt.SIGNAL_LONGEXIT,
}
class SMACloseSignal(bt.Indicator):
lines = ('signal',)
params = (('period', 30),)
def __init__(self):
self.lines.signal = self.data - bt.indicators.SMA(period=self.p.period)
class SMAExitSignal(bt.Indicator):
lines = ('signal',)
params = (('p1', 5), ('p2', 30),)
def __init__(self):
sma1 = bt.indicators.SMA(period=self.p.p1)
sma2 = bt.indicators.SMA(period=self.p.p2)
self.lines.signal = sma1 - sma2
def runstrat(args=None):
args = parse_args(args)
cerebro = bt.Cerebro()
cerebro.broker.set_cash(args.cash)
dkwargs = dict()
if args.fromdate is not None:
fromdate = datetime.datetime.strptime(args.fromdate, '%Y-%m-%d')
dkwargs['fromdate'] = fromdate
cerebro.add_signal(MAINSIGNALS[args.signal],
SMACloseSignal, period=args.smaperiod)
169
backtrader’s documentation Version-1.9.58.122
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 Signal concepts')
parser.add_argument('--data', required=False,
default='../../datas/2005-2006-day-001.txt',
help='Specific data to be read in')
170
backtrader’s documentation Version-1.9.58.122
# 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'))
return parser.parse_args()
if __name__ == '__main__':
runstrat()
Broker
Reference
class backtrader.brokers.BackBroker
Broker Simulator
• Market: to be executed with the 1st tick of the next bar (namely the open price)
• Close: meant for intraday in which the order is executed with the closing price of the last bar of
the session
• Limit: executes if the given limit price is seen during the session
• Stop: executes a Market order if the given stop price is seen
• StopLimit: sets a Limit order in motion if the given stop price is seen
1. Manually create an instance of this class with the desired params and use cerebro.broker =
instance to set the instance as the broker for the run execution
2. Use the set_xxx to set the value using cerebro.broker.set_xxx where `xxx stands for the name of
the parameter to set
Note
Params:
172
backtrader’s documentation Version-1.9.58.122
Note:
o 0.01 is 1%
o 0.001 is 0.1%
• slip_fixed (default: 0.0) Percentage in units (and positive) that
should be used to slip prices up/down for buy/sell orders
This also applies to some of the other executions, because the logic
tries to detect if the opening price would match the requested
price/execution type when moving to a new bar.
173
backtrader’s documentation Version-1.9.58.122
If False the broker will not match the order with the current prices
and will try execution during the next iteration
Limit orders, given the exact match price requested, will be matched
even if slip_match is False.
If False and slippage exceeds the cap, then there will be no match
Provide slippage even if the price falls outside the high - low
range.
matching a Market order to the closing price of the bar in which the order
was issued. This is actually cheating, because the bar is closed and any
order should first be matched against the prices in the next bar
matching a Market order to the opening price, by for example using a timer
with cheat set to True, because such a timer gets executed before the
broker has evaluated
If False then the cash will be deducted as operation cost and the
calculated value will be positive to end up with the same amount
This parameter controls the start value for measuring the performance
in a fund-like way, i.e.: cash can be added and deducted increasing
the amount of shares. Performance is not measured using the net asset
value of the porftoflio but using the value of the fund
set_cash(cash)
get_cash()
Returns the portfolio value of the given datas (if datas is None, then the
total portfolio value will be returned (alias: getvalue)
set_eosbar(eosbar)
set_checksubmit(checksubmit)
set_filler(filler)
175
backtrader’s documentation Version-1.9.58.122
set_coc(coc)
set_coo(coo)
set_int2pnl(int2pnl)
set_fundstartval(fundstartval)
get_orders_open(safe=False)
Returns an iterable with the orders which are still open (either not
executed or partially executed
getcommissioninfo(data)
If name is None, this will be the default for assets for which no other
CommissionInfo scheme can be found
176
backtrader’s documentation Version-1.9.58.122
addcommissioninfo(comminfo, name=None)
Adds a CommissionInfo object that will be the default for all assets if
name is None
getposition(data)
Returns the current position status (a Position instance) for the given
data
get_fundshares()
get_fundvalue()¶
Slippage
backtesting cannot guarantee real market conditions. No matter how good the
market simulation is, under real market conditions slippage can happen. That
means:
The integrated backtesting broker supports slippage. The following parameters can
be passed to the broker
Note:
o 0.01 is 1%
o 0.001 is 0.1%
• slip_fixed (default: 0.0) Percentage in units (and positive) that should be
used to slip prices up/down for buy/sell orders
• slip_open (default: False) whether to slip prices for order execution which
would specifically used the opening price of the next bar. An example would
be Market order which is executed with the next available tick, i.e: the
opening price of the bar.
177
backtrader’s documentation Version-1.9.58.122
This also applies to some of the other executions, because the logic tries
to detect if the opening price would match the requested price/execution
type when moving to a new bar.
If False the broker will not match the order with the current prices and
will try execution during the next iteration
Limit orders, given the exact match price requested, will be matched even
if slip_match is False.
If True, then Limit orders will be matched by capping prices to the limit /
high/low prices
If False and slippage exceeds the cap, then there will be no match
Provide slippage even if the price falls outside the high - low range.
How it works
In order to decide when to apply slippage the order execution type is taken into
account:
This order is matched against the close price and this price is the last
one of the day. Slippage cannot happen because the order can only happen
with the last tick of the session and this is a unique price with no
tolerance.
Please check the slip_open exception. Because Market orders will be matched
against the opening price of the next bar.
178
backtrader’s documentation Version-1.9.58.122
This approach tries to offer the most realistic possible approach within the
limits of the simulation and available data
Configuring slippage
A broker is already instantiated by a cerebro engine for each run with the
default parameters. There are two ways to alter the behavior:
Practical examples
The sources contain a sample which uses the order execution type Market and a
long/short approach using signals. This should allow to understand the logic.
179
backtrader’s documentation Version-1.9.58.122
$ ./slippage.py --plot
01 2005-03-22 23:59:59 SELL Size: -1 / Price: 3040.55
02 2005-04-11 23:59:59 BUY Size: +1 / Price: 3088.47
03 2005-04-11 23:59:59 BUY Size: +1 / Price: 3088.47
04 2005-04-19 23:59:59 SELL Size: -1 / Price: 2948.38
05 2005-04-19 23:59:59 SELL Size: -1 / Price: 2948.38
06 2005-05-19 23:59:59 BUY Size: +1 / Price: 3034.88
...
35 2006-12-19 23:59:59 BUY Size: +1 / Price: 4121.01
180
backtrader’s documentation Version-1.9.58.122
The Market orders are matched against the opening price of the next bar and
we are not allowing the open price to be moved.
And one can immediately see tht the prices HAVE MOVED. And the allocated prices
are worst or equal like for operation 35. This is not a copy and paste error
The price cannot be pushed above the high because that would mean returning
a non-existent price.
Of course, backtrader allows to match outide the high - low range if wished with
slip_out. A run with it activated:
181
backtrader’s documentation Version-1.9.58.122
A matching expression for the matched prices would be: OMG! (Oh My God!). The
prices are clearly outside of the range. Suffice to look at operation 35, which
has been matched at 4182.83. A quick inspection of the chart in this document
shows that the asset never came close to that price.
slip_match has a default of True and that means that backtrader offers a match,
be it with capped or uncapped prices as seen above. Let’s disable it:
Deactivating slip_match disallows matching operations if slippage would push the matching price above the high or
below the low of the bar. It seems that with the 1.5% of requested slippage, around 22 of the operations fail to be
executed.
The examples should have shown how the different slippage options work together.
Fillers
The backtrader broker simulation has a default strategy when it comes to using
volume for order execution:
• Ignore volume
182
backtrader’s documentation Version-1.9.58.122
A quick example is a Fill or Kill order. Even down to the tick resolution
and with enough volume for a fill, the backtrader broker cannot know how
many extra actors happen to be in the market to discriminate if such an
order would be or would not be matched to stick to the Fill part or if the
order should be Kill
But the broker can accept Volume Fillers which determine how much of the volume
at a given point in time has to be used for order matching.
A filler in the backtrader ecosystem can be any callable which matches the
following signature:
Where:
This object gives access to the data object which is the target of the
operation, creation sizes/prices, execution prices/sizes/remaining sizes
and other details
In almost all cases this will be 0 (current point in time) but in a corner
case to cover Close orders this may be -1
barvolume = order.data.volume[ago]
class MyFiller(object):
def __call__(self, order, price, ago):
pass
183
backtrader’s documentation Version-1.9.58.122
import backtrader as bt
cerebro = Cerebro()
cerebro.broker.set_filler(bt.broker.fillers.FixedSize())
The second choice is to completely replace the broker, although this is probably
only meant for subclasses of BrokerBack which have rewritten portions of the
functionality:
import backtrader as bt
cerebro = Cerebro()
filler = bt.broker.fillers.FixedSize()
newbroker = bt.broker.BrokerBack(filler=filler)
cerebro.broker = newbroker
The sample
The backtrader sources contain a sample named volumefilling which allows to test
some of the integrated fillers (initially all)
Reference
class backtrader.fillers.FixedSize
Returns the execution size for a given order using a percentage of the
volume in a bar.
Params:
class backtrader.fillers.FixedBarPerc
184
backtrader’s documentation Version-1.9.58.122
Returns the execution size for a given order using a percentage of the
volume in a bar.
Params:
class backtrader.fillers.BarPointPerc
Returns the execution size for a given order. The volume will be
distributed uniformly in the range high-low using minmov to partition.
From the allocated volume for the given price, the perc percentage will be
used
Params:
Orders
Cerebro is the key control system in backtrader and Strategy (a subclass) is the
key control point of the end user. The latter needs a chaining method to other
parts of the system and that’s where orders play a key role.
Orders translate the decisions made by the logic in a Strategy into a message
suitable for the Broker to execute an action. This is done with:
• Creation
Through Strategy’s methods: buy`, sell and close (Strategy) which return
an order instance as a reference
185
backtrader’s documentation Version-1.9.58.122
• Cancellation
And the orders serve also as a communication method back to the user, to notify
how things are running in the broker.
• Notification
Order creation
When invoking the buy, sell and close the following parameters apply for
creation:
For which data the order has to be created. If None then the first data in
the system, self.datas[0] or self.data0 (aka self.data) will be used
If None the sizer instance retrieved via getsizer will be used to determine
the size.
Price to use (live brokers may place restrictions on the actual format if
it does not comply to minimum tick size requirements)
None is valid for Market and Close orders (the market determines the price)
For Limit, Stop and StopLimit orders this value determines the trigger
point (in the case of Limit the trigger is obviously at which price the
order should be matched)
Only applicable to StopLimit orders. This is the price at which to set the
implicit Limit order, once the Stop has been triggered (for which price has
been used)
186
backtrader’s documentation Version-1.9.58.122
Possible values:
o Order.Market or None. A market order will be executed with the next available price. In
backtesting it will be the opening price of the next bar
o Order.Limit. An order which can only be executed at the given price or better
o Order.Stop. An order which is triggered at price and executed like an Order.Market order
o Order.StopLimit. An order which is triggered at price and executed as an implicit Limit order with
price given by pricelimit
• valid (default: None)
Possible values:
o None: this generates an order that will not expire (aka Good till cancel) and remain in the market
until matched or canceled. In reality brokers tend to impose a temporal limit, but this is usually so
far away in time to consider it as not expiring
o datetime.datetime or datetime.date instance: the date will be used to generate an order valid
until the given datetime (aka good till date)
o Order.DAY or 0 or timedelta(): a day valid until the End of the Session (aka day order) will be
generated
o numeric value: This is assumed to be a value corresponding to a datetime in matplotlib coding
(the one used by backtrader) and will used to generate an order valid until that time (good till
date)
• tradeid (default: 0)
This would override the settings created by backtrader and generate a LIMIT
IF TOUCHED order with a touched price of 9.8 and a limit price of 10.0.
Note
187
backtrader’s documentation Version-1.9.58.122
The close method will examine the current position and correspondingly use buy or
sell to effectively close the position. size will also be automatically
calculated unless the parameter is an input from the user, in which case a
partial close or a reversal can be achieved
Order notification
An order may be submitted to the broker and be accepted and its execution
completed before next will be invoked again.
In this case at least 3 notifications will happen with the following status
values:
Notifications may happen even several times for the same status in the case of
Order.Partial. This status will not be seen in the backtesting broker (which
doesn’t consider volume when matching) but it will for sure be set by real
brokers.
Real brokers may issue one or more executions before updating a position, and
this group of executions will make up for an Order.Partial notification.
The values at the time of creation are stored in order.created which remains
unchanged throughout the lifecycle of an order
188
backtrader’s documentation Version-1.9.58.122
The reason will be notified via the notify_store method of the strategy.
Although this may seem awkward, the reason is that real life brokers will
notify this over an event, which may or may not be direclty related to the
order. But the notification from the broker can still be seen in
notify_store.
• Order.Margin: the order execution would imply a margin call and the
previously accepted order has been taken off the system
• Order.Cancelled (or Order.Canceled): confirmation of the user requested
cancellation
It must be taken into account that a request to cancel an order via the
cancel method of the strategy is no guarantee of cancellation. The order
may have been already executed but such execution may not have yet notified
by the broker and/or the notification may not have yet been delivered to
the strategy
189
backtrader’s documentation Version-1.9.58.122
These objects are the generic classes in the backtrader ecosystem. They may been
extended and/or contain extra embedded information when operating with other
brokers. See the reference of the appropriate broker
class backtrader.order.Order
This can happen during order submission (and therefore the order will
not reach the Accepted status) or before execution with each new bar
price because cash has been drawn by other sources (future-like
instruments may have reduced the cash or orders orders may have been
executed)
Member Attributes:
User Methods:
190
backtrader’s documentation Version-1.9.58.122
In the case of Creation the request made and in the case of Execution the
actual outcome.
Member Attributes:
Member Attributes:
Backtesting, and hence backtrader, would not be complete if orders could not be
simulated. To do so, the following is available in the platform.
• buy
• sell
• cancel
Note
An update primitive is obviously something logic but common sense dictates that
such a method is mostly used by manual operators working with a judgmental
trading approach.
• Market
• Close
• Limit
• Stop
• StopLimit
Order Management
Some examples:
# buy the main date, with sizer default stake, Market order
order = self.buy()
# Limit order - want to set the price and can set a validity
order = self.buy(exectype=Order.Limit,
192
backtrader’s documentation Version-1.9.58.122
price=self.data.close[0] * 1.02,
valid=datetime.datetime.now() + datetime.timedelta(days=3)))
Note
All order types can be create by creating an Order instance (or one of its
subclasses) and then passed to to the broker with:
order = self.broker.submit(order)
Note
There are buy and sell primitives in the broker itself, but they are less
forgiving with regards to default parameters.
• The current data has already happened and cannot be used to execcute an
order.
The expectation CANNOT be that the order will be executed with the
``close`` price which is being examined in the logic BECAUSE it has already
happened.
The order CAN BE 1st EXECUTED withing the bounds of the next set of
Open/High/Low/Close price points (and the conditions set forth herein by
the order)
193
backtrader’s documentation Version-1.9.58.122
It actually does in real trading if the trader goes for non-liquid assets
or precisely the extremes (high/low) of a price bar are hit.
But hitting the high/low points is a seldom occurrence (if you do ... you
don’t need backtrader) and the chosen assets will have enough liquidity to
absorb the orders of any regular trading
Market
Execution:
• Opening price of the next set of Open/High/Low/Close prices (commonly referred as bar)
Rationale:
• If the logic has executed at point X in time and issued a Market order, the next price spot that will happen
is the upcoming open price
Note
This order executes always and disregards any price and valid parameters used to
create it
Close
Execution:
• Using the close price of the next barwhen the next bar actually CLOSES
Rationale:
• Most backtesting feeds contain already closed bars and the order will
execute immediately with the close price of the next bar. A daily data feed
is the most common example.
But the system could be fed with “tick” prices and the actual bar
(time/date wise) is being udpated constantly with the new ticks, without
actually moving to the next bar (because time and/or date have not changed)
Only when the time or date changes, the bar has actually been closed and
the order gets executed
194
backtrader’s documentation Version-1.9.58.122
Limit
Execution:
• The price set at order creation if the data touches it, starting with the
next price bar.
The order will be canceled if valid is set and the time point is reached
Price Matching:
o Case 1:
If the open price of the bar is below the limit price the order
executes immediately with the open price. The order has been swept
during the opening phase of the session
o Case 2:
If the open price has not penetrated below the limit price but the
low price is below the limit price, then the limit price has been
seen during the session and the order can be executed
Stop
Execution:
• The trigger price set at order creation if the data touches it, starting
with the next price bar.
The order will be canceled if valid is set and the time point is reached
Price Matching:
195
backtrader’s documentation Version-1.9.58.122
• backtrader tries to provide most realistic trigger price for Stop orders.
o Case 1:
If the open price of the bar is above the stop price the order is
executed immediately with the open price.
o Case 2:
If the open price has not penetrated above the stop price but the
high price is above the stop price, then the stop price has been seen
during the session and the order can be executed
StopLimit
Execution:
• The trigger price sets the order in motion starting with the next price bar.
Price Matching:
• Trigger: Uses the Stop matching logic (but only triggers and turns the order into a Limit order)
• Limit: Uses the Limit price matching logic
Some samples
As always pictures (with code) are worth several million long explanations.
Please note that the snippets concentrate on the order creation part. The full
code is at the bottom.
A price closes above/below a simple moving average strategy will be used for the
generation of the buy/sell signals
196
backtrader’s documentation Version-1.9.58.122
The signal is seen at the bottom of the charts: the CrossOver using the crossover
indicator.
See in the chart how how the orders are executed one bar after the signal is
generated with the opening price.
if self.p.exectype == 'Market':
self.buy(exectype=bt.Order.Market) # default if not given
197
backtrader’s documentation Version-1.9.58.122
198
backtrader’s documentation Version-1.9.58.122
Now the orders are also executed one bar after the signal but with the closing
price.
199
backtrader’s documentation Version-1.9.58.122
Validity is being calculated some lines before in case it has been passed as
argument.
if self.p.valid:
valid = self.data.datetime.date(0) + \
datetime.timedelta(days=self.p.valid)
else:
valid = None
A limit price 1% below the signal generation price (the close at the signal bar)
is set. Notice how this prevents many from the orders above from being executed.
if self.p.valid:
txt = 'BUY CREATE, exectype Limit, price %.2f, valid: %s'
self.log(txt % (price, valid.strftime('%Y-%m-%d')))
200
backtrader’s documentation Version-1.9.58.122
else:
txt = 'BUY CREATE, exectype Limit, price %.2f'
self.log(txt % price)
Just 4 orders have been issued. Limiting the price trying to catch a small dip
has completly changed the output.
201
backtrader’s documentation Version-1.9.58.122
To not wait forever on a limit order which may only execute when the price is
moving against the “buy” order, the order will only be valid 4 (calendar) days.
202
backtrader’s documentation Version-1.9.58.122
More orders have been generated, but all but one “buy” order expired, further
limiting the amount of operations.
204
backtrader’s documentation Version-1.9.58.122
A stop price 1% above the signal price is set. That means that the strategy only
buys if the signal is generated and the price continues climbing up, which could
be intrepreted as a signal of strength.
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)
205
backtrader’s documentation Version-1.9.58.122
206
backtrader’s documentation Version-1.9.58.122
A stop price 1% above the signal price is set. But the limit price is set 0.5%
above the signal (close) price which could be interpreted as: wait for the
strength to show up but do not buy the peak. Wait for a dip.
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))
207
backtrader’s documentation Version-1.9.58.122
$ ./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]
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
209
backtrader’s documentation Version-1.9.58.122
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),
)
210
backtrader’s documentation Version-1.9.58.122
if order.status in [order.Expired]:
self.log('BUY EXPIRED')
else: # Sell
self.log('SELL EXECUTED, Price: %.2f, Cost: %.2f, Comm %.2f' %
(order.executed.price,
order.executed.value,
order.executed.comm))
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)
self.order = None
def next(self):
if self.order:
# An order is pending ... nothing can be done
return
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'
212
backtrader’s documentation Version-1.9.58.122
self.log(txt % price)
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)
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,
213
backtrader’s documentation Version-1.9.58.122
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')
default='../../datas/2006-day-001.txt',
help='File to be read in')
return parser.parse_args()
if __name__ == '__main__':
runstrat()
OCO orders
Release 1.9.34.116 adds OCO (aka One Cancel Others) to the backtesting arsenal.
Note
Note
The usage pattern tries to remain user friendly. As such and if the logic in the
strategy has decided it is the moment to issue orders, using OCO can be done like
this:
def next(self):
...
o1 = self.buy(...)
...
o2 = self.buy(..., oco=o1)
...
o3 = self.buy(..., oco=o1) # or even oco=o2, o2 is already in o1 group
Easy. The 1st order o1 will something like the group leader. o2 and o3 become
part of the OCO Group by specifying o1 with the oco named argument. See that the
comment in the snippet indicates that o3 could have also become part of the group
by specifying o2 (which as already part of the group)
216
backtrader’s documentation Version-1.9.58.122
• If any order in the group is executed, cancelled or expires, the other orders will be cancelled
The sample below puts the OCO concept in play. A standard execution with a plot:
Note
cash is increased to 50000, because the asset reaches values of 4000 and 3 orders
of 1 item would require at least 12000 monetary units (the default in the broker
is 10000)
which actually doesn’t provide much information (it is a standard SMA Crossover
strategy). The sample does the following:
217
backtrader’s documentation Version-1.9.58.122
• When the fast SMA crosses the slow SMA to the upside 3 orders are issued
• order1 is a Limit order which will expire in limdays days (parameter to the strategy) with the close price
reduced by a percentage as the limit price
• order2 is a Limit order with a much longer period to expire and a much more reduced limit price.
• order3 is a Limit order which further reduces the limit price
As such the execution of order2 and order3 is not going to happen because:
• order1 will be executed first and this should trigger the cancellation of the others
or
• order1 will expire and this will trigger the the cancellation of the others
The system keeps the ref identifier of the 3 orders and will only issue new buy
orders if the three ref identifiers are seen in notify_order as either Completed,
Cancelled, Margin or Expired
Exiting is simply done after holding the position for some bars.
To try to keep track of the actual execution, textual output is produced. Some of
it:
• The 1st batch of orders is issued. Order 1 expires and 2 and 3 are cancelled. As expected.
• Some months later another batch of 3 orders is issued. In this case Order 49 gets Completed and 50 and
51 are immediately cancelled
• The last batch is just like the 1st
And that’s it, which isn’t much (no order execution, not much need for a chart
either)
219
backtrader’s documentation Version-1.9.58.122
• Order 1 expires, but because the strategy has gotten the parameter do_oco=False, orders 2 and 3 are not
made part of the OCO group
• Orders 2 and 3 are therefore not cancelled and because the default expiration delta is 1000 days later,
they never expire with the available data for the sample (2 years of data)
• The system never issues a 2nd bath of orders.
Sample usage
$ ./oco.py --help
usage: oco.py [-h] [--data0 DATA0] [--fromdate FROMDATE] [--todate TODATE]
[--cerebro kwargs] [--broker kwargs] [--sizer kwargs]
[--strat kwargs] [--plot [kwargs]]
Sample Skeleton
optional arguments:
-h, --help show this help message and exit
--data0 DATA0 Data to read in (default:
../../datas/2005-2006-day-001.txt)
--fromdate FROMDATE Date[time] in YYYY-MM-DD[THH:MM:SS] format (default: )
--todate TODATE Date[time] in YYYY-MM-DD[THH:MM:SS] format (default: )
--cerebro kwargs kwargs in key=value format (default: )
--broker kwargs kwargs in key=value format (default: )
--sizer kwargs kwargs in key=value format (default: )
--strat kwargs kwargs in key=value format (default: )
--plot [kwargs] kwargs in key=value format (default: )
Sample Code
import argparse
import datetime
import backtrader as bt
class St(bt.Strategy):
params = dict(
ma=bt.ind.SMA,
p1=5,
220
backtrader’s documentation Version-1.9.58.122
p2=15,
limit=0.005,
limdays=3,
limdays2=1000,
hold=10,
switchp1p2=False, # switch prices of order1 and order2
oco1oco2=False, # False - use order1 as oco for order3, else order2
do_oco=True, # use oco or not
)
if order.status == order.Completed:
self.holdstart = len(self)
def __init__(self):
ma1, ma2 = self.p.ma(period=self.p.p1), self.p.ma(period=self.p.p2)
self.cross = bt.ind.CrossOver(ma1, ma2)
self.orefs = list()
def next(self):
if self.orefs:
return # pending orders do nothing
if not self.position:
if self.cross > 0.0: # crossing up
if self.p.switchp1p2:
p1, p2 = p2, p1
o1 = self.buy(exectype=bt.Order.Limit, price=p1,
valid=datetime.timedelta(self.p.limdays))
221
backtrader’s documentation Version-1.9.58.122
if self.p.do_oco:
oco3 = o1 if not self.p.oco1oco2 else oco2
else:
oco3 = None
o3 = self.buy(exectype=bt.Order.Limit, price=p3,
valid=datetime.timedelta(self.p.limdays2),
oco=oco3)
def runstrat(args=None):
args = parse_args(args)
cerebro = bt.Cerebro()
# Parse from/to-date
dtfmt, tmfmt = '%Y-%m-%d', 'T%H:%M:%S'
for a, d in ((getattr(args, x), x) for x in ['fromdate', 'todate']):
if a:
strpfmt = dtfmt + tmfmt * ('T' in a)
222
backtrader’s documentation Version-1.9.58.122
# Data feed
data0 = bt.feeds.BacktraderCSVData(dataname=args.data0, **kwargs)
cerebro.adddata(data0)
# Broker
cerebro.broker = bt.brokers.BackBroker(**eval('dict(' + args.broker + ')'))
# Sizer
cerebro.addsizer(bt.sizers.FixedSize, **eval('dict(' + args.sizer + ')'))
# Strategy
cerebro.addstrategy(St, **eval('dict(' + args.strat + ')'))
# Execute
cerebro.run(**eval('dict(' + args.cerebro + ')'))
def parse_args(pargs=None):
parser = argparse.ArgumentParser(
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
description=(
'Sample Skeleton'
)
)
parser.add_argument('--data0', default='../../datas/2005-2006-day-001.txt',
required=False, help='Data to read in')
return parser.parse_args(pargs)
if __name__ == '__main__':
runstrat()
StopTrail(Limit)
Release 1.9.35.116 adds the StopTrail and StopTrailLimit order execution types to
the backtesting arsenal.
Note
Note
The usage pattern is fully integrated into the standard buy, sell and close
market operation methods of the strategy instances. To notice:
224
backtrader’s documentation Version-1.9.58.122
• And whether the trailing price must be calculated with a fixed distance or with a percentage based
distance
o Fixed distance: trailamount=10
o Percentage based distance: trailpercent=0.02 (i.e.: 2%)
If one has entered the market long by issuing a buy, this is what a sell with
StopTrail and trailamount does:
That is: the trailing stop price follows the price upwards, but remains fixed if
the prices start falling, to potentially secure a profit.
If one had entered the market with a sell, then issuing a buy order with
StopTrail simply does the opposite, i.e.: prices are followed downwards.
One can also specify trailpercent instead of trailamount and the distance to the
price will be calculated as a percentage of the price
For a StopTrailLimit
• The only difference is what happens when the trailing stop price is
triggered.
• In this case the order is executed as a Limit order (the same behavior a
StopLimit order has, but in this case with a dynamic triggering price)
Note
one has to specify plimit=x.x to buy or sell, which will be the limit price
Note
the limit price is not changed dynamically like the stop/trigger price
An example is always worth a thousand words and hence the usual backtrader
sample, which
226
backtrader’s documentation Version-1.9.58.122
**************************************************
2005-02-14,3075.76,3025.76,3025.76
----------
2005-02-15,3086.95,3036.95,3036.95
2005-02-16,3068.55,3036.95,3018.55
2005-02-17,3067.34,3036.95,3017.34
2005-02-18,3072.04,3036.95,3022.04
2005-02-21,3063.64,3036.95,3013.64
...
...
**************************************************
2005-05-19,3051.79,3001.79,3001.79
----------
2005-05-20,3050.45,3001.79,3000.45
2005-05-23,3070.98,3020.98,3020.98
227
backtrader’s documentation Version-1.9.58.122
2005-05-24,3066.55,3020.98,3016.55
2005-05-25,3059.84,3020.98,3009.84
2005-05-26,3086.08,3036.08,3036.08
2005-05-27,3084.0,3036.08,3034.0
2005-05-30,3096.54,3046.54,3046.54
2005-05-31,3076.75,3046.54,3026.75
2005-06-01,3125.88,3075.88,3075.88
2005-06-02,3131.03,3081.03,3081.03
2005-06-03,3114.27,3081.03,3064.27
2005-06-06,3099.2,3081.03,3049.2
2005-06-07,3134.82,3084.82,3084.82
2005-06-08,3125.59,3084.82,3075.59
2005-06-09,3122.93,3084.82,3072.93
2005-06-10,3143.85,3093.85,3093.85
2005-06-13,3159.83,3109.83,3109.83
2005-06-14,3162.86,3112.86,3112.86
2005-06-15,3147.55,3112.86,3097.55
2005-06-16,3160.09,3112.86,3110.09
2005-06-17,3178.48,3128.48,3128.48
2005-06-20,3162.14,3128.48,3112.14
2005-06-21,3179.62,3129.62,3129.62
2005-06-22,3182.08,3132.08,3132.08
2005-06-23,3190.8,3140.8,3140.8
2005-06-24,3161.0,3140.8,3111.0
...
...
...
**************************************************
2006-12-19,4100.48,4050.48,4050.48
----------
2006-12-20,4118.54,4068.54,4068.54
2006-12-21,4112.1,4068.54,4062.1
2006-12-22,4073.5,4068.54,4023.5
2006-12-27,4134.86,4084.86,4084.86
2006-12-28,4130.66,4084.86,4080.66
2006-12-29,4119.94,4084.86,4069.94
Rather than waiting for the usual cross down pattern the system uses the trailing
stop to exit the market. Let’s see the 1st operation for example
• The closing price goes up to 3086.95 and the stop price is adjusted to 3036.95
• The following closing prices don’t exceed 3086.95 and the trigger price doesn’t change
For the sake of comparison, an execution with just 30 points of fixed distance
(just the chart)
229
backtrader’s documentation Version-1.9.58.122
$ ./trail.py --help
usage: trail.py [-h] [--data0 DATA0] [--fromdate FROMDATE] [--todate TODATE]
[--cerebro kwargs] [--broker kwargs] [--sizer kwargs]
[--strat kwargs] [--plot [kwargs]]
StopTrail Sample
optional arguments:
-h, --help show this help message and exit
--data0 DATA0 Data to read in (default:
../../datas/2005-2006-day-001.txt)
--fromdate FROMDATE Date[time] in YYYY-MM-DD[THH:MM:SS] format (default: )
--todate TODATE Date[time] in YYYY-MM-DD[THH:MM:SS] format (default: )
--cerebro kwargs kwargs in key=value format (default: )
--broker kwargs kwargs in key=value format (default: )
230
backtrader’s documentation Version-1.9.58.122
import argparse
import datetime
import backtrader as bt
class St(bt.Strategy):
params = dict(
ma=bt.ind.SMA,
p1=10,
p2=30,
stoptype=bt.Order.StopTrail,
trailamount=0.0,
trailpercent=0.0,
)
def __init__(self):
ma1, ma2 = self.p.ma(period=self.p.p1), self.p.ma(period=self.p.p2)
self.crup = bt.ind.CrossUp(ma1, ma2)
self.order = None
def next(self):
if not self.position:
if self.crup:
o = self.buy()
self.order = None
print('*' * 50)
if self.p.trailamount:
tcheck = self.data.close - self.p.trailamount
231
backtrader’s documentation Version-1.9.58.122
else:
tcheck = self.data.close * (1.0 - self.p.trailpercent)
print(','.join(
map(str, [self.datetime.date(), self.data.close[0],
self.order.created.price, tcheck])
)
)
print('-' * 10)
else:
if self.p.trailamount:
tcheck = self.data.close - self.p.trailamount
else:
tcheck = self.data.close * (1.0 - self.p.trailpercent)
print(','.join(
map(str, [self.datetime.date(), self.data.close[0],
self.order.created.price, tcheck])
)
)
def runstrat(args=None):
args = parse_args(args)
cerebro = bt.Cerebro()
# Parse from/to-date
dtfmt, tmfmt = '%Y-%m-%d', 'T%H:%M:%S'
for a, d in ((getattr(args, x), x) for x in ['fromdate', 'todate']):
if a:
strpfmt = dtfmt + tmfmt * ('T' in a)
kwargs[d] = datetime.datetime.strptime(a, strpfmt)
# Data feed
data0 = bt.feeds.BacktraderCSVData(dataname=args.data0, **kwargs)
cerebro.adddata(data0)
# Broker
cerebro.broker = bt.brokers.BackBroker(**eval('dict(' + args.broker + ')'))
# Sizer
cerebro.addsizer(bt.sizers.FixedSize, **eval('dict(' + args.sizer + ')'))
232
backtrader’s documentation Version-1.9.58.122
# Strategy
cerebro.addstrategy(St, **eval('dict(' + args.strat + ')'))
# Execute
cerebro.run(**eval('dict(' + args.cerebro + ')'))
def parse_args(pargs=None):
parser = argparse.ArgumentParser(
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
description=(
'StopTrail Sample'
)
)
parser.add_argument('--data0', default='../../datas/2005-2006-day-001.txt',
required=False, help='Data to read in')
return parser.parse_args(pargs)
if __name__ == '__main__':
runstrat()
Bracket Orders
Release 1.9.37.116 adds bracket orders giving a very broad spectrum of orders
which are supported by the backtesting broker (Market, Limit, Close, Stop,
StopLimit, StopTrail, StopTrailLimit, OCO)
Note
This is implemented for backtesting and for the Interactivers Brokers store
With corresponding sell and 2 x buy orders for the short side.
The low/high side orders do actually create a bracket around the main side order.
• The 3 orders are submitted together to avoid having any of them triggered independently
• The low/high side orders are marked as children of the main side
• The children are not active until the main side is executed
• The cancellation of the main side cancels both the low and high side
• The execution of the main side activates both the low and high side
• Upon being active
o The execution or cancellation of any of low/high side orders automatically cancels the other
Usage Pattern
backtrader offers two new methods in the Strategy to control bracket orders.
Note
This should be enough. The actual target data would be data0 and the size would
be automatically determined by the default sizer. Of course both and many other
parameters can be specified to have a fine control of the execution.
Because when issuing a sell_bracket order, the low and high sides would be turned
aound, the parameters are named following convention stop and limit
• stop is meant to stop the losses (low side in a long operation, and high side in a short operation)
• limit is meant to take the profit (high side in a long operation and low side in a short operation)
This involves the generation of the 3 orders and playing around with the transmit
and parent arguments. The rules:
• The main side order must be created 1st and have transmit=False
• The low/high side orders must have parent=main_side_order
• The 1st low/high side order to be created must have transmit=False
• The last order to be created (either the low or high side) sets transmit=True
A practical example doing what the single command from above did:
transmit=False, parent=mainside)
highside = self.sell(price=14.00, size=mainsize.size, exectype=bt.Order.Limit,
transmit=True, parent=mainside)
• Keep track of the mainside order to indicate it is the parent of the others
• Control transmit to make sure only the last order triggers the joint
transmission
• Specify the execution types
• Specify the size for the low and high side
Because the size MUST be the same. If the parameter were not specified
manually and the end user had introduced a sizer, the sizer could actually
indicate a different value for the orders. That’s why it has to be
manually added to the calls after it has been set for the mainside order.
A sample of it
Running the sample from below produces this output (capped for brevity)
$ ./bracket.py --plot
• In the 1st case the main side order expired and this automatically
cancelled the other two
• In the 2nd case the main side order was completed and the low (stop in the
buy case) was executed limiting losses
• In the 3rd case the main side order was completed and the high side (limit)
was executed
This can be noticed because the Completed ids are 22 and 24 and the high
side order is being issued last, which means the non-executed low side
order has id 23.
Visually
237
backtrader’s documentation Version-1.9.58.122
It can be immediately seen that the losing trades align around the same value and
winning trades too, which is the purpose of the backeting. Controlling both
sides.
The sample as run issues the 3 orders manually, but it can be told to use
buy_bracket. Let’s see the output:
238
backtrader’s documentation Version-1.9.58.122
Some reference
For which data the order has to be created. If ``None`` then the
first data in the system, ``self.datas[0] or self.data0`` (aka
``self.data``) will be used
stop
Returns:
- A list containing the 3 bracket orders [order, stop side, limit
side]
'''
242
backtrader’s documentation Version-1.9.58.122
Returns:
- A list containing the 3 bracket orders [order, stop side, limit
side]
'''
Sample usage
$ ./bracket.py --help
usage: bracket.py [-h] [--data0 DATA0] [--fromdate FROMDATE] [--todate TODATE]
[--cerebro kwargs] [--broker kwargs] [--sizer kwargs]
[--strat kwargs] [--plot [kwargs]]
Sample Skeleton
optional arguments:
-h, --help show this help message and exit
--data0 DATA0 Data to read in (default:
../../datas/2005-2006-day-001.txt)
--fromdate FROMDATE Date[time] in YYYY-MM-DD[THH:MM:SS] format (default: )
--todate TODATE Date[time] in YYYY-MM-DD[THH:MM:SS] format (default: )
--cerebro kwargs kwargs in key=value format (default: )
--broker kwargs kwargs in key=value format (default: )
--sizer kwargs kwargs in key=value format (default: )
--strat kwargs kwargs in key=value format (default: )
--plot [kwargs] kwargs in key=value format (default: )
Sample Code
import argparse
import datetime
import backtrader as bt
class St(bt.Strategy):
params = dict(
ma=bt.ind.SMA,
243
backtrader’s documentation Version-1.9.58.122
p1=5,
p2=15,
limit=0.005,
limdays=3,
limdays2=1000,
hold=10,
usebracket=False, # use order_target_size
switchp1p2=False, # switch prices of order1 and order2
)
if order.status == order.Completed:
self.holdstart = len(self)
def __init__(self):
ma1, ma2 = self.p.ma(period=self.p.p1), self.p.ma(period=self.p.p2)
self.cross = bt.ind.CrossOver(ma1, ma2)
self.orefs = list()
if self.p.usebracket:
print('-' * 5, 'Using buy_bracket')
def next(self):
if self.orefs:
return # pending orders do nothing
if not self.position:
if self.cross > 0.0: # crossing up
close = self.data.close[0]
p1 = close * (1.0 - self.p.limit)
p2 = p1 - 0.02 * close
p3 = p1 + 0.02 * close
valid1 = datetime.timedelta(self.p.limdays)
244
backtrader’s documentation Version-1.9.58.122
if self.p.switchp1p2:
p1, p2 = p2, p1
valid1, valid2 = valid2, valid1
if not self.p.usebracket:
o1 = self.buy(exectype=bt.Order.Limit,
price=p1,
valid=valid1,
transmit=False)
o2 = self.sell(exectype=bt.Order.Stop,
price=p2,
valid=valid2,
parent=o1,
transmit=False)
o3 = self.sell(exectype=bt.Order.Limit,
price=p3,
valid=valid3,
parent=o1,
transmit=True)
else:
os = self.buy_bracket(
price=p1, valid=valid1,
stopprice=p2, stopargs=dict(valid=valid2),
limitprice=p3, limitargs=dict(valid=valid3),)
def runstrat(args=None):
args = parse_args(args)
cerebro = bt.Cerebro()
# Parse from/to-date
dtfmt, tmfmt = '%Y-%m-%d', 'T%H:%M:%S'
for a, d in ((getattr(args, x), x) for x in ['fromdate', 'todate']):
if a:
strpfmt = dtfmt + tmfmt * ('T' in a)
kwargs[d] = datetime.datetime.strptime(a, strpfmt)
# Data feed
data0 = bt.feeds.BacktraderCSVData(dataname=args.data0, **kwargs)
cerebro.adddata(data0)
# Broker
cerebro.broker = bt.brokers.BackBroker(**eval('dict(' + args.broker + ')'))
# Sizer
cerebro.addsizer(bt.sizers.FixedSize, **eval('dict(' + args.sizer + ')'))
# Strategy
cerebro.addstrategy(St, **eval('dict(' + args.strat + ')'))
# Execute
cerebro.run(**eval('dict(' + args.cerebro + ')'))
def parse_args(pargs=None):
parser = argparse.ArgumentParser(
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
description=(
'Sample Skeleton'
246
backtrader’s documentation Version-1.9.58.122
)
)
parser.add_argument('--data0', default='../../datas/2005-2006-day-001.txt',
required=False, help='Data to read in')
return parser.parse_args(pargs)
if __name__ == '__main__':
runstrat()
Release 1.9.32.116 adds support for an interesting use case presented in the
Community
247
backtrader’s documentation Version-1.9.58.122
The future expires on the same day the operation on the spot price takes
place
That means:
• The platform is fed with data points from two different assets
• The platform has to somehow understand the assets are related and that
operations on the spot price will close positions open on the future
Using that compensation concept, backtrader adds a way to let the user
communicate to the platform that things on one data feed will have compensating
effects on another. The usage pattern
import backtrader as bt
cerebro = bt.Cerebro()
data0 = bt.feeds.MyFavouriteDataFeed(dataname='futurename')
cerebro.adddata(data0)
data1 = bt.feeds.MyFavouriteDataFeed(dataname='spotname')
data1.compensate(data0) # let the system know ops on data1 affect data0
cerebro.adddata(data1)
...
cerebro.run()
An example is always worth a thousand posts, so let’s put all the pieces
together for it.
• Use one of the standard sample feeds from the backtrader sources. This will
be the future
248
backtrader’s documentation Version-1.9.58.122
• Simulate a similar but distinct price, by reusing the same feed and adding
a filter which will randomly move the price some points above/below, to
create a spread. As simple as:
• # The filter which changes the close price
• def close_changer(data, *args, **kwargs):
• data.close[0] += 50.0 * random.randint(-1, 1)
• return False # length of stream is unchanged
• Plotting on the same axis will mix the default included BuyObserver markers
and therefore the standard observers will be disabled and manually readded
to plot with different per-data markers
• Positions will be entered randomly and exited 10 days later
This doesn’t match future expiration periods, but this is just putting the
functionality in place and not checking a trading calendar
Note
The execution:
$ ./future-spot.py --no-comp
249
backtrader’s documentation Version-1.9.58.122
And it works:
• buy operations are signaled with a green triangle pointing upwards and the legend tells us they belong to
data0 as expected
• sell operations are signaled with an arrow pointing downwards and the legend tells us they belong to
data1 as expected
• Trades are being closed, even if they are being open with data0 and being closed with data1, achieving
the desired effect (which in real life is avoiding the physical delivery of the goods acquired by means of
the future)
One could only imagine what would happen if the same logic is applied without the
compensation taking place. Let’s do it:
$ ./future-spot.py --no-comp
• The logic expects positions on data0 to be closed by the operations on data1 and to only open positions
on data0 when not in the market
• But compensation has been deactivated and the intial operation on data0 (green triangle) is never closed,
so no other operation can never be initiated and short positions on data1 start accumulating.
Sample Usage
$ ./future-spot.py --help
usage: future-spot.py [-h] [--no-comp]
Compensation example
optional arguments:
-h, --help show this help message and exit
--no-comp
251
backtrader’s documentation Version-1.9.58.122
Sample Code
import argparse
import random
import backtrader as bt
class St(bt.Strategy):
def __init__(self):
bt.obs.BuySell(self.data0, barplot=True) # done here for
BuySellArrows(self.data1, barplot=True) # different markers per data
def next(self):
if not self.position:
if random.randint(0, 1):
self.buy(data=self.data0)
self.entered = len(self)
def runstrat(args=None):
args = parse_args(args)
cerebro = bt.Cerebro()
252
backtrader’s documentation Version-1.9.58.122
cerebro.broker.set_coc(True)
cerebro.run(stdstats=False) # execute
cerebro.plot(volume=False) # and plot
def parse_args(pargs=None):
parser = argparse.ArgumentParser(
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
description=('Compensation example'))
if __name__ == '__main__':
runstrat()
Data Feeds
backtrader comes with a set of Data Feed parsers (at the time of writing all CSV
Based) to let you load data from different sources.
253
backtrader’s documentation Version-1.9.58.122
From the Quickstart guide it should be clear that you add data feeds to a Cerebro
instance. The data feeds will later be available to the different strategies in:
import backtrader as bt
import backtrader.feeds as btfeeds
data = btfeeds.YahooFinanceCSVData(dataname='wheremydatacsvis.csv')
cerebro = bt.Cerebro()
This data feed can download data directly from Yahoo and feed into the system.
Parameters:
The meaning varies with the data feed type (file location, ticker, ...)
Python datetime object indicating that any datetime prior to this should be
ignored
Potential values: Ticks, Seconds, Minutes, Days, Weeks, Months and Years
• compression (default: 1)
Indication of session starting time for the data. May be used by classes
for purposes like resampling
Indication of session ending time for the data. May be used by classes for
purposes like resampling
GenericCSVData
This class exposes a generic interface allowing parsing mostly every CSV file
format out there.
Parses a CSV file according to the order and field presence defined by the
parameters
• dataname
• time (default: -1) column containing the time field if separate from the
datetime field (-1 indicates it’s not present)
• open (default: 1) , high (default: 2), low (default: 3), close (default:
4), volume (default: 5), openinterest (default: 6)
Value that will be used if a value which should be there is missing (the
CSV field is empty)
Format used to parse the time CSV field if “present” (the default for the
“time” CSV field is not to be present)
The code:
import datetime
import backtrader as bt
import backtrader.feeds as btfeeds
...
...
data = btfeeds.GenericCSVData(
dataname='mydata.csv',
fromdate=datetime.datetime(2000, 1, 1),
256
backtrader’s documentation Version-1.9.58.122
nullvalue=0.0,
dtformat=('%Y-%m-%d'),
datetime=0,
high=1,
low=2,
open=3,
close=4,
volume=5,
openinterest=-1
)
...
The code:
import datetime
import backtrader as bt
import backtrader.feeds as btfeed
...
...
data = btfeeds.GenericCSVData(
dataname='mydata.csv',
fromdate=datetime.datetime(2000, 1, 1),
todate=datetime.datetime(2000, 12, 31),
nullvalue=0.0,
dtformat=('%Y-%m-%d'),
tmformat=('%H.%M.%S'),
257
backtrader’s documentation Version-1.9.58.122
datetime=0,
time=1,
high=2,
low=3,
open=4,
close=5,
volume=6,
openinterest=-1
)
import datetime
import backtrader.feeds as btfeed
class MyHLOC(btfreeds.GenericCSVData):
params = (
('fromdate', datetime.datetime(2000, 1, 1)),
('todate', datetime.datetime(2000, 12, 31)),
('nullvalue', 0.0),
('dtformat', ('%Y-%m-%d')),
('tmformat', ('%H.%M.%S')),
('datetime', 0),
('time', 1),
('high', 2),
('low', 3),
('open', 4),
('close', 5),
('volume', 6),
('openinterest', -1)
)
This new class can be reused now by just providing the dataname:
data = btfeeds.MyHLOC(dataname='mydata.csv')
backtrader already offers a Generic CSV Data feed and some specific CSV Data
Feeds. Summarizing:
258
backtrader’s documentation Version-1.9.58.122
• GenericCSVData
• VisualChartCSVData
• YahooFinanceData (for online downloads)
• YahooFinanceCSVData (for already downloaded data)
• BacktraderCSVData (in-house ... for testing purposed, but can be used)
But even with that, the end user may wish to develop support for a specific CSV
Data Feed.
The usual motto would be: “It’s easier said than done”. Actually the structure
is meant to make it easy.
Steps:
As the name suggests this contains the tokens after the current line has
been splitten according to the separator parameter (inherited from the base
class)
If after doing its work there is new data ... fill up the corresponding
lines and return True
Returning False may not even be needed if the behind the scenes code which
is reading the file lines finds out there are no more lines to parse.
259
backtrader’s documentation Version-1.9.58.122
Note
backtrader data feeds contain the usual industry standard feeds, which are the
ones to be filled. Namely:
• datetime
• open
• high
• low
• close
• volume
• openinterest
If your strategy/algorithm or simple data perusal only needs, for example the
closing prices you can leave the others untouched (each iteration fills them
automatically with a float(‘NaN’) value before the end user code has a chance
to do anything.
import itertools
...
import backtrader as bt
class MyCSVData(bt.CSVDataBase):
def start(self):
# Nothing to do for this data feed type
pass
def stop(self):
# Nothing to do for this data feed type
pass
dttxt = linetokens[next(i)]
# Format is YYYY-MM-DD
y = int(dttxt[0:4])
m = int(dttxt[5:7])
d = int(dttxt[8:10])
260
backtrader’s documentation Version-1.9.58.122
dt = datetime.datetime(y, m, d)
dtnum = date2num(dt)
self.lines.datetime[0] = dtnum
self.lines.open[0] = float(linetokens[next(i)])
self.lines.high[0] = float(linetokens[next(i)])
self.lines.low[0] = float(linetokens[next(i)])
self.lines.close[0] = float(linetokens[next(i)])
self.lines.volume[0] = float(linetokens[next(i)])
self.lines.openinterest[0] = float(linetokens[next(i)])
return True
The code expects all fields to be in place and be convertible to floats, except
for the datetime which has a fixed YYYY-MM-DD format and can be parsed without
using datetime.datetime.strptime.
More complex needs can be covered by adding just a few lines of code to account
for null values, date format parsing. The GenericCSVData does that.
Caveat Emptor
Using the GenericCSVData existing feed and inheritance a lot can be acomplished
in order to support formats.
Let’s add support for Sierra Chart daily format (which is always stored in CSV
format).
The industry standard ones and the ones already supported by GenericCSVData
in the same order (which is also industry standard)
• Separator: ,
• Date Format: YYYY/MM/DD
class SierraChartCSVData(backtrader.feeds.GenericCSVData):
261
backtrader’s documentation Version-1.9.58.122
The params definition simply redefines one of the existing parameters in the base
class. In this case just the formatting string for dates needs a change.
class GenericCSVData(feed.CSVDataBase):
params = (
('nullvalue', float('NaN')),
('dtformat', '%Y-%m-%d %H:%M:%S'),
('tmformat', '%H:%M:%S'),
('datetime', 0),
('time', -1),
('open', 1),
('high', 2),
('low', 3),
('close', 4),
('volume', 5),
('openinterest', 6),
)
Note
The binary file used in the examples goog.fd belongs to VisualChart and cannot be
distributed with backtrader.
CSV Data feed development has shown how to add new CSV based data feeds. The
existing base class CSVDataBase provides the framework taking most of the work
off the subclasses which in most cases can simply do:
262
backtrader’s documentation Version-1.9.58.122
The base class takes care of the parameters, initialization, opening of files,
reading lines, splitting the lines in tokens and additional things like skipping
lines which don’t fit into the date range (fromdate, todate) which the end user
may have defined.
Developing a non-CSV datafeed follows the same pattern without going down to the
already splitted line tokens.
Things to do:
...
...
• dataname is what allows the data feed to identify how to fetch the data. In
the case of the CSVDataBase this parameter is meant to be a path to a file
or already a file-like object.
• fromdate and todate define the date range which will be passed to
strategies. Any value provided by the feed outside of this range will be
ignored
• name is cosmetic for plotting purposes
• timeframe indicates the temporal working reference
Potential values: Ticks, Seconds, Minutes, Days, Weeks, Months and Years
263
backtrader’s documentation Version-1.9.58.122
• compression (default: 1)
• compression
• sessionend if passed (a datetime.time object) will be added to the datafeed
datetime line which allows identifying the end of the session
Initialization
The binary VisualChart data files can contain either daily (.fd extension) or
intraday data (.min extension). Here the parameter timeframe will be used to
distinguish which type of file is being read.
During __init__ constants which differ for each type are set up.
def __init__(self):
super(VChartData, self).__init__()
264
backtrader’s documentation Version-1.9.58.122
Start
The Datafeed will be started when backtesting commences (it can actually be
started several times during optimizations)
In the start method the binary file is open unless a file-like object has been
passed.
def start(self):
# the feed must start ... get the file open (or see if it was open)
self.f = None
if hasattr(self.p.dataname, 'read'):
# A file has been passed in (ex: from a GUI)
self.f = self.p.dataname
else:
# Let an exception propagate
self.f = open(self.p.dataname, 'rb')
Stop
def stop(self):
# Close the file if any
if self.f is not None:
self.f.close()
self.f = None
Actual Loading
The actual work is done in _load. Called to load the next set of data, in this
case the next : datetime, open, high, low, close, volume, openinterest. In
backtrader the “actual” moment corresponds to index 0.
A number of bytes will be read from the open file (determined by the constants
set up during __init__), parsed with the struct module, further processed if
needed (like with divmod operations for date and time) and stored in the lines of
the data feed: datetime, open, high, low, close, volume, openinterest.
265
backtrader’s documentation Version-1.9.58.122
If no data can be read from the file it is assumed that the End Of File (EOF) has
been reached
• True is returned to indicate the loading of the data set was a success
def _load(self):
if self.f is None:
# if no file ... no parsing
return False
self.lines.datetime[0] = date2num(dt)
self.lines.volume[0] = v
self.lines.openinterest[0] = oi
# Say success
return True
• Database
• Hierarchical data storage
• Online source
• __init__ -> Any init code for the instance, only once
• start -> start of backtesting (one or more times if optimization will be
run)
This would for example open the connection to the database or a socket to
an online service
• stop -> clean-up like closing the database connection or open sockets
• _load -> query the database or online source for the next set of data and
load it into the lines of the object. The standard fields being: datetime,
open, high, low, close, volume, openinterest
VChartData Test
The VCharData loading data from a local ”.fd” file for Google for the year
2006.
It’s only about loading the data, so not even a subclass of Strategy is needed.
import datetime
import backtrader as bt
from vchart import VChartData
267
backtrader’s documentation Version-1.9.58.122
if __name__ == '__main__':
# Create a cerebro entity
cerebro = bt.Cerebro(stdstats=False)
# Add a strategy
cerebro.addstrategy(bt.Strategy)
###########################################################################
# Note:
# The goog.fd file belongs to VisualChart and cannot be distributed with
# backtrader
#
# VisualChart can be downloaded from www.visualchart.com
###########################################################################
# Create a Data Feed
datapath = '../../datas/goog.fd'
data = VChartData(
dataname=datapath,
fromdate=datetime.datetime(2006, 1, 1),
todate=datetime.datetime(2006, 12, 31),
timeframe=bt.TimeFrame.Days
)
268
backtrader’s documentation Version-1.9.58.122
import datetime
import struct
class VChartData(DataBase):
def __init__(self):
269
backtrader’s documentation Version-1.9.58.122
super(VChartData, self).__init__()
def start(self):
# the feed must start ... get the file open (or see if it was open)
self.f = None
if hasattr(self.p.dataname, 'read'):
# A file has been passed in (ex: from a GUI)
self.f = self.p.dataname
else:
# Let an exception propagate
self.f = open(self.p.dataname, 'rb')
def stop(self):
# Close the file if any
if self.f is not None:
self.f.close()
self.f = None
def _load(self):
if self.f is None:
# if no file ... no parsing
return False
y, md = divmod(bdata[0], 500)
# Months are stored as if they had 32 days
m, d = divmod(md, 32)
# put y, m, d in a datetime
dt = datetime.datetime(y, m, d)
self.lines.datetime[0] = date2num(dt)
# Say success
return True
Extending a Datafeed
• Can the end user easily extend the existing mechanisms to add extra information in the form of lines that
gets passed along other existing price information spots like open, high, etc?
271
backtrader’s documentation Version-1.9.58.122
Let’s build on the CSV Data Feed Development and GenericCSVData example posts.
Steps:
• Assume the P/E information is being set in the CSV data which is parsed
• Use GenericCSVData as the base class
• Extend the existng lines (open/high/low/close/volumen/openinterest) with pe
• Add a parameter to let the caller determine the column position of the P/E information
The result:
class GenericCSV_PE(GenericCSVData):
# Add a 'pe' line to the inherited ones from the base class
lines = ('pe',)
import backtrader as bt
....
class MyStrategy(bt.Strategy):
...
def next(self):
272
backtrader’s documentation Version-1.9.58.122
There is obviously no automated plot support for that extra line in the data
feed.
import backtrader as bt
import backtrader.indicators as btind
....
class MyStrategy(bt.Strategy):
def __init__(self):
...
def next(self):
Note
class PandasData(feed.DataBase):
'''
The ``dataname`` parameter inherited from ``feed.DataBase`` is the pandas
DataFrame
'''
params = (
# Possible values for datetime (must always be present)
# None : datetime is the "index" in the Pandas Dataframe
# -1 : autodetect position or case-wise equal name
# >= 0 : numeric index to the colum in the pandas dataframe
# string : column name (as index) in the pandas dataframe
('datetime', None),
The above excerpt from the PandasData class shows the keys:
• The dataname parameter to the class during instantiation holds the Pandas
Dataframe
• The new parameters have the names of the regular fields in the DataSeries
and follow these conventions
o datetime (default: None)
None : datetime is the “index” in the Pandas Dataframe
-1 : autodetect position or case-wise equal name
>= 0 : numeric index to the colum in the pandas dataframe
string : column name (as index) in the pandas dataframe
o open, high, low, high, close, volume, openinterest (default: -1 for all of them)
274
backtrader’s documentation Version-1.9.58.122
A small sample should be able to load the standar 2006 sample, having been parsed
by Pandas, rather than directly by backtrader
Running the sample to use the exiting “headers” in the CSV data:
$ ./panda-test.py
--------------------------------------------------
Open High Low Close Volume OpenInterest
Date
2006-01-02 3578.73 3605.95 3578.73 3604.33 0 0
2006-01-03 3604.08 3638.42 3601.84 3614.34 0 0
2006-01-04 3615.23 3652.46 3615.23 3652.46 0 0
$ ./panda-test.py --noheaders
--------------------------------------------------
1 2 3 4 5 6
0
2006-01-02 3578.73 3605.95 3578.73 3604.33 0 0
2006-01-03 3604.08 3638.42 3601.84 3614.34 0 0
2006-01-04 3615.23 3652.46 3615.23 3652.46 0 0
The backtrader support for Pandas tries to automatically detect if column names
have been used or else numeric indices and acts accordingly, trying to offer a
best match.
The following chart is the tribute to success. The Pandas Dataframe has been
correctly loaded (in both cases)
275
backtrader’s documentation Version-1.9.58.122
import argparse
import backtrader as bt
import backtrader.feeds as btfeeds
import pandas
def runstrat():
args = parse_args()
276
backtrader’s documentation Version-1.9.58.122
cerebro = bt.Cerebro(stdstats=False)
# Add a strategy
cerebro.addstrategy(bt.Strategy)
dataframe = pandas.read_csv(datapath,
skiprows=skiprows,
header=header,
parse_dates=True,
index_col=0)
if not args.noprint:
print('--------------------------------------------------')
print(dataframe)
print('--------------------------------------------------')
cerebro.adddata(data)
def parse_args():
parser = argparse.ArgumentParser(
description='Pandas test script')
return parser.parse_args()
if __name__ == '__main__':
runstrat()
Trading Calendar
Release 1.9.42.116 adds support for Trading Calendars. This is useful when
resampling in for example the following scenarios:
• Daily to Weekly resampling can now deliver the weekly bar together with the
last bar of the week.
This is so because the trading calendar identifies the next trading day and
the last trading day of the week can be identified in advance
• Sub-daily to Daily resampling when the end of the session is not the
regular one (which can already be specified to the data feed)
There is a base class TradingCalendarBase which is used as a base for any trading
calendar. It defines two (2) methods which have to be overridden:
raise NotImplementedError
Implementations
PandasMarketCalendar
class PandasMarketCalendar(TradingCalendarBase):
'''
Wrapper of ``pandas_market_calendars`` for a trading calendar. The package
``pandas_market_calendar`` must be installed
Params:
See also:
- https://github.com/rsheftel/pandas_market_calendars
- http://pandas-market-calendars.readthedocs.io/
'''
params = (
('calendar', None), # A pandas_market_calendars instance or exch name
279
backtrader’s documentation Version-1.9.58.122
TradingCalendar
class TradingCalendar(TradingCalendarBase):
'''
Wrapper of ``pandas_market_calendars`` for a trading calendar. The package
``pandas_market_calendar`` must be installed
Params:
'''
params = (
('open', time.min),
('close', _time_max),
280
backtrader’s documentation Version-1.9.58.122
Usage pattern
Via Cerebro one can add a global calendar which is the default for all data
feeds, unless one is specified for the data feed:
Per data-feed
For example:
...
data = bt.feeds.YahooFinanceData(dataname='YHOO', calendar='NYSE', ...)
cerebro.adddata(data)
...
281
backtrader’s documentation Version-1.9.58.122
Examples
Daily to Weekly
Let’s have a look at a sample run of the code that can be found below. In 2016,
Easter Friday (2016-03-25) was a holiday also in the NYSE. If the sample is run
with no trading calendar, let’s see what happens around that date.
In this case the resampling is being done from daily to weekly (using YHOO and
the daily data for 2016):
$ ./tcal.py
...
Strategy len 56 datetime 2016-03-23 Data0 len 56 datetime 2016-03-23 Data1 len 11
datetime 2016-03-18
Strategy len 57 datetime 2016-03-24 Data0 len 57 datetime 2016-03-24 Data1 len 11
datetime 2016-03-18
Strategy len 58 datetime 2016-03-28 Data0 len 58 datetime 2016-03-28 Data1 len 12
datetime 2016-03-24
...
In this output, the 1st date is the accounting made by the strategy. The 2nd date
is that of the daily
The same but run with a PandasMarketCalendar for NYSE (and adding a plot)
...
Strategy len 56 datetime 2016-03-23 Data0 len 56 datetime 2016-03-23 Data1 len 11
datetime 2016-03-18
Strategy len 57 datetime 2016-03-24 Data0 len 57 datetime 2016-03-24 Data1 len 12
datetime 2016-03-24
Strategy len 58 datetime 2016-03-28 Data0 len 58 datetime 2016-03-28 Data1 len 12
datetime 2016-03-24
...
282
backtrader’s documentation Version-1.9.58.122
There is a change! Thanks to the calendar the resampler knows the week is over on
2016-03-24 and delivers the corresponding weekly resampled bar for 2016-03-24 on
the same day.
Since the information may not necessarily be available for each and every market,
one can also craft the calendar. For the NYSE and 2016 it looks like:
class NYSE_2016(bt.TradingCalendar):
params = dict(
holidays=[
datetime.date(2016, 1, 1),
datetime.date(2016, 1, 18),
datetime.date(2016, 2, 15),
datetime.date(2016, 3, 25),
datetime.date(2016, 5, 30),
datetime.date(2016, 7, 4),
283
backtrader’s documentation Version-1.9.58.122
datetime.date(2016, 9, 5),
datetime.date(2016, 11, 24),
datetime.date(2016, 12, 26),
]
)
Easter Friday (2016-03-25) is listed as one of the holidays. Running the sample
now:
...
Strategy len 56 datetime 2016-03-23 Data0 len 56 datetime 2016-03-23 Data1 len 11
datetime 2016-03-18
Strategy len 57 datetime 2016-03-24 Data0 len 57 datetime 2016-03-24 Data1 len 12
datetime 2016-03-24
Strategy len 58 datetime 2016-03-28 Data0 len 58 datetime 2016-03-28 Data1 len 12
datetime 2016-03-24
...
And the same result has been obtained with the crafted calendar definition.
Minutes to Daily
Using some private intraday data and the knowledge that the market closed early
on 2016-11-25 (the day after Thanksgiving the market closed at 13:00 in
US/Eastern timezone), another test run, this time with the 2nd sample.
Note
The source data is taken directly from the displayed data and is in CET timeozone
even if the asset in question, YHOO trades in the USA. The tzinput='CET' and
tz='US/Eastern' is used in the code for the data feed to let the platform
appropriately transform the input and display the output
$ ./tcal-intra.py
...
Strategy len 6838 datetime 2016-11-25 18:00:00 Data0 len 6838 datetime 2016-11-25
13:00:00 Data1 len 21 datetime 2016-11-23 16:00:00
Strategy len 6839 datetime 2016-11-25 18:01:00 Data0 len 6839 datetime 2016-11-25
13:01:00 Data1 len 21 datetime 20 16-11-23 16:00:00
284
backtrader’s documentation Version-1.9.58.122
Strategy len 6840 datetime 2016-11-28 14:31:00 Data0 len 6840 datetime 2016-11-28
09:31:00 Data1 len 22 datetime 2016-11-25 16:00:00
Strategy len 6841 datetime 2016-11-28 14:32:00 Data0 len 6841 datetime 2016-11-28
09:32:00 Data1 len 22 datetime 2016-11-25 16:00:00
...
As expected the day closes early at 13:00, but the resampler doesn’t know it
(the official session ends at 16:00) and keeps on delivering the resampled daily
bar from the previous day (2016-11-23) and the new resampled daily bar is first
delivered during the next trading day (2016-11-28) with a date of 2016-11-25.
Note
The data has an extra minute bar at 13:01 which is probably due to the auction
process offering a last price after the market closing time.
We could add a filter to the stream to filter out the bars outside of the session
times (the filter would find it out from the trading calendar)
...
Strategy len 6838 datetime 2016-11-25 18:00:00 Data0 len 6838 datetime 2016-11-25
13:00:00 Data1 len 15 datetime 2016-11-25 13:00:00
Strategy len 6839 datetime 2016-11-25 18:01:00 Data0 len 6839 datetime 2016-11-25
13:01:00 Data1 len 15 datetime 2016-11-25 13:00:00
Strategy len 6840 datetime 2016-11-28 14:31:00 Data0 len 6840 datetime 2016-11-28
09:31:00 Data1 len 15 datetime 2016-11-25 13:00:00
Strategy len 6841 datetime 2016-11-28 14:32:00 Data0 len 6841 datetime 2016-11-28
09:32:00 Data1 len 15 datetime 2016-11-25 13:00:00
...
And now the daily bar for 2016-11-25 is delivered when the intraday 1-minute feed
hits 2016-11-25 at 13:00 (let’s disregard the 13:01 bar), because the trading
calendar is telling the resampling code that the day is over.
Let’s add a crafted definition. The same as before but extending it with some
earlydays
class NYSE_2016(bt.TradingCalendar):
params = dict(
285
backtrader’s documentation Version-1.9.58.122
holidays=[
datetime.date(2016, 1, 1),
datetime.date(2016, 1, 18),
datetime.date(2016, 2, 15),
datetime.date(2016, 3, 25),
datetime.date(2016, 5, 30),
datetime.date(2016, 7, 4),
datetime.date(2016, 9, 5),
datetime.date(2016, 11, 24),
datetime.date(2016, 12, 26),
],
earlydays=[
(datetime.date(2016, 11, 25),
datetime.time(9, 30), datetime.time(13, 1))
],
open=datetime.time(9, 30),
close=datetime.time(16, 0),
)
The run:
$ ./tcal-intra.py --owncal
...
Strategy len 6838 datetime 2016-11-25 18:00:00 Data0 len 6838 datetime 2016-11-25
13:00:00 Data1 len 15 datetime 2016-11-23 16:00:00
Strategy len 6839 datetime 2016-11-25 18:01:00 Data0 len 6839 datetime 2016-11-25
13:01:00 Data1 len 16 datetime 2016-11-25 13:01:00
Strategy len 6840 datetime 2016-11-28 14:31:00 Data0 len 6840 datetime 2016-11-28
09:31:00 Data1 len 16 datetime 2016-11-25 13:01:00
Strategy len 6841 datetime 2016-11-28 14:32:00 Data0 len 6841 datetime 2016-11-28
09:32:00 Data1 len 16 datetime 2016-11-25 13:01:00
...
The avid reader will notice that the crafted definition contains has defined
13:01 (with datetime.time(13, 1)) as the end of session for our short day of
2016-11-25. This is only to show how the crafted TradingCalendar can help into
fitting things.
Now the daily resampled bar for 2016-11-25 is delivered together with the 1-
minute bar at 13:01.
286
backtrader’s documentation Version-1.9.58.122
The first datetime, the one belonging to the strategy, is always in a different
timezone which is actually UTC. Also with this release 1.9.42.116 this can be
synchronized. The following parameter has been added to Cerebro (use either
during instantiation or with cerebro.run
'''
287
backtrader’s documentation Version-1.9.58.122
Repeating the last run of the intraday sample and using 0 for tz (synchronize
with the timezone of data0) the following is the output focusing on the same
dates and times as above:
...
Strategy len 6838 datetime 2016-11-25 13:00:00 Data0 len 6838 datetime 2016-11-25
13:00:00 Data1 len 15 datetime 2016-11-23 16:00:00
Strategy len 6839 datetime 2016-11-25 13:01:00 Data0 len 6839 datetime 2016-11-25
13:01:00 Data1 len 16 datetime 2016-11-25 13:01:00
Strategy len 6840 datetime 2016-11-28 09:31:00 Data0 len 6840 datetime 2016-11-28
09:31:00 Data1 len 16 datetime 2016-11-25 13:01:00
Strategy len 6841 datetime 2016-11-28 09:32:00 Data0 len 6841 datetime 2016-11-28
09:32:00 Data1 len 16 datetime 2016-11-25 13:01:00
...
$ ./tcal.py --help
usage: tcal.py [-h] [--data0 DATA0] [--offline] [--fromdate FROMDATE]
[--todate TODATE] [--cerebro kwargs] [--broker kwargs]
[--sizer kwargs] [--strat kwargs] [--plot [kwargs]]
[--pandascal PANDASCAL | --owncal]
[--timeframe {Weeks,Months,Years}]
optional arguments:
-h, --help show this help message and exit
--data0 DATA0 Data to read in (default: YHOO)
--offline Read from disk with same name as ticker (default:
False)
--fromdate FROMDATE Date[time] in YYYY-MM-DD[THH:MM:SS] format (default:
2016-01-01)
--todate TODATE Date[time] in YYYY-MM-DD[THH:MM:SS] format (default:
2016-12-31)
--cerebro kwargs kwargs in key=value format (default: )
--broker kwargs kwargs in key=value format (default: )
--sizer kwargs kwargs in key=value format (default: )
--strat kwargs kwargs in key=value format (default: )
--plot [kwargs] kwargs in key=value format (default: )
288
backtrader’s documentation Version-1.9.58.122
--pandascal PANDASCAL
Name of trading calendar to use (default: )
--owncal Apply custom NYSE 2016 calendar (default: False)
--timeframe {Weeks,Months,Years}
Timeframe to resample to (default: Weeks)
$ ./tcal-intra.py --help
usage: tcal-intra.py [-h] [--data0 DATA0] [--fromdate FROMDATE]
[--todate TODATE] [--cerebro kwargs] [--broker kwargs]
[--sizer kwargs] [--strat kwargs] [--plot [kwargs]]
[--pandascal PANDASCAL | --owncal] [--timeframe {Days}]
optional arguments:
-h, --help show this help message and exit
--data0 DATA0 Data to read in (default: yhoo-2016-11.csv)
--fromdate FROMDATE Date[time] in YYYY-MM-DD[THH:MM:SS] format (default:
2016-01-01)
--todate TODATE Date[time] in YYYY-MM-DD[THH:MM:SS] format (default:
2016-12-31)
--cerebro kwargs kwargs in key=value format (default: )
--broker kwargs kwargs in key=value format (default: )
--sizer kwargs kwargs in key=value format (default: )
--strat kwargs kwargs in key=value format (default: )
--plot [kwargs] kwargs in key=value format (default: )
--pandascal PANDASCAL
Name of trading calendar to use (default: )
--owncal Apply custom NYSE 2016 calendar (default: False)
--timeframe {Days} Timeframe to resample to (default: Days)
import argparse
import datetime
import backtrader as bt
289
backtrader’s documentation Version-1.9.58.122
class NYSE_2016(bt.TradingCalendar):
params = dict(
holidays=[
datetime.date(2016, 1, 1),
datetime.date(2016, 1, 18),
datetime.date(2016, 2, 15),
datetime.date(2016, 3, 25),
datetime.date(2016, 5, 30),
datetime.date(2016, 7, 4),
datetime.date(2016, 9, 5),
datetime.date(2016, 11, 24),
datetime.date(2016, 12, 26),
]
)
class St(bt.Strategy):
params = dict(
)
def __init__(self):
pass
def start(self):
self.t0 = datetime.datetime.utcnow()
def stop(self):
t1 = datetime.datetime.utcnow()
print('Duration:', t1 - self.t0)
def prenext(self):
self.next()
def next(self):
print('Strategy len {} datetime {}'.format(
len(self), self.datetime.date()), end=' ')
if len(self.data1):
print('Data1 len {} datetime {}'.format(
len(self.data1), self.data1.datetime.date()))
290
backtrader’s documentation Version-1.9.58.122
else:
print()
def runstrat(args=None):
args = parse_args(args)
cerebro = bt.Cerebro()
# Parse from/to-date
dtfmt, tmfmt = '%Y-%m-%d', 'T%H:%M:%S'
for a, d in ((getattr(args, x), x) for x in ['fromdate', 'todate']):
if a:
strpfmt = dtfmt + tmfmt * ('T' in a)
kwargs[d] = datetime.datetime.strptime(a, strpfmt)
YahooData = bt.feeds.YahooFinanceData
if args.offline:
YahooData = bt.feeds.YahooFinanceCSVData # change to read file
# Data feed
data0 = YahooData(dataname=args.data0, **kwargs)
cerebro.adddata(data0)
d1 = cerebro.resampledata(data0,
timeframe=getattr(bt.TimeFrame, args.timeframe))
d1.plotinfo.plotmaster = data0
d1.plotinfo.sameaxis = True
if args.pandascal:
cerebro.addcalendar(args.pandascal)
elif args.owncal:
cerebro.addcalendar(NYSE_2016)
# Broker
cerebro.broker = bt.brokers.BackBroker(**eval('dict(' + args.broker + ')'))
# Sizer
cerebro.addsizer(bt.sizers.FixedSize, **eval('dict(' + args.sizer + ')'))
# Strategy
291
backtrader’s documentation Version-1.9.58.122
# Execute
cerebro.run(**eval('dict(' + args.cerebro + ')'))
def parse_args(pargs=None):
parser = argparse.ArgumentParser(
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
description=(
'Trading Calendar Sample'
)
)
parser.add_argument('--data0', default='YHOO',
required=False, help='Data to read in')
pgroup = parser.add_mutually_exclusive_group(required=False)
pgroup.add_argument('--pandascal', required=False, action='store',
default='', help='Name of trading calendar to use')
return parser.parse_args(pargs)
if __name__ == '__main__':
runstrat()
import argparse
import datetime
import backtrader as bt
class NYSE_2016(bt.TradingCalendar):
params = dict(
holidays=[
datetime.date(2016, 1, 1),
datetime.date(2016, 1, 18),
datetime.date(2016, 2, 15),
datetime.date(2016, 3, 25),
datetime.date(2016, 5, 30),
datetime.date(2016, 7, 4),
datetime.date(2016, 9, 5),
datetime.date(2016, 11, 24),
datetime.date(2016, 12, 26),
],
293
backtrader’s documentation Version-1.9.58.122
earlydays=[
(datetime.date(2016, 11, 25),
datetime.time(9, 30), datetime.time(13, 1))
],
open=datetime.time(9, 30),
close=datetime.time(16, 0),
)
class St(bt.Strategy):
params = dict(
)
def __init__(self):
pass
def prenext(self):
self.next()
def next(self):
print('Strategy len {} datetime {}'.format(
len(self), self.datetime.datetime()), end=' ')
if len(self.data1):
print('Data1 len {} datetime {}'.format(
len(self.data1), self.data1.datetime.datetime()))
else:
print()
def runstrat(args=None):
args = parse_args(args)
cerebro = bt.Cerebro()
tz = 'US/Eastern'
kwargs = dict(tzinput=tzinput, tz=tz)
# Parse from/to-date
dtfmt, tmfmt = '%Y-%m-%d', 'T%H:%M:%S'
for a, d in ((getattr(args, x), x) for x in ['fromdate', 'todate']):
if a:
strpfmt = dtfmt + tmfmt * ('T' in a)
kwargs[d] = datetime.datetime.strptime(a, strpfmt)
# Data feed
data0 = bt.feeds.BacktraderCSVData(dataname=args.data0, **kwargs)
cerebro.adddata(data0)
d1 = cerebro.resampledata(data0,
timeframe=getattr(bt.TimeFrame, args.timeframe))
# d1.plotinfo.plotmaster = data0
# d1.plotinfo.sameaxis = False
if args.pandascal:
cerebro.addcalendar(args.pandascal)
elif args.owncal:
cerebro.addcalendar(NYSE_2016()) # or NYSE_2016() to pass an instance
# Broker
cerebro.broker = bt.brokers.BackBroker(**eval('dict(' + args.broker + ')'))
# Sizer
cerebro.addsizer(bt.sizers.FixedSize, **eval('dict(' + args.sizer + ')'))
# Strategy
cerebro.addstrategy(St, **eval('dict(' + args.strat + ')'))
# Execute
cerebro.run(**eval('dict(' + args.cerebro + ')'))
def parse_args(pargs=None):
parser = argparse.ArgumentParser(
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
description=(
295
backtrader’s documentation Version-1.9.58.122
parser.add_argument('--data0', default='yhoo-2016-11.csv',
required=False, help='Data to read in')
pgroup = parser.add_mutually_exclusive_group(required=False)
pgroup.add_argument('--pandascal', required=False, action='store',
default='', help='Name of trading calendar to use')
return parser.parse_args(pargs)
296
backtrader’s documentation Version-1.9.58.122
if __name__ == '__main__':
runstrat()
Data Resampling
When data is only available in a single timeframe and the analysis has to be done
for a different timeframe, it’s time to do some resampling.
“Resampling” should actually be called “Upsampling” given that one goes from
a source timeframe to a larger time frame (for example: days to weeks)
backtrader has built-in support for resampling by passing the original data
through a filter object. Although there are several ways to achieve this, a
straightforward interface exists to achieve this:
cerebro.resampledata(data, **kwargs)
• compression (default: 1)
The output:
297
backtrader’s documentation Version-1.9.58.122
The output:
298
backtrader’s documentation Version-1.9.58.122
A last example in which we first change the time frame from daily to weekly and
then apply a 3 to 1 compression:
The output:
From the original 256 daily bars we end up with 18 3-week bars. The breakdown:
• 52 weeks
• 52 / 3 = 17.33 and therefore 18 bars
300
backtrader’s documentation Version-1.9.58.122
It doesn’t take much more. Of course intraday data can also be resampled.
The resampling filter supports additional parameters, which in most cases should
not be touched:
resamples using time boundaries as the target. For example with a “ticks
-> 5 seconds” the resulting 5 seconds bars will be aligned to xx:00,
xx:05, xx:10 ...
Use the time at the boundary to adjust the time of the delivered resampled
bar instead of the last seen timestamp. If resampling to “5 seconds” the
time of the bar will be adjusted for example to hh:mm:05 even if the last
seen timestamp was hh:mm:04.33
Note
Use the right edge of the time boundaries to set the time.
If True the used boundary for the time will be hh:mm:05 (the ending
boundary)
• boundoff (default: 0)
301
backtrader’s documentation Version-1.9.58.122
o Use the bars from 00:00:00 to 00:14:00 for the generation of the 15-minutes bar
import argparse
import backtrader as bt
import backtrader.feeds as btfeeds
def runstrat():
args = parse_args()
# Add a strategy
cerebro.addstrategy(bt.Strategy)
302
backtrader’s documentation Version-1.9.58.122
def parse_args():
parser = argparse.ArgumentParser(
description='Pandas test script')
return parser.parse_args()
if __name__ == '__main__':
runstrat()
Or 5 minutes vs 60 minutes.
Native support for it is already built-in. The end user must only follow these
rules:
• The data with the smallest timeframe (and thus the larger number of bars) must be the 1st one to be
added to the Cerebro instance
• The datas must be properly date-time aligned for the platform to make any sense out of them
303
backtrader’s documentation Version-1.9.58.122
Minimum period which will probably have the side effect of having to consume
several orders of magnitude of the smaller timeframe bars before a Strategy added
to Cerebro kicks into action.
Some examples below, but first the sauce of the test script.
The steps:
• Load a data
• Resample it according to the user specified arguments
305
backtrader’s documentation Version-1.9.58.122
Although plotting is nice, the key issue here is showing how the larger timeframe
influences the system, especially when it comes down to the starting point
The script can take a --indicators to add a strategy which creates simple moving
averages of period 10 on the smaller an larger timeframe datas.
• next would be called first after 10 bars, which is the time the Simple
Moving Average needs to produce a value
Note
Remember that Strategy monitors created indicators and only calls next when
all indicators have produced a value. The rationale is that the end user
306
backtrader’s documentation Version-1.9.58.122
has added the indicators to use them in the logic and thus no logic should
take place if the indicators have produced no values
But in this case the larger timeframe (weekly) delays the invocation of next
until the Simple Moving Average oon the weekly data has produced a value, which
takes ... 10 weeks.
The script overrides nextstart which is only called once and which defaults to
calling next to show when it is first called.
Invocation 1:
307
backtrader’s documentation Version-1.9.58.122
Invocation 2:
• Instead of being called after 10 periods, the strategy is 1st called after
50 periods.
This is a natural side effect of having mixed the timeframe and having (in
this case only one) indicators applied to the larger timeframe.
The larger timeframe Simple Moving Average produces 5 times the same value
whilst 5 daily bars are being consumed.
And because the start of the period is being controlled by the larger
timeframe nextstart gets called 5 times.
309
backtrader’s documentation Version-1.9.58.122
Conclusion
import argparse
import backtrader as bt
import backtrader.feeds as btfeeds
import backtrader.indicators as btind
310
backtrader’s documentation Version-1.9.58.122
class SMAStrategy(bt.Strategy):
params = (
('period', 10),
('onlydaily', False),
)
def __init__(self):
self.sma_small_tf = btind.SMA(self.data, period=self.p.period)
if not self.p.onlydaily:
self.sma_large_tf = btind.SMA(self.data1, period=self.p.period)
def nextstart(self):
print('--------------------------------------------------')
print('nextstart called with len', len(self))
print('--------------------------------------------------')
super(SMAStrategy, self).nextstart()
def runstrat():
args = parse_args()
# Add a strategy
if not args.indicators:
cerebro.addstrategy(bt.Strategy)
else:
cerebro.addstrategy(
SMAStrategy,
def parse_args():
parser = argparse.ArgumentParser(
description='Multitimeframe test')
parser.add_argument('--noresample', action='store_true',
help='Do not resample, rather load larger timeframe')
parser.add_argument('--indicators', action='store_true',
help='Wether to apply Strategy with indicators')
parser.add_argument('--onlydaily', action='store_true',
help='Indicator only to be applied to daily timeframe')
312
backtrader’s documentation Version-1.9.58.122
return parser.parse_args()
if __name__ == '__main__':
runstrat()
Data - Replay
The time is gone and testing a strategy against a fully formed and closed bar is
good, but it could be better.
and
This is of course not exactly how the market developed, but it is far better than
looking at the daily fully formed and closed bar in isolation:
If the strategy operates in realtime during the formation of the daily bar,
the approximation of the formation of the bar gives a chance to replicate the
actual behavior of the strategy under real conditions
Putting Data Replay into action follows the regular usage patterns of backtrader
Note
Preloading is not supported when data is being replayed because each bar is
actually built in real-time. It will automatically disabled in any Cerebro
instance.
313
backtrader’s documentation Version-1.9.58.122
• compression (default: 1)
replays using time boundaries as the target of the closed bar. For example
with a “ticks -> 5 seconds” the resulting 5 seconds bars will be aligned
to xx:00, xx:05, xx:10 ...
Use the time at the boundary to adjust the time of the delivered resampled
bar instead of the last seen timestamp. If resampling to “5 seconds” the
time of the bar will be adjusted for example to hh:mm:05 even if the last
seen timestamp was hh:mm:04.33
Note
Use the right edge of the time boundaries to set the time.
If True the used boundary for the time will be hh:mm:05 (the ending
boundary)
For the sake of working with a example the standard 2006 daily data will be
replayed on a weekly basis. Which means:
• Cerebro will call prenext and next a total of 255 times, which is the original count of daily bars
The trick:
• When a weekly bar is forming, the length (len(self)) of the strategy will remain unchanged.
• With each new week the length will increase by one
Some examples below, but first the sauce of the test script in which the data is
loaded and passed to cerebro with replaydata ... and then run.
The chart cannot unfortunately show us the real thing happening in the
background, so let’s have a look at the console output:
The key:
• The length (len(self)) of the strategy changes every 5 bars (5 trading days in the week)
This, again, doesn’t replicate the actual tick-by-tick (and not even
minute, hour) development of the market, but it is better than actually
seeing a bar.
The visual output is that of the weekly chart which is the final outcome the
system is being tested again.
316
backtrader’s documentation Version-1.9.58.122
The console:
This time we got half the bars as expected because of the factor 2 requested
compression.
The chart:
Conclusion
import argparse
import backtrader as bt
import backtrader.feeds as btfeeds
import backtrader.indicators as btind
class SMAStrategy(bt.Strategy):
params = (
('period', 10),
('onlydaily', False),
)
def __init__(self):
self.sma = btind.SMA(self.data, period=self.p.period)
def start(self):
self.counter = 0
def prenext(self):
self.counter += 1
print('prenext len %d - counter %d' % (len(self), self.counter))
def next(self):
self.counter += 1
print('---next len %d - counter %d' % (len(self), self.counter))
def runstrat():
args = parse_args()
cerebro.addstrategy(
SMAStrategy,
# args for the strategy
period=args.period,
)
319
backtrader’s documentation Version-1.9.58.122
def parse_args():
parser = argparse.ArgumentParser(
description='Pandas test script')
return parser.parse_args()
if __name__ == '__main__':
320
backtrader’s documentation Version-1.9.58.122
runstrat()
Not every provider offers a continuous future for the instruments with which one
can trade. Sometimes the data offered is that of the still valid expiration
dates, i.e.: those still being traded
This is not so helpful when it comes to backtesting because the data is scattered
over several different instruments which additionally ... overlap in time.
Being able to properly join the data of those instruments, from the past, into a
continuous stream alleviates the pain. The problem:
• There is no law as to how best join the different expiration dates into a continuous future
• http://www.sierrachart.com/index.php?page=doc/ChangingFuturesContract.html
backtrader has added with 1.8.10.99` the possibility to join futures’ data from
different expiration dates into a continuous future:
import backtrader as bt
cerebro = bt.Cerebro()
data0 = bt.feeds.MyFeed(dataname='Expiry0')
data1 = bt.feeds.MyFeed(dataname='Expiry1')
...
dataN = bt.feeds.MyFeed(dataname='ExpiryN')
cerebro.run()
Note
It can also be done by directly accessing the RollOver feed (which is helpful if
subclassing is done):
321
backtrader’s documentation Version-1.9.58.122
import backtrader as bt
cerebro = bt.Cerebro()
data0 = bt.feeds.MyFeed(dataname='Expiry0')
data1 = bt.feeds.MyFeed(dataname='Expiry1')
...
dataN = bt.feeds.MyFeed(dataname='ExpiryN')
cerebro.run()
Note
Note
When using RollOver the name is assigned using dataname. This is the standard
parameter used for all data feeds to pass the name/ticker. In this case it is
reused to assign a common name to the complete set of rolled over futures.
Bottomline:
• Data Feeds are created as usual but ARE NOT added to cerebro
• Those data feeds are given as input to bt.feeds.RollOver
checkdate(dt, d):
322
backtrader’s documentation Version-1.9.58.122
Where:
o dt is a datetime.datetime object
o d is the current data feed for the active future
checkcondition(d0, d1)
Where:
Following with the example from checkdate, this could say that the
roll-over can only happend if the volume from d0 is already less than
the volume from d1
Subclassing RollOver
If specifying the callables isn’t enough, there is always the chance to subclass
RollOver. The methods to subclass:
Which matches the signature of the parameter of the same name above. The
expected return values are also the saame.
Which matches the signature of the parameter of the same name above. The
expected return values are also the saame.
Let’s Roll
Note
Futures concatenation
$ ./rollover.py
Len, Name, RollName, Datetime, WeekDay, Open, High, Low, Close, Volume,
OpenInterest
0001, FESX, 199FESXM4, 2013-09-26, Thu, 2829.0, 2843.0, 2829.0, 2843.0, 3.0,
1000.0
0002, FESX, 199FESXM4, 2013-09-27, Fri, 2842.0, 2842.0, 2832.0, 2841.0, 16.0,
1101.0
...
0176, FESX, 199FESXM4, 2014-06-20, Fri, 3315.0, 3324.0, 3307.0, 3322.0, 134777.0,
520978.0
0177, FESX, 199FESXU4, 2014-06-23, Mon, 3301.0, 3305.0, 3265.0, 3285.0, 730211.0,
3003692.0
...
0241, FESX, 199FESXU4, 2014-09-19, Fri, 3287.0, 3308.0, 3286.0, 3294.0, 144692.0,
566249.0
0242, FESX, 199FESXZ4, 2014-09-22, Mon, 3248.0, 3263.0, 3231.0, 3240.0, 582077.0,
2976624.0
...
324
backtrader’s documentation Version-1.9.58.122
0306, FESX, 199FESXZ4, 2014-12-19, Fri, 3196.0, 3202.0, 3131.0, 3132.0, 226415.0,
677924.0
0307, FESX, 199FESXH5, 2014-12-22, Mon, 3151.0, 3177.0, 3139.0, 3168.0, 547095.0,
2952769.0
...
0366, FESX, 199FESXH5, 2015-03-20, Fri, 3680.0, 3698.0, 3672.0, 3695.0, 147632.0,
887205.0
0367, FESX, 199FESXM5, 2015-03-23, Mon, 3654.0, 3655.0, 3608.0, 3618.0, 802344.0,
3521988.0
...
0426, FESX, 199FESXM5, 2015-06-18, Thu, 3398.0, 3540.0, 3373.0, 3465.0,
1173246.0, 811805.0
0427, FESX, 199FESXM5, 2015-06-19, Fri, 3443.0, 3499.0, 3440.0, 3488.0, 104096.0,
516792.0
Len, Name, RollName, Datetime, WeekDay, Open, High, Low, Close, Volume,
OpenInterest
0001, FESX, 199FESXM4, 2013-09-26, Thu, 2829.0, 2843.0, 2829.0, 2843.0, 3.0,
1000.0
0002, FESX, 199FESXM4, 2013-09-27, Fri, 2842.0, 2842.0, 2832.0, 2841.0, 16.0,
1101.0
...
0176, FESX, 199FESXM4, 2014-06-20, Fri, 3315.0, 3324.0, 3307.0, 3322.0, 134777.0,
520978.0
0177, FESX, 199FESXU4, 2014-06-23, Mon, 3301.0, 3305.0, 3265.0, 3285.0, 730211.0,
3003692.0
...
0241, FESX, 199FESXU4, 2014-09-19, Fri, 3287.0, 3308.0, 3286.0, 3294.0, 144692.0,
566249.0
0242, FESX, 199FESXZ4, 2014-09-22, Mon, 3248.0, 3263.0, 3231.0, 3240.0, 582077.0,
2976624.0
...
325
backtrader’s documentation Version-1.9.58.122
0306, FESX, 199FESXZ4, 2014-12-19, Fri, 3196.0, 3202.0, 3131.0, 3132.0, 226415.0,
677924.0
0307, FESX, 199FESXH5, 2014-12-22, Mon, 3151.0, 3177.0, 3139.0, 3168.0, 547095.0,
2952769.0
...
0366, FESX, 199FESXH5, 2015-03-20, Fri, 3680.0, 3698.0, 3672.0, 3695.0, 147632.0,
887205.0
0367, FESX, 199FESXM5, 2015-03-23, Mon, 3654.0, 3655.0, 3608.0, 3618.0, 802344.0,
3521988.0
...
0426, FESX, 199FESXM5, 2015-06-18, Thu, 3398.0, 3540.0, 3373.0, 3465.0,
1173246.0, 811805.0
0427, FESX, 199FESXM5, 2015-06-19, Fri, 3443.0, 3499.0, 3440.0, 3488.0, 104096.0,
516792.0
The same behavior. It can clearly be seen that contract changes are being made on
the 3rd Friday of either Mar, Jun, Sep, Dec.
But this is mostly WRONG. backtradr cannot know it, but the author knows that the
EuroStoxx 50 futures stop trading at 12:00 CET. So even if there is a daily bar
for the 3rd Friday of the expiration month, the change is happening too late.
326
backtrader’s documentation Version-1.9.58.122
checkdate will allow a roll over as soon as the week of the 3rd Friday of the
month is reached (it may be Tuesday if for example Monday is a bank holiday)
Len, Name, RollName, Datetime, WeekDay, Open, High, Low, Close, Volume,
OpenInterest
0001, FESX, 199FESXM4, 2013-09-26, Thu, 2829.0, 2843.0, 2829.0, 2843.0, 3.0,
1000.0
0002, FESX, 199FESXM4, 2013-09-27, Fri, 2842.0, 2842.0, 2832.0, 2841.0, 16.0,
1101.0
...
327
backtrader’s documentation Version-1.9.58.122
0171, FESX, 199FESXM4, 2014-06-13, Fri, 3283.0, 3292.0, 3253.0, 3276.0, 734907.0,
2715357.0
0172, FESX, 199FESXU4, 2014-06-16, Mon, 3261.0, 3275.0, 3252.0, 3262.0, 180608.0,
844486.0
...
0236, FESX, 199FESXU4, 2014-09-12, Fri, 3245.0, 3247.0, 3220.0, 3232.0, 650314.0,
2726874.0
0237, FESX, 199FESXZ4, 2014-09-15, Mon, 3209.0, 3224.0, 3203.0, 3221.0, 153448.0,
983793.0
...
0301, FESX, 199FESXZ4, 2014-12-12, Fri, 3127.0, 3143.0, 3038.0, 3042.0,
1409834.0, 2934179.0
0302, FESX, 199FESXH5, 2014-12-15, Mon, 3041.0, 3089.0, 2963.0, 2980.0, 329896.0,
904053.0
...
0361, FESX, 199FESXH5, 2015-03-13, Fri, 3657.0, 3680.0, 3627.0, 3670.0, 867678.0,
3499116.0
0362, FESX, 199FESXM5, 2015-03-16, Mon, 3594.0, 3641.0, 3588.0, 3629.0, 250445.0,
1056099.0
...
0426, FESX, 199FESXM5, 2015-06-18, Thu, 3398.0, 3540.0, 3373.0, 3465.0,
1173246.0, 811805.0
0427, FESX, 199FESXM5, 2015-06-19, Fri, 3443.0, 3499.0, 3440.0, 3488.0, 104096.0,
516792.0
Much better. The roll over is now happening 5 days before. A quick visual
inspection of the Len indices show it. For example:
The roll over is happening on the Monday before the 3rd Friday of the expiration
month.
328
backtrader’s documentation Version-1.9.58.122
Even with the improvement, the situation can be further improved in that not only
the date but also de negotiated volume will be taken into account. Do switch when
the new contract trades more volume than the currently active one.
Len, Name, RollName, Datetime, WeekDay, Open, High, Low, Close, Volume,
OpenInterest
0001, FESX, 199FESXM4, 2013-09-26, Thu, 2829.0, 2843.0, 2829.0, 2843.0, 3.0,
1000.0
0002, FESX, 199FESXM4, 2013-09-27, Fri, 2842.0, 2842.0, 2832.0, 2841.0, 16.0,
1101.0
...
329
backtrader’s documentation Version-1.9.58.122
0175, FESX, 199FESXM4, 2014-06-19, Thu, 3307.0, 3330.0, 3300.0, 3321.0, 717979.0,
759122.0
0176, FESX, 199FESXU4, 2014-06-20, Fri, 3309.0, 3318.0, 3290.0, 3298.0, 711627.0,
2957641.0
...
0240, FESX, 199FESXU4, 2014-09-18, Thu, 3249.0, 3275.0, 3243.0, 3270.0, 846600.0,
803202.0
0241, FESX, 199FESXZ4, 2014-09-19, Fri, 3273.0, 3293.0, 3250.0, 3252.0,
1042294.0, 3021305.0
...
0305, FESX, 199FESXZ4, 2014-12-18, Thu, 3095.0, 3175.0, 3085.0, 3172.0,
1309574.0, 889112.0
0306, FESX, 199FESXH5, 2014-12-19, Fri, 3195.0, 3200.0, 3106.0, 3147.0,
1329040.0, 2964538.0
...
0365, FESX, 199FESXH5, 2015-03-19, Thu, 3661.0, 3691.0, 3646.0, 3668.0,
1271122.0, 1054639.0
0366, FESX, 199FESXM5, 2015-03-20, Fri, 3607.0, 3664.0, 3595.0, 3646.0,
1182235.0, 3407004.0
...
0426, FESX, 199FESXM5, 2015-06-18, Thu, 3398.0, 3540.0, 3373.0, 3465.0,
1173246.0, 811805.0
0427, FESX, 199FESXM5, 2015-06-19, Fri, 3443.0, 3499.0, 3440.0, 3488.0, 104096.0,
516792.0
Even better*. We have moved the switch date to the Thursday before the well known
3rd Friday of the expiration month
This should come to no surprise because the expiring future trades a lot less
hours on that Friday and the volume must be small.
Note
The roll over date could have also been set to that Thursday by the checkdate
callable. But that isn’t the point of the sample.
330
backtrader’s documentation Version-1.9.58.122
Concluding
Sample Usage
$ ./rollover.py --help
usage: rollover.py [-h] [--no-cerebro] [--rollover] [--checkdate]
[--checkcondition] [--plot [kwargs]]
optional arguments:
-h, --help show this help message and exit
--no-cerebro Use RollOver Directly (default: False)
331
backtrader’s documentation Version-1.9.58.122
--rollover
--checkdate Change during expiration week (default: False)
--checkcondition Change when a given condition is met (default: False)
--plot [kwargs], -p [kwargs]
Plot the read data applying any kwargs passed For
example: --plot style="candle" (to plot candles)
(default: None)
Sample Code
import argparse
import bisect
import calendar
import datetime
import backtrader as bt
class TheStrategy(bt.Strategy):
def start(self):
header = ['Len', 'Name', 'RollName', 'Datetime', 'WeekDay', 'Open',
'High', 'Low', 'Close', 'Volume', 'OpenInterest']
print(', '.join(header))
def next(self):
txt = list()
txt.append('%04d' % len(self.data0))
txt.append('{}'.format(self.data0._dataname))
# Internal knowledge ... current expiration in use is in _d
txt.append('{}'.format(self.data0._d._dataname))
txt.append('{}'.format(self.data.datetime.date()))
txt.append('{}'.format(self.data.datetime.date().strftime('%a')))
txt.append('{}'.format(self.data.open[0]))
txt.append('{}'.format(self.data.high[0]))
txt.append('{}'.format(self.data.low[0]))
txt.append('{}'.format(self.data.close[0]))
txt.append('{}'.format(self.data.volume[0]))
txt.append('{}'.format(self.data.openinterest[0]))
print(', '.join(txt))
332
backtrader’s documentation Version-1.9.58.122
M = MONTHS[d._dataname[-2]]
YCode = int(d._dataname[-1])
Y = decade + YCode
if Y < dt.year: # Example: year 2019 ... YCode is 0 for 2020
Y += 10
exp_day = 21 - (calendar.weekday(Y, M, 1) + 2) % 7
exp_dt = datetime.datetime(Y, M, exp_day)
def runstrat(args=None):
args = parse_args(args)
cerebro = bt.Cerebro()
store = bt.stores.VChartFile()
ffeeds = [store.getdata(dataname=x) for x in fcodes]
rollkwargs = dict()
if args.checkdate:
rollkwargs['checkdate'] = checkdate
if args.checkcondition:
rollkwargs['checkcondition'] = checkvolume
if not args.no_cerebro:
if args.rollover:
cerebro.rolloverdata(name='FESX', *ffeeds, **rollkwargs)
else:
cerebro.chaindata(name='FESX', *ffeeds)
else:
drollover = bt.feeds.RollOver(*ffeeds, dataname='FESX', **rollkwargs)
cerebro.adddata(drollover)
cerebro.addstrategy(TheStrategy)
cerebro.run(stdstats=False)
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 Roll Over of Futures')
parser.add_argument('--checkcondition', required=False,
action='store_true',
help='Change when a given condition is met')
# 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'))
return parser.parse_args()
if __name__ == '__main__':
runstrat()
Filters
Although the implementation tried to allow plug and play filter chaining, the
pre-existing internals made it difficult to ensure that could always be achieved.
As such, some filters may be chained and some others may not.
Purpose
• Transform the values provided by a data feed to deliver a different data feed
The implementation was started to simplify the implementation of the two obvious
filters which can be directly used via the cerebro API. These are:
• Resampling (cerebro.resampledata)
335
backtrader’s documentation Version-1.9.58.122
Here the filter transforms the timeframe and compression of the incoming
data feed. For example:
That means that the original data feed is delivery bars with a resolution
of 1 Second. The Resampling filter intercepts the data and buffers it until
it can deliver a 1 Day bar. This will happen when a 1 Second bar from the
next day is seen.
• Replaying (cerebro.replaydata)
For the same timeframes as above, the filter would use the 1 Second
resolution bars to rebuild the 1 Day bar.
That means that the 1 Day bar is delivered as many times as 1 Second bars
are seen, updated to contain the latest information.
This simulates, for example, how an actual trading day has developed.
Note
the length of the data, len(data) and therefore the length of the strategy
remain unchanged as long as the day doesn’t change.
Filters at work
Given an existing data feed/source you use the addfilter method of the data feed:
data = MyDataFeed(dataname=myname)
data.addfilter(filter, *args, **kwargs)
cerebro.addata(data)
data = MyDataFeed(dataname=myname)
data.addfilter(filter, *args, **kwargs)
cerebro.replaydata(data)
Filter Interface
336
backtrader’s documentation Version-1.9.58.122
or
The instance will be called for each new incoming values from the
data feed. The *args and *kwargs are the same passed to __init__
RETURN VALUES:
True: the inner data fetching loop of the data feed must retry fetching data from the
feed, becaue the length of the stream was manipulated
False even if data may have been edited (example: changed close price), the length of
the stream has remain untouched
This will be called when the data feed is over, allowing the filter
to deliver data it may have for example buffered. A typical case is
resampling, because a bar is buffered until data from the next time
period is seen. When the data feed is over, there is no new data to
push the buffered data out.
Note
It is obvious that if the filter supports no arguments at all and will be added
without any, the signatures can be simplified as in:
A Sample Filter
337
backtrader’s documentation Version-1.9.58.122
class SessionFilter(object):
def __init__(self, data):
pass
This filter:
Note
the data.backwards() makes uses of the LineBuffer interface. This digs deep
into the internals of backtrader.
• Some data feeds contain out of regular trading hours data, which may not be of interest to the trader.
With this filter only in-session bars will be considered.
In the example above it has been shown how the filter invokes data.backwards() to
remove the current bar from the stream. Useful calls from the data feed objects
which are meant as a pseudo-API for Filters are:
If stash=True the bar will undergo the entire loop processing including
potentially being reparsed by filters
This is an example of a filter that can be chained, and is meant so, to another
filter, namely the replay filter. The Pinkfish name is from the library which
describes the idea in its main page: using daily data to execute operations which
would only be possible with intraday data.
Logic:
• When an OHLC bar is received it is copied into an interable and broken down to become:
o An OHL bar. Because this concept doesn’t actually exist the closing price is replaced with the
opening price to really form an OHLO bar.
339
backtrader’s documentation Version-1.9.58.122
o An C bar whic also doesn’t exist. The reality is that it will be delivered like a tick CCCC
o The volume if distributed between the 2 parts
o The current bar is removed from the stream
o The OHLO part is put onto the stack for immediate processing
o The CCCC part is put into the stash for processing in the next round
o Because the stack has something for immediate processing the filter can return False to indicate
it.
• The replay filter which puts together the OHLO and CCCC parts to finally deliver an OHLC bar.
• Seeing something like if the maximum today is the highest maximum in the last 20 sessions an issuing a
Close order which gets executed with the 2nd tick.
The code:
and
The ``Close`` price will be used for the four components of the price
The volume will be split amongst the 2 ticks using the parameters:
340
backtrader’s documentation Version-1.9.58.122
'''
params = (
('closevol', 0.5), # 0 -> 1 amount of volume to keep for close
)
# replaying = True
if self.lastdt == datadt:
return False # skip bars that come again in the filter
# Adjust times
dt = datetime.datetime.combine(datadt, data.p.sessionstart)
ohlbar[data.DateTime] = data.date2num(dt)
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)
Using Indicators
• Inside Strategies
• Inside other Indicators
Indicators in action
• Any Indicator (or value thereof derived) declared during __init__ will be precalculated before next is
called.
__init__ vs next
• Any operation involving lines objects during __init__ generates another lines object
• Any operation involving lines objects during next yields regular Python types like floats and bools.
342
backtrader’s documentation Version-1.9.58.122
During __init__
It does obviously contains for each bar of the data feed the difference between
the high and the low.
This also works when mixing simple lines (like those in the self.data Data Feed)
and complex ones like indicators:
sma = bt.SimpleMovingAverage(self.data.close)
close_sma_diff = self.data.close - sma
During next
In this case close_over_sma yields a boolen which is the result of comparing two
floating point values, the ones returned by the [0] operator applied to
self.data.close and self.sma
343
backtrader’s documentation Version-1.9.58.122
Logic simplification (and with it ease of use) is the key. Calculations and most
of the associated logic can be declared during __init__ keeping the actual
operational logic to a minimum during next.
class MyStrategy(bt.Strategy):
def __init__(self):
sma1 = btind.SimpleMovingAverage(self.data)
ema1 = btind.ExponentialMovingAverage()
def next(self):
if buy_sig:
self.buy()
Note
Python’s and operator cannot be overriden, forcing the platform to define its
own And. The same applies to other constructs like Or and If
It should be obvious that the “declarative” approach during __init__ keeps the
bloating of next (where the actual strategy work happens) to a minimum.
Note
When the logic gets really complicated and involves several operations it is
usually much better to encapsulate that inside an Indicator.
344
backtrader’s documentation Version-1.9.58.122
Some notes
In the example above there are two things which have been simplified in
backtrader when compared to other platforms:
And in spite of it the strategy will kick the calculation of the Indicators
and any lines object generated because of operations (like sma - ema)
This is intentional. If no data is passed, the 1st data of the parent (in
this case the Strategy in which is being created) will be automatically
passed in the background
Indicator Plotting
The name parameter gives name to the single line held by this indicator.
Controlling plotting
class MyIndicator(bt.Indicator):
....
plotinfo = dict(subplot=False)
345
backtrader’s documentation Version-1.9.58.122
....
The value can be later accessed (and set) as follows (if needed):
The subplot=True will be passed to the (behind the scenes) intantiated member
variable plotinfo for the indicator.
Sets the plotname to show on the plot. The empty value means the canonical
name of the indicator (class.__name__) will be used. This has some
limitations because Python identifiers cannot use for example arithmetic
operators.
class DIPlus(bt.Indicator):
plotinfo=dict(plotname='DI+')
Indicators are usually plotted (those with subplot=True) below the data
they have operated on. Setting this to True will make the indicator be
plotted above the data.
This default behavior makes sense because the user wants to usually see
that a SimpleMovingAverage has been created using the RSI.
if the value is set to True the actual name of the line inside the
SimpleMovingAverage will be used.
Amount of margin to leave at the top and bottom of the indicator (0.15 ->
15%). Sometimes the matplotlib plots go too far to the top/bottom of the
axis and a margin may be wished
Some indicators offer parameters like upperband and lowerband that are
actually used to manipulate the y ticks
Used to control the drawing of horizontal lines along the indicator axis.
For something like a Stochastic it may make sense to draw lines for well-
known idustry standards like: [20.0, 80.0]
Some indicators offer parameters like upperband and lowerband that are
actually used to manipulate the horizontal lines
TA-Lib
• Indicator X is in the library and not in backtrader (the author would gladly accept a request)
• TA-LIB behavior is well known and people trust good old things
Requirements
Using ta-lib
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)
...
...
import backtrader as bt
348
backtrader’s documentation Version-1.9.58.122
class MyStrategy(bt.Strategy):
params = (('period', 20),)
def __init__(self):
self.sma = bt.talib.SMA(self.data, timeperiod=self.p.period)
...
...
Et voilá! Of course the params for the ta-lib indicators are defined by the
library itself and not by backtrader. In this case the SMA in ta-lib takes a
parameter named timeperiod to defined the size of the operating window.
For indicators that require more than one input, for example the Stochastic:
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)
...
...
Notice how high, low and close have been individually passed. One could always
pass open instead of low (or any other data series) and experiment.
print(bt.talib.SMA.__doc__)
SMA([input_arrays], [timeperiod=30])
349
backtrader’s documentation Version-1.9.58.122
Inputs:
price: (any ndarray)
Parameters:
timeperiod: 30
Outputs:
real
• Which Input is to be expected (DISREGARD the ``ndarray`` comment because backtrader manages the
conversions in the background)
• Which parameters and which default values
• Which output lines the indicator actually offers
import backtrader as bt
print('SMA:', bt.talib.MA_Type.SMA)
print('T3:', bt.talib.MA_Type.T3)
Just as with regular usage, there is nothing special to do to plot the ta-lib
indicators.
Note
Indicators which output a CANDLE (all those looking for a candlestick pattern)
deliver a binary output: either 0 or 100. In order to avoid adding a subplot to
the chart, there is an automated plotting translation to plot them over the data
at the point in time in which the pattern was recognized.
The following are plots comparing the outputs of some ta-lib indicators against
the equivalent built-in indicators in backtrader. To consider:
• The ta-lib indicators get a TA_ prefix on the plot. This is specifically done by the sample to help the user
spot which is which
350
backtrader’s documentation Version-1.9.58.122
• Moving Averages (if both deliver the same result) will be plotted ON top of the other existing Moving
Average. The two indicators cannot be seen separately and the test is a pass if that’s the case.
• All samples include a CDLDOJI indicator as a reference
This is the 1st example because it is the only (from all indicators which the
sample directly compare) that has a difference:
• The initial values of the the samples are not the same
• At some point in time, the values converge and both KAMA implementations have the same behavior.
The choice can be seen in the source code quoting from the source code):
The yesterday price is used here as the previous KAMA.
backtrader does the usual choice which is the same as for example the one from
Stockcharts:
• KAMA at StockCharts
Since we need an initial value to start the calculation, the first KAMA is
just a simple moving average
• The ta-lib KAMA implementation doesn’t allow specifying the fast and slow periods for the adjustment of
the scalable constant defined by Kaufman.
Sample execution:
Output
351
backtrader’s documentation Version-1.9.58.122
SMA
Output
352
backtrader’s documentation Version-1.9.58.122
EMA
Output
353
backtrader’s documentation Version-1.9.58.122
Stochastic
Output
354
backtrader’s documentation Version-1.9.58.122
RSI
Output
355
backtrader’s documentation Version-1.9.58.122
MACD
Output
356
backtrader’s documentation Version-1.9.58.122
Bollinger Bands
Output
357
backtrader’s documentation Version-1.9.58.122
AROON
Note that ta-lib chooses to put the down line first and the colours are inverted
when compared with the backtrader built-in indicator.
Output
358
backtrader’s documentation Version-1.9.58.122
Ultimate Oscillator
Output
359
backtrader’s documentation Version-1.9.58.122
Trix
Output
360
backtrader’s documentation Version-1.9.58.122
ADXR
Output
361
backtrader’s documentation Version-1.9.58.122
DEMA
Output
362
backtrader’s documentation Version-1.9.58.122
TEMA
Output
363
backtrader’s documentation Version-1.9.58.122
PPO
Here backtrader offers not only the ppo line, but a more traditional macd
approach.
Output
364
backtrader’s documentation Version-1.9.58.122
WilliamsR
Output
365
backtrader’s documentation Version-1.9.58.122
ROC
All indicators show have exactly the same shape, but how to track momentum or
rate of change has several definitions
Output
366
backtrader’s documentation Version-1.9.58.122
Sample Usage
$ ./talibtest.py --help
usage: talibtest.py [-h] [--data0 DATA0] [--fromdate FROMDATE]
[--todate TODATE]
[--ind
{sma,ema,stoc,rsi,macd,bollinger,aroon,ultimate,trix,kama,adxr,dema,tema,ppo,will
iamsr,roc}]
[--no-doji] [--use-next] [--plot [kwargs]]
optional arguments:
-h, --help show this help message and exit
--data0 DATA0 Data to be read in (default:
../../datas/yhoo-1996-2015.txt)
367
backtrader’s documentation Version-1.9.58.122
Sample Code
import argparse
import datetime
import backtrader as bt
class TALibStrategy(bt.Strategy):
params = (('ind', 'sma'), ('doji', True),)
def __init__(self):
if self.p.doji:
bt.talib.CDLDOJI(self.data.open, self.data.high,
self.data.low, self.data.close)
if self.p.ind == 'sma':
bt.talib.SMA(self.data.close, timeperiod=25, plotname='TA_SMA')
bt.indicators.SMA(self.data, period=25)
elif self.p.ind == 'ema':
368
backtrader’s documentation Version-1.9.58.122
bt.talib.EMA(timeperiod=25, plotname='TA_SMA')
bt.indicators.EMA(period=25)
elif self.p.ind == 'stoc':
bt.talib.STOCH(self.data.high, self.data.low, self.data.close,
fastk_period=14, slowk_period=3, slowd_period=3,
plotname='TA_STOCH')
bt.indicators.Stochastic(self.data)
369
backtrader’s documentation Version-1.9.58.122
def runstrat(args=None):
args = parse_args(args)
cerebro = bt.Cerebro()
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
370
backtrader’s documentation Version-1.9.58.122
cerebro.plot(**pkwargs)
def parse_args(pargs=None):
parser = argparse.ArgumentParser(
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
description='Sample for sizer')
parser.add_argument('--data0', 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')
# Plot options
parser.add_argument('--plot', '-p', nargs='?', required=False,
371
backtrader’s documentation Version-1.9.58.122
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'))
return parser.parse_args()
if __name__ == '__main__':
runstrat()
Release 1.3.0.92 brings up the possibility to have data (from either data feeds
and/or indicators) from different timeframes mixed.
As such:
• If the data sources providing the values have different timeframes, different lengths inside the Cerebro
engine, the indicator will break.
Example of a calculation, in which data0 has a timeframe of days and data1 has a
timeframe of months:
pivotpoint = btind.PivotPoint(self.data1)
sellsignal = self.data0.close < pivotpoint.s1
Here a sell signal is sought when the close is below the s1 line (1st support)
Note
And for a good reason: self.data.close provides values from the very 1st instant,
but PivotPoint (and hence the s1 line) will only deliver values once a full month
has gone by, which is roughly equivalent to 22 values of self.data0.close. During
this 22 closes there isn’t yet a value for s1 and the attempt to fetch it from
the underlying array fails.
Lines objects support the (ago) operator (__call__ special method in Python) for
deliver a delayed version of itself:
close1 = self.data.close(-1)
In this example the object close1 (when accessed via [0]) always contains the
previous value (-1) delivered by close. The syntax has been reused to accomodate
adapting timeframes. Let’s rewrite the above pivotpoint snippet:
pivotpoint = btind.PivotPoint(self.data1)
sellsignal = self.data0.close < pivotpoint.s1()
See how the () is executed with no arguments (in the background a None is being
supplied). The following is happening:
• pivotpoint.s1() is returning an internal LinesCoupler object which follows the rhythm of the larger scope.
This coupler fills itself with the latest delivered value from the real s1 (starting with a default value of
NaN)
But something extra is needed to make the magic work. Cerebro has to be created
with:
cerebro = bt.Cerebro(runonce=False)
or executed with:
cerebro.run(runonce=False)
In this mode the indicators and late-evaluated automatic lines objects are
executed step by step rather than in tight loops. This makes the entire operation
slower, but it makes it possible
The sample script at the bottom which was breaking above, now runs:
$ ./mixing-timeframes.py
With output:
373
backtrader’s documentation Version-1.9.58.122
0021,0021,0001,2005-01-31,2984.75,2935.96,0.00
0022,0022,0001,2005-02-01,3008.85,2935.96,0.00
...
0073,0073,0003,2005-04-15,3013.89,3010.76,0.00
0074,0074,0003,2005-04-18,2947.79,3010.76,1.00
...
The script also provides insight into the additional possiblity: couple all lines
of an indicator. Before we had:
pp1 = pp()
self.sellsignal = self.data0.close < pp1.s1
Now the entire PivotPoint indicator has been coupled and any of its lines can be
accessed (namely p, r1, r2, s1, s2). The script has only interest in s1 and the
access is direct.:
$ ./mixing-timeframes.py --multi
The output:
0021,0021,0001,2005-01-31,2984.75,2935.96,0.00
0022,0022,0001,2005-02-01,3008.85,2935.96,0.00
...
0073,0073,0003,2005-04-15,3013.89,3010.76,0.00
0074,0074,0003,2005-04-18,2947.79,3010.76,1.00
...
No surprises here. The same as before. The “coupled” object can even be
plotted:
374
backtrader’s documentation Version-1.9.58.122
For lines objects with multiple lines (for example Indicators like PivotPoint):
• obj(clockref=None, line=-1)
o clockref If clockref is None, the surrounding object (in the examples
a Strategy) will be the reference to adapt larger timeframes (for
example: Months) to smaller/faster timeframes (for example: Days)
• line
o If the default -1 is given, all lines are coupled.
o If another integer (for example, 0 or 1) a single line will be
coupled and fetched by index (from obj.lines[x])
o If a string is passed, the line will be fetched by name.
375
backtrader’s documentation Version-1.9.58.122
coupled_s1 = pp(line='s1')
For lines objects with a single line (for example line s1 from the indicator
PivotPoint):
Conclusion
Integrated in the regular () syntax, data feeds from different timeframes can be
mixed in indicators, always taking into account that cerebro needs to be
instantiated or created with runonce=False.
$ ./mixing-timeframes.py --help
usage: mixing-timeframes.py [-h] [--data DATA] [--multi] [--plot]
optional arguments:
-h, --help show this help message and exit
--data DATA Data to be read in (default: ../../datas/2005-2006-day-001.txt)
--multi Couple all lines of the indicator (default: False)
--plot Plot the result (default: False)
The code:
import argparse
import backtrader as bt
import backtrader.feeds as btfeeds
import backtrader.indicators as btind
import backtrader.utils.flushfile
376
backtrader’s documentation Version-1.9.58.122
class St(bt.Strategy):
params = dict(multi=True)
def __init__(self):
self.pp = pp = btind.PivotPoint(self.data1)
pp.plotinfo.plot = False # deactivate plotting
if self.p.multi:
pp1 = pp() # couple the entire indicators
self.sellsignal = self.data0.close < pp1.s1
else:
self.sellsignal = self.data0.close < pp.s1()
def next(self):
txt = ','.join(
['%04d' % len(self),
'%04d' % len(self.data0),
'%04d' % len(self.data1),
self.data.datetime.date(0).isoformat(),
'%.2f' % self.data0.close[0],
'%.2f' % self.pp.s1[0],
'%.2f' % self.sellsignal[0]])
print(txt)
def runstrat():
args = parse_args()
cerebro = bt.Cerebro()
data = btfeeds.BacktraderCSVData(dataname=args.data)
cerebro.adddata(data)
cerebro.resampledata(data, timeframe=bt.TimeFrame.Months)
cerebro.addstrategy(St, multi=args.multi)
cerebro.run(stdstats=False, runonce=False)
if args.plot:
cerebro.plot(style='bar')
def parse_args():
parser = argparse.ArgumentParser(
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
377
backtrader’s documentation Version-1.9.58.122
parser.add_argument('--data', required=False,
default='../../datas/2005-2006-day-001.txt',
help='Data to be read in')
return parser.parse_args()
if __name__ == '__main__':
runstrat()
Indicator Development
If anything (besides one or more winning Strategies) must ever be developed, this
something is a custom Indicator.
Such development within the platform is, according to the author, easy.
378
backtrader’s documentation Version-1.9.58.122
Be it not the case, at least a next has to be provided where the indicator
must assign a value to the line(s) at index 0
Optimization of the calculation for the runonce mode (batch operation) can
be achieved by providing a once method.
Indicators produce an output for each bar they receive. No assumption has to be
made about how many times the same bar will be sent. Operations have to be
idempotent.
• The same bar (index-wise) can be sent many times with changing values (namely the changing value is the
closing price)
This enables, for example, “replaying” a daily session but using intraday data
which could be made of 5 minutes bars.
It could also allow the platform to get values from a live feed.
So can it be:
class DummyInd(bt.Indicator):
lines = ('dummyline',)
def __init__(self):
self.lines.dummyline = bt.Max(0.0, self.params.value)
Done! The indicator will output always the same value: either 0.0 or
self.params.value if it happens to be greater than 0.0.
class DummyInd(bt.Indicator):
lines = ('dummyline',)
379
backtrader’s documentation Version-1.9.58.122
def next(self):
self.lines.dummyline[0] = max(0.0, self.params.value)
Note
Notice how in the __init__ version bt.Max is used to assign to the Line object
self.lines.dummyline.
bt.Max returns an lines object that is automatically iterated for each bar passed
to the indicator.
Had max been used instead, the assigment would have been pointless, because
instead of a line, the indicator would have a member variable with a fixed value.
During next the work is done directly with floating point values and the standard
max built-in can be used
Let’s recall that self.lines.dummyline is the long notation and that it can be
shortened to:
• self.l.dummyline
• self.dummyline
The latter being only possible if the code has not obscured this with a member
attribute.
The 3rd and last version provides an additional once method to optimize the
calculation:
class DummyInd(bt.Indicator):
lines = ('dummyline',)
def next(self):
self.lines.dummyline[0] = max(0.0, self.params.value)
A lot more effective but developing the once method has forced to scratch beyond
the surface. Actually the guts have been looked into.
Be it needed for development, the indicator can also override the methods
associated to next and once:
If possible the platform will calculate it, but manual action may be needed.
class SimpleMovingAverage1(Indicator):
lines = ('sma',)
params = (('period', 20),)
def next(self):
datasum = math.fsum(self.data.get(size=self.p.period))
self.lines.sma[0] = datasum / self.p.period
Although it seems sound, the platform doesn’t know what the minimum period is,
even if the parameter is named “period” (the name could be misleading and some
indicators receive several “period”s which have different usages)
In this case next would be called already for the 1st bar and everthing would
explode because get cannot return the needed self.p.period.
• The data feeds passed to the indicators may already carry a minimum period
This has a default mininum period of 1 (just wait for the 1st bar that
enters the system)
• Another Moving Average ... and this in turn already has a period
If this is 20 and again our sample moving average has also 20, we end up
with a minimum period of 40 bars
Actually the internal calculation says 39 ... because as soon as the first
moving average has produced a bar this counts for the next moving average,
which creates an overlapping bar, thus 39 are needed.
class SimpleMovingAverage1(Indicator):
lines = ('sma',)
params = (('period', 20),)
def __init__(self):
self.addminperiod(self.params.period)
def next(self):
datasum = math.fsum(self.data.get(size=self.p.period))
self.lines.sma[0] = datasum / self.p.period
The addminperiod method is telling the system to take into account the extra
period bars needed by this indicator to whatever minimum period there may be in
existence.
Sometimes this is absolutely not needed, if all calculations are done with
objects which already communicate its period needs to the system.
class MACD(Indicator):
lines = ('macd', 'signal', 'histo',)
params = (('period_me1', 12), ('period_me2', 26), ('period_signal', 9),)
def __init__(self):
me1 = EMA(self.data, period=self.p.period_me1)
me2 = EMA(self.data, period=self.p.period_me2)
382
backtrader’s documentation Version-1.9.58.122
And this one (already in the platform) already states what it needs
• The named lines of the indicator “macd” and “signal” are being assigned
objects which already carry declared (behind the scenes) periods
o macd takes the period from the operation “me1 - me2” which has in turn take the maximum
from the periods of me1 and me2 (which are both exponential moving averages with different
periods)
o signal takes directly the period of the Exponential Moving Average over macd. This EMA also
takes into account the already existing macd period and the needed amount of samples
(period_signal) to calculate itself
o histo takes the maximum of the two operands “signal - macd”. Once both are ready can histo also
produce a value
import backtrader as bt
import backtrader.indicators as btind
class OverUnderMovAv(bt.Indicator):
lines = ('overunder',)
params = dict(period=20, movav=btind.MovAv.Simple)
def __init__(self):
movav = self.p.movav(self.data, period=self.p.period)
self.l.overunder = bt.Cmp(movav, self.data)
Done! The indicator will have a value of “1” if the average is above the data
and “-1” if below.
Be the data a regular data feed the 1s and -1s would be produced comparing with
the close price.
383
backtrader’s documentation Version-1.9.58.122
Although more can be seen in the Plotting section and to have a behaved and nice
citizen in the plotting world, a couple of things can be added:
import backtrader as bt
import backtrader.indicators as btind
class OverUnderMovAv(bt.Indicator):
lines = ('overunder',)
params = dict(period=20, movav=bt.ind.MovAv.Simple)
plotinfo = dict(
# Add extra margins above and below the 1s and -1s
plotymargin=0.15,
# Plot the line "overunder" (the only one) with dash style
# ls stands for linestyle and is directly passed to matplotlib
plotlines = dict(overunder=dict(ls='--'))
def _plotlabel(self):
# This method returns a list of labels that will be displayed
# behind the name of the indicator on the plot
# Put only the moving average if it's not the default one
plabels += [self.p.movav] * self.p.notdefault('movav')
return plabels
def __init__(self):
movav = self.p.movav(self.data, period=self.p.period)
self.l.overunder = bt.Cmp(movav, self.data)
Strategies running inside the backtrader do mostly deal with data feeds and
indicators.
384
backtrader’s documentation Version-1.9.58.122
Data feeds are added to Cerebro instances and end up being part of the input of
strategies (parsed and served as attributes of the instance) whereas Indicators
are declared and managed by the Strategy itself.
All backtrader sample charts have so far had 3 things plotted which seem to be
taken for granted because they are not declared anywhere:
• Cash and Value (what’s happening with the money in the broker)
• Trades (aka Operations)
• Buy/Sell Orders
They are Observers and exist within the submodule backtrader.observers. They are
there because Cerebro supports a parameter to automatically add (or not) them to
the Strategy:
If the default is respected Cerebro executes the following equivalent user code:
import backtrader as bt
...
cerebro.addobserver(bt.observers.Broker)
cerebro.addobserver(bt.observers.Trades)
cerebro.addobserver(bt.observers.BuySell)
Let’s see the usual chart with those 3 default observers (even if no order is
issued and therefore no trade happens and there is no change to the cash and
portfolio value)
import backtrader as bt
import backtrader.feeds as btfeeds
if __name__ == '__main__':
cerebro = bt.Cerebro(stdstats=False)
cerebro.addstrategy(bt.Strategy)
data = bt.feeds.BacktraderCSVData(dataname='../../datas/2006-day-001.txt')
cerebro.adddata(data)
385
backtrader’s documentation Version-1.9.58.122
cerebro.run()
cerebro.plot()
Now let’s change the value of stdstats to False when creating the Cerebro
instance (can also be done when invoking run):
cerebro = bt.Cerebro(stdstats=False)
386
backtrader’s documentation Version-1.9.58.122
The Observers as seen above are already there in the default case and collecting
information which can be used for statistical purposes and that’s why acess to
the observers can be done through an attribute of the strategy called:
• stats
...
cerebro.addobserver(backtrader.observers.Broker)
...
387
backtrader’s documentation Version-1.9.58.122
The obvious question would be how to access the Broker observer. Here for example
how it’s done from the next method of a strategy:
class MyStrategy(bt.Strategy):
def next(self):
The Broker observer just like a Data, an Indicator and the Strategy itself is
also a Lines objects. In this case the Broker has 2 lines:
• cash
• value
Observer Implementation
class Broker(Observer):
alias = ('CashValue',)
lines = ('cash', 'value')
def next(self):
self.lines.cash[0] = self._owner.broker.getcash()
self.lines.value[0] = value = self._owner.broker.getvalue()
Steps:
388
backtrader’s documentation Version-1.9.58.122
In the Broker case it’s simply blindly recording the broker cash and portfolio
values at each point in time.
As already pointed out above, Cerebro is using the stdstats parameter to decide
whether to add 3 default Observers, alleviating the work of the end user.
Let’s go for the usual strategy which buys when the close price goes above a
SimpleMovingAverage and sells if the opposite is true.
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 MyStrategy(bt.Strategy):
params = (('smaperiod', 15),)
def __init__(self):
389
backtrader’s documentation Version-1.9.58.122
...
2006-12-14T23:59:59+00:00, MaxDrawDown: 2.62
2006-12-15T23:59:59+00:00, DrawDown: 0.22
2006-12-15T23:59:59+00:00, MaxDrawDown: 2.62
2006-12-18T23:59:59+00:00, DrawDown: 0.00
2006-12-18T23:59:59+00:00, MaxDrawDown: 2.62
2006-12-19T23:59:59+00:00, DrawDown: 0.00
2006-12-19T23:59:59+00:00, MaxDrawDown: 2.62
2006-12-20T23:59:59+00:00, DrawDown: 0.10
2006-12-20T23:59:59+00:00, MaxDrawDown: 2.62
2006-12-21T23:59:59+00:00, DrawDown: 0.39
2006-12-21T23:59:59+00:00, MaxDrawDown: 2.62
2006-12-22T23:59:59+00:00, DrawDown: 0.21
390
backtrader’s documentation Version-1.9.58.122
Note
As seen in the text output and in the code, the DrawDown observer has actually 2
lines:
• drawdown
• maxdrawdown
The choice is not to plot the maxdrawdown line, but make it is still available to
the user.
Developing Observers
• _orderspending -> list orders created by the strategy and for which the
broker has notified an event to the strategy.
The BuySell observer traverses the list looking for orders which have
executed (totally or partially) to create an average execution price for
the given point in time (index 0)
391
backtrader’s documentation Version-1.9.58.122
An Observer can obviously access other observers over the self._owner.stats path.
Custom OrderObserver
The standard BuySell observer does only care about operations which have
executed. We can create an observer which shows when orders where created and if
they expired.
For the sake of visibility the display will not be plotted along the price but on
a separate axis.
import math
import backtrader as bt
class OrderObserver(bt.observer.Observer):
lines = ('created', 'expired',)
plotlines = dict(
created=dict(marker='*', markersize=8.0, color='lime', fillstyle='full'),
expired=dict(marker='s', markersize=8.0, color='red', fillstyle='full')
)
def next(self):
for order in self._owner._orderspending:
if order.data is not self.data:
continue
if not order.isbuy():
continue
392
backtrader’s documentation Version-1.9.58.122
The custom observer only cares about buy orders, because this is a strategy which
only buys to try to make a profit. Sell orders are Market orders and will be
executed immediately.
• Create a Limit order with a price below 1.0% the close price at the moment of the signal
• A validity for the order of 7 (calendar) days
393
backtrader’s documentation Version-1.9.58.122
Several orders have expired as can be seen in the new subchart (red squares) and
we can also appreciate that between “creation” and “execution” several days
happen to be.
Finally the code for this strategy which applies the new observer
import datetime
import backtrader as bt
import backtrader.feeds as btfeeds
import backtrader.indicators as btind
class MyStrategy(bt.Strategy):
params = (
('smaperiod', 15),
('limitperc', 1.0),
('valid', 7),
)
if order.status in [order.Expired]:
self.log('BUY EXPIRED')
394
backtrader’s documentation Version-1.9.58.122
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))
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)
def next(self):
if self.order:
# pending order ... do nothing
return
395
backtrader’s documentation Version-1.9.58.122
def runstrat():
cerebro = bt.Cerebro()
data = bt.feeds.BacktraderCSVData(dataname='../../datas/2006-day-001.txt')
cerebro.adddata(data)
cerebro.addobserver(OrderObserver)
cerebro.addstrategy(MyStrategy)
cerebro.run()
cerebro.plot()
if __name__ == '__main__':
runstrat()
As of now backtrader has not implemented any mechanism to track the values of
observers storing them into files. The best way to do it:
class MyStrategy(bt.Strategy):
def start(self):
def next(self):
self.mystats.write(self.data.datetime.date(0).strftime('%Y-%m-%d'))
self.mystats.write(',%.2f' % self.stats.drawdown.drawdown[-1])
self.mystats.write(',%.2f' % self.stats.drawdown.maxdrawdown-1])
self.mystats.write('\n')
To save the values of index 0, once all observers have been processed a custom
observer which writes to a file could be added as the last observer to the system
to save values to a csv file.
396
backtrader’s documentation Version-1.9.58.122
Note
Benchmarking
Ticket #89 is about adding benchmarking against an asset. Sensible as one may
actually have a strategy that even if positive is below what simply tracking the
asset would have delivered.
backtrader includes 2 different types of objects which can aid with tracking:
• Observers
• Analyzers
In the realm of Analyzers there was already a TimeReturn object which tracks the
evolution of the returns of the entire portfolio value (i.e: including cash)
This could have also obviously been an Observer, so whilst adding some
benchmarking some work has also gone into being able to plug together an Observer
and an Analyzer which are meant to track the same thing.
Note
The major difference between Observers and Analyzers is the lines nature of
observers, which record every value and this makes them suitable for plotting and
real time querying. This of course consumes memory.
Analyzers on the other hand return a set of results via get_analysis and the
implementation may not deliver any result until the very end of a run.
Analyzers - Benchmarking
The standard TimeReturn analyzer has been extended to support tracking a data
feed. The 2 major parameters invoved:
• timeframe (default: None) If None then the complete return over the entire
backtested period will be reported
397
backtrader’s documentation Version-1.9.58.122
Note
this data must have been added to a cerebro instance with addata,
resampledata or replaydata
As such, the returns of the porftolio on a yearly basis can be tracked like this
import backtrader as bt
cerebro = bt.Cerebro()
cerebro.addanalyzer(bt.analyzers.TimeReturn, timeframe=bt.TimeFrame.Years)
results = cerebro.run()
strat0 = results[0]
# If no name has been specified, the name is the class name lowercased
tret_analyzer = strat0.analyzers.getbyname('timereturn')
print(tret_analyzer.get_analysis())
import backtrader as bt
cerebro = bt.Cerebro()
cerebro.addanalyzer(bt.analyzers.TimeReturn, timeframe=bt.TimeFrame.Years,
data=data)
results = cerebro.run()
strat0 = results[0]
# If no name has been specified, the name is the class name lowercased
tret_analyzer = strat0.analyzers.getbyname('timereturn')
print(tret_analyzer.get_analysis())
398
backtrader’s documentation Version-1.9.58.122
import backtrader as bt
cerebro = bt.Cerebro()
cerebro.addanalyzer(bt.analyzers.TimeReturn, timeframe=bt.TimeFrame.Years,
data=data, _name='datareturns')
cerebro.addanalyzer(bt.analyzers.TimeReturn, timeframe=bt.TimeFrame.Years)
_name='timereturns')
results = cerebro.run()
strat0 = results[0]
# If no name has been specified, the name is the class name lowercased
tret_analyzer = strat0.analyzers.getbyname('timereturns')
print(tret_analyzer.get_analysis())
tdata_analyzer = strat0.analyzers.getbyname('datareturns')
print(tdata_analyzer.get_analysis())
Observers - Benchmarking
• TimeReturn
• Benchmark
Rather than having code snippets like above, a full sample with some runs to show
their functionality.
Observing TimeReturn
Execution:
399
backtrader’s documentation Version-1.9.58.122
• The starting cash (obvious from the chart) are 50K monetary units and the strategy ends up with 36,970
monetary units and hence a -26% value decrement.
Observing Benchmarking
Because benchmarking will also display the timereturn results, let’s run the
same thing but with benchmarking active:
400
backtrader’s documentation Version-1.9.58.122
401
backtrader’s documentation Version-1.9.58.122
Watch out!
• The strategy last value has changed very slightly from -0.26 to -0.27
• The asset on the on the other hand shows a last value of -0.35 (versus -0.33 above)
The reason for values so close to each other is that when moving from 2005 to
2006, both the strategy and the benchmarking asset were almost at the starting
level from the beginning of 2005.
.. thumbnail:: 04-benchmarking-weeks.png
Now:
402
backtrader’s documentation Version-1.9.58.122
• The Benchmark observer shows a much more nervous aspect. Things move up and down, because now
weekly returns for both the portfolio and the data are being tracked
• And because no trade was active in the last week of the year and the asset barely moved, the last
displayed values are 0.00 (The last closing value before the last week was 25.54 and the sample data
closed at 25.55, and the difference is felt first at the 4th decimal point)
It’s clear now why there was no reason for celebration above:
• The results of the strategy have not changed for notimeframe and remain at -26% (-0.26)
• But when benchmarking against another data, this data has a +23% (0.23 ) in the same period
403
backtrader’s documentation Version-1.9.58.122
Concluding
There are now two ways, using the same underlying code/calculations, to track the
TimeReturn and Benchmark
and
$ ./observer-benchmark.py --help
usage: observer-benchmark.py [-h] [--data0 DATA0] [--data1 DATA1]
[--benchdata1] [--fromdate FROMDATE]
[--todate TODATE] [--printout] [--cash CASH]
[--period PERIOD] [--stake STAKE] [--timereturn]
[--timeframe
{months,days,notimeframe,years,None,weeks}]
[--plot [kwargs]]
optional arguments:
-h, --help show this help message and exit
--data0 DATA0 Data0 to be read in (default:
../../datas/yhoo-1996-2015.txt)
--data1 DATA1 Data1 to be read in (default:
../../datas/orcl-1995-2014.txt)
--benchdata1 Benchmark against data1 (default: False)
--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)
--printout Print data lines (default: False)
--cash CASH Cash to start with (default: 50000)
--period PERIOD Period for the crossover moving average (default: 30)
--stake STAKE Stake to apply for the buy operations (default: 1000)
--timereturn Use TimeReturn observer instead of Benchmark (default:
None)
404
backtrader’s documentation Version-1.9.58.122
--timeframe {months,days,notimeframe,years,None,weeks}
TimeFrame to apply to the Observer (default: None)
--plot [kwargs], -p [kwargs]
Plot the read data applying any kwargs passed For
example: --plot style="candle" (to plot candles)
(default: None)
The code
import argparse
import datetime
import random
import backtrader as bt
class St(bt.Strategy):
params = (
('period', 10),
('printout', False),
('stake', 1000),
)
def __init__(self):
sma = bt.indicators.SMA(self.data, period=self.p.period)
self.crossover = bt.indicators.CrossOver(self.data, sma)
def start(self):
if self.p.printout:
txtfields = list()
txtfields.append('Len')
txtfields.append('Datetime')
txtfields.append('Open')
txtfields.append('High')
txtfields.append('Low')
txtfields.append('Close')
txtfields.append('Volume')
txtfields.append('OpenInterest')
print(','.join(txtfields))
405
backtrader’s documentation Version-1.9.58.122
def next(self):
if self.p.printout:
# Print only 1st data ... is just a check that things are running
txtfields = list()
txtfields.append('%04d' % len(self))
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 self.position:
if self.crossover < 0.0:
if self.p.printout:
print('CLOSE {} @%{}'.format(size,
self.data.close[0]))
self.close()
else:
if self.crossover > 0.0:
self.buy(size=self.p.stake)
if self.p.printout:
print('BUY {} @%{}'.format(self.p.stake,
self.data.close[0]))
TIMEFRAMES = {
None: None,
'days': bt.TimeFrame.Days,
'weeks': bt.TimeFrame.Weeks,
'months': bt.TimeFrame.Months,
'years': bt.TimeFrame.Years,
'notimeframe': bt.TimeFrame.NoTimeFrame,
}
def runstrat(args=None):
args = parse_args(args)
cerebro = bt.Cerebro()
406
backtrader’s documentation Version-1.9.58.122
cerebro.broker.set_cash(args.cash)
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
cerebro.addstrategy(St,
period=args.period,
stake=args.stake,
printout=args.printout)
if args.timereturn:
cerebro.addobserver(bt.observers.TimeReturn,
timeframe=TIMEFRAMES[args.timeframe])
else:
benchdata = data0
if args.benchdata1:
data1 = bt.feeds.YahooFinanceCSVData(dataname=args.data1, **dkwargs)
cerebro.adddata(data1, name='Data1')
benchdata = data1
cerebro.addobserver(bt.observers.Benchmark,
data=benchdata,
timeframe=TIMEFRAMES[args.timeframe])
cerebro.run()
if args.plot:
pkwargs = dict()
if args.plot is not True: # evals to True but is not True
pkwargs = eval('dict(' + args.plot + ')') # args were passed
cerebro.plot(**pkwargs)
def parse_args(pargs=None):
407
backtrader’s documentation Version-1.9.58.122
parser = argparse.ArgumentParser(
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
description='Benchmark/TimeReturn Observers Sample')
parser.add_argument('--data0', required=False,
default='../../datas/yhoo-1996-2015.txt',
help='Data0 to be read in')
parser.add_argument('--data1', required=False,
default='../../datas/orcl-1995-2014.txt',
help='Data1 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')
default=None, choices=TIMEFRAMES.keys(),
help=('TimeFrame to apply to the Observer'))
# 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:
return parser.parse_args(pargs)
return parser.parse_args()
if __name__ == '__main__':
runstrat()
Analyzers
That’s where the family of Analyzer objects comes in: provide an analysis of
what’s happened or even of what’s actually happening.
Nature of analyzers
The interface is modeled after that of Lines objects, feature for example a next
method but there is a major difference:
That means they are not expensive in terms of memory because even after
having analyzed thousands of price bars they may still simply hold a single
result in memory.
409
backtrader’s documentation Version-1.9.58.122
Analyzer objects are (like strategies, observers and datas) added to the system
through a cerebro instance:
But when it comes to operation during cerebro.run the following will happen for
each strategy present in the system
That means:
• If the backtesting run contains for example 3 strategies then 3 instances of ancls will be created and each
of them will be attached to a different strategy.
Bottomline: an analyzer analyzes the performance of a single strategy and not the
performance of an entires system
Additional Location
Some Analyzer objects may actually use other analyzers to complete its work. For
example: SharpeRatio uses the output of TimeReturn for the calculations.
Attributes
To carry out the intended work, Analyzer objects are provided with some default
attributes which are automagically passed and set in the instance for ease of
use:
• self.strategy: reference to the strategy subclass in which the analyzer object is operating. Anything
accessible by the strategy can also be accessd by the analyzer
• self.datas[x]: the array of data feeds present in the strategy. Although this could be accesed over the
strategy reference, the shortcut makes work more comfortable.
• self.data: shortcut to self.datas[0] for extra comfort.
• self.dataX: shortcuts to the different self.datas[x]
Some other aliases are available although they are probably an overkill:
410
backtrader’s documentation Version-1.9.58.122
• self.dataX_Y where X is a reference to self.datas[X] and Y refers to the line, finally pointing to:
self.datas[X].lines[Y]
• self.dataX_Name which resolves to self.datas[X].Name returning the line by name rather than by index
For the first data, the last two shortcuts are available without the initial X
numeric reference. For example:
And
Modus operandi
Although Analyzer objects are not Lines objects and therefore do not iterate over
lines, they have been designed to follow the same operation pattern.
4. Orders and trades will be notified just like they are to the strategy via
notify_order and notify_trade
411
backtrader’s documentation Version-1.9.58.122
5. Cash and value will also be notified like it is done with the strategy over
the notify_cashvalue method
6. Cash, value and fundvalue and fund shares will also be notified like it is
done with the strategy over the notify_fund method
7. stop will be invoked to signal the end of operations
Once the regular operations cycle has been completed, the analyzers featuring
additional methods for extracting/outputting information
• get_analysis: which ideally (not enforced) returnes a dict -like object containing the analysis results.
• print uses a standard backtrader.WriterFile (unless overriden) to write the analysis result from
get_analysis.
• pprint (pretty print) uses the Python pprint module to print the get_analysis resutls.
And finally:
Analyzer Patterns
2. Gather (or not) the information as above, but generate the analysis in a
single pass during the stop method
A quick example
import datetime
import backtrader as bt
import backtrader.analyzers as btanalyzers
import backtrader.feeds as btfeeds
import backtrader.strategies as btstrats
cerebro = bt.Cerebro()
# data
dataname = '../datas/sample/2005-2006-day-001.txt'
data = btfeeds.BacktraderCSVData(dataname=dataname)
cerebro.adddata(data)
# strategy
cerebro.addstrategy(btstrats.SMA_CrossOver)
# Analyzer
cerebro.addanalyzer(btanalyzers.SharpeRatio, _name='mysharpe')
thestrats = cerebro.run()
thestrat = thestrats[0]
$ ./analyzer-test.py
Sharpe Ratio: {'sharperatio': 11.647332609673256}
There is no plotting, because the SharpeRatio is a single value at the end of the
calculation.
Let’s repeat that Analyzers are not Lines objects, but to seamlessly integrate
them into the backtrader ecosystem, the internal API conventions of several Lines
object are followed (actually a mixture of them)
Note
413
backtrader’s documentation Version-1.9.58.122
The code for the SharpeRatio has evolved to take for example into account
annualization and the version here should only be a reference.
import operator
class SharpeRatio(Analyzer):
params = (('timeframe', TimeFrame.Years), ('riskfreerate', 0.01),)
def __init__(self):
super(SharpeRatio, self).__init__()
self.anret = AnnualReturn()
def start(self):
# Not needed ... but could be used
pass
def next(self):
# Not needed ... but could be used
pass
def stop(self):
retfree = [self.p.riskfreerate] * len(self.anret.rets)
retavg = average(list(map(operator.sub, self.anret.rets, retfree)))
retdev = standarddev(self.anret.rets)
def get_analysis(self):
return dict(sharperatio=self.ratio)
414
backtrader’s documentation Version-1.9.58.122
• params declaration
Although the declared ones are not used (meant as an example), Analyzers
like most other objects in backtrader support parameters
• __init__ method
Note
The actual implementation of SharpeRatio uses the more generic and later
developed TimeReturn analyzer
• next method
SharpeRatio doesn’t need it, but this method will be called after each
invocation of the parent strategy next
• start method
Called right before the backtesting starts. Can be used for extra
initialization tasks. Sharperatio doesn’t need it
• stop method
Called right after the backtesting ends. Like SharpeRatio does, it can be
used to finish/make the calculation
Reference
class backtrader.Analyzer
415
backtrader’s documentation Version-1.9.58.122
• self.strategy (giving access to the strategy and anything accessible from it)
• self.datas[x] giving access to the array of data feeds present in the the system, which could also
be accessed via the strategy reference
• self.data, giving access to self.datas[0]
• self.dataX -> self.datas[X]
• self.dataX_Y -> self.datas[X].lines[Y]
• self.dataX_name -> self.datas[X].name
• self.data_name -> self.datas[0].name
• self.data_Y -> self.datas[0].lines[Y]
This is not a Lines object, but the methods and operation follow the same
design
start()
stop()
Invoked to indicate the end of operations, giving the analyzer time to shut
down needed things
416
backtrader’s documentation Version-1.9.58.122
prenext()
Invoked for each prenext invocation of the strategy, until the minimum
period of the strategy has been reached
nextstart()
Invoked exactly once for the nextstart invocation of the strategy, when the
minimum period has been first reached
next()
Invoked for each next invocation of the strategy, once the minum preiod of
the strategy has been reached
notify_cashvalue(cash, value)
notify_order(order)
notify_trade(trade)
get_analysis()
It is not even enforced that the result is a dict-like object, just the
convention
417
backtrader’s documentation Version-1.9.58.122
create_analysis()
print(*args, **kwargs)
pprint(*args, **kwargs)
Prints the results returned by get_analysis using the pretty print Python
module (pprint)
__len__()¶
PyFolio Overview
Note
• pyfolio obviously
• And its dependencies (things like pandas, seaborn ...)
Note
418
backtrader’s documentation Version-1.9.58.122
During the integration with version 0.5.1, an update to the most recent
packages of the dependencies was needed, like seaborn from the previously
installed 0.7.0-dev to 0.7.1, apparently due to the absence of the method
swarmplot
Usage
Note
The integration was done looking at test samples available with pyfolio and
the same headers (or absence of) has been replicated
• pyfolio automatic plotting works outside of a Jupyter Notebook, but it works best inside
• pyfolio data tables’ output seems to barely work outside of a Jupyter Notebook. It works inside the
Notebook
The conclusion is easy if working with pyfolio is wished: work inside a Jupyter
Notebook
Sample Code
...
cerebro.addanalyzer(bt.analyzers.PyFolio, _name='pyfolio')
...
results = cerebro.run()
419
backtrader’s documentation Version-1.9.58.122
strat = results[0]
pyfoliozer = strat.analyzers.getbyname('pyfolio')
returns, positions, transactions, gross_lev = pyfoliozer.get_pf_items()
...
...
# pyfolio showtime
import pyfolio as pf
pf.create_full_tear_sheet(
returns,
positions=positions,
transactions=transactions,
gross_lev=gross_lev,
live_start_date='2005-05-01', # This date is sample specific
round_trips=True)
Reference
Look into the Analyzers Reference for the PyFolio analyzer and which analyzers it
uses internally
Pyfolio Integration
The integration of a portfolio tool, namely pyfolio, came up with in Ticket #108.
A first look at the tutorial deemed it as difficult, given the tight integration
amongst zipline and pyfolio, but the sample test data available with pyfolio for
some other uses is actually pretty useful to decode what’s running behind the
scenes and hence the wonder of integration.
• Analyzer infrastructure
• Children analyzer
• A TimeReturn analyzer
Only a main PyFolio analyzer and 3 easy children analyzer are needed. Plus a
method that relies on one of the dependencies already needed by pyfolio which is
pandas.
The most challenging part ... “getting all the dependencies right”.
420
backtrader’s documentation Version-1.9.58.122
• Update of pandas
• Update of numpy
• Update of scikit-lean
• Update of seaborn
Under Unix-like environments with a C compiler it’s all about time. Under
Windows and even with the specific Microsoft compiler installed (in this case the
chain for Python 2.7) things failed. But a well known site with a collection of
up-to-date packages for Windows helped. Visit it if you ever need it:
• http://www.lfd.uci.edu/~gohlke/pythonlibs/
The integration wouldn’t be complete if it wasn’t tested and that’s why the
usual sample is as always present.
No PyFolio
Output:
Len,Datetime,Open,High,Low,Close,Volume,OpenInterest
0001,2005-01-03T23:59:59,38.36,38.90,37.65,38.18,25482800.00,0.00
BUY 1000 @%23.58
0002,2005-01-04T23:59:59,38.45,38.54,36.46,36.58,26625300.00,0.00
BUY 1000 @%36.58
SELL 500 @%22.47
0003,2005-01-05T23:59:59,36.69,36.98,36.06,36.13,18469100.00,0.00
...
SELL 500 @%37.51
0502,2006-12-28T23:59:59,25.62,25.72,25.30,25.36,11908400.00,0.00
0503,2006-12-29T23:59:59,25.42,25.82,25.33,25.54,16297800.00,0.00
SELL 250 @%17.14
SELL 250 @%37.01
421
backtrader’s documentation Version-1.9.58.122
There a 3 datas and several buy and sell operations are randomly chosen and
scattered over the 2 year default life of the test run
A PyFolio run
pyfolio things work well when running inside a Jupyter Notebook including inline
plotting. Here is the notebook
Note
runstrat gets here [] as argument to run with default arguments and skip
arguments passed by the notebook itself
%matplotlib inline
from __future__ import (absolute_import, division, print_function,
unicode_literals)
422
backtrader’s documentation Version-1.9.58.122
import argparse
import datetime
import random
import backtrader as bt
class St(bt.Strategy):
params = (
('printout', False),
('stake', 1000),
)
def __init__(self):
pass
def start(self):
if self.p.printout:
txtfields = list()
txtfields.append('Len')
txtfields.append('Datetime')
txtfields.append('Open')
txtfields.append('High')
txtfields.append('Low')
txtfields.append('Close')
txtfields.append('Volume')
txtfields.append('OpenInterest')
print(','.join(txtfields))
def next(self):
if self.p.printout:
# Print only 1st data ... is just a check that things are running
txtfields = list()
txtfields.append('%04d' % len(self))
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))
423
backtrader’s documentation Version-1.9.58.122
# Data 0
for data in self.datas:
toss = random.randint(1, 10)
curpos = self.getposition(data)
if curpos.size:
if toss > 5:
size = curpos.size // 2
self.sell(data=data, size=size)
if self.p.printout:
print('SELL {} @%{}'.format(size, data.close[0]))
def runstrat(args=None):
args = parse_args(args)
cerebro = bt.Cerebro()
cerebro.broker.set_cash(args.cash)
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
cerebro.addstrategy(St, printout=args.printout)
if not args.no_pyfolio:
cerebro.addanalyzer(bt.analyzers.PyFolio, _name='pyfolio')
424
backtrader’s documentation Version-1.9.58.122
results = cerebro.run()
if not args.no_pyfolio:
strat = results[0]
pyfoliozer = strat.analyzers.getbyname('pyfolio')
import pyfolio as pf
pf.create_full_tear_sheet(
returns,
positions=positions,
transactions=transactions,
gross_lev=gross_lev,
live_start_date='2005-05-01',
round_trips=True)
if args.plot:
cerebro.plot(style=args.plot_style)
def parse_args(args=None):
parser = argparse.ArgumentParser(
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
description='Sample for pivot point and cross plotting')
parser.add_argument('--data0', required=False,
default='../../datas/yhoo-1996-2015.txt',
help='Data to be read in')
parser.add_argument('--data1', required=False,
default='../../datas/orcl-1995-2014.txt',
help='Data to be read in')
425
backtrader’s documentation Version-1.9.58.122
parser.add_argument('--data2', required=False,
default='../../datas/nvda-1999-2014.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')
import sys
aargs = args if args is not None else sys.argv[1:]
return parser.parse_args(aargs)
runstrat([])
Entire data start date: 2005-01-03
Entire data end date: 2006-12-29
Out-of-Sample Months: 20
Backtest Months: 3
Performance statistics All history Backtest Out of sample
annual_return 0.06 -0.05 0.08
annual_volatility 0.09 0.09 0.10
sharpe_ratio 0.62 -0.55 0.83
426
backtrader’s documentation Version-1.9.58.122
427
backtrader’s documentation Version-1.9.58.122
428
backtrader’s documentation Version-1.9.58.122
429
backtrader’s documentation Version-1.9.58.122
430
backtrader’s documentation Version-1.9.58.122
431
backtrader’s documentation Version-1.9.58.122
432
backtrader’s documentation Version-1.9.58.122
D:drobinWinPython-64bit-2.7.10.3python-2.7.10.amd64libsite-
packagespyfolioplotting.py:1210: FutureWarning: .resample() is now a deferred
operation
use .resample(...).mean() instead of .resample(...)
**kwargs)
433
backtrader’s documentation Version-1.9.58.122
434
backtrader’s documentation Version-1.9.58.122
435
backtrader’s documentation Version-1.9.58.122
436
backtrader’s documentation Version-1.9.58.122
437
backtrader’s documentation Version-1.9.58.122
$ ./pyfoliotest.py --help
usage: pyfoliotest.py [-h] [--data0 DATA0] [--data1 DATA1] [--data2 DATA2]
[--fromdate FROMDATE] [--todate TODATE] [--printout]
[--cash CASH] [--plot] [--plot-style {bar,candle,line}]
[--no-pyfolio]
optional arguments:
-h, --help show this help message and exit
--data0 DATA0 Data to be read in (default:
../../datas/yhoo-1996-2015.txt)
--data1 DATA1 Data to be read in (default:
../../datas/orcl-1995-2014.txt)
--data2 DATA2 Data to be read in (default:
../../datas/nvda-1999-2014.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)
--printout Print data lines (default: False)
--cash CASH Cash to start with (default: 50000)
--plot Plot the result (default: False)
--plot-style {bar,candle,line}
Plot style (default: bar)
--no-pyfolio Do not do pyfolio things (default: False)
Writer
Which objects actually go into the csv stream can be controlled with the
csv attribute of each object (defaults to True for data feeds and observers
/ False for indicators)
438
backtrader’s documentation Version-1.9.58.122
There is only a single Writer defined called WriterFile, which can be added to
the system:
Given that a standard WriterFile does not ouput csv as a default, the
following addwriter invocation would take care of it:
cerebro.addwriter(bt.WriterFile, csv=True)
Reference
class backtrader.WriterFile
Which objects actually go into the csv stream can be controlled with
the csv attribute of each object (defaults to True for data feeds and
observers / False for indicators)
439
backtrader’s documentation Version-1.9.58.122
Agnosticity
Before going forward let’s remember that backtrader tries to remain agnostic as
to what the data represents. Different commission schemes can be applied to the
same data set.
This keeps the end user away from CommissionInfo objects because a commission
scheme can be created/set with a single function call. Within the regular cerebro
creation/set-up process, just add a call to setcommission over the broker member
attribute. The following call sets a usual commission scheme for Eurostoxx50
futures when working with Interactive Brokers:
Since most users will usually just test a single instrument, that’s all that’s
down to it. If you have given a name to your data feed, because several
instruments are being considered simultaneously on a chart, this call can be
slightly extended to look as follows:
440
backtrader’s documentation Version-1.9.58.122
In this case this on-the-fly commission scheme will only applied to instruments
whose name matches Eurostoxx50.
In the above example it is 2.0 euros per contract for a buy and again 2.0
euros per contract for a sell.
o If margin evaluates to False (it is False, 0 or None for example) then it will be considered that
commission expresses a percentage of the price times size operatin value
o If margin is something else, it is considered the operations are happenning on a futures like
intstrument and commission is a fixed price per size contracts
• margin (default: None)
This is what makes futures attractive and risky at the same time.
If left unset, the scheme will apply to any data present in the system.
441
backtrader’s documentation Version-1.9.58.122
Note
The 2nd syntax doesn’t set margin and mult and backtrader attempts a smart
approach by considering the commission to be % based.
import backtrader as bt
...
cerebro.broker.addcommissioninfo(commEuroStoxx50, name='Eurostoxxx50')
import backtrader as bt
class CommEurostoxx50(bt.CommissionInfo):
params = dict(commission=2.0, margin=2000.0, mult=10.0)
442
backtrader’s documentation Version-1.9.58.122
And later:
...
cerebro.broker.addcommissioninfoCommEuroStoxx50(), name='Eurostoxxx50')
Using a SimpleMovingAverage crossover as the entry/exit signal the same data set
is going to be tested with a futures like commission scheme and then with a
stocks like one.
Note
Futures positions could also not only be given the enter/exit behavior but a
reversal behavior on each occassion. But this example is about comparing the
commission schemes.
The code (see at the bottom for the full strategy) is the same and the scheme can
be chosen before the strategy is defined.
futures_like = True
if futures_like:
commission, margin, mult = 2.0, 2000.0, 10.0
else:
commission, margin, mult = 0.005, None, 1
Just set futures_like to false to run with the stocks like scheme.
Some logging code has been added to evaluate the impact of the differrent
commission schemes. Let’s concentrate on just the 2 first operations.
For futures:
443
backtrader’s documentation Version-1.9.58.122
For stocks:
Hey!! Commission has fully eaten up any profit on the stocks operation but has
only meant a small dent to the futures one.
The bite has been sensibly larger for this negative operation with futures
But:
The accumulated effect can be seen on the charts below, where it can also be seen
that at the end of the full year, futures have produced a larger profit, but have
also suffered a larger drawdown (were deeper underwater)
But the important thing: whether futures or stocks ... it can be backtested.
444
backtrader’s documentation Version-1.9.58.122
445
backtrader’s documentation Version-1.9.58.122
The code
import backtrader as bt
import backtrader.feeds as btfeeds
import backtrader.indicators as btind
futures_like = True
if futures_like:
446
backtrader’s documentation Version-1.9.58.122
class SMACrossOver(bt.Strategy):
def log(self, txt, dt=None):
''' Logging function fot this strategy'''
dt = dt or self.datas[0].datetime.date(0)
print('%s, %s' % (dt.isoformat(), txt))
self.buyprice = order.executed.price
self.buycomm = order.executed.comm
self.opsize = order.executed.size
else: # Sell
self.log('SELL EXECUTED, Price: %.2f, Cost: %.2f, Comm %.2f' %
(order.executed.price,
order.executed.value,
order.executed.comm))
if margin:
gross_pnl *= mult
def __init__(self):
sma = btind.SMA(self.data)
# > 0 crossing up / < 0 crossing down
self.buysell_sig = btind.CrossOver(self.data, sma)
def next(self):
if self.buysell_sig > 0:
self.log('BUY CREATE, %.2f' % self.data.close[0])
self.buy() # keep order ref to avoid 2nd orders
if __name__ == '__main__':
# Create a cerebro entity
cerebro = bt.Cerebro()
# Add a strategy
cerebro.addstrategy(SMACrossOver)
Reference
class backtrader.CommInfoBase
448
backtrader’s documentation Version-1.9.58.122
Params:
o margin is None: Internal _commtype is set to COMM_PERC and _stocklike is set to True
(Operating %-wise with Stocks)
o margin is not None: _commtype set to COMM_FIXED and _stocklike set to False
(Operating with fixed rount-trip commission with Futures)
Note
Some products like ETFs get charged on interest for short and long
positions. If ths is True and interest is non-zero the interest will
be charged on both directions
Amount of leverage for the asset with regards to the needed cash
- ``_stocklike``
- ``_commtype``
This two are used internally instead of the declared params to enable the
compatibility check described above for the legacy ``CommissionInfo``
object
class backtrader.CommissionInfo
Params:
get_leverage()
getsize(price, cash)
getoperationcost(size, price)
getvaluesize(size, price)
Returns the value of size for given a price. For future-like objects it is
fixed at size * margin
getvalue(position, price)
get_margin(price)
Returns the actual margin/guarantees needed for a single item of the asset
at the given price. The default implementation has this policy:
getcommission(size, price)
451
backtrader’s documentation Version-1.9.58.122
This method returns the cost in terms of credit interest charged by the
broker.
In the case of size > 0 this method will only be called if the parameter to
the class interest_long is True
The formulat for the calculation of the credit interest rate is:
dt0 and dt1 are not used in the default implementation and are provided as
extra input for overridden methods
Extending Commissions
The concept was limited to futures with margin and a fixed commission per
contract and stocks with a price/size percentage based commission. Not the most
flexible of schemes even if it has served its purpose.
A request for enhancement on GitHub #29 led to some rework in order to:
452
backtrader’s documentation Version-1.9.58.122
class CommInfoBase(with_metaclass(MetaParams)):
COMM_PERC, COMM_FIXED = range(2)
params = (
('commission', 0.0), ('mult', 1.0), ('margin', None),
('commtype', None),
('stocklike', False),
('percabs', False),
)
A base class for CommissionInfo has been introduced which add new parameters to
the mix:
This is the key to compatibility. If the value is None, the behavior of the
CommissionInfo object and broker.setcommission will work as before. Being
that:
o If margin is set then the commission scheme is for futures with a fixed commission per contract
o If margin is not set, the commission scheme is for stocks with a percentage based approach
If the value is COMM_PERC or COMM_FIXED (or any other from derived classes)
this obviously decides if the commission if fixed or percent based
As above if commtype is set to something else than None, then this value
indicates whether the asset is a futures-like asset (margin will be used
and bar based cash adjustment will be performed9 or else this a stocks-like
asset
453
backtrader’s documentation Version-1.9.58.122
All these parameters can also be used in broker.setcommission which now looks
like this:
def setcommission(self,
commission=0.0, margin=None, mult=1.0,
commtype=None, percabs=True, stocklike=False,
name=None):
• percabs is True to keep the behavior compatible with the old call as mentioned above for the
CommissionInfo object
The old sample to test commissions-schemes has been reworked to support command
line arguments and the new behavior. The usage help:
$ ./commission-schemes.py --help
usage: commission-schemes.py [-h] [--data DATA] [--fromdate FROMDATE]
[--todate TODATE] [--stake STAKE]
[--period PERIOD] [--cash CASH] [--comm COMM]
[--mult MULT] [--margin MARGIN]
[--commtype {none,perc,fixed}] [--stocklike]
[--percrel] [--plot] [--numfigs NUMFIGS]
Commission schemes
optional arguments:
-h, --help show this help message and exit
--data DATA, -d DATA data to add to the system (default:
../../datas/2006-day-001.txt)
--fromdate FROMDATE, -f FROMDATE
Starting date in YYYY-MM-DD format (default:
2006-01-01)
--todate TODATE, -t TODATE
Starting date in YYYY-MM-DD format (default:
2006-12-31)
--stake STAKE Stake to apply in each operation (default: 1)
--period PERIOD Period to apply to the Simple Moving Average (default:
30)
--cash CASH Starting Cash (default: 10000.0)
--comm COMM Commission factor for operation, either apercentage or
a per stake unit absolute value (default: 2.0)
--mult MULT Multiplier for operations calculation (default: 10)
--margin MARGIN Margin for futures-like operations (default: 2000.0)
--commtype {none,perc,fixed}
454
backtrader’s documentation Version-1.9.58.122
Let’s do some runs to recreate the original behavior of the original commission
schemes posts.
455
backtrader’s documentation Version-1.9.58.122
And the output showing a fixed commission of 2.0 monetary units (default stake is
1):
456
backtrader’s documentation Version-1.9.58.122
457
backtrader’s documentation Version-1.9.58.122
It should come to no surprise that by changing the commission ... the final
result has changed
Being in the previous run set a 2.0 monetary units (for the default stake of 1)
Another post will details the new classes and the implementation of a homme
cooked commission scheme.
import argparse
import datetime
import backtrader as bt
import backtrader.feeds as btfeeds
import backtrader.indicators as btind
class SMACrossOver(bt.Strategy):
params = (
('stake', 1),
('period', 30),
)
def __init__(self):
sma = btind.SMA(self.data, period=self.p.period)
# > 0 crossing up / < 0 crossing down
self.buysell_sig = btind.CrossOver(self.data, sma)
def next(self):
if self.buysell_sig > 0:
self.log('BUY CREATE, %.2f' % self.data.close[0])
self.buy(size=self.p.stake) # keep order ref to avoid 2nd orders
def runstrategy():
args = parse_args()
# Create a cerebro
cerebro = bt.Cerebro()
460
backtrader’s documentation Version-1.9.58.122
# Add a strategy
cerebro.addstrategy(SMACrossOver, period=args.period, stake=args.stake)
commtypes = dict(
none=None,
perc=bt.CommInfoBase.COMM_PERC,
fixed=bt.CommInfoBase.COMM_FIXED)
# And run it
cerebro.run()
# Plot if requested
if args.plot:
cerebro.plot(numfigs=args.numfigs, volume=False)
def parse_args():
parser = argparse.ArgumentParser(
description='Commission schemes',
formatter_class=argparse.ArgumentDefaultsHelpFormatter,)
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')
461
backtrader’s documentation Version-1.9.58.122
return parser.parse_args()
if __name__ == '__main__':
runstrategy()
462
backtrader’s documentation Version-1.9.58.122
The most important part of reworking the CommInfo object to the actual
incarnation involved:
Note
It involves 1 or 2 steps
1. Subclassing CommInfoBase
class CommInfo_Futures_Fixed(CommInfoBase):
params = (
('stocklike', False),
('commtype', CommInfoBase.COMM_FIXED),
)
class CommInfo_Stocks_Perc(CommInfoBase):
params = (
('stocklike', True),
('commtype', CommInfoBase.COMM_PERC),
)
As stated above the default for the interpretation of the percentage here
(passed as parameter commission) is that of: xx%. Should the old/other
behavior be wished 0.xx, it can be easily done:
class CommInfo_Stocks_PercAbs(CommInfoBase):
463
backtrader’s documentation Version-1.9.58.122
params = (
('stocklike', True),
('commtype', CommInfoBase.COMM_PERC),
('percabs', True),
)
Defined as:
...
Setting name means that the comminfo object will only apply to assets with that
name. The default value of None means it applies to all assets in the system.
A practical example
Ticket #45 asks about a commission scheme which applies to Futures, is percentage
wise and uses the commission percentage on the entire “virtual” value of the
contract. ie: includes the future multiplier in the commission calculation.
464
backtrader’s documentation Version-1.9.58.122
It should be easy:
import backtrader as bt
class CommInfo_Fut_Perc_Mult(bt.CommInfoBase):
params = (
('stocklike', False), # Futures
('commtype', bt.CommInfoBase.COMM_PERC), # Apply % Commission
# ('percabs', False), # pass perc as xx% which is the default
)
comminfo = CommInfo_Fut_Perc_Mult(
commission=0.1, # 0.1%
mult=10,
margin=2000 # Margin is needed for futures-like instruments
)
cerebro.addcommissioninfo(comminfo)
If the format 0.xx is preferred as the default, just set param percabs to True:
class CommInfo_Fut_Perc_Mult(bt.CommInfoBase):
params = (
('stocklike', False), # Futures
('commtype', bt.CommInfoBase.COMM_PERC), # Apply % Commission
('percabs', True), # pass perc as 0.xx
)
comminfo = CommInfo_Fut_Perc_Mult(
commission=0.001, # 0.1%
mult=10,
margin=2000 # Margin is needed for futures-like instruments
)
cerebro.addcommissioninfo(comminfo)
465
backtrader’s documentation Version-1.9.58.122
Explaining pseudoexec
The purpose of the pseudoexec arg may seem obscure but it serves a purpose.
• The platform may call this method to do precalculation of available cash and some other tasks
• This means that the method may (and it actually will) be called more than once with the same parameters
In such case and if pseudoexec was not there, the multiple non-execution
calls to the method would quickly trigger the assumption that the discount
is in place.
import backtrader as bt
class CommInfo_Fut_Discount(bt.CommInfoBase):
params = (
('stocklike', False), # Futures
('commtype', bt.CommInfoBase.COMM_FIXED), # Apply Commission
if not pseudoexec:
# keep track of actual real executed size for future discounts
self.negotiated_volume += size
return commvalue
Commissions: Credit
In some situations, the cash amount in real brokers may be decreased because the
operation on assets includes an interest rate. Examples:
The charge goes directly against the cash balance in the broker account. But it
can still be seen as part of a commission scheme. And as such it has been modeled
in backtrader.
The CommInfoBase class (and with it also the CommissionInfo main interface
object) has been extended with:
• Two (2) new parameters that allow setting the interest rate and determining if should be applied only to
the short side or to both long and short
Parameters
467
backtrader’s documentation Version-1.9.58.122
Note
Some products like ETFs get charged on interest for short and long
positions. If ths is True and interest is non-zero the interest will be
charged on both directions
The formula
Where:
• days: number of days elapsed since position was opened or the last credit interest calculation took place
In the case of ``size > 0`` this method will only be called if the
parameter to the class ``interest_long`` is ``True``
The formulat for the calculation of the credit interest rate is:
468
backtrader’s documentation Version-1.9.58.122
Params:
- ``data``: data feed for which interest is charged
- ``size``: current position size. > 0 for long positions and < 0 for
short positions (this parameter will not be ``0``)
``dt0`` and ``dt1`` are not used in the default implementation and are
provided as extra input for overridden methods
'''
It might be that the broker doesn’t consider weekends or bank holidays when
calculating the interest rate. In this case this subclass would do the trick
import backtrader as bt
class MyCommissionInfo(bt.CommInfo):
Because if weekends/bank holidays do not count, the next calculation will always
happen 1 trading da after the previous calculation
Position
469
backtrader’s documentation Version-1.9.58.122
Which will return the position on datas[0] of the strategy in the default
broker provided by cerebro
It serves as a status and can for example be used in deciding if an order has to
be issued or not (example: long positions are only entered if no position is
open)
Reference: Position
Keeps and updates the size and price of a position. The object has no
relationship to any asset. It only keeps size and price.
Member Attributes:
Trade
Definition of a trade:
• A Trade is open when the a position in a instrument goes from 0 to a size X which may positive/negative
for long/short positions)
• A Trade is closed when a position goes from X to 0.
• positive to negative
• negative to positive
Reference: Trade
Keeps track of the life of an trade: size, price, commission (and value?)
An trade is not meant to be reversed (no support in the logic for it)
Member Attributes:
471
backtrader’s documentation Version-1.9.58.122
The first entry in the history is the Opening Event The last entry in
the history is the Closing Event
Plotting
And because everything has a human being behind it, charting the data feeds,
indicators, operations, evolution of cash and portfolio value can help the humans
to better appreciate what’s going on, discard/modify/create ideas and whatever
the human looking at the chart may do with the visual information.
How to plot
Any backtesting run can be plotted with the invocation of a single method:
cerebro.plot()
Of course this is usually the last command issued like in this simple code which
uses one of the sample data from the backtrader sources.
import backtrader as bt
class St(bt.Strategy):
def __init__(self):
self.sma = bt.indicators.SimpleMovingAverage(self.data)
data = bt.feeds.BacktraderCSVData(dataname='../../datas/2005-2006-day-001.txt')
472
backtrader’s documentation Version-1.9.58.122
cerebro = bt.Cerebro()
cerebro.adddata(data)
cerebro.addstrategy(St)
cerebro.run()
cerebro.plot()
The chart includes 3 Observers which in this case and given the lack of any
trading are mostly pointless
• A CashValue observer which as the name implies keeps track of the Cash and
total portolio Value (including cash) during the life of the backtesting
run
• A Trade Observer which shows, at the end of a trade, the actual Profit and
Loss
473
backtrader’s documentation Version-1.9.58.122
• A BuySell observer which plots (on top of the prices) where buy and sell
operations have taken place
These 3 Observers are automatically added by cerebro, and are controlled with the
stdstats parameter (default: True). Do the following to disable them if you wish:
cerebro = bt.Cerebro(stdstats=False)
cerebro = bt.Cerebro()
...
cerebro.run(stdstats=False)
Plotted Elements
Although the Observers have already been mentioned above in the introduction,
they are not the only elements to get plotted. These 3 things get plotted:
The Observers are lines objects which run in sync with the strategy and
have access to the entire ecosystem, to be able to track things like Cash
and Value
Plotting Options
Indicators and Observers have several options that control how they have to be
plotted on the chart. There are 3 big groups:
474
backtrader’s documentation Version-1.9.58.122
plotinfo = dict(plot=True,
subplot=True,
plotname='',
plotskip=False,
plotabove=False,
plotlinelabels=False,
plotlinevalues=True,
plotvaluetags=True,
plotymargin=0.0,
plotyhlines=[],
plotyticks=[],
plothlines=[],
plotforce=False,
plotmaster=None,
plotylimited=True,
)
• If a subclass changes for example a value like subplot=True to subplot=False, subclasses further down the
hierarchy will have the latter as the default value for subplot
As can be inferred from the example, any **kwargs not consumed by the
SimpleMovingAverage constructor will be parsed (if possible) as plotinfo values.
The SimpleMovingAverage has a single parameter defined which is period. And this
means that plotname will be matched against the parameter of the same name in
plotinfo.
475
backtrader’s documentation Version-1.9.58.122
Example: The Bollinger Bands have 3 lines but the indicator is plotted on
top of the data. It seems sensible to have the legend only display a single
name like BollingerBands rather than having the name of the 3 individual
lines displayed (mid, top, bot)
A use case for this is the BuySell observer for which it makes sense to
display the name of the 2 lines and its markers: Buy and Sell to make it
clear for the end user what is what.
• plotlinevalues: controls whether the legend for the lines in indicators and
observers has the last plotted value. Can be controlled on a per-line basis
with _plotvalue for each line
• plotvaluetags: controls whether a value tag with the last value is plotted
on the right hand side of the line. Can be controlled on a per-line basis
with _plotvaluetag for each line
• plotymargin: margin to add to the top and bottom of individual subcharts on
the graph
This for example helps for the classical indicators with overbought,
oversold areas like the RSI which usually has lines plotted at 70 and 30
476
backtrader’s documentation Version-1.9.58.122
For example to force the scale to have a 50 to identify the mid point of
the scale. Although this seems obvious, the indicators use an auto-scaling
mechanism and the 50 may not be obviously be in the centre if an indicator
with a 0-100 scale moves between 30-95 on a regular basis.
If none of the above are defined, then where to place horizontal lines and
ticks will be entirely controlled by this value
If any of the above are defined they have precedence over the values
present in this option
• plotforce: sometimes and thus the complex process of matching data feeds to
indicators and bla, bla, bla ... a custom indicator may fail to plot. This
is a last resort mechanism to try to enforce plotting.
477
backtrader’s documentation Version-1.9.58.122
Indicators/Observers have lines and how this lines are plotted can be influenced
with the plotlines object. Most of options specified in plotlines are meant to be
directly passed over to matplotlib when plotting. The documentation relies
therefore on examples of things that have been done.
Some of the options are controlled directly by backtrader. These all start with
an underscore (_):
Example from MACDHisto. Here the histo line is plotted as a bar which is
the industry de-facto standard. The following definition can be found in
the definition of MACDHisto:
lines = ('histo',)
plotlines = dict(histo=dict(_method='bar', alpha=0.50, width=1.0))
• _fill_gt / _fill_lt
o Another line
o A numeric value
478
backtrader’s documentation Version-1.9.58.122
The filling will be done in between the own values and the values of
the line or the numeric value
or
An iterable where the 1st element is the string/hex value for the colour and the second
element is a numeric value specifying the alpha transparency (default: 0.20 controlled
with fillalpha in a plotting scheme)
Examples:
# Fill for myline when above other_line with colour red and 50%
# transparency (1.0 means "no transparency")
plotlines = dict(
myline=dict(_fill_gt('other_line', ('red', 0.50)))
)
• Ue the name _X where X stands for a digit in a zero-based index. This means that the options are for line X
plotlines = dict(_0=dict(_name='osc'))
479
backtrader’s documentation Version-1.9.58.122
And that’s why the options are specified to be for: _0. After the subclassing
has taken place the 1st line of the resulting class will have the name osc in
plot.
plotlines = dict(
buy=dict(marker='^', markersize=8.0, color='lime', fillstyle='full'),
sell=dict(marker='v', markersize=8.0, color='red', fillstyle='full')
)
The buy and sell lines have options which are passed directly to matplotlib to
define marker, markersize, color and fillstyle. All these options are defined in
matplotlib
...
lines = ('pnlplus', 'pnlminus')
...
plotlines = dict(
pnlplus=dict(_name='Positive',
marker='o', color='blue',
markersize=8.0, fillstyle='full'),
pnlminus=dict(_name='Negative',
marker='o', color='red',
markersize=8.0, fillstyle='full')
)
Here the names of the lines have been redefined from for example pnlplus to
Positive by using _name. The rest of the options are for matplotlib
480
backtrader’s documentation Version-1.9.58.122
...
plotlines = dict(maxdrawdown=dict(_plotskip='True',))
This one defines two lines to let the end users access not only the value of the
current drawdown but also its maximum value (maxdrawdown). But the latter is not
plotted due to _plotskip=True
plotlines = dict(
mid=dict(ls='--'),
top=dict(_samecolor=True),
bot=dict(_samecolor=True),
)
Here the mid line will have a dashed style and the top and bot lines will have
the same color as the mid line.
The slower line percD is plotted with a dashed style. And the names of the lines
are changed to include fancy % signs (%K and %D) which cannot be used in name
definitions in Python
When dealing with Indicators and Observers the following methods are supported to
further control plotting:
• _plotlabel(self)
Which should return a list of things to conform the labels which will be
placed in between parentheses after the name of the Indicators or Observer
def _plotlabel(self):
plabels = [self.p.period]
plabels += [self.p.movav] * self.p.notdefault('movav')
481
backtrader’s documentation Version-1.9.58.122
return plabels
o An int which indicates the period configured for the RSI and if the
default moving average has been changed, the specific class
• _plotinit(self)
def _plotinit(self):
self.plotinfo.plotyhlines = [self.p.upperband, self.p.lowerband]
Here the code assigns a value to plotyhlines to have horizontal lines (the
hlines part) plotted at specific y values.
The values of the parameters upperband and lowerband are used for this,
which cannot be known in advance, because the parameters can be changed by
the end user
Which means:
Sometimes a chart contains too many bars and will not be easily readable if
packed in a single figure. This breaks it down in as many pieces as
requested
482
backtrader’s documentation Version-1.9.58.122
PlotScheme
This object contains all the options that contol system-wide plotting. The
options are documented in the code:
class PlotScheme(object):
def __init__(self):
# to have a tight packing on the chart wether only the x axis or also
# the y axis have (see matplotlib)
self.ytight = False
# y-margin (top/bottom) for the subcharts. This will not overrule the
# option plotinfo.plotymargin
self.yadjust = 0.0
# Each new line is in z-order below the previous one. change it False
# to have lines paint above the previous line
self.zdown = True
# Rotation of the date labes on the x axis
self.tickrotation = 15
# How many "subparts" takes a major chart (datas) in the overall chart
# This is proportional to the total number of subcharts
self.rowsmajor = 5
# Default plotstyle for the OHLC bars which (line -> line on close)
# Other options: 'bar' and 'candle'
self.style = 'line'
483
backtrader’s documentation Version-1.9.58.122
# Plot a tag at the end of each line with the last value
self.valuetags = True
Colors in PlotScheme
The PlotScheme class defines a method which can be overriden in subclasses which
returns the next color to be used:
Where idx is the current index to the line being plotted on a individual
subchart. The MACD for example plots 3 lines and hence the idx variable will only
have the following values: 0, 1 and 2. The next chart (maybe another indicator)
will star the count again at 0.
The default color scheme used in backtrader uses (as seen above) is the Tableau
10 Color Palette with the index modified to be:
tab10_index = [3, 0, 2, 1, 2, 4, 5, 6, 7, 8, 9]
The source code contains also the defintions for the Tableau 10 Light and the
Tableau 20 color palettes.
• Either with indices to the full length array of timestamps kept in strategy instances
• Or with actual datetime.date or datetime.datetime instances that limit what has to be plotted.
Being that the straightforward way to do it for humans. Humans with extended
capabilities can actually try indices to the datetime timestamps as in:
cerebro.plot(start=75, end=185)
The eval magic in python allows to directly write datetime.date in the command
line and map actually that to something sensible. The output chart
486
backtrader’s documentation Version-1.9.58.122
Let’s compare it with the full plot to see that data was actually skipped from
both ends:
./partial-plot.py --plot
The eval magic in python allows to directly write datetime.date in the command
line and map actually that to something sensible. The output chart
487
backtrader’s documentation Version-1.9.58.122
Sample Usage
$ ./partial-plot.py --help
usage: partial-plot.py [-h] [--data0 DATA0] [--fromdate FROMDATE]
[--todate TODATE] [--cerebro kwargs] [--broker kwargs]
[--sizer kwargs] [--strat kwargs] [--plot [kwargs]]
optional arguments:
-h, --help show this help message and exit
--data0 DATA0 Data to read in (default:
../../datas/2005-2006-day-001.txt)
--fromdate FROMDATE Date[time] in YYYY-MM-DD[THH:MM:SS] format (default: )
--todate TODATE Date[time] in YYYY-MM-DD[THH:MM:SS] format (default: )
--cerebro kwargs kwargs in key=value format (default: )
488
backtrader’s documentation Version-1.9.58.122
Sample Code
import argparse
import datetime
import backtrader as bt
class St(bt.Strategy):
params = (
)
def __init__(self):
bt.ind.SMA()
stoc = bt.ind.Stochastic()
bt.ind.CrossOver(stoc.lines.percK, stoc.lines.percD)
def next(self):
pass
def runstrat(args=None):
args = parse_args(args)
cerebro = bt.Cerebro()
# Parse from/to-date
dtfmt, tmfmt = '%Y-%m-%d', 'T%H:%M:%S'
for a, d in ((getattr(args, x), x) for x in ['fromdate', 'todate']):
if a:
strpfmt = dtfmt + tmfmt * ('T' in a)
489
backtrader’s documentation Version-1.9.58.122
# Data feed
data0 = bt.feeds.BacktraderCSVData(dataname=args.data0, **kwargs)
cerebro.adddata(data0)
# Broker
cerebro.broker = bt.brokers.BackBroker(**eval('dict(' + args.broker + ')'))
# Sizer
cerebro.addsizer(bt.sizers.FixedSize, **eval('dict(' + args.sizer + ')'))
# Strategy
cerebro.addstrategy(St, **eval('dict(' + args.strat + ')'))
# Execute
cerebro.run(**eval('dict(' + args.cerebro + ')'))
def parse_args(pargs=None):
parser = argparse.ArgumentParser(
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
description=(
'Sample for partial plotting'
)
)
parser.add_argument('--data0', default='../../datas/2005-2006-day-001.txt',
required=False, help='Data to read in')
return parser.parse_args(pargs)
if __name__ == '__main__':
runstrat()
The previous post future-vs-spot, was plotting the original data and the slightly
(randomly) modified data on the same space, but not on the same axis.
491
backtrader’s documentation Version-1.9.58.122
• There are different scales on the left and right hand sides of the chart
• This is most obvious when looking at the swinging red line (the randomized
data) which oscillates +- 50 points around the original data.
On the chart the visual impression is that this randomized data is mostly
always above the original data. Which is only a visual impression due to
the different scales.
Although release 1.9.32.116 already had some initial support to fully plot on the
same axis, the legend labels would be duplicated (only the labels, not the data)
which was really confusing.
Release 1.9.33.116 cures that effect and allows full plotting on the same axis.
The usage pattern is like the one to decide with which other data to plot. From
the previous post.
492
backtrader’s documentation Version-1.9.58.122
import backtrader as bt
cerebro = bt.Cerebro()
data0 = bt.feeds.MyFavouriteDataFeed(dataname='futurename')
cerebro.adddata(data0)
data1 = bt.feeds.MyFavouriteDataFeed(dataname='spotname')
data1.compensate(data0) # let the system know ops on data1 affect data0
data1.plotinfo.plotmaster = data0
data1.plotinfo.sameaxis = True
cerebro.adddata(data1)
...
cerebro.run()
The reason for this indication is that the platform cannot know in advance
if the scales for each data will be compatible. That’s why it will plot
them on independent scales
The previous sample gets an additional option to plot on the sameaxis. A sample
execution:
$ ./future-spot.py --sameaxis
493
backtrader’s documentation Version-1.9.58.122
To notice:
Sample Usage
$ ./future-spot.py --help
usage: future-spot.py [-h] [--no-comp] [--sameaxis]
Compensation example
optional arguments:
-h, --help show this help message and exit
--no-comp
--sameaxis
494
backtrader’s documentation Version-1.9.58.122
Sample Code
import argparse
import random
import backtrader as bt
class St(bt.Strategy):
def __init__(self):
bt.obs.BuySell(self.data0, barplot=True) # done here for
BuySellArrows(self.data1, barplot=True) # different markers per data
def next(self):
if not self.position:
if random.randint(0, 1):
self.buy(data=self.data0)
self.entered = len(self)
def runstrat(args=None):
args = parse_args(args)
cerebro = bt.Cerebro()
495
backtrader’s documentation Version-1.9.58.122
cerebro.broker.set_coc(True)
cerebro.run(stdstats=False) # execute
cerebro.plot(volume=False) # and plot
def parse_args(pargs=None):
parser = argparse.ArgumentParser(
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
description=('Compensation example'))
if __name__ == '__main__':
runstrat()
Optimization improvements
Note
The behavior of these options can be controlled through two new Cerebro
parameters:
If True and optimizing (and the system can preload and use runonce, data
preloading will be done only once in the main process to save time and
resources.
If True the optimization results will not be full Strategy objects (and all
datas, indicators, observers ...) but and object with the following
attributes (same as in Strategy):
In most occassions, only the analyzers and with which params are the things
needed to evaluate a the performance of a strategy. If detailed analysis of
the generated values for (for example) indicators is needed, turn this off
• preload=True (default)
• runonce=True (default)
• The Data Feeds will be preloaded in the main process before spawning new subprocesses (the ones in
charge of executing the backtesting)
Results management
In a Optimization scenario two things should play the most important role when
evaluating the different parameters with which each *Strategy was run:
497
backtrader’s documentation Version-1.9.58.122
• strategy.analyzers
The objects in charge of providing the evaluation of how the Strategy has
actually performed. Example:
This avoids passing back lots of generated data like for example the values
generated by indicators during the backtesting
Should the full strategy objects be wished, simply set optreturn=False during
cerebro instantiation or when doing cerebro.run.
The optimization sample in the backtrader sources has been extended to add
control for optdatas and optreturn (actually to disable them)
As a reference what happens when the amount of CPUs is limited to 1 and the
multiprocessing module is not used:
$ ./optimization.py --maxcpus 1
==================================================
**************************************************
--------------------------------------------------
OrderedDict([(u'smaperiod', 10), (u'macdperiod1', 12), (u'macdperiod2', 26),
(u'macdperiod3', 9)])
**************************************************
--------------------------------------------------
OrderedDict([(u'smaperiod', 10), (u'macdperiod1', 13), (u'macdperiod2', 26),
(u'macdperiod3', 9)])
...
...
498
backtrader’s documentation Version-1.9.58.122
Without limiting the number of CPUs, the Python multiprocessing module will try
to use all of them. optdatas and optreturn will be disabled
$ ./optimization.py
...
...
...
==================================================
Time used: 56.5889185394
The total improvement by having multicore and the data feed and results
improvements means going down from 184.92 to 56.58 seconds.
Take into account that the sample is using 252 bars and the indicators generate
only values with a length of 252 points. This is just an example.
The real question is how much of this is attributable to the new behavior.
optreturn deactivated
$ ./optimization.py --no-optreturn
...
...
...
==================================================
Time used: 67.056914007
The execution time has increased 18.50% (or a speed-up of 15.62%) is in place.
499
backtrader’s documentation Version-1.9.58.122
optdatas deactivated
Each subproccess is forced to load its own set of values for the data feeds:
$ ./optimization.py --no-optdatas
...
...
...
==================================================
Time used: 72.7238112637
The execution time has increased 28.52% (or a speed-up of 22.19%) is in place.
Both deactivated
The execution time has increased 47.79% (or a speed-up of 32.34%) is in place.
This shows that the used of multiple cores is the major contributor to the time
improvement.
Note
The executions have been done in a Laptop with a i7-4710HQ (4-core / 8 logical)
with 16 GBytes of RAM under Windows 10 64bit. The mileage may vary under other
conditions
Concluding
• The greatest factor in time reduction during optimization is the use of the multiple cores
• The sample runs with optdatas and optreturn show speed-ups of around 22.19% and 15.62% each
(32.34% both together in the test)
500
backtrader’s documentation Version-1.9.58.122
Sample Usage
$ ./optimization.py --help
usage: optimization.py [-h] [--data DATA] [--fromdate FROMDATE]
[--todate TODATE] [--maxcpus MAXCPUS] [--no-runonce]
[--exactbars EXACTBARS] [--no-optdatas]
[--no-optreturn] [--ma_low MA_LOW] [--ma_high MA_HIGH]
[--m1_low M1_LOW] [--m1_high M1_HIGH] [--m2_low M2_LOW]
[--m2_high M2_HIGH] [--m3_low M3_LOW]
[--m3_high M3_HIGH]
Optimization
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
--maxcpus MAXCPUS, -m MAXCPUS
Number of CPUs to use in the optimization
- 0 (default): use all available CPUs
- 1 -> n: use as many as specified
--no-runonce Run in next mode
--exactbars EXACTBARS
Use the specified exactbars still compatible with preload
0 No memory savings
-1 Moderate memory savings
-2 Less moderate memory savings
--no-optdatas Do not optimize data preloading in optimization
--no-optreturn Do not optimize the returned values to save time
--ma_low MA_LOW SMA range low to optimize
--ma_high MA_HIGH SMA range high to optimize
--m1_low M1_LOW MACD Fast MA range low to optimize
--m1_high M1_HIGH MACD Fast MA range high to optimize
--m2_low M2_LOW MACD Slow MA range low to optimize
--m2_high M2_HIGH MACD Slow MA range high to optimize
--m3_low M3_LOW MACD Signal range low to optimize
--m3_high M3_HIGH MACD Signal range high to optimize
501
backtrader’s documentation Version-1.9.58.122
Automating BackTesting
So far all backtrader examples and working samples have started from scratch
creating a main Python module which loads datas, strategies, observers and
prepares cash and commission schemes.
One of the goals of algorithmic trading is the automation of trading and given
that bactrader is a backtesting platform intented to check trading algorithms
(hence is an algotrading platform), automating the use of backtrader was an
obvious goal.
• bt-run-py a script which uses the codebase from the next item
and
• btrun (executable)
This was an original extra switch before the “Cerebro” parameters were
implemented. As such and if a parameter to cerebro with regards to Standard
Observers is passed, this will be ignored (parameter stdstats to Cerebro)
• Load one or more observers (example: DrawDown) from the built-in ones or
from a python module
• Set the cash and commission scheme parameters for the broker (commission,
margin, mult)
• Enable plotting, controlling the amount of charts and style to present the
data
• Add a parametrized writer to the system
502
backtrader’s documentation Version-1.9.58.122
import backtrader as bt
import backtrader.indicators as btind
class MyTest(bt.Strategy):
params = (('period', 15),)
def __init__(self):
sma = btind.SMA(period=self.p.period)
def next(self):
ltxt = '%d, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f'
self.log(ltxt %
(len(self),
self.data.open[0], self.data.high[0],
self.data.low[0], self.data.close[0],
self.data.volume[0], self.data.openinterest[0]))
503
backtrader’s documentation Version-1.9.58.122
Executing the strategy with the usual testing sample is easy: easy:
505
backtrader’s documentation Version-1.9.58.122
Note
backtrader will slowly be including sample (textbook) strategies. Along with the
bt-run.py script a standard Simple Moving Average CrossOver strategy is included.
The name:
• SMA_CrossOver
• Parameters
o fast (default 10) period of the fast moving average
o slow (default 30) period of the slow moving average
The strategy buys if the fast moving average crosses up the fast and sells (only
if it has bought before) upon the fast moving average crossing down the slow
moving average.
The code
import backtrader as bt
import backtrader.indicators as btind
class SMA_CrossOver(bt.Strategy):
def __init__(self):
sma_fast = btind.SMA(period=self.p.fast)
sma_slow = btind.SMA(period=self.p.slow)
def next(self):
if self.position.size:
if self.buysig < 0:
self.sell()
506
backtrader’s documentation Version-1.9.58.122
Standard execution:
Notice the :. The standard notation (see below) to load a strategy is:
• module:stragegy:kwargs
• If module is there and strategy is specified, then that strategy will be used
• If module is there but no strategy is specified, the 1st strategy found in the module will be returned
• If no module is specified, “strategy” is assumed to refer to a strategy in the backtrader package
• If module and/or strategy are there, if kwargs are present they will be passed to the corresponding
strategy
Note
The same notation and rules apply to --observer, --analyzer and --indicator
options
The output
507
backtrader’s documentation Version-1.9.58.122
One last example adding commission schemes, cash and changing the parameters:
The output
508
backtrader’s documentation Version-1.9.58.122
See the continuous variations in cash with each bar, as cash is adjusted
for the futures-like instrument daily changes
Using no Strategy
This is a an over-statement. A strategy will be applied, but you can ommit any
kind of strategy and a default backtrader.Strategy will be added.
An example:
Adding Analyzers
btrun also supports adding Analyzers with the same syntax used for the strategies
to choose between internal/external analyzers.
510
backtrader’s documentation Version-1.9.58.122
• --pranalyzer which defaults to calling the next one (unless the Analyzer has overriden the proper method)
• --ppranalyzer which uses the pprint module to print the results
Note
The two printing options were implemented before writers were part of backtrader.
Adding a writer without csv output will achieve the same (and the output has been
improved)
====================
== Analyzers
====================
##########
sharperatio
##########
{'sharperatio': 11.647332609673256}
Good strategy!!! (Pure luck for the example actually which also bears no
commissions)
The chart (which simply shows the Analyzer is not in the plot, because Analyzers
cannot be plotted, they aren’t lines objects)
511
backtrader’s documentation Version-1.9.58.122
===============================================================================
Cerebro:
-----------------------------------------------------------------------------
- Datas:
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- Data0:
- Name: 2005-2006-day-001
- Timeframe: Days
512
backtrader’s documentation Version-1.9.58.122
- Compression: 1
-----------------------------------------------------------------------------
- Strategies:
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- SMA_CrossOver:
*************************************************************************
- Params:
- fast: 10
- slow: 30
- _movav: SMA
*************************************************************************
- Indicators:
.......................................................................
- SMA:
- Lines: sma
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Params:
- period: 30
.......................................................................
- CrossOver:
- Lines: crossover
- Params: None
*************************************************************************
- Observers:
.......................................................................
- Broker:
- Lines: cash, value
- Params: None
.......................................................................
- BuySell:
- Lines: buy, sell
- Params: None
.......................................................................
- Trades:
- Lines: pnlplus, pnlminus
- Params: None
*************************************************************************
- Analyzers:
.......................................................................
- Value:
- Begin: 10000.0
- End: 10496.68
.......................................................................
- SharpeRatio:
513
backtrader’s documentation Version-1.9.58.122
- Params: None
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Analysis:
- sharperatio: 11.6473326097
• Indicators
and
• Observers
The syntax is exactly the same as seen above when adding a Broker observer.
Let’s repeat the example but adding a Stochastic, the Broker and having a look
at the plot (we’ll change some parameters):
The chart
514
backtrader’s documentation Version-1.9.58.122
Plotting Control
• --plot style="candle" for example to plot with candlesticks instead of plotting with a LineOnClose style
(which is the plotting default)
The invocation:
--indicator :Stochastic:period_dslow=5 \
--plot style=\"candle\"
Note
The quotes around candle are quoted with backslashed \ because the example is
being run in a bash shell which removes that before passing the arguments to the
script.
Backslash quoting is needed in this case to ensure “bar” makes it to the script
and can be evaluated as a string
The chart
$ btrun --help
usage: btrun-script.py [-h] --data DATA [--cerebro [kwargs]] [--nostdstats]
[--format
{yahoocsv_unreversed,vchart,vchartcsv,yahoo,mt4csv,ibdata,sierracsv,yahoocsv,btcs
v,vcdata}]
[--fromdate FROMDATE] [--todate TODATE]
[--timeframe
{microseconds,seconds,weeks,months,minutes,days,years}]
[--compression COMPRESSION]
[--resample RESAMPLE | --replay REPLAY]
[--strategy module:name:kwargs]
[--signal module:signaltype:name:kwargs]
[--observer module:name:kwargs]
[--analyzer module:name:kwargs]
[--pranalyzer | --ppranalyzer]
[--indicator module:name:kwargs] [--writer [kwargs]]
[--cash CASH] [--commission COMMISSION]
[--margin MARGIN] [--mult MULT] [--interest INTEREST]
[--interest_long] [--slip_perc SLIP_PERC]
[--slip_fixed SLIP_FIXED] [--slip_open]
[--no-slip_match] [--slip_out] [--flush]
[--plot [kwargs]]
optional arguments:
-h, --help show this help message and exit
--resample RESAMPLE, -rs RESAMPLE
resample with timeframe:compression values
--replay REPLAY, -rp REPLAY
replay with timeframe:compression values
--pranalyzer, -pralyzer
Automatically print analyzers
--ppranalyzer, -ppralyzer
Automatically PRETTY print analyzers
--plot [kwargs], -p [kwargs]
Plot the read data applying any kwargs passed
For example:
Data options:
--data DATA, -d DATA Data files to be added to the system
517
backtrader’s documentation Version-1.9.58.122
Cerebro options:
--cerebro [kwargs], -cer [kwargs]
The argument can be specified with the following form:
- kwargs
Strategy options:
--strategy module:name:kwargs, -st module:name:kwargs
518
backtrader’s documentation Version-1.9.58.122
- module:classname:kwargs
Example: mymod:myclass:a=1,b=2
kwargs is optional
- :name:kwargs or :name
- module or module::kwargs
Signals:
--signal module:signaltype:name:kwargs, -sig module:signaltype:name:kwargs
This option can be specified multiple times.
- signaltype:module:signaltype:classname:kwargs
Example: longshort+mymod:myclass:a=1,b=2
Example: mymod:myclass:a=1,b=2
kwargs is optional
- LONGSHORT::name:kwargs or :name
519
backtrader’s documentation Version-1.9.58.122
- module or module:::kwargs
- module:classname:kwargs
Example: mymod:myclass:a=1,b=2
kwargs is optional
- :name:kwargs or :name
- module or module::kwargs
Analyzers:
--analyzer module:name:kwargs, -an module:name:kwargs
This option can be specified multiple times.
- module:classname:kwargs
Example: mymod:myclass:a=1,b=2
kwargs is optional
- :name:kwargs or :name
520
backtrader’s documentation Version-1.9.58.122
- module or module::kwargs
Indicators:
--indicator module:name:kwargs, -ind module:name:kwargs
This option can be specified multiple times.
- module:classname:kwargs
Example: mymod:myclass:a=1,b=2
kwargs is optional
- :name:kwargs or :name
- module or module::kwargs
Writers:
--writer [kwargs], -wr [kwargs]
This option can be specified multiple times.
- kwargs
Example: a=1,b=2
kwargs is optional
521
backtrader’s documentation Version-1.9.58.122
Saving Memory
Release 1.3.1.92 has reworked and fully implemented the memory saving schemes
that were previously in place, although not much touted and less used.
backtrader was (and will be further) developed in machines with nice amounts of
RAM and that put together with the fact that visual feedback through plotting is
a nice to have and almost a must have, mde it easy for a design decision: keep
everything in memory.
• array.array which is used for data storage has to allocate and move data when some bounds are exceeded
• Machines with low amounts of RAM may suffer
• Connection to a live data feed which can be online for weeks/months feeded thousands of
seconds/minutes resolution ticks into the system
The latter being even more important than the 1st due to another design decision
which was made for backtrader:
522
backtrader’s documentation Version-1.9.58.122
Hence the need to have backtrader support dynamic memory schemes. Now Cerebro can
be instantiated or run with the following semantics:
With the default False value each and every value stored in a line is kept
in memory
Possible values:
523
backtrader’s documentation Version-1.9.58.122
Note
This is a small sample. The EuroStoxx50 future which trades 14 hours a day, would
produce approximately 18000 1-minute bars in just 1 month of trading.
The script 1st executed to see how many memory positions are used when no memory
savings are requested:
$ ./memory-savings.py --save 0
Total memory cells used: 506430
$ ./memory-savings.py --save 1
Total memory cells used: 2041
OMG!!! Down from half-a-million to 2041. Indeed. Each an every lines object in
the system uses a collections.deque as buffer (instead of array.array) and is
length-bounding to the absolute needed minimum for the requested operations.
Example:
• The data feed will have a buffer of 30 positions, the amount needed by the SimpleMovingAverage to
produce the next value
• The SimpleMovingAverage will have a buffer of 1 position, because unless needed by other indicator
(which would rely on the moving average) there is no need to keep a larger buffer in place.
Note
The most attractive and probably important feature of this mode is that the
amount of memory used remains constant throughout the entire life of a script.
This would be of great use if for example connected to a live feed for a long
period of time.
524
backtrader’s documentation Version-1.9.58.122
There is for sure a trade off point from which memory management is more
expensive than the step-by-step execution of the backtesting, but this can
only be judged by the end-user of the platform on a case by case basis.
Now the negative levels. These are meant to keep plotting available whilst still
saving a decent amount of memory. First level -1:
$ ./memory-savings.py --save -1
Total memory cells used: 184623
In this case the 1st level of indicators (those declared in the strategy) keep
its full length buffers. But if this indicators rely on others (which is the
case) to do its work, the subobjects will be length-bounded. In this case we have
gone from:
Note
Of course array.array objects have been traded for collections.deque which are
more expensive in memory terms although faster in operation terms. But the
collection.deque objects are rather small and the savings approach the roughly
counted memory positions used.
Level -2 now, which is meant to also save on the indicators declared at the
strategy level which have been marked as no to be plotted:
$ ./memory-savings.py --save -2
Total memory cells used: 174695
Not much has been saved now. This being because a single indicator has been
tagged as not be plotted: TestInd().plotinfo.plot = False
For the interested reader, the sample script can produce a detailed analysis of
each lines object traversed in the hierarchy of indicators. Running with plotting
enabled (saving at -1):
526
backtrader’s documentation Version-1.9.58.122
The 2nd output immediately shows how the lines in the data feed have been capped
to 38 memory positions instead of the 4965 which comprises the full data source
length.
And indicators and observers* have been when possible capped to 1 as seen in the
last lines of the output.
$ ./memory-savings.py --help
usage: memory-savings.py [-h] [--data DATA] [--save SAVE] [--datalines]
[--lendetails] [--plot]
optional arguments:
-h, --help show this help message and exit
--data DATA Data to be read in (default: ../../datas/yhoo-1996-2015.txt)
--save SAVE Memory saving level [1, 0, -1, -2] (default: 0)
--datalines Print data lines (default: False)
--lendetails Print individual items memory usage (default: False)
--plot Plot the result (default: False)
527
backtrader’s documentation Version-1.9.58.122
The code:
import argparse
import sys
import backtrader as bt
import backtrader.feeds as btfeeds
import backtrader.indicators as btind
import backtrader.utils.flushfile
class TestInd(bt.Indicator):
lines = ('a', 'b')
def __init__(self):
self.lines.a = b = self.data.close - self.data.high
self.lines.b = btind.SMA(b, period=20)
class St(bt.Strategy):
params = (
('datalines', False),
('lendetails', False),
)
def __init__(self):
btind.SMA()
btind.Stochastic()
btind.RSI()
btind.MACD()
btind.CCI()
TestInd().plotinfo.plot = False
def next(self):
if self.p.datalines:
txt = ','.join(
['%04d' % len(self),
'%04d' % len(self.data0),
self.data.datetime.date(0).isoformat()]
)
528
backtrader’s documentation Version-1.9.58.122
print(txt)
def stop(self):
super(St, self).stop()
tlen = 0
self.loglendetails('-- Evaluating Datas')
for i, data in enumerate(self.datas):
tdata = 0
for line in data.lines:
tdata += len(line.array)
tline = len(line.array)
tlen += tdata
logtxt = '---- Data {} Total Cells {} - Cells per Line {}'
self.loglendetails(logtxt.format(i, tdata, tline))
tlen += tdata
logtxt = '---- Observer {} Total Cells {} - Cells per Line {}'
self.loglendetails(logtxt.format(i, tobs, tline))
529
backtrader’s documentation Version-1.9.58.122
thisind = tind
tsub = 0
for j, sind in enumerate(ind.getindicators()):
tsub += self.rindicator(sind, j, deep + 1)
iname = ind.__class__.__name__.split('.')[-1]
logtxt = '---- Indicator {}.{} {} Total Cells {} - Cells per line {}'
self.loglendetails(logtxt.format(deep, i, iname, tind, tline))
logtxt = '---- SubIndicators Total Cells {}'
self.loglendetails(logtxt.format(deep, i, iname, tsub))
def runstrat():
args = parse_args()
cerebro = bt.Cerebro()
data = btfeeds.YahooFinanceCSVData(dataname=args.data)
cerebro.adddata(data)
cerebro.addstrategy(
St, datalines=args.datalines, lendetails=args.lendetails)
cerebro.run(runonce=False, exactbars=args.save)
if args.plot:
cerebro.plot(style='bar')
def parse_args():
parser = argparse.ArgumentParser(
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
description='Check Memory Savings')
parser.add_argument('--data', required=False,
default='../../datas/yhoo-1996-2015.txt',
help='Data to be read in')
return parser.parse_args()
if __name__ == '__main__':
runstrat()
DateTime Management
And the same for any user input like in the case of the parameter fromdate (or
sessionstart) which can be given to any data source
The approach was fine given the direct control over frozen data sources for
backtesting. It was easy to assume that the input datetimes had already been
taken care of before they entered the system.
But with 1.5.0, live data sources are supported and this forces to take into
account datetime management. Such management would not be needed if the following
were always true:
• A trader in New York trades the ES-Mini. The time zone for both in US/Eastern (or one of the aliases)
• A trader in Berlin trades the DAX future. In this case for both the CET (or Europe/Berling) timezone applies
The direct input-output datetime approach from above would work, becase the
trader, in Berlin for example, could always do something like this:
class Strategy(bt.Strategy):
def next(self):
The problem with the direct approach surfaces when the same trader in Berlin
decides to trade the ES-Mini. Because the change to from DST happens at different
point in time in the year and this causes the time difference to be out of sync a
couple of weeks during the year. The following wouldn’t always work:
class Strategy(bt.Strategy):
def next(self):
To solve the aforementioned situations and still remain compatible with the
direct input-output time approach, backtrader offers the end user the following
Datetime Input
• As a default the platform will not touch the datetime provided by a data
source
o The end-user can override this input by:
Providing a tzinput parameter to the data source. This must be an object compatible
with the datetime.tzinfo interface. Most likely the user will provide a pytz.timezone
instance
532
backtrader’s documentation Version-1.9.58.122
Datetime output
• If the data feed can automatically determine the timezone for the output,
this will be the default
This makes sense in the case of live-feeds and especially in use cases like
the one in which a trader in Berlin (CET timezone), trades products with
US/Eastern timezone.
Because the trader gets always the right time and in the example above the
opening time remains constant at 09:30 US/Eastern, rather than 15:30 CET
most of the year, but sometimes 16:30 CET and sometimes 14:30 CET.
Note
Input fromt the user like for example the parameters fromdate or sessionstart are
expected to be in sync with the actual tz, be it automatically calculated by the
data source, supplied by the user or left as default (None, which means direct
input-output of datetime)
With all that in mind let’s recall the Berlin trader, trading in US/Eastern:
import pytz
import bt
class Strategy(bt.Strategy):
def next(self):
533
backtrader’s documentation Version-1.9.58.122
In the case of a data source which can automatically determine the output
timezone:
import bt
data = bt.feeds.MyFeedAutoTZ('ES-Mini')
class Strategy(bt.Strategy):
def next(self):
Obviously MyFeed and MyFeedAuto in the example above are just dummy names.
Note
At the time of writing the only data source included in the distribution which
can automatically determine the timezone is the one connecting to Interactive
Brokers
Starting with release 1.5.0 backtrader supports live data and live trading.
534
backtrader’s documentation Version-1.9.58.122
Interactive Brokers
Visual Chart
Oanda
AbstractDataBase
Lines:
• close
• low
• high
• open
• volume
• openinterest
• datetime
Params:
• dataname (None)
• name ()
• compression (1)
• timeframe (5)
• fromdate (None)
• todate (None)
• sessionstart (None)
• sessionend (None)
• filters ([])
• tz (None)
• tzinput (None)
• qcheck (0.0)
• calendar (None)
BacktraderCSVData
535
backtrader’s documentation Version-1.9.58.122
Specific parameters:
Lines:
• close
• low
• high
• open
• volume
• openinterest
• datetime
Params:
• dataname (None)
• name ()
• compression (1)
• timeframe (5)
• fromdate (None)
• todate (None)
• sessionstart (None)
• sessionend (None)
• filters ([])
• tz (None)
• tzinput (None)
• qcheck (0.0)
• calendar (None)
• headers (True)
• separator (,)
CSVDataBase
The class takes care of opening the file, reading the lines and tokenizing them.
• _loadline(tokens)
The return value of _loadline (True/False) will be the return value of _load
which has been overriden by this base class
536
backtrader’s documentation Version-1.9.58.122
Lines:
• close
• low
• high
• open
• volume
• openinterest
• datetime
Params:
• dataname (None)
• name ()
• compression (1)
• timeframe (5)
• fromdate (None)
• todate (None)
• sessionstart (None)
• sessionend (None)
• filters ([])
• tz (None)
• tzinput (None)
• qcheck (0.0)
• calendar (None)
• headers (True)
• separator (,)
Chainer
Lines:
• close
• low
• high
• open
• volume
• openinterest
• datetime
Params:
537
backtrader’s documentation Version-1.9.58.122
• dataname (None)
• name ()
• compression (1)
• timeframe (5)
• fromdate (None)
• todate (None)
• sessionstart (None)
• sessionend (None)
• filters ([])
• tz (None)
• tzinput (None)
• qcheck (0.0)
• calendar (None)
DataClone
Lines:
• close
• low
• high
• open
• volume
• openinterest
• datetime
Params:
• dataname (None)
• name ()
• compression (1)
• timeframe (5)
• fromdate (None)
• todate (None)
• sessionstart (None)
• sessionend (None)
• filters ([])
• tz (None)
• tzinput (None)
• qcheck (0.0)
• calendar (None)
538
backtrader’s documentation Version-1.9.58.122
DataFiller
This class will fill gaps in the source data using the following information bits
from the underlying data source
If a data feed has missing bars in between 10:31 and 10:34 and the timeframe is
minutes, the output will be filled with bars for minutes 10:32 and 10:33 using
the closing price of the last bar (10:31)
Params:
• fill_price (def: None): if None (or evaluates to False),the closing price will be used, else the passed
value (which can be for example ‘NaN’ to have a missing bar in terms of evaluation but present in
terms of time
• fill_vol (def: NaN): used to fill the volume of missing bars
• fill_oi (def: NaN): used to fill the openinterest of missing bars
Lines:
• close
• low
• high
• open
• volume
• openinterest
• datetime
Params:
• dataname (None)
• name ()
• compression (1)
• timeframe (5)
• fromdate (None)
• todate (None)
• sessionstart (None)
• sessionend (None)
• filters ([])
• tz (None)
539
backtrader’s documentation Version-1.9.58.122
• tzinput (None)
• qcheck (0.0)
• calendar (None)
• fill_price (None)
• fill_vol (nan)
• fill_oi (nan)
DataFilter
This class filters out bars from a given data source. In addition to the standard
parameters of a DataBase it takes a funcfilter parameter which can be any
callable
Logic:
o Return value True: current data source bar values will used
o Return value False: current data source bar values will discarded
Lines:
• close
• low
• high
• open
• volume
• openinterest
• datetime
Params:
• dataname (None)
• name ()
• compression (1)
• timeframe (5)
• fromdate (None)
• todate (None)
• sessionstart (None)
• sessionend (None)
• filters ([])
• tz (None)
540
backtrader’s documentation Version-1.9.58.122
• tzinput (None)
• qcheck (0.0)
• calendar (None)
• funcfilter (None)
GenericCSVData
Parses a CSV file according to the order and field presence defined by the
parameters
Value that will be used if a value which should be there is missing (the
CSV field is empty)
• dtformat: Format used to parse the datetime CSV field. See the python
strptime/strftime documentation for the format.
o 1: The value is a Unix timestamp of type int representing the number of seconds since Jan 1st,
1970
o 2: The value is a Unix timestamp of type float
If a callable is passed
Lines:
• close
• low
• high
• open
541
backtrader’s documentation Version-1.9.58.122
• volume
• openinterest
• datetime
Params:
• dataname (None)
• name ()
• compression (1)
• timeframe (5)
• fromdate (None)
• todate (None)
• sessionstart (None)
• sessionend (None)
• filters ([])
• tz (None)
• tzinput (None)
• qcheck (0.0)
• calendar (None)
• headers (True)
• separator (,)
• nullvalue (nan)
• dtformat (%Y-%m-%d %H:%M:%S)
• tmformat (%H:%M:%S)
• datetime (0)
• time (-1)
• open (1)
• high (2)
• low (3)
• close (4)
• volume (5)
• openinterest (6)
IBData
• TICKER-CFD-EXCHANGE # CFD
• TICKER-CDF-EXCHANGE-CURRENCY # Stock
• TICKER-IND-EXCHANGE # Index
• TICKER-IND-EXCHANGE-CURRENCY # Index
• TICKER-YYYYMM-EXCHANGE # Future
• TICKER-YYYYMM-EXCHANGE-CURRENCY # Future
• TICKER-YYYYMM-EXCHANGE-CURRENCY-MULT # Future
• TICKER-FUT-EXCHANGE-CURRENCY-YYYYMM-MULT # Future
• TICKER-YYYYMM-EXCHANGE-CURRENCY-STRIKE-RIGHT # FOP
• TICKER-YYYYMM-EXCHANGE-CURRENCY-STRIKE-RIGHT-MULT # FOP
• TICKER-FOP-EXCHANGE-CURRENCY-YYYYMM-STRIKE-RIGHT # FOP
• TICKER-FOP-EXCHANGE-CURRENCY-YYYYMM-STRIKE-RIGHT-MULT # FOP
• CUR1.CUR2-CASH-IDEALPRO # Forex
• TICKER-YYYYMMDD-EXCHANGE-CURRENCY-STRIKE-RIGHT # OPT
• TICKER-YYYYMMDD-EXCHANGE-CURRENCY-STRIKE-RIGHT-MULT # OPT
• TICKER-OPT-EXCHANGE-CURRENCY-YYYYMMDD-STRIKE-RIGHT # OPT
• TICKER-OPT-EXCHANGE-CURRENCY-YYYYMMDD-STRIKE-RIGHT-MULT # OPT
Params:
If set to True the data feed will stop after doing the first download of
data.
The standard data feed parameters fromdate and todate will be used as
reference.
543
backtrader’s documentation Version-1.9.58.122
The data feed will make multiple requests if the requested duration is
larger than the one allowed by IB given the timeframe/compression chosen
for the data.
If None the default for different assets types will be used for historical
data requests:
If False then the RTVolume prices will be used, which are based on
receiving ticks. In the case of CASH assets (like for example EUR.JPY)
RTVolume will always be used and from it the bid price (industry de-facto
standard with IB according to the literature scattered over the Internet)
Perform backfilling at the start. The maximum possible historical data will
be fetched in a single request.
544
backtrader’s documentation Version-1.9.58.122
If the data source is resampled/replayed, some ticks may come in too late
for the already delivered resampled/replayed bar. If this is True those
ticks will bet let through in any case.
Check the Resampler documentation to see who to take those ticks into
account.
• tradename (default: None) Useful for some specific cases like CFD in which
prices are offered by one asset and trading happens in a different onel
o SPY-STK-SMART-USD -> SP500 ETF (will be specified as dataname)
o SPY-CFD-SMART-USD -> which is the corresponding CFD which offers not price tracking but in this
case will be the trading asset (specified as tradename)
The default values in the params are the to allow things like `TICKER, to which
the parameter sectype (default: STK) and exchange (default: SMART) are applied.
Some assets like AAPL need full specification including currency (default: ‘’)
whereas others like TWTR can be simply passed as it is.
Lines:
• close
• low
• high
• open
• volume
• openinterest
• datetime
Params:
545
backtrader’s documentation Version-1.9.58.122
• dataname (None)
• name ()
• compression (1)
• timeframe (5)
• fromdate (None)
• todate (None)
• sessionstart (None)
• sessionend (None)
• filters ([])
• tz (None)
• tzinput (None)
• qcheck (0.5)
• calendar (None)
• sectype (STK)
• exchange (SMART)
• currency ()
• rtbar (False)
• historical (False)
• what (None)
• useRTH (False)
• backfill_start (True)
• backfill (True)
• backfill_from (None)
• latethrough (False)
• tradename (None)
InfluxDB
Lines:
• close
• low
• high
• open
• volume
• openinterest
• datetime
Params:
• dataname (None)
• name ()
• compression (1)
• timeframe (5)
546
backtrader’s documentation Version-1.9.58.122
• fromdate (None)
• todate (None)
• sessionstart (None)
• sessionend (None)
• filters ([])
• tz (None)
• tzinput (None)
• qcheck (0.0)
• calendar (None)
• host (127.0.0.1)
• port (8086)
• username (None)
• password (None)
• database (None)
• startdate (None)
• high (high_p)
• low (low_p)
• open (open_p)
• close (close_p)
• volume (volume)
• ointerest (oi)
MT4CSVData
Lines:
• close
• low
• high
• open
• volume
• openinterest
• datetime
Params:
• dataname (None)
547
backtrader’s documentation Version-1.9.58.122
• name ()
• compression (1)
• timeframe (5)
• fromdate (None)
• todate (None)
• sessionstart (None)
• sessionend (None)
• filters ([])
• tz (None)
• tzinput (None)
• qcheck (0.0)
• calendar (None)
• headers (True)
• separator (,)
• nullvalue (nan)
• dtformat (%Y.%m.%d)
• tmformat (%H:%M)
• datetime (0)
• time (1)
• open (2)
• high (3)
• low (4)
• close (5)
• volume (6)
• openinterest (-1)
OandaData
Params:
If set to True the data feed will stop after doing the first download of
data.
The standard data feed parameters fromdate and todate will be used as
reference.
548
backtrader’s documentation Version-1.9.58.122
The data feed will make multiple requests if the requested duration is
larger than the one allowed by IB given the timeframe/compression chosen
for the data.
Perform backfilling at the start. The maximum possible historical data will
be fetched in a single request.
If True the ask part of the bidask prices will be used instead of the
default use of bid
549
backtrader’s documentation Version-1.9.58.122
This data feed supports only this mapping of timeframe and compression, which
comply with the definitions in the OANDA API Developer’s Guid:
Lines:
• close
• low
• high
• open
• volume
• openinterest
• datetime
Params:
• dataname (None)
• name ()
550
backtrader’s documentation Version-1.9.58.122
• compression (1)
• timeframe (5)
• fromdate (None)
• todate (None)
• sessionstart (None)
• sessionend (None)
• filters ([])
• tz (None)
• tzinput (None)
• qcheck (0.5)
• calendar (None)
• historical (False)
• backfill_start (True)
• backfill (True)
• backfill_from (None)
• bidask (True)
• useask (False)
• includeFirst (True)
• reconnect (True)
• reconnections (-1)
• reconntimeout (5.0)
PandasData
Uses a Pandas DataFrame as the feed source, using indices into column names
(which can be “numeric”)
This means that all parameters related to lines must have numeric values as
indices into the tuples
Params:
Note:
Lines:
• close
• low
• high
• open
• volume
• openinterest
• datetime
Params:
• dataname (None)
• name ()
• compression (1)
• timeframe (5)
• fromdate (None)
• todate (None)
• sessionstart (None)
• sessionend (None)
• filters ([])
• tz (None)
• tzinput (None)
• qcheck (0.0)
• calendar (None)
• nocase (True)
• datetime (None)
• open (-1)
• high (-1)
• low (-1)
• close (-1)
• volume (-1)
• openinterest (-1)
PandasDirectData
Uses a Pandas DataFrame as the feed source, iterating directly over the tuples
returned by “itertuples”.
This means that all parameters related to lines must have numeric values as
indices into the tuples
552
backtrader’s documentation Version-1.9.58.122
Note:
Lines:
• close
• low
• high
• open
• volume
• openinterest
• datetime
Params:
• dataname (None)
• name ()
• compression (1)
• timeframe (5)
• fromdate (None)
• todate (None)
• sessionstart (None)
• sessionend (None)
• filters ([])
• tz (None)
• tzinput (None)
• qcheck (0.0)
• calendar (None)
• datetime (0)
• open (1)
• high (2)
• low (3)
• close (4)
• volume (5)
• openinterest (6)
Quandl
Executes a direct download of data from Quandl servers for the given time range.
• dataname
• baseurl
The server url. Someone might decide to open a Quandl compatible service in
the future.
• proxies
• buffered
If True the entire socket connection wil be buffered locally before parsing
starts.
• reverse
• adjclose
Whether to use the dividend/split adjusted close and adjust all values
according to it.
• apikey
• dataset
Lines:
• close
• low
• high
• open
• volume
• openinterest
554
backtrader’s documentation Version-1.9.58.122
• datetime
Params:
• dataname (None)
• name ()
• compression (1)
• timeframe (5)
• fromdate (None)
• todate (None)
• sessionstart (None)
• sessionend (None)
• filters ([])
• tz (None)
• tzinput (None)
• qcheck (0.0)
• calendar (None)
• headers (True)
• separator (,)
• reverse (True)
• adjclose (True)
• round (False)
• decimals (2)
• baseurl (https://www.quandl.com/api/v3/datasets)
• proxies ({})
• buffered (True)
• apikey (None)
• dataset (WIKI)
QuandlCSV
Parses pre-downloaded Quandl CSV Data Feeds (or locally generated if they comply
to the Quandl format)
Specific parameters:
It is assumed that locally stored files have already been reversed during
the download process
555
backtrader’s documentation Version-1.9.58.122
Whether to use the dividend/split adjusted close and adjust all values
according to it.
• decimals (default: 2)
Lines:
• close
• low
• high
• open
• volume
• openinterest
• datetime
Params:
• dataname (None)
• name ()
• compression (1)
• timeframe (5)
• fromdate (None)
• todate (None)
• sessionstart (None)
• sessionend (None)
• filters ([])
• tz (None)
• tzinput (None)
• qcheck (0.0)
• calendar (None)
• headers (True)
• separator (,)
• reverse (False)
• adjclose (True)
• round (False)
• decimals (2)
556
backtrader’s documentation Version-1.9.58.122
RollOver
Class that rolls over to the next future when a condition is met
Params:
checkdate(dt, d):
Where:
o dt is a datetime.datetime object
o d is the current data feed for the active future
o True: as long as the callable returns this, a switchover can happen to the next future
If a commodity expires on the 3rd Friday of March, checkdate could return True
for the entire week in which the expiration takes place.
checkcondition(d0, d1)
Where:
557
backtrader’s documentation Version-1.9.58.122
Following with the example from checkdate, this could say that the roll-over can
only happend if the volume from d0 is already less than the volume from d1
Lines:
• close
• low
• high
• open
• volume
• openinterest
• datetime
Params:
• dataname (None)
• name ()
• compression (1)
• timeframe (5)
• fromdate (None)
• todate (None)
• sessionstart (None)
• sessionend (None)
• filters ([])
• tz (None)
• tzinput (None)
• qcheck (0.0)
• calendar (None)
• checkdate (None)
• checkcondition (None)
SierraChartCSVData
Lines:
558
backtrader’s documentation Version-1.9.58.122
• close
• low
• high
• open
• volume
• openinterest
• datetime
Params:
• dataname (None)
• name ()
• compression (1)
• timeframe (5)
• fromdate (None)
• todate (None)
• sessionstart (None)
• sessionend (None)
• filters ([])
• tz (None)
• tzinput (None)
• qcheck (0.0)
• calendar (None)
• headers (True)
• separator (,)
• nullvalue (nan)
• dtformat (%Y/%m/%d)
• tmformat (%H:%M:%S)
• datetime (0)
• time (-1)
• open (1)
• high (2)
• low (3)
• close (4)
• volume (5)
• openinterest (6)
VCData
Params:
559
backtrader’s documentation Version-1.9.58.122
• milliseconds (default: True) The bars constructed by Visual Chart have this
aspect: HH:MM:59.999000
• tradename (default: None) Continous futures cannot be traded but are ideal
for data tracking. If this parameter is supplied it will be the name of the
current future which will be the trading asset. Example:
o 001ES -> ES-Mini continuous supplied as dataname
o ESU16 -> ES-Mini 2016-09. If this is supplied in tradename it will be the trading asset.
• usetimezones (default: True) For most markets the time offset information
provided by Visual Chart allows for datetime to be converted to market time
(backtrader choice for representation)
Some markets are special (096) and need special internal coverage and
timezone support to display in the user expected market time.
Disabling it will remove timezone usage (may help if the load is excesive)
Lines:
• close
• low
• high
• open
• volume
• openinterest
• datetime
Params:
560
backtrader’s documentation Version-1.9.58.122
• dataname (None)
• name ()
• compression (1)
• timeframe (5)
• fromdate (None)
• todate (None)
• sessionstart (None)
• sessionend (None)
• filters ([])
• tz (None)
• tzinput (None)
• qcheck (0.5)
• calendar (None)
• historical (False)
• millisecond (True)
• tradename (None)
• usetimezones (True)
VChartCSVData
Lines:
• close
• low
• high
• open
• volume
• openinterest
• datetime
Params:
• dataname (None)
• name ()
• compression (1)
• timeframe (5)
• fromdate (None)
• todate (None)
561
backtrader’s documentation Version-1.9.58.122
• sessionstart (None)
• sessionend (None)
• filters ([])
• tz (None)
• tzinput (None)
• qcheck (0.0)
• calendar (None)
• headers (True)
• separator (,)
VChartData
Support for Visual Chart binary on-disk files for both daily and intradaily
formats.
Note:
Else the file extension (.fd for daily and .min for intraday) will be used.
Lines:
• close
• low
• high
• open
• volume
• openinterest
• datetime
Params:
• dataname (None)
• name ()
• compression (1)
• timeframe (5)
• fromdate (None)
• todate (None)
• sessionstart (None)
• sessionend (None)
562
backtrader’s documentation Version-1.9.58.122
• filters ([])
• tz (None)
• tzinput (None)
• qcheck (0.0)
• calendar (None)
VChartFile
Support for Visual Chart binary on-disk files for both daily and intradaily
formats.
Note:
• dataname: Market code displayed by Visual Chart. Example: 015ES for EuroStoxx 50 continuous future
Lines:
• close
• low
• high
• open
• volume
• openinterest
• datetime
Params:
• dataname (None)
• name ()
• compression (1)
• timeframe (5)
• fromdate (None)
• todate (None)
• sessionstart (None)
• sessionend (None)
• filters ([])
• tz (None)
• tzinput (None)
• qcheck (0.0)
• calendar (None)
563
backtrader’s documentation Version-1.9.58.122
YahooFinanceCSVData
Parses pre-downloaded Yahoo CSV Data Feeds (or locally generated if they comply
to the Yahoo format)
Specific parameters:
It is assumed that locally stored files have already been reversed during
the download process
Whether to use the dividend/split adjusted close and adjust all values
according to it.
• decimals (default: 2)
In May-2017 Yahoo discontinued the original ichart API for downloads and
moved to a new API, which contains a v7 string. This is the default
version.
Lines:
• close
• low
564
backtrader’s documentation Version-1.9.58.122
• high
• open
• volume
• openinterest
• datetime
Params:
• dataname (None)
• name ()
• compression (1)
• timeframe (5)
• fromdate (None)
• todate (None)
• sessionstart (None)
• sessionend (None)
• filters ([])
• tz (None)
• tzinput (None)
• qcheck (0.0)
• calendar (None)
• headers (True)
• separator (,)
• reverse (False)
• adjclose (True)
• round (True)
• decimals (2)
• version (v7)
• swapcloses (False)
YahooFinanceData
Executes a direct download of data from Yahoo servers for the given time range.
• dataname
• baseurl
The server url. Someone might decide to open a Yahoo compatible service in
the future.
565
backtrader’s documentation Version-1.9.58.122
• proxies
• period
The timeframe to download data in. Pass ‘w’ for weekly and ‘m’ for
monthly.
• buffered
If True the entire socket connection wil be buffered locally before parsing
starts.
• reverse
Yahoo returns the data with last dates first (against all industry
standards) and it must be reversed for it to work. Should this Yahoo
standard change, the parameter is available.
• adjclose
Whether to use the dividend/split adjusted close and adjust all values
according to it.
• urlhist
The url of the historical quotes in Yahoo Finance used to gather a crumb
authorization cookie for the download
• urldown
• retries
Number of times (each) to try to get a crumb cookie and download the data
Lines:
• close
• low
• high
• open
• volume
566
backtrader’s documentation Version-1.9.58.122
• openinterest
• datetime
Params:
• dataname (None)
• name ()
• compression (1)
• timeframe (5)
• fromdate (None)
• todate (None)
• sessionstart (None)
• sessionend (None)
• filters ([])
• tz (None)
• tzinput (None)
• qcheck (0.0)
• calendar (None)
• headers (True)
• separator (,)
• reverse (True)
• adjclose (True)
• round (True)
• decimals (2)
• version (v7)
• swapcloses (False)
• baseurl (http://ichart.yahoo.com/table.csv?)
• proxies ({})
• period (d)
• buffered (True)
• urlhist (https://finance.yahoo.com/quote/{}/history)
• urldown (https://query1.finance.yahoo.com/v7/finance/download)
• retries (3)
YahooLegacyCSV
This is intended to load files which were downloaded before Yahoo discontinued
the original service in May-2017
Lines:
• close
• low
• high
567
backtrader’s documentation Version-1.9.58.122
• open
• volume
• openinterest
• datetime
Params:
• dataname (None)
• name ()
• compression (1)
• timeframe (5)
• fromdate (None)
• todate (None)
• sessionstart (None)
• sessionend (None)
• filters ([])
• tz (None)
• tzinput (None)
• qcheck (0.0)
• calendar (None)
• headers (True)
• separator (,)
• reverse (False)
• adjclose (True)
• round (True)
• decimals (2)
• version ()
• swapcloses (False)
In May 2017 Yahoo discontinued the existing API for historical data downloads in
csv format.
A new API (here named v7) was quickly standardized and has been implemented.
Starting with version 1.9.49.116 this is the default behavior. Choose simply from
568
backtrader’s documentation Version-1.9.58.122
data = bt.feeds.YahooFinanceCSVData(
...
version='',
...
)
It might be that the online service comes back (the service was
discontinued without any announcement ... it might as well come back)
or
2. Only for Offline files downloaded before the change happened, the following
can also be done:
3. data = bt.feeds.YahooLegacyCSV(
4. ...
5. ...
6. )
Indicator Reference
AccelerationDecelerationOscillator
Alias:
• AccDeOsc
569
backtrader’s documentation Version-1.9.58.122
Formula:
See:
• https://www.metatrader5.com/en/terminal/help/indicators/bw_indicators/ao
• https://www.ifcmarkets.com/en/ntx-indicators/ntx-indicators-accelerator-decelerator-oscillator
Lines:
• accde
Params:
• period (5)
• movav (SMA)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (True)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
570
backtrader’s documentation Version-1.9.58.122
Accum
Alias:
• CumSum, CumulativeSum
Formula:
• accum += data
Lines:
• accum
Params:
• seed (0.0)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (True)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• accum:
571
backtrader’s documentation Version-1.9.58.122
AdaptiveMovingAverage
Alias:
• KAMA, MovingAverageAdaptive
If the market trends the value will tend to the fast ema smoothing period. If the
market doesn’t trend it will move towards the slow EMA smoothing period.
Formula:
See also:
• http://fxcodebase.com/wiki/index.php/Kaufman’s_Adaptive_Moving_Average_(KAMA)
• http://www.metatrader5.com/en/terminal/help/analytics/indicators/trend_indicators/ama
• http://help.cqg.com/cqgic/default.htm#!Documents/adaptivemovingaverag2.htm
Lines:
• kama
Params:
• period (30)
• fast (2)
• slow (30)
572
backtrader’s documentation Version-1.9.58.122
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (False)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• kama:
AdaptiveMovingAverageEnvelope
Alias:
• KAMAEnvelope, MovingAverageAdaptiveEnvelope
Formula:
See also:
• http://stockcharts.com/school/doku.php?id=chart_school:technical_indicators:moving_average_
envelopes
Lines:
• kama
• top
573
backtrader’s documentation Version-1.9.58.122
• bot
Params:
• period (30)
• fast (2)
• slow (30)
• perc (2.5)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (False)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• kama:
• top: - _samecolor (True)
• bot: - _samecolor (True)
AdaptiveMovingAverageOscillator
Alias:
Lines:
• kama
574
backtrader’s documentation Version-1.9.58.122
Params:
• period (30)
• fast (2)
• slow (30)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (True)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• kama:
• _0: - _name (osc)
AllN
Has a value of True (stored as 1.0 in the lines) if all of the values in the
period evaluates to non-zero (ie: True)
Formula:
Lines:
• alln
Params:
575
backtrader’s documentation Version-1.9.58.122
• period (1)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (True)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• alln:
AnyN
Has a value of True (stored as 1.0 in the lines) if any of the values in the
period evaluates to non-zero (ie: True)
Formula:
Lines:
• anyn
Params:
• period (1)
PlotInfo:
576
backtrader’s documentation Version-1.9.58.122
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (True)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• anyn:
ApplyN
Formula:
Lines:
• apply
Params:
• period (1)
• func (None)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (True)
• plotvaluetags (True)
• plotskip (False)
577
backtrader’s documentation Version-1.9.58.122
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• apply:
AroonDown
This is the AroonDown from the indicator AroonUpDown developed by Tushar Chande
in 1995.
Formula:
Note:
The lines oscillate between 0 and 100. That means that the “distance” to
the last highest or lowest must go from 0 to period so that the formula can
yield 0 and 100.
Hence the lookback period is period + 1, because the current bar is also
taken into account. And therefore this indicator needs an effective
lookback period of period + 1.
See:
• http://stockcharts.com/school/doku.php?id=chart_school:technical_indicators:aroon
Lines:
• aroondown
Params:
• period (14)
• upperband (70)
578
backtrader’s documentation Version-1.9.58.122
• lowerband (30)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (True)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([0, 100])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.05)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• aroondown:
AroonOscillator
Alias:
• AroonOsc
Formula:
See:
• http://stockcharts.com/school/doku.php?id=chart_school:technical_indicators:aroon
Lines:
579
backtrader’s documentation Version-1.9.58.122
• aroonosc
Params:
• period (14)
• upperband (70)
• lowerband (30)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (True)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([0, 100])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.05)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• aroonosc:
AroonUp
This is the AroonUp from the indicator AroonUpDown developed by Tushar Chande in
1995.
Formula:
Note:
The lines oscillate between 0 and 100. That means that the “distance” to
the last highest or lowest must go from 0 to period so that the formula can
yield 0 and 100.
580
backtrader’s documentation Version-1.9.58.122
Hence the lookback period is period + 1, because the current bar is also
taken into account. And therefore this indicator needs an effective
lookback period of period + 1.
See:
• http://stockcharts.com/school/doku.php?id=chart_school:technical_indicators:aroon
Lines:
• aroonup
Params:
• period (14)
• upperband (70)
• lowerband (30)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (True)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([0, 100])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.05)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• aroonup:
AroonUpDown
Alias:
• AroonIndicator
581
backtrader’s documentation Version-1.9.58.122
It tries to determine if a trend exists or not by calculating how far away within
a given period the last highs/lows are (AroonUp/AroonDown)
Formula:
Note:
The lines oscillate between 0 and 100. That means that the “distance” to
the last highest or lowest must go from 0 to period so that the formula can
yield 0 and 100.
Hence the lookback period is period + 1, because the current bar is also
taken into account. And therefore this indicator needs an effective
lookback period of period + 1.
See:
• http://stockcharts.com/school/doku.php?id=chart_school:technical_indicators:aroon
Lines:
• aroonup
• aroondown
Params:
• period (14)
• upperband (70)
• lowerband (30)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (True)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([0, 100])
582
backtrader’s documentation Version-1.9.58.122
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.05)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• aroonup:
• aroondown:
AroonUpDownOscillator
Alias:
• AroonUpDownOsc
Formula:
(None, uses the aforementioned indicators)
See:
• http://stockcharts.com/school/doku.php?id=chart_school:technical_indicators:aroon
Lines:
• aroonup
• aroondown
• aroonosc
Params:
• period (14)
• upperband (70)
• lowerband (30)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (True)
• plotvaluetags (True)
583
backtrader’s documentation Version-1.9.58.122
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([0, 100])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.05)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• aroonup:
• aroondown:
• aroonosc:
Average
Alias:
• ArithmeticMean, Mean
Formula:
• av = data(period) / period
See also:
• https://en.wikipedia.org/wiki/Arithmetic_mean
Lines:
• av
Params:
• period (1)
PlotInfo:
• plot (True)
• legendloc (None)
584
backtrader’s documentation Version-1.9.58.122
• plotmaster (None)
• subplot (True)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• av:
AverageDirectionalMovementIndex
Alias:
• ADX
Defined by J. Welles Wilder, Jr. in 1978 in his book “New Concepts in Technical
Trading Systems”.
Formula:
585
backtrader’s documentation Version-1.9.58.122
The moving average used is the one originally defined by Wilder, the
SmoothedMovingAverage
See:
• https://en.wikipedia.org/wiki/Average_directional_movement_index
Lines:
• adx
Params:
• period (14)
• movav (SmoothedMovingAverage)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (True)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
586
backtrader’s documentation Version-1.9.58.122
AverageDirectionalMovementIndexRating
Alias:
• ADXR
Defined by J. Welles Wilder, Jr. in 1978 in his book “New Concepts in Technical
Trading Systems”.
Formula:
The moving average used is the one originally defined by Wilder, the
SmoothedMovingAverage
See:
• https://en.wikipedia.org/wiki/Average_directional_movement_index
Lines:
• adx
• adxr
587
backtrader’s documentation Version-1.9.58.122
Params:
• period (14)
• movav (SmoothedMovingAverage)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (True)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
AverageTrueRange
Alias:
• ATR
Defined by J. Welles Wilder, Jr. in 1978 in his book “New Concepts in Technical
Trading Systems”.
The idea is to take the close into account to calculate the range if it yields a
larger range than the daily range (High - Low)
Formula:
• SmoothedMovingAverage(TrueRange, period)
588
backtrader’s documentation Version-1.9.58.122
See:
• http://en.wikipedia.org/wiki/Average_true_range
Lines:
• atr
Params:
• period (14)
• movav (SmoothedMovingAverage)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (True)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• atr:
AwesomeOscillator
Alias:
• AwesomeOsc, AO
589
backtrader’s documentation Version-1.9.58.122
Formula:
See:
• https://www.metatrader5.com/en/terminal/help/indicators/bw_indicators/awesome
• https://www.ifcmarkets.com/en/ntx-indicators/awesome-oscillator
Lines:
• ao
Params:
• fast (5)
• slow (34)
• movav (SMA)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (True)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
590
backtrader’s documentation Version-1.9.58.122
BaseApplyN
Base class for ApplyN and others which may take a func as a parameter but want to
define the lines in the indicator.
Calculates func for a given period where func is given as a parameter, aka named
argument or kwarg
Formula:
Any extra lines defined beyond the first (index 0) are not calculated
Params:
• period (1)
• func (None)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (True)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
BollingerBands
Alias:
• BBands
591
backtrader’s documentation Version-1.9.58.122
Formula:
See:
• http://en.wikipedia.org/wiki/Bollinger_Bands
Lines:
• mid
• top
• bot
Params:
• period (20)
• devfactor (2.0)
• movav (MovingAverageSimple)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (False)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
BollingerBandsPct
Lines:
• mid
• top
• bot
• pctb
Params:
• period (20)
• devfactor (2.0)
• movav (MovingAverageSimple)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (False)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
593
backtrader’s documentation Version-1.9.58.122
CointN
Calculates the score (coint_t) and pvalue for a given period for the data feeds
Lines:
• score
• pvalue
Params:
• period (10)
• regression (c)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (True)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• score:
• pvalue:
CommodityChannelIndex
Alias:
• CCI
594
backtrader’s documentation Version-1.9.58.122
Formula:
See:
• https://en.wikipedia.org/wiki/Commodity_channel_index
Lines:
• cci
Params:
• period (20)
• factor (0.015)
• movav (MovingAverageSimple)
• upperband (100.0)
• lowerband (-100.0)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (True)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
595
backtrader’s documentation Version-1.9.58.122
PlotLines:
• cci:
CrossDown
This indicator gives a signal if the 1st provided data crosses over the 2nd
indicator upwards
It does need to look into the current time index (0) and the previous time index
(-1) of both the 1t and 2nd data
Formula:
Lines:
• cross
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (True)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([0.0, 1.0])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.05)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• cross:
596
backtrader’s documentation Version-1.9.58.122
CrossOver
This indicator gives a signal if the provided datas (2) cross up or down.
It does need to look into the current time index (0) and the previous time index
(-1) of both the 1t and 2nd data
Formula:
Lines:
• crossover
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (True)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([-1.0, 1.0])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.05)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• crossover:
597
backtrader’s documentation Version-1.9.58.122
CrossUp
This indicator gives a signal if the 1st provided data crosses over the 2nd
indicator upwards
It does need to look into the current time index (0) and the previous time index
(-1) of both the 1t and 2nd data
Formula:
Lines:
• cross
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (True)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([0.0, 1.0])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.05)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• cross:
DV2
See also:
• http://web.archive.org/web/20131216100741/http://quantingdutchman.wordpress.com/2010/08/06/dv
2-indicator-for-amibroker/
Lines:
• dv2
Params:
• period (252)
• maperiod (2)
• _movav (SMA)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (True)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• dv2:
DemarkPivotPoint
Defines a level of significance by taking into account the average of price bar
componentes of the past period of a larget timeframe. For example when operating
with days, the values are taking from the already “past” month fixed prices.
599
backtrader’s documentation Version-1.9.58.122
The indicator will try to automatically plo to the non-resampled data. To disable
this behavior use the following during construction:
• _autoplot=False
Note:
The example shows days and months, but any combination of timeframes can be used. See the literature for
recommended combinations
Formula:
See:
• http://stockcharts.com/school/doku.php?id=chart_school:technical_indicators:pivot_points
Lines:
• p
• s1
• r1
Params:
• open (False)
• close (False)
• _autoplot (True)
• level1 (0.382)
• level2 (0.618)
• level3 (1.0)
600
backtrader’s documentation Version-1.9.58.122
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (False)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• p:
• s1:
• r1:
DetrendedPriceOscillator
Alias:
• DPO
It measures the price variations against a Moving Average (the trend) and
therefore removes the “trend” factor from the price.
Formula:
See:
• http://en.wikipedia.org/wiki/Detrended_price_oscillator
Lines:
601
backtrader’s documentation Version-1.9.58.122
• dpo
Params:
• period (20)
• movav (MovingAverageSimple)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (True)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([0.0])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• dpo:
DicksonMovingAverage
Alias:
• DMA, DicksonMA
By Nathan Dickson
Formula:
• ec = ZeroLagIndicator(period, gainlimit)
• hma = HullMovingAverage(hperiod)
602
backtrader’s documentation Version-1.9.58.122
Note
the passed moving average must calculate alpha (and 1 - alpha) and
make them available as attributes alpha and alpha1
• The 2nd moving averag can be changed from Hull to anything else with
the param _hma
See also:
• https://www.reddit.com/r/algotrading/comments/4xj3vh/dickson_moving_average
Lines:
• dma
Params:
• period (30)
• gainlimit (50)
• hperiod (7)
• _movav (EMA)
• _hma (HMA)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (False)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
603
backtrader’s documentation Version-1.9.58.122
PlotLines:
• dma:
DicksonMovingAverageEnvelope
Alias:
• DMAEnvelope, DicksonMAEnvelope
Formula:
See also:
• http://stockcharts.com/school/doku.php?id=chart_school:technical_indicators:moving_average_
envelopes
Lines:
• dma
• top
• bot
Params:
• period (30)
• gainlimit (50)
• hperiod (7)
• _movav (EMA)
• _hma (HMA)
• perc (2.5)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (False)
• plotvaluetags (True)
604
backtrader’s documentation Version-1.9.58.122
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• dma:
• top: - _samecolor (True)
• bot: - _samecolor (True)
DicksonMovingAverageOscillator
Alias:
Lines:
• dma
Params:
• period (30)
• gainlimit (50)
• hperiod (7)
• _movav (EMA)
• _hma (HMA)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (True)
• plotvaluetags (True)
• plotskip (False)
605
backtrader’s documentation Version-1.9.58.122
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• dma:
• _0: - _name (osc)
DirectionalIndicator
Alias:
• DI
Defined by J. Welles Wilder, Jr. in 1978 in his book “New Concepts in Technical
Trading Systems”.
Formula:
606
backtrader’s documentation Version-1.9.58.122
The moving average used is the one originally defined by Wilder, the
SmoothedMovingAverage
See:
• https://en.wikipedia.org/wiki/Average_directional_movement_index
Lines:
• plusDI
• minusDI
Params:
• period (14)
• movav (SmoothedMovingAverage)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (True)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• minusDI:
• plusDI:
DirectionalMovement
Alias:
• DM
607
backtrader’s documentation Version-1.9.58.122
Defined by J. Welles Wilder, Jr. in 1978 in his book “New Concepts in Technical
Trading Systems”.
Formula:
The moving average used is the one originally defined by Wilder, the
SmoothedMovingAverage
See:
• https://en.wikipedia.org/wiki/Average_directional_movement_index
Lines:
• adx
• adxr
• plusDI
• minusDI
Params:
• period (14)
• movav (SmoothedMovingAverage)
PlotInfo:
608
backtrader’s documentation Version-1.9.58.122
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (True)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• minusDI:
• plusDI:
• adx: - _name (ADX)
• adxr: - _name (ADXR)
DirectionalMovementIndex
Alias:
• DMI
Defined by J. Welles Wilder, Jr. in 1978 in his book “New Concepts in Technical
Trading Systems”.
Formula:
609
backtrader’s documentation Version-1.9.58.122
The moving average used is the one originally defined by Wilder, the
SmoothedMovingAverage
See:
• https://en.wikipedia.org/wiki/Average_directional_movement_index
Lines:
• adx
• plusDI
• minusDI
Params:
• period (14)
• movav (SmoothedMovingAverage)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (True)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
610
backtrader’s documentation Version-1.9.58.122
PlotLines:
• minusDI:
• plusDI:
• adx: - _name (ADX)
DoubleExponentialMovingAverage
Alias:
• DEMA, MovingAverageDoubleExponential
DEMA was first time introduced in 1994, in the article “Smoothing Data with
Faster Moving Averages” by Patrick G. Mulloy in “Technical Analysis of Stocks &
Commodities” magazine.
Formula:
See:
(None)
Lines:
• dema
Params:
• period (30)
• _movav (EMA)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (False)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
611
backtrader’s documentation Version-1.9.58.122
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• dema:
DoubleExponentialMovingAverageEnvelope
Alias:
• DEMAEnvelope, MovingAverageDoubleExponentialEnvelope
Formula:
See also:
• http://stockcharts.com/school/doku.php?id=chart_school:technical_indicators:moving_average_
envelopes
Lines:
• dema
• top
• bot
Params:
• period (30)
• _movav (EMA)
• perc (2.5)
PlotInfo:
• plot (True)
• legendloc (None)
612
backtrader’s documentation Version-1.9.58.122
• plotmaster (None)
• subplot (False)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• dema:
• top: - _samecolor (True)
• bot: - _samecolor (True)
DoubleExponentialMovingAverageOscillator
Alias:
Lines:
• dema
Params:
• period (30)
• _movav (EMA)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (True)
• plotvaluetags (True)
613
backtrader’s documentation Version-1.9.58.122
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• dema:
• _0: - _name (osc)
DownDay
Defined by J. Welles Wilder, Jr. in 1978 in his book “New Concepts in Technical
Trading Systems” for the RSI
Recods days which have been “down”, i.e.: the close price has been lower than
the day before.
Formula:
See:
• http://en.wikipedia.org/wiki/Relative_strength_index
Lines:
• downday
Params:
• period (1)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
614
backtrader’s documentation Version-1.9.58.122
• subplot (True)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• downday:
DownDayBool
Defined by J. Welles Wilder, Jr. in 1978 in his book “New Concepts in Technical
Trading Systems” for the RSI
Recods days which have been “down”, i.e.: the close price has been lower than
the day before.
Note:
Formula:
See:
• http://en.wikipedia.org/wiki/Relative_strength_index
Lines:
• downday
Params:
• period (1)
615
backtrader’s documentation Version-1.9.58.122
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (True)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• downday:
DownMove
Defined by J. Welles Wilder, Jr. in 1978 in his book “New Concepts in Technical
Trading Systems” as part of the Directional Move System to calculate Directional
Indicators.
Positive if the given data has moved lower than the previous day
Formula:
See:
• https://en.wikipedia.org/wiki/Average_directional_movement_index
Lines:
• downmove
PlotInfo:
• plot (True)
616
backtrader’s documentation Version-1.9.58.122
• legendloc (None)
• plotmaster (None)
• subplot (True)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• downmove:
Envelope
It creates envelopes bands separated from the source data by a given percentage
Formula:
• src = datasource
• top = src * (1 + perc)
• bot = src * (1 - perc)
See also:
• http://stockcharts.com/school/doku.php?id=chart_school:technical_indicators:moving_average_
envelopes
Lines:
• src
• top
• bot
Params:
• perc (2.5)
PlotInfo:
617
backtrader’s documentation Version-1.9.58.122
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (False)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
ExponentialMovingAverage
Alias:
• EMA, MovingAverageExponential
It is a subclass of SmoothingMovingAverage.
Formula:
See also:
• http://en.wikipedia.org/wiki/Moving_average#Exponential_moving_average
Lines:
618
backtrader’s documentation Version-1.9.58.122
• ema
Params:
• period (30)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (False)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• ema:
ExponentialMovingAverageEnvelope
Alias:
• EMAEnvelope, MovingAverageExponentialEnvelope
Formula:
See also:
619
backtrader’s documentation Version-1.9.58.122
• http://stockcharts.com/school/doku.php?id=chart_school:technical_indicators:moving_average_
envelopes
Lines:
• ema
• top
• bot
Params:
• period (30)
• perc (2.5)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (False)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• ema:
• top: - _samecolor (True)
• bot: - _samecolor (True)
ExponentialMovingAverageOscillator
Alias:
620
backtrader’s documentation Version-1.9.58.122
Lines:
• ema
Params:
• period (30)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (True)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• ema:
• _0: - _name (osc)
ExponentialSmoothing
Alias:
• ExpSmoothing
Formula:
621
backtrader’s documentation Version-1.9.58.122
See also:
• https://en.wikipedia.org/wiki/Exponential_smoothing
Lines:
• av
Params:
• period (1)
• alpha (None)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (True)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• av:
ExponentialSmoothingDynamic
Alias:
• ExpSmoothingDynamic
622
backtrader’s documentation Version-1.9.58.122
Note:
Formula:
See also:
• https://en.wikipedia.org/wiki/Exponential_smoothing
Lines:
• av
Params:
• period (1)
• alpha (None)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (True)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• av:
623
backtrader’s documentation Version-1.9.58.122
FibonacciPivotPoint
Defines a level of significance by taking into account the average of price bar
componentes of the past period of a larget timeframe. For example when operating
with days, the values are taking from the already “past” month fixed prices.
The indicator will try to automatically plo to the non-resampled data. To disable
this behavior use the following during construction:
• _autoplot=False
Note:
The example shows days and months, but any combination of timeframes can be used. See the literature for
recommended combinations
Formula:
See:
• http://stockcharts.com/school/doku.php?id=chart_school:technical_indicators:pivot_points
Lines:
• p
• s1
• s2
624
backtrader’s documentation Version-1.9.58.122
• s3
• r1
• r2
• r3
Params:
• open (False)
• close (False)
• _autoplot (True)
• level1 (0.382)
• level2 (0.618)
• level3 (1.0)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (False)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• r1:
• r2:
• r3:
• s3:
• s2:
• s1:
• p:
625
backtrader’s documentation Version-1.9.58.122
FindFirstIndex
Returns the index of the last data that satisfies equality with the condition
generated by the parameter _evalfunc
Note:
Returned indexes look backwards. 0 is the current index and 1 is the previous bar.
Formula:
Lines:
• index
Params:
• period (1)
• _evalfunc (None)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (True)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• index:
626
backtrader’s documentation Version-1.9.58.122
FindFirstIndexHighest
Returns the index of the first data that is the highest in the period
Note:
Returned indexes look backwards. 0 is the current index and 1 is the previous bar.
Formula:
Lines:
• index
Params:
• period (1)
• _evalfunc (<built-in function max>)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (True)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• index:
FindFirstIndexLowest
Returns the index of the first data that is the lowest in the period
627
backtrader’s documentation Version-1.9.58.122
Note:
Returned indexes look backwards. 0 is the current index and 1 is the previous bar.
Formula:
Lines:
• index
Params:
• period (1)
• _evalfunc (<built-in function min>)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (True)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• index:
FindLastIndex
Returns the index of the last data that satisfies equality with the condition
generated by the parameter _evalfunc
Note:
Returned indexes look backwards. 0 is the current index and 1 is the previous bar.
Formula:
628
backtrader’s documentation Version-1.9.58.122
Lines:
• index
Params:
• period (1)
• _evalfunc (None)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (True)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• index:
FindLastIndexHighest
Returns the index of the last data that is the highest in the period
Note:
Returned indexes look backwards. 0 is the current index and 1 is the previous bar.
Formula:
Lines:
629
backtrader’s documentation Version-1.9.58.122
• index
Params:
• period (1)
• _evalfunc (<built-in function max>)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (True)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• index:
FindLastIndexLowest
Returns the index of the last data that is the lowest in the period
Note:
Returned indexes look backwards. 0 is the current index and 1 is the previous bar.
Formula:
Lines:
• index
Params:
630
backtrader’s documentation Version-1.9.58.122
• period (1)
• _evalfunc (<built-in function min>)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (True)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• index:
Fractal
References:
[Ref 1] http://www.investopedia.com/articles/trading/06/fractals.asp
Lines:
• fractal_bearish
• fractal_bullish
Params:
• period (5)
• bardist (0.015)
• shift_to_potential_fractal (2)
PlotInfo:
• plot (True)
• legendloc (None)
631
backtrader’s documentation Version-1.9.58.122
• plotmaster (None)
• subplot (False)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
HeikinAshi
Formula:
ha_open = (ha_open(-1) + ha_close(-1)) / 2 ha_high = max(hi, ha_open, ha_close) ha_low = min(lo, ha_open,
ha_close) ha_close = (open + high + low + close) / 4
See also:
https://en.wikipedia.org/wiki/Candlestick_chart#Heikin_Ashi_candlesticks
http://stockcharts.com/school/doku.php?id=chart_school:chart_analysis:heikin_ashi
Lines:
• ha_open
• ha_high
• ha_low
• ha_close
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (False)
• plotvaluetags (True)
• plotskip (False)
632
backtrader’s documentation Version-1.9.58.122
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• ha_close:
• ha_open:
• ha_low:
• ha_high:
Highest
Alias:
• MaxN
Formula:
Lines:
• highest
Params:
• period (1)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (True)
633
backtrader’s documentation Version-1.9.58.122
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• highest:
HullMovingAverage
Alias:
• HMA, HullMA
By Alan Hull
The Hull Moving Average solves the age old dilemma of making a moving average
more responsive to current price activity whilst maintaining curve smoothness. In
fact the HMA almost eliminates lag altogether and manages to improve smoothing at
the same time.
Formula:
See also:
• http://alanhull.com/hull-moving-average
Note:
• Please note that the final minimum period is not the period passed with the
parameter period. A final moving average on moving average is done in which
the period is the square root of the original.
In the default case of 30 the final minimum period before the moving
average produces a non-NAN value is 34
634
backtrader’s documentation Version-1.9.58.122
Lines:
• hma
Params:
• period (30)
• _movav (WMA)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (False)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• hma:
HullMovingAverageEnvelope
Alias:
• HMAEnvelope, HullMAEnvelope
Formula:
635
backtrader’s documentation Version-1.9.58.122
See also:
• http://stockcharts.com/school/doku.php?id=chart_school:technical_indicators:moving_average_
envelopes
Lines:
• hma
• top
• bot
Params:
• period (30)
• _movav (WMA)
• perc (2.5)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (False)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• hma:
• top: - _samecolor (True)
• bot: - _samecolor (True)
HullMovingAverageOscillator
Alias:
636
backtrader’s documentation Version-1.9.58.122
Lines:
• hma
Params:
• period (30)
• _movav (WMA)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (True)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• hma:
• _0: - _name (osc)
HurstExponent
Alias:
• Hurst
References:
• https://www.quantopian.com/posts/hurst-exponent
637
backtrader’s documentation Version-1.9.58.122
• https://www.quantopian.com/posts/some-code-from-ernie-chans-new-book-implemented-in-
python
Important notes:
• The default period is 40, but experimentation by users has shown that it
would be advisable to have at least 2000 samples (i.e.: a period of at
least 2000) to have stable values.
• The lag_start and lag_end values will default to be 2 and self.p.period / 2
unless the parameters are specified.
Experimentation by users has also shown that values of around 10 and 500
produce good results
Lines:
• hurst
Params:
• period (40)
• lag_start (None)
• lag_end (None)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (True)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
638
backtrader’s documentation Version-1.9.58.122
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• hurst:
Ichimoku
Formula:
• chikou = close
See:
• http://stockcharts.com/school/doku.php?id=chart_school:technical_indicators:ichimoku_cloud
Lines:
• tenkan_sen
• kijun_sen
• senkou_span_a
• senkou_span_b
• chikou_span
Params:
• tenkan (9)
• kijun (26)
639
backtrader’s documentation Version-1.9.58.122
• senkou (52)
• senkou_lead (26)
• chikou (26)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (False)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
KnowSureThing
Alias:
• KST
Formula:
640
backtrader’s documentation Version-1.9.58.122
See:
• http://stockcharts.com/school/doku.php?id=chart_school:technical_indicators:know_sure_thing
_kst
Params
Lines:
• kst
• signal
Params:
• rp1 (10)
• rp2 (15)
• rp3 (20)
• rp4 (30)
• rma1 (10)
• rma2 (10)
• rma3 (10)
• rma4 (10)
• rsignal (9)
• rfactors ([1.0, 2.0, 3.0, 4.0])
• _rmovav (SMA)
• _smovav (SMA)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (True)
• plotvaluetags (True)
641
backtrader’s documentation Version-1.9.58.122
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([0.0])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• kst:
• signal:
LaguerreFilter
Alias:
• LAGF
Defined by John F. Ehlers in Cybernetic Analysis for Stock and Futures, 2004,
published by Wiley. ISBN: 978-0-471-46307-8
gamma is meant to have values between 0.2 and 0.8, with the best balance found
theoretically at the default of 0.5
Lines:
• lfilter
Params:
• period (1)
• gamma (0.5)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (False)
• plotvaluetags (True)
• plotskip (False)
642
backtrader’s documentation Version-1.9.58.122
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• lfilter:
LaguerreRSI
Alias:
• LRSI
Defined by John F. Ehlers in Cybernetic Analysis for Stock and Futures, 2004,
published by Wiley. ISBN: 978-0-471-46307-8
The Laguerre RSI tries to implements a better RSI by providing a sort of Time
Warp without Time Travel using a Laguerre filter. This provides for faster
reactions to price changes
gamma is meant to have values between 0.2 and 0.8, with the best balance found
theoretically at the default of 0.5
Lines:
• lrsi
Params:
• period (6)
• gamma (0.5)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (True)
643
backtrader’s documentation Version-1.9.58.122
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.15)
• plotlinelabels (False)
• plotyticks ([0.0, 0.2, 0.5, 0.8, 1.0])
PlotLines:
• lrsi:
LinePlotterIndicator
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (True)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
Lowest
Alias:
• MinN
Formula:
Lines:
• lowest
Params:
• period (1)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (True)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• lowest:
MACD
It measures the distance of a short and a long term moving average to try to
identify the trend.
Formula:
See:
• http://en.wikipedia.org/wiki/MACD
Lines:
• macd
• signal
Params:
• period_me1 (12)
• period_me2 (26)
• period_signal (9)
• movav (ExponentialMovingAverage)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (True)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([0.0])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• signal: - ls (–)
• macd:
646
backtrader’s documentation Version-1.9.58.122
MACDHisto
Alias:
• MACDHistogram
Subclass of MACD which adds a “histogram” of the difference between the macd
and signal lines
Formula:
See:
• http://en.wikipedia.org/wiki/MACD
Lines:
• macd
• signal
• histo
Params:
• period_me1 (12)
• period_me2 (26)
• period_signal (9)
• movav (ExponentialMovingAverage)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (True)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([0.0])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
647
backtrader’s documentation Version-1.9.58.122
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• signal: - ls (–)
• macd:
• histo: - width (1.0) - alpha (0.5) - _method (bar)
MeanDeviation
Alias:
• MeanDev
Calculates the Mean Deviation of the passed data for a given period
Note:
• If 2 datas are provided as parameters, the 2nd is considered to be the mean of the first
Formula:
See:
• https://en.wikipedia.org/wiki/Average_absolute_deviation
Lines:
• meandev
Params:
• period (20)
• movav (MovingAverageSimple)
PlotInfo:
• plot (True)
648
backtrader’s documentation Version-1.9.58.122
• legendloc (None)
• plotmaster (None)
• subplot (True)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• meandev:
MinusDirectionalIndicator
Alias:
• MinusDI
Defined by J. Welles Wilder, Jr. in 1978 in his book “New Concepts in Technical
Trading Systems”.
Formula:
649
backtrader’s documentation Version-1.9.58.122
The moving average used is the one originally defined by Wilder, the
SmoothedMovingAverage
See:
• https://en.wikipedia.org/wiki/Average_directional_movement_index
Lines:
• minusDI
Params:
• period (14)
• movav (SmoothedMovingAverage)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (True)
• plotvaluetags (True)
• plotskip (False)
• plotname (-DirectionalIndicator)
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• minusDI:
• plusDI: - _name (+DI)
Momentum
Measures the change in price by calculating the difference between the current
price and the price from a given period ago
650
backtrader’s documentation Version-1.9.58.122
Formula:
See:
• http://en.wikipedia.org/wiki/Momentum_(technical_analysis)
Lines:
• momentum
Params:
• period (12)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (True)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([0.0])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• momentum:
MomentumOscillator
Alias:
• MomentumOsc
Formula:
See:
• http://ta.mql4.com/indicators/oscillators/momentum
Lines:
• momosc
Params:
• period (12)
• band (100.0)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (True)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• momosc:
MovingAverageBase
Params:
• period (30)
652
backtrader’s documentation Version-1.9.58.122
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (False)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
MovingAverageSimple
Alias:
• SMA, SimpleMovingAverage
Formula:
See also:
• http://en.wikipedia.org/wiki/Moving_average#Simple_moving_average
Lines:
• sma
Params:
• period (30)
PlotInfo:
• plot (True)
653
backtrader’s documentation Version-1.9.58.122
• legendloc (None)
• plotmaster (None)
• subplot (False)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• sma:
MovingAverageSimpleEnvelope
Alias:
• SMAEnvelope, SimpleMovingAverageEnvelope
Formula:
See also:
• http://stockcharts.com/school/doku.php?id=chart_school:technical_indicators:moving_average_
envelopes
Lines:
• sma
• top
• bot
Params:
654
backtrader’s documentation Version-1.9.58.122
• period (30)
• perc (2.5)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (False)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• sma:
• top: - _samecolor (True)
• bot: - _samecolor (True)
MovingAverageSimpleOscillator
Alias:
Lines:
• sma
Params:
• period (30)
PlotInfo:
655
backtrader’s documentation Version-1.9.58.122
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (True)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• sma:
• _0: - _name (osc)
OLS_BetaN
Uses pandas
Lines:
• beta
Params:
• period (10)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (True)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
656
backtrader’s documentation Version-1.9.58.122
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• beta:
OLS_Slope_InterceptN
Lines:
• slope
• intercept
Params:
• period (10)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (True)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
657
backtrader’s documentation Version-1.9.58.122
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• slope:
• intercept:
OLS_TransformationN
Calculates the zscore for data0 and data1. Although it doesn’t directly uses any
external package it relies on OLS_SlopeInterceptN which uses pandas and
statsmodels
Lines:
• spread
• spread_mean
• spread_std
• zscore
Params:
• period (10)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (True)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
658
backtrader’s documentation Version-1.9.58.122
• spread_mean:
• spread_std:
• zscore:
• spread:
OperationN
Serves as a base for classes that work with a period and can express the logic in
a callable object
Note:
Base classes must provide a “func” attribute which is a callable
Formula:
Params:
• period (1)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (True)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
Oscillator
659
backtrader’s documentation Version-1.9.58.122
Datas:
The calculated oscillation will be that of the Moving Average (in the
example) around the data that was used for the average calculation
Formula:
Lines:
• osc
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (True)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• osc:
• _0: - _name (osc)
660
backtrader’s documentation Version-1.9.58.122
OscillatorMixIn
MixIn class to create a subclass with another indicator. The main line of that
indicator will be substracted from the other base class main line creating an
oscillator
Formula:
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (True)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
ParabolicSAR
Alias:
• PSAR
661
backtrader’s documentation Version-1.9.58.122
Defined by J. Welles Wilder, Jr. in 1978 in his book “New Concepts in Technical
Trading Systems” for the RSI
SAR stands for Stop and Reverse and the indicator was meant as a signal for entry
(and reverse)
How to select the 1st signal is left unspecified in the book and the
increase/derease of bars
See:
• https://en.wikipedia.org/wiki/Parabolic_SAR
• http://stockcharts.com/school/doku.php?id=chart_school:technical_indicators:parabolic_sar
Lines:
• psar
Params:
• period (2)
• af (0.02)
• afmax (0.2)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (False)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
662
backtrader’s documentation Version-1.9.58.122
PercentChange
Alias:
• PctChange
Measures the perccentage change of the current value with respect to that of
period bars ago
Lines:
• pctchange
Params:
• period (30)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (True)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
PercentRank
Alias:
• PctRank
663
backtrader’s documentation Version-1.9.58.122
Measures the percent rank of the current value with respect to that of period
bars ago
Lines:
• pctrank
Params:
• period (50)
• func (<function <lambda> at 0x00000000054FB908>)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (True)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• pctrank:
PercentagePriceOscillator
Alias:
• PPO, PercPriceOsc
Shows the difference between a short and long exponential moving averages
expressed in percentage. The MACD does the same but expressed in absolute points.
664
backtrader’s documentation Version-1.9.58.122
Formula:
See:
• http://stockcharts.com/school/doku.php?id=chart_school:technical_indicators:price_oscillators_
ppo
Lines:
• ppo
• signal
• histo
Params:
• period1 (12)
• period2 (26)
• _movav (ExponentialMovingAverage)
• period_signal (9)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (True)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([0.0])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
665
backtrader’s documentation Version-1.9.58.122
• signal:
• ppo:
• histo: - width (1.0) - alpha (0.5) - _method (bar)
PercentagePriceOscillatorShort
Alias:
• PPOShort, PercPriceOscShort
Shows the difference between a short and long exponential moving averages
expressed in percentage. The MACD does the same but expressed in absolute points.
Most on-line literature shows the percentage calculation having the long
exponential moving average as the denominator. Some sources like MetaStock use
the short one.
Formula:
See:
• http://www.metastock.com/Customer/Resources/TAAZ/?c=3&p=94
Lines:
• ppo
• signal
• histo
Params:
• period1 (12)
• period2 (26)
• _movav (ExponentialMovingAverage)
• period_signal (9)
PlotInfo:
• plot (True)
666
backtrader’s documentation Version-1.9.58.122
• legendloc (None)
• plotmaster (None)
• subplot (True)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([0.0])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• signal:
• ppo:
• histo: - width (1.0) - alpha (0.5) - _method (bar)
PeriodN
Base class for indicators which take a period (__init__ has to be called either
via super or explicitly)
Params:
• period (1)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (True)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
667
backtrader’s documentation Version-1.9.58.122
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PivotPoint
Defines a level of significance by taking into account the average of price bar
componentes of the past period of a larget timeframe. For example when operating
with days, the values are taking from the already “past” month fixed prices.
The indicator will try to automatically plo to the non-resampled data. To disable
this behavior use the following during construction:
• _autoplot=False
Note:
The example shows days and months, but any combination of timeframes can be used. See the literature for
recommended combinations
Formula:
See:
• http://stockcharts.com/school/doku.php?id=chart_school:technical_indicators:pivot_points
• https://en.wikipedia.org/wiki/Pivot_point_(technical_analysis)
Lines:
668
backtrader’s documentation Version-1.9.58.122
• p
• s1
• s2
• r1
• r2
Params:
• open (False)
• close (False)
• _autoplot (True)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (False)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• p:
• s1:
• r1:
• r2:
• s2:
PlusDirectionalIndicator
Alias:
• PlusDI
669
backtrader’s documentation Version-1.9.58.122
Defined by J. Welles Wilder, Jr. in 1978 in his book “New Concepts in Technical
Trading Systems”.
Formula:
The moving average used is the one originally defined by Wilder, the
SmoothedMovingAverage
See:
• https://en.wikipedia.org/wiki/Average_directional_movement_index
Lines:
• plusDI
Params:
• period (14)
• movav (SmoothedMovingAverage)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (True)
• plotvaluetags (True)
• plotskip (False)
• plotname (+DirectionalIndicator)
670
backtrader’s documentation Version-1.9.58.122
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
PrettyGoodOscillator
Alias:
• PGO, PrettyGoodOsc
The “Pretty Good Oscillator” (PGO) by Mark Johnson measures the distance of the
current close from its simple moving average of period Average), expressed in
terms of an average true range (see Average True Range) over a similar period.
So for instance a PGO value of +2.5 would mean the current close is 2.5 average
days’ range above the SMA.
Johnson’s approach was to use it as a breakout system for longer term trades. If
the PGO rises above 3.0 then go long, or below -3.0 then go short, and in both
cases exit on returning to zero (which is a close back at the SMA).
Formula:
See also:
• http://user42.tuxfamily.org/chart/manual/Pretty-Good-Oscillator.html
Lines:
• pgo
Params:
671
backtrader’s documentation Version-1.9.58.122
• period (14)
• _movav (MovingAverageSimple)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (True)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• pgo:
PriceOscillator
Alias:
Shows the difference between a short and long exponential moving averages
expressed in points.
Formula:
• po = ema(short) - ema(long)
See:
• http://www.metastock.com/Customer/Resources/TAAZ/?c=3&p=94
Lines:
• po
672
backtrader’s documentation Version-1.9.58.122
Params:
• period1 (12)
• period2 (26)
• _movav (ExponentialMovingAverage)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (True)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([0.0])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• po:
RSI_EMA
See:
• http://en.wikipedia.org/wiki/Relative_strength_index
Lines:
• rsi
Params:
• period (14)
• movav (ExponentialMovingAverage)
• upperband (70.0)
673
backtrader’s documentation Version-1.9.58.122
• lowerband (30.0)
• safediv (False)
• safehigh (100.0)
• safelow (50.0)
• lookback (1)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (True)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• rsi:
RSI_SMA
Alias:
• RSI_Cutler
See:
• http://en.wikipedia.org/wiki/Relative_strength_index
Lines:
• rsi
Params:
674
backtrader’s documentation Version-1.9.58.122
• period (14)
• movav (MovingAverageSimple)
• upperband (70.0)
• lowerband (30.0)
• safediv (False)
• safehigh (100.0)
• safelow (50.0)
• lookback (1)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (True)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• rsi:
RSI_Safe
Subclass of RSI which changes parameers safediv to True as the default value
See:
• http://en.wikipedia.org/wiki/Relative_strength_index
Lines:
• rsi
Params:
675
backtrader’s documentation Version-1.9.58.122
• period (14)
• movav (SmoothedMovingAverage)
• upperband (70.0)
• lowerband (30.0)
• safediv (True)
• safehigh (100.0)
• safelow (50.0)
• lookback (1)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (True)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• rsi:
RateOfChange
Alias:
• ROC
Formula:
See:
676
backtrader’s documentation Version-1.9.58.122
• http://en.wikipedia.org/wiki/Momentum_(technical_analysis)
Lines:
• roc
Params:
• period (12)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (True)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• roc:
RateOfChange100
Alias:
• ROC100
Measures the ratio of change in prices over a period with base 100
Formula:
See:
• http://stockcharts.com/school/doku.php?id=chart_school:technical_indicators:rate_of_change_r
oc_and_momentum
Lines:
• roc100
Params:
• period (12)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (True)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• roc100:
ReduceN
Calculates the Reduced value of the period data points applying function
Uses the built-in reduce for the calculation plus the func that subclassess
define
Formula:
Notes:
• In order to mimic the python reduce, this indicator takes a function non-named argument as the 1st
argument, unlike other Indicators which take only named arguments
Lines:
• reduced
Params:
• period (1)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (True)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• reduced:
RelativeMomentumIndex
Alias:
• RMI
Description: The Relative Momentum Index was developed by Roger Altman and was
introduced in his article in the February, 1993 issue of Technical Analysis of
Stocks & Commodities magazine.
679
backtrader’s documentation Version-1.9.58.122
While your typical RSI counts up and down days from close to close, the Relative
Momentum Index counts up and down days from the close relative to a close x
number of days ago. The result is an RSI that is a bit smoother.
Usage: Use in the same way you would any other RSI . There are overbought and
oversold zones, and can also be used for divergence and trend analysis.
See:
• https://www.marketvolume.com/technicalanalysis/relativemomentumindex.asp
• https://www.tradingview.com/script/UCm7fIvk-FREE-INDICATOR-Relative-Momentum-Index-
RMI/
• https://www.prorealcode.com/prorealtime-indicators/relative-momentum-index-rmi/
Lines:
• rsi
Params:
• period (20)
• movav (SmoothedMovingAverage)
• upperband (70.0)
• lowerband (30.0)
• safediv (False)
• safehigh (100.0)
• safelow (50.0)
• lookback (5)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (True)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
680
backtrader’s documentation Version-1.9.58.122
• plotyticks ([])
PlotLines:
RelativeStrengthIndex
Alias:
Defined by J. Welles Wilder, Jr. in 1978 in his book “New Concepts in Technical
Trading Systems”.
It measures momentum by calculating the ration of higher closes and lower closes
after having been smoothed by an average, normalizing the result between 0 and
100
Formula:
• up = upday(data)
• down = downday(data)
• maup = movingaverage(up, period)
• madown = movingaverage(down, period)
• rs = maup / madown
• rsi = 100 - 100 / (1 + rs)
The moving average used is the one originally defined by Wilder, the
SmoothedMovingAverage
See:
• http://en.wikipedia.org/wiki/Relative_strength_index
Notes:
• safediv (default: False) If this parameter is True the division rs = maup / madown will be checked
for the special cases in which a 0 / 0 or x / 0 division will happen
• safehigh (default: 100.0) will be used as RSI value for the x / 0 case
• safelow (default: 50.0) will be used as RSI value for the 0 / 0 case
Lines:
• rsi
681
backtrader’s documentation Version-1.9.58.122
Params:
• period (14)
• movav (SmoothedMovingAverage)
• upperband (70.0)
• lowerband (30.0)
• safediv (False)
• safehigh (100.0)
• safelow (50.0)
• lookback (1)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (True)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• rsi:
Signal
Lines:
• signal
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
682
backtrader’s documentation Version-1.9.58.122
• subplot (True)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• signal:
SmoothedMovingAverage
Alias:
Smoothing Moving Average used by Wilder in his 1978 book New Concepts in
Technical Trading
Formula:
See also:
• http://en.wikipedia.org/wiki/Moving_average#Modified_moving_average
Lines:
683
backtrader’s documentation Version-1.9.58.122
• smma
Params:
• period (30)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (False)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• smma:
SmoothedMovingAverageEnvelope
Alias:
Formula:
See also:
684
backtrader’s documentation Version-1.9.58.122
• http://stockcharts.com/school/doku.php?id=chart_school:technical_indicators:moving_average_
envelopes
Lines:
• smma
• top
• bot
Params:
• period (30)
• perc (2.5)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (False)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• smma:
• top: - _samecolor (True)
• bot: - _samecolor (True)
SmoothedMovingAverageOscillator
Alias:
685
backtrader’s documentation Version-1.9.58.122
Lines:
• smma
Params:
• period (30)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (True)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• smma:
• _0: - _name (osc)
StandardDeviation
Alias:
• StdDev
Calculates the standard deviation of the passed data for a given period
Note:
686
backtrader’s documentation Version-1.9.58.122
• If 2 datas are provided as parameters, the 2nd is considered to be the mean of the first
• safepow (default: False) If this parameter is True, the standard deviation will be calculated as
pow(abs(meansq - sqmean), 0.5) to safe guard for possible negative results of meansq - sqmean
caused by the floating point representation.
Formula:
See:
• http://en.wikipedia.org/wiki/Standard_deviation
Lines:
• stddev
Params:
• period (20)
• movav (MovingAverageSimple)
• safepow (True)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (True)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• stddev:
687
backtrader’s documentation Version-1.9.58.122
Stochastic
Alias:
• StochasticSlow
The regular (or slow version) adds an additional moving average layer and thus:
Formula:
• k=k
• d=d
• d = MovingAverage(d, period_dslow)
See:
• http://en.wikipedia.org/wiki/Stochastic_oscillator
Lines:
• percK
• percD
Params:
• period (14)
• period_dfast (3)
• movav (MovingAverageSimple)
• upperband (80.0)
• lowerband (20.0)
• safediv (False)
• safezero (0.0)
• period_dslow (3)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (True)
• plotvaluetags (True)
• plotskip (False)
688
backtrader’s documentation Version-1.9.58.122
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
StochasticFast
By Dr. George Lane in the 50s. It compares a closing price to the price range and
tries to show convergence if the closing prices are close to the extremes
It shows divergence if the extremes keep on growign but closing prices do not in
the same manner (distance to the extremes grow)
Formula:
• hh = highest(data.high, period)
• ll = lowest(data.low, period)
• knum = data.close - ll
• kden = hh - ll
• k = 100 * (knum / kden)
• d = MovingAverage(k, period_dfast)
See:
• http://en.wikipedia.org/wiki/Stochastic_oscillator
Lines:
• percK
• percD
Params:
689
backtrader’s documentation Version-1.9.58.122
• period (14)
• period_dfast (3)
• movav (MovingAverageSimple)
• upperband (80.0)
• lowerband (20.0)
• safediv (False)
• safezero (0.0)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (True)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
StochasticFull
• percK
• percD
• percSlow
Formula:
• k=d
• d = MovingAverage(k, period_dslow)
• dslow =
690
backtrader’s documentation Version-1.9.58.122
See:
• http://en.wikipedia.org/wiki/Stochastic_oscillator
Lines:
• percK
• percD
• percDSlow
Params:
• period (14)
• period_dfast (3)
• movav (MovingAverageSimple)
• upperband (80.0)
• lowerband (20.0)
• safediv (False)
• safezero (0.0)
• period_dslow (3)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (True)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
691
backtrader’s documentation Version-1.9.58.122
SumN
Uses math.fsum for the calculation rather than the built-in sum to avoid
precision errors
Formula:
Lines:
• sumn
Params:
• period (1)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (True)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• sumn:
TripleExponentialMovingAverage
Alias:
692
backtrader’s documentation Version-1.9.58.122
• TEMA, MovingAverageTripleExponential
TEMA was first time introduced in 1994, in the article “Smoothing Data with
Faster Moving Averages” by Patrick G. Mulloy in “Technical Analysis of Stocks &
Commodities” magazine.
Formula:
See:
(None)
Lines:
• tema
Params:
• period (30)
• _movav (EMA)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (False)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
693
backtrader’s documentation Version-1.9.58.122
• tema:
TripleExponentialMovingAverageEnvelope
Alias:
• TEMAEnvelope, MovingAverageTripleExponentialEnvelope
Formula:
See also:
• http://stockcharts.com/school/doku.php?id=chart_school:technical_indicators:moving_average_
envelopes
Lines:
• tema
• top
• bot
Params:
• period (30)
• _movav (EMA)
• perc (2.5)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (False)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
694
backtrader’s documentation Version-1.9.58.122
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• tema:
• top: - _samecolor (True)
• bot: - _samecolor (True)
TripleExponentialMovingAverageOscillator
Alias:
Lines:
• tema
Params:
• period (30)
• _movav (EMA)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (True)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
695
backtrader’s documentation Version-1.9.58.122
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• tema:
• _0: - _name (osc)
Trix
Alias:
• TRIX
Defined by Jack Hutson in the 80s and shows the Rate of Change (%) or slope of a
triple exponentially smoothed moving average
Formula:
The moving average used is the one originally defined by Wilder, the
SmoothedMovingAverage
See:
• https://en.wikipedia.org/wiki/Trix_(technical_analysis)
• http://stockcharts.com/school/doku.php?id=chart_school:technical_indicators:trix
Lines:
• trix
Params:
• period (15)
• _rocperiod (1)
• _movav (EMA)
PlotInfo:
696
backtrader’s documentation Version-1.9.58.122
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (True)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([0.0])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• trix:
TrixSignal
Formula:
See:
• http://stockcharts.com/school/doku.php?id=chart_school:technical_indicators:trix
Lines:
• trix
• signal
Params:
• period (15)
• _rocperiod (1)
• _movav (EMA)
• sigperiod (9)
697
backtrader’s documentation Version-1.9.58.122
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (True)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([0.0])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• trix:
• signal:
TrueHigh
Defined by J. Welles Wilder, Jr. in 1978 in his book “New Concepts in Technical
Trading Systems” for the ATR
Records the “true high” which is the maximum of today’s high and yesterday’s
close
Formula:
See:
• http://en.wikipedia.org/wiki/Average_true_range
Lines:
• truehigh
PlotInfo:
698
backtrader’s documentation Version-1.9.58.122
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (True)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• truehigh:
TrueLow
Defined by J. Welles Wilder, Jr. in 1978 in his book “New Concepts in Technical
Trading Systems” for the ATR
Records the “true high” which is the maximum of today’s high and yesterday’s
close
Formula:
See:
• http://en.wikipedia.org/wiki/Average_true_range
Lines:
• truelow
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
699
backtrader’s documentation Version-1.9.58.122
• subplot (True)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• truelow:
TrueRange
Alias:
• TR
Defined by J. Welles Wilder, Jr. in 1978 in his book New Concepts in Technical
Trading Systems.
Formula:
See:
• http://en.wikipedia.org/wiki/Average_true_range
The idea is to take the previous close into account to calculate the range if it
yields a larger range than the daily range (High - Low)
Lines:
• tr
700
backtrader’s documentation Version-1.9.58.122
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (True)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• tr:
TrueStrengthIndicator
Alias:
• TSI
The True Strength Indicators was first introduced in Stocks & Commodities
Magazine by its author William Blau. It measures momentum with a double
exponential (default) of the prices.
It shows divergence if the extremes keep on growign but closing prices do not in
the same manner (distance to the extremes grow)
Formula:
701
backtrader’s documentation Version-1.9.58.122
See:
• http://stockcharts.com/school/doku.php?id=chart_school:technical_indicators:true_strength_ind
ex
Params
Lines:
• tsi
Params:
• period1 (25)
• period2 (13)
• pchange (1)
• _movav (EMA)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (True)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• tsi:
702
backtrader’s documentation Version-1.9.58.122
UltimateOscillator
Formula:
See:
• https://en.wikipedia.org/wiki/Ultimate_oscillator
• http://stockcharts.com/school/doku.php?id=chart_school:technical_indicators:ultimate_oscillator
Lines:
• uo
Params:
• p1 (7)
• p2 (14)
• p3 (28)
• upperband (70.0)
• lowerband (30.0)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (True)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
703
backtrader’s documentation Version-1.9.58.122
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• uo:
UpDay
Defined by J. Welles Wilder, Jr. in 1978 in his book “New Concepts in Technical
Trading Systems” for the RSI
Recods days which have been “up”, i.e.: the close price has been higher than
the day before.
Formula:
See:
• http://en.wikipedia.org/wiki/Relative_strength_index
Lines:
• upday
Params:
• period (1)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (True)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
704
backtrader’s documentation Version-1.9.58.122
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• upday:
UpDayBool
Defined by J. Welles Wilder, Jr. in 1978 in his book “New Concepts in Technical
Trading Systems” for the RSI
Recods days which have been “up”, i.e.: the close price has been higher than
the day before.
Note:
Formula:
See:
• http://en.wikipedia.org/wiki/Relative_strength_index
Lines:
• upday
Params:
• period (1)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (True)
705
backtrader’s documentation Version-1.9.58.122
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• upday:
UpMove
Defined by J. Welles Wilder, Jr. in 1978 in his book “New Concepts in Technical
Trading Systems” as part of the Directional Move System to calculate Directional
Indicators.
Positive if the given data has moved higher than the previous day
Formula:
See:
• https://en.wikipedia.org/wiki/Average_directional_movement_index
Lines:
• upmove
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (True)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
706
backtrader’s documentation Version-1.9.58.122
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• upmove:
Vortex
See:
• http://www.vortexindicator.com/VFX_VORTEX.PDF
Lines:
• vi_plus
• vi_minus
Params:
• period (14)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (True)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
707
backtrader’s documentation Version-1.9.58.122
• plotyticks ([])
PlotLines:
WeightedAverage
Alias:
• AverageWeighted
The default weights (if none are provided) are linear to assigne more weight to
the most recent data
Formula:
See:
• https://en.wikipedia.org/wiki/Weighted_arithmetic_mean
Lines:
• av
Params:
• period (1)
• coef (1.0)
• weights (())
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (True)
• plotvaluetags (True)
708
backtrader’s documentation Version-1.9.58.122
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• av:
WeightedMovingAverage
Alias:
• WMA, MovingAverageWeighted
A Moving Average which gives an arithmetic weighting to values with the newest
having the more weight
Formula:
See also:
• http://en.wikipedia.org/wiki/Moving_average#Weighted_moving_average
Lines:
• wma
Params:
• period (30)
PlotInfo:
• plot (True)
709
backtrader’s documentation Version-1.9.58.122
• legendloc (None)
• plotmaster (None)
• subplot (False)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• wma:
WeightedMovingAverageEnvelope
Alias:
• WMAEnvelope, MovingAverageWeightedEnvelope
Formula:
See also:
• http://stockcharts.com/school/doku.php?id=chart_school:technical_indicators:moving_average_
envelopes
Lines:
• wma
• top
• bot
Params:
710
backtrader’s documentation Version-1.9.58.122
• period (30)
• perc (2.5)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (False)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• wma:
• top: - _samecolor (True)
• bot: - _samecolor (True)
WeightedMovingAverageOscillator
Alias:
Lines:
• wma
Params:
• period (30)
PlotInfo:
711
backtrader’s documentation Version-1.9.58.122
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (True)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• wma:
• _0: - _name (osc)
WilliamsAD
See: - http://www.metastock.com/Customer/Resources/TAAZ/?p=125 -
http://ta.mql4.com/indicators/trends/williams_accumulation_distribution
Lines:
• ad
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (True)
• plotvaluetags (True)
712
backtrader’s documentation Version-1.9.58.122
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• ad:
WilliamsR
Formula:
See:
• http://en.wikipedia.org/wiki/Williams_%25R
Lines:
• percR
Params:
• period (14)
• upperband (-20.0)
• lowerband (-80.0)
PlotInfo:
• plot (True)
713
backtrader’s documentation Version-1.9.58.122
• legendloc (None)
• plotmaster (None)
• subplot (True)
• plotvaluetags (True)
• plotskip (False)
• plotname (Williams R%)
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
ZeroLagExponentialMovingAverage
Alias:
• ZLEMA, ZeroLagEma
The zero-lag exponential moving average (ZLEMA) is a variation of the EMA which
adds a momentum term aiming to reduce lag in the average so as to track current
prices more closely.
Formula:
• lag = (period - 1) / 2
• zlema = ema(2 * data - data(-lag))
See also:
• http://user42.tuxfamily.org/chart/manual/Zero_002dLag-Exponential-Moving-Average.html
Lines:
• zlema
Params:
• period (30)
714
backtrader’s documentation Version-1.9.58.122
• _movav (EMA)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (False)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• zlema:
ZeroLagExponentialMovingAverageEnvelope
Alias:
• ZLEMAEnvelope, ZeroLagEmaEnvelope
Formula:
See also:
• http://stockcharts.com/school/doku.php?id=chart_school:technical_indicators:moving_average_
envelopes
Lines:
715
backtrader’s documentation Version-1.9.58.122
• zlema
• top
• bot
Params:
• period (30)
• _movav (EMA)
• perc (2.5)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (False)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• zlema:
• top: - _samecolor (True)
• bot: - _samecolor (True)
ZeroLagExponentialMovingAverageOscillator
Alias:
Lines:
716
backtrader’s documentation Version-1.9.58.122
• zlema
Params:
• period (30)
• _movav (EMA)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (True)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• zlema:
• _0: - _name (osc)
ZeroLagIndicator
Alias:
The zero-lag indicator (ZLIndicator) is a variation of the EMA which modifies the
EMA by trying to minimize the error (distance price - error correction) and thus
reduce the lag
Formula:
• EMA(data, period)
717
backtrader’s documentation Version-1.9.58.122
Note
the passed moving average must calculate alpha (and 1 - alpha) and
make them available as attributes alpha and alpha1 in the instance
See also:
• http://www.mesasoftware.com/papers/ZeroLag.pdf
Lines:
• ec
Params:
• period (30)
• gainlimit (50)
• _movav (EMA)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (False)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• ec:
718
backtrader’s documentation Version-1.9.58.122
ZeroLagIndicatorEnvelope
Alias:
Formula:
• ec (from ZeroLagIndicator)
• top = ec * (1 + perc)
• bot = ec * (1 - perc)
See also:
• http://stockcharts.com/school/doku.php?id=chart_school:technical_indicators:moving_average_
envelopes
Lines:
• ec
• top
• bot
Params:
• period (30)
• gainlimit (50)
• _movav (EMA)
• perc (2.5)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (False)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
719
backtrader’s documentation Version-1.9.58.122
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• ec:
• top: - _samecolor (True)
• bot: - _samecolor (True)
ZeroLagIndicatorOscillator
Alias:
Lines:
• ec
Params:
• period (30)
• gainlimit (50)
• _movav (EMA)
PlotInfo:
• plot (True)
• legendloc (None)
• plotmaster (None)
• subplot (True)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
720
backtrader’s documentation Version-1.9.58.122
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
• ec:
• _0: - _name (osc)
haDelta
Alias:
• haD
Heikin Ashi Delta. Defined by Dan Valcu in his book “Heikin-Ashi: How to Trade
Without Candlestick Patterns ”.
This indicator measures difference between Heikin Ashi close and open of Heikin
Ashi candles, the body of the candle.
For correct use, the data for the indicator must have been previously passed by
the Heikin Ahsi filter.
Formula:
Lines:
• haDelta
• smoothed
Params:
• period (3)
• movav (SMA)
• autoheikin (True)
PlotInfo:
• plot (True)
• legendloc (None)
721
backtrader’s documentation Version-1.9.58.122
• plotmaster (None)
• subplot (True)
• plotvaluetags (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotlinevalues (True)
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotyticks ([])
PlotLines:
ACOS
ACOS([input_arrays])
Inputs:
price: (any ndarray)
Outputs:
real
Lines:
• real
PlotInfo:
• subplot (True)
• plot (True)
• plotskip (False)
• plotname ()
722
backtrader’s documentation Version-1.9.58.122
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotmaster (None)
• plotyticks ([])
PlotLines:
• real: - ls (-)
AD
AD([input_arrays])
Inputs:
prices: [‘high’, ‘low’, ‘close’, ‘volume’]
Outputs:
real
Lines:
• real
PlotInfo:
• subplot (True)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotmaster (None)
• plotyticks ([])
PlotLines:
• real: - ls (-)
723
backtrader’s documentation Version-1.9.58.122
ADD
ADD([input_arrays])
Inputs:
price0: (any ndarray) price1: (any ndarray)
Outputs:
real
Lines:
• real
PlotInfo:
• subplot (True)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotmaster (None)
• plotyticks ([])
PlotLines:
• real: - ls (-)
ADOSC
Inputs:
prices: [‘high’, ‘low’, ‘close’, ‘volume’]
Parameters:
fastperiod: 3 slowperiod: 10
Outputs:
real
Lines:
724
backtrader’s documentation Version-1.9.58.122
• real
Params:
• fastperiod (3)
• slowperiod (10)
PlotInfo:
• subplot (True)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotmaster (None)
• plotyticks ([])
PlotLines:
• real: - ls (-)
ADX
ADX([input_arrays], [timeperiod=14])
Inputs:
prices: [‘high’, ‘low’, ‘close’]
Parameters:
timeperiod: 14
Outputs:
real
Lines:
• real
Params:
• timeperiod (14)
725
backtrader’s documentation Version-1.9.58.122
PlotInfo:
• subplot (True)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotmaster (None)
• plotyticks ([])
PlotLines:
• real: - ls (-)
ADXR
ADXR([input_arrays], [timeperiod=14])
Inputs:
prices: [‘high’, ‘low’, ‘close’]
Parameters:
timeperiod: 14
Outputs:
real
Lines:
• real
Params:
• timeperiod (14)
PlotInfo:
• subplot (True)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
726
backtrader’s documentation Version-1.9.58.122
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotmaster (None)
• plotyticks ([])
PlotLines:
• real: - ls (-)
APO
Inputs:
price: (any ndarray)
Parameters:
fastperiod: 12 slowperiod: 26 matype: 0 (Simple Moving Average)
Outputs:
real
Lines:
• real
Params:
• fastperiod (12)
• slowperiod (26)
• matype (0)
PlotInfo:
• subplot (True)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
727
backtrader’s documentation Version-1.9.58.122
• plotlinelabels (False)
• plotmaster (None)
• plotyticks ([])
PlotLines:
• real: - ls (-)
AROON
AROON([input_arrays], [timeperiod=14])
Inputs:
prices: [‘high’, ‘low’]
Parameters:
timeperiod: 14
Outputs:
aroondown aroonup
Lines:
• aroondown
• aroonup
Params:
• timeperiod (14)
PlotInfo:
• subplot (True)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotmaster (None)
• plotyticks ([])
PlotLines:
728
backtrader’s documentation Version-1.9.58.122
• aroondown: - ls (–)
• aroonup: - ls (-)
AROONOSC
AROONOSC([input_arrays], [timeperiod=14])
Inputs:
prices: [‘high’, ‘low’]
Parameters:
timeperiod: 14
Outputs:
real
Lines:
• real
Params:
• timeperiod (14)
PlotInfo:
• subplot (True)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotmaster (None)
• plotyticks ([])
PlotLines:
• real: - ls (-)
ASIN
ASIN([input_arrays])
729
backtrader’s documentation Version-1.9.58.122
Inputs:
price: (any ndarray)
Outputs:
real
Lines:
• real
PlotInfo:
• subplot (True)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotmaster (None)
• plotyticks ([])
PlotLines:
• real: - ls (-)
ATAN
ATAN([input_arrays])
Inputs:
price: (any ndarray)
Outputs:
real
Lines:
• real
PlotInfo:
• subplot (True)
730
backtrader’s documentation Version-1.9.58.122
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotmaster (None)
• plotyticks ([])
PlotLines:
• real: - ls (-)
ATR
ATR([input_arrays], [timeperiod=14])
Inputs:
prices: [‘high’, ‘low’, ‘close’]
Parameters:
timeperiod: 14
Outputs:
real
Lines:
• real
Params:
• timeperiod (14)
PlotInfo:
• subplot (True)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
731
backtrader’s documentation Version-1.9.58.122
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotmaster (None)
• plotyticks ([])
PlotLines:
• real: - ls (-)
AVGPRICE
AVGPRICE([input_arrays])
Inputs:
prices: [‘open’, ‘high’, ‘low’, ‘close’]
Outputs:
real
Lines:
• real
PlotInfo:
• subplot (False)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotmaster (None)
• plotyticks ([])
PlotLines:
• real: - ls (-)
BBANDS
Inputs:
price: (any ndarray)
Parameters:
timeperiod: 5 nbdevup: 2 nbdevdn: 2 matype: 0 (Simple Moving Average)
Outputs:
upperband middleband lowerband
Lines:
• upperband
• middleband
• lowerband
Params:
• timeperiod (5)
• nbdevup (2)
• nbdevdn (2)
• matype (0)
PlotInfo:
• subplot (False)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotmaster (None)
• plotyticks ([])
PlotLines:
BETA
BETA([input_arrays], [timeperiod=5])
733
backtrader’s documentation Version-1.9.58.122
Inputs:
price0: (any ndarray) price1: (any ndarray)
Parameters:
timeperiod: 5
Outputs:
real
Lines:
• real
Params:
• timeperiod (5)
PlotInfo:
• subplot (True)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotmaster (None)
• plotyticks ([])
PlotLines:
• real: - ls (-)
BOP
BOP([input_arrays])
Inputs:
prices: [‘open’, ‘high’, ‘low’, ‘close’]
Outputs:
real
Lines:
734
backtrader’s documentation Version-1.9.58.122
• real
PlotInfo:
• subplot (True)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotmaster (None)
• plotyticks ([])
PlotLines:
• real: - ls (-)
CCI
CCI([input_arrays], [timeperiod=14])
Inputs:
prices: [‘high’, ‘low’, ‘close’]
Parameters:
timeperiod: 14
Outputs:
real
Lines:
• real
Params:
• timeperiod (14)
PlotInfo:
• subplot (True)
• plot (True)
• plotskip (False)
735
backtrader’s documentation Version-1.9.58.122
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotmaster (None)
• plotyticks ([])
PlotLines:
• real: - ls (-)
CDL2CROWS
CDL2CROWS([input_arrays])
Inputs:
prices: [‘open’, ‘high’, ‘low’, ‘close’]
Outputs:
integer (values are -100, 0 or 100)
Lines:
• integer
• _candleplot
PlotInfo:
• subplot (False)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (True)
• plotmaster (None)
• plotyticks ([])
PlotLines:
736
backtrader’s documentation Version-1.9.58.122
CDL3BLACKCROWS
CDL3BLACKCROWS([input_arrays])
Inputs:
prices: [‘open’, ‘high’, ‘low’, ‘close’]
Outputs:
integer (values are -100, 0 or 100)
Lines:
• integer
• _candleplot
PlotInfo:
• subplot (False)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (True)
• plotmaster (None)
• plotyticks ([])
PlotLines:
CDL3INSIDE
CDL3INSIDE([input_arrays])
Inputs:
prices: [‘open’, ‘high’, ‘low’, ‘close’]
737
backtrader’s documentation Version-1.9.58.122
Outputs:
integer (values are -100, 0 or 100)
Lines:
• integer
• _candleplot
PlotInfo:
• subplot (False)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (True)
• plotmaster (None)
• plotyticks ([])
PlotLines:
CDL3LINESTRIKE
CDL3LINESTRIKE([input_arrays])
Inputs:
prices: [‘open’, ‘high’, ‘low’, ‘close’]
Outputs:
integer (values are -100, 0 or 100)
Lines:
• integer
• _candleplot
PlotInfo:
• subplot (False)
• plot (True)
738
backtrader’s documentation Version-1.9.58.122
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (True)
• plotmaster (None)
• plotyticks ([])
PlotLines:
CDL3OUTSIDE
CDL3OUTSIDE([input_arrays])
Inputs:
prices: [‘open’, ‘high’, ‘low’, ‘close’]
Outputs:
integer (values are -100, 0 or 100)
Lines:
• integer
• _candleplot
PlotInfo:
• subplot (False)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (True)
• plotmaster (None)
• plotyticks ([])
739
backtrader’s documentation Version-1.9.58.122
PlotLines:
CDL3STARSINSOUTH
CDL3STARSINSOUTH([input_arrays])
Inputs:
prices: [‘open’, ‘high’, ‘low’, ‘close’]
Outputs:
integer (values are -100, 0 or 100)
Lines:
• integer
• _candleplot
PlotInfo:
• subplot (False)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (True)
• plotmaster (None)
• plotyticks ([])
PlotLines:
CDL3WHITESOLDIERS
CDL3WHITESOLDIERS([input_arrays])
740
backtrader’s documentation Version-1.9.58.122
Inputs:
prices: [‘open’, ‘high’, ‘low’, ‘close’]
Outputs:
integer (values are -100, 0 or 100)
Lines:
• integer
• _candleplot
PlotInfo:
• subplot (False)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (True)
• plotmaster (None)
• plotyticks ([])
PlotLines:
CDLABANDONEDBABY
CDLABANDONEDBABY([input_arrays], [penetration=0.3])
Inputs:
prices: [‘open’, ‘high’, ‘low’, ‘close’]
Parameters:
penetration: 0.3
Outputs:
integer (values are -100, 0 or 100)
Lines:
• integer
• _candleplot
741
backtrader’s documentation Version-1.9.58.122
Params:
• penetration (0.3)
PlotInfo:
• subplot (False)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (True)
• plotmaster (None)
• plotyticks ([])
PlotLines:
CDLADVANCEBLOCK
CDLADVANCEBLOCK([input_arrays])
Inputs:
prices: [‘open’, ‘high’, ‘low’, ‘close’]
Outputs:
integer (values are -100, 0 or 100)
Lines:
• integer
• _candleplot
PlotInfo:
• subplot (False)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
742
backtrader’s documentation Version-1.9.58.122
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (True)
• plotmaster (None)
• plotyticks ([])
PlotLines:
CDLBELTHOLD
CDLBELTHOLD([input_arrays])
Inputs:
prices: [‘open’, ‘high’, ‘low’, ‘close’]
Outputs:
integer (values are -100, 0 or 100)
Lines:
• integer
• _candleplot
PlotInfo:
• subplot (False)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (True)
• plotmaster (None)
• plotyticks ([])
PlotLines:
743
backtrader’s documentation Version-1.9.58.122
CDLBREAKAWAY
CDLBREAKAWAY([input_arrays])
Inputs:
prices: [‘open’, ‘high’, ‘low’, ‘close’]
Outputs:
integer (values are -100, 0 or 100)
Lines:
• integer
• _candleplot
PlotInfo:
• subplot (False)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (True)
• plotmaster (None)
• plotyticks ([])
PlotLines:
CDLCLOSINGMARUBOZU
CDLCLOSINGMARUBOZU([input_arrays])
Inputs:
prices: [‘open’, ‘high’, ‘low’, ‘close’]
744
backtrader’s documentation Version-1.9.58.122
Outputs:
integer (values are -100, 0 or 100)
Lines:
• integer
• _candleplot
PlotInfo:
• subplot (False)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (True)
• plotmaster (None)
• plotyticks ([])
PlotLines:
CDLCONCEALBABYSWALL
CDLCONCEALBABYSWALL([input_arrays])
Inputs:
prices: [‘open’, ‘high’, ‘low’, ‘close’]
Outputs:
integer (values are -100, 0 or 100)
Lines:
• integer
• _candleplot
PlotInfo:
• subplot (False)
745
backtrader’s documentation Version-1.9.58.122
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (True)
• plotmaster (None)
• plotyticks ([])
PlotLines:
CDLCOUNTERATTACK
CDLCOUNTERATTACK([input_arrays])
Inputs:
prices: [‘open’, ‘high’, ‘low’, ‘close’]
Outputs:
integer (values are -100, 0 or 100)
Lines:
• integer
• _candleplot
PlotInfo:
• subplot (False)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (True)
746
backtrader’s documentation Version-1.9.58.122
• plotmaster (None)
• plotyticks ([])
PlotLines:
CDLDARKCLOUDCOVER
CDLDARKCLOUDCOVER([input_arrays], [penetration=0.5])
Inputs:
prices: [‘open’, ‘high’, ‘low’, ‘close’]
Parameters:
penetration: 0.5
Outputs:
integer (values are -100, 0 or 100)
Lines:
• integer
• _candleplot
Params:
• penetration (0.5)
PlotInfo:
• subplot (False)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (True)
• plotmaster (None)
• plotyticks ([])
PlotLines:
747
backtrader’s documentation Version-1.9.58.122
CDLDOJI
CDLDOJI([input_arrays])
Inputs:
prices: [‘open’, ‘high’, ‘low’, ‘close’]
Outputs:
integer (values are -100, 0 or 100)
Lines:
• integer
• _candleplot
PlotInfo:
• subplot (False)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (True)
• plotmaster (None)
• plotyticks ([])
PlotLines:
CDLDOJISTAR
CDLDOJISTAR([input_arrays])
Inputs:
prices: [‘open’, ‘high’, ‘low’, ‘close’]
748
backtrader’s documentation Version-1.9.58.122
Outputs:
integer (values are -100, 0 or 100)
Lines:
• integer
• _candleplot
PlotInfo:
• subplot (False)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (True)
• plotmaster (None)
• plotyticks ([])
PlotLines:
CDLDRAGONFLYDOJI
CDLDRAGONFLYDOJI([input_arrays])
Inputs:
prices: [‘open’, ‘high’, ‘low’, ‘close’]
Outputs:
integer (values are -100, 0 or 100)
Lines:
• integer
• _candleplot
PlotInfo:
• subplot (False)
• plot (True)
749
backtrader’s documentation Version-1.9.58.122
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (True)
• plotmaster (None)
• plotyticks ([])
PlotLines:
CDLENGULFING
CDLENGULFING([input_arrays])
Inputs:
prices: [‘open’, ‘high’, ‘low’, ‘close’]
Outputs:
integer (values are -100, 0 or 100)
Lines:
• integer
• _candleplot
PlotInfo:
• subplot (False)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (True)
• plotmaster (None)
• plotyticks ([])
750
backtrader’s documentation Version-1.9.58.122
PlotLines:
CDLEVENINGDOJISTAR
CDLEVENINGDOJISTAR([input_arrays], [penetration=0.3])
Inputs:
prices: [‘open’, ‘high’, ‘low’, ‘close’]
Parameters:
penetration: 0.3
Outputs:
integer (values are -100, 0 or 100)
Lines:
• integer
• _candleplot
Params:
• penetration (0.3)
PlotInfo:
• subplot (False)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (True)
• plotmaster (None)
• plotyticks ([])
PlotLines:
751
backtrader’s documentation Version-1.9.58.122
CDLEVENINGSTAR
CDLEVENINGSTAR([input_arrays], [penetration=0.3])
Inputs:
prices: [‘open’, ‘high’, ‘low’, ‘close’]
Parameters:
penetration: 0.3
Outputs:
integer (values are -100, 0 or 100)
Lines:
• integer
• _candleplot
Params:
• penetration (0.3)
PlotInfo:
• subplot (False)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (True)
• plotmaster (None)
• plotyticks ([])
PlotLines:
CDLGAPSIDESIDEWHITE
CDLGAPSIDESIDEWHITE([input_arrays])
Inputs:
prices: [‘open’, ‘high’, ‘low’, ‘close’]
Outputs:
integer (values are -100, 0 or 100)
Lines:
• integer
• _candleplot
PlotInfo:
• subplot (False)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (True)
• plotmaster (None)
• plotyticks ([])
PlotLines:
CDLGRAVESTONEDOJI
CDLGRAVESTONEDOJI([input_arrays])
Inputs:
prices: [‘open’, ‘high’, ‘low’, ‘close’]
Outputs:
integer (values are -100, 0 or 100)
Lines:
• integer
• _candleplot
PlotInfo:
753
backtrader’s documentation Version-1.9.58.122
• subplot (False)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (True)
• plotmaster (None)
• plotyticks ([])
PlotLines:
CDLHAMMER
CDLHAMMER([input_arrays])
Inputs:
prices: [‘open’, ‘high’, ‘low’, ‘close’]
Outputs:
integer (values are -100, 0 or 100)
Lines:
• integer
• _candleplot
PlotInfo:
• subplot (False)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (True)
754
backtrader’s documentation Version-1.9.58.122
• plotmaster (None)
• plotyticks ([])
PlotLines:
CDLHANGINGMAN
CDLHANGINGMAN([input_arrays])
Inputs:
prices: [‘open’, ‘high’, ‘low’, ‘close’]
Outputs:
integer (values are -100, 0 or 100)
Lines:
• integer
• _candleplot
PlotInfo:
• subplot (False)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (True)
• plotmaster (None)
• plotyticks ([])
PlotLines:
CDLHARAMI
CDLHARAMI([input_arrays])
755
backtrader’s documentation Version-1.9.58.122
Inputs:
prices: [‘open’, ‘high’, ‘low’, ‘close’]
Outputs:
integer (values are -100, 0 or 100)
Lines:
• integer
• _candleplot
PlotInfo:
• subplot (False)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (True)
• plotmaster (None)
• plotyticks ([])
PlotLines:
CDLHARAMICROSS
CDLHARAMICROSS([input_arrays])
Inputs:
prices: [‘open’, ‘high’, ‘low’, ‘close’]
Outputs:
integer (values are -100, 0 or 100)
Lines:
• integer
• _candleplot
756
backtrader’s documentation Version-1.9.58.122
PlotInfo:
• subplot (False)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (True)
• plotmaster (None)
• plotyticks ([])
PlotLines:
CDLHIGHWAVE
CDLHIGHWAVE([input_arrays])
Inputs:
prices: [‘open’, ‘high’, ‘low’, ‘close’]
Outputs:
integer (values are -100, 0 or 100)
Lines:
• integer
• _candleplot
PlotInfo:
• subplot (False)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
757
backtrader’s documentation Version-1.9.58.122
• plotymargin (0.0)
• plotlinelabels (True)
• plotmaster (None)
• plotyticks ([])
PlotLines:
CDLHIKKAKE
CDLHIKKAKE([input_arrays])
Inputs:
prices: [‘open’, ‘high’, ‘low’, ‘close’]
Outputs:
integer (values are -100, 0 or 100)
Lines:
• integer
• _candleplot
PlotInfo:
• subplot (False)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (True)
• plotmaster (None)
• plotyticks ([])
PlotLines:
758
backtrader’s documentation Version-1.9.58.122
CDLHIKKAKEMOD
CDLHIKKAKEMOD([input_arrays])
Inputs:
prices: [‘open’, ‘high’, ‘low’, ‘close’]
Outputs:
integer (values are -100, 0 or 100)
Lines:
• integer
• _candleplot
PlotInfo:
• subplot (False)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (True)
• plotmaster (None)
• plotyticks ([])
PlotLines:
CDLHOMINGPIGEON
CDLHOMINGPIGEON([input_arrays])
Inputs:
prices: [‘open’, ‘high’, ‘low’, ‘close’]
Outputs:
integer (values are -100, 0 or 100)
Lines:
759
backtrader’s documentation Version-1.9.58.122
• integer
• _candleplot
PlotInfo:
• subplot (False)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (True)
• plotmaster (None)
• plotyticks ([])
PlotLines:
CDLIDENTICAL3CROWS
CDLIDENTICAL3CROWS([input_arrays])
Inputs:
prices: [‘open’, ‘high’, ‘low’, ‘close’]
Outputs:
integer (values are -100, 0 or 100)
Lines:
• integer
• _candleplot
PlotInfo:
• subplot (False)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
760
backtrader’s documentation Version-1.9.58.122
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (True)
• plotmaster (None)
• plotyticks ([])
PlotLines:
CDLINNECK
CDLINNECK([input_arrays])
Inputs:
prices: [‘open’, ‘high’, ‘low’, ‘close’]
Outputs:
integer (values are -100, 0 or 100)
Lines:
• integer
• _candleplot
PlotInfo:
• subplot (False)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (True)
• plotmaster (None)
• plotyticks ([])
PlotLines:
761
backtrader’s documentation Version-1.9.58.122
CDLINVERTEDHAMMER
CDLINVERTEDHAMMER([input_arrays])
Inputs:
prices: [‘open’, ‘high’, ‘low’, ‘close’]
Outputs:
integer (values are -100, 0 or 100)
Lines:
• integer
• _candleplot
PlotInfo:
• subplot (False)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (True)
• plotmaster (None)
• plotyticks ([])
PlotLines:
CDLKICKING
CDLKICKING([input_arrays])
Inputs:
prices: [‘open’, ‘high’, ‘low’, ‘close’]
762
backtrader’s documentation Version-1.9.58.122
Outputs:
integer (values are -100, 0 or 100)
Lines:
• integer
• _candleplot
PlotInfo:
• subplot (False)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (True)
• plotmaster (None)
• plotyticks ([])
PlotLines:
CDLKICKINGBYLENGTH
CDLKICKINGBYLENGTH([input_arrays])
Inputs:
prices: [‘open’, ‘high’, ‘low’, ‘close’]
Outputs:
integer (values are -100, 0 or 100)
Lines:
• integer
• _candleplot
PlotInfo:
• subplot (False)
• plot (True)
763
backtrader’s documentation Version-1.9.58.122
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (True)
• plotmaster (None)
• plotyticks ([])
PlotLines:
CDLLADDERBOTTOM
CDLLADDERBOTTOM([input_arrays])
Inputs:
prices: [‘open’, ‘high’, ‘low’, ‘close’]
Outputs:
integer (values are -100, 0 or 100)
Lines:
• integer
• _candleplot
PlotInfo:
• subplot (False)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (True)
• plotmaster (None)
• plotyticks ([])
764
backtrader’s documentation Version-1.9.58.122
PlotLines:
CDLLONGLEGGEDDOJI
CDLLONGLEGGEDDOJI([input_arrays])
Inputs:
prices: [‘open’, ‘high’, ‘low’, ‘close’]
Outputs:
integer (values are -100, 0 or 100)
Lines:
• integer
• _candleplot
PlotInfo:
• subplot (False)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (True)
• plotmaster (None)
• plotyticks ([])
PlotLines:
CDLLONGLINE
CDLLONGLINE([input_arrays])
765
backtrader’s documentation Version-1.9.58.122
Inputs:
prices: [‘open’, ‘high’, ‘low’, ‘close’]
Outputs:
integer (values are -100, 0 or 100)
Lines:
• integer
• _candleplot
PlotInfo:
• subplot (False)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (True)
• plotmaster (None)
• plotyticks ([])
PlotLines:
CDLMARUBOZU
CDLMARUBOZU([input_arrays])
Inputs:
prices: [‘open’, ‘high’, ‘low’, ‘close’]
Outputs:
integer (values are -100, 0 or 100)
Lines:
• integer
• _candleplot
PlotInfo:
766
backtrader’s documentation Version-1.9.58.122
• subplot (False)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (True)
• plotmaster (None)
• plotyticks ([])
PlotLines:
CDLMATCHINGLOW
CDLMATCHINGLOW([input_arrays])
Inputs:
prices: [‘open’, ‘high’, ‘low’, ‘close’]
Outputs:
integer (values are -100, 0 or 100)
Lines:
• integer
• _candleplot
PlotInfo:
• subplot (False)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (True)
767
backtrader’s documentation Version-1.9.58.122
• plotmaster (None)
• plotyticks ([])
PlotLines:
CDLMATHOLD
CDLMATHOLD([input_arrays], [penetration=0.5])
Inputs:
prices: [‘open’, ‘high’, ‘low’, ‘close’]
Parameters:
penetration: 0.5
Outputs:
integer (values are -100, 0 or 100)
Lines:
• integer
• _candleplot
Params:
• penetration (0.5)
PlotInfo:
• subplot (False)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (True)
• plotmaster (None)
• plotyticks ([])
PlotLines:
768
backtrader’s documentation Version-1.9.58.122
CDLMORNINGDOJISTAR
CDLMORNINGDOJISTAR([input_arrays], [penetration=0.3])
Inputs:
prices: [‘open’, ‘high’, ‘low’, ‘close’]
Parameters:
penetration: 0.3
Outputs:
integer (values are -100, 0 or 100)
Lines:
• integer
• _candleplot
Params:
• penetration (0.3)
PlotInfo:
• subplot (False)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (True)
• plotmaster (None)
• plotyticks ([])
PlotLines:
CDLMORNINGSTAR
769
backtrader’s documentation Version-1.9.58.122
CDLMORNINGSTAR([input_arrays], [penetration=0.3])
Inputs:
prices: [‘open’, ‘high’, ‘low’, ‘close’]
Parameters:
penetration: 0.3
Outputs:
integer (values are -100, 0 or 100)
Lines:
• integer
• _candleplot
Params:
• penetration (0.3)
PlotInfo:
• subplot (False)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (True)
• plotmaster (None)
• plotyticks ([])
PlotLines:
CDLONNECK
CDLONNECK([input_arrays])
Inputs:
770
backtrader’s documentation Version-1.9.58.122
• integer
• _candleplot
PlotInfo:
• subplot (False)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (True)
• plotmaster (None)
• plotyticks ([])
PlotLines:
CDLPIERCING
CDLPIERCING([input_arrays])
Inputs:
prices: [‘open’, ‘high’, ‘low’, ‘close’]
Outputs:
integer (values are -100, 0 or 100)
Lines:
• integer
• _candleplot
PlotInfo:
• subplot (False)
771
backtrader’s documentation Version-1.9.58.122
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (True)
• plotmaster (None)
• plotyticks ([])
PlotLines:
CDLRICKSHAWMAN
CDLRICKSHAWMAN([input_arrays])
Inputs:
prices: [‘open’, ‘high’, ‘low’, ‘close’]
Outputs:
integer (values are -100, 0 or 100)
Lines:
• integer
• _candleplot
PlotInfo:
• subplot (False)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (True)
• plotmaster (None)
772
backtrader’s documentation Version-1.9.58.122
• plotyticks ([])
PlotLines:
CDLRISEFALL3METHODS
CDLRISEFALL3METHODS([input_arrays])
Inputs:
prices: [‘open’, ‘high’, ‘low’, ‘close’]
Outputs:
integer (values are -100, 0 or 100)
Lines:
• integer
• _candleplot
PlotInfo:
• subplot (False)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (True)
• plotmaster (None)
• plotyticks ([])
PlotLines:
CDLSEPARATINGLINES
CDLSEPARATINGLINES([input_arrays])
773
backtrader’s documentation Version-1.9.58.122
Inputs:
prices: [‘open’, ‘high’, ‘low’, ‘close’]
Outputs:
integer (values are -100, 0 or 100)
Lines:
• integer
• _candleplot
PlotInfo:
• subplot (False)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (True)
• plotmaster (None)
• plotyticks ([])
PlotLines:
CDLSHOOTINGSTAR
CDLSHOOTINGSTAR([input_arrays])
Inputs:
prices: [‘open’, ‘high’, ‘low’, ‘close’]
Outputs:
integer (values are -100, 0 or 100)
Lines:
• integer
• _candleplot
774
backtrader’s documentation Version-1.9.58.122
PlotInfo:
• subplot (False)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (True)
• plotmaster (None)
• plotyticks ([])
PlotLines:
CDLSHORTLINE
CDLSHORTLINE([input_arrays])
Inputs:
prices: [‘open’, ‘high’, ‘low’, ‘close’]
Outputs:
integer (values are -100, 0 or 100)
Lines:
• integer
• _candleplot
PlotInfo:
• subplot (False)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
775
backtrader’s documentation Version-1.9.58.122
• plotymargin (0.0)
• plotlinelabels (True)
• plotmaster (None)
• plotyticks ([])
PlotLines:
CDLSPINNINGTOP
CDLSPINNINGTOP([input_arrays])
Inputs:
prices: [‘open’, ‘high’, ‘low’, ‘close’]
Outputs:
integer (values are -100, 0 or 100)
Lines:
• integer
• _candleplot
PlotInfo:
• subplot (False)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (True)
• plotmaster (None)
• plotyticks ([])
PlotLines:
776
backtrader’s documentation Version-1.9.58.122
CDLSTALLEDPATTERN
CDLSTALLEDPATTERN([input_arrays])
Inputs:
prices: [‘open’, ‘high’, ‘low’, ‘close’]
Outputs:
integer (values are -100, 0 or 100)
Lines:
• integer
• _candleplot
PlotInfo:
• subplot (False)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (True)
• plotmaster (None)
• plotyticks ([])
PlotLines:
CDLSTICKSANDWICH
CDLSTICKSANDWICH([input_arrays])
Inputs:
prices: [‘open’, ‘high’, ‘low’, ‘close’]
Outputs:
integer (values are -100, 0 or 100)
Lines:
777
backtrader’s documentation Version-1.9.58.122
• integer
• _candleplot
PlotInfo:
• subplot (False)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (True)
• plotmaster (None)
• plotyticks ([])
PlotLines:
CDLTAKURI
CDLTAKURI([input_arrays])
Takuri (Dragonfly Doji with very long lower shadow) (Pattern Recognition)
Inputs:
prices: [‘open’, ‘high’, ‘low’, ‘close’]
Outputs:
integer (values are -100, 0 or 100)
Lines:
• integer
• _candleplot
PlotInfo:
• subplot (False)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
778
backtrader’s documentation Version-1.9.58.122
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (True)
• plotmaster (None)
• plotyticks ([])
PlotLines:
CDLTASUKIGAP
CDLTASUKIGAP([input_arrays])
Inputs:
prices: [‘open’, ‘high’, ‘low’, ‘close’]
Outputs:
integer (values are -100, 0 or 100)
Lines:
• integer
• _candleplot
PlotInfo:
• subplot (False)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (True)
• plotmaster (None)
• plotyticks ([])
PlotLines:
779
backtrader’s documentation Version-1.9.58.122
CDLTHRUSTING
CDLTHRUSTING([input_arrays])
Inputs:
prices: [‘open’, ‘high’, ‘low’, ‘close’]
Outputs:
integer (values are -100, 0 or 100)
Lines:
• integer
• _candleplot
PlotInfo:
• subplot (False)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (True)
• plotmaster (None)
• plotyticks ([])
PlotLines:
CDLTRISTAR
CDLTRISTAR([input_arrays])
Inputs:
prices: [‘open’, ‘high’, ‘low’, ‘close’]
780
backtrader’s documentation Version-1.9.58.122
Outputs:
integer (values are -100, 0 or 100)
Lines:
• integer
• _candleplot
PlotInfo:
• subplot (False)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (True)
• plotmaster (None)
• plotyticks ([])
PlotLines:
CDLUNIQUE3RIVER
CDLUNIQUE3RIVER([input_arrays])
Inputs:
prices: [‘open’, ‘high’, ‘low’, ‘close’]
Outputs:
integer (values are -100, 0 or 100)
Lines:
• integer
• _candleplot
PlotInfo:
• subplot (False)
• plot (True)
781
backtrader’s documentation Version-1.9.58.122
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (True)
• plotmaster (None)
• plotyticks ([])
PlotLines:
CDLUPSIDEGAP2CROWS
CDLUPSIDEGAP2CROWS([input_arrays])
Inputs:
prices: [‘open’, ‘high’, ‘low’, ‘close’]
Outputs:
integer (values are -100, 0 or 100)
Lines:
• integer
• _candleplot
PlotInfo:
• subplot (False)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (True)
• plotmaster (None)
• plotyticks ([])
782
backtrader’s documentation Version-1.9.58.122
PlotLines:
CDLXSIDEGAP3METHODS
CDLXSIDEGAP3METHODS([input_arrays])
Inputs:
prices: [‘open’, ‘high’, ‘low’, ‘close’]
Outputs:
integer (values are -100, 0 or 100)
Lines:
• integer
• _candleplot
PlotInfo:
• subplot (False)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (True)
• plotmaster (None)
• plotyticks ([])
PlotLines:
CEIL
CEIL([input_arrays])
Inputs:
price: (any ndarray)
Outputs:
real
Lines:
• real
PlotInfo:
• subplot (True)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotmaster (None)
• plotyticks ([])
PlotLines:
• real: - ls (-)
CMO
CMO([input_arrays], [timeperiod=14])
Inputs:
price: (any ndarray)
Parameters:
timeperiod: 14
Outputs:
real
Lines:
• real
Params:
• timeperiod (14)
784
backtrader’s documentation Version-1.9.58.122
PlotInfo:
• subplot (True)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotmaster (None)
• plotyticks ([])
PlotLines:
• real: - ls (-)
CORREL
CORREL([input_arrays], [timeperiod=30])
Inputs:
price0: (any ndarray) price1: (any ndarray)
Parameters:
timeperiod: 30
Outputs:
real
Lines:
• real
Params:
• timeperiod (30)
PlotInfo:
• subplot (True)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
785
backtrader’s documentation Version-1.9.58.122
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotmaster (None)
• plotyticks ([])
PlotLines:
• real: - ls (-)
COS
COS([input_arrays])
Inputs:
price: (any ndarray)
Outputs:
real
Lines:
• real
PlotInfo:
• subplot (True)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotmaster (None)
• plotyticks ([])
PlotLines:
• real: - ls (-)
786
backtrader’s documentation Version-1.9.58.122
COSH
COSH([input_arrays])
Inputs:
price: (any ndarray)
Outputs:
real
Lines:
• real
PlotInfo:
• subplot (True)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotmaster (None)
• plotyticks ([])
PlotLines:
• real: - ls (-)
DEMA
DEMA([input_arrays], [timeperiod=30])
Inputs:
price: (any ndarray)
Parameters:
timeperiod: 30
Outputs:
real
Lines:
787
backtrader’s documentation Version-1.9.58.122
• real
Params:
• timeperiod (30)
PlotInfo:
• subplot (False)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotmaster (None)
• plotyticks ([])
PlotLines:
• real: - ls (-)
DIV
DIV([input_arrays])
Inputs:
price0: (any ndarray) price1: (any ndarray)
Outputs:
real
Lines:
• real
PlotInfo:
• subplot (True)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
788
backtrader’s documentation Version-1.9.58.122
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotmaster (None)
• plotyticks ([])
PlotLines:
• real: - ls (-)
DX
DX([input_arrays], [timeperiod=14])
Inputs:
prices: [‘high’, ‘low’, ‘close’]
Parameters:
timeperiod: 14
Outputs:
real
Lines:
• real
Params:
• timeperiod (14)
PlotInfo:
• subplot (True)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotmaster (None)
789
backtrader’s documentation Version-1.9.58.122
• plotyticks ([])
PlotLines:
• real: - ls (-)
EMA
EMA([input_arrays], [timeperiod=30])
Inputs:
price: (any ndarray)
Parameters:
timeperiod: 30
Outputs:
real
Lines:
• real
Params:
• timeperiod (30)
PlotInfo:
• subplot (False)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotmaster (None)
• plotyticks ([])
PlotLines:
• real: - ls (-)
EXP
790
backtrader’s documentation Version-1.9.58.122
EXP([input_arrays])
Inputs:
price: (any ndarray)
Outputs:
real
Lines:
• real
PlotInfo:
• subplot (True)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotmaster (None)
• plotyticks ([])
PlotLines:
• real: - ls (-)
FLOOR
FLOOR([input_arrays])
Inputs:
price: (any ndarray)
Outputs:
real
Lines:
• real
PlotInfo:
791
backtrader’s documentation Version-1.9.58.122
• subplot (True)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotmaster (None)
• plotyticks ([])
PlotLines:
• real: - ls (-)
HT_DCPERIOD
HT_DCPERIOD([input_arrays])
Inputs:
price: (any ndarray)
Outputs:
real
Lines:
• real
PlotInfo:
• subplot (True)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotmaster (None)
• plotyticks ([])
792
backtrader’s documentation Version-1.9.58.122
PlotLines:
• real: - ls (-)
HT_DCPHASE
HT_DCPHASE([input_arrays])
Inputs:
price: (any ndarray)
Outputs:
real
Lines:
• real
PlotInfo:
• subplot (True)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotmaster (None)
• plotyticks ([])
PlotLines:
• real: - ls (-)
HT_PHASOR
HT_PHASOR([input_arrays])
Inputs:
price: (any ndarray)
Outputs:
793
backtrader’s documentation Version-1.9.58.122
inphase quadrature
Lines:
• inphase
• quadrature
PlotInfo:
• subplot (True)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotmaster (None)
• plotyticks ([])
PlotLines:
• inphase: - ls (-)
• quadrature: - ls (–)
HT_SINE
HT_SINE([input_arrays])
Inputs:
price: (any ndarray)
Outputs:
sine leadsine
Lines:
• sine
• leadsine
PlotInfo:
• subplot (True)
• plot (True)
• plotskip (False)
794
backtrader’s documentation Version-1.9.58.122
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotmaster (None)
• plotyticks ([])
PlotLines:
• leadsine: - ls (–)
• sine: - ls (-)
HT_TRENDLINE
HT_TRENDLINE([input_arrays])
Inputs:
price: (any ndarray)
Outputs:
real
Lines:
• real
PlotInfo:
• subplot (False)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotmaster (None)
• plotyticks ([])
PlotLines:
795
backtrader’s documentation Version-1.9.58.122
• real: - ls (-)
HT_TRENDMODE
HT_TRENDMODE([input_arrays])
Inputs:
price: (any ndarray)
Outputs:
integer (values are -100, 0 or 100)
Lines:
• integer
PlotInfo:
• subplot (True)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotmaster (None)
• plotyticks ([])
PlotLines:
• integer: - ls (-)
KAMA
KAMA([input_arrays], [timeperiod=30])
Inputs:
price: (any ndarray)
Parameters:
timeperiod: 30
Outputs:
796
backtrader’s documentation Version-1.9.58.122
real
Lines:
• real
Params:
• timeperiod (30)
PlotInfo:
• subplot (False)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotmaster (None)
• plotyticks ([])
PlotLines:
• real: - ls (-)
LINEARREG
LINEARREG([input_arrays], [timeperiod=14])
Inputs:
price: (any ndarray)
Parameters:
timeperiod: 14
Outputs:
real
Lines:
• real
Params:
797
backtrader’s documentation Version-1.9.58.122
• timeperiod (14)
PlotInfo:
• subplot (False)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotmaster (None)
• plotyticks ([])
PlotLines:
• real: - ls (-)
LINEARREG_ANGLE
LINEARREG_ANGLE([input_arrays], [timeperiod=14])
Inputs:
price: (any ndarray)
Parameters:
timeperiod: 14
Outputs:
real
Lines:
• real
Params:
• timeperiod (14)
PlotInfo:
• subplot (True)
• plot (True)
• plotskip (False)
798
backtrader’s documentation Version-1.9.58.122
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotmaster (None)
• plotyticks ([])
PlotLines:
• real: - ls (-)
LINEARREG_INTERCEPT
LINEARREG_INTERCEPT([input_arrays], [timeperiod=14])
Inputs:
price: (any ndarray)
Parameters:
timeperiod: 14
Outputs:
real
Lines:
• real
Params:
• timeperiod (14)
PlotInfo:
• subplot (False)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
799
backtrader’s documentation Version-1.9.58.122
• plotlinelabels (False)
• plotmaster (None)
• plotyticks ([])
PlotLines:
• real: - ls (-)
LINEARREG_SLOPE
LINEARREG_SLOPE([input_arrays], [timeperiod=14])
Inputs:
price: (any ndarray)
Parameters:
timeperiod: 14
Outputs:
real
Lines:
• real
Params:
• timeperiod (14)
PlotInfo:
• subplot (True)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotmaster (None)
• plotyticks ([])
PlotLines:
• real: - ls (-)
800
backtrader’s documentation Version-1.9.58.122
LN
LN([input_arrays])
Inputs:
price: (any ndarray)
Outputs:
real
Lines:
• real
PlotInfo:
• subplot (True)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotmaster (None)
• plotyticks ([])
PlotLines:
• real: - ls (-)
LOG10
LOG10([input_arrays])
Inputs:
price: (any ndarray)
Outputs:
real
Lines:
• real
801
backtrader’s documentation Version-1.9.58.122
PlotInfo:
• subplot (True)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotmaster (None)
• plotyticks ([])
PlotLines:
• real: - ls (-)
MA
Inputs:
price: (any ndarray)
Parameters:
timeperiod: 30 matype: 0 (Simple Moving Average)
Outputs:
real
Lines:
• real
Params:
• timeperiod (30)
• matype (0)
PlotInfo:
• subplot (False)
• plot (True)
• plotskip (False)
• plotname ()
802
backtrader’s documentation Version-1.9.58.122
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotmaster (None)
• plotyticks ([])
PlotLines:
• real: - ls (-)
MACD
Inputs:
price: (any ndarray)
Parameters:
fastperiod: 12 slowperiod: 26 signalperiod: 9
Outputs:
macd macdsignal macdhist
Lines:
• macd
• macdsignal
• macdhist
Params:
• fastperiod (12)
• slowperiod (26)
• signalperiod (9)
PlotInfo:
• subplot (True)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
803
backtrader’s documentation Version-1.9.58.122
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotmaster (None)
• plotyticks ([])
PlotLines:
• macdsignal: - ls (–)
• macd: - ls (-)
• macdhist: - _method (bar)
MACDEXT
Inputs:
price: (any ndarray)
Parameters:
fastperiod: 12 fastmatype: 0 slowperiod: 26 slowmatype: 0 signalperiod: 9 signalmatype: 0
Outputs:
macd macdsignal macdhist
Lines:
• macd
• macdsignal
• macdhist
Params:
• fastperiod (12)
• fastmatype (0)
• slowperiod (26)
• slowmatype (0)
• signalperiod (9)
• signalmatype (0)
PlotInfo:
• subplot (True)
• plot (True)
804
backtrader’s documentation Version-1.9.58.122
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotmaster (None)
• plotyticks ([])
PlotLines:
• macdsignal: - ls (–)
• macd: - ls (-)
• macdhist: - _method (bar)
MACDFIX
MACDFIX([input_arrays], [signalperiod=9])
Inputs:
price: (any ndarray)
Parameters:
signalperiod: 9
Outputs:
macd macdsignal macdhist
Lines:
• macd
• macdsignal
• macdhist
Params:
• signalperiod (9)
PlotInfo:
• subplot (True)
• plot (True)
• plotskip (False)
• plotname ()
805
backtrader’s documentation Version-1.9.58.122
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotmaster (None)
• plotyticks ([])
PlotLines:
• macdsignal: - ls (–)
• macd: - ls (-)
• macdhist: - _method (bar)
MAMA
Inputs:
price: (any ndarray)
Parameters:
fastlimit: 0.5 slowlimit: 0.05
Outputs:
mama fama
Lines:
• mama
• fama
Params:
• fastlimit (0.5)
• slowlimit (0.05)
PlotInfo:
• subplot (False)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
806
backtrader’s documentation Version-1.9.58.122
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotmaster (None)
• plotyticks ([])
PlotLines:
• mama: - ls (-)
• fama: - ls (–)
MAVP
Inputs:
price: (any ndarray) periods: (any ndarray)
Parameters:
minperiod: 2 maxperiod: 30 matype: 0 (Simple Moving Average)
Outputs:
real
Lines:
• real
Params:
• minperiod (2)
• maxperiod (30)
• matype (0)
PlotInfo:
• subplot (False)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
807
backtrader’s documentation Version-1.9.58.122
• plotlinelabels (False)
• plotmaster (None)
• plotyticks ([])
PlotLines:
• real: - ls (-)
MAX
MAX([input_arrays], [timeperiod=30])
Inputs:
price: (any ndarray)
Parameters:
timeperiod: 30
Outputs:
real
Lines:
• real
Params:
• timeperiod (30)
PlotInfo:
• subplot (False)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotmaster (None)
• plotyticks ([])
PlotLines:
• real: - ls (-)
808
backtrader’s documentation Version-1.9.58.122
MAXINDEX
MAXINDEX([input_arrays], [timeperiod=30])
Inputs:
price: (any ndarray)
Parameters:
timeperiod: 30
Outputs:
integer (values are -100, 0 or 100)
Lines:
• integer
Params:
• timeperiod (30)
PlotInfo:
• subplot (True)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotmaster (None)
• plotyticks ([])
PlotLines:
• integer: - ls (-)
MEDPRICE
MEDPRICE([input_arrays])
Inputs:
809
backtrader’s documentation Version-1.9.58.122
• real
PlotInfo:
• subplot (False)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotmaster (None)
• plotyticks ([])
PlotLines:
• real: - ls (-)
MFI
MFI([input_arrays], [timeperiod=14])
Inputs:
prices: [‘high’, ‘low’, ‘close’, ‘volume’]
Parameters:
timeperiod: 14
Outputs:
real
Lines:
• real
Params:
• timeperiod (14)
810
backtrader’s documentation Version-1.9.58.122
PlotInfo:
• subplot (True)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotmaster (None)
• plotyticks ([])
PlotLines:
• real: - ls (-)
MIDPOINT
MIDPOINT([input_arrays], [timeperiod=14])
Inputs:
price: (any ndarray)
Parameters:
timeperiod: 14
Outputs:
real
Lines:
• real
Params:
• timeperiod (14)
PlotInfo:
• subplot (False)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
811
backtrader’s documentation Version-1.9.58.122
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotmaster (None)
• plotyticks ([])
PlotLines:
• real: - ls (-)
MIDPRICE
MIDPRICE([input_arrays], [timeperiod=14])
Inputs:
prices: [‘high’, ‘low’]
Parameters:
timeperiod: 14
Outputs:
real
Lines:
• real
Params:
• timeperiod (14)
PlotInfo:
• subplot (False)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotmaster (None)
812
backtrader’s documentation Version-1.9.58.122
• plotyticks ([])
PlotLines:
• real: - ls (-)
MIN
MIN([input_arrays], [timeperiod=30])
Inputs:
price: (any ndarray)
Parameters:
timeperiod: 30
Outputs:
real
Lines:
• real
Params:
• timeperiod (30)
PlotInfo:
• subplot (False)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotmaster (None)
• plotyticks ([])
PlotLines:
• real: - ls (-)
MININDEX
813
backtrader’s documentation Version-1.9.58.122
MININDEX([input_arrays], [timeperiod=30])
Inputs:
price: (any ndarray)
Parameters:
timeperiod: 30
Outputs:
integer (values are -100, 0 or 100)
Lines:
• integer
Params:
• timeperiod (30)
PlotInfo:
• subplot (True)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotmaster (None)
• plotyticks ([])
PlotLines:
• integer: - ls (-)
MINMAX
MINMAX([input_arrays], [timeperiod=30])
Inputs:
price: (any ndarray)
Parameters:
814
backtrader’s documentation Version-1.9.58.122
timeperiod: 30
Outputs:
min max
Lines:
• min
• max
Params:
• timeperiod (30)
PlotInfo:
• subplot (False)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotmaster (None)
• plotyticks ([])
PlotLines:
• max: - ls (-)
• min: - ls (-)
MINMAXINDEX
MINMAXINDEX([input_arrays], [timeperiod=30])
Indexes of lowest and highest values over a specified period (Math Operators)
Inputs:
price: (any ndarray)
Parameters:
timeperiod: 30
Outputs:
minidx maxidx
Lines:
815
backtrader’s documentation Version-1.9.58.122
• minidx
• maxidx
Params:
• timeperiod (30)
PlotInfo:
• subplot (True)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotmaster (None)
• plotyticks ([])
PlotLines:
• maxidx: - ls (-)
• minidx: - ls (-)
MINUS_DI
MINUS_DI([input_arrays], [timeperiod=14])
Inputs:
prices: [‘high’, ‘low’, ‘close’]
Parameters:
timeperiod: 14
Outputs:
real
Lines:
• real
Params:
• timeperiod (14)
816
backtrader’s documentation Version-1.9.58.122
PlotInfo:
• subplot (True)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotmaster (None)
• plotyticks ([])
PlotLines:
• real: - ls (-)
MINUS_DM
MINUS_DM([input_arrays], [timeperiod=14])
Inputs:
prices: [‘high’, ‘low’]
Parameters:
timeperiod: 14
Outputs:
real
Lines:
• real
Params:
• timeperiod (14)
PlotInfo:
• subplot (True)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
817
backtrader’s documentation Version-1.9.58.122
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotmaster (None)
• plotyticks ([])
PlotLines:
• real: - ls (-)
MOM
MOM([input_arrays], [timeperiod=10])
Inputs:
price: (any ndarray)
Parameters:
timeperiod: 10
Outputs:
real
Lines:
• real
Params:
• timeperiod (10)
PlotInfo:
• subplot (True)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotmaster (None)
818
backtrader’s documentation Version-1.9.58.122
• plotyticks ([])
PlotLines:
• real: - ls (-)
MULT
MULT([input_arrays])
Inputs:
price0: (any ndarray) price1: (any ndarray)
Outputs:
real
Lines:
• real
PlotInfo:
• subplot (True)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotmaster (None)
• plotyticks ([])
PlotLines:
• real: - ls (-)
NATR
NATR([input_arrays], [timeperiod=14])
Inputs:
819
backtrader’s documentation Version-1.9.58.122
• real
Params:
• timeperiod (14)
PlotInfo:
• subplot (True)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotmaster (None)
• plotyticks ([])
PlotLines:
• real: - ls (-)
OBV
OBV([input_arrays])
Inputs:
price: (any ndarray) prices: [‘volume’]
Outputs:
real
Lines:
• real
820
backtrader’s documentation Version-1.9.58.122
PlotInfo:
• subplot (True)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotmaster (None)
• plotyticks ([])
PlotLines:
• real: - ls (-)
PLUS_DI
PLUS_DI([input_arrays], [timeperiod=14])
Inputs:
prices: [‘high’, ‘low’, ‘close’]
Parameters:
timeperiod: 14
Outputs:
real
Lines:
• real
Params:
• timeperiod (14)
PlotInfo:
• subplot (True)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
821
backtrader’s documentation Version-1.9.58.122
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotmaster (None)
• plotyticks ([])
PlotLines:
• real: - ls (-)
PLUS_DM
PLUS_DM([input_arrays], [timeperiod=14])
Inputs:
prices: [‘high’, ‘low’]
Parameters:
timeperiod: 14
Outputs:
real
Lines:
• real
Params:
• timeperiod (14)
PlotInfo:
• subplot (True)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotmaster (None)
822
backtrader’s documentation Version-1.9.58.122
• plotyticks ([])
PlotLines:
• real: - ls (-)
PPO
Inputs:
price: (any ndarray)
Parameters:
fastperiod: 12 slowperiod: 26 matype: 0 (Simple Moving Average)
Outputs:
real
Lines:
• real
Params:
• fastperiod (12)
• slowperiod (26)
• matype (0)
PlotInfo:
• subplot (True)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotmaster (None)
• plotyticks ([])
PlotLines:
• real: - ls (-)
823
backtrader’s documentation Version-1.9.58.122
ROC
ROC([input_arrays], [timeperiod=10])
Inputs:
price: (any ndarray)
Parameters:
timeperiod: 10
Outputs:
real
Lines:
• real
Params:
• timeperiod (10)
PlotInfo:
• subplot (True)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotmaster (None)
• plotyticks ([])
PlotLines:
• real: - ls (-)
ROCP
ROCP([input_arrays], [timeperiod=10])
Inputs:
824
backtrader’s documentation Version-1.9.58.122
• real
Params:
• timeperiod (10)
PlotInfo:
• subplot (True)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotmaster (None)
• plotyticks ([])
PlotLines:
• real: - ls (-)
ROCR
ROCR([input_arrays], [timeperiod=10])
Inputs:
price: (any ndarray)
Parameters:
timeperiod: 10
Outputs:
real
Lines:
825
backtrader’s documentation Version-1.9.58.122
• real
Params:
• timeperiod (10)
PlotInfo:
• subplot (True)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotmaster (None)
• plotyticks ([])
PlotLines:
• real: - ls (-)
ROCR100
ROCR100([input_arrays], [timeperiod=10])
Inputs:
price: (any ndarray)
Parameters:
timeperiod: 10
Outputs:
real
Lines:
• real
Params:
• timeperiod (10)
PlotInfo:
826
backtrader’s documentation Version-1.9.58.122
• subplot (True)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotmaster (None)
• plotyticks ([])
PlotLines:
• real: - ls (-)
RSI
RSI([input_arrays], [timeperiod=14])
Inputs:
price: (any ndarray)
Parameters:
timeperiod: 14
Outputs:
real
Lines:
• real
Params:
• timeperiod (14)
PlotInfo:
• subplot (True)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
827
backtrader’s documentation Version-1.9.58.122
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotmaster (None)
• plotyticks ([])
PlotLines:
• real: - ls (-)
SAR
Inputs:
prices: [‘high’, ‘low’]
Parameters:
acceleration: 0.02 maximum: 0.2
Outputs:
real
Lines:
• real
Params:
• acceleration (0.02)
• maximum (0.2)
PlotInfo:
• subplot (False)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotmaster (None)
828
backtrader’s documentation Version-1.9.58.122
• plotyticks ([])
PlotLines:
• real: - ls (-)
SAREXT
Inputs:
prices: [‘high’, ‘low’]
Parameters:
startvalue: 0 offsetonreverse: 0 accelerationinitlong: 0.02 accelerationlong: 0.02 accelerationmaxlong: 0.2
accelerationinitshort: 0.02 accelerationshort: 0.02 accelerationmaxshort: 0.2
Outputs:
real
Lines:
• real
Params:
• startvalue (0)
• offsetonreverse (0)
• accelerationinitlong (0.02)
• accelerationlong (0.02)
• accelerationmaxlong (0.2)
• accelerationinitshort (0.02)
• accelerationshort (0.02)
• accelerationmaxshort (0.2)
PlotInfo:
• subplot (False)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
829
backtrader’s documentation Version-1.9.58.122
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotmaster (None)
• plotyticks ([])
PlotLines:
• real: - ls (-)
SIN
SIN([input_arrays])
Inputs:
price: (any ndarray)
Outputs:
real
Lines:
• real
PlotInfo:
• subplot (True)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotmaster (None)
• plotyticks ([])
PlotLines:
• real: - ls (-)
SINH
830
backtrader’s documentation Version-1.9.58.122
SINH([input_arrays])
Inputs:
price: (any ndarray)
Outputs:
real
Lines:
• real
PlotInfo:
• subplot (True)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotmaster (None)
• plotyticks ([])
PlotLines:
• real: - ls (-)
SMA
SMA([input_arrays], [timeperiod=30])
Inputs:
price: (any ndarray)
Parameters:
timeperiod: 30
Outputs:
real
Lines:
• real
831
backtrader’s documentation Version-1.9.58.122
Params:
• timeperiod (30)
PlotInfo:
• subplot (False)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotmaster (None)
• plotyticks ([])
PlotLines:
• real: - ls (-)
SQRT
SQRT([input_arrays])
Inputs:
price: (any ndarray)
Outputs:
real
Lines:
• real
PlotInfo:
• subplot (True)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
832
backtrader’s documentation Version-1.9.58.122
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotmaster (None)
• plotyticks ([])
PlotLines:
• real: - ls (-)
STDDEV
Inputs:
price: (any ndarray)
Parameters:
timeperiod: 5 nbdev: 1
Outputs:
real
Lines:
• real
Params:
• timeperiod (5)
• nbdev (1)
PlotInfo:
• subplot (True)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotmaster (None)
• plotyticks ([])
833
backtrader’s documentation Version-1.9.58.122
PlotLines:
• real: - ls (-)
STOCH
Inputs:
prices: [‘high’, ‘low’, ‘close’]
Parameters:
fastk_period: 5 slowk_period: 3 slowk_matype: 0 slowd_period: 3 slowd_matype: 0
Outputs:
slowk slowd
Lines:
• slowk
• slowd
Params:
• fastk_period (5)
• slowk_period (3)
• slowk_matype (0)
• slowd_period (3)
• slowd_matype (0)
PlotInfo:
• subplot (True)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotmaster (None)
• plotyticks ([])
834
backtrader’s documentation Version-1.9.58.122
PlotLines:
• slowk: - ls (–)
• slowd: - ls (–)
STOCHF
Inputs:
prices: [‘high’, ‘low’, ‘close’]
Parameters:
fastk_period: 5 fastd_period: 3 fastd_matype: 0
Outputs:
fastk fastd
Lines:
• fastk
• fastd
Params:
• fastk_period (5)
• fastd_period (3)
• fastd_matype (0)
PlotInfo:
• subplot (True)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotmaster (None)
• plotyticks ([])
PlotLines:
• fastk: - ls (-)
835
backtrader’s documentation Version-1.9.58.122
• fastd: - ls (-)
STOCHRSI
Inputs:
price: (any ndarray)
Parameters:
timeperiod: 14 fastk_period: 5 fastd_period: 3 fastd_matype: 0
Outputs:
fastk fastd
Lines:
• fastk
• fastd
Params:
• timeperiod (14)
• fastk_period (5)
• fastd_period (3)
• fastd_matype (0)
PlotInfo:
• subplot (True)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotmaster (None)
• plotyticks ([])
PlotLines:
• fastk: - ls (-)
836
backtrader’s documentation Version-1.9.58.122
• fastd: - ls (-)
SUB
SUB([input_arrays])
Inputs:
price0: (any ndarray) price1: (any ndarray)
Outputs:
real
Lines:
• real
PlotInfo:
• subplot (True)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotmaster (None)
• plotyticks ([])
PlotLines:
• real: - ls (-)
SUM
SUM([input_arrays], [timeperiod=30])
Inputs:
price: (any ndarray)
Parameters:
timeperiod: 30
Outputs:
837
backtrader’s documentation Version-1.9.58.122
real
Lines:
• real
Params:
• timeperiod (30)
PlotInfo:
• subplot (True)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotmaster (None)
• plotyticks ([])
PlotLines:
• real: - ls (-)
T3
Inputs:
price: (any ndarray)
Parameters:
timeperiod: 5 vfactor: 0.7
Outputs:
real
Lines:
• real
Params:
838
backtrader’s documentation Version-1.9.58.122
• timeperiod (5)
• vfactor (0.7)
PlotInfo:
• subplot (False)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotmaster (None)
• plotyticks ([])
PlotLines:
• real: - ls (-)
TAN
TAN([input_arrays])
Inputs:
price: (any ndarray)
Outputs:
real
Lines:
• real
PlotInfo:
• subplot (True)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
839
backtrader’s documentation Version-1.9.58.122
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotmaster (None)
• plotyticks ([])
PlotLines:
• real: - ls (-)
TANH
TANH([input_arrays])
Inputs:
price: (any ndarray)
Outputs:
real
Lines:
• real
PlotInfo:
• subplot (True)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotmaster (None)
• plotyticks ([])
PlotLines:
• real: - ls (-)
TEMA
TEMA([input_arrays], [timeperiod=30])
840
backtrader’s documentation Version-1.9.58.122
Inputs:
price: (any ndarray)
Parameters:
timeperiod: 30
Outputs:
real
Lines:
• real
Params:
• timeperiod (30)
PlotInfo:
• subplot (False)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotmaster (None)
• plotyticks ([])
PlotLines:
• real: - ls (-)
TRANGE
TRANGE([input_arrays])
Inputs:
prices: [‘high’, ‘low’, ‘close’]
Outputs:
real
Lines:
841
backtrader’s documentation Version-1.9.58.122
• real
PlotInfo:
• subplot (True)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotmaster (None)
• plotyticks ([])
PlotLines:
• real: - ls (-)
TRIMA
TRIMA([input_arrays], [timeperiod=30])
Inputs:
price: (any ndarray)
Parameters:
timeperiod: 30
Outputs:
real
Lines:
• real
Params:
• timeperiod (30)
PlotInfo:
• subplot (False)
• plot (True)
• plotskip (False)
842
backtrader’s documentation Version-1.9.58.122
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotmaster (None)
• plotyticks ([])
PlotLines:
• real: - ls (-)
TRIX
TRIX([input_arrays], [timeperiod=30])
Inputs:
price: (any ndarray)
Parameters:
timeperiod: 30
Outputs:
real
Lines:
• real
Params:
• timeperiod (30)
PlotInfo:
• subplot (True)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
843
backtrader’s documentation Version-1.9.58.122
• plotlinelabels (False)
• plotmaster (None)
• plotyticks ([])
PlotLines:
• real: - ls (-)
TSF
TSF([input_arrays], [timeperiod=14])
Inputs:
price: (any ndarray)
Parameters:
timeperiod: 14
Outputs:
real
Lines:
• real
Params:
• timeperiod (14)
PlotInfo:
• subplot (False)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotmaster (None)
• plotyticks ([])
PlotLines:
• real: - ls (-)
844
backtrader’s documentation Version-1.9.58.122
TYPPRICE
TYPPRICE([input_arrays])
Inputs:
prices: [‘high’, ‘low’, ‘close’]
Outputs:
real
Lines:
• real
PlotInfo:
• subplot (False)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotmaster (None)
• plotyticks ([])
PlotLines:
• real: - ls (-)
ULTOSC
Inputs:
prices: [‘high’, ‘low’, ‘close’]
Parameters:
timeperiod1: 7 timeperiod2: 14 timeperiod3: 28
Outputs:
real
Lines:
845
backtrader’s documentation Version-1.9.58.122
• real
Params:
• timeperiod1 (7)
• timeperiod2 (14)
• timeperiod3 (28)
PlotInfo:
• subplot (True)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotmaster (None)
• plotyticks ([])
PlotLines:
• real: - ls (-)
VAR
Inputs:
price: (any ndarray)
Parameters:
timeperiod: 5 nbdev: 1
Outputs:
real
Lines:
• real
Params:
• timeperiod (5)
846
backtrader’s documentation Version-1.9.58.122
• nbdev (1)
PlotInfo:
• subplot (True)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotmaster (None)
• plotyticks ([])
PlotLines:
• real: - ls (-)
WCLPRICE
WCLPRICE([input_arrays])
Inputs:
prices: [‘high’, ‘low’, ‘close’]
Outputs:
real
Lines:
• real
PlotInfo:
• subplot (False)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
847
backtrader’s documentation Version-1.9.58.122
• plotymargin (0.0)
• plotlinelabels (False)
• plotmaster (None)
• plotyticks ([])
PlotLines:
• real: - ls (-)
WILLR
WILLR([input_arrays], [timeperiod=14])
Inputs:
prices: [‘high’, ‘low’, ‘close’]
Parameters:
timeperiod: 14
Outputs:
real
Lines:
• real
Params:
• timeperiod (14)
PlotInfo:
• subplot (True)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotmaster (None)
• plotyticks ([])
PlotLines:
848
backtrader’s documentation Version-1.9.58.122
• real: - ls (-)
WMA
WMA([input_arrays], [timeperiod=30])
Inputs:
price: (any ndarray)
Parameters:
timeperiod: 30
Outputs:
real
Lines:
• real
Params:
• timeperiod (30)
PlotInfo:
• subplot (False)
• plot (True)
• plotskip (False)
• plotname ()
• plotforce (False)
• plotyhlines ([])
• plothlines ([])
• plotabove (False)
• plotymargin (0.0)
• plotlinelabels (False)
• plotmaster (None)
• plotyticks ([])
PlotLines:
• real: - ls (-)
Strategies Reference
849
backtrader’s documentation Version-1.9.58.122
MA_CrossOver
Alias:
• SMA_CrossOver
Note:
Buy Logic:
Sell Logic:
• Market
Lines:
• datetime
Params:
• fast (10)
• slow (30)
• _movav (<class ‘backtrader.indicators.sma.SMA’>)
SignalStrategy
850
backtrader’s documentation Version-1.9.58.122
Main Group:
• LONGSHORT: both long and short indications from this signal are taken
• LONG: - long indications are taken to go long - short indications are taken
to close the long position. But:
o If a LONGEXIT (see below) signal is in the system it will be used to exit the long
o If a SHORT signal is available and no LONGEXIT is available , it will be used to close a long before
opening a short
• SHORT: - short indications are taken to go short - long indications are
taken to close the short position. But:
o If a SHORTEXIT (see below) signal is in the system it will be used to exit the short
o If a LONG signal is available and no SHORTEXIT is available , it will be used to close a short before
opening a long
Exit Group:
This 2 signals are meant to override others and provide criteria for exitins a
long/short position
Order Issuing
Orders execution type is Market and validity is None (Good until Canceled)
Params:
851
backtrader’s documentation Version-1.9.58.122
o A data instance
Lines:
• datetime
Params:
• signals ([])
• _accumulate (False)
• _concurrent (False)
• _data (None)
852
backtrader’s documentation Version-1.9.58.122
Analyzers Reference
AnnualReturn
Calmar
DrawDown
TimeDrawDown
GrossLeverage
PositionsValue
PyFolio
LogReturnsRolling
PeriodStats
Returns
SharpeRatio
SharpeRatio_A
SQN
TimeReturn
TradeAnalyzer
Transactions
VWR
853
backtrader’s documentation Version-1.9.58.122
Observers Reference
Benchmark
class backtrader.observers.Benchmark
This observer stores the returns of the strategy and the return of a
reference asset which is one of the datas passed to the system.
Params:
• timeframe (default: None) If None then the complete return over the
entire backtested period will be reported
• compression (default: None)
Note
this data must have been added to a cerebro instance with addata,
resampledata or replaydata.
Benchmarking will take place from the point at which the strategy
kicks in (i.e.: when the minimum period of the strategy has been
met).
Keepint it as False ensures that the 1st comparison point between the
value and the benchmark starts at 0%, because the benchmark will not
use its opening price.
Remember that at any moment of a run the current values can be checked by
looking at the lines by name at index 0.
Broker
This observer keeps track of the current cash amount and portfolio value in
the broker (including the cash)
Params: None
Broker - Cash
This observer keeps track of the current amount of cash in the broker
Params: None
Broker - Value
This observer keeps track of the current portfolio value in the broker
including the cash
Params:
855
backtrader’s documentation Version-1.9.58.122
BuySell
Params:
• barplot (default: False) Plot buy signals below the minimum and sell
signals above the maximum.
DrawDown
class backtrader.observers.DrawDown
This observer keeps track of the current drawdown level (plotted) and the
maxdrawdown (not plotted) levels
Params:
856
backtrader’s documentation Version-1.9.58.122
TimeReturn
class backtrader.observers.TimeReturn
Params:
• timeframe (default: None) If None then the complete return over the
entire backtested period will be reported
Remember that at any moment of a run the current values can be checked by
looking at the lines by name at index 0.
Trades
class backtrader.observers.Trades
This observer keeps track of full trades and plot the PnL level achieved
when a trade is closed.
A trade is open when a position goes from 0 (or crossing over 0) to X and
is then closed when it goes back to 0 (or crosses over 0 in the opposite
direction)
Params: None
857
backtrader’s documentation Version-1.9.58.122
LogReturns
class backtrader.observers.LogReturns
Params:
• timeframe (default: None) If None then the complete return over the
entire backtested period will be reported
Remember that at any moment of a run the current values can be checked by
looking at the lines by name at index 0.
LogReturns2
class backtrader.observers.LogReturns2
FundValue
858
backtrader’s documentation Version-1.9.58.122
Params: None
FundShares
Params: None
Sizers Reference
FixedSize¶
class backtrader.sizers.FixedSize
This sizer simply returns a fixed size for any operation. Size can be
controlled by number of tranches that a system wishes to use to scale into
trades by specifying the tranches parameter.
Params:
• stake (default: 1)
• tranches (default: 1)
FixedReverser
class backtrader.sizers.FixedReverser
This sizer returns the needes fixed size to reverse an open position or the
fixed size to open one
Params:
• stake (default: 1)
859
backtrader’s documentation Version-1.9.58.122
PercentSizer
class backtrader.sizers.PercentSizer
Params:
AllInSizer
class backtrader.sizers.AllInSizer
Params:
Filters Reference
SessionFilter
class backtrader.filters.SessionFilter(data)
This class can be applied to a data source as a filter and will filter out
intraday bars which fall outside of the regular session times (ie: pre/post
market data)
This is a “non-simple” filter and must manage the stack of the data
(passed during init and __call__)
SessionFilterSimple
class backtrader.filters.SessionFilterSimple(data)
860
backtrader’s documentation Version-1.9.58.122
This class can be applied to a data source as a filter and will filter out
intraday bars which fall outside of the regular session times (ie: pre/post
market data)
This is a “simple” filter and must NOT manage the stack of the data
(passed during init and __call__)
SessionFilller
class backtrader.filters.SessionFiller(data)
Bar Filler for a Data Source inside the declared session start/end times.
The fill bars are constructed using the declared Data Source timeframe and
compression (used to calculate the intervening missing times)
Params:
Upon seeing the 1st valid bar do not fill from the sessionstart up to
that bar
861
backtrader’s documentation Version-1.9.58.122
CalendarDays
class backtrader.filters.CalendarDays(data)
Params:
> 0: The given value to fill 0 or None: Use the last known closing
price -1: Use the midpoint of the last bar (High-Low average)
BarReplayer_Open
class backtrader.filters.BarReplayer_Open(data)
• Open: the opening price of the bar will be used to deliver an initial
price bar in which the four components (OHLC) are equal
The split simulates a replay without the need to use the replay filter.
DaySplitter_Close
class backtrader.filters.DaySplitter_Close(data)
Splits a daily bar in two parts simulating 2 ticks which will be used to
replay the data:
862
backtrader’s documentation Version-1.9.58.122
The Close will be replaced by the average of Open, High and Low
and
The Close price will be used for the four components of the price
The volume will be split amongst the 2 ticks using the parameters:
• closevol (default: 0.5) The value indicate which percentage, in absolute terms from 0.0 to 1.0, has
to be assigned to the closing tick. The rest will be assigned to the OHLX tick.
HeikinAshi
class backtrader.filters.HeikinAshi(data)
The filter remodels the open, high, low, close to make HeikinAshi
candlesticks
See:
• https://en.wikipedia.org/wiki/Candlestick_chart#Heikin_Ashi_candlesticks
• http://stockcharts.com/school/doku.php?id=chart_school:chart_analysis:heikin_ashi
HeikinAshi
class backtrader.filters.Renko(data)
Params:
• hilo (default: False) Use high and low instead of close to decide if
a new brick is needed
• size (default: None) The size to consider for each brick
863
backtrader’s documentation Version-1.9.58.122
See:
• http://stockcharts.com/school/doku.php?id=chart_school:chart_analysis:renko
864