scipy.stats для точного моделирования «тяжелых хвостов» (fat tails) крипторынка.Видеоинструкция
Исходный код
Классическое геометрическое броуновское движение (GBM) предполагает нормальное распределение доходностей. Однако для криптовалют характерны экстремальные выбросы и тяжелые хвосты. Использование многомерного распределения Стьюдента (multivariate_t) из библиотеки scipy позволяет построить гораздо более реалистичную модель риска.
Перед расчетом ковариационной матрицы критически важно очистить исторические данные от рыночных манипуляций и аномалий. В этом поможет статья про Выявление Аномалий в Торговых Объемах: Isolation Forest в Python.
Для более глубокого анализа структуры портфеля и снижения размерности перед симуляцией полезно использовать PCA для портфеля альткоинов: Уменьшение размерности в Python scikit-learn.
Если вы работаете с деривативами в портфеле, рекомендуем ознакомиться с руководством по Бэктесту опционных стратегий Iron Condor на Python с Implied Volatility.
import numpy as np
import pandas as pd
from scipy.stats import multivariate_t
# Настройка воспроизводимости
np.random.seed(42)
# 1. Генерация синтетических исторических доходностей (BTC, ETH, SOL)
# Используем распределение Стьюдента для симуляции тяжелых хвостов
num_assets = 3
df_historical = 3.0 # Степени свободы для крипты
loc_historical = np.array([0.0012, 0.0018, 0.0025]) # Ожидаемая дневная доходность
shape_historical = np.array([
[0.0008, 0.0005, 0.0004],
[0.0005, 0.0012, 0.0006],
[0.0004, 0.0006, 0.0020]
])
# Генерируем 1000 дней "истории"
hist_returns = multivariate_t.rvs(
loc=loc_historical,
shape=shape_historical,
df=df_historical,
size=1000
)
# 2. Оценка параметров для Монте-Карло
mean_returns = np.mean(hist_returns, axis=0)
cov_matrix = np.cov(hist_returns, rowvar=False)
# Задаем степени свободы для симуляции (тяжелые хвосты)
nu = 3.0
# Корректируем матрицу формы для распределения Стьюдента
shape_matrix = cov_matrix * (nu - 2) / nu
# 3. Параметры симуляции Монте-Карло
num_simulations = 100000
time_horizon = 10 # Горизонт риска в днях
portfolio_value = 1000000.0 # Размер портфеля в USD
weights = np.array([0.50, 0.30, 0.20]) # BTC: 50%, ETH: 30%, SOL: 20%
# 4. Генерация многомерных случайных величин
# Генерируем доходности для всех симуляций и дней сразу
sim_returns = multivariate_t.rvs(
loc=mean_returns,
shape=shape_matrix,
df=nu,
size=(num_simulations, time_horizon)
)
# 5. Расчет доходности портфеля по путям
portfolio_sim_returns = np.zeros(num_simulations)
for i in range(num_simulations):
# Накапливаем доходность активов за time_horizon дней: prod(1 + r) - 1
cum_asset_returns = np.prod(1 + sim_returns[i], axis=0) - 1
# Взвешенная доходность портфеля
portfolio_sim_returns[i] = np.dot(cum_asset_returns, weights)
# Расчет конечной стоимости и убытков
portfolio_end_values = portfolio_value * (1 + portfolio_sim_returns)
portfolio_losses = portfolio_value - portfolio_end_values
# 6. Расчет метрик риска (VaR и CVaR)
confidence_levels = [0.95, 0.99]
risk_metrics = {}
for cl in confidence_levels:
# Value at Risk (VaR)
var = np.percentile(portfolio_losses, cl * 100)
# Conditional Value at Risk (CVaR)
cvar = portfolio_losses[portfolio_losses >= var].mean()
risk_metrics[cl] = {'VaR': var, 'CVaR': cvar}
# Вывод результатов
for cl, metrics in risk_metrics.items():
print(f'Уровень доверия {cl*100}%:')
print(f' Value at Risk (VaR): ${metrics["VaR"]:,.2f}')
print(f' Conditional Value at Risk (CVaR): ${metrics["CVaR"]:,.2f}') Разбор параметров
multivariate_t: Класс из модуляscipy.stats, используемый для генерации многомерного распределения Стьюдента, которое лучше описывает экстремальные риски криптовалют по сравнению с нормальным распределением.df(degrees of freedom): Число степеней свободы. Чем меньше этот параметр, тем «тяжелее» хвосты распределения. Для крипторынка стандартным выбором является диапазон от 2.5 до 4.0.shape_matrix: Матрица формы (масштаба). В распределении Стьюдента она связана с ковариационной матрицей формулойcov * (nu - 2) / nuдляnu > 2.portfolio_losses: Массив смоделированных убытков портфеля в базовой валюте (USD) на конец временного горизонта. Используется для расчета квантилей риска.np.percentile: Функция для расчета Value at Risk (VaR) как определенного квантиля распределения убытков.
Как запустить
Для запуска симуляции вам понадобятся библиотеки numpy, pandas и scipy. Установите их с помощью пакетного менеджера pip:
pip install numpy pandas scipy Скопируйте исходный код в файл monte_carlo.py и запустите его в терминале или вашей любимой IDE. Скрипт сгенерирует синтетические исторические данные, настроит параметры распределения Стьюдента, проведет 100 000 итераций симуляции для 10-дневного горизонта и выведет значения VaR и CVaR для уровней доверия 95% и 99%.




