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): # 일일 누적 수익률 계산 및 시각화 daily_cum_returns = 1 + data.dropna().pct_change() daily_cum_returns = daily_cum_returns.cumprod() * 100 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="최대 샤프") ax.legend() 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, '개별 주식의 누적 수익률 ($100 시작)') # 주식 간 상관 관계 계산 및 시각화 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) # 효율적 투자선 시각화 fig_efficient_frontier = plot_efficient_frontier_and_max_sharpe(mu, S) return fig_cum_returns, fig_efficient_frontier, fig_corr, fig_indiv_prices # Gradio 인터페이스 구성 with gr.Blocks() as app: with gr.Row(): gr.HTML("

글로벌 주식 포트폴리오 최적화 도구

") with gr.Row(): start_date = gr.Textbox("2013-01-01", label="시작 일자") end_date = gr.Textbox(datetime.now().date(), label="종료 일자") with gr.Row(): tickers_string = gr.Textbox("TSLA,META,AMZN,MSFT,BTC-USD", label="포트폴리오에 포함될 주식 티커를 쉼표로 구분하여 입력하세요 (예: 'TSLA,META,AMZN,MSFT,BTC-USD')") btn = gr.Button("포트폴리오 최적화 결과 보기") with gr.Row(): expected_annual_return = gr.Text(label="예상 연간 수익률") annual_volatility = gr.Text(label="연간 변동성") sharpe_ratio = gr.Text(label="샤프 비율") with gr.Row(): fig_cum_returns = gr.Plot(label="최적화된 포트폴리오의 누적 수익률 (시작 가격 $100)") fig_efficient_frontier = gr.Plot(label="효율적 투자선") fig_corr = gr.Plot(label="주식 간 상관 관계") fig_indiv_prices = 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]) app.launch()