페어 트레이딩과 공적분 개념 및 실전 계산법
페어 트레이딩의 핵심인 공적분(cointegration)의 원리를 설명합니다. 상관관계와의 차이점을 분석하고 실제 종가를 활용하여 헤지 비율(hedge ratio), 스프레드(spread), Z-스코어(z score)를 직접 산출하는 과정을 다룹니다.
페어 트레이딩과 공적분(cointegration)
페어 트레이딩과 공적분은 밀접한 관계가 있습니다. 이 거래는 두 주식 가격 사이의 격차가 안정적인 수준으로 회귀한다는 점을 전제로 하며, 공적분은 이러한 격차가 존재함을 입증하는 통계적 속성입니다. 상관관계(correlation)는 이와는 다른 개념을 측정합니다. 두 주식의 상관관계가 높더라도 영원히 멀어질 수 있으며, 일일 변동이 거의 일치하지 않는 두 주식도 수년간 일정한 격차를 유지할 수 있습니다. 이 페이지에서는 헤지 비율(hedge ratio), 스프레드(spread), Z-스코어(z score)를 직접 산출하고, 실제 종가(closing prices)를 바탕으로 이 세 가지 지표를 측정합니다. 또한, 이러한 구성 방식이 실패하는 경우에 대해서도 동일한 비중으로 다룹니다.
페어 트레이딩에서 공적분(cointegration)이란 무엇인가?
상관관계(correlation)는 두 주식의 일간 수익률이 얼마나 밀접하게 움직이는지를 나타냅니다. 이 수치는 -1에서 +1 사이의 값을 가지며, +1은 표본 기간 내 모든 거래일 동안 두 종목이 함께 상승하고 하락했음을 의미합니다. 그러나 상관관계는 두 주가 사이의 거리(distance)에 대해서는 아무런 정보를 제공하지 않습니다.
공적분은 바로 그 거리에 관한 개념입니다. 주식 B의 가격에서 주식 A의 가격에 특정 배수를 곱한 값을 뺀 나머지를 살펴봅니다. 만약 이 잔차(residual)인 스프레드(spread)가 무한히 발산하지 않고 일정한 범위 내에 머문다면, 두 종목은 공적분 관계에 있다고 합니다. 개별 주가는 어디로든 자유롭게 움직일 수 있지만, 두 종목을 조합한 결과물은 일정한 범위 안에 묶여 있습니다.
교과서에서는 이를 목줄을 맨 개에 비유합니다. 산책하는 사람과 개는 모두 예측할 수 없는 경로로 길을 걷지만, 목줄이 두 대상 사이의 거리를 일정하게 유지합니다. 상관관계는 두 대상이 동시에 발을 내딛는지 묻는 것이라면, 공적분은 목줄이 팽팽하게 유지되는지를 묻는 것입니다.
아래 표는 2024년과 2025년에 걸쳐 다섯 가지 익숙한 페어에 대해 첫 번째 개념을 측정한 결과입니다. return_corr 열은 사람들이 흔히 상관관계라고 부르는 일간 수익률의 상관계수입니다. price_corr 열은 원본 종가(raw closing prices)의 상관계수인데, 이는 단순히 두 종목이 모두 상승하기만 해도 수치가 높게 나타나는 경향이 있습니다.
모든 수치 뒤에 숨겨진 정확한 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를 보였습니다. 두 열 모두 페어 트레이더가 던지는 질문에 대한 답을 주지 못합니다. 두 열 모두 동반 움직임(co-movement)을 측정할 뿐이며, 실제 트레이딩에는 거리(distance)에 대한 척도가 필요하기 때문입니다.
헤지 비율(hedge ratio)과 스프레드(spread)는 어떻게 계산하는가?
종가 리스트 두 개를 사용하여 순서대로 다섯 단계를 거칩니다. math만 임포트하면 별도의 패키지, 데이터 공급자, 네트워크 연결 없이 순수 Python만으로 모든 과정을 처리할 수 있습니다.
- 각 시계열의 중심화(centering).
mean_a = sum(a) / len(a)을 수행하고, 리스트b에 대해서도 동일하게 적용합니다. - 헤지 비율 산출. 이는 A에 대한 B의 직선 기울기입니다:
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). 이를 B 한 단위를 상쇄하는 A의 단위 수로 해석합니다. - 스프레드 구축.
spread = [b[i] - beta * a[i] for i in range(len(a))]. 공적분(cointegrated) 관계인 쌍의 경우, 이 시계열은 추세를 형성하지 않고 특정 수준을 중심으로 맴돕니다. - 후행 윈도우(trailing window) 설정.
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-점수가 2라는 것은 스프레드가 최근 평균보다 두 표준편차만큼 위에 있음을 의미합니다.
하드코딩된 두 개의 가격 리스트만으로도 실행 과정을 확인하기에 충분하며, win을 5로 설정하면 예제 데이터를 읽기 쉽게 유지할 수 있습니다. 실무에서는 약 1분기 분량인 63거래일 정도를 사용합니다. 진입 기준 1.5와 청산 기준 0.5는 여러 튜토리얼을 거쳐 전해 내려오는 관습적인 수치입니다. 이는 분석을 통해 도출된 결과값이 아니며, 아래 패널의 어떤 항목도 이 수치를 직접 선택하지 않았습니다.
실제 가격에서 페어 트레이딩(pairs trading) Z-score는 어떤 모습인가?
다음은 두 대표적인 음료 기업인 KO와 PEP를 대상으로 동일한 계산을 수행한 결과입니다. 헤지 비율(hedge ratio)은 2023년 종가만을 기준으로 산출되었으며, 차트가 포함하는 기간인 2024년과 2025년 동안 고정되었습니다. 평가 대상 기간과 동일한 표본으로 기울기를 산출하는 것은 백테스팅에서의 미래 정보 편향(look-ahead bias)에 해당하며, 적합(fitting) 기간과 평가(scoring) 기간을 분리하는 것은 이를 방지하는 가장 기본적인 방법입니다.
모든 수치 뒤에 숨겨진 정확한 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에서 종료됩니다. 단일 지점보다는 전체적인 형태를 파악하십시오. 전략이 가정하는 대로 움직이는 페어는 임계값을 교차한 뒤 몇 주에 걸쳐 0으로 회귀하며 다시 임계값을 교차합니다. 평균 회귀(mean reverting)가 멈춘 페어는 임계값 너머에 머무르게 되며, 차트상에서는 중심에서 멀리 떨어진 긴 평탄 구간으로 나타납니다.
공적분된 스프레드는 항상 회귀하는가?
아니오. 이를 확인하는 가장 정직한 방법은 모든 시작점 이후에 어떤 결과가 나타났는지 측정하는 것입니다. 아래 패널은 2019년부터 2025년 말까지의 각 세션을 해당 일자의 Z-score(표준점수)별로 분류한 뒤, 20거래일 후 동일한 스프레드의 평균 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_startz below -2 버킷에서 시작된 세션은 당일 평균 -2.42을 기록했으며, 20거래일 후 동일한 스프레드는 138개의 세션에 걸쳐 평균 -0.84을 기록했습니다. 반대편 끝인 z above 2 버킷은 2.64에서 시작하여 20거래일 후 0.92로 측정되었습니다. 양 끝에서 0을 향해 당겨지는 곡선은 평균 회귀(mean reversion)가 만드는 형태입니다.
이 데이터를 읽을 때는 개수(count) 열을 함께 고려해야 합니다. 바깥쪽 버킷일수록 포함된 세션 수가 가장 적으며, 한 버킷 내부의 세션들은 서로 크게 중첩됩니다. 즉, 소수의 긴 기간이 대부분의 행을 구성합니다. 평균은 개별 진입에 대한 수익을 보장하지 않습니다.
페어 트레이딩은 왜 작동을 멈추는가?
헤지 비율(hedge ratio)은 상수가 아니다. 매년 새로 산출하면 비율은 변한다.
모든 수치 뒤에 숨겨진 정확한 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 yearPEP와 KO의 기울기를 2.338 기간 동안 측정하고, 2019 및 -0.543 기간 동안 2025로 측정하였으며, 비교를 위해 두 번째 섹터 페어를 함께 제시하였다. 전체 기간에 걸쳐 하나의 기울기를 산출하고 첫날부터 거래하는 백테스트는, 당시에는 아무도 보유할 수 없었던 수치를 모든 초기 거래에 적용하는 오류를 범한다. 이를 해결하는 방법은 단순하지만 효과적이다. 이동 윈도우(trailing window)를 사용하여 매번 새로 산출하고, 해당 시점에 가용한 파라미터로 매일의 점수를 산정하는 것이다. 재현 가능한 백테스트는 이러한 원칙을 타인이 검증할 수 있게 한다.
기업 활동은 하룻밤 사이에 한쪽 종목의 데이터를 재작성한다. 4대 1 주식 분할은 1주를 4주로 만들고 호가를 4분의 1로 낮추는데, 조정되지 않은 가격으로 계산된 스프레드(spread)는 실제 거래된 적 없는 수준으로 급등한다. 합병, 분사, 지수 변경 등도 이와 유사한 현상을 조용히 일으킨다. 분할 조정된 가격 이력으로 시작해야 하며, 티커(ticker) 심볼은 완전히 다른 기업에 재할당될 수 있다는 점에 유의해야 한다. 이것이 티커 심볼이 데이터셋을 망가뜨리는 이유이다.
붕괴와 기회는 발생하는 동안에는 동일해 보인다. 페어가 기록한 가장 넓은 z-score는 역대 최고의 진입 기회이거나, 관계가 끝난 첫 주일 수 있다. 두 경우 모두 당일에는 스프레드가 벌어진 것처럼 보인다. 통계가 해결하지 못하는 부분은 포지션 규모 산정이 담당한다. 켈리 공식(Kelly criterion) 포지션 사이징과 변동성 타겟팅 포지션 사이징은 하나의 스프레드가 계좌에서 차지할 수 있는 비중을 결정하는 두 가지 프레임워크이며, 최대 낙폭(maximum drawdown)은 평균의 반대편에서 장기간 머물 때 자기자본 곡선에 어떤 영향을 미치는지 측정한다.
롤링 z-score는 공적분(cointegration) 검정이 아니다. 공식적인 검정 방법은 따로 존재한다. 엥글-그레인저(Engle-Granger) 절차는 회귀 분석을 수행한 뒤 잔차 스프레드의 정상성(stationarity)을 검정하며, 요한슨(Johansen) 검정은 이를 두 종목 이상으로 확장한다. z-score는 이러한 검정이 확인하는 속성을 가정할 뿐이며, 평균이 안정적이지 않은 스프레드에서도 큰 수치를 도출할 수 있다. 추세가 있는 시계열은 항상 이동 평균으로부터 멀리 떨어져 있기 때문이다.
데이터 참고 사항 및 제외된 요소
상관관계 패널은 2024년 1월 1일부터 2025년 12월 31일까지의 일일 종가를 사용하며, 각 종목의 첫 거래일을 제외하고 연속된 종가로부터 수익률을 계산한다. z-score 추적은 2023년 종가만을 사용하여 헤지 비율을 산출한 뒤, 2024년과 2025년 데이터를 63거래일 이동 평균 및 표본 표준편차로 점수화하고 매주 마지막 거래일 기준으로 샘플링한다. 평균 회귀 패널은 2018년부터의 이력을 불러와 2019년부터 보고하므로, 점수화된 모든 날짜는 충분한 이동 윈도우를 확보하고 있다. 또한 2025년 11월 중순에 종료하여 모든 날짜가 샘플 내에서 20거래일의 미래 데이터를 포함하도록 하였다.
이 패널들은 전략이 아니다. 거래 비용, 매수-매도 호가 스프레드, 공매도 종목의 대차 수수료, 배당금, 금융 비용이 반영되지 않았다. 종가만을 사용했으므로, 종가에 표시된 진입 시점은 실제 시장에서 아무도 체결할 수 없었던 가격이다.
자주 묻는 질문(FAQ)
상관관계(correlation)와 공적분(cointegration)의 차이는 무엇입니까?
상관관계는 두 주식이 같은 날 같은 방향으로 움직이는지를 영하 일에서 영상 일 사이의 수치로 측정합니다. 공적분은 두 주식 가격 사이의 거리가 안정적인 범위 내에 머무르는지를 측정합니다. 한 쌍의 종목이 상관관계 점수는 높더라도 공적분은 성립하지 않을 수 있는데, 이는 상관관계 스크리닝을 통과한 종목들이 실제로는 서로 멀어지는 주된 이유입니다.
페어 트레이딩에서 헤지 비율(hedge ratio)은 어떻게 계산합니까?
한 주식의 가격을 다른 주식의 가격에 대해 직선으로 회귀 분석하여 그 기울기를 구합니다. 이 기울기는 두 번째 주식 한 단위를 상쇄하기 위해 필요한 첫 번째 주식의 단위 수입니다. 이는 변동하는 값이므로, 대부분의 구현 방식에서는 전체 표본에 대해 한 번만 계산하기보다 후행 기간(trailing window)을 설정하여 지속적으로 재산출합니다.
페어 트레이더는 진입과 청산에 어떤 Z-score를 사용합니까?
입문용 예제에서는 보통 후행 평균에서 표준편차의 일 점 오 배에서 이 배만큼 벗어났을 때 진입하고, 영 점 오 배 근처에서 청산합니다. 이러한 수치는 측정된 최적값이라기보다 초기 문헌에서부터 내려온 관습적인 기준입니다. 이 기준을 변경하면 거래 횟수와 각 거래의 보유 기간이 모두 달라집니다.
상관관계가 낮은 두 주식도 공적분 관계일 수 있습니까?
네, 가능합니다. 상관관계는 일일 변동폭을 기준으로 계산되지만, 공적분은 가격 차이의 수준을 기준으로 계산됩니다. 따라서 일일 움직임이 거의 일치하지 않는 두 종목이라도 장기적으로는 안정적인 거리 관계를 유지할 수 있습니다. 반대의 경우도 발생하는데, 일일 상관관계는 높지만 가격 차이가 해마다 벌어지는 상황이 이에 해당합니다.
공적분 관계인 페어가 작동을 멈추는 이유는 무엇입니까?
가격 차이를 유지하던 연결 고리가 합병, 분사, 기업 사업 구조의 변화, 또는 주식 보유 주체를 변화시키는 지수 변경 등으로 인해 바뀔 수 있습니다. 관계가 깨지기 직전의 통계적 수치는 일반적인 평균 회귀 직전의 모습과 동일하게 나타나며, 이 부분은 예측하기보다 리스크 관리를 통해 대응해야 합니다.
이곳의 모든 패널은 그 아래에 정확한 SQL을 함께 제공하므로, 윈도우 설정, 적합 기간, 버킷 경계 등을 모두 확인할 수 있습니다. 추적 중인 종목 쌍에 대해 동일한 스프레드(spread)와 Z-score를 실행하려면 Strasmore 터미널에 평이한 영어로 질문하십시오.