ทฤษฎีพอร์ตโฟลิโอ Markowitz สำหรับคริปโต: จากศูนย์สู่ผู้เชี่ยวชาญ
การสร้างพอร์ตโฟลิโอคริปโตที่เหมาะสมที่สุดด้วย Python — เพราะ YOLO ไม่ใช่กลยุทธ์
ทฤษฎีพอร์ตโฟลิโอ Markowitz: การเพิ่มประสิทธิภาพทางคณิตศาสตร์ที่ประยุกต์ใช้กับสินทรัพย์ดิจิทัลเพื่อเพิ่มผลตอบแทนสูงสุดสำหรับระดับความเสี่ยงที่กำหนด
บทนำ: ทำไมพอร์ตโฟลิโอคริปโตของคุณถึงต้องการคณิตศาสตร์ (ไม่ใช่แค่ความรู้สึก)
สวัสดีนักเก็งกำไรคริปโตทุกท่าน! 👋
คุณยังจำตอนที่ทุ่มเงินทั้งหมดซื้อ DOGE เพราะ Elon ทวีตอยู่ไหม? หรือตอนที่ตื่นตระหนกขายทุกอย่างระหว่างการตกของตลาดครั้งล่าสุด? ใช่แล้ว พวกเราเคยผ่านสิ่งนั้นกันมาหมด วันนี้เราจะพูดถึงสิ่งที่อาจช่วยพอร์ตโฟลิโอของคุณ (และสติสัมปชัญญะของคุณ): ทฤษฎีพอร์ตโฟลิโอ Markowitz
Harry Markowitz ได้รับรางวัลโนเบลสำหรับสิ่งนี้เมื่อปี 1990 แนวคิดพื้นฐาน? คุณสามารถเพิ่มประสิทธิภาพพอร์ตโฟลิโอของคุณทางคณิตศาสตร์เพื่อให้ได้ผลตอบแทนที่ดีที่สุดเท่าที่เป็นไปได้สำหรับระดับความเสี่ยงที่กำหนด มันเหมือนกับการมี GPS สำหรับการลงทุนของคุณแทนที่จะขับรถโดยปิดตา
แนวคิดหลัก: ความเสี่ยงเทียบกับผลตอบแทน (การเต้นรำชั่วนิรันดร์)
ก่อนที่เราจะเริ่มเขียนโค้ด มาทำความเข้าใจกับสิ่งที่เรากำลังจัดการ:
- ผลตอบแทนที่คาดหวัง: จำนวนเงินที่คุณคาดว่าจะได้รับ
- ความเสี่ยง (ความผันผวน): ค่าพอร์ตโฟลิโอของคุณกระโดดขึ้นลงมากแค่ไหน
- ความสัมพันธ์: สินทรัพย์ต่างๆ เคลื่อนไหวพร้อมกันอย่างไร
ความมหัศจรรย์เกิดขึ้นเมื่อคุณรวมสินทรัพย์ที่ไม่เคลื่อนไหวพร้อมกันอย่างสมบูรณ์แบบ เมื่อ Bitcoin ตก บางทีโทเค็น DeFi บางตัวอาจยืนหยัดได้ดีกว่า นั่นคือการกระจายความเสี่ยงที่ทำงานเพื่อคุณ
ความเสี่ยงเทียบกับผลตอบแทน: การสร้างสมดุลระหว่างสินทรัพย์ที่ให้ผลตอบแทนสูงแต่ผันผวนกับฐานที่มั่นคงเพื่อให้ได้ค่าเฉลี่ยผลตอบแทนทางเรขาคณิตที่เหมาะสมที่สุด
การตั้งค่าสภาพแวดล้อม Python ของเรา
อันดับแรก มาเตรียมเครื่องมือของเรา:
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")
ระดับ 1: ก้าวแรก — คณิตศาสตร์พอร์ตโฟลิโอพื้นฐาน
มาเริ่มจากพื้นฐาน เราจะคำนวณผลตอบแทนและความเสี่ยงสำหรับพอร์ตโฟลิโอ 2 สินทรัพย์อย่างง่าย
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())
ตอนนี้มาคำนวณเมตริกพอร์ตโฟลิโอพื้นฐาน:
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}")
ระดับ 2: จริงจังขึ้น — Efficient Frontier
ตอนนี้เราเริ่มต้นแล้ว! Efficient Frontier แสดงให้เราเห็นพอร์ตโฟลิโอที่เหมาะสมที่สุดทั้งหมดที่เป็นไปได้ แต่ละจุดแสดงถึงผลตอบแทนที่ดีที่สุดที่เป็นไปได้สำหรับระดับความเสี่ยงที่กำหนด
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: เส้นโค้งที่แสดงถึงผลตอบแทนที่คาดหวังสูงสุดที่เป็นไปได้สำหรับระดับความเสี่ยงที่กำหนด
ระดับ 3: การเพิ่มประสิทธิภาพขั้นปรมาจารย์ — ค้นหาพอร์ตโฟลิโอที่สมบูรณ์แบบ
การสุ่มตัวอย่างเป็นเรื่องสนุก แต่เราต้องการคำตอบที่เหมาะสมที่สุดทางคณิตศาสตร์ ถึงเวลาใช้อาวุธหนัก — scipy optimization!
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%}")
ระดับ 4: ความบ้าคลั่งหลายสินทรัพย์ — พอร์ตโฟลิโอคริปโตจริง
มาขยายขนาดเป็นพอร์ตโฟลิโอคริปโตที่เหมาะสมพร้อมสินทรัพย์หลายตัว:
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}")
การกระจายความเสี่ยงในหลายสินทรัพย์: การสร้างพอร์ตโฟลิโอที่แข็งแกร่งโดยการรวมสินทรัพย์คริปโตที่ไม่มีความสัมพันธ์กันเป็นโครงสร้างทางเรขาคณิตที่มั่นคง
ระดับ 5: เทคนิคขั้นสูง — Black-Litterman และ Risk Parity
สำหรับนินจาการเพิ่มประสิทธิภาพพอร์ตโฟลิโอตัวจริง มาใช้งานเทคนิคขั้นสูง:
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()

