Анализ рисков

«Достаточно ли вы делаете интересные, причудливые, дальние, странные ставки?» — Том Питерс
  • Анализ рисков с помощью анализа главных компонентов
  • Создание безрискового портфеля
  • Моделирование рисков для анализа фондового рынка
  • Моделирование доходности активов с помощью негауссовых распределений

Анализ рисков с помощью анализа главных компонентов

Почему матрица данных порвала со своими старыми методами? Войти в новое измерение просветления!

Все мы, кто изо всех сил старался что-то проанализировать, были бы ошеломлены огромным количеством присутствующих факторов! Что ж, компьютеры могут облегчить задачу, но изучение более значительного количества факторов и переменных все равно обходится ценой места, времени и денег! В этом блоге мы рассмотрим мир анализа главных компонент, в частности, аналитику рисков, чтобы упростить его, где мы изучим способы сокращения количества переменных, которые мы будем учитывать в наших расчетах, используя некоторые интересные принципы.

Роль PCA в анализе рисков: финансовая перспектива

Факторы риска

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

Виды факторов риска

Факторы риска – это переменные, которые могут повлиять на стоимость финансового инструмента. Их можно разделить на две основные категории: систематические факторы риска и несистематические факторы риска.

  • Систематические факторы риска влияют на все финансовые инструменты, такие как процентные ставки, инфляция и экономический рост. Эти факторы не могут быть диверсифицированы и являются основными факторами волатильности рынка.
  • Специфические факторы риска – это факторы, влияющие только на конкретный финансовый инструмент или группу инструментов, такие как финансовое состояние компании или политическая стабильность страны. Эти факторы можно диверсифицировать, инвестируя в диверсифицированный портфель активов.

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

Ограничения в случае большого количества факторов:

Анализ факторов, упомянутых выше, является хорошим началом для наших целей анализа рисков; Однако выполнение анализа при наличии большого количества признаков не только становится вычислительно затратным, но и более сложным для получения выводов.

Чтобы решить эту проблему, мы можем использовать некоторые мощные методы, которые существуют для решения этой проблемы. В этом блоге мы рассмотрим один из таких методов под названием PCA (Principal Component Analysis).

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

~ Практическая финансовая эконометрика, Кэрол Александер

PCA, хотя и полезен для широкого спектра портфелей, особенно выгоден для портфелей облигаций, потому что:

1) Они, как правило, очень диверсифицированы, что делает уменьшение размерности незаменимым.

2) Сравнительно более высокая корреляция между факторами риска.

Обзор различных факторов риска в портфелях облигаций

Учитывая его явные преимущества, этот блог будет сосредоточен на факторах риска, связанных с портфелями облигаций. Но прежде чем внедрять PCA, давайте углубимся в различные факторы риска, обычно связанные с портфелями облигаций.

1. Процентный риск:

Процентный риск является одним из наиболее значимых факторов риска портфеля облигаций. Он относится к чувствительности цен на облигации к изменениям процентных ставок. Облигации с более длительным сроком погашения, как правило, более чувствительны к изменениям процентных ставок. Для количественной оценки процентного риска можно учитывать такие факторы, как:

  • Дюрация: Дюрация измеряет чувствительность цен облигаций к изменениям процентных ставок. Он определяет, сколько времени требуется для восстановления цены облигации за счет купонных выплат и погашения основной суммы долга.

2. Кредитный риск:

Кредитный риск, или риск дефолта, — это риск того, что эмитент облигаций может не выполнить свои обязательства по выплате процентов или основной суммы долга. Для количественной оценки кредитного риска можно учитывать такие факторы, как:

  • Кредитные рейтинги: Кредитные рейтинги, присваиваемые рейтинговыми агентствами, указывают на кредитоспособность эмитентов облигаций.
  • Spread over Benchmark (Спред по отношению к бенчмарку): Спред доходности облигации по отношению к бенчмарку (например, доходность казначейских облигаций) может указывать на ее кредитный риск.
Кредитный риск в банках

3. Риск ликвидности:

Риск ликвидности относится к риску невозможности купить или продать облигацию по желаемой цене из-за отсутствия рыночной ликвидности. Для количественной оценки риска ликвидности можно учитывать такие факторы, как:

  • Спред между ценой покупки и продажи: более широкий спред между ценой покупки и продажи предполагает более низкую ликвидность.
  • Средний объем торгов: Облигации с более высокими объемами торгов, как правило, более ликвидны.
Понимание риска ликвидности

4. Инфляционный риск:

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

  • Real Yield (Реальная доходность) — Реальная доходность облигации (номинальная доходность минус ожидаемая инфляция) дает представление о ее доходности с поправкой на инфляцию.

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

10-летние и инфляционные ожидания

Демистификация PCA: математическое ядро

Целью PCA является «уменьшение размерности». Это означает, что мы пытаемся сократить количество признаков (факторов риска) до меньшего числа важных, с которыми мы можем оперировать быстрее. Мы стремимся удалить избыточные измерения, сосредоточившись на измерениях с наибольшим объемом данных.

Давайте уделим немного времени, чтобы исследовать, что мы подразумеваем под измерениями, думая об этом в более геометрическом смысле.

Это изображение служит отличным примером представления объектов (точек данных) в терминах признаков (измерений)

Несмотря на то, что человек не может представить себе N-мерное пространство, N-мерное пространство — это всего лишь математическое представление такой возможности. Как упоминалось ранее, наша цель по уменьшению измерений может быть достигнута путем определения направлений, содержащих «большую часть информации». Позже мы увидим, что эту так называемую информацию можно измерить через процент дисперсии каждого компонента.

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

Взгляните на изображение ниже, чтобы получить лучшее представление:

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

Измерение корреляции

Для этого составляется ковариационная матрица стандартизированных входных признаков (входных данных).

Теперь, когда у нас есть математическое представление наших данных, мы идем дальше, чтобы попытаться определить «направления» (если рассматривать их в размерном смысле), в которых мы можем получить больше всего данных.

Мы можем сделать это, используя собственные векторы! Что ж, мы не будем вдаваться в тонкости математики, почему наши главные компоненты совпадают с собственными векторами ковариационной матрицы.

Мы возьмем единичный вектор, вдоль которого среднеквадратичная ошибка (MSE) является минимальным, в качестве нашего ПК, чтобы обеспечить сохранение максимума информации вдоль выбранного направления, как видно на второй диаграмме. Математически можно показать, что минимизация MSE максимизирует дисперсию вдоль рассматриваемого вектора.

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

Теперь давайте рассмотрим это подробнее, применив эти концепции на практике к реальным рыночным данным.

Подготовка к работе: общие сведения о наборе данных

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

Мы будем использовать два набора данных:

  1. Срок против процента (MarketData.csv)
    Этот набор данных содержит данные о процентных ставках для различных сроков (сроков погашения) с течением времени. Он включает в себя процентные ставки для разных сроков, таких как 3 месяца, 6 месяцев и так далее. Этот тип данных часто используется в финансах для различных целей, включая ценообразование финансовых инструментов, анализ рисков и моделирование.
Каждая строка представляет определенную дату или момент времени, а столбцы содержат процентные ставки для разных сроков на эту конкретную дату или время.

2. Чувствительность к изменению процентных ставок (PortfolioData.csv)

  • PV01 — это мера, используемая в управлении рисками и торговле для количественной оценки чувствительности стоимости портфеля к изменениям процентных ставок. Он помогает оценить риск, связанный с движением процентных ставок.
Столбец «PV01» представляет собой чувствительность портфеля к изменениям процентных ставок по каждому соответствующему сроку.

Реализация PCA: подробное пошаговое руководство по коду

Общие сведения о коде

Прежде чем мы перейдем к коду, давайте кратко рассмотрим, как мы будем подходить к решению этой проблемы.

  • Мы начинаем с загрузки данных из «PortfolioData.csv», который содержит информацию о финансовом портфеле, включая его чувствительность к изменениям процентных ставок (PV01).
  • Далее мы создаем DataFrame «df_calculation» для выполнения определенных манипуляций/вычислений.
  • Извлекаем значения «PV01» из загруженных данных портфеля и сохраняем их в столбце «PV» «df_calculation».
  • Мы используем факторные нагрузки (компоненты собственного вектора), полученные из PCA (в частности, первый главный компонент, «PC1») и сохраняем их в столбце «PC1» в «df_calculation». В этом конкретном примере мы возьмем только ПК1, потому что мы достигли желаемой дисперсии (сохраненной информации) всего с 1 ПК.
  • Вычисляем произведение «ПК1» и «ПВ» для каждой строки, сохраняя результаты в столбце «Результат1» «df_calculation».
  • Мы вычисляем сумму квадратов значений «Result1» и умножаем ее на первое собственное значение, полученное из PCA, которое представляет собой дисперсию, объясняемую первым главным компонентом.

Наконец, мы рассчитываем риск портфеля как квадратный корень из результата, масштабированный на коэффициент (2,33), представляющий значение 99-го процентиля. Значение этого 99-го процентиля будет объяснено более подробно ближе к концу.

