QuantConnect: Plotting Our First Script

In this post, we are going to build on the RSI script we created back in the first tutorial. Those of you who followed that post will have noted that plotting was ignored. This is because the focus was to produce a minimal, viable, working algorithm. Now we have the basics out of the way, we can start to look at fleshing the script out and adding parts which are not absolutely required but often very helpful. Plotting is one of those items. Although our algorithms never need to look at a plot or a chart in order to make a decision, plotting is often very useful for the creator. This is to not only verify the algorithm is behaving as expected but also help us identify areas for improvement. Just looking at log files does not allow us to use one of our brains most advanced features, pattern recognition!

Tutorial Scope

By the end of this tutorial, we will aim to have fully plotted RSI and Volume Bar indicators. As we progress through it, we should cover the following topcis:
  • One line plotting of an indicator with self.PlotIndicator()
  • Plotting Data with self.Plot()
  • Creating a new custom chart
  • Adding a series to the chart
  • A brief look at SeriesType and ChartType
  • Adding our custom chart to an algorithm
  • Plotting limits

Plotting Concepts

Before we dive into the code, it is worth discussing a little background and some general plotting concepts to give context to the code. Plotting is something which varies a great deal between platforms. For example, in Backtrader all indicators are automatically plotted when added. In fact, if you don’t want to plot them, you need to manually turn them off. In Pine Script, you can just call a plot()function and plot pretty much anything you like at any time. QuantConnect takes a bit of a hybrid approach. Only our Equity, Benchmark and Stock plots are available and plotted by default. Everything else you should plot yourself. Plotting in QuantConnect can be as straightforward as calling a self.Plot() function during OnData(). However, if we want more customization options, users can dive deeper and create custom charts in a way which shares some similarity with creating a plot in matplotlib(a popular Python module for charting). At each stage of the creation process, we can specify options to really customize the chart to our preference. So summary, QuantConnect provides a nice level of flexibility. You can keep things simple if you need to but the tools are there for those willing to pay a slightly increased cost on the learning curve.

Let’s Begin

The code in this tutorial will be built over a few examples. This will allow us to progress from the most basic plotting through to creating a custom plot.

PlotIndicator()

First we will start with PlotIndicator() method (function), a simple relevant helper method that that does exactly what it says on the tin. Furthermore, we can use this in the Initializemethod. This means once we add the plot, we do not need to update it when new data arrives. It is automatically updated for us.
### <summary>
### Simple RSI Strategy intended to provide a minimal algorithm example using
### one indicator with the most basic plotting
### </summary>
class RSIAlgorithm(QCAlgorithm):

    def Initialize(self):
        '''Initialise the data and resolution required, as well as the cash and start-end dates for your algorithm. All algorithms must initialized.'''
        
        # Set our main strategy parameters
        self.SetStartDate(2016,1, 1)   # Set Start Date
        self.SetEndDate(2017,1,1)      # Set End Date
        self.SetCash(10000)            # Set Strategy Cash
        
        RSI_Period    = 14                # RSI Look back period 
        self.RSI_OB   = 60                # RSI Overbought level
        self.RSI_OS   = 40                # RSI Oversold level
        self.Allocate = 0.25              # Percentage of captital to allocate
        
        # Find more symbols here: http://quantconnect.com/data
        self.AddEquity("AAPL", Resolution.Daily)
        
        self.RSI_Ind = self.RSI("AAPL", RSI_Period)
        
        # Ensure that the Indicator has enough data before trading,. 
        self.SetWarmUp(RSI_Period)
        
        # Plot the RSI
        self.PlotIndicator("RSI", self.RSI_Ind)
        
    def OnData(self, data):
        '''OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here.

        Arguments:
            data: Slice object keyed by symbol containing the stock data
        '''
        # Check if we are in the market
        if not self.Portfolio.Invested:
            # If not, we check the RSI Indicator
            if self.RSI_Ind.Current.Value < self.RSI_OS:
                # Buy Apple
                self.SetHoldings("AAPL", self.Allocate)
        else:
            if self.RSI_Ind.Current.Value > self.RSI_OB:
                # Sell Apple 
                self.Liquidate("AAPL")

Mini Commentary

Those just graduating from our first script tutorial might be hard pressed to see the difference with our first script. We are simply adding one extra line to our Initialize()method. self.PlotIndicator("RSI", self.RSI_Ind) This creates a new plot called RSI and will plot whatever value is reported by self.RSI_Ind.Current.Value. Nice and simple!

Running the Algorithm

Let’s run the algorithm and take a look at what we have created. As soon as the backtest is finished, you should see something that looks like this: Plotting the RSI indicator with PlotIndicator I know what you might be thinking…

Where is my Plot?

QuantConnect does not show you any stacked plots by default (stacked means appears under the main chart). As such, you need to select the RSI chart from the right-hand side of the results. Showing how to find your plotted indicator Once you do that, you will see the RSI chart is inserted underneath the equity chart. Plotted RSI

