Teori Portofolio Markowitz untuk Kripto: Dari Nol Hingga Mahir
Membangun portofolio kripto yang optimal dengan Python - karena YOLO bukan sebuah strategi. Pelajari cara menerapkan teori portofolio pemenang Hadiah Nobel pada investasi kripto dengan contoh kode Python yang praktis.

Membangun portofolio kripto yang optimal dengan Python - karena YOLO bukan sebuah strategi
Teori Portofolio Markowitz: Optimasi matematis yang diterapkan pada aset digital untuk memaksimalkan imbal hasil pada tingkat risiko tertentu.
Pendahuluan: Mengapa Portofolio Kripto Anda Membutuhkan Matematika (Bukan Hanya Insting)
Halo para degens kripto! 👋
Ingat ketika kamu melempar seluruh modalmu ke DOGE hanya karena Elon nge-tweet? Atau saat kamu panik-jual semuanya selama crash terakhir? Ya, kita semua pernah ada di sana. Hari ini kita akan membahas sesuatu yang mungkin bisa menyelamatkan portofoliomu (dan kewarasanmu): Teori Portofolio Markowitz.
Harry Markowitz secara harfiah memenangkan Hadiah Nobel untuk ini pada tahun 1990. Ide dasarnya? Kamu bisa mengoptimalkan portofoliomu secara matematis untuk mendapatkan imbal hasil terbaik yang mungkin untuk setiap tingkat risiko yang diberikan. Ini seperti memiliki GPS untuk investasimu, bukan berkendara dengan mata tertutup.
Konsep Inti: Risiko vs Imbal Hasil (Tarian Abadi)
Sebelum kita menyelami kode, mari pahami apa yang kita hadapi:
- Imbal Hasil yang Diharapkan: Seberapa banyak uang yang kamu harapkan untuk didapatkan
- Risiko (Volatilitas): Seberapa banyak nilai portofoliomu naik turun
- Korelasi: Seberapa mirip pergerakan aset-aset yang berbeda satu sama lain
Keajaiban terjadi ketika kamu menggabungkan aset-aset yang tidak bergerak secara sempurna serempak. Saat Bitcoin jatuh, mungkin beberapa token DeFi bertahan lebih baik. Itulah diversifikasi yang bekerja untukmu.
Risiko vs. Imbal Hasil: Menyeimbangkan aset bervolatilitas tinggi dengan imbal hasil tinggi bersama fondasi yang stabil untuk mencapai imbal hasil rata-rata geometris yang optimal.
Menyiapkan Lingkungan Python Kita
Pertama-tama - mari siapkan alat-alat kita:
# Essential libraries for our crypto portfolio optimization
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from scipy.optimize import minimize
import yfinance as yf
import warnings
warnings.filterwarnings('ignore')
# Set up plotting style
plt.style.use('dark_background')
sns.set_palette("husl")
Level 1: Langkah Awal - Matematika Portofolio Sederhana
Mari mulai dengan dasar-dasarnya. Kita akan menghitung imbal hasil dan risiko untuk portofolio 2 aset sederhana.
def get_crypto_data(symbols, period="1y"):
"""
Fetch crypto data from Yahoo Finance
symbols: list of crypto symbols (e.g., ['BTC-USD', 'ETH-USD'])
period: time period for data
"""
data = yf.download(symbols, period=period)['Adj Close']
return data
# Get data for Bitcoin and Ethereum
crypto_symbols = ['BTC-USD', 'ETH-USD']
prices = get_crypto_data(crypto_symbols)
# Calculate daily returns
returns = prices.pct_change().dropna()
print("Daily Returns Preview:")
print(returns.head())
Sekarang mari hitung beberapa metrik portofolio dasar:
def portfolio_performance(weights, returns):
"""
Calculate portfolio return and volatility
weights: array of portfolio weights
returns: dataframe of asset returns
"""
# Portfolio return (annualized)
portfolio_return = np.sum(returns.mean() * weights) * 252
# Portfolio volatility (annualized)
portfolio_vol = np.sqrt(np.dot(weights.T, np.dot(returns.cov() * 252, weights)))
return portfolio_return, portfolio_vol
# Example: 50% BTC, 50% ETH
weights_5050 = np.array([0.5, 0.5])
ret_5050, vol_5050 = portfolio_performance(weights_5050, returns)
print(f"50/50 Portfolio:")
print(f"Expected Annual Return: {ret_5050:.2%}")
print(f"Annual Volatility: {vol_5050:.2%}")
print(f"Sharpe Ratio: {ret_5050/vol_5050:.3f}")
Level 2: Serius - The Efficient Frontier
Sekarang kita memasak! The efficient frontier menunjukkan kepada kita semua portofolio optimal yang mungkin. Setiap titik mewakili imbal hasil terbaik yang mungkin untuk tingkat risiko tertentu.
def generate_random_portfolios(returns, num_portfolios=10000):
"""
Generate random portfolio combinations
"""
num_assets = len(returns.columns)
results = np.zeros((4, num_portfolios))
for i in range(num_portfolios):
# Generate random weights
weights = np.random.random(num_assets)
weights /= np.sum(weights) # Normalize to sum to 1
# Calculate portfolio metrics
portfolio_return, portfolio_vol = portfolio_performance(weights, returns)
sharpe_ratio = portfolio_return / portfolio_vol
# Store results
results[0,i] = portfolio_return
results[1,i] = portfolio_vol
results[2,i] = sharpe_ratio
results[3,i:] = weights
return results
# Generate 10,000 random portfolios
results = generate_random_portfolios(returns)
# Create a dataframe for easier handling
portfolio_results = pd.DataFrame({
'Returns': results[0],
'Volatility': results[1],
'Sharpe_Ratio': results[2]
})
# Plot the efficient frontier
plt.figure(figsize=(12, 8))
scatter = plt.scatter(portfolio_results['Volatility'],
portfolio_results['Returns'],
c=portfolio_results['Sharpe_Ratio'],
cmap='viridis', alpha=0.6)
plt.colorbar(scatter, label='Sharpe Ratio')
plt.xlabel('Volatility (Risk)')
plt.ylabel('Expected Return')
plt.title('Efficient Frontier - Random Portfolios')
plt.show()
The Efficient Frontier: Kurva yang mewakili imbal hasil yang diharapkan maksimum yang mungkin untuk tingkat risiko tertentu.
Level 3: Penguasaan Optimasi - Menemukan Portofolio Sempurna
Pengambilan sampel acak itu menyenangkan, tetapi kita menginginkan solusi yang optimal secara matematis. Saatnya mengeluarkan senjata besar - optimasi scipy!
def negative_sharpe_ratio(weights, returns, risk_free_rate=0.02):
"""
Calculate negative Sharpe ratio (we minimize this)
"""
portfolio_return, portfolio_vol = portfolio_performance(weights, returns)
sharpe = (portfolio_return - risk_free_rate) / portfolio_vol
return -sharpe
def minimize_volatility(weights, returns):
"""
Calculate portfolio volatility (we minimize this)
"""
_, portfolio_vol = portfolio_performance(weights, returns)
return portfolio_vol
def portfolio_return_objective(weights, returns):
"""
Calculate portfolio return (we maximize this)
"""
portfolio_return, _ = portfolio_performance(weights, returns)
return -portfolio_return # Negative because we minimize
def optimize_portfolio(returns, objective='sharpe', target_return=None):
"""
Optimize portfolio based on different objectives
"""
num_assets = len(returns.columns)
# Constraints and bounds
constraints = ({'type': 'eq', 'fun': lambda x: np.sum(x) - 1}) # Weights sum to 1
bounds = tuple((0, 1) for _ in range(num_assets)) # No short selling
# Initial guess
initial_guess = num_assets * [1. / num_assets]
if objective == 'sharpe':
# Maximize Sharpe ratio
result = minimize(negative_sharpe_ratio, initial_guess,
args=(returns,), method='SLSQP',
bounds=bounds, constraints=constraints)
elif objective == 'min_vol':
# Minimize volatility
result = minimize(minimize_volatility, initial_guess,
args=(returns,), method='SLSQP',
bounds=bounds, constraints=constraints)
elif objective == 'target_return':
# Minimize volatility for target return
constraints = ({'type': 'eq', 'fun': lambda x: np.sum(x) - 1},
{'type': 'eq', 'fun': lambda x: portfolio_performance(x, returns)[0] - target_return})
result = minimize(minimize_volatility, initial_guess,
args=(returns,), method='SLSQP',
bounds=bounds, constraints=constraints)
return result
# Find optimal portfolios
max_sharpe = optimize_portfolio(returns, 'sharpe')
min_vol = optimize_portfolio(returns, 'min_vol')
print("🎯 Maximum Sharpe Ratio Portfolio:")
for i, symbol in enumerate(crypto_symbols):
print(f"{symbol}: {max_sharpe.x[i]:.3f}")
ret_sharpe, vol_sharpe = portfolio_performance(max_sharpe.x, returns)
print(f"Return: {ret_sharpe:.2%}, Volatility: {vol_sharpe:.2%}")
print(f"Sharpe Ratio: {ret_sharpe/vol_sharpe:.3f}\n")
print("🛡️ Minimum Volatility Portfolio:")
for i, symbol in enumerate(crypto_symbols):
print(f"{symbol}: {min_vol.x[i]:.3f}")
ret_minvol, vol_minvol = portfolio_performance(min_vol.x, returns)
print(f"Return: {ret_minvol:.2%}, Volatility: {vol_minvol:.2%}")
Level 4: Multi-Aset - Portofolio Kripto Nyata
Mari skalakan ini ke portofolio kripto yang tepat dengan beberapa aset:
# Expand to more cryptocurrencies
crypto_portfolio = ['BTC-USD', 'ETH-USD', 'BNB-USD', 'ADA-USD', 'SOL-USD', 'DOT-USD']
prices_multi = get_crypto_data(crypto_portfolio, period="2y")
returns_multi = prices_multi.pct_change().dropna()
# Check correlations
correlation_matrix = returns_multi.corr()
plt.figure(figsize=(10, 8))
sns.heatmap(correlation_matrix, annot=True, cmap='RdYlBu_r', center=0)
plt.title('Crypto Asset Correlation Matrix')
plt.show()
def efficient_frontier(returns, num_portfolios=50):
"""
Calculate the efficient frontier
"""
# Calculate range of target returns
ret_range = np.linspace(returns.mean().min()*252, returns.mean().max()*252, num_portfolios)
efficient_portfolios = []
for target_ret in ret_range:
try:
result = optimize_portfolio(returns, 'target_return', target_ret)
if result.success:
ret, vol = portfolio_performance(result.x, returns)
efficient_portfolios.append([ret, vol, result.x])
except:
continue
return np.array(efficient_portfolios)
# Calculate efficient frontier
efficient_port = efficient_frontier(returns_multi)
# Plot everything together
plt.figure(figsize=(14, 10))
# Random portfolios
random_results = generate_random_portfolios(returns_multi, 5000)
plt.scatter(random_results[1], random_results[0],
c=random_results[2], cmap='viridis', alpha=0.3, s=10)
# Efficient frontier
if len(efficient_port) > 0:
plt.plot(efficient_port[:,1], efficient_port[:,0], 'r-', linewidth=3, label='Efficient Frontier')
# Optimal portfolios
max_sharpe_multi = optimize_portfolio(returns_multi, 'sharpe')
min_vol_multi = optimize_portfolio(returns_multi, 'min_vol')
ret_sharpe_multi, vol_sharpe_multi = portfolio_performance(max_sharpe_multi.x, returns_multi)
ret_minvol_multi, vol_minvol_multi = portfolio_performance(min_vol_multi.x, returns_multi)
plt.scatter(vol_sharpe_multi, ret_sharpe_multi, marker='*', color='gold', s=500, label='Max Sharpe')
plt.scatter(vol_minvol_multi, ret_minvol_multi, marker='*', color='red', s=500, label='Min Volatility')
plt.colorbar(label='Sharpe Ratio')
plt.xlabel('Volatility (Risk)')
plt.ylabel('Expected Return')
plt.title('Multi-Asset Crypto Portfolio Optimization')
plt.legend()
plt.show()
# Display optimal allocations
print("🚀 Optimal Multi-Asset Allocations:")
print("\nMaximum Sharpe Ratio Portfolio:")
sharpe_weights = pd.Series(max_sharpe_multi.x, index=crypto_portfolio).sort_values(ascending=False)
for asset, weight in sharpe_weights.items():
if weight > 0.01: # Only show significant allocations
print(f"{asset}: {weight:.1%}")
print(f"\nPortfolio Metrics:")
print(f"Expected Return: {ret_sharpe_multi:.1%}")
print(f"Volatility: {vol_sharpe_multi:.1%}")
print(f"Sharpe Ratio: {ret_sharpe_multi/vol_sharpe_multi:.2f}")
Diversifikasi Multi-Aset: Membangun portofolio yang kuat dengan menggabungkan aset kripto yang tidak berkorelasi menjadi struktur geometris yang stabil.
Level 5: Teknik Lanjutan - Black-Litterman dan Risk Parity
Untuk para ninja optimasi portofolio sejati, mari implementasikan beberapa teknik lanjutan:
def risk_parity_portfolio(returns):
"""
Risk Parity Portfolio - each asset contributes equally to portfolio risk
"""
def risk_contribution(weights, cov_matrix):
portfolio_vol = np.sqrt(np.dot(weights.T, np.dot(cov_matrix, weights)))
marginal_contrib = np.dot(cov_matrix, weights) / portfolio_vol
contrib = weights * marginal_contrib
return contrib
def risk_parity_objective(weights, cov_matrix):
contrib = risk_contribution(weights, cov_matrix)
target_contrib = np.ones(len(weights)) / len(weights)
return np.sum((contrib - target_contrib)**2)
num_assets = len(returns.columns)
cov_matrix = returns.cov() * 252
constraints = ({'type': 'eq', 'fun': lambda x: np.sum(x) - 1})
bounds = tuple((0.001, 1) for _ in range(num_assets))
initial_guess = num_assets * [1. / num_assets]
result = minimize(risk_parity_objective, initial_guess,
args=(cov_matrix,), method='SLSQP',
bounds=bounds, constraints=constraints)
return result
# Calculate Risk Parity portfolio
risk_parity_result = risk_parity_portfolio(returns_multi)
print("⚖️ Risk Parity Portfolio:")
rp_weights = pd.Series(risk_parity_result.x, index=crypto_portfolio).sort_values(ascending=False)
for asset, weight in rp_weights.items():
print(f"{asset}: {weight:.1%}")
ret_rp, vol_rp = portfolio_performance(risk_parity_result.x, returns_multi)
print(f"\nRisk Parity Metrics:")
print(f"Expected Return: {ret_rp:.1%}")
print(f"Volatility: {vol_rp:.1%}")
print(f"Sharpe Ratio: {ret_rp/vol_rp:.2f}")
def backtest_portfolio(weights, prices):
"""
Simple backtest of portfolio performance
"""
returns = prices.pct_change().dropna()
portfolio_returns = (returns * weights).sum(axis=1)
# Calculate cumulative returns
cumulative_returns = (1 + portfolio_returns).cumprod()
# Performance metrics
total_return = cumulative_returns.iloc[-1] - 1
annualized_return = (1 + total_return) ** (252 / len(portfolio_returns)) - 1
annualized_vol = portfolio_returns.std() * np.sqrt(252)
sharpe_ratio = annualized_return / annualized_vol
max_dd = (cumulative_returns / cumulative_returns.expanding().max() - 1).min()
return {
'total_return': total_return,
'annualized_return': annualized_return,
'annualized_volatility': annualized_vol,
'sharpe_ratio': sharpe_ratio,
'max_drawdown': max_dd,
'cumulative_returns': cumulative_returns
}
# Backtest our strategies
strategies = {
'Max Sharpe': max_sharpe_multi.x,
'Min Volatility': min_vol_multi.x,
'Risk Parity': risk_parity_result.x,
'Equal Weight': np.ones(len(crypto_portfolio)) / len(crypto_portfolio)
}
plt.figure(figsize=(14, 8))
for name, weights in strategies.items():
backtest_results = backtest_portfolio(weights, prices_multi)
plt.plot(backtest_results['cumulative_returns'], label=f"{name} (Sharpe: {backtest_results['sharpe_ratio']:.2f})")
plt.title('Portfolio Strategy Backtests')
plt.xlabel('Date')
plt.ylabel('Cumulative Returns')
plt.legend()
plt.yscale('log')
plt.grid(True, alpha=0.3)
plt.show()