А теперь мы пишем код!

  • Импортируем необходимые библиотеки и датасет:

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.decomposition import PCA

data = pd.read_csv(«MarketData.csv»)

# Create a DataFrame from the loaded data
x = pd.DataFrame(data)

  • Стандартизация данных с последующей визуализацией ковариационной матрицы:

# Remove the ‘Date’ column as it’s not needed for standardization
df = x.drop(axis=1, columns=[‘Date’])

# Get the values of the DataFrame
X = df.values

# Calculate the mean for each feature
mean = np.mean(X, axis=0)

# Calculate the standard deviation for each feature
std_dev = np.std(X, axis=0)

# Subtract the mean from each data point and divide by the standard deviation
# This centers the data around zero and scales it to have unit variance
X_standardized = (X — mean) / std_dev

# Convert the standardized data back to a DataFrame
df_standardized = pd.DataFrame(X_standardized, columns=df.columns)

# Calculate the covariance matrix for the standardized data
cov_matrix = df_standardized.cov()

# Plot the covariance matrix as a heatmap
sns.heatmap(cov_matrix, annot=True, fmt=’.2f’, cmap=’coolwarm’)
plt.show()

Ковариационная матрица для нормализованных значений
  • Поиск главных компонентов с помощью PCA:

pca = PCA(n_components=0.95,svd_solver=’full’)
pca.fit(X)
factor_loading = pca.components_
df_factor_loading = pd.DataFrame(factor_loading)
df_factor_loading

df_factor_loading дает нам собственные значения каждого из PC, которые взяли finally.

В связи с этой частью приведенного выше кода необходимо обсудить две важные части:

  1. n_components = k, позволяет нам решить, сколько главных компонентов мы хотим выбрать. Однако, когда k является числом с плавающей запятой, лежащим между 0 и 1, это помогает нам определить количество ПК (главных компонентов), необходимых для сохранения этой дисперсии (или, проще говоря, сохраненной информации).
    0,95, которое мы использовали, означало, что мы хотели взять это количество главных компонентов, чтобы получить дисперсию 0,95!
    В этом конкретном примере случилось так, что мы смогли добиться этого только с одним ПК, но это полностью из-за типа данных, которые у нас есть в наборе данных, и могут отличаться в вашем случае.
  2. svd_solver относится к математической модели, используемой для решения PCA, сингулярного разложения. Поскольку наш набор данных был небольшим, мы выбрали тип svd_solver «full», который вычисляет все компьютеры, а затем сравнивает. Тем не менее, ради практических целей, которые сильно различаются от случая к случаю, мы рекомендуем ознакомиться с этой документацией.
  • Далее проверяем собственные значения ПК:

variance_percent_df = pd.DataFrame(data=pca.explained_variance_)

# pca.explained_variance_ contains the eigenvalues of the covariance matrix, which represent the variance explained by each principal component.

variance_ratio_df = pd.DataFrame(data=pca.explained_variance_ratio_)

#pca.explained_variance_ratio_ contains the ratio of each eigenvalue to the total variance, indicating the proportion of variance explained by each principal component.

variance_ratio_df = variance_ratio_df * 100

Собственные значения
Относительный вклад собственных значений в %
  • Раскрытие информации с помощью расчета портфельного риска:

portfolio_data = pd.DataFrame(data=pd.read_csv(«PortfolioData.csv»))
df_calculation = pd.DataFrame()

df_calculation[‘PV’] = portfolio_data.iloc[:,1]
df_calculation[‘PC1’] = df_factor_loading.iloc[:,0]

df_calculation[‘Result1’] = df_calculation[‘PC1’] * df_calculation[‘PV’]

result1 = ((df_calculation[‘Result1’].sum())**2) * variance_percent_df.iloc[0]

portfolio_risk = np.sqrt(result1) * 2.33 #99 percentile value
print(‘portfolio risk:’, portfolio_risk)

Наконец, риск нашего портфеля составляет около 9%

Как и было обещано ранее, давайте теперь немного подробнее рассмотрим значение этого «99 процентиля».

Во-первых, значение 99 процентиля при расчете риска портфеля указывает на то, что мы рассчитываем вероятность до 99%, что наш фактический убыток не превысит сделанную нами оценку риска.

Значение 2,33 — это коэффициент масштабирования, соответствующий этому конкретному процентилю, который умножается. Обратите внимание, что итоговое значение, которое мы получаем, выражается в той же единице, в которой мы измеряли риск. В нашем случае мы измеряли его в PV01, и именно в этих единицах мы получаем ответ.

Если вам интересно, как именно мы пришли к фактору 2,33, то это произошло просто с помощью стандартной кривой нормального распределения. Примерно 99% данных находятся в пределах +(или) — 2,33 стандартных отклонений от среднего значения. Для получения дополнительной информации по этому вопросу, пожалуйста, обратитесь к этому документу.

Наконец, мы хотели бы закончить цитатой, близкой нашему сердцу:

«Ты промахиваешься в 100% случаев, когда не делаешь — Уэйн Гретцки — Майкл Скотт»

FIN.

Создание безрискового портфеля

Сегодня мы углубимся в практическую сторону торговли на Форекс, стремясь создать надежную стратегию хеджирования. Чтобы эффективно ориентироваться в этом финансовом ландшафте, мы будем полагаться на TraderMade Forex API, удобный инструмент, который предоставляет нам легкий доступ к широкому спектру рыночных данных.

Этот API становится нашим окном в динамичный мир валютных пар, позволяя нам визуализировать тенденции, анализировать движение цен и, в конечном итоге, разрабатывать надежный подход к хеджированию. Присоединяйтесь к нам, и мы исследуем синергию между торговлей на рынке Форекс, стратегиями хеджирования и бесценной информацией, предоставляемой конечными точками TraderMade Forex API.

Импорт данных

Чтобы запустить наши процессы, мы начнем извлечение данных через конечные точки TraderMade Forex API. Учитывая волатильность, присущую рынку Форекс, мы будем избегать длительных временных рамок, таких как год или два. Наш подход заключается в том, чтобы начать с более детализированных данных, в частности, ежедневных данных для первоначального тестирования, а затем ежечасных данных для последующего анализа. Это позволяет нам улавливать нюансы и принимать обоснованные решения, не упуская из виду важные детали.

Здесь я использую TradeMade Python SDK, удивительно полезный инструмент, который не только упрощает процесс извлечения данных, но и делает его исключительно удобным для пользователя для бесперебойной работы в наших операциях.

Теперь давайте начнем с импорта необходимых библиотекimport tradermade as tm
import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt

Далее, наша цель состоит в том, чтобы систематически извлекать цены закрытия пар, котируемых в долларах США G10, что способствует всестороннему анализу корреляций между этими основными валютными парами. Будут извлечены данные для AUDUSD, CADUSD, EURUSD, JPYUSD, NZDUSD, NOKUSD, GBPUSD, SEKUSD и CHFUSD как за 1-месячный на дневной, так и за 1-дневный часовой таймфреймы.tm.set_rest_api_key(«YOUR API KEY») #Setting up the REST API token (Replace YOUR API KEY with your secret API key)

df_month = tm.timeseries(currency=’AUDUSD,CADUSD,EURUSD,JPYUSD,NZDUSD,NOKUSD,GBPUSD,SEKUSD,CHFUSD’,start=»2023-11-10″,end=»2023-12-10″,interval=»daily»,fields=[«close»])
df_day = tm.timeseries(currency=’AUDUSD,CADUSD,EURUSD,JPYUSD,NZDUSD,NOKUSD,GBPUSD,SEKUSD,CHFUSD’,start=»2023-12-13-00:00″,end=»2023-12-14-00:00″,interval=»hourly»,fields=[«close»])

Чтобы начать извлечение данных, начните с настройки токена REST API (замените ВАШ КЛЮЧ API секретным ключом API). Используя конечные точки данных временных рядов, введите желаемые валюты, начальную и конечную дату и время, предпочтительный интервал (ежедневный, ежечасный, минутный) и выбранное поле (открытие, максимум, минимум, закрытие). Затем ежемесячные и еженедельные наборы данных хранятся в отдельных фреймах данных с именами df_month и df_day. Извлеченные данные будут выглядеть следующим образом:

Данные за месяц:

Изображение автора

Данные по дням:

Изображение автора

Понимание хеджирования в торговле на Форекс

В торговле на рынке Форекс хеджирование — это тактика, позволяющая защитить вашу позицию по валютной паре от неожиданных сдвигов. Это краткосрочный ход, который часто используется, когда есть опасения по поводу новостей или событий, вызывающих турбулентность на валютных рынках.

Когда дело доходит до хеджирования валютных пар, существует три основные стратегии:

1. Стратегия прямого хеджирования:

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

2. Стратегия корреляционного хеджирования:

Использование корреляции между валютными парами является широко распространенной стратегией хеджирования на рынке Форекс, позволяющей трейдерам ориентироваться в волатильности рынка, одновременно торгуя парами с высокой или отрицательной корреляцией для эффективного снижения риска.

3. Стратегия хеджирования опционов:

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

