Что такое иерархический равный вклад в риски (HERC)?

HERC - это новый метод оптимизации портфеля, разработанный Томасом Раффино (2018). Эта модель устранила недостаток иерархического паритета рисков (HRP), который не использовал кластеры, полученные на этапе кластеризации иерархического дерева в процессе распределения активов. Эта модель состоит из следующих пяти шагов:

  1. Иерархическая древовидная кластеризация: мы используем взаимосвязь между финансовыми активами (корреляцию) для создания иерархической структуры, которую можно представить в виде дендрограммы.
  2. Выбор оптимального количества кластеров: мы выбираем оптимальное количество кластеров на основе иерархической структуры, построенной на первом этапе. Раффино предложил использовать индекс разрыва (Tibshirani 2001), однако из-за вычислительных затрат Riskfolio-Lib использует индекс разрыва двух разностей (Yue, S., Wang, X. & Wei 2009).
  3. Серийная матрица: мы сортируем активы в дендрограмме, минимизируя расстояние между листами.
  4. Рекурсивное деление сверху вниз: мы разделяем веса вдоль дендрограммы на две части, используя равное распределение вклада в риск (вклад каждого кластера в риск - это сумма, обратная риску актива) из верхней части дерева. к кластерам. Результат - вес для каждого кластера.
  5. Наивный паритет риска внутри кластеров: мы используем наивный паритет риска (веса, основанные на обратной величине риска актива) для расчета весов внутри кластеров, а затем умножаем эти веса на вес кластера.

Как использовать HERC с Riskfolio-Lib?

Во-первых, вам необходимо установить Riskfolio-Lib. Вы должны запустить следующий код:

pip install Riskfolio-Lib

После его установки вам необходимо загрузить некоторые цены на активы, например, с помощью yfinace мы можем загрузить некоторые данные:

import numpy as np
import pandas as pd
import yfinance as yf
import warnings

warnings.filterwarnings("ignore")

yf.pdr_override()
pd.options.display.float_format = '{:.4%}'.format

# Date range
start = '2016-01-01'
end = '2019-12-30'

# Tickers of assets
assets = ['JCI', 'TGT', 'CMCSA', 'CPB', 'MO', 'APA', 'MMC', 'JPM',
          'ZION', 'PSA', 'BAX', 'BMY', 'LUV', 'PCAR', 'TXT', 'TMO',
          'DE', 'MSFT', 'HPQ', 'SEE', 'VZ', 'CNP', 'NI', 'T', 'BA']
assets.sort()

# Downloading data
data = yf.download(assets, start = start, end = end)
data = data.loc[:,('Adj Close', slice(None))]
data.columns = assets
# Calculating returns
Y = data[assets].pct_change().dropna()

display(Y.head())

Чтобы увидеть иерархическую взаимосвязь между активами и оптимальными кластерами на основе индекса разрыва двух разностей, мы можем построить тепловую карту корреляции с дендрограммой на каждой оси, используя следующий код:

import riskfolio.PlotFunctions as plf

# Plotting Assets Clusters

ax = plf.plot_clusters(returns=Y,
                       correlation='pearson',
                       linkage='ward',
                       k=None,
                       max_k=10,
                       leaf_order=True,
                       dendrogram=True,
                       #linecolor='tab:purple',
                       ax=None)

Затем нам нужно построить объект HCPortfolio, этот объект содержит все модели портфеля, основанные на иерархической взаимосвязи между активами:

import riskfolio.HCPortfolio as hc

# Building the portfolio object
port = hc.HCPortfolio(returns=Y)

# Estimate optimal portfolio:

model='HERC' # Could be HRP or HERC
correlation = 'pearson' # Correlation matrix used to group assets in clusters
rm = 'MV' # Risk measure used, this time will be variance
rf = 0 # Risk free rate
linkage = 'ward' # Linkage method used to build clusters
max_k = 10 # Max number of clusters used in two difference gap statistic
leaf_order = True # Consider optimal order of leafs in dendrogram

w = port.optimization(model=model,
                      correlation=correlation,
                      rm=rm,
                      rf=rf,
                      linkage=linkage,
                      max_k=max_k,
                      leaf_order=leaf_order)

display(w.T)

Как видите, мы получаем оптимальное портфолио на основе HERC за несколько шагов. Если мы хотим увидеть структуру портфеля, мы можем построить круговую диаграмму:

# Plotting the composition of the portfolio

ax = plf.plot_pie(w=w,
                  title='HERC Naive Risk Parity',
                  others=0.05,
                  nrow=25,
                  cmap="tab20",
                  height=8,
                  width=10,
                  ax=None)

