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}")