Розробка системи Monte Carlo симуляції портфелю

Проєктуємо та розробляємо блокчейн-рішення повного циклу: від архітектури смарт-контрактів до запуску DeFi-протоколів, NFT-маркетплейсів та криптобірж. Аудит безпеки, токеноміка, інтеграція з наявною інфраструктурою.
Показано 1 з 1Усі 1306 послуг
Розробка системи Monte Carlo симуляції портфелю
Складний
~3-5 днів
Часті запитання

Напрямки блокчейн-розробки

Етапи блокчейн-розробки

Останні роботи

  • image_website-b2b-advance_0.webp
    Розробка сайту компанії B2B ADVANCE
    1288
  • image_web-applications_feedme_466_0.webp
    Розробка веб-додатків для компанії FEEDME
    1198
  • image_websites_belfingroup_462_0.webp
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    902
  • image_ecommerce_furnoro_435_0.webp
    Розробка інтернет магазину для компанії FURNORO
    1122
  • image_logo-advance_0.webp
    Розробка логотипу компанії B2B Advance
    589
  • image_crm_enviok_479_0.webp
    Розробка веб-додатків для компанії Enviok
    859

Розробка системи Monte Carlo симуляції портфеля

Monte Carlo симуляція генерує тисячі можливих майбутніх траєкторій портфеля на основі статистичних властивостей ринкових даних. Це дозволяє оцінити розподіл можливих результатів, а не просто одне «очікуване» значення.

Принцип Monte Carlo симуляції

Замість «портфель виросте на X%» говоримо: «з ймовірністю 70% портфель виросте на 20-80%, з ймовірністю 15% втратить 10-30%».

Базова GBM (Geometric Brownian Motion):

import numpy as np

def simulate_gbm(initial_price, mu, sigma, days, n_simulations=10000):
    """
    mu: середня денна дохідність
    sigma: середня денна волатильність
    """
    dt = 1  # 1 день
    random_returns = np.random.normal(
        mu * dt, 
        sigma * np.sqrt(dt), 
        (n_simulations, days)
    )
    
    # Кумулятивні returns
    cumulative = np.cumprod(1 + random_returns, axis=1)
    price_paths = initial_price * cumulative
    
    return price_paths

Мультиактивна симуляція з кореляціями

Для портфеля важливо враховувати кореляції між активами:

from numpy.linalg import cholesky

def simulate_correlated_portfolio(initial_prices, means, cov_matrix, 
                                   days=365, n_sims=10000):
    """
    initial_prices: dict {symbol: price}
    means: dict {symbol: daily_mean}
    cov_matrix: матриця коваріацій денних returns
    """
    n_assets = len(initial_prices)
    symbols = list(initial_prices.keys())
    
    # Розкладання Холецького для генерації корельованих випадкових чисел
    L = cholesky(cov_matrix)
    
    portfolio_paths = []
    
    for _ in range(n_sims):
        # Генеруємо некорельовані нормальні випадкові числа
        z = np.random.standard_normal((days, n_assets))
        # Застосовуємо кореляційну структуру
        correlated_returns = z @ L.T
        
        # Додаємо drifts (mean returns)
        daily_means = np.array([means[s] for s in symbols])
        actual_returns = correlated_returns + daily_means
        
        # Еволюція цін
        prices = np.zeros((days + 1, n_assets))
        prices[0] = [initial_prices[s] for s in symbols]
        
        for t in range(1, days + 1):
            prices[t] = prices[t-1] * (1 + actual_returns[t-1])
        
        # Вартість портфеля (припускаємо рівні ваги)
        weights = np.ones(n_assets) / n_assets
        portfolio_value = (prices * weights).sum(axis=1)
        portfolio_paths.append(portfolio_value)
    
    return np.array(portfolio_paths)

Удосконалені моделі returns

GBM припускає нормальний розподіл returns. Для крипто це неправильно — є fat tails і кластеризація волатильності.

Розподіл Student's t для fat tails:

from scipy.stats import t as t_dist

def simulate_fat_tail(mu, sigma, df, n_sims, days):
    returns = t_dist.rvs(df=df, loc=mu, scale=sigma, size=(n_sims, days))
    return np.cumprod(1 + returns, axis=1)

GARCH(1,1) умовна волатильність: волатильність завтра залежить від дохідності сьогодні та волатильності вчора.

from arch import arch_model

def fit_garch_and_simulate(returns_history, n_sims=10000, horizon=252):
    model = arch_model(returns_history * 100, vol='GARCH', p=1, q=1)
    result = model.fit(disp='off')
    
    # Симулюємо з налаштованої GARCH моделі
    simulations = result.forecast(horizon=horizon, method='simulation', 
                                   simulations=n_sims)
    return simulations.simulations.values

Аналіз результатів симуляції

def analyze_simulation_results(portfolio_paths, initial_value, 
                                 confidence_levels=[0.05, 0.25, 0.50, 0.75, 0.95]):
    final_values = portfolio_paths[:, -1]
    
    # Розподіл фінальних значень
    percentiles = {f'p{int(c*100)}': np.percentile(final_values, c*100) 
                   for c in confidence_levels}
    
    # Ймовірність втрати
    prob_loss = (final_values < initial_value).mean()
    
    # Очікуваний return і std
    returns = (final_values - initial_value) / initial_value
    
    # VaR з симуляції
    var_95 = np.percentile(final_values - initial_value, 5)
    cvar_95 = (final_values - initial_value)[
        final_values - initial_value <= var_95
    ].mean()
    
    # Розподіл max drawdown
    max_drawdowns = []
    for path in portfolio_paths:
        peaks = np.maximum.accumulate(path)
        drawdowns = (peaks - path) / peaks
        max_drawdowns.append(drawdowns.max())
    
    return {
        'percentiles': percentiles,
        'prob_loss': prob_loss,
        'expected_return': returns.mean(),
        'return_std': returns.std(),
        'var_95': var_95,
        'cvar_95': cvar_95,
        'avg_max_drawdown': np.mean(max_drawdowns),
        'worst_max_drawdown': np.max(max_drawdowns)
    }

Візуалізація результатів

Fan chart: показує діапазон можливих траєкторій портфеля. Центральна лінія — медіана (50-й перцентиль). Темніші зони — вірогідні діапазони (25-75%), світліші — рідкісні (5-95%).

Гістограма розподілу returns: гістограма фінальних returns з усіх симуляцій. Нормальний vs реальний розподіл.

Розподіл drawdown: гістограма максимальних drawdown по симуляціях. Показує ймовірність різних рівнів просідання.

Застосування в управлінні портфелем

Ймовірність досягнення цілі: «яка ймовірність що портфель виросте на 50% за рік при поточній стратегії?»

Порівняння стратегій: запустити симуляцію для двох стратегій, порівняти розподіли результатів.

Оптимальна частота ребалансування: симулювати портфель з різними частотами ребалансування, вибрати оптимальну.

Розподіл капіталу: скільки виділити на ризиковану vs консервативну стратегію для досягнення цілі при допустимому ризику?

Технічний стек

Python (numpy, scipy, arch для GARCH), Numba для прискорення симуляцій (JIT компіляція дає 10-50x прискорення), pandas для обробки даних, matplotlib/plotly для візуалізації fan chart. 10,000 симуляцій на 252 дні займають < 1 секунди з Numba.

Розробляємо систему Monte Carlo симуляції з підтримкою GBM, fat-tail розподілів та GARCH моделі, мультиактивною симуляцією з кореляціями, аналізом результатів (перцентилі, VaR, розподіл drawdown) та інтерактивними візуалізаціями.