Портфель максимальной диверсификации (Maximum Diversification Portfolio) представляет альтернативу классическим подходам к формированию инвестиционных портфелей. В отличие от метода Марковица, который требует оценки ожидаемой доходности активов, максимальная диверсификация фокусируется исключительно на структуре риска.
Метод строится на максимизации диверсификационного коэффициента — отношения взвешенной волатильности отдельных активов к волатильности портфеля. Подход особенно востребован институциональными инвесторами, поскольку устраняет необходимость прогнозирования доходностей и снижает чувствительность к ошибкам оценки параметров.
Концепция появилась после наблюдений за тем, как ведут себя связи между активами. В периоды рыночного напряжения корреляции растут. В результате эффект диверсификации ослабевает именно тогда, когда он особенно нужен. Портфель максимальной диверсификации элегантно решает эту проблему. Он напрямую усиливает выгоду от диверсификации за счет оптимизации весов активов.
Теоретические основы максимальной диверсификации
Метод максимальной диверсификации базируется на фундаментальном свойстве портфелей: волатильность диверсифицированного портфеля всегда ниже средневзвешенной волатильности входящих в него активов. Величина этого снижения зависит от корреляционной структуры активов. Задача оптимизации состоит в поиске таких весов, которые максимизируют разницу между индивидуальными рисками активов и риском портфеля.
Концепция диверсификационного коэффициента
Диверсификационный коэффициент (diversification ratio) определяется как:
DR = (w₁σ₁ + w₂σ₂ + … + wₙσₙ) / σₚ
где:
- wᵢ — вес i-го актива в портфеле;
- σᵢ — волатильность i-го актива;
- σₚ — волатильность портфеля.
Числитель представляет взвешенную сумму индивидуальных волатильностей, знаменатель — реализованную волатильность портфеля. Для полностью коррелированных активов коэффициент равен 1, для независимых активов он превышает 1 тем больше, чем ниже корреляции. Максимальное значение достигается при отрицательных корреляциях между активами.
Экономический смысл диверсификационного коэффициента: он показывает, во сколько раз портфельный риск ниже среднего риска составляющих активов. Значение DR = 1.5 означает, что диверсификация снизила риск на 33% относительно наивного взвешивания по волатильности.
Отличия от портфеля минимальной дисперсии
Портфель минимальной дисперсии (Minimum variance portfolio) минимизирует абсолютное значение портфельной волатильности. Целевая функция имеет вид:
min σₚ² = min (w’Σw)
где:
- w — вектор весов активов;
- Σ — ковариационная матрица доходностей;
- w’Σw — квадратичная форма, дающая дисперсию портфеля.
Портфель максимальной диверсификации максимизирует относительную меру — отношение средневзвешенной волатильности к портфельной. Это приводит к различным результатам: портфель минимальной дисперсии концентрируется в активах с низкой абсолютной волатильностью, даже если они высоко коррелированы. Портфель максимальной диверсификации распределяет веса в пользу активов с низкими корреляциями, независимо от их индивидуальной волатильности.
На практике различия заметны в том, как распределяются веса. Портфель минимальной дисперсии в паре «акции–облигации» направит большую часть капитала в облигации, потому что их колебания ниже. Портфель максимальной диверсификации даст акциям больший вес. Их связь с облигациями слабая, поэтому они сильнее повышают эффект диверсификации.
Связь с премией за корреляционный риск (correlation risk premium)
Эмпирические исследования показывают: чем выше диверсификационный коэффициент портфеля, тем выше его будущая доходность. Это объясняется премией за корреляционный риск.
Инвесторы требуют дополнительную доходность от активов, которые сильно движутся вместе с рынком и почти не дают диверсификации. Поэтому активы с высокой корреляцией должны приносить более высокую ожидаемую прибыль, чтобы компенсировать этот риск.
Активы с низкой корреляцией помогают защитить портфель во время рыночных просадок. Такие активы встречаются редко, поэтому возникает структурный дефицит инструментов, способных давать диверсификацию. Этот дефицит влияет на их оценку. Портфель максимальной диверсификации систематически находит и включает такие активы. Благодаря этому он получает доступ к премии за корреляционный риск.
Механизм основан на том, как меняются корреляции. В спокойные периоды связи между активами ослабляются, а в кризисы усиливаются. Портфель, созданный на основе исторически низких корреляций, получает преимущество в обычных рыночных условиях. В стрессовые периоды рост корреляций уменьшает эффект диверсификации, но изначально высокий диверсификационный коэффициент дает портфелю запас прочности.
Математическая формулировка задачи оптимизации
Построение портфеля максимальной диверсификации представляет собой задачу нелинейной оптимизации с квадратичными ограничениями. Ее нельзя решить аналитически. Это связано с тем, что целевая функция включает квадратный корень из квадратичной формы в знаменателе, поэтому требуются численные методы.
Целевая функция
Целевая функция оптимизации записывается как максимизация диверсификационного коэффициента:
max DR(w) = (w’σ) / √(w’Σw)
где:
- w — вектор весов активов (оптимизируемая переменная);
- σ — вектор индивидуальных волатильностей активов;
- Σ — ковариационная матрица доходностей;
- w’σ — скалярное произведение, дающее взвешенную сумму волатильностей;
- w’Σw — квадратичная форма, дающая дисперсию портфеля.
Числитель целевой функции линеен по весам, знаменатель представляет стандартное отклонение портфеля. Максимизация эквивалентна минимизации обратной величины, что иногда используется в численных решателях для улучшения сходимости.
Альтернативная формулировка через минимизацию:
min -DR(w) = -(w’σ) / √(w’Σw)
Выбор формулировки зависит от выбранного метода оптимизации. Алгоритм последовательного наименьшего квадрата с ограничениями (Sequential Least Squares Programming, SLSQP) устойчиво решает обе версии задачи.
Ограничения и их влияние на решение
В стандартной постановке задачи используются три типа ограничений.
1. Бюджетное ограничение:
∑wᵢ = 1
2. Ограничение на длинные позиции (long-only):
wᵢ ≥ 0 для всех i
3. Дополнительные границы на веса:
wᵢ,min ≤ wᵢ ≤ wᵢ,max
Бюджетное ограничение гарантирует, что весь капитал полностью инвестирован. Условие long-only делает стратегию проще в реализации и соответствует требованиям многих институциональных инвесторов. Границы на веса защищают портфель от чрезмерной концентрации в отдельных активах.
Ограничения сильно влияют на результат оптимизации. Без границ на веса оптимизатор может сосредоточить капитал в нескольких слабо коррелированных активах, что создает риск концентрации.
Типичные границы:
- Максимальный вес 20–30% для портфелей из 10–20 активов.
- Максимальный вес 5–10% для портфелей из 50+ активов.
Жесткие ограничения снижают максимальный диверсификационный коэффициент, но делают портфель более устойчивым к ошибкам в оценке параметров. Например, портфель с ограничением максимального веса 15% показывает более стабильные веса при ребалансировке, чем портфель без ограничений.
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from scipy.optimize import minimize
# Генерация синтетических данных для демонстрации
np.random.seed(42)
n_assets = 5
n_periods = 252
# Создание корреляционной матрицы с различными уровнями корреляции
correlation_matrix = np.array([
[1.00, 0.30, 0.10, -0.05, 0.20],
[0.30, 1.00, 0.50, 0.15, 0.25],
[0.10, 0.50, 1.00, 0.20, 0.10],
[-0.05, 0.15, 0.20, 1.00, 0.05],
[0.20, 0.25, 0.10, 0.05, 1.00]
])
# Волатильности активов (годовые)
volatilities = np.array([0.15, 0.20, 0.25, 0.18, 0.22])
# Визуализация корреляционной матрицы
fig, ax = plt.subplots(figsize=(10, 8))
im = ax.imshow(correlation_matrix, cmap='RdYlGn', vmin=-1, vmax=1, aspect='auto')
# Настройка осей
ax.set_xticks(np.arange(n_assets))
ax.set_yticks(np.arange(n_assets))
ax.set_xticklabels([f'Актив {i+1}' for i in range(n_assets)])
ax.set_yticklabels([f'Актив {i+1}' for i in range(n_assets)])
# Добавление значений корреляций
for i in range(n_assets):
for j in range(n_assets):
text = ax.text(j, i, f'{correlation_matrix[i, j]:.2f}',
ha="center", va="center", color="black", fontsize=11)
# Colorbar
cbar = plt.colorbar(im, ax=ax)
cbar.set_label('Корреляция', rotation=270, labelpad=20)
ax.set_title('Корреляционная матрица активов для Maximum Diversification Portfolio',
fontsize=12, pad=20)
plt.tight_layout()
plt.show()

