Plotting on the same axis
Following a comment on the blog a slight addition (luckily just a few lines of code) has been made to plotting.
- The abilitiy to plot any indicator on any other indicator
A potential use case:
-
Saving precious screen real estate by plotting some indicators together and having more room to appreciate the OHLC bars
Example: join Stochastic and RSI plots
Of course something has to be taken into account:
-
If the scaling of the indicators is too different, some of the indicators would not be visible.
Example: a MACD oscillating around 0.0 plus/minus 0.5 plotted over a Stochastic which moves across the 0-100 range.
The first implementation is in the development branch on commit …14252c6
A sample script (see below for the full code) let us see the effects
Note
Because the sample strategy does nothing, the standards observers are removed unless activated via a command line switch.
First the script run with no switches.
-
A Simple Moving Average is plotted over the data
-
A MACD, Stochastic and RSI are plotted on own axis/subplots
Execution:
$ ./plot-same-axis.py
And the chart.
The second execution changes the panorama:
-
The Simple Moving Average is moved to a subplot
-
The MACD is hidden
-
The RSI is plotted over the Stochastic (the y-axis range is compatible: 0-100)
This is achieved by setting the
plotinfo.plotmaster
value of the indicator to the other indicator to be plotted onto.In this case and because the local variables in
__init__
are namedstoc
for Stochastic andrsi
for RSI, it looks like:rsi.plotinfo.plotmaster = stoc
Execution:
$ ./plot-same-axis.py --smasubplot --nomacdplot --rsioverstoc
The chart.
And to check the incompatibility of scales, let’s try plotting the rsi over the SMA:
$ ./plot-same-axis.py --rsiovermacd
The chart.
The RSI label shows up with the data and the SMA, but the scale is in the 3400-4200 range and hence … no traces of the RSI.
A further futile attempt is to place the SMA on a subplot and again plot the RSI on the SMA
$ ./plot-same-axis.py –rsiovermacd –smasubplot
The chart.
The label is clear but all that remains from the RSI is a faint blue line at the bottom of the SMA plot.
Note
Added multi-line indicator plotted over another indicator
Going in the other direction, let’s plot a multi-line indicator on another indicator. Let’s plot the Stochastic on the RSI:
$ ./plot-same-axis.py --stocrsi
It works. The Stochastic
label shows up and the 2 lines K%
and D%
too. But the lines are not “named” because we have got the name of the
indicator.
In the code, the current setting would be:
stoc.plotinfo.plotmaster = rsi
To have the names of the Stochastic lines displayed instead of the name, we would additionally need:
stoc.plotinfo.plotlinelabels = True
This has been parametrized and a new execution shows it:
$ ./plot-same-axis.py --stocrsi --stocrsilabels
With the chart now showing the name of the Stochasti lines below the name of the RSI line.
The script usage:
$ ./plot-same-axis.py --help
usage: plot-same-axis.py [-h] [--data DATA] [--fromdate FROMDATE]
[--todate TODATE] [--stdstats] [--smasubplot]
[--nomacdplot]
[--rsioverstoc | --rsioversma | --stocrsi]
[--stocrsilabels] [--numfigs NUMFIGS]
Plotting Example
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
--stdstats, -st Show standard observers
--smasubplot, -ss Put SMA on own subplot/axis
--nomacdplot, -nm Hide the indicator from the plot
--rsioverstoc, -ros Plot the RSI indicator on the Stochastic axis
--rsioversma, -rom Plot the RSI indicator on the SMA axis
--stocrsi, -strsi Plot the Stochastic indicator on the RSI axis
--stocrsilabels Plot line names instead of indicator name
--numfigs NUMFIGS, -n NUMFIGS
Plot using numfigs figures
And the code.
from __future__ import (absolute_import, division, print_function,
unicode_literals)
import argparse
import datetime
# The above could be sent to an independent module
import backtrader as bt
import backtrader.feeds as btfeeds
import backtrader.indicators as btind
class PlotStrategy(bt.Strategy):
'''
The strategy does nothing but create indicators for plotting purposes
'''
params = dict(
smasubplot=False, # default for Moving averages
nomacdplot=False,
rsioverstoc=False,
rsioversma=False,
stocrsi=False,
stocrsilabels=False,
)
def __init__(self):
sma = btind.SMA(subplot=self.params.smasubplot)
macd = btind.MACD()
# In SMA we passed plot directly as kwarg, here the plotinfo.plot
# attribute is changed - same effect
macd.plotinfo.plot = not self.params.nomacdplot
# Let's put rsi on stochastic/sma or the other way round
stoc = btind.Stochastic()
rsi = btind.RSI()
if self.params.stocrsi:
stoc.plotinfo.plotmaster = rsi
stoc.plotinfo.plotlinelabels = self.p.stocrsilabels
elif self.params.rsioverstoc:
rsi.plotinfo.plotmaster = stoc
elif self.params.rsioversma:
rsi.plotinfo.plotmaster = sma
def runstrategy():
args = parse_args()
# Create a cerebro
cerebro = bt.Cerebro()
# Get the dates from the args
fromdate = datetime.datetime.strptime(args.fromdate, '%Y-%m-%d')
todate = datetime.datetime.strptime(args.todate, '%Y-%m-%d')
# Create the 1st data
data = btfeeds.BacktraderCSVData(
dataname=args.data,
fromdate=fromdate,
todate=todate)
# Add the 1st data to cerebro
cerebro.adddata(data)
# Add the strategy
cerebro.addstrategy(PlotStrategy,
smasubplot=args.smasubplot,
nomacdplot=args.nomacdplot,
rsioverstoc=args.rsioverstoc,
rsioversma=args.rsioversma,
stocrsi=args.stocrsi,
stocrsilabels=args.stocrsilabels)
# And run it
cerebro.run(stdstats=args.stdstats)
# Plot
cerebro.plot(numfigs=args.numfigs, volume=False)
def parse_args():
parser = argparse.ArgumentParser(description='Plotting Example')
parser.add_argument('--data', '-d',
default='../../datas/2006-day-001.txt',
help='data to add to the system')
parser.add_argument('--fromdate', '-f',
default='2006-01-01',
help='Starting date in YYYY-MM-DD format')
parser.add_argument('--todate', '-t',
default='2006-12-31',
help='Starting date in YYYY-MM-DD format')
parser.add_argument('--stdstats', '-st', action='store_true',
help='Show standard observers')
parser.add_argument('--smasubplot', '-ss', action='store_true',
help='Put SMA on own subplot/axis')
parser.add_argument('--nomacdplot', '-nm', action='store_true',
help='Hide the indicator from the plot')
group = parser.add_mutually_exclusive_group(required=False)
group.add_argument('--rsioverstoc', '-ros', action='store_true',
help='Plot the RSI indicator on the Stochastic axis')
group.add_argument('--rsioversma', '-rom', action='store_true',
help='Plot the RSI indicator on the SMA axis')
group.add_argument('--stocrsi', '-strsi', action='store_true',
help='Plot the Stochastic indicator on the RSI axis')
parser.add_argument('--stocrsilabels', action='store_true',
help='Plot line names instead of indicator name')
parser.add_argument('--numfigs', '-n', default=1,
help='Plot using numfigs figures')
return parser.parse_args()
if __name__ == '__main__':
runstrategy()