Здесь мы погружаемся в стратегию корреляционного хеджирования. Подход предполагает выбор оптимальной корзины (обычно используется для обозначения пар валютных пар) путем оценки корреляции между ними. Наше внимание сосредоточено на выявлении пар, которые демонстрируют особенно положительную корреляцию, когда движения положительно влияют друг на друга, что позволяет открывать противоположные позиции для валютных пар в корзине. Впоследствии, используя коэффициент хеджирования, мы проанализируем наиболее эффективный способ построения нашего хеджингового портфеля.

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

Коэффициент хеджирования

Коэффициент хеджирования – это, по сути, пропорция или сравнительная стоимость хеджирования по отношению к общей позиции. Он служит важнейшей метрикой управления рисками, предоставляя представление о потенциальном риске, связанном с движениями инструмента хеджирования.

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

Где:

ρ = коэффициент корреляции изменения спотовой и фьючерсной цен

σs = Стандартное отклонение изменения спотовой цены ‘s’

σp = Стандартное отклонение изменения цены фьючерса ‘f’

Развивая эту концепцию под свои нужды, применим формулу для коэффициента хеджирования в паре валютных пар X и Y:

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

Идентификация коррелированных пар

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

Тепловая карта корреляции для данных за месяц

correlation_matrix_month = df_month.corr()

# Create a heatmap using seaborn
plt.figure(figsize=(12, 10))
sns.heatmap(correlation_matrix_month, annot=True, cmap=’coolwarm’, fmt=».2f», linewidths=.5)
plt.title(‘Correlation Matrix of Forex Codes’)
plt.show()

Изображение автора

Тепловая карта корреляции для дневных данных

correlation_matrix_day = df_day.corr()

# Create the day Data heatmap using seaborn
plt.figure(figsize=(12, 10))
sns.heatmap(correlation_matrix_day, annot=True, cmap=’coolwarm’, fmt=».2f», linewidths=.5)
plt.title(‘Correlation Matrix of Forex Codes’)
plt.show()

Изображение автора

Изучив данные, мы выделили две отдельные группы валютных пар — одна для ежедневных данных за месяц, а другая для часовых. Это подчеркивает волатильность, присущую рынку Форекс, где отношения между валютными парами постоянно меняются, по-разному влияя на наши стратегии хеджирования.

Теперь давайте определим наиболее положительно коррелированные пары для данных по месяцам и дням:

Для ежемесячных данных:stacked_corr = correlation_matrix_month.stack()
filtered_corr = stacked_corr[stacked_corr < 1]
sorted_corr = filtered_corr.sort_values(ascending=False)
sorted_corr

Изображение автора

Таким образом, с помощью анализа ежемесячных данных мы выбираем NZDUSD и CHFUSD в качестве нашей корзины с корреляцией, равной 0,97 (наиболее положительно коррелированная корзина)

Для данных за день:stacked_corr_day = correlation_matrix_day.stack()
filtered_corr_day = stacked_corr_day[stacked_corr_day < 1]
sorted_corr_day = filtered_corr_day.sort_values(ascending=False)
sorted_corr_day

Изображение автора

Таким образом, с помощью анализа дневных данных мы выбираем SEKUSD и EURUSD в качестве нашей корзины с корреляцией, равной 0,99 (наиболее положительно коррелированная корзина)

Визуализации

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

Теперь, чтобы визуализировать дневные значения доходности, нам нужно рассчитать дневную доходность для каждой отдельной валютной пары следующим образом:# Daily Returns for Month Data

df_month_CHFUSD = tm.timeseries(currency=’CHFUSD’, start=»2023-11-10″, end=»2023-12-10″, interval=»daily», fields=[«open», «high», «low», «close»]) # Fetching Month Data for CHFUSD
df_month_CHFUSD[‘Daily_Return’] = ((df_month_CHFUSD[‘close’] — df_month_CHFUSD[‘open’]) / df_month_CHFUSD[‘open’]) * 100 # Creating Daily Return Value for CHFUSD
df_month_NZDUSD = tm.timeseries(currency=’NZDUSD’, start=»2023-11-10″, end=»2023-12-10″, interval=»daily», fields=[«open», «high», «low», «close»]) # Fetching Month Data for NZDUSD
df_month_NZDUSD[‘Daily_Return’] = ((df_month_NZDUSD[‘close’] — df_month_NZDUSD[‘open’]) / df_month_NZDUSD[‘open’]) * 100 # Creating Daily Return Value for NZDUSD

# Daily Returns for Day Data

df_day_SEKUSD = tm.timeseries(currency=’SEKUSD’, start=»2023-12-13-00:00″, end=»2023-12-14-00:00″, interval=»hourly», fields=[«open», «high», «low», «close»]) # Fetching day Data for SEKUSD
df_day_SEKUSD[‘Daily_Return’] = ((df_day_SEKUSD[‘close’] — df_day_SEKUSD[‘open’]) / df_day_SEKUSD[‘open’]) * 100 # Creating hourly Return Value for SEKUSD
df_day_EURUSD = tm.timeseries(currency=’EURUSD’, start=»2023-12-13-00:00″, end=»2023-12-14-00:00″, interval=»hourly», fields=[«open», «high», «low», «close»]) # Fetching day Data for EURUSD
df_day_EURUSD[‘Daily_Return’] = ((df_day_EURUSD[‘close’] — df_day_EURUSD[‘open’]) / df_day_EURUSD[‘open’]) * 100 # Creating hourly Return Value for EURUSD
df_day_CHFUSD = tm.timeseries(currency=’CHFUSD’, start=»2023-12-13-00:00″, end=»2023-12-14-00:00″, interval=»hourly», fields=[«open», «high», «low», «close»]) # Fetching day Data for CHFUSD
df_day_CHFUSD[‘Daily_Return’] = ((df_day_CHFUSD[‘close’] — df_day_CHFUSD[‘open’]) / df_day_CHFUSD[‘open’]) * 100 # Creating hourly Return Value for CHFUSD
df_day_NZDUSD = tm.timeseries(currency=’NZDUSD’, start=»2023-12-13-00:00″, end=»2023-12-14-00:00″, interval=»hourly», fields=[«open», «high», «low», «close»]) # Fetching day Data for NZDUSD
df_day_NZDUSD[‘Daily_Return’] = ((df_day_NZDUSD[‘close’] — df_day_NZDUSD[‘open’]) / df_day_NZDUSD[‘open’]) * 100 # Creating hourly Return Value for NZDUSD

1. Сравнение дневной доходности CHFUSD и NZDUSD на месячном таймфрейме

plt.figure(figsize=(10, 6))
plt.style.use(‘ggplot’)

plt.plot(df_month_CHFUSD[‘date’], df_month_CHFUSD[‘Daily_Return’], label=’CHFUSD’, marker=’o’)
plt.plot(df_month_CHFUSD[‘date’], df_month_NZDUSD[‘Daily_Return’], label=’NZDUSD’, marker=’o’)

plt.title(‘CHFUSD/NZDUSD Returns Comparison’)
plt.xlabel(‘Date’)
plt.ylabel(‘Returns’)
plt.legend()
plt.xticks(rotation = 50)
plt.grid(True)
plt.show()Image by Author

Изображение автора

При рассмотрении визуального представления вырисовывается четкая закономерность: когда одна валютная пара испытывает восходящее движение, другая стремится двигаться в противоположном направлении, подчеркивая нашу отрицательную корреляцию. Эта наблюдаемая обратная зависимость имеет решающее значение для нашей стратегии хеджирования, поскольку движения в одной паре действуют как противовес другой в выбранной нами корзине. Аналогично визуализируем данные за 1-дневный таймфрейм.

2. Сравнение часовой доходности SEKUSD и EURUSD на 1-дневном таймфрейме

plt.figure(figsize=(10, 6))
plt.style.use(‘ggplot’)

plt.plot(df_day_SEKUSD[‘date’], df_day_SEKUSD[‘Daily_Return’], label=’SEKUSD’, marker=’o’)
plt.plot(df_day_SEKUSD[‘date’], df_day_EURUSD[‘Daily_Return’], label=’EURUSD’, marker=’o’)

plt.title(‘SEKUSD/EURUSD Returns Comparison’)
plt.xlabel(‘Hour’)
plt.ylabel(‘Returns’)
plt.legend()
plt.xticks(rotation = 50)
plt.grid(True)
plt.show()

Изображение автора

3. Сравнение часовой доходности CHFUSD и NZDUSD на 1-дневном таймфрейме

plt.figure(figsize=(10, 6))
plt.style.use(‘ggplot’)

plt.plot(df_day_CHFUSD[‘date’], df_day_CHFUSD[‘Daily_Return’], label=’CHFUSD’, marker=’o’)
plt.plot(df_day_CHFUSD[‘date’], df_day_NZDUSD[‘Daily_Return’], label=’NZDUSD’, marker=’o’)

plt.title(‘CHFUSD/NZDUSD Returns Comparison’)
plt.xlabel(‘Hour’)
plt.ylabel(‘Returns’)
plt.legend()
plt.xticks(rotation = 50)
plt.grid(True)
plt.show()

