arif97/Portfolio-Optimization
0
1import streamlit as st2from streamlit_option_menu import option_menu3 4import pandas as pd5import yfinance as yf6import plotly.express as px7import datetime8from datetime import date9import numpy as np10from dataclasses import dataclass11import warnings12 13warnings.filterwarnings('ignore')14np.set_printoptions(suppress=True)15 16 17# Define the commodities and their Yahoo Finance tickers18commodities = {19 'Gold': 'GC=F',20 'Silver': 'SI=F',21 'Crude Oil': 'CL=F',22 'Natural Gas': 'NG=F',23 'Copper': 'HG=F',24 'Platinum': 'PL=F',25 'Paladium': 'PA=F',26 'RBOB Gasoline': 'RB=F',27 'Brent Crude Oil': 'BZ=F',28 'Corn Futures': 'ZC=F',29 'Oat Futures': 'ZO=F',30 'KC HRW Wheat Futures': 'KE=F',31 'Soybean Oil Futures': 'ZL=F',32 'Soybean Futures': 'ZS=F',33 'Live Cattle Futures': 'LE=F',34 'Cocoa': 'CC=F',35 'Coffee': 'KC=F',36 'Cotton': 'CT=F',37 'Sugar': 'SB=F'38}39 40 41# Define the Class Structure42@dataclass43class Data:44 collectedData: pd.DataFrame45 commTickers: dict46 years: int47 upperBoundLimit: float48 49 50 51import plotly.express as px52import pandas as pd53import streamlit as st54 55def plot_optimal_weights(weights: pd.DataFrame, title: str = "Weights Allocation Bar Chart"):56 """57 Plot optimal weights using Plotly and display it on Streamlit.58 59 Parameters:60 - weights: pd.DataFrame containing asset names and their corresponding weights.61 - title: Title of the plot.62 """63 # Ensure the DataFrame has the correct format64 if weights.shape[1] != 2:65 raise ValueError("DataFrame should have two columns: 'Tickers' and 'Weights'.")66 67 # Fill NaN weights with 068 weights['Weights'] = weights['Weights'].fillna(0)69 70 fig = px.bar(weights,71 x='Tickers',72 y='Weights',73 title=title,74 labels={"Tickers": "Assets", "Weights": "Weights"},75 template='plotly_dark')76 77 fig.update_layout(78 width=1000,79 height=475,80 xaxis_title="Assets",81 yaxis_title="Weights",82 title_font=dict(size=24, color='white'),83 legend=dict(84 title_font=dict(size=36, color='white'),85 font=dict(size=28, color='white')86 ),87 plot_bgcolor='black',88 paper_bgcolor='black'89 )90 91 fig.update_traces(marker=dict(color='blue', line=dict(color='white', width=1.5)))92 return fig93 94 95 96# Function to retrieve ticker data or Stock Prices from Yahoo Finance97def retrieve_tickers():98 global dt99 if len(st.session_state.dtVariable.commTickers) <= 0:100 return101 startDate = date.today() - datetime.timedelta(days=st.session_state.dtVariable.years * 365)102 endDate = date.today()103 for com, tick in st.session_state.dtVariable.commTickers.items():104 # st.write("Hello",st.session_state.dtVariable.collectedData.columns)105 if com not in st.session_state.dtVariable.collectedData.columns:106 st.session_state.dtVariable.collectedData[com] = yf.download(tickers=tick, start=startDate, end=endDate)['Adj Close']107 st.session_state.dtVariable.collectedData.dropna(inplace=True)108 109 110# Function to Visualize Ticker Data111def visualize(data: pd.DataFrame,112 title: str, hoverLabel: dict, 113 xTitle: str, 114 yTitle: str, 115 legendTitle: str,116 width: int = 1000 # Default width set to 1000, you can adjust as needed117 ):118 # Create interactive plots119 fig = px.line(data,120 title=title,121 labels=hoverLabel)122 fig.update_layout(123 width=width, # Set the width of the plot124 xaxis_title=xTitle,125 yaxis_title=yTitle,126 legend_title_text=legendTitle,127 template='plotly_dark',128 hovermode='x unified',129 plot_bgcolor='black', # Set plot background color to black130 paper_bgcolor='black', # Set paper background color to black131 title_font=dict(color='white'),132 legend=dict(133 title_font=dict(color='white'), # Set legend title color to white134 font=dict(color='white') # Set legend items color to white135 ) # Set title color to white136 )137 return fig138 139 140# Function to Calculate Key metrics141class KeyMetrics:142 def __init__(self, data, logNormal=False):143 self.data = data144 self.initialWeights = np.array([1/len(self.data.columns) for _ in range(len(self.data.columns))])145 self.logNormal = logNormal146 self.dailyReturns = None147 self.covarianceMatrix = None148 self.variance = None149 self.standardDeviation = None150 self.expectedReturns = None151 self.sharpeRatio = None152 self.negSharpeRatio = None153 154 def calculate_daily_returns(self):155 self.dailyReturns = np.log(self.data / self.data.shift(1)).dropna() if self.logNormal else self.data.pct_change().dropna()156 157 def calculate_covariance(self):158 if self.dailyReturns is None:159 return "Please Calculate Daily Returns First"160 self.covarianceMatrix = self.dailyReturns.cov() * 252161 162 def calculate_standard_deviation(self):163 if self.covarianceMatrix is None:164 return "Please Calculate Covariance Matrix First"165 self.variance = self.initialWeights.T @ self.covarianceMatrix @ self.initialWeights166 self.standardDeviation = np.sqrt(self.variance)167 168 def calculate_expected_return(self):169 if self.standardDeviation is None:170 return "Please Calculate Standard Deviation First"171 self.expectedReturns = np.sum(self.dailyReturns.mean() * self.initialWeights) * 252172 173 def calculate_sharpe_ratio(self, riskFreeRate):174 if self.expectedReturns is None:175 return "Please Calculate Expected Returns First"176 self.sharpeRatio = (self.expectedReturns - riskFreeRate) / self.standardDeviation177 178 def negative_sharpe_ratio(self):179 if self.sharpeRatio is None:180 return "Please Calculate Sharpe Ratio First"181 self.negSharpeRatio = - self.sharpeRatio182 183 184# Navigation Bar185def navigationBar():186 # Use the following link to get whichever icon you'd like:187 # https://getbootstrap.com/188 options = [189 {"label": "Sharpe Ratio Technique", "icon": "bezier"}190 ]191 192 193 selected = option_menu(194 menu_title= None, #"Ask Me Anything", # Menu title195 options=[option["label"] for option in options],196 icons=[option["icon"] for option in options],197 menu_icon="lightbulb-fill",198 default_index=0,199 orientation="horizontal",200 styles={201 "container": {202 "display": "flex",203 "flex-direction": "column",204 "justify-content": "center",205 "padding": "20px 40px 20px 40px", # Increased top and bottom padding206 "background-color": "#00E0FF", # Dark background color207 "border-radius": "20px",208 "width":"100%",209 "box-shadow": "0px 2px 10px rgba(0, 0, 0, 0.2)", # Shadow effect210 "margin": "auto", # Center align the navigation bar211 "overflow-x": "auto", # Allow horizontal scrolling for small screens212 },213 "menu-title": {214 "font-size": "36px",215 "font-weight": "bold",216 "background-color": "#292",217 "color": "#FFFFFF", # White text color218 "margin-bottom": "20px", # Spacing below the menu title219 },220 "menu-icon": {221 "color": "#FFD700", # Golden yellow icon color222 "font-size": "36px",223 "margin-right": "10px",224 },225 "icon": {226 "color": "#FFD700", # Golden yellow icon color227 "font-size": "36px",228 "margin-right": "10px",229 },230 "nav-link": {231 "font-size": "20px",232 "text-align": "center",233 "color": "#FFFFFF", # White text color234 "padding": "10px 20px",235 "border-radius": "15px",236 "transition": "background-color 0.3s ease",237 238 },239 "nav-link-selected": {240 "background-color": "#07A2F4", # Tomato red when selected241 "color": "#FFFFFF", # White text color when selected242 }243 },244 245 )246 return selected