Spaces:
Sleeping
Sleeping
| import streamlit as st | |
| import pandas as pd | |
| import joblib | |
| from tensorflow import keras | |
| from datetime import date | |
| import os | |
| from utils import forecast_to_annual_return, plot_forecast_vs_actual | |
| from optimization import ( | |
| load_processed_prices, | |
| compute_mu_and_cov, | |
| optimize_portfolio, | |
| optimize_for_target, | |
| plot_efficient_frontier, | |
| ) | |
| from forecast import forecast_lstm | |
| # --- Config --- | |
| tickers = ["TSLA", "BND", "SPY"] | |
| sequence_length = 60 | |
| start_date_data = "2015-01-01" | |
| APP_DIR = os.path.dirname(os.path.abspath(__file__)) | |
| PROJECT_ROOT = os.path.dirname(APP_DIR) | |
| proc_dir = os.path.join(PROJECT_ROOT, "src", "data", "processed") | |
| models_dir = os.path.join(PROJECT_ROOT, "src","models") | |
| # --- App Layout --- | |
| st.set_page_config(layout="wide") | |
| st.title("Portfolio Optimization with LSTM-Forecasted Returns") | |
| st.sidebar.header("User Inputs") | |
| investment_capital = st.sidebar.number_input("Enter Investment Capital ($)", min_value=1000, value=10000, step=1000) | |
| target_return = st.sidebar.slider("Select Target Annual Return (%)", min_value=5.0, max_value=50.0, value=20.0, step=1.0) / 100 | |
| if st.sidebar.button("Run Optimization"): | |
| # --- 1. Fetch live historical data --- | |
| with st.spinner("Loading historical data..."): | |
| end_date_data = date.today().strftime("%Y-%m-%d") | |
| data = load_processed_prices(proc_dir, tickers) | |
| # --- 2. Load trained LSTM model & scaler from local models folder --- | |
| with st.spinner("Loading forecasting model..."): | |
| model_path = os.path.join(models_dir, "lstm_model.keras") | |
| scaler_path = os.path.join(models_dir, "scaler.joblib") | |
| model = keras.models.load_model(model_path) | |
| scaler = joblib.load(scaler_path) | |
| # --- 3. Prepare TSLA data & forecast --- | |
| with st.spinner("Generating TSLA price forecast..."): | |
| tsla_close = data["TSLA"][["Close"]].dropna() | |
| test_data_input = tsla_close.tail(2 * sequence_length) | |
| tsla_forecast = forecast_lstm(model, tsla_close, test_data_input, scaler, sequence_length) | |
| last_price = tsla_close["Close"].iloc[-1] | |
| # --- 4. Convert forecast → annual expected return --- | |
| tsla_annual = forecast_to_annual_return( | |
| tsla_forecast, last_price, method="avg_daily", cap=2.0 | |
| ) | |
| # --- 5. Build mu & cov --- | |
| with st.spinner("Calculating expected returns and covariance..."): | |
| mu, cov = compute_mu_and_cov(data, tsla_annual) | |
| # --- 6. Optimize portfolios --- | |
| with st.spinner("Running portfolio optimizations..."): | |
| general_results = optimize_portfolio(mu, cov, rf=0.02) | |
| user_portfolio = optimize_for_target(mu, cov, target_type="return", target_value=target_return) | |
| # --- 7. Display Results --- | |
| st.header("Optimization Results") | |
| col1, col2 = st.columns(2) | |
| with col1: | |
| st.subheader("General Optimal Portfolios") | |
| st.write("**Max Sharpe Portfolio** (Best risk-adjusted return)") | |
| st.json(general_results["weights_sharpe"]) | |
| st.write(pd.DataFrame([general_results["perf_sharpe"]])) | |
| st.write("**Min Volatility Portfolio** (Lowest risk)") | |
| st.json(general_results["weights_minvol"]) | |
| st.write(pd.DataFrame([general_results["perf_minvol"]])) | |
| with col2: | |
| st.subheader(f"Your Custom Portfolio (Target Return: {target_return:.1%})") | |
| if "error" in user_portfolio["performance"]: | |
| st.error(f"Could not find a portfolio for this target return. Error: {user_portfolio['performance']['error']}") | |
| else: | |
| st.write("**Recommended Weights**") | |
| st.json(user_portfolio["weights"]) | |
| st.write("**Expected Performance**") | |
| st.write(pd.DataFrame([user_portfolio["performance"]])) | |
| st.write("**Investment Allocation**") | |
| weights_df = pd.Series(user_portfolio["weights"]) | |
| allocation_df = (weights_df * investment_capital).map('${:,.2f}'.format) | |
| st.dataframe(allocation_df) | |
| # --- 8. Efficient Frontier Plot --- | |
| st.subheader("Efficient Frontier") | |
| fig_frontier = plot_efficient_frontier(mu, cov, general_results) | |
| st.pyplot(fig_frontier) | |
| # --- 9. Forecast vs Actual Plot --- | |
| st.subheader("TSLA Forecast vs. Recent Actuals") | |
| actual_plot_data = tsla_close.tail(len(tsla_forecast) * 2) | |
| fig_forecast = plot_forecast_vs_actual(actual_plot_data, tsla_forecast) | |
| st.pyplot(fig_forecast) | |
| else: | |
| st.info("Adjust the inputs in the sidebar and click 'Run Optimization' to begin.") | |