|
import gradio as gr |
|
import yfinance as yf |
|
from pypfopt.discrete_allocation import DiscreteAllocation, get_latest_prices |
|
from pypfopt import EfficientFrontier |
|
from pypfopt import risk_models |
|
from pypfopt import expected_returns |
|
from pypfopt import plotting |
|
import copy |
|
import numpy as np |
|
import pandas as pd |
|
import plotly.express as px |
|
import matplotlib.pyplot as plt |
|
from datetime import datetime |
|
import datetime |
|
|
|
def plot_cum_returns(data, title): |
|
daily_cum_returns = 1 + data.dropna().pct_change() |
|
daily_cum_returns = daily_cum_returns.cumprod()*100 |
|
fig = px.line(daily_cum_returns, title=title) |
|
return fig |
|
|
|
|
|
|
|
def output_results(start_date, end_date, tickers_string, investment_amount): |
|
tickers = tickers_string.split(',') |
|
|
|
|
|
stocks_df = yf.download(tickers, start=start_date, end=end_date)['Adj Close'] |
|
company_names = stocks_df['Adj Close'].columns.tolist() |
|
|
|
fig_indiv_prices = px.line(stocks_df, title='Price of Individual Stocks') |
|
|
|
|
|
fig_cum_returns = plot_cum_returns(stocks_df, 'Cumulative Returns of Individual Stocks Starting with ₹100') |
|
|
|
|
|
|
|
|
|
|
|
|
|
mu = expected_returns.mean_historical_return(stocks_df) |
|
S = risk_models.sample_cov(stocks_df) |
|
|
|
|
|
|
|
|
|
|
|
ef = EfficientFrontier(mu, S) |
|
ef.max_sharpe(risk_free_rate=0.04) |
|
weights = ef.clean_weights() |
|
expected_annual_return, annual_volatility, sharpe_ratio = ef.portfolio_performance() |
|
|
|
expected_annual_return, annual_volatility, sharpe_ratio = '{}%'.format((expected_annual_return*100).round(2)), \ |
|
'{}%'.format((annual_volatility*100).round(2)), \ |
|
'{}%'.format((sharpe_ratio*100).round(2)) |
|
|
|
weights_df = pd.DataFrame.from_dict(weights, orient='index').reset_index() |
|
weights_df.columns = ['Tickers', 'Weights'] |
|
|
|
|
|
latest_prices = get_latest_prices(stocks_df) |
|
|
|
|
|
da = DiscreteAllocation(weights, latest_prices, total_portfolio_value=investment_amount) |
|
allocation, leftover = da.lp_portfolio() |
|
|
|
allocation_df = pd.DataFrame(list(allocation.items()), columns=['Ticker', 'Shares']) |
|
|
|
|
|
stocks_df['Optimized Portfolio'] = 0 |
|
for ticker, weight in weights.items(): |
|
stocks_df['Optimized Portfolio'] += stocks_df[ticker]*weight |
|
|
|
|
|
fig_cum_returns_optimized = plot_cum_returns(stocks_df['Optimized Portfolio'], 'Cumulative Returns of Optimized Portfolio Starting with ₹100') |
|
|
|
return fig_cum_returns_optimized, allocation_df, \ |
|
expected_annual_return, leftover.round(), fig_indiv_prices, fig_cum_returns |
|
|
|
|
|
with gr.Blocks() as app: |
|
with gr.Row(): |
|
gr.HTML("<h1>Indian Stock Portfolio Optimizer</h1>") |
|
|
|
with gr.Row(): |
|
start_date = gr.Textbox("2013-01-01", label="Start Date") |
|
end_date = gr.Textbox(datetime.datetime.now().date(), label="End Date") |
|
|
|
with gr.Row(): |
|
tickers_string = gr.Textbox("TCS.NS,INFY.NS,RELIANCE.NS,HDFCBANK.NS,ICICIBANK.NS,SBIN.NS", |
|
label='Enter all stock tickers to be included in portfolio separated \ |
|
by commas WITHOUT spaces, e.g. "TCS.NS,INFY.NS,RELIANCE.NS,HDFCBANK.NS,ICICIBANK.NS,SBIN.NS"') |
|
investment_amount = gr.Number(label="Investment Amount (in ₹)") |
|
btn = gr.Button("Get Optimized Portfolio") |
|
|
|
|
|
|
|
|
|
with gr.Row(): |
|
expected_annual_return = gr.Text(label="Expected Annual Return") |
|
leftover = gr.Number(label="Leftover Amount (in ₹)") |
|
|
|
with gr.Row(): |
|
fig_cum_returns_optimized = gr.Plot(label="Cumulative Returns of Optimized Portfolio (Starting Price of ₹100)") |
|
allocation_df = gr.DataFrame(label="Stock Allocation") |
|
|
|
|
|
|
|
|
|
|
|
with gr.Row(): |
|
fig_indiv_prices = gr.Plot(label="Price of Individual Stocks") |
|
fig_cum_returns = gr.Plot(label="Cumulative Returns of Individual Stocks Starting with ₹100") |
|
|
|
|
|
|
|
|
|
|
|
btn.click(fn=output_results, inputs=[start_date, end_date, tickers_string, investment_amount], |
|
outputs=[fig_cum_returns_optimized, allocation_df, \ |
|
expected_annual_return,leftover, fig_indiv_prices, fig_cum_returns]) |
|
|
|
app.launch() |
|
|