Изображение автора

Сравнивая визуализации часовых данных для CHFUSD и NZDUSD и SEKUSD и EURUSD, становится очевидно, что они имеют высокую степень сходства. Однако, основываясь на данных корреляции, более значимая положительная корреляция наблюдается между SEKUSD и EURUSD на часовом уровне. Поэтому для нашего часового анализа мы остановим свой выбор на SEKUSD и EURUSD.

Использование коэффициентов хеджирования для построения эффективных профилей хеджирования

В начале формирования профилей хеджирования в игру вступает ключевой показатель — коэффициент хеджирования. Этот показатель не только освещает тенденцию, которой следует хеджирование, но и обеспечивает критический коэффициент, определяющий наши инвестиционные решения. Коэффициент хеджирования выступает в качестве количественного индикатора, позволяющего получить представление об оптимальном распределении для эффективного управления рисками. Понимая и используя этот показатель, трейдеры могут принимать обоснованные решения о том, как распределить свои инвестиции в соответствии с рыночными тенденциями и потенциальными рисками.

Теперь, чтобы вычислить коэффициенты хеджирования, нам нужно вычислить как корреляцию, так и стандартное отклонение. Давайте упростим процесс, объединив эти вычисления в одну функцию, как описано ниже:

Функция коэффициента хеджирования

def calculate_hedging_ratio(df1, df2):

# Merge the two DataFrames on the ‘date’ column
merged_df = pd.merge(df1[[‘date’, ‘Daily_Return’]], df2[[‘date’, ‘Daily_Return’]], on=’date’, suffixes=(‘_1’, ‘_2’))

# Calculate the correlation coefficient between the returns of the two currency pairs
correlation = merged_df[‘Daily_Return_1’].corr(merged_df[‘Daily_Return_2’])

# Calculate the hedging ratio
hedging_ratio = — correlation * (df1[‘Daily_Return’].std() / df2[‘Daily_Return’].std())

print(f»Correlation between the two currency pairs: {correlation}»)
print(f»Hedging Ratio: {hedging_ratio}»)

#Calling the function to get the results

calculate_hedging_ratio(df_month_CHFUSD,df_month_NZDUSD) #for daily data
calculate_hedging_ratio(df_day_SEKUSD,df_day_EURUSD) #for hourly data

Результаты, полученные для функции ‘calculate_hedging_ratio’, выглядят следующим образом:

1. Почасовые данные:

Изображение автора

2. Ежедневные данные:

Изображение автора

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

Начальный этап создания профиля хеджирования включает в себя присвоение весов каждой отдельной валютной паре в корзине на основе соответствующего коэффициента хеджирования

Присвоение весов отдельным валютным парам

# For Daily Data
hedging_ratio_CHFUSD_NZDUSD = 0.5203035958912856

# Calculate weights based on hedging ratio
weights_CHFUSD_NZDUSD = {‘CHFUSD’: 1 / (1 + abs(hedging_ratio_CHFUSD_NZDUSD)),
‘NZDUSD’: abs(hedging_ratio_CHFUSD_NZDUSD) / (1 + abs(hedging_ratio_CHFUSD_NZDUSD))}
#For Hourly Data
hedging_ratio_SEKUSD_EURUSD = 1.4597042985219284

# Calculate weights based on the hedging ratio
weights_SEKUSD_EURUSD = {‘SEKUSD’: 1 / (1 + abs(hedging_ratio_SEKUSD_EURUSD)),
‘EURUSD’: abs(hedging_ratio_SEKUSD_EURUSD) / (1 + abs(hedging_ratio_SEKUSD_EURUSD))}

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

Изображение автора

Оценка

Дневной портфель мы оценим по данным следующего дня, а почасовой портфель оценим уже на следующий час. Чтобы облегчить эту задачу, мы будем экспортировать новые данные, используя конечные точки исторических данных TraderMade Forex API, который предоставляет множество разнообразных исторических данных.

Импорт данных нового дня

# For Daily Data
df_next_day = tm.historical(currency=’CHFUSD,NZDUSD’, date=»2023-12-11″, interval=»daily», fields=[«open», «high», «low», «close»]) # Fetching new Day data
df_next_day[‘Daily_Return’] = ((df_next_day[‘close’] — df_next_day[‘open’]) / df_next_day[‘open’]) * 100 # Calculating Daily Return

# For Hourly Data
df_next_hour_SEKUSD = tm.timeseries(currency=’SEKUSD’, start=»2023-12-14-00:05″, end=»2023-12-14-01:00″, interval=»hourly», fields=[«open», «high», «low», «close»]) # Fetching Hourly Data for SEKUSD
df_next_hour_SEKUSD[‘Hourly_Return’] = ((df_next_hour_SEKUSD[‘close’] — df_next_hour_SEKUSD[‘open’]) / df_next_hour_SEKUSD[‘open’]) * 100 # Calculating Hourly Return for SEKUSD
df_next_hour_EURUSD = tm.timeseries(currency=’EURUSD’, start=»2023-12-14-00:05″, end=»2023-12-14-01:00″, interval=»hourly», fields=[«open», «high», «low», «close»]) # Fetching Hourly Data for EURUSD
df_next_hour_EURUSD[‘Hourly_Return’] = ((df_next_hour_EURUSD[‘close’] — df_next_hour_EURUSD[‘open’]) / df_next_hour_EURUSD[‘open’]) * 100 # Calculating Hourly Return for EURUSD

Теперь оценим доходность портфеля на предстоящий день/час на основе ранее сформированного портфеля:# Calculate next hour portfolio return
portfolio_return_next_hour = weights_SEKUSD_EURUSD[‘SEKUSD’] * df_next_hour_SEKUSD[‘Hourly_Return’].item() + weights_SEKUSD_EURUSD[‘EURUSD’] * df_next_hour_EURUSD[‘Hourly_Return’].item()

# Calculate next day portfolio return
portfolio_return_next_day = weights_CHFUSD_NZDUSD[‘CHFUSD’] * df_next_day.loc[df_next_day[‘instrument’] == ‘CHFUSD’, ‘Daily_Return’].values[0] + weights_CHFUSD_NZDUSD[‘NZDUSD’] * df_next_day.loc[df_next_day[‘instrument’] == ‘NZDUSD’, ‘Daily_Return’].values[0]

Затем мы оцениваем окончательный результат с помощью метрики, известной как общая доходность. Общая доходность — это показатель, который отражает общее процентное изменение стоимости инвестиций, охватывающее как прирост капитала, так и доход, такой как дивиденды. Положительная общая доходность указывает на прибыль, а отрицательная – на убыток. Кроме того, годовая доходность представляет собой стандартизированную меру на ежегодной основе, учитывающую эффект накопления прибыли или убытка с течением времени. Эти показатели важны для оценки комплексной эффективности портфеля или инвестиционной стратегии, позволяя получить представление как о краткосрочных выгодах, так и о долгосрочных эффектах сложного процента.

def calculate_and_print_total_return(starting_portfolio_value, portfolio_return_next_day):
ending_portfolio_value = starting_portfolio_value * (1 + portfolio_return_next_day / 100)
total_return = (ending_portfolio_value — starting_portfolio_value) / starting_portfolio_value * 100
print(f»Total Return: {total_return:.2f}%»)

# Calling the ‘calculate_and_print_total_return’ function
calculate_and_print_total_return(1, portfolio_return_next_day)# For Daily Data
calculate_and_print_total_return(1, portfolio_return_next_hour)# For Hourly Data
trading_days_in_year_daily = 252 #assuming 252 trading days in a year
trading_hours_per_day_hourly = 8 # Assuming 8 trading hours per day

# Calculate annualized total return for daily data
annualized_total_return_daily = ((1 + total_return_daily / 100) ** (trading_days_in_year_daily / 1)) — 1
print(f»Annualized Total Return (Daily Data): {annualized_total_return_daily * 100:.2f}%»)

# Calculate annualized total return for hourly data
annualized_total_return_hourly = ((1 + total_return_hourly / 100) ** (trading_days_in_year_hourly * trading_hours_per_day_hourly / 1)) — 1
print(f»Annualized Total Return (Hourly Data): {annualized_total_return_hourly * 100:.2f}%»)

После применения функции совокупной доходности к обоим нашим портфелям мы получаем следующие результаты:

1. Профиль на основе ежедневных данных:

Изображения автора

2. Профиль на основе почасовых данных:

Изображения автора

В этом анализе очевидно влияние детализации данных на результаты торговли. Портфель, основанный на ежедневных данных, принес прибыль в размере 0,19%, что подчеркивает эффективность стратегического подхода, учитывающего долгосрочные тенденции. Напротив, тот, который был сформулирован с использованием часовых данных, дал меньшую прибыль в размере 0,03%, что отражает компромисс между точностью и оперативностью в торговых стратегиях Форекс. Годовая совокупная доходность для портфеля ежедневных данных составила 61,63%, в то время как портфель почасовых данных показал более высокую годовую общую доходность в 70,07%. Это подчеркивает важность тщательного баланса между шумом исторических данных и реакцией в реальном времени для принятия оптимальных решений в торговле на рынке Форекс.

