Spaces:
Sleeping
Sleeping
File size: 3,539 Bytes
18ee127 b02bd01 c54e392 18ee127 c54e392 18ee127 c54e392 48663c9 d9c4174 785660b c54e392 b02bd01 c54e392 e44a316 c54e392 785660b c54e392 785660b c54e392 e44a316 c54e392 b02bd01 c54e392 785660b c54e392 785660b b02bd01 18ee127 c54e392 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 |
import gradio as gr
import yfinance as yf
import numpy as np
import pandas as pd
from scipy.optimize import minimize
TICKERS = [
'AAPL', 'MSFT', 'NVDA', 'AVGO', 'ADBE',
'AMZN', 'TSLA', 'HD',
'PG', 'COST',
'UNH', 'JNJ', 'LLY',
'JPM', 'GS', 'V',
'CAT', 'UNP', 'GE',
'XOM', 'NEE',
'D',
'GOOGL', 'META', 'CMCSA',
'PLD'
]
def optimize_portfolio(years, target_return):
try:
data = yf.download(TICKERS, period=f"{years}y", interval="1mo", group_by="ticker", auto_adjust=True)
if isinstance(data.columns, pd.MultiIndex):
try:
prices = pd.concat([data[ticker]['Close'] for ticker in TICKERS], axis=1)
prices.columns = TICKERS
except Exception:
return pd.DataFrame(), "Error: Failed to extract Close prices from multi-index data.", "", "", ""
else:
prices = data.get("Adj Close")
if prices is None or prices.empty:
return pd.DataFrame(), "Error: 'Adj Close' data not found or empty.", "", "", ""
returns = prices.pct_change().dropna()
mean_returns = returns.mean() * 12
cov_matrix = returns.cov() * 12
num_assets = len(TICKERS)
init_weights = np.ones(num_assets) / num_assets
def portfolio_volatility(weights):
return np.sqrt(weights @ cov_matrix @ weights)
constraints = [
{"type": "eq", "fun": lambda w: np.sum(w) - 1},
{"type": "eq", "fun": lambda w: w @ mean_returns - target_return}
]
bounds = tuple((0, 1) for _ in range(num_assets))
result = minimize(
portfolio_volatility,
init_weights,
method="SLSQP",
bounds=bounds,
constraints=constraints
)
if not result.success:
return pd.DataFrame(), "Optimization failed. Try adjusting inputs.", "", "", ""
weights = result.x
port_return = weights @ mean_returns
port_vol = np.sqrt(weights @ cov_matrix @ weights)
risk_free_rate = 0.045
sharpe_ratio = (port_return - risk_free_rate) / port_vol
df = pd.DataFrame({
"Ticker": TICKERS,
"Weight (%)": np.round(weights * 100, 2)
}).sort_values("Weight (%)", ascending=False).reset_index(drop=True)
return df, "", f"{port_return*100:.2f}%", f"{port_vol*100:.2f}%", f"{sharpe_ratio:.2f}"
except Exception as e:
return pd.DataFrame(), f"Error: {str(e)}", "", "", ""
with gr.Blocks() as demo:
gr.Markdown("# π Modern Portfolio Optimizer (MPT)")
gr.Markdown("Optimize a portfolio of 25 S&P 500 stocks for **minimum risk** with a target return.")
with gr.Row():
years_slider = gr.Slider(1, 10, value=5, step=1, label="Years of Historical Data")
return_slider = gr.Slider(1.0, 15.0, value=5.0, step=0.1, label="Target Annual Return (%)")
run_button = gr.Button("Optimize Portfolio")
output_table = gr.Dataframe(headers=["Ticker", "Weight (%)"], label="Optimal Allocation")
error_box = gr.Textbox(label="Message", lines=1)
ret_text = gr.Textbox(label="Expected Return")
vol_text = gr.Textbox(label="Expected Volatility")
sharpe_text = gr.Textbox(label="Sharpe Ratio")
run_button.click(
fn=lambda years, target: optimize_portfolio(years, target / 100),
inputs=[years_slider, return_slider],
outputs=[output_table, error_box, ret_text, vol_text, sharpe_text]
)
demo.launch()
|