*Backtesting Algoritmik: Mensimulasikan kinerja historis untuk memvalidasi model optimasi teoretis.*
# Performance summary table
performance_summary = pd.DataFrame()
for name, weights in strategies.items():
results = backtest_portfolio(weights, prices_multi)
performance_summary[name] = [
f"{results['annualized_return']:.1%}",
f"{results['annualized_volatility']:.1%}",
f"{results['sharpe_ratio']:.2f}",
f"{results['max_drawdown']:.1%}"
]
performance_summary.index = ['Annual Return', 'Annual Volatility', 'Sharpe Ratio', 'Max Drawdown']
print("\n📊 Strategy Performance Summary:")
print(performance_summary)
Pemeriksaan Realitas: Apa yang Tidak Diceritakan Markowitz
Sebelum kamu terjun penuh ke optimasi matematis, berikut beberapa kebenaran pahit tentang kripto:
1. Kinerja Masa Lalu ≠ Hasil Masa Depan Pasar kripto masih muda dan kacau. Korelasi yang kamu hitung? Bisa berbalik dalam semalam ketika regulasi berubah atau ketika hack besar berikutnya terjadi.
2. Biaya Transaksi Penting Menyeimbangkan kembali portofoliomu membutuhkan biaya. Di DeFi, biaya gas bisa menggerogoti keuntunganmu. Masukkan ini ke dalam strategimu.
3. Masalah Likuiditas Tidak semua kripto sama-sama likuid. Altcoin berkapitalisasi kecil itu mungkin terlihat bagus dalam optimasimu, tetapi coba jual saat crash.
4. Perubahan Rezim Pasar kripto memiliki "rezim" yang berbeda - bull market, bear market, crab market. Apa yang berhasil di satu kondisi mungkin tidak berhasil di kondisi lain.
Tips Implementasi Praktis
def practical_portfolio_rebalancing(target_weights, current_weights, threshold=0.05):
"""
Only rebalance when weights drift beyond threshold
"""
weight_diff = np.abs(target_weights - current_weights)
needs_rebalancing = np.any(weight_diff > threshold)
if needs_rebalancing:
print("🔄 Rebalancing needed!")
for i, (target, current) in enumerate(zip(target_weights, current_weights)):
if abs(target - current) > threshold:
print(f"Asset {i}: {current:.1%} → {target:.1%}")
else:
print("✅ Portfolio within tolerance, no rebalancing needed")
return needs_rebalancing
# Example usage
current_allocation = np.array([0.35, 0.25, 0.15, 0.10, 0.10, 0.05])
target_allocation = max_sharpe_multi.x
practical_portfolio_rebalancing(target_allocation, current_allocation)
Kesimpulan: Perangkat Optimasi Portofoliomu
Kamu sekarang memiliki perangkat lengkap untuk optimasi portofolio kripto:
- Kalkulasi dasar untuk risiko dan imbal hasil
- Visualisasi efficient frontier
- Optimasi matematis untuk berbagai tujuan
- Strategi lanjutan seperti risk parity
- Kerangka backtesting untuk memvalidasi strategimu
- Pertimbangan praktis untuk implementasi di dunia nyata
Poin-Poin Utama
- Diversifikasi adalah makan siang gratis - satu-satunya makan siang gratis dalam berinvestasi
- Optimalkan berdasarkan toleransi risikomu - max Sharpe tidak selalu terbaik untukmu
- Seimbangkan kembali secara sistematis tetapi jangan terlalu banyak trading
- Tetap rendah hati - model adalah alat, bukan bola kristal
- Mulai dari yang sederhana dan tambahkan kompleksitas seiring belajar
Ingat: Dalam kripto, bahkan model matematis terbaik pun tidak bisa memprediksi kapan Elon akan men-tweet tentang Dogecoin atau kapan bursa berikutnya akan diretas. Gunakan teori portofolio sebagai fondasimu, tetapi selalu simpan sebagian cadangan dan jangan pernah berinvestasi lebih dari yang bisa kamu tanggung untuk kehilangkan.
Sekarang majulah dan optimalkan dengan bertanggung jawab! 🚀
Bacaan Lebih Lanjut
Repositori Kode
Semua kode dari tutorial ini tersedia di GitHub: https://github.com/suenot/markowitz
Selamat mengoptimalkan! 📈