ЗАМЕТКА:

В этом проекте используются базовые и четкие определения, чтобы продемонстрировать применение различных финансовых инструментов, включая коэффициент хеджирования. Он создан в учебных целях, делая акцент на фундаментальных концепциях. Необходимо признать, что в реальных сценариях включение транзакционных издержек может существенно повлиять на общую прибыльность. Результаты, представленные в этом проекте, получены исключительно из модели и алгоритма. Пользователям рекомендуется настраивать и совершенствовать методологию в соответствии со своими уникальными требованиями и факторами окружающей среды. Важно понимать, что фактическая прибыль, учитывающая транзакционные издержки, может отличаться от упрощенных представлений, представленных в данном проекте. Кроме того, существуют альтернативные и модифицированные уравнения для коэффициента хеджирования, и используемое здесь уравнение намеренно является базовым для ясности; Пользователям рекомендуется адаптировать его в зависимости от конкретного контекста.

Заключение

В заключение мы разработали стратегию торговли на рынке Форекс с использованием двух типов данных — 1) дневных и 2) часовых. Эта стратегия предполагала расчет корреляций для определения оптимальной корзины валютных пар с последующим определением коэффициента хеджирования. Используя полученный коэффициент хеджирования, мы сформировали два портфеля и оценили их эффективность.

Ключевой вывод из нашего анализа заключается в существенном влиянии детализации данных на результаты торговли, при этом подход с ежедневными данными дает более высокую прибыль (0,19%) по сравнению с часовой стратегией (0,03%), что подчеркивает важность выбора подходящих временных рамок для более эффективного принятия решений в торговле на рынке Форекс.

На протяжении всего этого процесса TraderMade Forex API доказал свою эффективность, предложив легкодоступный SDK и разнообразные наборы данных, которые значительно облегчили рабочий процесс.

Моделирование рисков для анализа фондового рынка

Часть 1

В этой части представлена записная книжка, доступная на моем GitHub («04_AlphaResearch_FactorModeling.ipynb»), которая помогает читателям построить модель риска с использованием общепринятых статистических методов.

Ядром этой статьи является раздел «Статистическая модель риска» в записной книжке. Он предлагает путь от сбора данных до внедрения модели риска, стремясь сделать сложные статистические методы доступными для практической оценки рисков на фондовом рынке.

Несмотря на то, что записная книжка затрагивает и другие темы, эта статья в первую очередь посвящена пониманию и расчету риска в рамках модели.

В последующих статьях мы углубимся в альфа-факторы, их оценку и оптимизацию портфеля. Цель этой серии статей — вооружить читателей знаниями для разработки и оценки оптимального портфеля, ограниченного моделью риска.

Получение данных об акциях и получение доходов

Блокнот начинается со сбора основных данных о фондовом рынке. Используя библиотеку yfinance, он извлекает исторические цены открытия и закрытия для выбранного списка биржевых тикеров за определенный период.def fetch_stock_data(ticker_list, years=5, year_end=None):
if year_end is None:
year_end = datetime.now().year

end_date = datetime(year_end, 12, 31)
start_date = end_date — timedelta(days=years * 365)

close_data_df = pd.DataFrame()
open_data_df = pd.DataFrame()

for ticker in ticker_list:
stock = yf.Ticker(ticker)
hist_data = stock.history(period=’1d’, start=start_date, end=end_date)

# Close Data
close_data = hist_data[‘Close’].rename(ticker)
close_data_df = pd.merge(close_data_df, pd.DataFrame(close_data), left_index=True, right_index=True, how=’outer’)

# Open Data
open_data = hist_data[‘Open’].rename(ticker)
open_data_df = pd.merge(open_data_df, pd.DataFrame(open_data), left_index=True, right_index=True, how=’outer’)

return close_data_df, open_data_df

# Fetch the data
ticker_list = [
‘AAPL’, ‘ABBV’, ‘AMGN’, ‘AMZN’, ‘AXP’, ‘BA’, ‘BIIB’, ‘BMY’, ‘CAT’, ‘CMCSA’, ‘CSCO’, ‘CVX’, ‘DD’, ‘DIS’, ‘F’, ‘GE’, ‘GILD’, ‘GM’, ‘GOOGL’,
‘GS’, ‘HD’, ‘HON’, ‘IBM’, ‘INTC’, ‘JCI’, ‘JNJ’, ‘JPM’, ‘KO’, ‘MCD’, ‘META’, ‘MMM’, ‘MRK’, ‘MSFT’, ‘PEP’, ‘PFE’, ‘PG’, ‘T’, ‘TSLA’, ‘UNH’, ‘V’,
‘VZ’, ‘WMT’, ‘XOM’
]

years = 5
year_end = 2022

close, open = fetch_stock_data(ticker_list, years, year_end)

В разделе также рассматривается расчет отдачи от собранных данных.def generate_returns(prices, shift):
return_prices = prices.pct_change(shift).iloc[shift:, :]
return return_prices

returns = generate_returns(close, 1)

Статистическая модель риска

В этом разделе описывается построение статистической модели риска с использованием метода главных компонент (PCA) для упрощения и количественной оценки данных фондового рынка для эффективной оценки рисков.

Анализ главных компонент (PCA)

Мы используем анализ главных компонент (PCA) в качестве основного инструмента для дальнейшего анализа. После сбора и обработки данных фондового рынка в игру вступает PCA, преобразующий коррелированные переменные в ряд линейно некоррелированных главных компонентов. Этот метод играет важную роль в снижении сложности данных, позволяя нам раскрыть фундаментальную структуру доходности акций. Эти основные компоненты отражают ключевые рыночные тенденции и закономерности, выступая в качестве жизненно важных элементов нашей модели управления рисками.

Наше практическое применение PCA выполняется с использованием PCA (из sklearn.decomposition), где мы подгоняем возвращаемые данные для извлечения значимых компонентов. Количество извлекаемых компонентов, определяемое num_factor_exposures, является критической точкой принятия решения в анализе. Вот как мы это реализуем:from sklearn.decomposition import PCA

def fit_pca(returns, num_factor_exposures, svd_solver):
pca = PCA(n_components=num_factor_exposures, svd_solver=svd_solver)
return pca.fit(returns)

num_factor_exposures = 20
pca = fit_pca(returns, num_factor_exposures, ‘full’)

Затем pca.explained_variance_ratio_ количественно оценивает дисперсионный вклад каждого компонента, необходимый для понимания их влияния на модель. Гистограмма, отображающая эти коэффициенты, дает четкое представление об их значении для объяснения поведения доходности акций.plt.figure(figsize=(8, 3))
plt.bar(np.arange(num_factor_exposures), pca.explained_variance_ratio_)

Факторы бета

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

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

Полученная матрица дает нам детальное представление о том, как каждая акция в нашем портфеле, вероятно, будет вести себя в ответ на различные рыночные сценарии, инкапсулированные основными компонентами.def factor_betas(pca, factor_beta_indices, factor_beta_columns):
factor_betas = pd.DataFrame(pca.components_.T, factor_beta_indices, factor_beta_columns)

return factor_betas

risk_model = {}
risk_model[‘factor_betas’] = factor_betas(pca, returns.columns.values, np.arange(num_factor_exposures))

20 случайных строк из factor_betas

Факторная доходность

В то время как коэффициенты бета факторов указывают на чувствительность, факторная доходность показывает реальное влияние этой чувствительности на производительность портфеля. Например, высокая факторная доходность по определенному компоненту указывает на то, что этот фактор внес существенный вклад в общую доходность портфеля в течение анализируемого периода.def factor_returns(pca, returns, factor_return_indices, factor_return_columns):
factor_returns = pd.DataFrame(pca.transform(returns), factor_return_indices, factor_return_columns)
return factor_returns

risk_model[‘factor_returns’] = factor_returns(
pca,
returns,
returns.index,
np.arange(num_factor_exposures))

Первые 5 строк ‘factor_returns’

Матрица факторной ковариации

Мы вычисляем матрицу факторной ковариации с фокусом, который отличается от традиционных ковариационных вычислений, таких как numpy.cov, который оценивает ковариацию между каждой парой компонентов. Наш метод нацелен на главную диагональ. Интересно, что наш подход и стандартное ковариационное вычисление дают схожие результаты, поскольку ковариации за пределами главной диагонали почти всегда близки к нулю. Это сходство коренится в некоррелированном характере компонентов PCA. Ключевое отличие нашего подхода заключается в том, что мы подчеркиваем и уточняем отсутствие корреляции между этими компонентами, усиливая понимание их ортогональной взаимосвязи в модели риска.def factor_cov_matrix(factor_returns, ann_factor):
factor_cov_matrix = np.var(factor_returns, ddof=1)
factor_cov_matrix = np.diag(factor_cov_matrix) * ann_factor
return factor_cov_matrix

ann_factor = 252 # Annualization factor
risk_model[‘factor_cov_matrix’] = factor_cov_matrix(risk_model[‘factor_returns’], ann_factor)

Матрица идиосинкразической дисперсии

