import yfinance as yf
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
# Get NIFTY 50 stock symbols
stocks = pd.read_html('https://en.wikipedia.org/wiki/NIFTY_50')[2]['Symbol']
stocks = stocks + '.NS'
# Download historical data
df = yf.download(stocks.to_list(), start='2014-01-01')
df_close = df['Adj Close']
df_dret = df_close.pct_change()
df_mret = (df_dret + 1).resample('M').prod() - 1
# Calculate 12-month rolling returns
df_mret_12 = df_mret.rolling(12).apply(lambda x: (x + 1).prod() - 1).dropna()
# Function to calculate top performers for a given date
def top_performers(date):
top = df_mret_12.loc[date].nlargest(10)
return df_mret.loc[date:][1:3][top.index].mean(axis=1).values
# Calculate bimonthly returns of the strategy
bimonthly_ret = []
for date in df_mret_12.index[:-2:2]: # Adjust index for 2-month rebalancing
try:
bimonthly_ret.extend(top_performers(date)) #we use extend not append
except IndexError:
continue
print(bimonthly_ret[0:3])
# Calculate portfolio value over time
portfolio_value = [1]
for r in bimonthly_ret:
portfolio_value.append(portfolio_value[-1] * (1 + r))
# Create a DataFrame for portfolio value
portfolio_dates = df_mret_12.index[1:-1:1] # Adjust dates for 1-month periods
portfolio_df = pd.DataFrame({
'Date': portfolio_dates,
'Portfolio Value': portfolio_value[1:]
})
portfolio_df.set_index('Date', inplace=True)
# Calculate drawdown
portfolio_df['Drawdown'] = portfolio_df['Portfolio Value'] / portfolio_df['Portfolio Value'].cummax() - 1
# Calculate Sharpe ratio
annualized_return = np.prod([1 + r for r in bimonthly_ret]) ** (12 / len(bimonthly_ret) ) - 1
annualized_std = np.std(bimonthly_ret) * np.sqrt(12)
sharpe_ratio = annualized_return / annualized_std
# Calculate Beta
# Use NIFTY 50 index as benchmark
nifty50 = yf.download('^NSEI', start='2014-01-01')['Adj Close']
nifty50_mret = nifty50.pct_change().resample('M').apply(lambda x: (x + 1).prod() - 1).dropna()
cov_matrix = np.cov(nifty50_mret[df_mret_12.index[1]:df_mret_12.index[-2]], bimonthly_ret)
beta = cov_matrix[0, 1] / cov_matrix[0, 0]
print(f"Annualized Return: {annualized_return:.2%}")
print(f"Annualized Volatility: {annualized_std:.2%}")
print(f"Sharpe Ratio: {sharpe_ratio:.2f}")
print(f"Beta: {beta:.2f}")
print(f"Maximum Drawdown: {portfolio_df['Drawdown'].min():.2%}")
# Plot portfolio value over time
plt.figure(figsize=(10, 7))
plt.plot(portfolio_df['Portfolio Value'], label='Portfolio Value')
plt.title('Portfolio Value Over Time')
plt.xlabel('Date')
plt.ylabel('Portfolio Value')
plt.legend()
plt.grid(True)
plt.show()
# Plot drawdown over time
plt.figure(figsize=(10, 7))
plt.plot(portfolio_df['Drawdown'], label='Drawdown', color='red')
plt.title('Drawdown Over Time')
plt.xlabel('Date')
plt.ylabel('Drawdown')
plt.legend()
plt.grid(True)
plt.show()
Result: