ทฤษฎีพอร์ตโฟลิโอ Markowitz สำหรับคริปโต: จากศูนย์สู่ผู้เชี่ยวชาญ
การสร้างพอร์ตโฟลิโอคริปโตที่เหมาะสมที่สุดด้วย Python - เพราะ YOLO ไม่ใช่กลยุทธ์ เรียนรู้วิธีประยุกต์ใช้ทฤษฎีพอร์ตโฟลิโอที่ได้รับรางวัลโนเบลกับการลงทุนในคริปโต พร้อมตัวอย่างโค้ด Python ที่ใช้งานได้จริง

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

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