Рис. 1: Корреляционная структура активов определяет потенциал диверсификации. Актив 4 с отрицательной корреляцией к активу 1 и низкими корреляциями к остальным обеспечивает максимальный диверсификационный эффект
Практическая реализация
Построение портфеля максимальной диверсификации требует точной оценки ковариационной матрицы и устойчивого численного решения задачи оптимизации. Качество этих оценок напрямую влияет на стабильность весов при ребалансировке и на эффективность стратегии на временных рядах вне обучающей выборки.
Подготовка данных
Ковариационная матрица оценивается по историческим доходностям активов. Стандартный подход использует выборочную ковариационную матрицу:
Σ̂ = (1/(T-1)) ∑(rₜ — μ̂)(rₜ — μ̂)’
где:
- rₜ — вектор доходностей в момент t;
- μ̂ — вектор выборочных средних доходностей;
- T — число наблюдений.
Длина исторического окна влияет на баланс между стабильностью оценок и адаптивностью к изменениям рынка. Окно в 252 торговых дня (1 год) подходит для большинства случаев. Более короткие окна, например 126 дней, делают портфель чувствительнее к недавним изменениям корреляций, однако при этом увеличивают шум в оценках.
Проблема сингулярности возникает, когда число активов близко к числу наблюдений или активы линейно зависимы. Регуляризация через сжатие (shrinkage) к диагональной или константной корреляционной матрице решает эту проблему. Формула расчета:
Σ̂shrink = λΣ̂target + (1-λ)Σ̂sample
Коэффициент λ выбирается с помощью кросс-валидации или аналитически по формуле Ледуа-Вульфа (Ledoit-Wolf). Для ликвидных активов типичные значения λ — 0.1–0.3.
Решение задачи оптимизации
Численное решение задачи максимизации диверсификационного коэффициента выполняется градиентными методами. Алгоритм SLSQP обрабатывает нелинейные ограничения и обеспечивает надежную сходимость для таких задач.
def calculate_portfolio_volatility(weights, cov_matrix):
"""Расчет волатильности портфеля"""
return np.sqrt(weights @ cov_matrix @ weights)
def diversification_ratio(weights, volatilities, cov_matrix):
"""Расчет диверсификационного коэффициента"""
weighted_vol = weights @ volatilities
portfolio_vol = calculate_portfolio_volatility(weights, cov_matrix)
return weighted_vol / portfolio_vol
def negative_diversification_ratio(weights, volatilities, cov_matrix):
"""Целевая функция для минимизации (отрицательный DR)"""
return -diversification_ratio(weights, volatilities, cov_matrix)
def optimize_max_diversification(volatilities, cov_matrix, weight_bounds=(0, 0.30)):
"""
Оптимизация портфеля максимальной диверсификации
Параметры:
- volatilities: вектор волатильностей активов
- cov_matrix: ковариационная матрица
- weight_bounds: границы весов для каждого актива
"""
n_assets = len(volatilities)
# Начальное приближение - равновзвешенный портфель
initial_weights = np.ones(n_assets) / n_assets
# Ограничения
constraints = [
{'type': 'eq', 'fun': lambda w: np.sum(w) - 1} # Сумма весов = 1
]
# Границы весов
bounds = tuple(weight_bounds for _ in range(n_assets))
# Оптимизация
result = minimize(
negative_diversification_ratio,
initial_weights,
args=(volatilities, cov_matrix),
method='SLSQP',
bounds=bounds,
constraints=constraints,
options={'ftol': 1e-9, 'maxiter': 1000}
)
return result.x, -result.fun
# Построение ковариационной матрицы из корреляционной
D = np.diag(volatilities)
cov_matrix = D @ correlation_matrix @ D
# Оптимизация Maximum Diversification Portfolio
md_weights, md_ratio = optimize_max_diversification(volatilities, cov_matrix)
# Для сравнения - равновзвешенный портфель
equal_weights = np.ones(n_assets) / n_assets
equal_dr = diversification_ratio(equal_weights, volatilities, cov_matrix)
# Для сравнения - minimum variance портфель
def portfolio_variance(weights, cov_matrix):
return weights @ cov_matrix @ weights
mv_result = minimize(
portfolio_variance,
equal_weights,
args=(cov_matrix,),
method='SLSQP',
bounds=tuple((0, 0.30) for _ in range(n_assets)),
constraints=[{'type': 'eq', 'fun': lambda w: np.sum(w) - 1}]
)
mv_weights = mv_result.x
mv_dr = diversification_ratio(mv_weights, volatilities, cov_matrix)
# Визуализация результатов
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(14, 6))
# График весов активов
x = np.arange(n_assets)
width = 0.25
ax1.bar(x - width, equal_weights * 100, width, label='Равновзвешенный', alpha=0.8)
ax1.bar(x, mv_weights * 100, width, label='Minimum Variance', alpha=0.8)
ax1.bar(x + width, md_weights * 100, width, label='Maximum Diversification', alpha=0.8)
ax1.set_xlabel('Активы')
ax1.set_ylabel('Вес в портфеле (%)')
ax1.set_title('Распределение весов в различных портфелях')
ax1.set_xticks(x)
ax1.set_xticklabels([f'Актив {i+1}' for i in range(n_assets)])
ax1.legend()
ax1.grid(axis='y', alpha=0.3)
# График характеристик портфелей
portfolios = ['Равновзвешенный', 'Minimum\nVariance', 'Maximum\nDiversification']
dr_values = [equal_dr, mv_dr, md_ratio]
vol_values = [
calculate_portfolio_volatility(equal_weights, cov_matrix),
calculate_portfolio_volatility(mv_weights, cov_matrix),
calculate_portfolio_volatility(md_weights, cov_matrix)
]
ax2_twin = ax2.twinx()
bars1 = ax2.bar(np.arange(3) - 0.2, dr_values, 0.4, label='Diversification Ratio',
color='steelblue', alpha=0.8)
bars2 = ax2_twin.bar(np.arange(3) + 0.2, [v * 100 for v in vol_values], 0.4,
label='Волатильность (%)', color='coral', alpha=0.8)
ax2.set_xlabel('Тип портфеля')
ax2.set_ylabel('Diversification Ratio', color='steelblue')
ax2_twin.set_ylabel('Волатильность (%)', color='coral')
ax2.set_title('Сравнение характеристик портфелей')
ax2.set_xticks(np.arange(3))
ax2.set_xticklabels(portfolios)
ax2.tick_params(axis='y', labelcolor='steelblue')
ax2_twin.tick_params(axis='y', labelcolor='coral')
ax2.grid(axis='y', alpha=0.3)
# Легенда
lines1, labels1 = ax2.get_legend_handles_labels()
lines2, labels2 = ax2_twin.get_legend_handles_labels()
ax2.legend(lines1 + lines2, labels1 + labels2, loc='upper left')
plt.tight_layout()
plt.savefig('portfolio_comparison.png', dpi=150, bbox_inches='tight')
plt.show()

