نظرية محفظة ماركويتز للعملات المشفرة: من الصفر إلى الاحتراف

بناء محافظ عملات مشفرة مثالية باستخدام Python - لأن YOLO ليست استراتيجية. تعلّم كيفية تطبيق نظرية المحفظة الحائزة على جائزة نوبل على استثمارات العملات المشفرة مع أمثلة عملية بلغة Python.

بناء محافظ عملات مشفرة مثالية باستخدام Python — لأن YOLO ليست استراتيجية

نظرية محفظة ماركويتز نظرية محفظة ماركويتز: التحسين الرياضي المطبّق على الأصول الرقمية لتعظيم العوائد عند مستوى مخاطر معين.


المقدمة: لماذا تحتاج محفظة العملات المشفرة إلى الرياضيات (وليس مجرد حدس)

مرحباً يا عشاق العملات المشفرة! 👋

هل تتذكر تلك المرة التي ألقيت فيها كل أموالك في DOGE لأن إيلون غرّد؟ أو عندما بعت كل شيء في حالة ذعر أثناء آخر انهيار؟ نعم، كلنا مررنا بذلك. اليوم سنتحدث عن شيء قد ينقذ محفظتك (وصحتك النفسية): نظرية محفظة ماركويتز.

حصل هاري ماركويتز على جائزة نوبل لهذا العمل في عام 1990. الفكرة الأساسية؟ يمكنك تحسين محفظتك رياضياً للحصول على أفضل عوائد ممكنة لأي مستوى من المخاطر. إنه مثل امتلاك GPS لاستثماراتك بدلاً من القيادة معصوب العينين.

المفهوم الأساسي: المخاطر مقابل العائد (الرقصة الأبدية)

قبل الغوص في الكود، لنفهم ما نتعامل معه:

  • العائد المتوقع: كم من المال تتوقع أن تربح
  • المخاطر (التقلب): مقدار تذبذب قيمة محفظتك
  • الارتباط: مدى تشابه حركة الأصول المختلفة معاً

يحدث السحر عندما تجمع أصولاً لا تتحرك بتزامن مثالي. عندما ينهار البيتكوين، ربما تصمد بعض رموز 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: الخطوات الأولى — رياضيات محفظة بسيطة

لنبدأ بالأساسيات. سنحسب العوائد والمخاطر لمحفظة بسيطة من أصلين.

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: الجدية — الحدود الفعالة

الآن نبدأ الطبخ الحقيقي! تُظهر لنا الحدود الفعالة جميع المحافظ المثالية الممكنة. كل نقطة تمثل أفضل عائد ممكن لمستوى مخاطر معين.

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()

الحدود الفعالة الحدود الفعالة: المنحنى الذي يمثل أقصى عائد متوقع ممكن لمستوى مخاطر معين.

المستوى 3: سيد التحسين — إيجاد المحفظة المثالية

أخذ العينات العشوائية ممتع، لكننا نريد الحل الأمثل رياضياً. حان وقت إخراج الأسلحة الثقيلة — تحسين 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%}")

المستوى 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: تقنيات متقدمة — بلاك-ليترمان وتكافؤ المخاطر

لمحترفي تحسين المحافظ الحقيقيين، لننفذ بعض التقنيات المتقدمة:

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()

![Portfolio Strategy Backtests](/images/blog/markowitz-backtest.webp)
*الاختبار الخلفي الخوارزمي: محاكاة الأداء التاريخي للتحقق من نماذج التحسين النظرية.*


# 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)

فحص الواقع: ما لا يخبرك به ماركويتز

قبل أن تراهن كل شيء على التحسين الرياضي، إليك بعض الحقائق القاسية حول العملات المشفرة:

1. الأداء الماضي ≠ النتائج المستقبلية سوق العملات المشفرة شاب وفوضوي. تلك الارتباطات التي حسبتها؟ قد تنقلب بين عشية وضحاها عندما تتغير اللوائح أو عندما يحدث الاختراق الكبير التالي.

2. تكاليف المعاملات مهمة إعادة توازن محفظتك تكلف مالاً. في DeFi، يمكن لرسوم الغاز أن تلتهم أرباحك. ضع هذا في اعتبارك في استراتيجيتك.

3. مشاكل السيولة ليست كل العملات المشفرة سائلة بنفس القدر. تلك العملة البديلة الصغيرة قد تبدو رائعة في التحسين، لكن حاول بيعها أثناء الانهيار.

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)

الخلاصة: مجموعة أدوات تحسين المحفظة

لديك الآن مجموعة أدوات كاملة لتحسين محفظة العملات المشفرة:

  1. حسابات أساسية للمخاطر والعائد
  2. تصور الحدود الفعالة
  3. تحسين رياضي لأهداف مختلفة
  4. استراتيجيات متقدمة مثل تكافؤ المخاطر
  5. إطار اختبار خلفي للتحقق من استراتيجياتك
  6. اعتبارات عملية للتطبيق في العالم الحقيقي

النقاط الرئيسية

  • التنويع هو وجبة مجانية — الوجبة المجانية الوحيدة في الاستثمار
  • حسّن بناءً على تحمّلك للمخاطر — أقصى شارب ليس دائماً الأفضل لك
  • أعد التوازن بشكل منهجي لكن لا تفرط في التداول
  • كن متواضعاً — النماذج أدوات وليست كرات بلورية
  • ابدأ ببساطة وأضف التعقيد كلما تعلمت

تذكّر: في عالم العملات المشفرة، حتى أفضل النماذج الرياضية لا تستطيع التنبؤ بموعد تغريد إيلون عن Dogecoin أو اختراق البورصة التالية. استخدم نظرية المحفظة كأساس، لكن احتفظ دائماً ببعض الاحتياطي ولا تستثمر أكثر مما يمكنك تحمّل خسارته.

والآن، انطلق وحسّن بمسؤولية! 🚀

قراءات إضافية

مستودع الكود

جميع الأكواد من هذا الدرس متاحة على GitHub: https://github.com/suenot/markowitz

Happy optimizing! 📈