Spaces:
Running
Running
Download Portfolio.py from arif97/Portfolio-Optimization: direct link, hf CLI and curl.
- Browser
- Download file 7.43 kB
-
https://huggingface.co/spaces/arif97/Portfolio-Optimization/resolve/main/Portfolio.py
- Command line
-
hf download hf://spaces/arif97/Portfolio-Optimization/Portfolio.py
-
curl -L -o Portfolio.py https://huggingface.co/spaces/arif97/Portfolio-Optimization/resolve/main/Portfolio.py
7.43 kB
| import streamlit as st | |
| from streamlit_lottie import st_lottie | |
| import pandas as pd | |
| import plotly.express as px | |
| import numpy as np | |
| from scipy.optimize import minimize | |
| from fredapi import Fred | |
| import warnings | |
| import time | |
| import json | |
| import plotly.graph_objects as go | |
| warnings.filterwarnings('ignore') | |
| np.set_printoptions(suppress=True) | |
| from PortfolioHelperFuncs import navigationBar | |
| from PortfolioHelperFuncs import commodities | |
| from PortfolioHelperFuncs import Data | |
| from PortfolioHelperFuncs import visualize | |
| from PortfolioHelperFuncs import retrieve_tickers | |
| from PortfolioHelperFuncs import KeyMetrics | |
| from PortfolioHelperFuncs import plot_optimal_weights | |
| st.set_page_config(layout="wide", | |
| page_title="Portfolio Optimization For Commodities", | |
| page_icon="Portfolio_Icon.jpg") | |
| if "dtVariable" not in st.session_state: | |
| st.session_state.dtVariable = Data(collectedData=pd.DataFrame(), | |
| commTickers={}, | |
| years=5, | |
| upperBoundLimit=0.5) | |
| if 'loadOnce' not in st.session_state: | |
| st.session_state.loadOnce = True | |
| if st.session_state.loadOnce: | |
| with open(file='Portfolio_Anim.json', mode = "r") as f: | |
| anim = json.load(f) | |
| with st.lottie_spinner(anim, height = 700): | |
| time.sleep(2) | |
| st.session_state.loadOnce = False | |
| #------------------------------------------------------------------------------ Navigation Bar | |
| selected_option = navigationBar() | |
| if selected_option == 'Sharpe Ratio Technique': | |
| _, c, _ = st.columns((3,5,3)) | |
| c.title('Portfolio Optimization with Commodities') | |
| with c.form(key='Parameters Button'): | |
| selected_commodities = st.multiselect('Select Commodities', list(commodities.keys()), default=list()) | |
| years_of_data = st.slider('Select Number of Years of Data', 1, 10, 5) | |
| upper_bound_limit = st.slider('Set Upper Bound Limit for Asset Allocation', 0.0, 1.0, 0.3) | |
| risk_free_rate_source = st.radio('Select Risk-Free Rate Source', ['Manual', 'FRED API']) | |
| disabledTF = True if risk_free_rate_source == "FRED API" else False | |
| risk_free_rate_manual = st.number_input('Enter Risk-Free Rate (%)', min_value=0.0, max_value=100.0, value=3.0,) | |
| log_normal_returns = st.checkbox('Use Log Normal Returns (Will use Simple Returns if not selected)', value=False) | |
| submitted = st.form_submit_button("Get me my Optimal Investment Strategy") | |
| if submitted: | |
| st.write('<br>', unsafe_allow_html=True) | |
| st.divider() | |
| st.write('<br>', unsafe_allow_html=True) | |
| st.session_state.dtVariable.collectedData = pd.DataFrame() | |
| st.session_state.dtVariable.commTickers = {k: commodities[k] for k in selected_commodities} | |
| st.session_state.dtVariable.years = years_of_data | |
| st.session_state.dtVariable.upperBoundLimit = upper_bound_limit | |
| retrieve_tickers() | |
| st.session_state.dtVariable.collectedData = st.session_state.dtVariable.collectedData[selected_commodities] | |
| f = visualize(st.session_state.dtVariable.collectedData, 'Historical Prices', {'value': 'Price', 'variable': 'Commodity'}, 'Date', 'Price', 'Commodities') | |
| _, cnt, _ = st.columns((2,5,2)) | |
| cnt.plotly_chart(f, use_container_width= True) | |
| if risk_free_rate_source == 'FRED API': | |
| f = Fred(api_key='385c2ddfc6d3c369a67ad83c63f6fd7d') | |
| treasuryRate = f.get_series_latest_release('GS10') | |
| risk_free_rate = treasuryRate.iloc[-1] / 100 | |
| else: | |
| risk_free_rate = risk_free_rate_manual / 100 | |
| constraints = {'type': 'eq', 'fun': lambda weights: np.sum(weights) - 1} | |
| bounds = [(0, st.session_state.dtVariable.upperBoundLimit) for _ in range(len(st.session_state.dtVariable.collectedData.columns))] | |
| metrics = KeyMetrics(data=st.session_state.dtVariable.collectedData, logNormal=log_normal_returns) | |
| metrics.calculate_daily_returns() | |
| metrics.calculate_covariance() | |
| def objective(weights): | |
| metrics.initialWeights = weights | |
| metrics.calculate_standard_deviation() | |
| metrics.calculate_expected_return() | |
| metrics.calculate_sharpe_ratio(riskFreeRate=risk_free_rate) | |
| return -metrics.sharpeRatio | |
| result = minimize(fun=objective, x0=metrics.initialWeights, constraints=constraints, bounds=bounds, method='SLSQP') | |
| if result.success: | |
| optimal_weights = result.x | |
| optimal_weights = np.round(optimal_weights, 3) | |
| if np.isclose(np.sum(optimal_weights), 1): | |
| metrics.initialWeights = optimal_weights | |
| metrics.calculate_covariance() | |
| metrics.calculate_standard_deviation() | |
| metrics.calculate_expected_return() | |
| metrics.calculate_sharpe_ratio(riskFreeRate=risk_free_rate) | |
| # optimal_weights_df = pd.DataFrame(data=optimal_weights.reshape(-1, 1), index=st.session_state.dtVariable.collectedData.columns) | |
| optimal_weights_df = pd.DataFrame({ 'Tickers': np.array(st.session_state.dtVariable.collectedData.columns), 'Weights': optimal_weights }) | |
| st.write('<br>', unsafe_allow_html=True) | |
| st.divider() | |
| st.write('<br>', unsafe_allow_html=True) | |
| riskCol, sharpeRatioCol, returnsCol = st.columns((2,2,2)) | |
| riskCol.header("Investment Risk Associated with your Portfolio and the Weights Allocation") | |
| fig_gauge = go.Figure(go.Indicator( | |
| mode="gauge+number", | |
| value=metrics.standardDeviation * 100, | |
| title={'text': ""}, | |
| gauge={'axis': {'range': [0, 100]}} | |
| )) | |
| riskCol.plotly_chart(fig_gauge) | |
| # Metric Card | |
| sharpeRatioCol.header("Sharpe Ratio") | |
| sharpeRatioCol.metric(label="", value=np.round(metrics.sharpeRatio,4)) | |
| returnsCol.header("Expected Returns on your Portfolio & its Optimal Weights") | |
| fig_gauge = go.Figure(go.Indicator( | |
| mode="gauge+number", | |
| value=metrics.expectedReturns * 100, | |
| title={'text': ""}, | |
| gauge={'axis': {'range': [0, 100]}} | |
| )) | |
| returnsCol.plotly_chart(fig_gauge) | |
| st.write('<br>', unsafe_allow_html=True) | |
| st.divider() | |
| st.write('<br>', unsafe_allow_html=True) | |
| _, weightsDepictionColumns1, _, weightsDepictionColumns2, _ = st.columns((1,4,1,2,1)) | |
| weightsDepictionColumns1.plotly_chart(plot_optimal_weights(optimal_weights_df), use_container_width=True) | |
| weightsDepictionColumns2.header('Weights Allocation Pie Chart') | |
| fig_pie = px.pie(optimal_weights_df, values='Weights', names='Tickers', title='', height=400) | |
| weightsDepictionColumns2.plotly_chart(fig_pie) | |
| else: | |
| cnt.error("The sum of the optimal weights is not equal to 1.") | |
| else: | |
| cnt.error(f"Optimization failed: {result.message}") | |
| cnt.write("Try Different Combinations, add more tickers or adjusting Upper Bound Values or Something other") | |