Spaces:
Sleeping
Sleeping
File size: 5,585 Bytes
f4505cc b59b790 715f9f2 615b087 715f9f2 615b087 1aabc74 715f9f2 615b087 715f9f2 1aabc74 715f9f2 b59b790 715f9f2 615b087 715f9f2 b59b790 715f9f2 b59b790 615b087 715f9f2 b59b790 715f9f2 b59b790 615b087 715f9f2 b59b790 715f9f2 b59b790 715f9f2 b59b790 715f9f2 615b087 715f9f2 615b087 715f9f2 |
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 131 |
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
def get_stock_data(tickers, start, end):
"""Mengambil data harga saham dari Yahoo Finance."""
data = yf.download(tickers, start=start, end=end)
if data.empty:
st.error("Data saham tidak ditemukan. Periksa ticker atau rentang tanggal.")
return None
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
def calculate_returns(data):
"""Menghitung return logaritmik dan matriks kovarians saham."""
log_returns = np.log(data / data.shift(1))
return log_returns.mean() * 252, log_returns.cov() * 252
def optimize_portfolio(returns, cov_matrix):
"""Mengoptimalkan portofolio dengan memaksimalkan rasio Sharpe."""
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
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
def generate_efficient_frontier(returns, cov_matrix, num_portfolios=5000):
"""Membuat simulasi Efficient Frontier untuk berbagai kombinasi portofolio."""
num_assets = len(returns)
results = np.zeros((3, num_portfolios))
for i in range(num_portfolios):
weights = np.random.dirichlet(np.ones(num_assets), size=1)[0]
portfolio_return = np.dot(weights, returns)
portfolio_volatility = np.sqrt(np.dot(weights.T, np.dot(cov_matrix, weights)))
sharpe_ratio = portfolio_return / portfolio_volatility
results[0, i] = portfolio_return
results[1, i] = portfolio_volatility
results[2, i] = sharpe_ratio
return results
st.title("Analisis Portofolio Saham Optimal (Model Markowitz)")
st.write("""
Portofolio optimal adalah strategi investasi yang bertujuan untuk mencapai return maksimum dengan risiko minimal.
Model Markowitz digunakan untuk menentukan kombinasi saham terbaik dalam suatu portofolio.
""")
def get_recommended_stocks():
return "KLBF.JK, SIDO.JK, KAEF.JK, TLKM.JK, UNVR.JK"
def validate_tickers(tickers):
invalid_tickers = [t for t in tickers if yf.Ticker(t).history(period='1d').empty]
if invalid_tickers:
st.warning(f"Ticker tidak valid atau tidak memiliki data: {', '.join(invalid_tickers)}")
return False
return True
st.subheader("Rekomendasi Saham Bertahan Saat COVID-19")
st.write(get_recommended_stocks())
tickers_list = st.text_input("Masukkan ticker saham", "KLBF.JK, SIDO.JK, KAEF.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("2023-12-31"))
if st.button("Analisis Portofolio"):
if validate_tickers(tickers_list):
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)
optimal_weights = optimize_portfolio(mean_returns, cov_matrix)
st.subheader("Statistik Saham")
st.write(stock_data.describe())
if optimal_weights is not None:
st.subheader("Bobot Portofolio Optimal")
portfolio_weights = {stock: weight for stock, weight in zip(stock_data.columns, optimal_weights)}
st.write(portfolio_weights)
fig, ax = plt.subplots()
ax.pie(optimal_weights, labels=stock_data.columns, autopct='%1.1f%%', startangle=140)
ax.axis('equal')
st.pyplot(fig)
st.write("""
**Interpretasi:**
- Bobot dalam portofolio menunjukkan proporsi investasi pada masing-masing saham.
- Semakin besar bobot, semakin besar porsi dana yang dialokasikan ke saham tersebut.
""")
results = generate_efficient_frontier(mean_returns, cov_matrix)
st.subheader("Efficient Frontier")
fig, ax = plt.subplots()
scatter = ax.scatter(results[1, :], results[0, :], c=results[2, :], cmap="viridis", marker='o')
ax.set_xlabel("Risiko (Standar Deviasi)")
ax.set_ylabel("Return Tahunan")
ax.set_title("Efficient Frontier")
fig.colorbar(scatter, label="Sharpe Ratio")
st.pyplot(fig)
st.write("""
**Penjelasan Efficient Frontier:**
- Grafik ini menunjukkan hubungan antara risiko dan return dari berbagai kombinasi portofolio.
- Portofolio yang berada di frontier efisien memberikan return terbaik untuk tingkat risiko tertentu.
""")
else:
st.error("Optimasi portofolio gagal. Coba dengan saham yang berbeda.")
|