Maximizing Profits with Moving Average Crossover Trading Strategies

We talk about using a simple but successful strategy

EODHD APIs
7 min readApr 25, 2024

There are a multitude of trading strategies out there, ranging from technical analysis and candlestick patterns to arbitrage and even Artificial Intelligence (AI). While some strategies are complex and advanced, particularly those involving AI — which has been touted as a near-miraculous solution for profitable trading — this hype is often overstated. Most tested and backtested trading strategies operate on a simple premise: success comes when gains exceed losses. In our experience, the most effective strategies are usually the simplest. Utilizing moving average crossovers effectively can significantly increase the chances of success. In this article, we’ll outline a successful trading strategy using moving average crossovers, and you might be surprised by its simplicity once you understand how it works.

The Basics of Moving Averages

Before diving deeper, it’s crucial to understand the concept of a Simple Moving Average (SMA) in trading. Trading data, often provided by exchanges and data APIs like EODHD APIs, comes in various forms, such as daily candles. Each candle represents a data point that includes OHLCV (Open, High, Low, Close, and Volume) information. If you plot the closing price of a stock, you’ll notice that the line is quite “choppy,” which isn’t very useful for analysis. The goal is to smooth out these fluctuations by calculating a rolling moving average of the closing prices. For instance, taking a 50-day rolling average, commonly known as SMA50, helps in creating a more interpretable and smoother line.

from eodhd import APIClient
import config as cfg

api = APIClient(cfg.API_KEY)

def get_ohlc_data():
df = api.get_historical_data("AAPL", "d")
return df

def calculate_technical_indicators(df):
df_ta = df.copy()
df_ta["sma50"] = df_ta["close"].rolling(50, min_periods=0).mean()
return df_ta

if __name__ == "__main__":
df_apple = get_ohlc_data()
df_apple_ta = calculate_technical_indicators(df_apple)
print(df_apple_ta)
Apple APPL Daily OHLCV
import matplotlib.pyplot as plt
from eodhd import APIClient
import config as cfg

api = APIClient(cfg.API_KEY)

def get_ohlc_data():
df = api.get_historical_data("AAPL", "d")
return df

def calculate_technical_indicators(df):
df_ta = df.copy()
df_ta["sma50"] = df_ta["close"].rolling(50, min_periods=0).mean()
return df_ta

if __name__ == "__main__":
df_apple = get_ohlc_data()
df_apple_ta = calculate_technical_indicators(df_apple)

plt.figure(figsize=(30, 10))
plt.plot(df_apple_ta["close"], color="black", label="Close")
plt.plot(df_apple_ta["sma50"], color="blue", label="SMA50")
plt.ylabel("Price")
plt.xticks(rotation=90)
plt.title(f"Close vs. SMA50")
plt.legend()
plt.show()
Apple AAPL “close” vs “SMA50”

As illustrated, the black line represents the closing price, which appears “choppy”, while the blue line shows the smoothed rolling daily average, providing a clearer view of the price trend.

Moving Average Crossovers

You might wonder if a simple moving average (SMA) is useful by itself — it’s not. The real value comes from comparing two SMAs, like the SMA50 and SMA200. This comparison can reveal important trends in the market.

import matplotlib.pyplot as plt
from eodhd import APIClient
import config as cfg

api = APIClient(cfg.API_KEY)

def get_ohlc_data():
df = api.get_historical_data("AAPL", "d")
return df

def calculate_technical_indicators(df):
df_ta = df.copy()
df_ta["sma50"] = df_ta["close"].rolling(50, min_periods=0).mean()
df_ta["sma200"] = df_ta["close"].rolling(200, min_periods=0).mean()
return df_ta

if __name__ == "__main__":
df_apple = get_ohlc_data()
df_apple_ta = calculate_technical_indicators(df_apple)

plt.figure(figsize=(30, 10))
plt.plot(df_apple_ta["close"], color="black", label="Close")
plt.plot(df_apple_ta["sma50"], color="blue", label="SMA50")
plt.plot(df_apple_ta["sma200"], color="green", label="SMA200")
plt.ylabel("Price")
plt.xticks(rotation=90)
plt.title(f"Close vs. SMA50 vs. SMA200")
plt.legend()
plt.show()
Apple AAPL “close” vs “SMA50” vs “SMA200”

The SMA50 is represented by the blue line and the SMA200 by the green line in the graph above. The blue line is the “short-term moving average” and the green is the “long-term moving average”. Comparing these two gives a strong indication of market direction. For instance, if the SMA50 (short-term) is above the SMA200 (long-term), it suggests a rising market, or a “bull market”. Conversely, if the SMA50 is below the SMA200, it indicates a declining market, or a “bear market”. Many traders use these crossover points as signals to buy or sell, and this approach can be quite effective. Observing the crossover points about the closing price clearly shows this dynamic in action.

While any short-term and long-term moving averages can be compared, the SMA50 and SMA200 are particularly noteworthy. Their crossovers are referred to as the “Golden Cross” when the market is trending up, and the “Death Cross” when trending down. The terms are quite self-explanatory. Other common moving averages like the SMA5, SMA10, SMA20, SMA50, and SMA200 are also frequently used.

You might think that moving average crossovers is a well-known concept with nothing new to add. However, this is the fundamental basis that remains very effective. The real advancement comes from comparing moving average crossovers at different intervals. This is where the strategy gains significant power and can become nearly foolproof.

