Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
@@ -10,7 +10,6 @@ import numpy as np
|
|
10 |
import pandas as pd
|
11 |
import plotly.express as px
|
12 |
import matplotlib.pyplot as plt
|
13 |
-
from matplotlib import gridspec
|
14 |
from datetime import datetime
|
15 |
|
16 |
def plot_cum_returns(data, title, initial_capital=1000):
|
@@ -40,105 +39,16 @@ def plot_weights(weights):
|
|
40 |
ax.axis('equal')
|
41 |
return fig
|
42 |
|
43 |
-
def
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
ax1 = plt.subplot(gs[0, 0])
|
48 |
-
# ํฌํธํด๋ฆฌ์ค ๋ด ์์ฐ ๋ฐฐ๋ถ ๋น์จ ๊ทธ๋ํ (๋ง๋ ๊ทธ๋ํ ๋๋ ํ์ด ์ฐจํธ)
|
49 |
-
ax1.pie(list(weights.values()), labels=list(weights.keys()), autopct='%1.1f%%')
|
50 |
-
ax1.axis('equal')
|
51 |
-
ax1.set_title('Portfolio Asset Allocation')
|
52 |
-
|
53 |
-
ax2 = plt.subplot(gs[0, 1])
|
54 |
-
# ํฌํธํด๋ฆฌ์ค์ ์ฐ๊ฐ ์์ต๋ฅ ๋ฐ ๋ณ๋์ฑ ์ถ์ด ๊ทธ๋ํ
|
55 |
-
portfolio_returns = portfolio_data.pct_change().dropna()
|
56 |
-
portfolio_returns = (portfolio_returns + 1).cumprod()
|
57 |
-
portfolio_returns.plot(ax=ax2)
|
58 |
-
ax2.set_title('Portfolio Annual Returns and Volatility')
|
59 |
-
ax2.set_ylabel('Cumulative Returns')
|
60 |
-
|
61 |
-
ax3 = plt.subplot(gs[1, 0])
|
62 |
-
# ํฌํธํด๋ฆฌ์ค์ ์คํ ๋น์จ(Sharpe Ratio) ์ถ์ด ๊ทธ๋ํ
|
63 |
-
sharpe_ratio = portfolio_returns.mean() / portfolio_returns.std() * np.sqrt(252)
|
64 |
-
sharpe_ratio.plot(ax=ax3)
|
65 |
-
ax3.set_title('Portfolio Sharpe Ratio')
|
66 |
-
ax3.set_ylabel('Sharpe Ratio')
|
67 |
-
|
68 |
-
ax4 = plt.subplot(gs[1, 1])
|
69 |
-
# ๊ฐ๋ณ ์ฃผ์์ ์๋ณ ์์ต๋ฅ ๊ทธ๋ํ
|
70 |
-
stock_data[top_ticker].resample('M').last().pct_change().plot(ax=ax4)
|
71 |
-
ax4.set_title(f'{top_ticker} Monthly Returns')
|
72 |
-
ax4.set_ylabel('Returns')
|
73 |
-
|
74 |
-
ax5 = plt.subplot(gs[2, 0])
|
75 |
-
# ๊ฐ๋ณ ์ฃผ์์ ์ฐ๊ฐ ์์ต๋ฅ ๊ทธ๋ํ
|
76 |
-
stock_data[top_ticker].resample('Y').last().pct_change().plot(ax=ax5)
|
77 |
-
ax5.set_title(f'{top_ticker} Annual Returns')
|
78 |
-
ax5.set_ylabel('Returns')
|
79 |
-
|
80 |
-
ax6 = plt.subplot(gs[2, 1])
|
81 |
-
# ๊ฐ๋ณ ์ฃผ์์ ์ด๋ํ๊ท ์ (์: 20์ผ, 50์ผ, 200์ผ) ๊ทธ๋ํ
|
82 |
-
stock_data[top_ticker].plot(ax=ax6)
|
83 |
-
stock_data[top_ticker].rolling(window=20).mean().plot(ax=ax6, label='20-day MA')
|
84 |
-
stock_data[top_ticker].rolling(window=50).mean().plot(ax=ax6, label='50-day MA')
|
85 |
-
stock_data[top_ticker].rolling(window=200).mean().plot(ax=ax6, label='200-day MA')
|
86 |
-
ax6.set_title(f'{top_ticker} Moving Averages')
|
87 |
-
ax6.set_ylabel('Price')
|
88 |
-
ax6.legend()
|
89 |
-
|
90 |
-
ax7 = plt.subplot(gs[3, 0])
|
91 |
-
# ํฌํธํด๋ฆฌ์ค์ ๋๋ก๋ค์ด(Drawdown) ๊ทธ๋ํ
|
92 |
-
portfolio_drawdown = (portfolio_returns.cummax() - portfolio_returns) / portfolio_returns.cummax()
|
93 |
-
portfolio_drawdown.plot(ax=ax7)
|
94 |
-
ax7.set_title('Portfolio Drawdown')
|
95 |
-
ax7.set_ylabel('Drawdown')
|
96 |
-
|
97 |
-
ax8 = plt.subplot(gs[3, 1])
|
98 |
-
# ๊ฐ๋ณ ์ฃผ์์ RSI(Relative Strength Index) ๊ทธ๋ํ
|
99 |
-
delta = stock_data[top_ticker].diff()
|
100 |
-
up = delta.clip(lower=0)
|
101 |
-
down = -1 * delta.clip(upper=0)
|
102 |
-
ema_up = up.ewm(com=13, adjust=False).mean()
|
103 |
-
ema_down = down.ewm(com=13, adjust=False).mean()
|
104 |
-
rs = ema_up / ema_down
|
105 |
-
rsi = 100 - (100 / (1 + rs))
|
106 |
-
rsi.plot(ax=ax8)
|
107 |
-
ax8.set_title(f'{top_ticker} RSI')
|
108 |
-
ax8.set_ylabel('RSI')
|
109 |
-
|
110 |
-
ax9 = plt.subplot(gs[4, 0])
|
111 |
-
# ๊ฐ๋ณ ์ฃผ์์ MACD(Moving Average Convergence Divergence) ๊ทธ๋ํ
|
112 |
-
exp1 = stock_data[top_ticker].ewm(span=12, adjust=False).mean()
|
113 |
-
exp2 = stock_data[top_ticker].ewm(span=26, adjust=False).mean()
|
114 |
-
macd = exp1 - exp2
|
115 |
-
signal = macd.ewm(span=9, adjust=False).mean()
|
116 |
-
ax9.plot(macd, label='MACD')
|
117 |
-
ax9.plot(signal, label='Signal')
|
118 |
-
ax9.set_title(f'{top_ticker} MACD')
|
119 |
-
ax9.set_ylabel('MACD')
|
120 |
-
ax9.legend()
|
121 |
-
|
122 |
-
ax10 = plt.subplot(gs[4, 1])
|
123 |
-
# ๊ฐ๋ณ ์ฃผ์์ ๋ณผ๋ฆฐ์ ๋ฐด๋(Bollinger Bands) ๊ทธ๋ํ
|
124 |
-
rolling_mean = stock_data[top_ticker].rolling(window=20).mean()
|
125 |
-
rolling_std = stock_data[top_ticker].rolling(window=20).std()
|
126 |
-
upper_band = rolling_mean + (rolling_std * 2)
|
127 |
-
lower_band = rolling_mean - (rolling_std * 2)
|
128 |
-
ax10.plot(stock_data[top_ticker], label='Price')
|
129 |
-
ax10.plot(rolling_mean, label='Moving Average')
|
130 |
-
ax10.plot(upper_band, label='Upper Band')
|
131 |
-
ax10.plot(lower_band, label='Lower Band')
|
132 |
-
ax10.set_title(f'{top_ticker} Bollinger Bands')
|
133 |
-
ax10.set_ylabel('Price')
|
134 |
-
ax10.legend()
|
135 |
-
|
136 |
-
plt.tight_layout()
|
137 |
return fig
|
138 |
|
139 |
def output_results(start_date, end_date, tickers_string):
|
140 |
tickers = tickers_string.split(',')
|
141 |
stocks_df = yf.download(tickers, start=start_date, end=end_date)['Adj Close']
|
|
|
142 |
tickers_info = {}
|
143 |
news_data = {}
|
144 |
for ticker in tickers:
|
@@ -153,6 +63,7 @@ def output_results(start_date, end_date, tickers_string):
|
|
153 |
fig_cum_returns = px.line(daily_cum_returns, title='๊ฐ๋ณ ์ฃผ์์ ๋์ ์์ต๋ฅ ($1,000 ์์)')
|
154 |
corr_df = stocks_df.corr().round(2)
|
155 |
fig_corr = px.imshow(corr_df, text_auto=True, title='์ฃผ์ ๊ฐ ์๊ด ๊ด๊ณ')
|
|
|
156 |
mu = expected_returns.mean_historical_return(stocks_df)
|
157 |
S = risk_models.sample_cov(stocks_df)
|
158 |
ef = EfficientFrontier(mu, S)
|
@@ -169,16 +80,14 @@ def output_results(start_date, end_date, tickers_string):
|
|
169 |
for ticker in tickers
|
170 |
])
|
171 |
|
172 |
-
# ๊ฐ์ฅ ์์ต๋ฅ ๊ณผ ๋น์ค์ด ํฐ ์ข
๋ชฉ ์ ํ
|
173 |
-
top_ticker = max(cleaned_weights, key=cleaned_weights.get)
|
174 |
-
fig_top_ticker = plot_top_ticker_graphs(top_ticker, stocks_df, daily_cum_returns[top_ticker], cleaned_weights)
|
175 |
-
|
176 |
return fig_cum_returns, fig_efficient_frontier, fig_corr, fig_indiv_prices, fig_weights, \
|
177 |
-
f"{expected_annual_return*100:.2f}%", f"{annual_volatility*100:.2f}%", f"{sharpe_ratio:.2f}",
|
178 |
-
|
|
|
179 |
|
180 |
css = """footer { visibility: hidden; }"""
|
181 |
|
|
|
182 |
with gr.Blocks(css=css) as app:
|
183 |
gr.Markdown("""
|
184 |
<style>
|
@@ -194,23 +103,18 @@ with gr.Blocks(css=css) as app:
|
|
194 |
end_date = gr.Textbox(datetime.now().date(), label="์ข
๋ฃ ์ผ์")
|
195 |
tickers_string = gr.Textbox("NVDA,^GSPC,GC=F,MSFT,BTC-USD", label="์ฃผ์ ํฐ์ปค๋ฅผ ์ผํ๋ก ๊ตฌ๋ถํ์ฌ ์
๋ ฅํ์ธ์")
|
196 |
btn = gr.Button("ํฌํธํด๋ฆฌ์ค ์ต์ ํ ๊ฒฐ๊ณผ ๋ณด๊ธฐ")
|
197 |
-
|
198 |
with gr.Row():
|
199 |
expected_annual_return = gr.Text(label="์์ ์ฐ๊ฐ ์์ต๋ฅ ")
|
200 |
annual_volatility = gr.Text(label="์ฐ๊ฐ ๋ณ๋์ฑ")
|
201 |
sharpe_ratio = gr.Text(label="์คํ ๋น์จ")
|
202 |
-
|
203 |
with gr.Column():
|
204 |
fig_cum_returns = gr.Plot(label="์ต์ ํ๋ ํฌํธํด๋ฆฌ์ค์ ๋์ ์์ต๋ฅ (์์ ๊ฐ๊ฒฉ $1,000)")
|
205 |
fig_efficient_frontier = gr.Plot(label="ํจ์จ์ ํฌ์์ ")
|
206 |
fig_corr = gr.Plot(label="์ฃผ์ ๊ฐ ์๊ด ๊ด๊ณ")
|
207 |
fig_indiv_prices = gr.Plot(label="๊ฐ๋ณ ์ฃผ์ ๊ฐ๊ฒฉ")
|
208 |
fig_weights = gr.Plot(label="ํฌํธํด๋ฆฌ์ค ์ต์ ํฌ์ ๋น์จ")
|
209 |
-
fig_top_ticker = gr.Plot(label="๊ฐ์ฅ ์์ต๋ฅ ๊ณผ ๋น์ค์ด ํฐ ์ข
๋ชฉ์ ๊ทธ๋ํ")
|
210 |
ticker_info_output = gr.Textbox(label="ํฐ์ปค ์ ๋ณด ๋ฐ ๋ด์ค")
|
|
|
211 |
|
212 |
-
|
213 |
-
outputs=[fig_cum_returns, fig_efficient_frontier, fig_corr, fig_indiv_prices, fig_weights,
|
214 |
-
expected_annual_return, annual_volatility, sharpe_ratio, ticker_info_output, fig_top_ticker])
|
215 |
-
|
216 |
-
app.launch()
|
|
|
10 |
import pandas as pd
|
11 |
import plotly.express as px
|
12 |
import matplotlib.pyplot as plt
|
|
|
13 |
from datetime import datetime
|
14 |
|
15 |
def plot_cum_returns(data, title, initial_capital=1000):
|
|
|
39 |
ax.axis('equal')
|
40 |
return fig
|
41 |
|
42 |
+
def plot_individual_volatility(data):
|
43 |
+
# ๊ฐ๋ณ ์ฃผ์์ ๋ณ๋์ฑ ๊ทธ๋ํ ์ถ๋ ฅ
|
44 |
+
rolling_std = data.pct_change().rolling(window=30).std() * np.sqrt(252)
|
45 |
+
fig = px.line(rolling_std, title='๊ฐ๋ณ ์ฃผ์์ ๋ณ๋์ฑ (30์ผ ๋กค๋ง ์ฐ๊ฐํ)')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
46 |
return fig
|
47 |
|
48 |
def output_results(start_date, end_date, tickers_string):
|
49 |
tickers = tickers_string.split(',')
|
50 |
stocks_df = yf.download(tickers, start=start_date, end=end_date)['Adj Close']
|
51 |
+
|
52 |
tickers_info = {}
|
53 |
news_data = {}
|
54 |
for ticker in tickers:
|
|
|
63 |
fig_cum_returns = px.line(daily_cum_returns, title='๊ฐ๋ณ ์ฃผ์์ ๋์ ์์ต๋ฅ ($1,000 ์์)')
|
64 |
corr_df = stocks_df.corr().round(2)
|
65 |
fig_corr = px.imshow(corr_df, text_auto=True, title='์ฃผ์ ๊ฐ ์๊ด ๊ด๊ณ')
|
66 |
+
|
67 |
mu = expected_returns.mean_historical_return(stocks_df)
|
68 |
S = risk_models.sample_cov(stocks_df)
|
69 |
ef = EfficientFrontier(mu, S)
|
|
|
80 |
for ticker in tickers
|
81 |
])
|
82 |
|
|
|
|
|
|
|
|
|
83 |
return fig_cum_returns, fig_efficient_frontier, fig_corr, fig_indiv_prices, fig_weights, \
|
84 |
+
f"{expected_annual_return*100:.2f}%", f"{annual_volatility*100:.2f}%", f"{sharpe_ratio:.2f}", ticker_info_output
|
85 |
+
|
86 |
+
|
87 |
|
88 |
css = """footer { visibility: hidden; }"""
|
89 |
|
90 |
+
|
91 |
with gr.Blocks(css=css) as app:
|
92 |
gr.Markdown("""
|
93 |
<style>
|
|
|
103 |
end_date = gr.Textbox(datetime.now().date(), label="์ข
๋ฃ ์ผ์")
|
104 |
tickers_string = gr.Textbox("NVDA,^GSPC,GC=F,MSFT,BTC-USD", label="์ฃผ์ ํฐ์ปค๋ฅผ ์ผํ๋ก ๊ตฌ๋ถํ์ฌ ์
๋ ฅํ์ธ์")
|
105 |
btn = gr.Button("ํฌํธํด๋ฆฌ์ค ์ต์ ํ ๊ฒฐ๊ณผ ๋ณด๊ธฐ")
|
106 |
+
|
107 |
with gr.Row():
|
108 |
expected_annual_return = gr.Text(label="์์ ์ฐ๊ฐ ์์ต๋ฅ ")
|
109 |
annual_volatility = gr.Text(label="์ฐ๊ฐ ๋ณ๋์ฑ")
|
110 |
sharpe_ratio = gr.Text(label="์คํ ๋น์จ")
|
|
|
111 |
with gr.Column():
|
112 |
fig_cum_returns = gr.Plot(label="์ต์ ํ๋ ํฌํธํด๋ฆฌ์ค์ ๋์ ์์ต๋ฅ (์์ ๊ฐ๊ฒฉ $1,000)")
|
113 |
fig_efficient_frontier = gr.Plot(label="ํจ์จ์ ํฌ์์ ")
|
114 |
fig_corr = gr.Plot(label="์ฃผ์ ๊ฐ ์๊ด ๊ด๊ณ")
|
115 |
fig_indiv_prices = gr.Plot(label="๊ฐ๋ณ ์ฃผ์ ๊ฐ๊ฒฉ")
|
116 |
fig_weights = gr.Plot(label="ํฌํธํด๋ฆฌ์ค ์ต์ ํฌ์ ๋น์จ")
|
|
|
117 |
ticker_info_output = gr.Textbox(label="ํฐ์ปค ์ ๋ณด ๋ฐ ๋ด์ค")
|
118 |
+
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, ticker_info_output])
|
119 |
|
120 |
+
app.launch()
|
|
|
|
|
|
|
|