|
import gradio as gr |
|
import yfinance as yf |
|
from pypfopt.discrete_allocation import DiscreteAllocation, get_latest_prices |
|
from pypfopt import EfficientFrontier |
|
from pypfopt import risk_models |
|
from pypfopt import expected_returns |
|
from pypfopt import plotting |
|
import copy |
|
import numpy as np |
|
import pandas as pd |
|
import plotly.express as px |
|
import matplotlib.pyplot as plt |
|
from datetime import datetime |
|
|
|
def plot_cum_returns(data, title, initial_capital=1000): |
|
|
|
daily_cum_returns = (1 + data.dropna().pct_change()).cumprod() * initial_capital |
|
fig = px.line(daily_cum_returns, title=title) |
|
return fig |
|
|
|
def plot_efficient_frontier_and_max_sharpe(mu, S): |
|
|
|
ef = EfficientFrontier(mu, S) |
|
fig, ax = plt.subplots(figsize=(6, 4)) |
|
ef_max_sharpe = copy.deepcopy(ef) |
|
plotting.plot_efficient_frontier(ef, ax=ax, show_assets=False) |
|
ef_max_sharpe.max_sharpe(risk_free_rate=0.02) |
|
ret_tangent, std_tangent, _ = ef_max_sharpe.portfolio_performance() |
|
ax.scatter(std_tangent, ret_tangent, marker="*", s=100, c="r", label="MAX Sharpe") |
|
ax.legend() |
|
return fig |
|
|
|
def plot_weights(weights): |
|
|
|
labels = weights.keys() |
|
sizes = weights.values() |
|
fig, ax = plt.subplots() |
|
ax.pie(sizes, labels=labels, autopct='%1.1f%%') |
|
ax.axis('equal') |
|
return fig |
|
|
|
def output_results(start_date, end_date, tickers_string): |
|
tickers = tickers_string.split(',') |
|
stocks_df = yf.download(tickers, start=start_date, end=end_date)['Adj Close'] |
|
fig_indiv_prices = px.line(stocks_df, title='๊ฐ๋ณ ์ฃผ์ ๊ฐ๊ฒฉ') |
|
fig_cum_returns = plot_cum_returns(stocks_df, '๊ฐ๋ณ ์ฃผ์์ ๋์ ์์ต๋ฅ ($1,000 ์์)') |
|
corr_df = stocks_df.corr().round(2) |
|
fig_corr = px.imshow(corr_df, text_auto=True, title='์ฃผ์ ๊ฐ ์๊ด ๊ด๊ณ') |
|
mu = expected_returns.mean_historical_return(stocks_df) |
|
S = risk_models.sample_cov(stocks_df) |
|
ef = EfficientFrontier(mu, S) |
|
weights = ef.max_sharpe(risk_free_rate=0.02) |
|
cleaned_weights = ef.clean_weights() |
|
fig_weights = plot_weights(cleaned_weights) |
|
expected_annual_return, annual_volatility, sharpe_ratio = ef.portfolio_performance() |
|
fig_efficient_frontier = plot_efficient_frontier_and_max_sharpe(mu, S) |
|
|
|
return fig_cum_returns, fig_efficient_frontier, fig_corr, fig_indiv_prices, fig_weights, \ |
|
f"{expected_annual_return*100:.2f}%", f"{annual_volatility*100:.2f}%", f"{sharpe_ratio:.2f}" |
|
|
|
css = """ |
|
footer { |
|
visibility: hidden; |
|
} |
|
""" |
|
|
|
|
|
with gr.Blocks(css=css) as app: |
|
gr.Markdown("<h1>๊ธ๋ก๋ฒ ์์ฐ(์ฃผ์,์ง์,BTC,์ํ ๋ฑ) ํฌํธํด๋ฆฌ์ค ์ต์ ํ ๋๊ตฌ</h1>") |
|
with gr.Row(): |
|
start_date = gr.Textbox("2013-01-01", label="์์ ์ผ์") |
|
end_date = gr.Textbox(datetime.now().date(), label="์ข
๋ฃ ์ผ์") |
|
tickers_string = gr.Textbox("NVDA,^GSPC,GC=F,MSFT,BTC-USD", label="์ฃผ์ ํฐ์ปค๋ฅผ ์ผํ๋ก ๊ตฌ๋ถํ์ฌ ์
๋ ฅํ์ธ์") |
|
btn = gr.Button("ํฌํธํด๋ฆฌ์ค ์ต์ ํ ๊ฒฐ๊ณผ ๋ณด๊ธฐ") |
|
|
|
with gr.Row(): |
|
expected_annual_return = gr.Text(label="์์ ์ฐ๊ฐ ์์ต๋ฅ ") |
|
annual_volatility = gr.Text(label="์ฐ๊ฐ ๋ณ๋์ฑ") |
|
sharpe_ratio = gr.Text(label="์คํ ๋น์จ") |
|
|
|
with gr.Column(): |
|
fig_cum_returns = gr.Plot(label="์ต์ ํ๋ ํฌํธํด๋ฆฌ์ค์ ๋์ ์์ต๋ฅ (์์ ๊ฐ๊ฒฉ $1,000)") |
|
fig_efficient_frontier = gr.Plot(label="ํจ์จ์ ํฌ์์ ") |
|
fig_corr = gr.Plot(label="์ฃผ์ ๊ฐ ์๊ด ๊ด๊ณ") |
|
fig_indiv_prices = gr.Plot(label="๊ฐ๋ณ ์ฃผ์ ๊ฐ๊ฒฉ") |
|
fig_weights = gr.Plot(label="ํฌํธํด๋ฆฌ์ค ์ต์ ํฌ์ ๋น์จ") |
|
|
|
btn.click(fn=output_results, inputs=[start_date, end_date, tickers_string], |
|
outputs=[fig_cum_returns, fig_efficient_frontier, fig_corr, fig_indiv_prices, fig_weights, expected_annual_return, annual_volatility, sharpe_ratio]) |
|
|
|
app.launch() |
|
|
|
|