Развиваясь в рамках нашей модели риска, матрица идиосинкразической дисперсии количественно определяет уникальный риск, присущий каждому активу, отличный от более широких рыночных влияний. Эта матрица фокусируется на изоляции рисков, не учитываемых факторной доходностью и коэффициентами бета факторов. В своих вычислениях матрица фиксирует дисперсию остаточной доходности — ту доходность каждого актива, которая не объясняется факторами модели. Результирующая диагональная структура с нулями вне диагонали подчеркивает независимость конкретного риска каждого актива, обеспечивая четкий и целенаправленный анализ волатильности отдельных активов в портфеле.def idiosyncratic_var_matrix(returns, factor_returns, factor_betas, ann_factor):
dot_product = np.dot(factor_returns, factor_betas.T)
common_return = pd.DataFrame(dot_product, returns.index, returns.columns)
residual_return = returns — common_return

idiosyncratic_var_matrix = pd.DataFrame(np.diag(np.var(residual_return)) * ann_factor, returns.columns, returns.columns)

return idiosyncratic_var_matrix

risk_model[‘idiosyncratic_var_matrix’] = idiosyncratic_var_matrix(returns, risk_model[‘factor_returns’], risk_model[‘factor_betas’], ann_factor)

Вектор идиосинкразической дисперсии

Идиосинкразический вектор дисперсии сжимает матрицу в простую форму. Извлекая и линеаризуя диагональные элементы матрицы идиосинкразической дисперсии, мы создаем вектор, который непосредственно отражает специфический риск каждого актива.def idiosyncratic_var_vector(returns, idiosyncratic_var_matrix):
idiosyncratic_var_vector = pd.DataFrame(np.diagonal(idiosyncratic_var_matrix), returns.columns)

return idiosyncratic_var_vector

risk_model[‘idiosyncratic_var_vector’] = idiosyncratic_var_vector(returns, risk_model[‘idiosyncratic_var_matrix’])

Прогнозирование риска портфеля

Общие сведения о функции

Функция predict_portfolio_risk предназначена для оценки общего риска финансового портфеля.

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

Разбивка формулы

Суть этой функции заключается в ее формуле:

Где:

  • X — весовые коэффициенты портфеля
  • — коэффициент бета
  • — матрица факторной ковариации
  • — идиосинкразическая дисперсионная матрица

Пошаговый анализ

Сочетание факторных и идиосинкразических рисков

Начальный этап расчета риска включает в себя комбинацию факторных и идиосинкразических рисков путем расчета BFB. Т + С.

Этот подход объединяет риски, связанные с общерыночными факторами, такими как экономические изменения или отраслевые тенденции (факторные риски), с рисками, присущими отдельным активам (идиосинкразические риски).

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

Применение весовых коэффициентов портфеля

На следующем шаге к объединенной матрице рисков применяются весовые коэффициенты портфеля, обозначенные X. Выбор равных весов для различных активов в этом примере упрощает иллюстрацию применения функции.

Тем не менее, важно отметить, что различное распределение веса может существенно повлиять на общий риск портфеля. Например, чрезмерный вес в более волатильных активах или секторах может повысить восприимчивость портфеля к рыночным колебаниям. И наоборот, более диверсифицированное или консервативное распределение веса может снизить подверженность риску.

Этот шаг подчеркивает важность стратегического распределения активов в управлении портфельными рисками, подчеркивая, как состав портфеля напрямую влияет на уровень риска.

Расчет прогнозируемого риска

Последний шаг включает в себя получение прогнозируемого стандартного отклонения доходности портфеля.

Это достигается путем извлечения квадратного корня из всего выражения матрицы, что дает единственную метрику риска. Это рассчитанное значение представляет собой общий риск портфеля, включающий в себя систематические и несистематические элементы, интегрированные ранее.def predict_portfolio_risk(factor_betas, factor_cov_matrix, idiosyncratic_var_matrix, weights):
form_break_01 = np.dot(np.dot(factor_betas, factor_cov_matrix), factor_betas.T) + idiosyncratic_var_matrix # (BFB.T + S)
form_break_02 = np.dot(np.dot(weights.T, form_break_01), weights) # (X.T(form_break_01)X)

predicted_portfolio_risk = np.sqrt(form_break_02)

return predicted_portfolio_risk[0][0]

all_weights = pd.DataFrame(np.repeat(1/len(ticker_list), len(ticker_list)), ticker_list)

predict_portfolio_risk(
risk_model[‘factor_betas’],
risk_model[‘factor_cov_matrix’],
risk_model[‘idiosyncratic_var_matrix’],
all_weights)

Прогнозируемый риск портфеля

Заключение

Завершая наше исследование моделирования рисков, мы не просто провели расчеты, но и открыли ключевой инструмент для анализа портфеля.

С этими расчетами рисков…

Точное сравнение портфелей

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

Подготовка к оптимизации портфеля

Мы готовим почву для следующего важного шага: оптимизации портфеля. Дело не только в цифрах; Речь идет о стратегическом согласовании ваших инвестиционных решений с вашими финансовыми целями, используя риск в качестве руководящего показателя.

По сути, мы перешли от простой теории к практическому применению, где понимание рисков становится мощным союзником в вашем стремлении к оптимизированному управлению портфелем.

Часть 2. Создание и оценка альфа-факторов

Углубляясь в область анализа фондового рынка, эта статья является продолжением нашего предыдущего исследования. В нашем последнем обсуждении мы углубились в тонкости построения надежной модели риска.

Опираясь на этот фундамент, мы сосредоточимся на альфа-факторах — ключевой концепции предиктивной финансовой аналитики. Alpha Factors стремится использовать неэффективность рынка и прогнозировать будущие движения акций, предлагая инвесторам усовершенствованные стратегии взаимодействия с рынком.

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

Если вы хотите получить доступ к записной книжке, которую мы рассмотрим в этой статье, вы можете найти ее на моем GitHub («04_AlphaResearch_FactorModeling.ipynb»).

Создание альфа-факторов

Знакомство с альфа-факторами начинается с функции fetch_sector_data. Эта функция является ключевой для категоризации секторов, что имеет решающее значение для нашего анализа. Определив сектор каждой акции в нашем списке тикеров, мы подготовили почву для более целенаправленных расчетов альфа-фактора, особенно для тех, которые требуют сравнения по секторам. Вот реализация функции:# Function to fetch sector information for a list of tickers
def fetch_sector_data(ticker_list):
sector = {}
for ticker in ticker_list:
tickerdata = yf.Ticker(ticker)
sector[ticker] = tickerdata.info.get(‘sector’, ‘Unknown’)
return sector

sectors_data = fetch_sector_data(ticker_list)
sectors_series = pd.Series(sectors_data)

Еще одним важным компонентом нашего инструментария альфа-фактора является функция calculate_z_scores. Эта функция стандартизирует наши данные, приводя их в формат, позволяющий проводить последовательные сравнения по разным акциям или таймфреймам. В альфа-факторном анализе, где относительные различия часто более показательны, чем абсолютные значения, эта стандартизация является ключевой.# Auxiliary function to calculate z-scores
def calculate_z_scores(demeaned):
# Adding a small value to the standard deviation to avoid division by zero
epsilon = 1e-7
demeaned_std_aligned = demeaned.std(axis=1).to_frame(name=’std’)
demeaned_std_aligned = pd.concat([demeaned_std_aligned] * demeaned.shape[1], axis=1)
demeaned_std_aligned.columns = demeaned.columns
demeaned_std_aligned += epsilon

# Calculating z-scores
demeaned_mean_aligned = demeaned.mean(axis=1).to_frame(name=’mean’)
demeaned_mean_aligned = pd.concat([demeaned_mean_aligned] * demeaned.shape[1], axis=1)
demeaned_mean_aligned.columns = demeaned.columns
z_scored = (demeaned — demeaned_mean_aligned) / demeaned_std_aligned

return z_scored

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

Возврат к среднему значению 5-дневный нейтральный фактор сектора

Этот фактор основан на концепции, согласно которой цены на акции имеют тенденцию возвращаться к своему среднему значению в течение определенного периода. Основное внимание уделяется 5-дневному окну с поправкой на влияние сектора. Согласовывая доходность каждой акции со средним значением по отрасли, а затем стандартизируя эти отклонения, мы создаем фактор, который точно определяет потенциальные возможности возврата к среднему значению.# Function for 5-day sector neutral mean reversion
def calculate_mean_reversion_5day_sector_neutral(returns, sectors):
# Aligning sectors with the return columns
aligned_sectors = sectors_series.reindex(returns.columns)

# Subtracting the sector mean from each return
sector_means = returns.groupby(aligned_sectors, axis=1).transform(‘mean’)
demeaned = — returns.sub(sector_means)

# Normalizing the results
demeaned = demeaned.rank(axis=1)
z_scored = calculate_z_scores(demeaned)

# Converting to long format
z_scored_long = z_scored.stack().reset_index()
z_scored_long.columns = [‘Date’, ‘Ticker’, ‘Mean_Reversion_5Day_Sector_Neutral’]

return z_scored_long

