QuantConnect: Accessing Previous Values

If you are coming to QuantConnect from other platforms, you might be wondering how to access the previous close price or the previous value of an indicator. Like consolidators, the solution/documentation is out there but also like consolidators, new users might not make a connection between the topic name and what they are trying to achieve. What we need is a rolling window!

Rolling Windows

It is fairly common throughout trading platforms to access historical data by indexing. For example, in Backtrader, we simply can reference: self.data.close[-1] This will nicely give us the previous close value. If we want to get the value before that we change [-1]to[-2]! It is so simple because Backtrader stores all close data in a line series object. A line series object is essentially just a long list of stored values. By contrast, QuantConnect just gives you the pure data piece by piece. What you do with that data is up to you. If you never need to access historical data, then there is no benefit in storing it. It will just eat up memory and memory usage should be controlled in an environment where people share resources. Having said that, this doesn’t mean that we cannot or should not store historical data. QuantConnect does provide tools for the job. It is just that we need to set it up ourselves when required. This is where a “Rolling Window” comes into play.
RollingWindow is an array of data that allows for reverse list access semantics, where the object with index [0] refers to the most recent item in the window and index [Length-1] refers to the last item in the window, where Length is the number of elements in the window.
Source: https://www.quantconnect.com/docs/algorithm-reference/rolling-window Although that description might be intimidating to beginners, a rolling window is essentially a storage box. As data comes in, we stuff it into the box so we can find it again later. We can define how big the box is but ultimately, space in the box is limited. Once the storage box is full, we need to take out the first/oldest item before putting a new item in. When we want to access items in the box, we do this by specifying an index value just like the Backtrader example above. See this article for a real beginner look at indexing. It is written for pine script but the concepts apply here.

Visualizing a Rolling Window

Once you understand how a rolling window works, they are dead simple. It is something that just clicks. However, since there is a lot of jargon on the internet, simple concepts can sometimes be made to sound more complex than they are. As such, it will help to visualize how a rolling window works. By doing this, we will also see why QuantConnect chose the name “Rolling Window”. Let’s take our box example. Empty Rolling Window Rolling window with 2 items Finally, it might become clear by now why the name “Rolling Window” is quite appropriate. It is like we are rolling through a conveyor belt of prices.

Adding, Updating and Accessing

Now we know that we want a rolling window, let’s take a look at how to work with one. The rolling window is added during Initialize() with a RollingWindow[]()call. When we do this we need to specify the type of object that will go in our box inside the square brackets []and we also need to specify the size of the box inside the round brackets (). For example: self.tradeBarWindow = RollingWindow[TradeBar](5) Would create a rolling window that will allow us to store up to 5 TradeBars. Following this, we need to add data to our rolling window. We can do this when data is delivered via OnData(). The rolling window has an Add()method (function) we can use to feed the data: self.tradeBarWindow.Add(data["AAPL"]) Accessing the data is as easy as indexing. self.tradeBarWindow[1] We just need to be careful to make sure that the window has data at the index position we are trying to access. For example, if you tried to access Storage Box[2] during the first or second example images above, you would get an error.

Code Example

The code example below takes a step back from the most recent tutorials in order to keep things simple and clear. It builds on the back of the first script tutorial. This allows us to declutter and not confuse readers with code added for plotting, mixing timeframes and trading multiple instruments.
### <summary>
### Simple RSI Strategy intended to provide a minimal algorithm example using
### one indicator
### </summary>
from decimal import *
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(2018,1, 1)   # Set Start Date
        self.SetEndDate(2018,1,10)      # 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)
        # Create our rolling windows
        self.tradeBarWindow = RollingWindow[TradeBar](5) # Store the last 5 values 
        self.rsiWindow = RollingWindow[Decimal](10) # Store the last 10 values
        # Ensure that the Indicator has enough data before trading,. 
    def OnData(self, data):
        '''OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here.

            data: Slice object keyed by symbol containing the stock data
        # Update our rolling windows
        # Wait for windows to be ready.
        if not (self.tradeBarWindow.IsReady and self.rsiWindow.IsReady): return
        self.Debug('{} Current RSI: {}, Prev RSI: {}'.format(self.Time, round(self.rsiWindow[0],2), round(self.rsiWindow[1],2)))
        self.Debug('{} Current Close: {}, Prev Close: {}'.format(self.Time, round(self.tradeBarWindow[0].Close,2), round(self.tradeBarWindow[1].Close,2)))

Code Commentary

The code creates rolling windows to capture TradeBardata. This is done so we can access previous OHLCVvalues. We also create a second rolling window to store RSI indicator values. The difference is that this type of rolling window can accept any Decimalnumber.
# Create our rolling windows
self.tradeBarWindow = RollingWindow[TradeBar](5) # Store the last 5 values 
self.rsiWindow = RollingWindow[Decimal](10) # Store the last 10 values
Although we only print debug for current and previous values in our example code, the windows are larger than 2 to make it clear that these can be any size you like. Next, we update our rolling window during onData()with:
# Update our rolling windows
Predictably, we are adding a TradeBardata from AAPL to the tradeBarWindowand a Decimalvalue from the RSI indicator to the rsiWindow Finally, we should prevent our strategy from doing any actions until our windows are ready. This helps avoid indexing errors as the window is being filled. The following line will return(i.e not execute any code following it) until the windows are full.
# Wait for windows to be ready.
if not (self.tradeBarWindow.IsReady and self.rsiWindow.IsReady): return
We need to be careful to make sure we don’t place this line above the lines where we add the data. If you do this, your windows will never fill and the code following it will never run!

Checking our Results

If you run the code, above, you should see it print the RSI values to the terminal. It is here we can see the current value becoming the previous value on each of the following bars. Comparison of current and previous values

Find This Post Useful?

If this post saved you time and effort, please consider support the site! There are many ways to support us and some won’t even cost you a penny.