std-var_Marko / app.py
MVesalA's picture
Update app.py
4bf4fa0 verified
Raw
History Blame Contribute Delete
6.43 kB
import gradio as gr
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import gurobipy as gp
from gurobipy import GRB
# =====================================================
# DATA
# =====================================================
df = pd.read_csv(
"dow_jones_close_prices_2014_to_present3.csv"
)
df.set_index("Date", inplace=True)
returns_df = df.pct_change().dropna()
# =====================================================
# OPTIMIZER
# =====================================================
def utility_frontier(
df_returns,
selected_assets=None,
gammas=None,
allow_short=False
):
if selected_assets:
df = df_returns[selected_assets].copy()
else:
df = df_returns.copy()
n = df.shape[1]
mu = df.mean().values
Sigma = df.cov().values
risks = []
returns = []
utilities = []
weights_list = []
for gamma in gammas:
model = gp.Model()
model.setParam("OutputFlag", 0)
if allow_short:
w = model.addVars(
n,
lb=-GRB.INFINITY,
name="w"
)
else:
w = model.addVars(
n,
lb=0,
ub=1,
name="w"
)
expected_return = gp.quicksum(
mu[i] * w[i]
for i in range(n)
)
variance = gp.quicksum(
Sigma[i, j] * w[i] * w[j]
for i in range(n)
for j in range(n)
)
model.setObjective(
expected_return - gamma * variance,
GRB.MAXIMIZE
)
model.addConstr(
gp.quicksum(w[i] for i in range(n)) == 1
)
model.optimize()
weights = np.array(
[w[i].X for i in range(n)]
)
port_return = weights @ mu
port_var = (
weights.T @ Sigma @ weights
)
port_risk = np.sqrt(port_var)
utility = (
port_return
- gamma * port_var
)
risks.append(port_risk)
returns.append(port_return)
utilities.append(utility)
weights_list.append(weights)
frontier = pd.DataFrame({
"Gamma": gammas,
"Risk": risks,
"Return": returns,
"Utility": utilities
})
weights_df = pd.DataFrame(
weights_list,
columns=df.columns
)
return frontier, weights_df
# =====================================================
# CALLBACK
# =====================================================
def optimize(
assets,
gamma,
allow_short
):
if len(assets) < 2:
raise gr.Error(
"Select at least two assets."
)
frontier, weights_df = utility_frontier(
returns_df,
selected_assets=assets,
gammas=np.linspace(
0.01,
gamma,
100
),
allow_short=allow_short
)
# ---------------------------------
# Frontier plot
# ---------------------------------
fig1, ax1 = plt.subplots(
figsize=(8, 5)
)
ax1.plot(
frontier["Risk"],
frontier["Return"],
marker="o"
)
asset_returns = (
returns_df[assets]
.mean()
)
asset_risks = (
returns_df[assets]
.std()
)
ax1.scatter(
asset_risks,
asset_returns,
s=100
)
for asset in assets:
ax1.annotate(
asset,
(
asset_risks[asset],
asset_returns[asset]
)
)
ax1.set_title(
"Efficient Frontier"
)
ax1.set_xlabel(
"Risk"
)
ax1.set_ylabel(
"Return"
)
ax1.grid(True)
# ---------------------------------
# Best utility portfolio
# ---------------------------------
best_idx = frontier[
"Utility"
].idxmax()
best_weights = (
weights_df.iloc[best_idx]
)
# ---------------------------------
# Weight plot
# ---------------------------------
fig2, ax2 = plt.subplots(
figsize=(8, 5)
)
best_weights.sort_values(
ascending=False
).plot.bar(ax=ax2)
ax2.set_title(
"Portfolio Weights"
)
ax2.set_ylabel(
"Weight"
)
ax2.grid(True)
weights_table = (
best_weights
.sort_values(
ascending=False
)
.reset_index()
)
weights_table.columns = [
"Asset",
"Weight"
]
return (
fig1
# fig2,
# weights_table
)
# =====================================================
# UI
# =====================================================
with gr.Blocks() as demo:
gr.Markdown(
"# Portfolio Optimization"
)
with gr.Row():
with gr.Column(scale=1):
asset_selector = gr.CheckboxGroup(
choices=returns_df.columns.tolist(),
value=returns_df.columns[:5].tolist(),
label="Assets"
)
gamma_slider = gr.Slider(
minimum=0.1,
maximum=100,
value=100,
step=0.1,
label="Maximum Gamma"
)
# short_box = gr.Checkbox(
# label="Allow Short Selling"
# )
run_btn = gr.Button(
"Optimize"
)
with gr.Column(scale=2):
frontier_plot = gr.Plot(
label="Efficient Frontier"
)
# weight_plot = gr.Plot(
# label="Weights"
# )
# weight_table = gr.Dataframe(
# label="Weights Table"
# )
run_btn.click(
fn=optimize,
inputs=[
asset_selector,
gamma_slider,
# short_box
],
outputs=[
frontier_plot
# weight_plot,
# weight_table
]
)
demo.launch()