*การทดสอบย้อนหลังเชิงอัลกอริทึม: การจำลองประสิทธิภาพในอดีตเพื่อตรวจสอบความถูกต้องของโมเดลการเพิ่มประสิทธิภาพทางทฤษฎี*
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)
การตรวจสอบความเป็นจริง: สิ่งที่ Markowitz ไม่บอกคุณ
ก่อนที่คุณจะทุ่มทุนทั้งหมดไปกับการเพิ่มประสิทธิภาพทางคณิตศาสตร์ นี่คือความจริงที่ยากสำหรับคริปโต:
1. ประสิทธิภาพในอดีต ≠ ผลลัพธ์ในอนาคต ตลาดคริปโตยังอยู่ในช่วงเริ่มต้นและวุ่นวาย ความสัมพันธ์ที่คุณคำนวณไว้? มันอาจพลิกกลับข้ามคืนเมื่อกฎระเบียบเปลี่ยนแปลงหรือเมื่อการแฮ็กครั้งใหญ่ครั้งต่อไปเกิดขึ้น
2. ต้นทุนการทำธุรกรรมมีความสำคัญ การปรับสมดุลพอร์ตโฟลิโอของคุณมีค่าใช้จ่าย ใน DeFi ค่าธรรมเนียมแก๊สสามารถกินกำไรของคุณหมด คำนึงถึงสิ่งนี้ในกลยุทธ์ของคุณ
3. ปัญหาสภาพคล่อง คริปโตทุกตัวไม่มีสภาพคล่องเท่ากัน altcoin มูลค่าตลาดเล็กที่ดูดีในการเพิ่มประสิทธิภาพของคุณ? ลองขายมันในช่วงตลาดตก
4. การเปลี่ยนแปลงระบอบการปกครอง ตลาดคริปโตมี "ระบอบการปกครอง" ต่างๆ — ตลาดกระทิง ตลาดหมี ตลาดปู สิ่งที่ได้ผลในอันหนึ่งอาจไม่ได้ผลในอีกอัน
เคล็ดลับการนำไปใช้งานจริง
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)
สรุป: ชุดเครื่องมือการเพิ่มประสิทธิภาพพอร์ตโฟลิโอของคุณ
ตอนนี้คุณมีชุดเครื่องมือครบครันสำหรับการเพิ่มประสิทธิภาพพอร์ตโฟลิโอคริปโต:
- การคำนวณพื้นฐาน สำหรับความเสี่ยงและผลตอบแทน
- การแสดงภาพ Efficient Frontier
- การเพิ่มประสิทธิภาพทางคณิตศาสตร์ สำหรับวัตถุประสงค์ที่แตกต่างกัน
- กลยุทธ์ขั้นสูง เช่น risk parity
- กรอบการทดสอบย้อนหลัง เพื่อตรวจสอบกลยุทธ์ของคุณ
- ข้อพิจารณาในทางปฏิบัติ สำหรับการนำไปใช้งานในโลกจริง
ประเด็นสำคัญ
- การกระจายความเสี่ยงคืออาหารกลางวันฟรี — อาหารกลางวันฟรีเดียวในการลงทุน
- เพิ่มประสิทธิภาพตามความเสี่ยงที่ยอมรับได้ — max Sharpe ไม่ใช่สิ่งที่ดีที่สุดเสมอไปสำหรับคุณ
- ปรับสมดุลอย่างเป็นระบบ แต่อย่าซื้อขายมากเกินไป
- อยู่กับความถ่อมตัว — โมเดลเป็นเครื่องมือ ไม่ใช่ลูกแก้วทำนายอนาคต
- เริ่มอย่างเรียบง่าย และเพิ่มความซับซ้อนเมื่อคุณเรียนรู้
จำไว้ว่า: ในคริปโต แม้แต่โมเดลทางคณิตศาสตร์ที่ดีที่สุดก็ไม่สามารถทำนายได้ว่าเมื่อไหร่ Elon จะทวีตเรื่อง Dogecoin หรือเมื่อไหร่การแลกเปลี่ยนครั้งต่อไปจะถูกแฮ็ก ใช้ทฤษฎีพอร์ตโฟลิโอเป็นรากฐาน แต่เสมอต้องเก็บเงินสำรองและอย่าลงทุนมากกว่าที่คุณจะสูญเสียได้
ตอนนี้ออกไปและเพิ่มประสิทธิภาพอย่างมีความรับผิดชอบ! 🚀
อ่านเพิ่มเติม
โค้ดของบทเรียนนี้
โค้ดทั้งหมดจากบทเรียนนี้มีให้บน GitHub: https://github.com/suenot/markowitz
ขอให้สนุกกับการเพิ่มประสิทธิภาพ! 📈
ผู้เขียน
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.