File size: 5,915 Bytes
dde01d0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
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
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):
    # Optimize portfolio for max Sharpe ratio and plot it out with efficient frontier curve
    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)
    # Find the max sharpe portfolio
    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")
    # Generate random portfolios with random weights
    n_samples = 1000
    w = np.random.dirichlet(np.ones(ef.n_assets), n_samples)
    rets = w.dot(ef.expected_returns)
    stds = np.sqrt(np.diag(w @ ef.cov_matrix @ w.T))
    sharpes = rets / stds
    ax.scatter(stds, rets, marker=".", c=sharpes, cmap="viridis_r")
    # Output
    ax.legend()
    return fig

def output_results(start_date, end_date, tickers_string):
    tickers = tickers_string.split(',')

    # Get Stock Prices
    stocks_df = yf.download(tickers, start=start_date, end=end_date)['Adj Close']

    # Plot Individual Stock Prices
    fig_indiv_prices = px.line(stocks_df, title='Giá cổ phiếu riêng lẻ')

    # Plot Individual Cumulative Returns
    fig_cum_returns = plot_cum_returns(stocks_df, 'Lợi nhuận tích lũy của từng cổ phiếu bắt đầu từ 100 USD')

    # Calculatge and Plot Correlation Matrix between Stocks
    corr_df = stocks_df.corr().round(2)
    fig_corr = px.imshow(corr_df, text_auto=True, title = 'Tương quan giữa các cổ phiếu')

    # Calculate expected returns and sample covariance matrix for portfolio optimization later
    mu = expected_returns.mean_historical_return(stocks_df)
    S = risk_models.sample_cov(stocks_df)

    # Plot efficient frontier curve
    fig_efficient_frontier = plot_efficient_frontier_and_max_sharpe(mu, S)

    # Get optimized weights
    ef = EfficientFrontier(mu, S)
    ef.max_sharpe(risk_free_rate=0.04)
    weights = ef.clean_weights()
    expected_annual_return, annual_volatility, sharpe_ratio = ef.portfolio_performance()

    expected_annual_return, annual_volatility, sharpe_ratio = '{}%'.format((expected_annual_return*100).round(2)), \
    '{}%'.format((annual_volatility*100).round(2)), \
    '{}%'.format((sharpe_ratio*100).round(2))

    weights_df = pd.DataFrame.from_dict(weights, orient = 'index')
    weights_df = weights_df.reset_index()
    weights_df.columns = ['Mã chứng khoán', 'Trọng số']

    # Calculate returns of portfolio with optimized weights
    stocks_df['Danh mục đầu tư được tối ưu hóa'] = 0
    for ticker, weight in weights.items():
        stocks_df['Danh mục đầu tư được tối ưu hóa'] += stocks_df[ticker]*weight

    # Plot Cumulative Returns of Optimized Portfolio
    fig_cum_returns_optimized = plot_cum_returns(stocks_df['Danh mục đầu tư được tối ưu hóa'], 'Lợi nhuận tích lũy của từng cổ phiếu bắt đầu từ 100 USD')

    return  fig_cum_returns_optimized, weights_df, fig_efficient_frontier, fig_corr,   \
            expected_annual_return, annual_volatility, sharpe_ratio, fig_indiv_prices, fig_cum_returns


with gr.Blocks(theme=gr.themes.Soft()) as app:
    with gr.Row():
        gr.HTML("<h1>Trình tối ưu hóa danh mục đầu tư chứng khoán</h1>")

    with gr.Row():
        start_date = gr.Textbox("2013-01-01", label="Ngày bắt đầu")
        end_date = gr.Textbox(datetime.datetime.now().date(), label="Ngày kết thúc")

    with gr.Row():
        tickers_string = gr.Textbox("MA,V,JPM,BA",
                                    label='Nhập tất cả các mã cổ phiếu sẽ được đưa vào danh mục đầu tư tách biệt \
                                    bằng dấu phẩy KHÔNG có dấu cách, ví dụ: "MA,V,JPM,BA"')
        btn = gr.Button("Tối ưu hóa danh mục đầu tư")

    with gr.Row():
        gr.HTML("<h3>Số liệu danh mục đầu tư được tối ưu hóa</h3>")

    with gr.Row():
        expected_annual_return = gr.Text(label="Lợi nhuận dự kiến ​​hàng năm")
        annual_volatility = gr.Text(label="Biến động hàng năm")
        sharpe_ratio = gr.Text(label="Tỷ lệ Sharpe")

    with gr.Row():
        fig_cum_returns_optimized = gr.Plot(label="Lợi nhuận tích lũy của danh mục đầu tư được tối ưu hóa (Giá khởi điểm là 100 USD)")
        weights_df = gr.DataFrame(label="Trọng số được tối ưu hóa của mỗi mã")

    with gr.Row():
        fig_efficient_frontier = gr.Plot(label="Biên giới hiệu quả")
        fig_corr = gr.Plot(label="Tương quan giữa các cổ phiếu")

    with gr.Row():
        fig_indiv_prices = gr.Plot(label="Giá cổ phiếu riêng lẻ")
        fig_cum_returns = gr.Plot(label="Lợi nhuận tích lũy của từng cổ phiếu bắt đầu từ 100 USD")

    btn.click(fn=output_results, inputs=[start_date, end_date, tickers_string],
              outputs=[fig_cum_returns_optimized, weights_df, fig_efficient_frontier, fig_corr,   \
            expected_annual_return, annual_volatility, sharpe_ratio, fig_indiv_prices, fig_cum_returns])

app.launch()