Momentum trading is one of the most effective algorithmic trading strategies that capitalise on the continuity of existing market trends. This automated trading approach uses technical indicators like the Relative Strength Index (RSI), Moving Average Convergence Divergence (MACD), and Stochastic Oscillator to identify and trade in the direction of strong price movements in algo trading systems.
Python for algo trading has changed how traders implement momentum strategies. This trading strategy in Python uses essential libraries, including pandas for data manipulation, numpy for calculations, yfinance for market data, matplotlib for visualisation, and the TA library for technical indicators. Our automated trading implementation demonstrates how to calculate RSI using a 14-period window, MACD with 12/26/9 parameters, and Stochastic Oscillator with a 14-period lookback. The algorithm employs a consensus approach where trades are executed only when at least 2 out of 3 indicators agree, significantly reducing false signals. Python for algo trading excels here by enabling comprehensive error handling with fallback calculations, multi-indicator visualisation through subplots, and robust performance metrics, including annualised returns, Sharpe ratio, and maximum drawdown.
import pandas as pd, numpy as np, matplotlib.pyplot as plt, yfinance as yf
from ta.momentum import RSIIndicator, StochasticOscillator,
from ta.trend import MACD,
# Download historical data
ticker = "INFY"
data = yf.download(ticker, start="2024-01-01", end="2024-12-31")
# Make sure data is properly formatted
data = data.astype(float)
# Convert to float to avoid dimension issues
# Calculate momentum indicators # RSI
try:
rsi_indicator = RSIIndicator(close=data['Close'], window=14)
data['RSI'] = rsi_indicator.rsi()
except ValueError as e:
print(f"RSI calculation error: {e}")
# Alternative calculation method if TA-Lib fails
delta = data['Close'].diff()
gain = delta.where(delta > 0, 0)
loss = -delta.where(delta < 0, 0)
avg_gain = gain.rolling(window=14).mean()
avg_loss = loss.rolling(window=14).mean()
rs = avg_gain / avg_loss data['RSI'] = 100 - (100 / (1 + rs))
# MACD
try:
macd_indicator = MACD(close=data['Close'],
window_slow=26,
window_fast=12,
window_sign=9) data['MACD'] = macd_indicator.macd()
data['MACD_Signal'] = macd_indicator.macd_signal()
data['MACD_Histogram'] = macd_indicator.macd_diff()
except
Exception as e:
print(f"MACD calculation error: {e}")
# Alternative calculation for MACD
ema12 = data['Close'].ewm(span=12, adjust=False).mean()
ema26 = data['Close'].ewm(span=26, adjust=False).mean()
data['MACD'] = ema12 - ema26
data['MACD_Signal'] = data['MACD'].ewm(span=9, adjust=False).mean()
data['MACD_Histogram'] = data['MACD'] - data['MACD_Signal']
# Stochastic Oscillator
try:
stoch = StochasticOscillator(high=data['High'],
low=data['Low'], close=data['Close'], window=14, smooth_window=3)
data['Stoch_K'] = stoch.stoch()
data['Stoch_D'] = stoch.stoch_signal()
except
Exception as e: print(f"Stochastic calculation error: {e}")
# Alternative calculation for Stochastic
low_min = data['Low'].rolling(window=14).min()
high_max = data['High'].rolling(window=14).max()
data['Stoch_K'] = 100 * ((data['Close'] - low_min) / (high_max - low_min))
data['Stoch_D'] = data['Stoch_K'].rolling(window=3).mean()
# Generate trading signals based on multiple indicators
data['RSI_Signal'] = 0
data.loc[data['RSI'] > 50, 'RSI_Signal'] = 1
data.loc[data['RSI'] < 50, 'RSI_Signal'] = -1
data['MACD_Signal_Line'] = 0
data.loc[data['MACD'] > data['MACD_Signal'], 'MACD_Signal_Line'] = 1
data.loc[data['MACD'] < data['MACD_Signal'], 'MACD_Signal_Line'] = -1
data['Stoch_Signal'] = 0
data.loc[(data['Stoch_K'] > data['Stoch_D']) & (data['Stoch_K'] < 80), 'Stoch_Signal'] = 1
data.loc[(data['Stoch_K'] < data['Stoch_D']) & (data['Stoch_K'] > 20), 'Stoch_Signal'] = -1
# Combine signals using a consensus approach
# Trade only when at least 2 out of 3 indicators agree
data['Combined_Signal'] = (data['RSI_Signal'] +
data['MACD_Signal_Line'] + data['Stoch_Signal'])
data['Signal'] = 0 data.loc[data['Combined_Signal'] >= 2, 'Signal'] = 1
# Strong buy signal
data.loc[data['Combined_Signal'] <= -2, 'Signal'] = -1
# Strong sell signal # Create position column
data['Position'] = data['Signal'].shift(1) data['Position'] = data['Position'].fillna(0)
# Calculate returns
data['Return'] = data['Close'].pct_change()
data['Strategy_Return'] = data['Position'] * data['Return']
# Calculate cumulative returns
data['Cumulative_Market_Return'] = (1 + data['Return']).cumprod()
data['Cumulative_Strategy_Return'] = (1 + data['Strategy_Return']).cumprod()
# Filter out NaN values
data = data.dropna()
# Visualize the indicators
fig, (ax1, ax2, ax3, ax4) = plt.subplots(4, 1, figsize=(14, 16), sharex=True)
# Price chart
ax1.plot(data.index, data['Close'])
ax1.set_title(f'{ticker} Price')
ax1.grid(True)
# RSI
ax2.plot(data.index, data['RSI'], label='RSI')
ax2.axhline(y=70, color='r', linestyle='--', alpha=0.5)
ax2.axhline(y=30, color='g', linestyle='--', alpha=0.5)
ax2.axhline(y=50, color='b', linestyle='--', alpha=0.5)
ax2.set_title('RSI')
ax2.grid(True)
ax2.legend()
# MACD
ax3.plot(data.index, data['MACD'], label='MACD')
ax3.plot(data.index, data['MACD_Signal'], label='Signal Line')
ax3.bar(data.index, data['MACD_Histogram'], label='Histogram', alpha=0.5)
ax3.set_title('MACD') ax3.grid(True) ax3.legend()
# Stochastic Oscillator
ax4.plot(data.index, data['Stoch_K'], label='%K')
ax4.plot(data.index, data['Stoch_D'], label='%D')
ax4.axhline(y=80, color='r', linestyle='--', alpha=0.5)
ax4.axhline(y=20, color='g', linestyle='--', alpha=0.5)
ax4.set_title('Stochastic Oscillator')
ax4.grid(True)
ax4.legend()
plt.tight_layout()
plt.show()
# Visualize strategy performance
plt.figure(figsize=(12, 8))
plt.plot(data.index, data['Cumulative_Market_Return'], label=f'{ticker} Buy and Hold')
plt.plot(data.index, data['Cumulative_Strategy_Return'], label='Momentum Strategy')
plt.title('Momentum Trading Strategy Performance')
plt.xlabel('Date')
plt.ylabel('Cumulative Return')
plt.legend()
plt.grid(True)
plt.show()
# Performance metrics
annualized_return = ((data['Cumulative_Strategy_Return'].iloc[-1]) ** (252 / len(data)) - 1) * 100 volatility = data['Strategy_Return'].std() * np.sqrt(252) * 100 sharpe_ratio = (data['Strategy_Return'].mean() / data['Strategy_Return'].std()) * np.sqrt(252) max_drawdown = ((data['Cumulative_Strategy_Return'] / data['Cumulative_Strategy_Return'].cummax()) - 1).min() * 100
print(f"Annualized Return: {annualized_return:.2f}%")
print(f"Annualized Volatility: {volatility:.2f}%")
print(f"Sharpe Ratio: {sharpe_ratio:.2f}")
print(f"Maximum Drawdown: {max_drawdown:.2f}%")
For optimal results in trading, consider combining momentum trading with volatility filters to avoid entering trades during low-volatility periods where momentum signals might be less reliable. You might also implement dynamic parameter adjustment based on market conditions using Python for algo trading capabilities.
The strategies and code examples presented are for educational purposes only and do not constitute financial advice. Always conduct thorough research and consider consulting with a financial experts before implementing any trading strategies with real capital and risk management principles, and ensure compliance with SEBI guidelines before live trading. Trading involves risk—always test strategies before investing real money.