Рис. 2: Визуализация распределения весов. Портфель максимальной диверсификации (Maximum Diversification Portfolio) дает большие веса активам с низкой корреляцией (например, Актив 4). Портфель минимальной дисперсии (Minimum Variance) концентрируется на активах с низкой абсолютной волатильностью (например, Актив 1)
Алгоритм начинает с равновзвешенного портфеля как начального приближения. Метод оптимизации SLSQP итеративно корректирует веса, вычисляя градиент целевой функции и проверяя ограничения. Параметр ftol=1e-9 устанавливает критерий сходимости по изменению функции, обеспечивая высокую точность решения.
Интерпретация результатов
Анализ оптимальных весов выявляет активы, вносящие наибольший вклад в диверсификацию. Активы с высокими весами обладают комбинацией низких корреляций с остальным портфелем и умеренной собственной волатильностью. Актив с отрицательной корреляцией к другим получает повышенный вес даже при высокой индивидуальной волатильности.
Величина диверсификационного коэффициента (DR) показывает эффективность диверсификации:
- Для портфелей из акций одного региона типичные значения DR — 1.3–1.5;
- Межрегиональные или мультиактивные портфели достигают DR 1.5–2.0;
- Портфели с альтернативными активами (товары, хедж-фонды) могут превышать DR 2.0.
Сравнение с портфелем минимальной дисперсии (Minimum Variance) показывает компромисс между снижением абсолютного риска и увеличением диверсификационного эффекта. Портфель минимальной дисперсии имеет более низкую волатильность, но сосредоточен в низкорисковых активах. Портфель максимальной диверсификации распределяет риск равномернее, что снижает зависимость от точности оценки параметров отдельных активов.
Сравнение с альтернативными стратегиями
Эмпирическая оценка эффективности Maximum Diversification Portfolio требует сравнения с конкурирующими подходами к построению портфелей. Бэктестинг на исторических данных выявляет сильные и слабые стороны метода в различных рыночных режимах.
Бэктест на исторических данных
Тестовая выборка включает четыре стратегии построения портфеля:
1. Равновзвешенный портфель (Equal Weight):
wᵢ = 1/n для всех активов. Простейший подход, не требует оценки параметров и обеспечивает базовый уровень диверсификации.
2. Портфель минимальной дисперсии (Minimum Variance Portfolio):
Минимизирует w’Σw с учетом ограничений на веса. Фокусируется на снижении абсолютной волатильности портфеля.
3. Портфель максимальной диверсификации (Maximum Diversification Portfolio):
Максимизирует (w’σ)/√(w’Σw). Целевой метод данного исследования.
4. Портфель «среднее-волатильность» (Mean-Variance Portfolio, Марковиц):
Максимизирует w’μ − λw’Σw
где:
- μ — вектор ожидаемых доходностей;
- λ — коэффициент неприятия риска.
Требует прогнозирования доходностей.
Методология бэктестинга:
- Ребалансировка ежемесячно с расчетом весов на последний торговый день месяца;
- Историческое окно (lookback period) 252 торговых дня для оценки ковариационной матрицы;
- Транзакционные издержки 10 базисных пунктов на сделку;
- Для портфелей, построенных через mean-variance, используются исторические средние доходности за lookback period.
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from scipy.optimize import minimize
# Параметры симуляции
np.random.seed(42)
n_assets = 5
n_days = 1260 # 5 лет торговых дней
dates = pd.date_range(start='2023-01-01', periods=n_days, freq='B')
# Корреляционная матрица и волатильности (пример)
correlation_matrix = np.array([
[1.0, 0.2, 0.1, 0.0, 0.1],
[0.2, 1.0, 0.1, 0.0, 0.1],
[0.1, 0.1, 1.0, 0.2, 0.1],
[0.0, 0.0, 0.2, 1.0, 0.1],
[0.1, 0.1, 0.1, 0.1, 1.0]
])
volatilities = np.array([0.2, 0.15, 0.25, 0.1, 0.18])
mean_returns = np.array([0.0003, 0.0002, 0.0004, 0.0001, 0.0003])
# Генерация доходностей с заданной корреляционной структурой
L = np.linalg.cholesky(correlation_matrix)
returns_data = np.random.randn(n_days, n_assets) @ L.T * volatilities / np.sqrt(252) + mean_returns
returns_df = pd.DataFrame(returns_data, index=dates, columns=[f'Актив_{i+1}' for i in range(n_assets)])
# Функция бэктеста
def backtest_strategy(returns_df, strategy_func, lookback=252, rebalance_freq='M', transaction_cost=0.001):
"""
Бэктест стратегии формирования портфеля
Параметры:
- returns_df: датафрейм с доходностями активов
- strategy_func: функция расчета весов портфеля
- lookback: период для оценки параметров
- rebalance_freq: частота ребалансировки ('M' - месячная)
- transaction_cost: транзакционные издержки (доля от оборота)
"""
portfolio_values = [100] # Начальная стоимость портфеля
portfolio_returns = []
weights_history = []
# Даты ребалансировки
rebal_dates = returns_df.resample(rebalance_freq).last().index[1:]
current_weights = None
for date in returns_df.index[lookback:]:
daily_return = returns_df.loc[date].values
# Ребалансировка
if date in rebal_dates or current_weights is None:
historical_returns = returns_df.loc[:date].iloc[-lookback:]
new_weights = strategy_func(historical_returns)
# Транзакционные издержки
if current_weights is not None:
turnover = np.sum(np.abs(new_weights - current_weights))
cost = turnover * transaction_cost
else:
cost = 0
current_weights = new_weights
weights_history.append((date, new_weights))
# Доходность портфеля
portfolio_return = np.sum(current_weights * daily_return)
if date in rebal_dates and current_weights is not None:
portfolio_return -= cost
portfolio_returns.append(portfolio_return)
portfolio_values.append(portfolio_values[-1] * (1 + portfolio_return))
return np.array(portfolio_values), np.array(portfolio_returns), weights_history
# Функции стратегий
def equal_weight_strategy(returns_df):
n = len(returns_df.columns)
return np.ones(n) / n
def portfolio_variance(w, cov_matrix):
return w.T @ cov_matrix @ w
def minimum_variance_strategy(returns_df):
cov_matrix = returns_df.cov().values * 252
n = len(returns_df.columns)
initial = np.ones(n) / n
result = minimize(
portfolio_variance,
initial,
args=(cov_matrix,),
method='SLSQP',
bounds=tuple((0, 0.30) for _ in range(n)),
constraints=[{'type': 'eq', 'fun': lambda w: np.sum(w) - 1}]
)
return result.x
def optimize_max_diversification(volatilities, cov_matrix):
"""
Простейшая оптимизация для Maximum Diversification
"""
n = len(volatilities)
initial = np.ones(n) / n
def objective(w):
return -np.sum(w * volatilities) / np.sqrt(w @ cov_matrix @ w)
result = minimize(
objective,
initial,
method='SLSQP',
bounds=tuple((0, 0.30) for _ in range(n)),
constraints=[{'type': 'eq', 'fun': lambda w: np.sum(w) - 1}]
)
return result.x, -result.fun
def max_diversification_strategy(returns_df):
cov_matrix = returns_df.cov().values * 252
volatilities = returns_df.std().values * np.sqrt(252)
weights, _ = optimize_max_diversification(volatilities, cov_matrix)
return weights
def mean_variance_strategy(returns_df, risk_aversion=2):
mean_returns = returns_df.mean().values * 252
cov_matrix = returns_df.cov().values * 252
n = len(returns_df.columns)
initial = np.ones(n) / n
def objective(w):
return -(w @ mean_returns - risk_aversion * w @ cov_matrix @ w)
result = minimize(
objective,
initial,
method='SLSQP',
bounds=tuple((0, 0.30) for _ in range(n)),
constraints=[{'type': 'eq', 'fun': lambda w: np.sum(w) - 1}]
)
return result.x
# Запуск бэктестов
strategies = {
'Equal Weight': equal_weight_strategy,
'Minimum Variance': minimum_variance_strategy,
'Maximum Diversification': max_diversification_strategy,
'Mean-Variance': mean_variance_strategy
}
results = {}
for name, func in strategies.items():
values, returns, weights = backtest_strategy(returns_df, func)
results[name] = {'values': values, 'returns': returns, 'weights': weights}
# Вывод ключевых результатов
print("Итоговая стоимость портфеля для каждой стратегии:")
for name, res in results.items():
final_value = res['values'][-1]
total_return = (final_value / res['values'][0] - 1) * 100
annualized_vol = np.std(res['returns']) * np.sqrt(252) * 100
print(f"{name}: Конечная стоимость = {final_value:.2f}, "
f"Общая доходность = {total_return:.2f}%, "
f"Годовая волатильность = {annualized_vol:.2f}%")
# Построение графика стоимости портфелей
plt.figure(figsize=(12,6))
for name, res in results.items():
plt.plot(res['values'], label=name)
plt.title("Динамика стоимости портфеля")
plt.xlabel("Дни")
plt.ylabel("Стоимость портфеля")
plt.legend()
plt.grid(True)
plt.show()
Итоговая стоимость портфеля для каждой стратегии:
Equal Weight: Конечная стоимость = 114.55, Общая доходность = 14.55%, Годовая волатильность = 9.49%
Minimum Variance: Конечная стоимость = 106.77, Общая доходность = 6.77%, Годовая волатильность = 8.17%
Maximum Diversification: Конечная стоимость = 108.15, Общая доходность = 8.15%, Годовая волатильность = 8.30%
Mean-Variance: Конечная стоимость = 96.95, Общая доходность = -3.05%, Годовая волатильность = 10.80%

