← Макалаларга кайтуу
September 25, 2025
5 мүн окуу

Крипто үчүн Марковиц портфель теориясы: нөлдөн баатырга чейин

Крипто үчүн Марковиц портфель теориясы: нөлдөн баатырга чейин
#portfolio optimization
#Markowitz
#crypto
#Python
#quantitative finance
#risk management
#diversification
#efficient frontier
#Sharpe ratio
#algorithmic trading
📊
Part 1 of 5 · Collection
Portfolio Construction & Risk

Python менен оптималдуу крипто портфелдерди түзүү - анткени YOLO стратегия эмес

Markowitz Portfolio Theory Марковиц портфель теориясы: белгилүү бир тобокелдик деңгээли үчүн кирешени максималдаштыруу максатында санарип активдерге колдонулган математикалык оптималдаштыруу.


Киришүү: эмне үчүн сиздин крипто портфелиңизге сезим эмес, математика керек

Салам, крипто-дегендер! 👋

Илон твит жазганы үчүн бүт стегиңизди DOGE'го таштап жибергениңизди эстейсизби? Же болбосо акыркы кулаган учурда баарын дүрбөлөңдө сатып жибергениңизди? Ооба, баарыбыз да ушундан өттүк. Бүгүн биз портфелиңизди (жана акыл-эсиңизди) сактап кала турган нерсе жөнүндө сүйлөшөбүз: Марковиц портфель теориясы.

Гарри Марковиц бул үчүн 1990-жылы чын эле Нобель сыйлыгын алган. Негизги идея кандай? Сиз каалаган тобокелдик деңгээли үчүн эң жакшы мүмкүн болгон кирешени алуу үчүн портфелиңизди математикалык жол менен оптималдаштыра аласыз. Бул көзүңүздү таңып айдоонун ордуна инвестицияларыңыз үчүн GPS болгону менен бирдей.

Негизги түшүнүк: тобокелдик менен киреше (түбөлүктүү бий)

Кодго киришээрден мурун, эмне менен алектенип жатканыбызды түшүнөлү:

  • Күтүлгөн киреше: канча акча табам деп күтөсүз
  • Тобокелдик (өзгөрмөлүүлүк): портфелиңиздин наркы канчалык термелет
  • Корреляция: ар түрдүү активдер бири-бирине окшош кандай кыймылдайт

Сыйкыр так синхрондуу кыймылдабаган активдерди бириктиргенде пайда болот. Bitcoin кулаганда, кээ бир DeFi токендер жакшыраак кармалышы мүмкүн. Бул сиз үчүн иштеп жаткан диверсификация.

Risk vs Return Тобокелдик менен киреше: оптималдуу геометриялык орточо кирешеге жетүү үчүн жогорку кирешелүү, өзгөрмөлүү активдерди туруктуу негиз менен теңдештирүү.

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)

Эми чыныгы иш башталат! Эффективдүү чек ара бизге бардык мүмкүн болгон оптималдуу портфелдерди көрсөтөт. Ар бир чекит берилген тобокелдик деңгээли үчүн эң жакшы мүмкүн болгон кирешени билдирет.

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 оптималдаштыруусу!

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

Multi-Asset Portfolio Optimization Көп активдүү диверсификация: туруктуу геометриялык структурада корреляциясыз крипто активдерин бириктирүү менен бекем портфель түзүү.

5-деңгээл: өнүккөн ыкмалар - Black-Litterman жана тобокелдик паритети

Портфель оптималдаштыруунун чыныгы нинзялары үчүн бир нече өнүккөн ыкманы ишке ашыралы:

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

![Portfolio Strategy Backtests](/images/blog/markowitz-backtest.webp)
*Алгоритмдик бэктестинг: теориялык оптималдаштыруу моделдерин ырастоо үчүн тарыхый көрсөткүчтөрдү симуляциялоо.*


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

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

Ийгиликтүү оптималдаштыруу! 📈

blog.disclaimer

Authors

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

Рынктан бир кадам алдыда болуңуз

AI соода аналитикасы, рынок талдоолору жана платформа жаңылыктары үчүн биздин жаңылыктар бюллетенине жазылыңыз.

Биз сиздин купуялыгыңызды урматтайбыз. Каалаган убакта жазылымдан чыга аласыз.