|
import gradio as gr |
|
import matplotlib.pyplot as plt |
|
import pandas as pd |
|
import sqlite3 |
|
from datetime import datetime |
|
import sqlite3 |
|
from datetime import datetime |
|
|
|
|
|
db_path = 'nifty50_stock_data.db' |
|
nifty_50_symbols = pd.read_csv("nifty50-stock-tickers.csv").Symbol.to_list() |
|
|
|
class Stock: |
|
def __init__(self, symbol, db_path, start_date, end_date): |
|
self.symbol = symbol |
|
self.db_path = db_path |
|
self.start_date = start_date |
|
self.end_date = end_date |
|
self.prices = self._download_prices() |
|
|
|
def _download_prices(self): |
|
conn = sqlite3.connect(self.db_path) |
|
query = f"SELECT Date, Close FROM `{self.symbol}` WHERE Date BETWEEN '{self.start_date}' AND '{self.end_date}'" |
|
prices = pd.read_sql_query(query, conn, parse_dates=['Date']) |
|
prices.set_index('Date', inplace=True) |
|
prices.ffill(inplace=True) |
|
return prices |
|
|
|
def CurPrice(self, curDate): |
|
return self.prices.loc[curDate, 'Close'] if curDate in self.prices.index else None |
|
|
|
def NDayRet(self, N, curDate): |
|
if curDate not in self.prices.index: |
|
return None |
|
start_date = self.prices.index[self.prices.index.get_loc(curDate) - N] |
|
start_price = self.prices.loc[start_date, 'Close'] |
|
end_price = self.prices.loc[curDate, 'Close'] |
|
return (end_price - start_price) / start_price |
|
|
|
def DailyRet(self, curDate): |
|
if curDate not in self.prices.index: |
|
return None |
|
previous_date = self.prices.index[self.prices.index.get_loc(curDate) - 1] |
|
previous_price = self.prices.loc[previous_date, 'Close'] |
|
current_price = self.prices.loc[curDate, 'Close'] |
|
return (current_price - previous_price) / previous_price |
|
|
|
def Last30daysPrice(self, curDate): |
|
end_loc = self.prices.index.get_loc(curDate) + 1 |
|
start_loc = max(0, end_loc - 30) |
|
return self.prices.iloc[start_loc:end_loc]['Close'].values |
|
|
|
|
|
def calculate_percentage_changes(stocks): |
|
monthly_pct_change = pd.DataFrame() |
|
for symbol, stock_obj in stocks.items(): |
|
monthly_pct_change[symbol] = stock_obj.prices['Close'].resample('M').last().pct_change() |
|
monthly_pct_change.fillna(0, inplace=True) |
|
return monthly_pct_change |
|
|
|
|
|
def update_stock_investments(monthly_pct_change, month_index, stock_investments): |
|
month = monthly_pct_change.index[month_index] |
|
month_performance = monthly_pct_change.loc[month] |
|
positive_stocks = [stock for stock, pct_change in month_performance.items() if pct_change > 0] |
|
portfolio_value = sum(stock_investments.iloc[month_index - 1][symbol] * (1 + monthly_pct_change.at[month, symbol]) |
|
for symbol in nifty_50_symbols if pd.notna(monthly_pct_change.at[month, symbol])) |
|
|
|
if positive_stocks: |
|
investment_per_positive_stock = portfolio_value / len(positive_stocks) |
|
stock_investments.loc[month] = {stock: investment_per_positive_stock if stock in positive_stocks else 0 for stock in nifty_50_symbols} |
|
else: |
|
stock_investments.loc[month] = 0 |
|
|
|
return portfolio_value |
|
|
|
|
|
def calculate_portfolio(start_date, end_date, investment_amount): |
|
|
|
|
|
stocks = {symbol: Stock(symbol, db_path, start_date, end_date) for symbol in nifty_50_symbols} |
|
monthly_pct_change = calculate_percentage_changes(stocks) |
|
stock_investments = pd.DataFrame(index=monthly_pct_change.index, columns=nifty_50_symbols) |
|
portfolio_returns = pd.DataFrame(index=monthly_pct_change.index, columns=["portfolio_returns"]) |
|
|
|
|
|
num_stocks = len(nifty_50_symbols) |
|
investment_per_stock = investment_amount / num_stocks |
|
stock_investments.iloc[0] = investment_per_stock |
|
|
|
|
|
for month_index in range(1, len(monthly_pct_change.index)): |
|
portfolio_value = update_stock_investments(monthly_pct_change, month_index, stock_investments) |
|
portfolio_returns.at[monthly_pct_change.index[month_index], 'portfolio_returns'] = portfolio_value |
|
|
|
|
|
nifty_50_stock = Stock('NIFTY50', db_path, start_date, end_date) |
|
nifty_50_monthly_return = nifty_50_stock.prices['Close'].resample('M').last().pct_change() |
|
nifty_50_portfolio_change = nifty_50_monthly_return*(investment_amount) |
|
nifty_50_portfolio_value =nifty_50_portfolio_change.cumsum()+investment_amount |
|
|
|
return portfolio_returns, nifty_50_portfolio_value |
|
|
|
def calculate_cagr(final_value, initial_value, start_date, end_date): |
|
num_years = (pd.to_datetime(end_date) - pd.to_datetime(start_date)).days / 365.25 |
|
return (final_value / initial_value) ** (1 / num_years) - 1 |
|
|
|
def plot_chart(start_date, end_date, investment_amount): |
|
|
|
portfolio_returns, nifty_50_portfolio_value = calculate_portfolio(start_date, end_date, investment_amount) |
|
|
|
portfolio_cagr = calculate_cagr(portfolio_returns.iloc[-1], investment_amount, start_date, end_date)[0] |
|
nifty50_cagr = calculate_cagr(nifty_50_portfolio_value.iloc[-1], investment_amount, start_date, end_date) |
|
|
|
|
|
plt.figure(figsize=(14, 10)) |
|
plt.plot(portfolio_returns.index, portfolio_returns, label=f'Portfolio (CAGR: {portfolio_cagr*100:.2f}%)') |
|
plt.plot(nifty_50_portfolio_value.index, nifty_50_portfolio_value, label=f'NIFTY 50 (CAGR: {nifty50_cagr*100:.2f}%)') |
|
plt.title('Portfolio Returns Vs NIFTY 50 Returns Over Time') |
|
plt.xlabel('Date') |
|
plt.ylabel('Portfolio Value (in Rupees)') |
|
plt.legend() |
|
plt.grid(True) |
|
plt.savefig('portfolio_chart.png') |
|
plt.show() |
|
|
|
|
|
print(portfolio_cagr) |
|
print(nifty50_cagr) |
|
|
|
return 'portfolio_chart.png' |
|
|
|
|
|
markdown_text = """ |
|
This interface allows you to test a stock selection strategy on nifty50 stocks and compare it with the return of nifty50 index. |
|
Please pick a date range from **2009-01-01 to 2024-01-06** |
|
Please reload the page if you are facing connection timeout / connection errored out """ |
|
|
|
|
|
iface = gr.Interface( |
|
fn=plot_chart, |
|
inputs=[ |
|
gr.Textbox(label="Start Date (YYYY-MM-DD)"), |
|
gr.Textbox(label="End Date (YYYY-MM-DD)"), |
|
gr.Number(label="Investment Amount (in Rupees)") |
|
], |
|
outputs=[ |
|
gr.Image(type="filepath"), |
|
|
|
], |
|
title="Stock Portfolio Performance", |
|
description=markdown_text |
|
) |
|
|
|
iface.launch() |
|
|