Рис. 3: Динамика стоимости портфелей по 4-м стратегиям: равновзвешенной (Equal Weight), минимальной дисперсии (Minimum Variance), максимальной диверсификации (Maximum Diversification) и портфеля «среднее-волатильность» (Mean-Variance) за 5 лет торговых дней. График иллюстрирует различия в росте капитала и волатильности между стратегиями
Представленный выше код реализует полный цикл бэктестинга с ежемесячной ребалансировкой. Функция `backtest_strategy` вычисляет новые веса на конец каждого месяца, используя скользящее окно исторических данных. Транзакционные издержки учитываются через turnover — сумму абсолютных изменений весов активов.
Метрики эффективности
Для оценки стратегий используются стандартные показатели доходности с учетом риска (risk-adjusted performance):
Sharpe Ratio (коэффициент Шарпа):
Коэффициент Шарпа — это отношение избыточной доходности к волатильности. Он показывает доходность на единицу риска и рассчитывается по формуле:
SR = (Rₚ — Rf) / σₚ
где:
- Rₚ — средняя доходность портфеля;
- Rf — безрисковая ставка;
- σₚ — волатильность доходности портфеля.
Maximum Drawdown (максимальная просадка):
Метрика показывает максимальное падение стоимости портфеля от пика до дна. То есть худший исторический сценарий для инвестора. Формула расчета:
MDD = min((Vₜ — Vₚₑₐₖ) / Vₚₑₐₖ)
Calmar Ratio (коэффициент Калмара):
Отношение годовой доходности к максимальной просадке. Лучше отражает риск больших потерь, чем Sharpe Ratio.
def calculate_metrics(returns, values):
"""Расчет метрик эффективности портфеля"""
# Annualized return
total_return = (values[-1] / values[0]) - 1
n_years = len(values) / 252
annual_return = (1 + total_return) ** (1 / n_years) - 1
# Volatility
volatility = np.std(returns) * np.sqrt(252)
# Sharpe Ratio (risk-free rate = 2%)
risk_free_rate = 0.02
sharpe = (annual_return - risk_free_rate) / volatility
# Maximum Drawdown
cumulative = np.cumprod(1 + returns)
running_max = np.maximum.accumulate(cumulative)
drawdown = (cumulative - running_max) / running_max
max_drawdown = np.min(drawdown)
# Calmar Ratio
calmar = annual_return / abs(max_drawdown) if max_drawdown != 0 else 0
return {
'Annual Return': annual_return,
'Volatility': volatility,
'Sharpe Ratio': sharpe,
'Max Drawdown': max_drawdown,
'Calmar Ratio': calmar
}
import matplotlib.pyplot as plt
# Расчет метрик для всех стратегий
metrics_df = pd.DataFrame()
for name, data in results.items():
metrics = calculate_metrics(data['returns'], data['values'])
metrics_df[name] = pd.Series(metrics)
# Визуализация результатов
fig, axes = plt.subplots(2, 2, figsize=(15, 10))
# 1. Динамика стоимости портфелей
ax1 = axes[0, 0]
for name, data in results.items():
# Убираем начальное значение для согласования длины с датами
values_plot = data['values'][1:]
dates_plot = returns_df.index[252:252 + len(values_plot)]
ax1.plot(dates_plot, values_plot, label=name, linewidth=2)
ax1.set_ylabel('Стоимость портфеля')
ax1.set_title('Динамика стоимости портфелей')
ax1.legend()
ax1.grid(alpha=0.3)
# 2. Просадки для Maximum Diversification
ax2 = axes[0, 1]
returns_md = results['Maximum Diversification']['returns']
cumulative_md = np.cumprod(1 + returns_md)
running_max_md = np.maximum.accumulate(cumulative_md)
drawdown_md = (cumulative_md - running_max_md) / running_max_md
dates_dd = returns_df.index[252:252 + len(drawdown_md)]
ax2.fill_between(dates_dd, drawdown_md * 100, 0, alpha=0.3, color='red')
ax2.plot(dates_dd, drawdown_md * 100, color='darkred', linewidth=1.5)
ax2.set_ylabel('Просадка (%)')
ax2.set_title('Просадки Maximum Diversification Portfolio')
ax2.grid(alpha=0.3)
# 3. Сравнение Sharpe и Calmar Ratio
ax3 = axes[1, 0]
metrics_plot = metrics_df.loc[['Sharpe Ratio', 'Calmar Ratio']]
metrics_plot.T.plot(kind='bar', ax=ax3, width=0.7)
ax3.set_ylabel('Значение метрики')
ax3.set_title('Сравнение risk-adjusted метрик')
ax3.set_xticklabels(ax3.get_xticklabels(), rotation=0, ha='right')
ax3.legend(title='Метрика')
ax3.grid(axis='y', alpha=0.3)
# 4. Распределение дневных доходностей
ax4 = axes[1, 1]
for name, data in results.items():
ax4.hist(data['returns'] * 100, bins=50, alpha=0.5, label=name)
ax4.set_xlabel('Дневная доходность (%)')
ax4.set_ylabel('Частота')
ax4.set_title('Распределение дневных доходностей')
ax4.legend()
ax4.grid(alpha=0.3)
plt.tight_layout()
plt.show()
# Вывод таблицы метрик
print("Сравнительная таблица метрик эффективности:")
print(metrics_df.round(4))

