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 both Backtrader and Tradingview in their first script posts. It was a simple RSI (Relative Strength Index) indicator strategy attempts to buy a stock when stock is oversold and simply sell the stock when the RSI is indicating the stock is overbought.
On our journey through this post 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
- Selling the stock with a
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.
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!
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.
In the main pane (on right hand side) of the screen, there are three boxes that contain links to documentation, the boot camp and the community forums. Of the three links, the documentation and community links are self-explanatory. However, the boot camp is fairly unique and deserves a few more words.
In summary, 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. 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.
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 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 to supplement this.
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:
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, My Alphas 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.
Time to get our hands dirty. First of all, we need to create a new script. First Click on the “Create New Algorithm” button shown below:
On the left hand side of the screen, there are some prebuilt modules that you can import. Each module falls into a category that has a specific task. For example, Alpha’s generate predictions, aka buy and sell signals and Universe modules help you to intelligently select a stocks based on a number of factors like fundamentals and/or technical indicators. You can see a full list of module categories on the right hand side of the screen.
In the recent past, piecing these modules together was known as creating a “framework” algorithm. The idea was and still is to promote code re-usability and allow users to focus on specific areas like risk management or stock selection. The other option back in the day, was to create something called a “Classic Algorithm” which was essentially a blank canvas that you build yourself from the ground up. Today however, there is no distinction between the two. Instead, the template code you see on screen dynamically updates as you add or remove modules leaving you with what would have been either a “framework” or “classic” algorithm. If you do not select any pre-built modules, you will be left with a classic algorithm and that is what we shall do for this tutorial.
Create a new algorithm
First click on “create new algorithm” as highlighted above without adding any modules. When you do this QuantConnect will a very basic template get you started. This will appear in your “My Projects” folder under the name that was randomly generated for the class in the template.
Once you have done this, you should have a screen which looks a little like this:
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:
Note: The screenshot below was taken before the UI update but the steps remain the same.
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.
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:
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.
Since this is the first post in the getting started series we will go through the lines of code one section at a time.
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. This is what allows us to access API features in our algorithm.
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.
# 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 QCAlgorithm 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.
The following line allows us to import Apple data at a daily resolution;
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:
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.
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 calling
self.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.
Our last chunk of code before we move onto running the script focuses on the trading logic. This all happens inside the
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
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_OS whereas the
RSI_Periodis not needed here and did not have the
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
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.
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.
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.
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!