We're going to create a Simple Moving Average crossover strategy in this finance with Python tutorial, which will allow us to get comfortable with creating our own algorithm and utilizing Quantopian's features. To start, head to your Algorithms tab and then choose the "New Algorithm" button. Here, you can name your algorithm whatever you like, and then you should have some starting code like:
# Put any initialization logic here. The context object will be passed to # the other methods in your algorithm. def initialize(context): pass # Will be called on every trade event for the securities you specify. def handle_data(context, data): # Implement your algorithm logic here. # data[sid(X)] holds the trade event data for that security. # context.portfolio holds the current portfolio state. # Place orders with the order(SID, amount) method. # TODO: implement your own logic here. order(sid(24), 50)
As you can see, some initial code has been prepared for us.
If you're not familiar with moving averages, what they do is take a certain number of "windows" of data. In the case of running against daily prices, one window would be one day. If you took a 20 moving average, this would mean a 20 day moving average. From here, the idea is let's say you have a 20 moving average and a 50 moving average. Plotting this on a graph might look something like:
Here, the blue line is the stock price, the red line is the 20 moving average and the yellow line is the 50 moving average. The idea is that when the 20 moving average, which reacts faster, moves above the 50 moving average, it means the price might be trending up, and we may want to invest. Conversely, if the 20 moving average falls below the 50 moving average, this signals maybe that the price is trending down, and that we might want to either sell or investment or even short sell the company.
Looking at the graph above, it looks to us like we'd do pretty well. We miss the absolute peaks and troughs of the price, but, overall, we think we'd do alright with this strategy.
Every time you create an algorithm with Zipline or Quantopian, you will need to have the initialize
and handle_data
methods. They should be included in every algorithm you start new.
The initialize
method runs once upon the starting of the algorithm (or once a day if you are running the algorithm live in real time). Handle_data
runs once per period. In our case, we're running on daily data, so this means it will run once per day.
Within our initialize
method, we usually pass this context parameter. Context is a Python Dictionary, which is what we'll use to track what we might otherwise use global variables for. Context will track various aspects of our trading algorithm as time goes on, so we can reference these things within our script.
Within our initialize
method:
def initialize(context): context.security = symbol('SPY')
What this does, is it sets our security for trading to the SPY. This is the Spyder S&P 500 ETF (Exchange Traded Fund), which is a method that we can use to trade the S&P 500 index.
That's all we'll do for now in our initialize
method, next we will begin our handle_data
method:
def handle_data(context, data): MA1 = data[context.security].mavg(50) MA2 = data[context.security].mavg(200)
Notice here that we pass context and a new parameter called data. Data tracks the current data of companies within our "trading universe." The universe is the collection of companies we're plausibly interested in maybe investing into. In our case, we set this universe at the beginning in the initialize
method, setting our entire universe to the SPY.
Put simply, the context var is used to track our current investment situation, with things like our portfolio and cash. The data variable is used to track our universe of companies and their information.
.mavg() is a method built into Quantopian, and "data[context.security]" is us referencing the key by this name in our context dictionary.
We could call these context.MA1 and context.MA2 if we wanted to store these to our context dictionary and use it outside of our handle_data
method, but we do not need to access this data outside of here, so we'll just make them local variables.
Now that we have the moving averages calculated, we're ready for more logic. In order to trade, we need to have logic like if the MAs have crossed over, but also, before we can make a trade, we need to see if we have enough money to make a purchase, we need to know the price of the security, and we should check to see if we already have this position. To do this, we add the following to our handle_data
method:
current_price = data[context.security].price current_positions = context.portfolio.positions[symbol('SPY')].amount cash = context.portfolio.cash
We grab current price by referencing data, which is our way of tracking our universe of companies (currently just the S&P 500 ETF $SPY). Next, we check to see any current positions that we have by referencing our context.portfolio. In here, we can reference all sorts of things in regards to our portfolio, but, right now, we just want to check our positions. This returns a dictionary of all of your positions, the amount, how much has been filled, and so on. So we're interested in a specific position in a company, so we do context.portfolio.positions[symbol('SPY')]. From here, our only concern right now is to just see if we have any investment at all, so the attribute we care about most is the amount of positions we have, so we use .amount at the end.
Up to now, we've created the information required for us to know before we actually use some logic to execute trades, but we haven't written anything to actually do the trading. That's what we're going to cover in the next tutorial.