# Calculating 5-day returns
returns_5d = generate_returns(close, 5)

# Applying the function
mean_reversion_5day_sector_neutral = calculate_mean_reversion_5day_sector_neutral(returns_5d, sectors_series)

Возврат к среднему значению 5-дневный секторно-нейтральный сглаженный фактор

Для уточнения коэффициента возврата к среднему значению мы вводим технику сглаживания с использованием скользящего среднего. Этот процесс помогает смягчить краткосрочную волатильность и шум, предлагая более стабильный и надежный фактор.# Function for smoothed 5-day sector neutral mean reversion
def calculate_mean_reversion_5day_sector_neutral_smoothed(factor_long):
# Reconverting to wide format for smoothing
factor_wide = factor_long.pivot(index=’Date’, columns=’Ticker’, values=’Mean_Reversion_5Day_Sector_Neutral’)

# Smoothing using simple moving average
smoothed = factor_wide.rolling(window=5).mean()

# Normalizing the results again
smoothed = smoothed.rank(axis=1)
z_scored = calculate_z_scores(smoothed)

# Converting to long format
z_scored_long = z_scored.stack().reset_index()
z_scored_long.columns = [‘Date’, ‘Ticker’, ‘Mean_Reversion_5Day_Sector_Neutral_Smoothed’]

return z_scored_long

mean_reversion_5day_sector_neutral_smoothed = calculate_mean_reversion_5day_sector_neutral_smoothed(mean_reversion_5day_sector_neutral.reset_index())

Фактор настроений овернайт

Вдохновленный гипотезой о том, что доходность овернайт отражает настроения инвесторов конкретной фирмы, этот фактор анализирует доходность, полученную между закрытием одного торгового дня и открытием следующего. Это новый подход к оценке настроений рынка, который может предшествовать более широкому признанию рынка.# Function to calculate overnight returns
def calculate_overnight_returns(open_prices, close_prices):
# Calculating the return from yesterday’s close to today’s open
return (open_prices — close_prices.shift(1)) / close_prices.shift(1)

# Function to calculate trailing overnight returns
def calculate_overnight_sentiment(overnight_returns, window_length):
# Calculating the rolling sum of overnight returns
summed = overnight_returns.rolling(window=window_length).sum()

# Normalizing the results by converting to z-score
z_scored = calculate_z_scores(summed)

# Converting back to long format
z_scored_long = z_scored.stack().reset_index()
z_scored_long.columns = [‘Date’, ‘Ticker’, ‘Sum_Overnight_Sentiment_5Day’]

return z_scored_long

# Applying the functions
overnight_returns = calculate_overnight_returns(open, close)
overnight_sentiment = calculate_overnight_sentiment(overnight_returns, window_length=5)

Фактор сглаживания настроений овернайт

Аналогично фактору возврата к среднему значению, мы применяем технику сглаживания к фактору настроений овернайт. Это сглаживание, достигаемое с помощью скользящей средней, направлено на то, чтобы привести фактор в более последовательную и надежную форму.def calculate_overnight_sentiment_smoothed(overnight_sentiment):
# Reconverting to wide format for smoothing
overnight_wide = overnight_sentiment.pivot(index=’Date’, columns=’Ticker’, values=’Sum_Overnight_Sentiment_5Day’)

# Smoothing using simple moving average
smoothed = overnight_wide.rolling(window=5).mean()

# Normalizing the results again
smoothed = smoothed.rank(axis=1)
z_scored = calculate_z_scores(smoothed)

# Converting to long format
z_scored_long = z_scored.stack().reset_index()
z_scored_long.columns = [‘Date’, ‘Ticker’, ‘Sum_Overnight_Sentiment_5Day_Smoothed’]

return z_scored_long

overnight_sentiment_smoothed = calculate_overnight_sentiment_smoothed(overnight_sentiment.reset_index())

Комбинирование факторов

После того, как все альфа-факторы рассчитаны, мы можем объединить их в один фрейм данных.from functools import reduce

# Create a list of all dataframes
dataframes = [mean_reversion_5day_sector_neutral,
mean_reversion_5day_sector_neutral_smoothed,
overnight_sentiment,
overnight_sentiment_smoothed]

# Use ‘reduce’ to merge all dataframes into a single dataframe
all_factors = reduce(lambda left, right: pd.merge(left, right, on=[‘Date’, ‘Ticker’], how=’inner’), dataframes)

# Readjust ‘Date’ and ‘Ticker’ as indices
all_factors = all_factors.set_index([‘Date’, ‘Ticker’])

all_factors[‘Combined_Factors’] = all_factors.mean(axis=1)

all_factors

Оценка альфа-факторов

На этом этапе анализа мы оцениваем эффективность и надежность созданных нами альфа-факторов. Эта оценка имеет решающее значение для определения практической полезности этих факторов для формулирования согласованной инвестиционной стратегии.

Анализ факторной доходности

Мы начинаем нашу оценку альфа-факторов с анализа форвардной доходности. Здесь нашим ориентиром является средняя доходность всех акций на каждую дату, служащая всеобъемлющим рыночным ориентиром. Когда мы сравниваем эффективность наших комбинированных альфа-факторов с этим эталоном, становится очевидным, что комбинированные факторы неизменно превосходят их, что подчеркивает их более сильные прогностические возможности. Это превосходство справедливо и при сравнении комбинированных факторов с каждым из отдельных факторов.# Calculate forward returns and align with factor data dates
forward_returns = generate_returns(close, 1).shift(-1).reset_index()
forward_returns = forward_returns.loc[forward_returns[‘Date’].isin(set(all_factors.reset_index().Date))].set_index(‘Date’)
forward_returns = forward_returns.stack().reset_index()
forward_returns.columns = [‘Date’, ‘Ticker’, ‘Returns’]
forward_returns.set_index([‘Date’, ‘Ticker’], inplace=True)

def calculate_allocation(df):
df[df < 0] = 0
return df.groupby(level=0, group_keys=False).apply(lambda x: x / x.sum())

# Calculate allocations and combine with forward returns
allocation = all_factors.copy()
allocation = calculate_allocation(allocation)
strategy_returns = allocation.reset_index().merge(forward_returns.reset_index(), on=[‘Date’, ‘Ticker’]).set_index([‘Date’, ‘Ticker’])

# Apply allocation weights to returns
strategy_returns.update(strategy_returns.drop(columns=’Returns’).mul(strategy_returns[‘Returns’], axis=0))

# Calculate strategy and benchmark returns
mean_returns = strategy_returns[[‘Returns’]].groupby(level=0, group_keys=False).apply(lambda x: x.mean())
strategy_returns = strategy_returns.drop(columns=’Returns’).groupby(level=0, group_keys=False).apply(lambda x: x.sum())
strategy_returns[‘Benchmark’] = mean_returns

# Plot cumulative returns
(1 + strategy_returns).cumprod().plot(figsize=(15, 5))
plt.show()

Корреляционный анализ

Этот анализ имеет решающее значение для определения того, дают ли эти факторы четкое представление или отражают схожие рыночные тенденции. Изучение коэффициентов корреляции, которые колеблются от -1 до 1, выявляет степень взаимосвязи между факторами. Высокая положительная корреляция указывает на перекрывающуюся информацию, в то время как отрицательная корреляция указывает на контрастные рыночные инсайты.# Calculate the correlation matrix for alpha factors
correlation_matrix = all_factors.corr()
correlation_matrix.style.background_gradient(cmap=’RdBu’)

Анализ просадки

Чтобы оценить риск и устойчивость нашей стратегии, мы проводим анализ просадки. Это включает в себя оценку снижения совокупной доходности по сравнению с пиками, что дает представление о потенциальных рисках и стабильности инвестиционной стратегии на основе наших альфа-факторов.# Calculate cumulative returns
cumulative_returns = (1 + strategy_returns).cumprod()

# Calculate drawdown
peak = cumulative_returns.expanding(min_periods=1).max()
drawdown = (cumulative_returns — peak) / peak

plt.figure(figsize=(6, 3))
plt.barh(drawdown.min().index, drawdown.min(), color=’red’)
plt.show()

Коэффициент возврата к волатильности

Наконец, мы рассчитываем коэффициент возврата к волатильности. Это ключевой показатель для оценки эффективности нашей стратегии с поправкой на риск, предлагающий сбалансированное представление как о доходности, так и о связанных с ней рисках.# Calculate annualized return
annualized_return = strategy_returns.mean() * 252

# Calculate annualized volatility
annualized_volatility = strategy_returns.std() * np.sqrt(252)

# Return to volatility ratio
return_to_volatility_ratio = annualized_return / annualized_volatility

plt.figure(figsize=(6, 3))
plt.barh(return_to_volatility_ratio.index, return_to_volatility_ratio, color=’darkblue’)
plt.show()

Заключение

Когда мы завершаем наше исследование альфа-факторов, становится очевидно, насколько они важны для улучшения анализа фондового рынка и инвестиционных стратегий.

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

