QuantConnect: First Script Tutorial

Welcome to the first QuantConnect tutorial in the getting started series. This post will attempt to guide readers through every step of creating a simple RSI strategy. There will be no bells or whistles on the algorithm. We will instead focus on providing an absolute minimum viable script to understand the core concepts and build on in the future. So without waffling too much, let’s dive in!

QuantConnect Tutorial Scope

We are going to mirror the exact same strategy that we developed for Backtrader and Tradingview’s respective first script posts. That is a simple RSI (Relative Strength Index) indicator strategy that will attempt to buy a stock when it is indicating that the stock is oversold and attempt to sell the stock when the RSI is indicating the stock is overbought. In putting this together we will cover the following core concepts:
  • Creating a new script and accessing the editor
  • Creating a new strategy class
  • Adding an Indicator
  • Accessing Indicator values
  • Buying the stock with a SetHoldings()
  • Selling the stock with a Liquidate()
Of course, there is so much more we could do to flesh this algorithm out (such as plotting, logging, debugging etc) but I believe starting with the absolute minimum keeps things simple and allows us to focus on the basics.

We begin

Before we can do anything, head over to QuantConnect.com and sign up for an account. Click on the “Sign In” button on the top right-hand corner of the site. You will be presented with a few sign up options. I doubt the tutorial needs to cover signing up in detail! Just pick the sign-up option that suits you, follow the instructions and log in!

First Login

After logging in for the first time, you will be taken to the “terminal” page. This page is the same page you would see when pressing the “Algorithm Lab” link in the header. It is the primary place for developing algorithms and testing. Note: This link is often shortened to just “Lab” if you are not working on a widescreen/high-resolution monitor. Algorithm Lab Getting Started Links In the main (right) pane of the screen, there are three boxes contain links to getting started documentation and tutorials. Of the three, the documentation and community links are self-explanatory. By comparison, the boot camp is fairly unique and deserves a few more words. The boot camp is a place to interactively learn some key concepts. Each boot camp provides an introduction to one or more key concepts and tests your ability with an interactive test at the end. It is a great idea in principle but I found this to be hit and miss. Whilst it is great to actually have guided tutorials through some of the key concepts, it can be tricky for QuantConnect to verify that your code passes the test. After all, there are often many ways to achieve the same thing when programming. Furthermore, I found myself in the situation where the test was failing even though I had copied the “correct” solution from the hints/answers section. Having said that, I do still recommend new users take some time to go over the boot camps as there is a lot of good information there!

Key Areas of the Lab

On the left-hand side of the screen, we have another smaller pane and a vertical menu bar. Clicking on any of the items will result in a popout bar appearing with further relevant information. The image below highlights the areas we will take a deeper look at below. Terminal after logging in

University

This is a great resource for providing code snippets and examples. The best way of learning the framework is to see how the experts to it! The only problem is that sometimes you just don’t know what you are looking for. Especially so if you are new to the platform. In other words, you might know how to describe what you want but not the keyword. For example, would you know to look at the “Rolling Window” section if you were trying to figure out how to access the previous close value?  As such, a good google or search in the community always helps supplement this.

API

The API section provides a tree view of all the available methods (functions) and attributes (variables) that are available to the strategy. If you are not used to reading API documentation, you might find this a little daunting at first. Stick with it though, there is a lot of good information here! As with anything, there are a few gripes though;
  • It automatically searches as you type. Often slowing and attempting to search before you have finished typing or pause for thought.
  • It automatically expands all search results which can get a bit messy if lots of results are returned
  • Some information is a second layer deep. For example, try searching to API to see what data resolutions are supported. It will return the following:
At first glance, you may believe there is nothing relevant here. In actual fact, the information we seek is available, we just need to expand the results and click on the resolution parameter to get further details on what resolutions are available:

My Projects

This is where your library of scripts and projects are located. It almost mirrors the left-hand pane that you will see after logging in. The reason for this duplication will become obvious once we start our project and the left-hand pane changes!

Data Manager, Live Projects and Support

These other areas, although equally important, are probably out of the scope of an initial first script tutorial. We may cover those in the future as the series progresses.

Moving Forward

Time to get our hands dirty. First of all, we need to create a new script. You may notice we have two choices available to us:
  • New Classic Algorithm
  • New Framework Algorithm:
