Building a Simple Trading Bot in QuantConnect using WallStreetBets Discussion Data
The purpose of this article is to provide a guide into how Quiver Quantitative’s WallStreetBets discussion data can be used to implement an algorithmic trading strategy on the QuantConnect platform using simple Python.
The goal here will not necessarily be to build a successful strategy, but rather to build a simple one that provides a framework for more complex development. The full code for the bot we will be building can be found here.
Step 1: Create an account for QuantConnect
QuantConnect is an open-source platform that allows users to develop, backtest, and trade with algorithmic strategies. This platform will make it easy for us to set up a simple bot to trade off WSB discussion.
Step 2: Add Quiver Quantitative’s WallStreetBets dataset to your account
For this strategy, we will be using the WallStreetBets dataset on QuantConnect. This will give us access to historical data on the number of times different tickers are mentioned in WallStreetBets’ discussion threads. For the purposes of this basic strategy, we will just focus on trading one ticker, $SPY.
Step 3: The Python Script
I’ll show you what the completed script looks like here and then we’ll break it down piece by piece in the article:
You can see that code contains the following three classes, which is how we’ll segment this post:
- SymbolData (For collecting ticker data)
- WallStreamBetsAlphaModel (For creating indicator)
- QuiverWallStreetBetsDataAlgorithm (For trading)
The libraries we will be using are the following:
from AlgorithmImports import *from QuantConnect.Data.Custom.Quiver import *
Step 4: Collecting Ticker Data
The way we can collect data for a specified ticker in Quant connect is:
self.quiver_wsb_symbol = algorithm.AddData(QuiverWallStreetBets, symbol).Symbol
We can use the above along with:
history = algorithm.History(QuiverWallStreetBets, self.quiver_wsb_symbol, 60, Resolution.Daily)
To collect the historic data of the ticker up to a certain time point. We also need to take into consideration when the bot sells a specific ticker then we should make sure we remove the dataset of that ticker as to not slow down the overall algorithm. The way we do this is by adding a new function:
def dispose(self):
self.algorithm.RemoveSecurity(self.quiver_wsb_symbol)
Now altogether we have the following class created for collecting a removing data for an individual ticker. Note the 3 class variables which we will be using, later on, to keep track of certain indicators over time.
Step 5: Creating the Alpha or Indicator
An Alpha algorithm is essentially keeping track of each ticker and checking whether the expected future trend of the ticker will be up or down or neither. The way we do this is by first creating a new class for our alpha. Along with a class variable dictionary that holds all the ticker information. For the initialize function we will set up a mentions threshold to indicate to our bot what the limit is. Below is the setup described in the last few sentences.
class WallStreamBetsAlphaModel(AlphaModel):
symbol_data_by_symbol = {} def __init__(self, mentions_threshold=200):
self.mentions_threshold = mentions_threshold
Next, to create an alpha we must follow the QuantConnect documentation. We will create a new Update function which will be called every time the bot receives a new time slice of data for the tickers we are trading. We can add the following function which will collect all the time slice data of the tickers the algorithmic bot is currently trading and calculate the rolling average of mentions of individual tickers:
def Update(self, algorithm, data):
insights = [] # stores the insight of each ticker # go through all tickers in the universe for the bot
for report in data.Get(QuiverWallStreetBets).Values: bef = self.symbol_data_by_symbol[report.Symbol.Underlying].time_ticker sum_v = bef*self.symbol_data_by_symbol[report.Symbol.Underlying].symb_mentions # get the total sum of mentions before this current time slice self.symbol_data_by_symbol[report.Symbol.Underlying].time_ticker+= 1 sum_v += report.Mentions # total sum of mentions to current time# the below calculates the new average mentions for the specific ticker
self.symbol_data_by_symbol[report.Symbol.Underlying].symb_mentions = sum_v/self.symbol_data_by_symbol[report.Symbol.Underlying].time_ticker
Once the above has been calculated we can then compare the new average value to determine whether this ticker is expected to go up or go down. The following code snippet does exactly that:
if self.symbol_data_by_symbol[report.Symbol.Underlying].symb_mentions > self.mentions_threshold: target_direction = InsightDirection.Upelif self.symbol_data_by_symbol[report.Symbol.Underlying].symb_mentions < self.mentions_threshold: target_direction = InsightDirection.Downelse:
target_direction = None
For the update function once the Insight has been figured out for an individual ticker we must make sure we append it into our insight list. Using the following code we can add and handle the insights generated above for multiple tickers:
try:
self.symbol_data_by_symbol[report.Symbol.Underlying].target_direction = target_directionexcept:
continuetry:
for symbol, symbol_data in self.symbol_data_by_symbol.items(): # Ensure we have security data for the current Slice
if not (data.ContainsKey(symbol) and data[symbol] is not None):
continue if symbol_data.target_direction is not None:
insights += [Insight.Price(symbol, timedelta(1), symbol_data.target_direction)]
symbol_data.target_direction = Noneexcept:
return insightsreturn insights
The last part of this function will be to create the OnSecuritiesChanged function which is called whenever a ticker has been either sold or bought. We want to be able to handle to data of the ticker as to not over-exhaust our system. Thus we can set up the following function to keep track of where we are selling and buying:
def OnSecuritiesChanged(self, algorithm, changes):
for security in changes.AddedSecurities:
symbol = security.Symbol
self.symbol_data_by_symbol[symbol] = SymbolData(algorithm, symbol) for security in changes.RemovedSecurities:
symbol_data = self.symbol_data_by_symbol.pop(security.Symbol, None) if symbol_data:
symbol_data.dispose()
Step 6: Combining the Alpha to trade
The last part of this code will be the Initialize script which handles when the bot starts and ends trading for backtesting as well as the amount of starting cash. We are also able to add tickers that we want this bot to trade, for simplicity we only let the bot trade on the SPY ticker. We can add the ticker to the Universe of tickers the bot can select using this function:
class QuiverWallStreetBetsDataAlgorithm(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2018, 1, 1)
self.SetEndDate(2021, 6, 1)
self.SetCash(100000)
symbols = [Symbol.Create(“SPY”, SecurityType.Equity, Market.USA)]
self.AddUniverseSelection(ManualUniverseSelectionModel(symbols))
Next, we need to add the alpha we create in step 4 to the algorithmic bot. we do this with the following command:
self.AddAlpha(WallStreamBetsAlphaModel())
Lastly, QuantConnect offers individuals the ability to create custom portfolio construction, risk management, and execution functions, but for the sake of this article, we will be using built-in methods to do the job for us. Take a look at the documentation for more information on these methods and how you may be able to customize them on your own. The following will add the different parts to our trading bot:
self.SetPortfolioConstruction(EqualWeightingPortfolioConstructionModel())self.AddRiskManagement(NullRiskManagementModel())self.SetExecution(VolumeWeightedAveragePriceExecutionModel())
Step 8: Back-Testing Algorithmic Bot
Once the algorithm is complete in the QuantConnect IDE, you can simply press the Back-testing button and the algorithm should automatically start running up. When we ran the above code through our backtesting, we were able to see the bot bring in a total of 10% returns when we started the bot in 2018 with 100k in cash.
Not outstanding returns considering how well the market did over the same time period but, as was previously stated, the goal in building this strategy was simplicity not performance. The graph below shows the performance of the strategy over time:
Conclusion
This step-by-step example shows how to create a simple algorithmic bot on top of data on WallStreetBets discussion using QuantConnect’s platform. I hope that you enjoyed reading this article, and I hope that it can serve as a framework for more complex strategies.
Jaskaran Bakshi wrote this article and the strategy, please feel free reach out to him with questions about set-up or implementation.
***All investments involve risk and the past performance of a security or financial product does not guarantee future results or returns. There is always the potential of losing money when you invest in securities or other financial products. This post is not financial advice.