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.
Through NSEPython, a comprehensive exploration and computation of Jensen’s Alpha becomes a straightforward endeavor. Let’s go through step by step.
This python code patch is written for NSEPython Library first time.
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}%")
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%
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}%")
TypeError Traceback (most recent call last)
in ()
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' |
return_nifty = ((float(price_today) - float(price_one_year_ago)) / float(price_one_year_ago)) * 100
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%
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)
-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:
Now Let’s refactor the entire work done so far into small functions.
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")
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()
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}")
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
get_alpha("SBIN",365, benchmark="NIFTY BANK")
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.