Use Python to Calculate the Jensen’s Alpha for a stock

Let’s discuss the process of using Python to compute Jensen’s Alpha for a single stock against a benchmark. One can apply the same method in portfolio containing multiple stocks with any benchmark in the same process.

Jensen’s Alpha is a risk-adjusted performance metric that elucidates the excess returns earned by a portfolio over what was anticipated, given its beta, or sensitivity to market movements. This metric furnishes a numerical representation of a portfolio manager’s ability to generate superior returns, while accounting for the systematic risk borne by the portfolio.

Calculating Jensen's Alpha Using NSEPython

Through NSEPython, a comprehensive exploration and computation of Jensen’s Alpha becomes a straightforward endeavor. Let’s go through step by step.

Python Code

This python code patch is written for NSEPython Library first time. 

Part 1 - Stock Returns

In this segment, the nse_eq() function is employed to obtain the current price of SBIN. Additionally, equity_history() function is used to fetch the price of SBIN from one year ago, illustrating an example of how to track a stock’s price history.
				
					from nsepythonserver import *

# Get today's price
today_price = nse_eq("SBIN")['priceInfo']['lastPrice']
print(f"Today's price: {today_price}")


# Get the price from 1 year ago
today = datetime.datetime.today().strftime('%d-%m-%Y')
one_year_ago = (datetime.datetime.today() - datetime.timedelta(days=365)).strftime('%d-%m-%Y')
print(f"Today's date: {today}")
print(f"Date one year ago: {one_year_ago}")

price_1_year_ago = equity_history("SBIN", "EQ", one_year_ago,today)['CH_CLOSING_PRICE'].iloc[0]
print(f"Price 1 year ago: {price_1_year_ago}")

# Calculate the return
historical_return = ((today_price - price_1_year_ago) / price_1_year_ago) * 100
print(f"The historical return of SBIN for the last 1 year is {historical_return:.2f}%")


				
			

Output

				
					Today's price: 552.4
Today's date: 24-10-2023
Date one year ago: 24-10-2022
Price 1 year ago: 571.2
The historical return of SBIN for the last 1 year is -3.29%

				
			

Part 2 - Get the Historical Price of the Benchmark from 1 Year Ago

In this section, the index_history() function is utilized to retrieve the historical data of NIFTY 50 from a year ago till today. The closing prices of NIFTY 50 from the start and end of this period are then employed to compute the historical return.
				
					
# Get today's date and the date from 1 year ago
today = datetime.datetime.today().strftime('%d-%b-%Y')
one_year_ago = (datetime.datetime.today() - datetime.timedelta(days=365)).strftime('%d-%b-%Y')

# Get the historical data
nifty_data = index_history("NIFTY 50", one_year_ago, today)

# Get the closing prices from 1 year ago and today
price_one_year_ago = nifty_data['CLOSE'].iloc[-1]
price_today = nifty_data['CLOSE'].iloc[0]

# Calculate the return
return_nifty = ((price_today - price_one_year_ago) / price_one_year_ago) * 100

print(f"Today's price: {price_today}")
print(f"Today's date: {today}")
print(f"Date one year ago: {one_year_ago}")
print(f"Price 1 year ago: {price_one_year_ago}")
print(f"The historical return of NIFTY 50 for the last 1 year is {return_nifty:.2f}%")
				
			

Output

				
					TypeError                                 Traceback (most recent call last)
<ipython-input-19-979a4571f060> in <cell line: 13>()
     11 
     12 # Calculate the return
---> 13 return_nifty = ((price_today - price_one_year_ago) / price_one_year_ago) * 100
     14 
     15 print(f"Today's price: {price_today}")

TypeError: unsupported operand type(s) for -: 'str' and 'str'
				
			
The error arises because the values retrieved are strings instead of numerical data. You need to convert them to floats before performing the subtraction operation. Here’s the updated line to calculate the return:
				
					return_nifty = ((float(price_today) - float(price_one_year_ago)) / float(price_one_year_ago)) * 100

				
			

Output

				
					Today's price: 19281.75
Today's date: 24-Oct-2023
Date one year ago: 24-Oct-2022
Price 1 year ago: 17730.75
The historical return of NIFTY 50 for the last 1 year is 8.75%
				
			

Part 3 - Computing Jensen's Alpha

n this segment, the get_beta() function is employed to obtain the beta value of SBIN relative to NIFTY 50. Subsequently, the expected return of SBIN is calculated and We determine Jensen’s Alpha.

				
					beta=get_beta(symbol="SBIN",days=365,symbol2="NIFTY 50")
risk_free_rate = .1  # Assuming 10% as the risk-free rate
expected_return = risk_free_rate + beta * (return_nifty - risk_free_rate)
alpha = historical_return - expected_return
print(alpha)
				
			

Output

				
					-1.514805791024175

				
			

An alpha of -1.514805791024175 suggests that the stock (in this case, SBIN) has underperformed compared to the benchmark index (NIFTY 50) over the specified time period (1 year). Here’s what this means:

  1. Negative Alpha: A negative alpha indicates that the stock’s returns were lower than what would be expected based on its risk as measured by beta. In other words, the stock didn’t generate returns in excess of what could have been achieved by investing in a risk-free asset with a similar level of risk.
  2. Underperformance: An alpha below zero suggests that the stock’s performance lagged behind the benchmark index. Investors who chose the benchmark index as an investment would have generated better returns than those who invested in the stock.
  3. Risk-Adjusted Performance: Alpha is a measure of risk-adjusted performance, which means it considers the risk (volatility) associated with the stock’s returns. A negative alpha indicates that the stock’s returns didn’t adequately compensate investors for the level of risk they took on.

