Constructing a simple Momentum Portfolio using past returns

MomentumLAB
4 min readJul 1, 2024

--

Introduction:

As a quant investor or programmer, leveraging Python to analyze stock data can offer you a competitive edge. In this article, we’ll explore a comprehensive Python-based strategy to analyze stock performance, identify trends, and rank stocks based on momentum.

Influence of Research Papers: Key Insights

Our quant strategy is deeply influenced by several groundbreaking research papers that have shaped the understanding of financial markets and stock performance analysis. Here are the key papers and insights that informed our approach:

  1. Frog in the Pan — Stocks with Smoother Path Give Better Momentum Returns
    Read the paper
  2. 52 Week High Effect — Evidence from India
    Read the paper
  3. Absolute Momentum — Its Overlay on Trend Following
    Read the paper

Why Python for Stock Analysis?

Python has emerged as a preferred tool for financial analysis due to its simplicity, robust libraries, and ease of handling large datasets. With libraries like yfinance, pandas, numpy, and matplotlib, you can fetch, manipulate, and visualize financial data efficiently.

Getting Started: Setting Up Your Environment

Before diving into the analysis, ensure you have the necessary Python libraries installed. You can install them using pip:

pip install yfinance pandas numpy matplotlib

Step 1: Importing Libraries and Initializing Variables

First, import the required libraries and set up the list of stock tickers you wish to analyze. These tickers represent major companies listed on the National Stock Exchange (NSE) of India.

import yfinance as yf
import pandas as pd
import numpy as np
from datetime import datetime, timedelta
import matplotlib.pyplot as plt
tickers = ["RELIANCE.NS", "TCS.NS", "HDFCBANK.NS", ...]  # Add more tickers as needed

Step 2: Fetching Historical Stock Data

Use yfinance to fetch historical stock data for the past two years. The data includes daily closing prices, which are crucial for calculating moving averages and returns.

def get_data(ticker, start_date, end_date):
return yf.download(ticker, start=start_date, end=end_date)
end_date = datetime.today()
start_date = end_date - timedelta(days=365 * 2)
data = {}
for ticker in tickers:
try:
stock_data = get_data(ticker, start_date, end_date)
if len(stock_data) > 0:
data[ticker] = stock_data
except Exception as e:
print(f"Error fetching data for {ticker}: {e}")

Step 3: Calculating Key Indicators

For each stock, calculate the 100-day and 200-day Exponential Moving Averages (EMAs). These EMAs help identify long-term trends and signal potential buying or selling opportunities.

for ticker, df in data.items():
df['EMA100'] = df['Close'].ewm(span=100).mean()
df['EMA200'] = df['Close'].ewm(span=200).mean()

Step 4: Analyzing Stock Performance

We analyze stocks based on several criteria:

  • 1-Year Return: Measures the stock’s performance over the past year.
  • 52-Week High Proximity: Checks if the stock is within 20% of its 52-week high, indicating strong momentum.
  • Percentage of Up Days: Calculates the percentage of positive trading days over the last 6 months.
summary = []
for ticker, df in data.items():
try:
one_year_return = (df['Close'][-1] / df['Close'][-252] - 1) * 100
high_52_week = df['Close'][-252:].max()
within_20_pct_high = df['Close'][-1] >= high_52_week * 0.8
six_month_data = df['Close'][-126:]
up_days = (six_month_data.pct_change() > 0).sum()
up_days_pct = up_days / len(six_month_data) * 100
if (df['Close'][-1] >= df['EMA100'][-1] >= df['EMA200'][-1] and
one_year_return >= 6.5 and
within_20_pct_high and
up_days_pct > 50):
return_6m = (df['Close'][-1] / df['Close'][-126] - 1) * 100
return_3m = (df['Close'][-1] / df['Close'][-63] - 1) * 100
return_1m = (df['Close'][-1] / df['Close'][-21] - 1) * 100
summary.append({
'Ticker': ticker,
'Return_6M': return_6m,
'Return_3M': return_3m,
'Return_1M': return_1m,
})
except Exception as e:
print(f"Error analyzing {ticker}: {e}")