Classic algorithms are kind of like a blank canvas where we start from scratch and put everything we need for the strategy into the script. By comparison, framework algorithms use building blocks to create new strategies from existing code. QuantConnect would like to encourage users to write re-usable code and therefore have defined some logical building blocks that should be re-usable between projects. These building blocks are split into categories such as “Universe Selection”, “Execution”, “Risk Management” etc. Other than promoting re-usability, it also allows people who are talented at a certain aspect to focus on that area in isolation. For the purposes of this tutorial, we will create a simple classic algorithm as we want to build from the foundations first and write a complete strategy.

Create a new algorithm

First click on “create new classic algorithm”. When you do this QuantConnect will clone a “Basic Template Algorithm” script to get you started. This will appear in your “My Projects” folder under the name “Basic Template Algorithm”. QuantConnect Tutorial: Create new classic Algorithm Once you have done this, you should have a screen which looks a little like this: QuantConnect Tutorial Basic Template Let’s change the name of the project to something more suitable. I have called mine “First Script: RSI Strategy”. You can do this by clicking on the name in the left-hand pane: You may notice that the left-hand pane also has several other options available to you. For example, adding other files to the project or collaborating with other users via the “share” button.  However, we don’t need to touch these in order to create a basic first script. As such, we won’t go into detail and focus on the task in-hand.

The Code

Now that we have our project open and ready, we can get to work. Delete everything in the right-hand pane and copy the code below into it.
### <summary>
### Simple RSI Strategy intended to provide a minimal algorithm example using
### one indicator
### </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(2013,1, 1)   # Set Start Date
        self.SetEndDate(2015,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)
        
    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")

Where is the save button?

There is no save button, your project should be saved automatically every time you make a build or close the project.  Speaking of which, the platform will automatically build the script every time you make a change to the code. If the build fails, it is generally because of a syntax error. When this happens you will see the following message in the terminal and a highlight in the code: Screenshot Syntax Error HighlightingScreenshot Showing an error in the terminal This is all nice but there is a couple of potential areas of confusion/annoyance:
  • Because the project will auto-build, it can sometimes build before you have finished writing your code resulting in some unintended errors.
  • When you fix an issue, it will still be highlighted as an error until the next build is complete. This can be a bit confusing at first when you believe you have fixed the issue but it is still showing an error. The feedback is not immediate like you would find on a local development environment. In fairness, it should be pointed out that you are not left waiting long. It is just not immediate feedback as you may be used to.

Code Commentary

Since this is the first post in the getting started series we will go through the lines of code one section at a time. class RSIAlgorithm(QCAlgorithm): Our first line creates our algorithm. We have called it RSIAlgorithm but you can rename this to anything you like. The QCAlgorithm in inside the brackets () allows us to “inherit” (in other words use) functions and variables from the QCAlgorithm class. In other words, this is what allows us to access API features in our algorithm. You will see this in action shortly: def Initialize(self): This is the first method (function) that we add to our algorithm. Every algorithm needs this method. It is “called” (run/executed) before the backtest is started. As such, it can be used to set variables, add indicators and a whole host of other things that define the core structure/blueprints of your algorithm.

