File size: 3,284 Bytes
23e99b2
c561271
2a180f0
 
23e99b2
2a180f0
1c7d42a
f0a10e4
6811b7e
35ba371
ad0953c
f0a10e4
 
 
ad0953c
2fe148a
 
 
 
 
 
 
 
35ba371
2fe148a
f0a10e4
2a180f0
 
 
c561271
f0a10e4
2a180f0
 
f0a10e4
2a180f0
 
 
f0a10e4
c561271
35ba371
 
 
f0a10e4
2a180f0
f0a10e4
1c7d42a
f0a10e4
2a180f0
c561271
f0a10e4
2a180f0
6811b7e
 
1c7d42a
2a180f0
 
f0a10e4
2a180f0
f0a10e4
 
2a180f0
f0a10e4
 
2a180f0
f0a10e4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2a180f0
f0a10e4
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
import streamlit as st
import yfinance as yf
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import scipy.optimize as sco

# Fungsi untuk mengunduh data saham
def get_stock_data(tickers, start, end):
    data = yf.download(tickers, start=start, end=end)

    if data.empty:
        st.error("Data saham tidak ditemukan. Periksa ticker atau rentang tanggal.")
        return None

    # Gunakan 'Adj Close' jika ada, jika tidak pakai 'Close'
    if 'Adj Close' in data.columns:
        return data['Adj Close']
    elif 'Close' in data.columns:
        st.warning("Menggunakan 'Close' karena 'Adj Close' tidak tersedia.")
        return data['Close']
    else:
        st.error("Data harga penutupan tidak ditemukan.")
        return None
        
# Fungsi untuk menghitung return tahunan dan matriks kovarians
def calculate_returns(data):
    log_returns = np.log(data / data.shift(1))
    return log_returns.mean() * 252, log_returns.cov() * 252

# Fungsi untuk menghitung portofolio optimal
def optimize_portfolio(returns, cov_matrix):
    num_assets = len(returns)

    def sharpe_ratio(weights):
        portfolio_return = np.dot(weights, returns)
        portfolio_volatility = np.sqrt(np.dot(weights.T, np.dot(cov_matrix, weights)))
        return -portfolio_return / portfolio_volatility  # Negatif untuk minimisasi

    constraints = ({'type': 'eq', 'fun': lambda x: np.sum(x) - 1})
    bounds = tuple((0, 1) for _ in range(num_assets))
    init_guess = num_assets * [1. / num_assets]

    result = sco.minimize(sharpe_ratio, init_guess, method='SLSQP', bounds=bounds, constraints=constraints)
    return result.x if result.success else None

# Streamlit UI
st.title("Analisis Portofolio Saham Optimal (Model Markowitz)")

# Input Saham & Tanggal
tickers_list = st.text_input("Masukkan ticker saham (contoh: BBCA.JK, TLKM.JK, BBRI.JK)", "BBCA.JK, TLKM.JK, BBRI.JK").split(", ")
start_date = st.date_input("Pilih tanggal mulai", pd.to_datetime("2020-01-01"))
end_date = st.date_input("Pilih tanggal akhir", pd.to_datetime("2020-12-31"))

if st.button("Analisis Portofolio"):
    try:
        # Ambil data saham
        stock_data = get_stock_data(tickers_list, start_date, end_date)

        if stock_data is not None:
            mean_returns, cov_matrix = calculate_returns(stock_data)

            # Optimasi portofolio
            optimal_weights = optimize_portfolio(mean_returns, cov_matrix)

            if optimal_weights is not None:
                st.subheader("Bobot Portofolio Optimal:")
                for i, stock in enumerate(tickers_list):
                    st.write(f"{stock}: {optimal_weights[i]:.2%}")

                # Plot Efficient Frontier
                st.subheader("Efficient Frontier")
                fig, ax = plt.subplots()
                ax.scatter(np.sqrt(np.diag(cov_matrix)), mean_returns, c=mean_returns / np.sqrt(np.diag(cov_matrix)), marker='o')
                ax.set_xlabel("Risiko (Standar Deviasi)")
                ax.set_ylabel("Return Tahunan")
                ax.set_title("Efficient Frontier")
                st.pyplot(fig)
            else:
                st.error("Optimasi portofolio gagal. Coba dengan saham yang berbeda.")

    except Exception as e:
        st.error(f"Terjadi kesalahan: {e}")