Benchmark and Stockplot

At this point, you may have also noticed the extra “Benchmark” and “Stock Plot” options. The benchmark plot provides an alternative “straight line” benchmark in addition to the S&P500 benchmark which appears on the equity curve. Press it and you will see it appear underneath the RSI chart (assuming you still have it selected). Stockplot is more interesting. Click on the down arrow and you will be able to select AAPL from the list. Only AAPL appears here because it is the only equity we added in the script. Selecting this plot will show you the close prices for AAPL and additionally buy/sell markers. Excellent for gauging whether you are buying/selling at good moments. That is not always easy to decipher from the equity chart.

Plot()

The next plotting method (function) we will take a look at is self.Plot(). This can be used in a simple form when OnData() is called (executed) or it can be used to update a custom chart that we have previously created ourselves. We will look at the former, simple method first before moving onto the latter in our final example. Let’s add some useful Volumeinformation to our strategy. We will do this using the simple plot method first. After doing this, we will also see very quickly that it can be improved a lot by creating a custom chart!
### <summary>
### Simple RSI Strategy intended to provide a minimal algorithm example using
### one indicator with the most basic plotting
### </summary>
class RSIAlgorithm(QCAlgorithm):

    def Initialize(self):
        '''Initialise the data and resolution required, as well as the cash and start-end dates for your algorithm. All algorithms must initialized.'''
        
        # Set our main strategy parameters
        self.SetStartDate(2016,1, 1)   # Set Start Date
        self.SetEndDate(2017,1,1)      # Set End Date
        self.SetCash(10000)            # Set Strategy Cash
        
        RSI_Period    = 14                # RSI Look back period 
        self.RSI_OB   = 60                # RSI Overbought level
        self.RSI_OS   = 40                # RSI Oversold level
        self.Allocate = 0.25              # Percentage of captital to allocate
        
        # Find more symbols here: http://quantconnect.com/data
        self.AddEquity("AAPL", Resolution.Daily)
        
        self.RSI_Ind = self.RSI("AAPL", RSI_Period)
        
        # Ensure that the Indicator has enough data before trading,. 
        self.SetWarmUp(RSI_Period)
        
        # Plot the RSI
        self.PlotIndicator("RSI", self.RSI_Ind)
        
    def OnData(self, data):
        '''OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here.

        Arguments:
            data: Slice object keyed by symbol containing the stock data
        '''
        
        self.Plot('Volume', data["AAPL"].Volume)
        
        # Check if we are in the market
        if not self.Portfolio.Invested:
            # If not, we check the RSI Indicator
            if self.RSI_Ind.Current.Value < self.RSI_OS:
                # Buy Apple
                self.SetHoldings("AAPL", self.Allocate)
        else:
            if self.RSI_Ind.Current.Value > self.RSI_OB:
                # Sell Apple 
                self.Liquidate("AAPL")

Mini Commentary

In the second example, we have simply added the following line to the On_Data()method (function). self.Plot('Volume', data["AAPL"].Volume) This will plot the Volumevalues every time On_Data()is called (In our case, On_Data()is called every time we receive a new daily bar). The first argument 'Volume' controls the name of the chart that will be updated. In this case it is a chart called Volume….. Wait a minute….. what volume chart? We have not added a volume chart yet! Well, it will actually be created behind the scenes using the name you provide (In this case 'Volume'). As such, for this example, you can put any text you like in that argument. If we had created a custom chart (which we will do soon) you could target plotting on that specific chart by giving it the custom charts name.

Running Example 2

After running the backtest you should have an equity chart that looks like this: Plotting Volume overlayed on the Equity chart As you can see, the plot is overlayed on the Equity chart. Furthermore, because Volume values are so much larger than the equity values, the equity bars are obscured. This is because they are sharing the same chart and the same scale/index. So we can see that when we use self.Plot()without setting up a custom chart first, it plots the values you feed it with a set of default values. In this case, one of the default values is to overlay the line on the main equity chart. Due to this, calling self.Plot() without setting up a custom chart first is probably best reserved for occasions when you want a quick and dirty debug plot or for values which share a similar scale to your account equity.

Creating a Custom Chart

In our final example, we will move onto creating a custom chart and look at some of the options which are available to us when doing so.
### <summary>
### Simple RSI Strategy intended to provide a minimal algorithm example using
### one indicator with the most basic plotting
### </summary>