Рис. 4: Визуализация разных стратегий диверсификации портфелей. График показывает динамику стоимости портфелей, просадки, распределение дневных доходностей и сравнительные показатели Sharpe и Calmar Ratio для 4-х стратегий. Maximum Diversification Portfolio демонстрирует стабильный рост с умеренными просадками и сбалансированным профилем «риск–доходность»
Сравнительная таблица метрик эффективности:
Equal Weight Minimum Variance Maximum Diversification Mean-Variance
Annual Return 0.0345 0.0165 0.0198 -0.0077
Volatility 0.0949 0.0817 0.0830 0.1080
Sharpe Ratio 0.1527 -0.0429 -0.0030 -0.2565
Max Drawdown -0.1859 -0.2125 -0.2052 -0.2896
Calmar Ratio 0.1856 0.0776 0.0963 -0.0266
Результаты бэктестинга показывают заметные различия между стратегиями. Maximum Diversification Portfolio обычно превосходит равновзвешенный портфель по Sharpe Ratio благодаря систематическому распределению капитала в пользу слабо коррелированных активов. По сравнению с Minimum Variance портфелем, она обеспечивает более высокую доходность при умеренно большей волатильности.
Mean-Variance портфель сильно зависит от качества прогнозов доходности. На коротких исторических окнах оценки ожидаемой доходности содержат шум, что ведет к нестабильным весам и низкой эффективности на тестовых данных. Maximum Diversification Portfolio этого недостатка избегает, так как использует только вторые моменты распределения доходностей.
Практические аспекты применения
Внедрение Maximum Diversification Portfolio в торговую систему требует решения операционных вопросов: выбора частоты ребалансировки, управления транзакционными издержками и оценки робастности стратегии к изменениям параметров.
Ребалансировка портфеля
Частота пересчета весов влияет на баланс между адаптивностью к изменениям корреляций и транзакционными издержками. Ежемесячная ребалансировка обычно обеспечивает оптимальный компромисс для ликвидных активов. Недельная пересборка портфеля повышает оборот капитала в 4–5 раз при незначительном улучшении эффективности.
Транзакционные издержки включают: спреды bid-ask (2–10 б.п. для ликвидных акций и 20–50 б.п. для менее ликвидных), влияние на рынок (market impact), которое растет с размером сделки, и брокерские комиссии, обычно незначительные для институциональных инвесторов.
Оценка оптимальной частоты ребалансировки сравнивает прирост Sharpe Ratio от более частого пересчета с затратами на оборот. Например, если месячная ребалансировка дает SR = 0.85, а недельная — 0.87, но годовой оборот увеличивается с 150% до 600%, дополнительные издержки 4.5% перевешивают небольшой выигрыш в SR.
Альтернатива календарной ребалансировке — метод Threshold-based rebalance: пересчет весов выполняется только при отклонении текущих весов от целевых более чем на 5%. Этот подход снижает оборачиваемость активов в портфеле в спокойные периоды и ускоряет реакцию портфеля во время рыночных стрессов.
Робастность к выбору исторического окна
Длина периода оценки (lookback period) влияет на баланс между точностью статистических оценок и адаптивностью к изменениям рыночного режима:
- Короткие окна (63–126 дней) быстро реагируют на недавние шоки, но дают более шумные оценки;
- Длинные окна (504–756 дней) сглаживают краткосрочные колебания корреляций, но хуже реагируют на новые рыночные условия.
Тестирование стратегии на разных lookback period позволяет оценить стабильность метода и чувствительность стратегий к выбору окна.

