Exploring Our Trading Script

First off, go ahead and get the script from GitHub with this command:

git clone https://github.com/alpacahq/Momentum-Trading-Example.git

Now, you can open it up in your favorite text editor and follow along. Note that near the top of the file, there are placeholders for your API information — your key ID, your secret key, and the URL you want to connect to. You can get all that information from the Alpaca dashboard.

Your secret key goes away after you’re shown it, so save it somewhere secure. If you lose it, though, you can always regenerate your API key to get a new secret.

Replace the placeholder strings with your own information, and the script is ready to run. But before we let it touch even your simulated account’s (entirely make-believe) money, let’s go over what it does. (If you’re more interested in how to get it running on GCP than what it’s doing, skip ahead to the next section.)

Broadly, this is a momentum-based algorithm. We’ll not trade for the first fifteen minutes after the market opens, because those are always pretty hectic. Between the fifteenth minute and the first hour, though, we’ll look for stocks that have increased at least 4% from their close on the previous day. If they’ve done that and they meet some other criteria, we’ll buy them, and we’ll hold them until they either rise high enough (meeting our price target) or fall too low (meeting our ‘stop’ level.)

You’ll notice that below the connection information in the code, there are some additional variables that can be configured. These can be tweaked easily to best suit your needs for the algorithm. There are thousands of stocks available to trade, but not all of them are suitable for a strategy like this.

We filter down the list by looking for a few things — we want a relatively low share price, but not one that’s so low that it behaves more like a penny stock. We also want to be sure that the stock is liquid enough that we’ll get our orders filled. We make sure that the dollar volume of the stock was at least min_last_dv on the previous trading day.

The default_stop and risk parameters are important to making sure that our algorithm stays within acceptable limits. Risk is what percent of our portfolio we’ll allocate to any given position. Since we sell when we hit the stop loss, the amount of cash from our portfolio at risk on a trade is default_stop * risk * account_balance .

I won’t go over how we get our initialization data here — if you want, you can take a look at the code and check out Polygon’s documentation on their ‘ticker’ data. What’s a little more interesting is the fact that we can also stream data in real time from Polygon. (This is also done in a recently-published “HFT-ish” example, another Alpaca day trading algorithm that trades much more frequently than this one and tries to profit from tiny order book imbalances.)

The Polygon.io logo.

Using Alpaca’s Python SDK, we connect to three types of streaming channels. The first is trade_updates , which is simply a connection to Alpaca on which we can hear updates on our orders as they happen. We’ll use this to make sure we’re not submitting multiple open orders at once for a stock and to see whether or not our orders get filled.

The other two channels are A.<symbol> and AM.<symbol> . For each stock that we’re going to watch, we subscribe to those channels to receive updates from Polygon about the price and volume of the stock. The A channel updates every second, whereas the AM channel updates every minute. We aggregate the information from the A channel ourselves so we can do up-to-the-second calculations, but we consider AM to be the source of truth, replacing whatever we’ve aggregated with what comes through that channel. While we might get away with only watching A and relying on our own aggregation, trusting AM gives us a little extra resilience to hiccups in the connection and such.

Once we’ve added the incoming data to our aggregate, if we haven’t already ordered shares of a stock, we check to see if it looks like a good buy. We define a “good buy” as something with a positive, growing MACD that’s been trading at a decent volume and is up over 4% from yesterday’s close so far today. We also want to make sure that it’s maintained its momentum after the open, so we look to see that the price is higher than its highest point during the first fifteen minutes after the market to open. We hope that these stocks will continue to rise in value as the day goes on.

If we have a position in a stock, we also check with each bar that comes in for that stock if it’s time to sell. We sell when the stock has reached either our target price or our stop loss, or if the MACD suggests that the security is losing its momentum and it’s fallen back to our cost basis. Ideally, enough stocks hit the target price we set that we can recover the losses from those that hit the stop loss, with some extra profits on top.

At the end of the trading day, we liquidate any remaining positions we’ve opened at market price. The use of market orders is generally not ideal, but they are used in this case because the potential cost of holding overnight is greater than we were willing to risk on the position. Ideally, we have already liquidated our shares based on our defined stop losses and target prices, but this allows us to catch anything that sneaks by those by trading flat.