Exploring Multi-Level Moving Average Crossovers

The trading strategy operates as follows:

Stage 1: Weekly Analysis Using SMA50 and SMA200

First, we retrieve the historical trading data on a weekly basis. Each data point represents one candlestick per week. By plotting and comparing the SMA50 and SMA200, you can assess the long-term health of the market through what are known as the Golden Cross and Death Cross signals. A Golden Cross, where the SMA50 is above the SMA200, indicates a long-term upward trend. Conversely, a Death Cross, where the SMA50 falls below the SMA200, suggests a declining trend. It’s advisable not to trade in markets exhibiting a Death Cross.

A potential complication here is that some exchanges and data providers only offer daily data, not weekly. However, you can use Python’s Pandas library to aggregate daily data into weekly data, creating your own customized weekly dataset.

import pandas as pd
import matplotlib.pyplot as plt
from eodhd import APIClient
import config as cfg

api = APIClient(cfg.API_KEY)


def get_ohlc_data():
df = api.get_historical_data("AAPL", "d", results=1000)
return df


def calculate_technical_indicators(df):
df_ta = df.copy()
df_ta["sma50"] = df_ta["close"].rolling(50, min_periods=0).mean()
df_ta["sma200"] = df_ta["close"].rolling(200, min_periods=0).mean()
return df_ta


if __name__ == "__main__":
df_daily = get_ohlc_data()

df_weekly = df_daily.resample("W").agg(
{
"open": "first",
"high": "max",
"low": "min",
"close": "last",
"adjusted_close": "last",
"volume": "sum",
}
)

df_weekly["symbol"] = "AAPL"
df_weekly["interval"] = "w"
df_weekly = df_weekly[["symbol", "interval", "open", "high", "low", "close", "adjusted_close", "volume"]]

df_weekly_ta = calculate_technical_indicators(df_weekly)

print(df_weekly_ta)

We initially used daily data labeled as “df_daily” in our code examples and then resampled this to weekly data, re-adding the “symbol” and “interval” to the aggregate for clarity.

As a practical note, to acquire 200 weeks of candle data, you’ll need about 1400 days worth of data, accounting for the 7 days per week. With the EODHD API’s Python Library, you can specify `results=1400` in the `get_historical_data` function to achieve this.

Using Apple’s stock (AAPL) as an example might not be ideal since the SMA50 (175.63620000) is currently below the SMA200 (176.28325000) on the weekly charts, which contradicts our first trading rule. However, looking at an index like the S&P 500 on the London Stock Exchange (“HSPX.LSE”) might reveal the SMA50 above the SMA200 on the weekly, fitting the criteria.

Stage 2: Daily Data Comparison

If the weekly data shows the SMA50 above the SMA200 (passing Stage 1), we then examine the daily data to ensure the SMA50 remains above the SMA200. A positive result here allows progression to the next stage.

Stage 3: Hourly Data Comparison

With positive confirmations from both weekly and daily data, we focus on hourly data for a buy signal. The key moment is when the SMA50 crosses above the SMA200 on the hourly chart, providing a triple confirmation which typically indicates a successful trade setup. Similarly, if the SMA50 crosses below the SMA200 on the hourly chart, it signals an opportunity to short sell, potentially profiting as the market declines.

We’ve also tested this strategy with minute data instead of hourly, and while it presents a higher risk and smaller gains, it maintains a near 100% success rate. This approach can be very effective, though it necessitates careful risk management.

How do we know when to sell?

To close a trade, employing a trailing stop loss is effective. For a buy order, where the expectation is that prices will rise, the stop loss should be adjusted to the low of the previous candle. As prices continue to ascend, the stop loss should be updated accordingly to the new lows of subsequent candles. If the price falls, the stop loss will trigger, automatically executing a sell order.

Conversely, for a sell order, where the expectation is that prices will fall, the strategy involves setting the stop loss at the high of the previous candle. As prices decrease, the stop loss should be adjusted downward to the highs of new candles. This way, if the market turns upwards, the stop loss will trigger a sell, closing the position.

Conclusion

In our view, this trading strategy ranks among the most effective, demonstrating an exceptionally high success rate. Based on our extensive experience and thorough evaluation of various trading strategies through backtesting, we’ve found that the most successful strategies are typically the simplest.

A common error we’ve observed is traders crafting overly unique and complex strategies. However, if a strategy is too unique, it may not align with the broader market movements. Ideally, you want to be buying when the majority are buying and selling when others are selling, aiming to react swiftly and not delay your actions. This approach ensures that you’re moving with the market, not against it.

Please note that this article is for informational purposes only and should not be taken as financial advice. We do not bear responsibility for any trading decisions made based on the content of this article. Readers are advised to conduct their research or consult with a qualified financial professional before making any investment decisions.

For those eager to delve deeper into such insightful articles and broaden their understanding of different strategies in financial markets, we invite you to follow our account and subscribe for email notifications.

We publish 2 pieces per week!

Stay tuned for more valuable articles that aim to enhance your data science skills and market analysis capabilities.

--

--

EODHD APIs
EODHD APIs

Written by EODHD APIs

eodhd.com — stock market fundamental and historical prices API for stocks, ETFs, mutual funds and bonds all over the world.

Responses (3)