← Kembali ke artikel
September 25, 2025
5 menit baca

Teori Portofolio Markowitz untuk Kripto: Dari Nol Hingga Mahir

Teori Portofolio Markowitz untuk Kripto: Dari Nol Hingga Mahir
#optimasi portofolio
#Markowitz
#kripto
#Python
#keuangan kuantitatif
#manajemen risiko
#diversifikasi
#efficient frontier
#rasio Sharpe
#trading algoritmik

Membangun portofolio kripto yang optimal dengan Python - karena YOLO bukan sebuah strategi

Teori Portofolio Markowitz 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 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()

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

Optimasi Portofolio Multi-Aset 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 Strategi Portofolio](/images/blog/markowitz-backtest.webp)
*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:

  1. Kalkulasi dasar untuk risiko dan imbal hasil
  2. Visualisasi efficient frontier
  3. Optimasi matematis untuk berbagai tujuan
  4. Strategi lanjutan seperti risk parity
  5. Kerangka backtesting untuk memvalidasi strategimu
  6. 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! 📈

Penafian: Informasi yang disediakan dalam artikel ini hanya untuk tujuan edukasi dan informasi serta tidak merupakan nasihat keuangan, investasi, atau trading. Trading mata uang kripto mengandung risiko kerugian yang signifikan.

Penulis

Eugen Soloviov
Eugen Soloviov

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.

Newsletter

Selangkah Lebih Maju dari Pasar

Berlangganan newsletter kami untuk wawasan AI trading eksklusif, analisis pasar, dan pembaruan platform.

Kami menghormati privasi Anda. Berhenti berlangganan kapan saja.