Part 4 - Refactoring

Now Let’s refactor the entire work done so far into small functions. 

benchmark_return()

				
					def benchmark_return(index_symbol="NIFTY 50", days=365):
    today = datetime.datetime.today().strftime('%d-%b-%Y')
    one_year_ago = (datetime.datetime.today() - datetime.timedelta(days=days)).strftime('%d-%b-%Y')
    nifty_data = index_history(index_symbol, one_year_ago, today)
    price_one_year_ago = nifty_data['CLOSE'].iloc[-1]
    price_today = nifty_data['CLOSE'].iloc[0]
    return_nifty = ((float(price_today) - float(price_one_year_ago)) / float(price_one_year_ago)) * 100
    
    print(f"Today's price: {price_today}")
    print(f"Today's date: {today}")
    print(f"Date one year ago: {one_year_ago}")
    print(f"Price 1 year ago: {price_one_year_ago}")
    print(f"The historical return of {index_symbol} for the last {days} days is {return_nifty:.2f}%")
    return return_nifty

# Usage:
benchmark_return("NIFTY 50")

				
			

symbol_return()

				
					def symbol_return(symbol="SBIN", days=365):
    today_price = nse_eq(symbol)['priceInfo']['lastPrice']
    today = datetime.datetime.today().strftime('%d-%m-%Y')
    one_year_ago = (datetime.datetime.today() - datetime.timedelta(days=days)).strftime('%d-%m-%Y')
    price_1_year_ago = equity_history(symbol, "EQ", one_year_ago, today)['CH_CLOSING_PRICE'].iloc[0]
    historical_return = ((today_price - price_1_year_ago) / price_1_year_ago) * 100
    
    print(f"Today's price: {today_price}")
    print(f"Today's date: {today}")
    print(f"Date one year ago: {one_year_ago}")
    print(f"Price 1 year ago: {price_1_year_ago}")
    print(f"The historical return of {symbol} for the last {days} days is {historical_return:.2f}%")
    return historical_return 
# Usage:
symbol_return("SBIN")
				
			

Then  stitch them back to make a new function named get_alpha()

Wrapping Up

Here goes the final version of the get_alpha() function. 

				
					def get_alpha(symbol, days=365, benchmark="NIFTY 50", risk_free_rate=0.1):
    historical_return = symbol_return(symbol, days)
    return_benchmark = benchmark_return(benchmark, days)
    beta = get_beta(symbol, days=days, symbol2=benchmark)
    expected_return = risk_free_rate + beta * (return_benchmark - risk_free_rate)
    alpha = historical_return - expected_return
    return alpha

# Usage:
alpha_value = get_alpha("SBIN")
print(f"The alpha value is: {alpha_value}")

				
			

Output

				
					Today's price: 552.4
Today's date: 24-10-2023
Date one year ago: 24-10-2022
Price 1 year ago: 571.2
The historical return of SBIN for the last 365 days is -3.29%
Today's price: 19281.75
Today's date: 24-Oct-2023
Date one year ago: 24-Oct-2022
Price 1 year ago: 17730.75
The historical return of NIFTY 50 for the last 365 days is 8.75%
The alpha value is: -1.514805791024175
				
			
Now, let’s quickly check SBIN’s Alpha against ‘NIFTY Bank’ using our function.
				
					get_alpha("SBIN",365, benchmark="NIFTY BANK")
				
			

Output

				
					Today's price: 552.4
Today's date: 24-10-2023
Date one year ago: 24-10-2022
Price 1 year ago: 571.2
The historical return of SBIN for the last 365 days is -3.29%
Today's price: 43151.20
Today's date: 24-Oct-2023
Date one year ago: 24-Oct-2022
Price 1 year ago: 41304.90
The historical return of NIFTY BANK for the last 365 days is 4.47%
-2.866924960476857
				
			

What insights does it provide about SBIN compared to NIFTY Bank?

The data suggests that over the past year, SBIN has underperformed in comparison to the NIFTY BANK index. The negative alpha value of -2.87 in Dataset  indicates that SBIN didn’t perform as well as the broader banking sector index, either due to SBIN-specific factors or stronger performance by other banks within the NIFTY BANK index. 

Does this indicate a higher likelihood of mean reversion?

A mean reversion theory suggests that prices or returns eventually move back towards their historical average. However, a negative alpha doesn’t necessarily imply a higher chance of mean reversion. 

  • The alpha value is more about the stock’s performance relative to a benchmark, adjusted for the stock’s beta (systematic risk). Individual stock behavior can be complex and influenced by many factors. 
  • Thorough analysis including factors like company fundamentals, sector performance, and broader economic conditions is necessary to make an informed judgment on whether SBIN is likely to experience mean reversion.

Join The Conversation?

Post a comment

Leave a Comment

Your email address will not be published. Required fields are marked *

×Close