Setting Parameters

        # Set our main strategy parameters
        self.SetStartDate(2013,1, 1)   # Set Start Date
        self.SetEndDate(2015,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
The first few lines of code within our initialize method is where we set a few parameters that the algorithm will use. These can actually dynamically passed from the web UI if you are working and sharing a project with someone who is not comfortable (or should not be) changing the code. This is something we may add in the future. It is during our parameter setup that we use the QuantConnect API for the first time. Do you remember when we were talking about inheriting methods (functions) and features from the QCAlgorith in the class section? Well, self.SetStartDate()is a method that we inherited and we will use to set the date which the test will start.

Adding Data

The next line allows us to import Apple data at a daily resolution; self.AddEquity("AAPL", Resolution.Daily) As you can see, we simply pass the Symbol/Ticker as the first argument and the desired data resolution as the second argument. Available resolutions are:
  • Resolution.Tick
  • Resolution.Second
  • Resolution.Minute
  • Resolution.Hour
  • Resolution.Daily
This example is the absolute minimum you need to get some data into the algorithm. However, there are some additional optional parameters you can specify. If you are interested, type “AddEquity” into the API search on the left-hand side of the screen: Finally, we are not limited to just Equities. We can import Forex, Futures, Options, Crypto and CFD’s (Contracts for difference) into the algorithm. When you do this, you need to use a different method (function) call from the API.
  • self.AddForex()
  • self.AddFuture()
  • self.AddOption()
  • self.AddCrypto()
  • self.AddCfd()

Adding an Indicator

Now we have data available, we need to add our RSI indicator so we can make some trading decisions based on it. To do this we use the following lines:
        self.RSI_Ind = self.RSI("AAPL", RSI_Period)
        
        # Ensure that the Indicator has enough data before trading,. 
        self.SetWarmUp(RSI_Period)
First, we need to create the indicator. We do this by callingself.RSI. Then we pass it the ticker that we want it to operate on. RSI_Periodis the parameter we set in the parameters section above and we use it to set a lookback period on the RSI indicator. For those of you who may be new to trading, the lookback period is the number of bars (candles on the chart or data points) that are used to calculate the final RSI value. Finally, we need to call self.SetWarmUp(). This will ensure that the algorithm does not start trading until the indicator has enough data to make the RSI calculations. This is why we pass it the same RSI_Period parameter as the RSI indicator. It will ensure we have 14 bars of data before starting to trade. Note that if you have more than one indicator, you should pass it the value of the indicator which needs to most data before it is ready.

Trading Logic

Our last chunk of code before we move onto running the script focuses on the trading logic. This all happens inside the OnData()method: def OnData(self, data): This method is called (run/executed) every time we have a new bar of data. In this case, since we asked for Resolution.Dailydata, this will be every day. Once we receive new data, our RSI indicator will be updated and we can check the current value to see if we want to trade.
        # 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")
Our first line in this code block is if not self.Portfolio.Invested. This will check to see if we are in a position or not. If we are are not (hence if not), then we will check to see if the RSI is oversold. If it is, we buy some stock using self.SetHoldings(). The most recent RSI values are retrieved from the self.RSI_Ind object we created during initialize(). Becuase we saved it as self.RSI_Ind instead of just RSI_Ind, we can access it here. You may also notice we did this for the overbought and oversold parameters. They were saved as self.RSI_OB and self.RSI_OS whereas the RSI_Periodis not needed here and did not have the self.prefix. If we do happen to be oversold, then we call self.SetHoldings()and simply pass it the ticker/symbol and tell it what percentage of our portfolio we want to allocate to it. This is where we reference our self.Allocateparameter. Finally, once we are in a position (self.Portiolio.Invested == true), we start to check whether Apple is now overbought. If so, we call self.Liquidate()and pass it our ticker/symbol. This will then sell all of our shares in the stock.

Running and Results

Now we have a complete algorithm, it is time to run it. To do this, click on the backtest button in the top right-hand corner of the main pane. QuantConnect Tutorial: Build and Run The project will then be built (if it is not already built). After this, you will need to wait a few moments whilst the backtest is analyzed and run. This can take some time which is one of the negatives (but an understandable and necessary one) highlighted in the series introduction post. Once the analysis is finished and the backtest is ready to run, you will see the equity chart appear. Each time you run it, the backtest is placed in a new tab and given a funky name to help you refer back to it later. The backtest will start running and if there is a lot of data to process, you will actually see the equity chart and results updating as it cycles through the data. This can add a little bit of spectator excitement to the process as you live a little through the drawdowns willing your algorithm on to perform! When the test is finished, you will be left with the results. You may notice that the main chart shows your equity, not the asset price chart like you might be used to on other platforms. First script results showing equity chart In addition to this, you will see some in-depth statistics allowing you to really dig into the performance of your algorithm in more detail. First script results showing statistics First Script Results showing rolling statistics And that should be enough for the first post in the series. Place a comment in the section below if any of this is unclear!

Find This Post Useful?

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


Dontate with PayPal using any payment method you are comfortable with. 


3PUY12Tgp8xynrMCbBdLE56DShzCbxFG8i

0x9c32a2e1e4a06b0995777ac86745c0db1c13bdfc

LUph5xfqvn2bNfthhEcw9QiVLBYeztacFR