In partnership with

7 Ways to Take Control of Your Legacy

Planning your estate might not sound like the most exciting thing on your to-do list, but trust us, it’s worth it. And with The Investor’s Guide to Estate Planning, preparing isn’t as daunting as it may seem.

Inside, you’ll find {straightforward advice} on tackling key documents to clearly spell out your wishes.

Plus, there’s help for having those all-important family conversations about your financial legacy to make sure everyone’s on the same page (and avoid negative future surprises).

Why leave things to chance when you can take control? Explore ways to start, review or refine your estate plan today with The Investor’s Guide to Estate Planning.

🚀 Your Algo Edge Just Leveled Up — Premium Plans Are Here!🚀

A year in, our Starter, Pro, and Elite Quant Plans are crushing it—members are live-trading bots and booking 1-on-1 wins. Now with annual + lifetime deals for max savings.

Every premium member gets: Full code from every article Private GitHub repos + templates 3–5 deep-dive paid articles/mo Early access + live strategy teardowns

Pick your edge:

  • Starter (€20/mo) → 1 paid article + public repos

  • Builder (€30/mo) → Full code + private repos (most popular)

  • Master (€50/mo) → Two 1-on-1 calls + custom bot built for you

Best deals: 📅 Annual: 2 months FREE 🔒 Lifetime: Own it forever + exclusive perks

First 50 annual/lifetime signups get a free 15-min audit. Don’t wait—the market won’t.

— AlgoEdge Insights Team

Today we are trying to learn to implement a proper momentum trading strategy, i.e. how to set up the trading signals, implement the trade, and optimizing for the best period to hit the trade.

What we are trying to learn?

  1. Basic use of classes

  2. Setting up signals and plotting them

  3. Comparing performance

  4. Optimizing for the best momentum signal

At the end of the day, we want to set up a Simple Moving Average, buy if the price is above it, and close our position once it goes below it. We then want to see what is the BEST Simple Moving Average.

Code

The full end-to-end workflow is available in a Google Colab notebook, exclusively for paid subscribers of my newsletter. Paid subscribers also gain access to the complete article, including the full code snippet in the Google Colab notebook, which is accessible below the paywall at the end of the article. Subscribe now to unlock these benefits

Setting Up The Class

First, we set up a class that plays our momentum trading strategy. This class takes in our closing price data, our expected number of days moving average, our initial capital and our transaction cost multiplier:

class Momentum:
    def __init__(self, data, x, init, tran_cost):
        self.data = pd.DataFrame(data, columns=["Close"])
        self.x = x  # number of days to calculate moving average
        self.init = init  # initial capital
        self.tran_cost = tran_cost  # transaction cost as a fraction

We then set up a function within this class that calculates the moving average based on some X trading days:

def SMA(self):
        """
        Calculate the Simple Moving Average (SMA) based on x days
        
        Returns:
        pd.Series: Simple Moving Average (SMA) based on x days and fills NaN values with Close prices of the same day
        """
        return self.data["Close"].rolling(window=self.x).mean().fillna(self.data["Close"])

Note that here we fill periods where the moving average cannot yet be calculated with that day’s price because we do not want trades before we can calculate the moving average.

Following that, we can implement our trade function. This would be more unruly but what we are essentially doing is:

  • We take the data and calculate the desired Simple Moving Average.

  • Set up our dataframe to keep track of our Position Value, Shares Currently Held, Transaction Cost Paid, Cash Available at any point in time

  • Set up a signal to denote when we should or should not trade

  • We do this by demarcating points in time where the close price is above SMA with 1, then using the diff()function to calculate how our signal has changed

  • That should give us 1 on the points where we need to buy and -1 on the points we need to close our position

  • Now, using a for loop, iterate to trade accordingly and update our position, shares, cost and cash trackers.

  • Create new columns where we calculate the returns for the index as well as the momentum trading strategy.

def trade(self):
        """
        Simulate trading based on the moving average strategy

        Returns:
        pd.DataFrame: DataFrame containing new columns for:
        - trading signals
        - positions
        - shares
        - cash
        - transaction costs
        - returns
        - cumulative returns
        """
        data = self.data.copy()
        data.index = pd.to_datetime(data.index)
        data["SMA"] = self.SMA()

        # Initialize portfolio, shares, cash, and transaction cost
        data["Position"] = 0
        data["Shares"] = 0
        data["Tran_Cost"] = 0
        data["Cash"] = 0

        data["Cash"].iloc[0] = self.init
        data["Position"].iloc[0] = self.init

        # check if price is above or below moving average using pandas
        data["Signal"] = np.where(data["Close"] > data["SMA"], 1, 0)
        data["Signal"] = data["Signal"].diff().fillna(0)
        data["Buy"] = np.where(data["Signal"] == 1, data["Close"], np.nan)
        data["Sell"] = np.where(data["Signal"] == -1, data["Close"], np.nan)

        # Calculate shares and cash
        for i in range(1, len(data)):
            if data["Signal"].iloc[i] == 1:
                # buy as many shares whole (non decimal) as funds allow
                data["Shares"].iloc[i] = data["Cash"].iloc[i - 1] // (data["Close"].iloc[i] * (1 + self.tran_cost))
                data["Tran_Cost"].iloc[i] = data["Shares"].iloc[i] * data["Close"].iloc[i] * self.tran_cost
                data["Cash"].iloc[i] = data["Cash"].iloc[i - 1] - data["Shares"].iloc[i] * data["Close"].iloc[i] - data["Tran_Cost"].iloc[i]
                data["Position"].iloc[i] = data["Shares"].iloc[i] * data["Close"].iloc[i] + data["Cash"].iloc[i]
            elif data["Signal"].iloc[i] == -1:
                data["Cash"].iloc[i] = data["Cash"].iloc[i - 1] + data["Shares"].iloc[i - 1] * data["Close"].iloc[i] * (1 - self.tran_cost)
                data["Shares"].iloc[i] = 0
                data["Position"].iloc[i] = data["Cash"].iloc[i]
            else:
                data["Cash"].iloc[i] = data["Cash"].iloc[i - 1]
                data["Shares"].iloc[i] = data["Shares"].iloc[i - 1]
                data["Position"].iloc[i] = data["Shares"].iloc[i] * data["Close"].iloc[i] + data["Cash"].iloc[i]

        # Calculate returns and cumulative returns
        data["Returns"] = data["Position"].pct_change().fillna(0)
        data["Cum_Returns"] = (1 + data["Returns"]).cumprod()

        # index returns for comparison
        data["Index_Returns"] = data["Close"].pct_change().fillna(0)
        data["Index_Cum_Returns"] = (1 + data["Index_Returns"]).cumprod()

        self.data = data

        return data

Now what we can do to test this function is apply it to S&P500 Index (SPX Index). To do this, we pull the SPX data from Yahoo Finance since inception and initialize the Momentum class using:

  • 200 Day Moving Average

  • Initial Capital of $1 Million

  • 0.1% Transaction Cost

import yfinance as yf

# pull SPX data from Jan 1928
spx = yf.Ticker("^GSPC")
spx_close = spx.history(start="1928-01-01")["Close"]

# Initialize the Momentum class
trade = Momentum(spx_close, 200, 1000000, 0.001)
trade.trade()

This should give us something like the following:

Signal Plotting Function

Now, how do we plot the following? Using the Buy or Sell signal we’ve used…

logo

Subscribe to our premium content to read the rest.

Become a paying subscriber to get access to this post and other subscriber-only content.

Upgrade

Keep Reading

No posts found