Spaces:
Sleeping
Sleeping
| 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() |