Step 5: Ranking Stocks Based on Performance

Convert the summary into a DataFrame and rank the stocks based on their 6-month, 3-month, and 1-month returns. The final rank is determined by the sum of these individual ranks.

df_summary = pd.DataFrame(summary)
df_summary['Return_6M'] = df_summary['Return_6M'].round(1)
df_summary['Return_3M'] = df_summary['Return_3M'].round(1)
df_summary['Return_1M'] = df_summary['Return_1M'].round(1)
df_summary['Rank_6M'] = df_summary['Return_6M'].rank(ascending=False)
df_summary['Rank_3M'] = df_summary['Return_3M'].rank(ascending=False)
df_summary['Rank_1M'] = df_summary['Return_1M'].rank(ascending=False)
df_summary['Final_Rank'] = df_summary['Rank_6M'] + df_summary['Rank_3M'] + df_summary['Rank_1M']
df_summary_sorted = df_summary.sort_values('Final_Rank').head(30)
df_summary_sorted['Position'] = np.arange(1, len(df_summary_sorted) + 1)

Step 6: Visualizing the Results

Create a table to visualize the top 30 stocks based on the final rank. Highlight the top 15 stocks with a red line to distinguish them from the rest.

tbl_data = []
for i, row in df_summary_sorted.iterrows():
tbl_data.append([row['Ticker'],
row['Return_6M'], row['Rank_6M'],
row['Return_3M'], row['Rank_3M'],
row['Return_1M'], row['Rank_1M'],
row['Final_Rank'], row['Position']])
fig, ax = plt.subplots(figsize=(14, 10))
ax.axis('tight')
ax.axis('off')
col_labels = ['Ticker', 'Return_6M', 'Rank_6M', 'Return_3M', 'Rank_3M', 'Return_1M', 'Rank_1M', 'Final_Rank', 'Position']
table = ax.table(cellText=tbl_data, colLabels=col_labels, cellLoc='center', loc='center')
table.auto_set_font_size(False)
table.set_fontsize(12)
table.scale(1, 1.5)
for i in range(len(col_labels)):
cell = table[(15, i)]
cell.set_edgecolor('red')
cell.set_linewidth(3)
plt.subplots_adjust(left=0.1, top=0.85)
plt.title('Top 30 Stocks Momentum Ranking', fontsize=18, y=1.05)
plt.show()

Results

This is how the results look like :

Momentum ranking based on past 1,3,6 month returns

Conclusion

By following this Python-based strategy, you can efficiently analyze stock data, identify trends, and make data-driven investment decisions. This approach not only saves time but also provides a systematic way to rank and filter stocks based on performance metrics.

Whether you’re a quant investor or a programmer, integrating Python into your stock analysis toolkit can significantly enhance your ability to analyze and interpret financial data.

Link to Github https://github.com/Momentum1ab/MomentumScreener/blob/main/1%2C3%2C6m_MomentumScreener.ipynb

You can watch our detailed video explaining on the methodology of their research here

— — — — — — — — — — — — — — — — — — — — — —

QuantX-Builder for Mastering Momentum Investing. 4 week comprehensive learning programme.

bit.ly/QuantX-MomentumLAB

— — — — — — — — — — — — — — — — — — — — — —

Important Links
Youtube: https://www.youtube.com/@MomentumLab_IN
Twitter: https://x.com/MomentumLab_IN

**Disclaimer:** We are not SEBI registered advisors. Any content shared on or through our digital media channels is for information and education purposes only and should not be treated as investment or trading advice.

--

--

MomentumLAB
MomentumLAB

Written by MomentumLAB

Momentum Investing for DIY investors who believe in India's growth story!

No responses yet