class RSIAlgorithm(QCAlgorithm):

    def Initialize(self):
        '''Initialise the data and resolution required, as well as the cash and start-end dates for your algorithm. All algorithms must initialized.'''
        
        # Set our main strategy parameters
        self.SetStartDate(2016,1, 1)   # Set Start Date
        self.SetEndDate(2017,1,1)      # Set End Date
        self.SetCash(10000)            # Set Strategy Cash
        
        RSI_Period    = 14                # RSI Look back period 
        self.RSI_OB   = 60                # RSI Overbought level
        self.RSI_OS   = 40                # RSI Oversold level
        self.Allocate = 0.25              # Percentage of captital to allocate
        
        # Find more symbols here: http://quantconnect.com/data
        self.AddEquity("AAPL", Resolution.Daily)
        
        self.RSI_Ind = self.RSI("AAPL", RSI_Period)
        
        # Ensure that the Indicator has enough data before trading,. 
        self.SetWarmUp(RSI_Period)
        
        # Plot the RSI
        self.PlotIndicator("RSI", self.RSI_Ind)
        
        # Create a custom volume chart
        VolChart = Chart("Volume", ChartType.Stacked)
        VolChart.AddSeries(Series('Buying Volume', SeriesType.Bar))
        VolChart.AddSeries(Series('Selling Volume', SeriesType.Bar))
        self.AddChart(VolChart)
        
    def OnData(self, data):
        '''OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here.

        Arguments:
            data: Slice object keyed by symbol containing the stock data
        '''
        if data["AAPL"].Close >= data["AAPL"].Open:
            self.Plot('Volume', 'Buying Volume', data["AAPL"].Volume)
        else:
            self.Plot('Volume', 'Selling Volume', data["AAPL"].Volume)
        
        # Check if we are in the market
        if not self.Portfolio.Invested:
            # If not, we check the RSI Indicator
            if self.RSI_Ind.Current.Value < self.RSI_OS:
                # Buy Apple
                self.SetHoldings("AAPL", self.Allocate)
        else:
            if self.RSI_Ind.Current.Value > self.RSI_OB:
                # Sell Apple 
                self.Liquidate("AAPL")

Commentary

The code to configure the chart appears in our  Initializemethod. It is here that we create our chart and customize it to our taste. So let’s take s look at our new code and discuss some of the customization options available. To start we create a new chart with: VolChart = Chart("Volume", ChartType.Stacked) It is here we specify ourChartType and we have the following options available to us:
  • Chart.Stacked: Used in our example. This means the chart will appear as a separate chart below the main equity chart.
  • Chart.Overlay: This means that the chart will be overlayed on top of the main equity chart.
Next, we add some data series to the chart. I.e things we want to plot. Since we are interested in volume, we will create two series. One for “buying volume” and one for “selling volume”. Buying volume just means that the candle/bar closed up (green) and so it signifies that the volume seen during that period saw more units bought than sold (else how would the price close up?). Conversely, “selling volume” is the opposite. A Series can be displayed in many different ways and as such QuantConnect provides quite a few types. We can specify Line, Scatter, Candle, Bar, Flag, StackedArea and Pie SeriesTypeoptions. In our example, we use SeriesType.Baras this is the industry standard way of displaying volume information. Finally, we add the chart to our algorithm with self.AddChart(). If we don’t do this, when we try to plot our volume values during OnData(), the chart won’t exist in the Algorithm. As such, Quanconnect will just create a new plot using the default settings like we say in example 2.

On Data

Ok, so now we have our chart setup and ready, we now just need to populate it! Because we created two series (buying and selling volume), we can’t just blindly add volume to both of them. Instead, we must first make a little check to see what type of volume we have and then plot to the correct series. This is exactly what we do with the following lines:
        if data["AAPL"].Close >= data["AAPL"].Open:
            self.Plot('Volume', 'Buying Volume', data["AAPL"].Volume)
        else:
            self.Plot('Volume', 'Selling Volume', data["AAPL"].Volume)
Some readers might take exception to the >=condition on the first line. After all, if the Closeis equal to the Openthen we do not really have buying volume. If you fall into that category, you can just add a third series to the chart.

Running Example 3

Once we run the script you should have a volume chart that look like this: Plotting tutorial - Final Volume Chart

Plotting Limits

Before we finish, we should point out that QuantConnect limits the number of points which can be charted on any given plot. The assumption is that this is limited for resource reasons. Afterall, they have vast amounts of tick data available and plotting tick data over a long period of time has got to be a recipe for system strain. Go ahead and change the line self.AddEquity("AAPL", Resolution.Daily)toself.AddEquity("AAPL", Resolution.Minute). Now run the script once again, you should notice a warning in the terminal that looks like this: Plotting Limit - Terminal output Also if you look at your RSI plot, you will see that it stops plotting once the plotting limit is reached. Plotting Limits - RSI Indicator As such it makes sense to select specific date ranges when you want to use plotting to verify the algorithm is performing as expected or generate new ideas.

Find This Post Useful?

If this post saved you time and effort, please consider donating a coffee to support the site!  

3PUY12Tgp8xynrMCbBdLE56DShzCbxFG8i

0xb90252f1a0af77a43c499102be8a08ce5e190e01

Le3ykk29k2TjD3ZFoEyWTFzJgUu9Q9v6Fq