Парный трейдинг и коинтеграция: пошаговое руководство
Узнайте, почему для парного трейдинга важна коинтеграция, а не корреляция. Мы пошагово рассчитываем коэффициент хеджирования, спред и z-score на реальных ценах закрытия активов.
0.479
Парный трейдинг и коинтеграция неразрывно связаны: в основе стратегии лежит спред между ценами двух акций, который стремится вернуться к стабильному уровню, а коинтеграция — это статистическое свойство, подтверждающее наличие такой зависимости. Корреляция оценивает иные параметры. Две акции могут демонстрировать высокую корреляцию, но при этом бесконечно расходиться в цене, тогда как активы с минимальной синхронностью дневных движений способны годами удерживать устойчивый спред. На этой странице мы вручную рассчитываем коэффициент хеджирования, спред и z-score, оцениваем все три показателя на реальных ценах закрытия, а затем уделяем равное внимание причинам, по которым данная конструкция может оказаться неэффективной.
Основы парного трейдинга
Парный трейдинг предполагает поиск двух активов, исторически связанных между собой. Когда спред между ними отклоняется от среднего значения, трейдер открывает позицию: продает дорогой актив и покупает дешевый. Расчет строится на предположении, что спред вернется к исторической норме. Коинтеграция является математическим доказательством того, что линейная комбинация двух временных рядов является стационарной, то есть имеет постоянное среднее и дисперсию.
Методология расчета коэффициента хеджирования
Коэффициент хеджирования определяет пропорцию, в которой необходимо удерживать активы для нейтрализации рыночного риска. Мы используем метод наименьших квадратов для определения наклона линии регрессии между двумя рядами цен. Полученное значение показывает, на какую величину изменяется цена одного актива при изменении цены другого на единицу.
Риски и ограничения стратегии
###
Даже при наличии коинтеграции стратегия может принести убытки. Во-первых, статистическая связь может разрушиться из-за фундаментальных изменений в бизнесе одной из компаний. Во-вторых, спред может расширяться в течение длительного времени, что приводит к маржинальным требованиям и принудительному закрытию позиций до момента возврата к среднему. Наконец, транзакционные издержки и проскальзывание при исполнении ордеров часто поглощают всю ожидаемую прибыль от конвергенции спреда.
Что такое коинтеграция в парном трейдинге?
Корреляция отражает степень синхронности ежедневных процентных изменений двух акций. Она варьируется от минус одного до плюс одного, где плюс один означает, что активы росли и падали одновременно в течение всего рассматриваемого периода. Этот показатель ничего не говорит о дистанции между ценами двух инструментов.
Коинтеграция — это характеристика именно этой дистанции. Если взять акцию B, вычесть из неё фиксированную долю акции A и проанализировать остаток, можно сделать вывод о связи активов. Если полученный ряд — спред — остается в рамках ограниченного диапазона и не уходит в бесконечность, значит, эти два инструмента коинтегрированы. Сами цены могут двигаться как угодно, но их комбинация остается стабильной.
В учебниках часто приводят аналогию с собакой на поводке. Хозяин и собака идут по улице непредсказуемыми путями, но поводок удерживает расстояние между ними в определенных пределах. Корреляция проверяет, делают ли они шаги одновременно. Коинтеграция проверяет, держит ли поводок.
В таблице ниже первая концепция оценивается для пяти известных пар за период две тысячи двадцать четвертого и две тысячи двадцать пятого годов. Столбец return_corr показывает корреляцию ежедневных процентных изменений — именно это обычно имеют в виду, когда говорят о корреляции. Столбец price_corr отражает корреляцию необработанных цен закрытия; этот показатель завышен почти для любых двух бумаг, которые обе выросли.
Точный SQL-код для каждого числа
WITH
px AS (
SELECT
ticker,
date,
toFloat64(any(close)) AS close_px
FROM global_markets.stocks_daily_aggs
WHERE ticker IN ('KO', 'PEP', 'HD', 'LOW', 'XOM', 'CVX', 'V', 'MA', 'AAPL', 'MSFT')
AND date BETWEEN '2024-01-01' AND '2025-12-31'
GROUP BY ticker, date
),
rets AS (
SELECT
ticker,
date,
close_px,
close_px / lagInFrame(close_px) OVER (
PARTITION BY ticker ORDER BY date
ROWS BETWEEN 1 PRECEDING AND CURRENT ROW
) - 1 AS ret
FROM px
)
SELECT
p.pair AS pair,
round(corr(a.ret, b.ret), 3) AS return_corr,
round(corr(a.close_px, b.close_px), 3) AS price_corr
FROM
(
SELECT
tupleElement(t, 1) AS leg_a,
tupleElement(t, 2) AS leg_b,
tupleElement(t, 3) AS pair
FROM
(
SELECT arrayJoin([
('KO', 'PEP', 'KO / PEP'),
('HD', 'LOW', 'HD / LOW'),
('XOM', 'CVX', 'XOM / CVX'),
('V', 'MA', 'V / MA'),
('AAPL', 'MSFT', 'AAPL / MSFT')
]) AS t
)
) AS p
INNER JOIN rets AS a ON a.ticker = p.leg_a
INNER JOIN rets AS b ON b.ticker = p.leg_b AND b.date = a.date
WHERE isFinite(a.ret) AND isFinite(b.ret)
GROUP BY pair
ORDER BY return_corr DESCПо уровню корреляции ежедневных изменений пара HD / LOW занимает верхнюю строчку с показателем 0.868, в то время как корреляция уровней цен за тот же период составила 0.849. В нижней строке пара AAPL / MSFT имеет корреляцию доходности 0.479 при корреляции цен 0.508. Ни один из этих столбцов не отвечает на вопрос, который задает парный трейдер. Оба показателя измеряют совместное движение, а для торговли требуется мера дистанции.
Как рассчитать коэффициент хеджирования и спред?
Пять шагов, выполняемых последовательно для двух списков цен закрытия. Стандартный Python позволяет выполнить всё это, используя math в качестве единственного импорта: никаких сторонних пакетов, поставщиков данных или сетевых запросов.
- Центрируйте каждый ряд.
mean_a = sum(a) / len(a), то же самое для спискаb. - Рассчитайте коэффициент хеджирования. Это наклон прямой линии зависимости B от A:
beta = sum((a[i] - mean_a) * (b[i] - mean_b) for i in range(len(a))) / sum((x - mean_a) ** 2 for x in a). Читайте его как количество единиц A, которое компенсирует одну единицу B. - Постройте спред.
spread = [b[i] - beta * a[i] for i in range(len(a))]. Для коинтегрированной пары этот ряд колеблется вокруг определенного уровня, а не демонстрирует тренд. - Используйте скользящее окно. С помощью
w = spread[i - win + 1 : i + 1]вычисляются среднее значение окнаmu = sum(w) / len(w)и выборочное стандартное отклонениеsd = math.sqrt(sum((x - mu) ** 2 for x in w) / (len(w) - 1)). Скользящее означает, что окно заканчивается на оцениваемом дне и не использует данные после него. - Оцените и выведите результат.
z = (spread[i] - mu) / sd, затем выведите строку входа, покаabs(z) > 1.5, и строку выхода, как толькоabs(z) < 0.5. Z-оценка, равная двум, означает, что спред находится на два стандартных отклонения выше своего недавнего среднего значения.
Двух жестко заданных списков цен достаточно, чтобы увидеть работу алгоритма, а win, равный пяти, делает учебный пример наглядным. В серьезной работе используются значения ближе к шестидесяти трем сессиям, что соответствует примерно одному кварталу. Эти пороговые значения, от полутора для входа до нуля целых пяти десятых для выхода, являются условностями, переходящими из одного руководства в другое. Они не являются результатами исследований, и ни один из приведенных ниже блоков не подбирал их автоматически.
Как выглядит z-score парного трейдинга на реальных ценах?
Ниже приведен расчет для двух известных производителей напитков: KO и PEP. Коэффициент хеджирования рассчитан исключительно по ценам закрытия за 2023 год и остается неизменным на протяжении 2024 и 2025 годов, охваченных графиком. Подгонка наклона на той же выборке, на которой вы затем проводите оценку, — это ошибка заглядывания в будущее при бэктестинге, и разделение периода подгонки и периода оценки — самый простой способ защиты от нее.
Точный SQL-код для каждого числа
WITH
daily AS (
SELECT
date,
anyIf(toFloat64(close), ticker = 'PEP') AS pep,
anyIf(toFloat64(close), ticker = 'KO') AS ko
FROM global_markets.stocks_daily_aggs
WHERE ticker IN ('KO', 'PEP')
AND date BETWEEN '2023-01-01' AND '2025-12-31'
GROUP BY date
HAVING pep > 0 AND ko > 0
),
fitted AS (
SELECT covarSamp(pep, ko) / varSamp(ko) AS beta
FROM daily
WHERE date < '2024-01-01'
),
spread AS (
SELECT
daily.date AS date,
daily.pep - fitted.beta * daily.ko AS spread_usd
FROM daily
CROSS JOIN fitted
),
scored AS (
SELECT
date,
(spread_usd - avg(spread_usd) OVER (
ORDER BY date ROWS BETWEEN 62 PRECEDING AND CURRENT ROW))
/ stddevSampStable(spread_usd) OVER (
ORDER BY date ROWS BETWEEN 62 PRECEDING AND CURRENT ROW) AS z
FROM spread
)
SELECT
toString(toMonday(date)) AS week,
round(argMax(z, date), 2) AS z_score
FROM scored
WHERE date >= '2024-01-01'
AND isFinite(z)
GROUP BY week
ORDER BY weekНа графике представлены 105 еженедельных значений. Окно открывается при z-score, равном -1.53, и закрывается на уровне -0.68. Анализируйте общую форму, а не отдельные точки. Пара, ведущая себя в соответствии с предположениями стратегии, пересекает пороговое значение, в течение нескольких недель возвращается к нулю и пересекает его снова. Пара, которая перестала возвращаться к среднему значению, застревает за пределами порога и остается там, что на графике выглядит как длинный плоский участок вдали от центральной линии.
Всегда ли коинтегрированный спред возвращается к среднему?
Нет, и самый объективный способ убедиться в этом — оценить результаты, следовавшие за каждой начальной точкой. В таблице ниже все торговые сессии с 2019 года по конец 2025 года распределены по корзинам в зависимости от z-score в конкретный день, после чего приводится среднее значение z-score того же спреда через двадцать сессий. Используется логарифм ценового соотношения, а не подобранный спред, поэтому никакие регрессионные оценки, сделанные постфактум, не влияют на график.
Точный SQL-код для каждого числа
WITH
daily AS (
SELECT
date,
anyIf(toFloat64(close), ticker = 'PEP') AS pep,
anyIf(toFloat64(close), ticker = 'KO') AS ko
FROM global_markets.stocks_daily_aggs
WHERE ticker IN ('KO', 'PEP')
AND date BETWEEN '2018-01-01' AND '2025-12-31'
GROUP BY date
HAVING pep > 0 AND ko > 0
),
spread AS (
SELECT
date,
log(pep / ko) AS log_ratio
FROM daily
),
scored AS (
SELECT
date,
(log_ratio - avg(log_ratio) OVER (
ORDER BY date ROWS BETWEEN 62 PRECEDING AND CURRENT ROW))
/ stddevSampStable(log_ratio) OVER (
ORDER BY date ROWS BETWEEN 62 PRECEDING AND CURRENT ROW) AS z
FROM spread
),
horizon AS (
SELECT
date,
z,
leadInFrame(z, 20) OVER (
ORDER BY date ROWS BETWEEN CURRENT ROW AND 20 FOLLOWING
) AS z_fwd
FROM scored
WHERE isFinite(z)
)
SELECT
multiIf(z < -2, 'z below -2',
z < -1, 'z -2 to -1',
z < 0, 'z -1 to 0',
z < 1, 'z 0 to 1',
z < 2, 'z 1 to 2',
'z above 2') AS z_bucket,
round(avg(z), 2) AS avg_z_start,
round(avg(z_fwd), 2) AS avg_z_20d_later,
count() AS episode_count
FROM horizon
WHERE date >= '2019-01-01'
AND date <= '2025-11-15'
AND isFinite(z_fwd)
GROUP BY z_bucket
ORDER BY avg_z_startСессии, начавшиеся в корзине z below -2, имели среднее значение -2.42 в этот день, а тот же спред в среднем составил -0.84 через двадцать сессий (на основе 138 сессий). С другой стороны, корзина z above 2 начиналась с 2.64 и составляла 0.92 через двадцать сессий. Кривая, стремящаяся к нулю с обоих концов, — это характерная форма возврата к среднему.
Изучайте данные с учетом столбца количества сессий. В крайних корзинах содержится наименьшее число сессий, а сессии внутри одной корзины сильно перекрываются, поэтому основная часть данных приходится на несколько длительных периодов. Среднее значение не является гарантией для каждой отдельной сделки.
Почему парный трейдинг перестает работать?
Коэффициент хеджирования не является константой. При пересчете на каждый календарный год он меняется.
Точный SQL-код для каждого числа
WITH daily AS (
SELECT
date,
anyIf(toFloat64(close), ticker = 'PEP') AS pep,
anyIf(toFloat64(close), ticker = 'KO') AS ko,
anyIf(toFloat64(close), ticker = 'LOW') AS lowes,
anyIf(toFloat64(close), ticker = 'HD') AS hd
FROM global_markets.stocks_daily_aggs
WHERE ticker IN ('KO', 'PEP', 'HD', 'LOW')
AND date BETWEEN '2019-01-01' AND '2025-12-31'
GROUP BY date
HAVING ko > 0 AND pep > 0 AND hd > 0 AND lowes > 0
)
SELECT
toYear(date) AS year,
round(covarSamp(pep, ko) / varSamp(ko), 3) AS pep_on_ko_beta,
round(covarSamp(lowes, hd) / varSamp(hd), 3) AS lowes_on_hd_beta
FROM daily
GROUP BY year
ORDER BY yearНаклон зависимости PEP от KO, измеренный 2.338 в течение 2019 и -0.543 в течение 2025, представлен вместе со второй парой из того же сектора для сравнения. Бэктест, который подбирает один коэффициент наклона на всей истории и торгует по нему с первого дня, дает каждой ранней сделке результат, который никто не мог получить в то время. Решение скучное, но эффективное: пересчитывайте параметры на скользящем окне и оценивайте каждый день, используя данные, доступные на тот момент. Воспроизводимый бэктест позволяет другому специалисту проверить эту дисциплину.
Корпоративные действия меняют одну из сторон пары за ночь. Сплит четыре-к-одному превращает одну акцию в четыре и делит котировку на четыре, из-за чего спред, рассчитанный через эту дату по неадаптированным ценам, совершает скачок до уровня, по которому никогда не было сделок. Слияния, выделения компаний (spin-offs) и изменения в индексах приводят к аналогичным, но менее заметным последствиям. Начинайте с истории цен с поправкой на сплиты и учитывайте, что тикер может быть передан совершенно другой компании, что является причиной поломки наборов данных из-за тикеров.
Разрыв отношений и возможность выглядят одинаково в моменте. Самое широкое значение z-score, которое когда-либо показывала пара, — это либо лучшая точка входа, либо первая неделя отношений, которые закончились. В моменте и то, и другое выглядит как растянутый спред. Размер позиции берет на себя ту нагрузку, с которой не справляется статистика: критерий Келли для определения размера позиции и таргетирование волатильности для определения размера позиции — это два подхода к тому, какую долю счета может занимать один спред, а максимальная просадка показывает, как долгое нахождение не на той стороне от среднего влияет на кривую доходности.
Скользящий z-score не является тестом на коинтеграцию. Существуют формальные тесты. Процедура Энгла-Грейнджера выполняет регрессию, а затем проверяет остаточный спред на стационарность; тест Йохансена расширяет эту идею на количество активов более двух. Z-score предполагает наличие свойства, которое проверяют эти тесты, и он будет охотно показывать большое значение для спреда, у которого вообще нет стабильного среднего, поскольку трендовый ряд всегда находится далеко от своего скользящего среднего.
Примечания к данным и что эти цифры не учитывают
Панель корреляции использует дневные цены закрытия с 01.01.2024 по 31.12.2025 и рассчитывает доходность по последовательным закрытиям, исключая первую сессию для каждого инструмента. График z-score подбирает коэффициент хеджирования только по ценам закрытия 2023 года, а затем оценивает 2024 и 2025 годы с использованием скользящего среднего за шестьдесят три сессии и выборочного стандартного отклонения, с выборкой по последнему значению каждой недели. Панель возврата к среднему загружает историю с 2018 года и предоставляет отчеты начиная с 2019 года, поэтому каждый оцененный день имеет за собой полное скользящее окно; расчеты заканчиваются в середине ноября 2025 года, чтобы каждый день имел двадцать сессий в будущем внутри выборки.
Ни одна из этих панелей не является стратегией. Они не учитывают торговые издержки, спред bid-ask, комиссию за заем короткой позиции, дивиденды и финансирование. Используются только цены закрытия, что означает, что вход, отмеченный по цене закрытия, — это вход, который никто не мог исполнить по этой цене.
Часто задаваемые вопросы
В чем разница между корреляцией и коинтеграцией?
Корреляция показывает, движутся ли две акции в одном направлении в одни и те же дни, по шкале от минус одного до плюс одного. Коинтеграция определяет, остается ли разница между их ценами в пределах стабильного диапазона. Пара может иметь высокий показатель по первому критерию и не соответствовать второму; именно поэтому скрининг по корреляции часто выявляет пары, которые впоследствии расходятся.
Как рассчитать коэффициент хеджирования в парном трейдинге?
Постройте прямую линию зависимости цены одной акции от другой и определите наклон. Этот наклон показывает количество единиц первой акции, необходимое для компенсации одной единицы второй. Поскольку это динамическая величина, большинство алгоритмов пересчитывают её на скользящем окне, а не один раз для всей выборки.
Какие значения z-score используют трейдеры для входа и выхода?
В учебных примерах вход обычно осуществляется при отклонении от скользящего среднего на полторы-две стандартных единицы, а выход — вблизи нуля целых пяти десятых. Эти цифры являются условными стандартами, унаследованными из ранних публикаций, а не измеренными оптимальными значениями. Их изменение влияет как на количество сделок, так и на длительность удержания позиции.
Могут ли две акции быть коинтегрированными при низкой корреляции?
Да. Корреляция рассчитывается на основе дневных изменений, а коинтеграция — на основе уровня разрыва. Поэтому два актива, чьи ежедневные движения редко совпадают, могут сохранять стабильную дистанцию в долгосрочной перспективе. Верно и обратное: высокая дневная корреляция может сопровождаться разрывом, который увеличивается из года в год.
Почему коинтегрированная пара перестает работать?
Связь, удерживающая разрыв, может измениться: из-за слияния, выделения бизнеса, смены структуры деятельности одной из компаний или изменения состава индекса, влияющего на состав акционеров. Статистические показатели в дни перед разрывом выглядят так же, как и перед обычным возвратом к среднему, поэтому данный риск необходимо учитывать при расчете размера позиции, а не пытаться его предсказать.
Каждая панель здесь содержит точный SQL-запрос, поэтому окна, период подгонки и границы корзин полностью прозрачны. Чтобы применить тот же спред и z-score к интересующей вас паре, задайте вопрос на обычном английском языке в терминале Strasmore.