Заглядывая в будущее, наш следующий шаг заключается в том, чтобы интегрировать эти знания в построение оптимального портфеля, ограниченного моделью риска. Этот предстоящий этап будет основываться на заложенном нами фундаменте, применяя наши альфа-факторы в структурированной портфельной модели, чтобы сбалансировать потенциальную доходность с сопутствующими рисками, что ознаменует собой еще один шаг в нашем непрерывном путешествии по финансовому анализу и разработке стратегии.

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

Следует ли использовать нормальное распределение при выборке?

Этот пост будет отформатирован немного по-другому по сравнению с некоторыми из моих предыдущих постов. В этом посте мы углубимся в некоторые эксперименты. Как я уже упоминал в предыдущем посте, байесовская статистика и логический вывод — это область, на которую я постоянно натыкаюсь. У меня также растет интерес узнать об этом больше. Вместе с байесовской статистикой приходит Монте-Карло с цепью Маркова (MCMC). Аспектом этого метода, на котором мы сосредоточимся, является метод Монте-Карло.

Если вы новичок в методе Монте-Карло, то вкратце это метод выборки, который выбирает значения независимо от известного распределения. Как его можно использовать в количественных финансах, так это путем выборки доходности для создания смоделированной траектории цены акций до желаемого периода времени. Затем вы можете выполнить итерацию по процессу n раз. После запуска процесса n раз у вас останется распределение потенциальных цен, которые акции могут принять в указанный период времени.

Де-факто распределение, используемое при выборке по методу Монте-Карло, является нормальным гауссовским распределением. Тем не менее, ничто не мешает вам использовать другие дистрибутивы, которые могут лучше соответствовать природе ваших данных.

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

Возврат журнала UBER и скорректированное закрытие

Для приведенного выше примера мы используем ежедневную скорректированную цену закрытия UBER. Диапазон дат — с 29 августа 2022 года по 11 января 2024 года, а сравнительный период времени — с 17 ноября 2019 года по 31 марта 2021 года. В этих двух сериях используется окно ретроспективного обзора в 500 дней от дат окончания 11 января 2024 года и 31 марта 2021 года. Ниже приведена описательная статистика для каждого лога временного ряда.******************* UBER — Normal (2022-08-29 to 2024-01-11) *******************

count 344.000000
mean 0.002303
std 0.026465
min -0.110094
25% -0.012054
50% 0.001876
75% 0.017692
max 0.113046
Name: Log Returns, dtype: float64

******************* UBER — Vol (2019-11-17 to 2021-03-31) *******************

count 343.000000
mean 0.002075
std 0.042347
min -0.243713
25% -0.016478
50% 0.001377
75% 0.022411
max 0.323959
Name: Log Returns, dtype: float64

Чтобы сгенерировать некоторые прогнозируемые выборки, на данный момент мы просто предположим, что логарифмические доходы нормально распределены. Исходя из этого предположения, мы можем передать параметры µ (среднее) и σ (стандартное отклонение) в функцию нормального распределения для получения независимых выборок. Давайте посмотрим, как сравниваются эти 2 распределения.

Случайные гауссовы величины и фактические величины

В приведенном выше примере мы используем гауссов случайный сэмплер для выборки логарифмических результатов с использованием статистических параметров каждого временного ряда. Первый временной ряд с 2022 по 2024 год обозначим как норму или норму. Вторую серию с 2019–2021 годов обозначим как волатильную или vol. Причины названий основаны на количестве экстремальных значений и том факте, что COVID-19 имел место в течение 2020 года. Если вы посмотрите на 2 распределения, то увидите, что распределение справа имеет более экстремальные значения. При моделировании доходности в волатильные периоды мы также хотели бы учитывать экстремальные значения, особенно отрицательные. Причина в том, что при повышенной волатильности нам нужно будет увидеть влияние на цены активов. При выборке из нормального распределения Гаусса этот уровень информации может быть замаскирован в случаях, когда волатильность увеличивается.

Чтобы измерить нормальность, мы можем использовать график qq для оценки каждого периода времени. Мы также можем измерить эксцесс 2 ряда. Эксцесс покажет нам, как часто мы видим экстремальные значения.

QQ-графики нормального и волатильного периодов

Если вы не знакомы с графиками qq, их можно использовать для оценки того, имеет ли непрерывная переменная нормальные гауссовы свойства. В совершенно нормальной непрерывной переменной все точки данных будут идеально выстроены в виде диагональной линии. На первом графике, который отображает период, который мы изначально обозначили как нормальный, он имеет это свойство, за исключением нескольких конечных точек данных. С другой стороны, второй график имеет более экстремальные концы. Концы могут указывать на некоторые негауссовы свойства.

При измерении эксцесса за вышеуказанные периоды времени мы получаем оценку 2,2601 для нормального периода и 13,2645. Мерой эксцесса является реализация фишера. С формулой можно ознакомиться ниже.

Чтобы интерпретировать оценку эксцесса Фишера, если значение равно 0, то случайная величина имеет нормальные гауссовы свойства и является мезокуртической. Если он меньше 0, то платикуртический. Platykurtic можно рассматривать как случайную величину, которая не имеет экстремальных значений, а максимальное и минимальное значения находятся в пределах 95% доверительного интервала распределения. Наконец, если балл больше 0, то говорят, что это лептокуртическая болезнь при чрезмерных экстремальных значениях.

Чтобы сравнить, похожи ли 2 выборки, мы можем использовать 2-х выборочный критерий Колмогорова-Смирнова. Этот тест технически используется для проверки того, были ли отобраны 2 выборки из одного и того же распределения. Тем не менее, мы можем использовать его, чтобы увидеть, даст ли выборка гауссова распределения, использующая моменты исходной выборки, идентичный набор случайных величин. Моменты дополнительного контекста — это параметры, описывающие распределение, среднее значение, стандартное отклонение, дисперсию и т. д. Результаты 2-х выборочного теста Колмогорова-Смирнова приведены ниже.******************* UBER — Normal (2022-08-29 to 2024-01-11) *****************

P-Value: 0.48316288593942747
Statistic: 0.06395348837209303


**
****************** UBER — Vol (2019-11-17 to 2021-03-31) ********************

P-Value: 0.045651255616753504
Statistic: 0.10495626822157435

Для теста метрикой, которая нас интересует, является p-значение. Для нормального периода, поскольку p-значение больше уровня значимости 0,05, мы отвергаем нулевую гипотезу теста и можем сделать предположение, что 2 выборки происходят из одного и того же распределения. В этом случае нормальное распределение Гаусса хорошо моделирует период времени. С другой стороны, волатильный период имеет p-значение, которое меньше 0,05, поэтому мы можем принять нулевую гипотезу, что означает, что распределение Гаусса не моделирует период времени.

В тех случаях, когда нормальное распределение Гаусса не является идеальным, мы можем заменить его другими, потенциально более подходящими распределениями. Мы можем проверить эту теорию, сделав выборку из t-распределения Стьюдента, а не из гауссова. Функция плотности вероятности t-распределений Стьюдента может быть представлена ниже.

В приведенном выше уравнении t-распределения Стьюдента x — действительное число, а ν — степень свободы. Если вы используете пакет python scipy для t-распределения Стьюдента, вы можете оценить надлежащие степени свободы, которые можно использовать для выборки из распределения. Исходя из аппроксимации, для моделирования волатильного периода времени идеально подойдет степень свободы 3,0948. Когда мы выбираем данные из логарифмических отчетов за волатильный период и выполняем 2-х выборочный критерий Колмогорова-Смирнова, мы получаем следующее.

Волатильный период t-выборки студентов в сравнении с фактическими

******************* UBER — Vol (2019-11-17 to 2021-03-31) *******************

P-Value: 0.9849177749966633
Statistic: 0.03498542274052478

Взглянув на приведенный выше график, мы видим, что t-распределение студента генерирует выборочные доходы, которые более идентичны фактическому распределению для возвратов журнала UBER в течение волатильного периода. Кроме того, 2-выборочный критерий Колмогорова-Смирнова имеет p-значение больше 0,05, что означает, что 2 случайные величины имеют аналогичное распределение. Таким образом, в этом случае моделирование доходности с t-распределением Стьюдента потенциально более идеально.

Заключение

Если вы планируете использовать моделирование по методу Монте-Карло для прогнозирования того, какими будут цены на активы в будущем, в зависимости от распределения прошлых значений, вы можете рассмотреть негауссово распределение. Как было показано, если из-за повышенной волатильности было больше экстремальных значений, выборка из распределения Гаусса будет пропускать эти потенциальные экстремальные значения. Экстремальные значения могут быть отрицательными, в чем и заключается риск. В игре инвестирования и бизнеса всегда важно учитывать риск. Здесь мы продемонстрируем моделирование доходности волатильных активов с использованием t-распределения Стьюдента. t-распределение Стьюдента может быть не лучшим вариантом использования в других случаях, и существует множество альтернативных распределений, которые можно попробовать. Некоторые из них, которые вы можете опробовать на других временных периодах и ценных бумагах, могут быть Q-Gaussian, Truncated Levy или Modified Weibull distribution. Если вы добились успеха с этими дистрибутивами, оставьте комментарий.

Источник

Источник