portfolio-optimizer / src /streamlit_app.py
abnsol's picture
Update src/streamlit_app.py
0824335 verified
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.")