Рис. 5: Влияние lookback period на коэффициент Шарпа и волатильность. Стабильность показателей при изменении lookback period показывает робастность стратегии к выбору параметров. Период в 252 торговых дня обеспечивает оптимальный баланс между адаптивностью к изменениям рынка и стабильностью оценок
Результаты показывают умеренную чувствительность стратегии к длине периода оценки. Различия в Sharpe Ratio между 252 и 504 днями обычно не превышают 0.05–0.10, что меньше статистической погрешности оценки. Период в 126 дней повышает волатильность весов при ребалансировке и увеличивает оборачиваемость портфеля на 30–50%.
Практическая рекомендация: использовать lookback 252 дня для портфелей из ликвидных активов при нормальном торговом режиме. В периоды структурных изменений рынка, например кризисов или смены монетарной политики, временное сокращение окна до 126 дней повышает адаптивность стратегии.
Ограничения метода
- Чувствительность к ошибкам оценки корреляций: шум в выборочных корреляциях, особенно при коротких исторических рядах, может завышать веса некоторых активов;
- Рост числа параметров: для n(n+1)/2 параметров. При небольшом lookback соотношение наблюдений к параметрам низкое, что снижает точность оценок;
- Методы снижения чувствительности: сжатие (shrinkage) к структурированной целевой матрице (constant correlation, factor model), регуляризация весов (максимальный вес актива, секторная концентрация), факторные модели, робастные оценки (Ledoit-Wolf, Minimum Covariance Determinant);
- Игнорирование ожидаемой доходности: стратегия может давать высокие веса низкодоходным активам, если они обеспечивают декорреляцию. При систематической недооценке риска отдельных классов активов возможна завышенная экспозиция;
- Комбинирование с прогнозами доходности: можно включать оба критерия (диверсификация и доходность) с весовыми коэффициентами. Фреймворк Блэка-Литтермана (Black-Litterman) позволяет учитывать экспертные оценки доходности.
Заключение
Портфель максимальной диверсификации представляет собой прагматичный подход к управлению капиталом, полностью независимый от прогнозов доходности. Метод опирается на корреляционную структуру рынка и перераспределяет капитал в пользу слабо коррелированных активов. Эмпирические исследования подтверждают устойчивую связь между высоким уровнем диверсификационного коэффициента и последующей доходностью с учетом риска, особенно выраженной в периоды рыночного стресса.
Практическая ценность метода проявляется в его устойчивости к ошибкам оценки параметров по сравнению с классическим mean-variance подходом. Отказ от прогнозирования ожидаемой доходности снижает риск построения портфеля на основе зашумленных данных. Регулярная ребалансировка поддерживает оптимальную корреляционную экспозицию, адаптируя портфель к изменениям рыночных условий.
Метод применим как самостоятельная стратегия в институциональном управлении активами и как компонент мультистратегических систем, где диверсификационный критерий дополняет другие сигналы формирования портфеля.