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 ScopeWe 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
- Selling the stock with a
We beginBefore 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 LoginAfter 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 (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 LabOn 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.
UniversityThis 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.
APIThe 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:
My ProjectsThis 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 SupportThese 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 ForwardTime 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:
Create a new algorithmFirst 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”. 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: 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 CodeNow 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.
Code CommentarySince 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.
# 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 allocateThe first few lines of code within our
initializemethod 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 DataThe 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:
Adding an IndicatorNow 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_Periodparameter 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 LogicOur 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
self.SetHoldings().The most recent RSI values are retrieved from the
self.RSI_Indobject we created during
initialize(). Becuase we saved it as
self.RSI_Indinstead 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
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.