Teori Portofolio Markowitz untuk Kripto: Dari Nol Hingga Mahir
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:
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')
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
crypto_symbols = ['BTC-USD', 'ETH-USD']
prices = get_crypto_data(crypto_symbols)
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 = np.sum(returns.mean() * weights) * 252
portfolio_vol = np.sqrt(np.dot(weights.T, np.dot(returns.cov() * 252, weights)))
return portfolio_return, portfolio_vol
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):
weights = np.random.random(num_assets)
weights /= np.sum(weights) # Normalize to sum to 1
portfolio_return, portfolio_vol = portfolio_performance(weights, returns)
sharpe_ratio = portfolio_return / portfolio_vol
results[0,i] = portfolio_return
results[1,i] = portfolio_vol
results[2,i] = sharpe_ratio
results[3,i:] = weights
return results
results = generate_random_portfolios(returns)
portfolio_results = pd.DataFrame({
'Returns': results[0],
'Volatility': results[1],
'Sharpe_Ratio': results[2]
})
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 = ({'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 = num_assets * [1. / num_assets]
if objective == 'sharpe':
result = minimize(negative_sharpe_ratio, initial_guess,
args=(returns,), method='SLSQP',
bounds=bounds, constraints=constraints)
elif objective == 'min_vol':
result = minimize(minimize_volatility, initial_guess,
args=(returns,), method='SLSQP',
bounds=bounds, constraints=constraints)
elif objective == '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
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:
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()
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
"""
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)
efficient_port = efficient_frontier(returns_multi)
plt.figure(figsize=(14, 10))
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)
if len(efficient_port) > 0:
plt.plot(efficient_port[:,1], efficient_port[:,0], 'r-', linewidth=3, label='Efficient Frontier')
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()
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
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)
cumulative_returns = (1 + portfolio_returns).cumprod()
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
}
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 = 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
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! 📈
Penulis
Trading-systems engineer
Trading-systems engineer building bots since 2017: cross-exchange arbitrage (connected up to 30 venues), cointegration-based pairs arbitrage across spot and futures, scalping, news and sentiment-driven strategies, trend algorithms, and portfolio management and balancing algorithms. Also builds sub-millisecond order execution, big-data warehouses, backtesting engines, AI agents, and trading interfaces (incl. open-source profitmaker.cc). Stack: JS/TS, Python, Rust/Zig/Go, DevOps, backend, frontend, architecture.