По сравнению с классическими моделями оптимизации портфеля, основанными на задачах выпуклого программирования, этот метод позволяет получать наиболее диверсифицированные портфели.

С другой стороны, аналогично HRP, HERC создает портфели, которые лучше распределяют риск между всеми активами. Чтобы увидеть это свойство, мы можем построить график доли риска для каждого актива, используя следующий код:

# Plotting the risk contribution per asset

mu = Y.mean()
cov = Y.cov() # Covariance matrix
returns = Y # Returns of the assets

ax = plf.plot_risk_con(w=w,
                       cov=cov,
                       returns=returns,
                       rm=rm,
                       rf=0,
                       alpha=0.05,
                       color="tab:blue",
                       height=6,
                       width=10,
                       t_factor=252,
                       ax=None)

Одна вещь, которую мы замечаем, когда видим график выше и тепловую карту, это то, что модель HERC не может обеспечить, чтобы вклад в риск каждого актива в кластерах был одинаковым, например, BAX и BMY находятся в одном кластере, но у них есть различный уровень вклада риска. Свойство равного вклада риска в кластер может быть достигнуто с помощью стандартной модели паритета рисков.

До сих пор мы работали с использованием дисперсии в качестве меры риска, однако Riskfolio-Lib имеет 22 меры риска, доступные для портфелей на основе иерархических отношений между активами, чтобы сравнить распределение активов на основе 22 мер риска с использованием HERC, мы должны запустить следующий код :

# Risk Measures available:
#
# 'vol': Standard Deviation.
# 'MV': Variance.
# 'MAD': Mean Absolute Deviation.
# 'MSV': Semi Standard Deviation.
# 'FLPM': First Lower Partial Moment (Omega Ratio).
# 'SLPM': Second Lower Partial Moment (Sortino Ratio).
# 'VaR': Conditional Value at Risk.
# 'CVaR': Conditional Value at Risk.
# 'EVaR': Entropic Value at Risk.
# 'WR': Worst Realization (Minimax)
# 'MDD': Maximum Drawdown of uncompounded cumulative returns (Calmar Ratio).
# 'ADD': Average Drawdown of uncompounded cumulative returns.
# 'DaR': Drawdown at Risk of uncompounded cumulative returns.
# 'CDaR': Conditional Drawdown at Risk of uncompounded cumulative returns.
# 'EDaR': Entropic Drawdown at Risk of uncompounded cumulative returns.
# 'UCI': Ulcer Index of uncompounded cumulative returns.
# 'MDD_Rel': Maximum Drawdown of compounded cumulative returns (Calmar Ratio).
# 'ADD_Rel': Average Drawdown of compounded cumulative returns.
# 'DaR_Rel': Drawdown at Risk of compounded cumulative returns.
# 'CDaR_Rel': Conditional Drawdown at Risk of compounded cumulative returns.
# 'EDaR_Rel': Entropic Drawdown at Risk of compounded cumulative returns.
# 'UCI_Rel': Ulcer Index of compounded cumulative returns.

rms = ['vol', 'MV', 'MAD', 'MSV', 'FLPM', 'SLPM',
       'VaR','CVaR', 'EVaR', 'WR', 'MDD', 'ADD',
       'DaR', 'CDaR', 'EDaR', 'UCI', 'MDD_Rel', 'ADD_Rel',
       'DaR_Rel', 'CDaR_Rel', 'EDaR_Rel', 'UCI_Rel']

w_s = pd.DataFrame([])

for i in rms:
    w = port.optimization(model=model,
                          correlation=correlation,
                          rm=i,
                          rf=rf,
                          linkage=linkage,
                          max_k=max_k,
                          leaf_order=leaf_order)

    w_s = pd.concat([w_s, w], axis=1)
    
w_s.columns = rms
w_s.style.format("{:.2%}").background_gradient(cmap='YlGn')

Мы можем построить гистограмму, сравнивающую распределение активов для каждой меры риска:

import matplotlib.pyplot as plt

# Plotting a comparison of assets weights for each portfolio

fig = plt.gcf()
fig.set_figwidth(14)
fig.set_figheight(6)
ax = fig.subplots(nrows=1, ncols=1)

w_s.plot.bar(ax=ax)

Спасибо за внимание, вот несколько ссылок, относящихся к проекту:

GitHub: https://github.com/dcajasn/Riskfolio-Lib

Документация: «https://riskfolio-lib.readthedocs.io/en/latest большие/

Pypi: https://pypi.org/project/Riskfolio-Lib/

Контакт

Вы можете связаться с нами по электронной почте [email protected] или Linkedin https://www.linkedin.com/company/orenj-i/