Pairs Trading ve Eşbütünleşme Analizi Nasıl Yapılır
Pairs trading stratejisinde eşbütünleşme ve korelasyon farklarını inceleyin. Hedge ratio, spread ve z-score hesaplamalarını gerçek hisse kapanış verileriyle adım adım öğrenin.
Pairs trading ve eşbütünleşme (cointegration) bir bütündür: İşlem, iki hisse senedi fiyatı arasındaki farkın istikrarlı bir seviyeye geri dönme eğilimine dayanır; eşbütünleşme ise bu farkın varlığını kanıtlayan istatistiksel özelliktir. Korelasyon ise farklı bir durumu ölçer. İki hisse senedi yüksek korelasyona sahip olsa dahi birbirinden sonsuza dek uzaklaşabilir; günlük hareketleri birbirine pek uymayan iki hisse senedi ise yıllarca sabit bir farkı koruyabilir. Bu sayfa, hedge ratio, spread ve z-score değerlerini manuel olarak oluşturur, her üçünü de gerçek kapanış fiyatları üzerinden ölçer ve ardından bu kurgunun hangi durumlarda başarısız olduğuna eşit ağırlıkta yer verir.
Pairs trading'de eşbütünleşme (cointegration) nedir?
Korelasyon, iki hissenin günlük yüzde değişimlerinin birbirine yakınlığını ifade eder. -1 ile +1 arasında değer alır; +1 değeri, örneklemdeki her seansta iki hissenin birlikte yükselip düştüğü anlamına gelir. Bu değer, iki fiyat arasındaki mesafe hakkında hiçbir bilgi vermez.
Eşbütünleşme ise bu mesafe ile ilgili bir durumdur. B hissesini alın, A hissesinin sabit bir katını çıkarın ve geriye kalana bakın. Eğer bu kalan seri, yani spread, uzaklaşıp gitmek yerine belirli bir aralıkta kalıyorsa, bu iki isim eşbütünleşiktir. Fiyatların kendileri her yöne gidebilir ancak kombinasyonları gidemez.
Ders kitaplarında kullanılan klasik benzetme, tasmalı bir köpektir. Yürüyüşçü ve köpek sokakta öngörülemez yollar izler ancak tasma, aralarındaki mesafenin sınırlı kalmasını sağlar. Korelasyon, ikisinin aynı anda adım atıp atmadığını sorgular. Eşbütünleşme ise tasmanın kopup kopmadığını sorgular.
Aşağıdaki panel, 2024 ve 2025 yılları boyunca beş tanıdık çift üzerinde ilk fikri ölçmektedir. return_corr sütunu, insanların genellikle bu kelimeyle kastettiği günlük yüzde değişim korelasyonudur. price_corr sütunu ise ham kapanış fiyatlarının korelasyonudur; bu sayı, her ikisi de yükselen neredeyse tüm hisse çiftleri için yanıltıcı derecede yüksek bir sonuç verir.
Her verinin arkasındaki tam 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 DESCGünlük değişim korelasyonuna göre sıralandığında, HD / LOW panelin en üstünde 0.868 değeriyle yer alırken, aynı dönemde iki fiyat seviyesinin korelasyonu 0.849 olarak ölçülmüştür. En alt satırda ise AAPL / MSFT, 0.479 getiri korelasyonuna karşılık 0.508 fiyat korelasyonuna sahiptir. Her iki sütun da bir pairs trader'ın sorduğu soruya yanıt vermez. İkisi de eş yönlü hareketi ölçer, oysa yapılan işlem bir mesafe ölçümü gerektirir.
Hedge oranı ve spread nasıl hesaplanır?
Kapanış fiyatlarından oluşan iki liste üzerinde, sırasıyla beş adım. math dışında hiçbir paket, veri sağlayıcı veya ağ bağlantısı gerektirmeyen yalın Python kodu tüm süreci kapsar.
- Her seriyi merkezleyin.
mean_a = sum(a) / len(a)ve aynı işlemblistesi için uygulanır. - Hedge oranını belirleyin. Bu, B'nin A'ya karşı çizilen düz bir doğrunun eğimidir:
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). Bu değer, bir birim B'yi dengeleyen A birim sayısı olarak okunur. - Spread'i oluşturun.
spread = [b[i] - beta * a[i] for i in range(len(a))]. Eşbütünleşik bir çiftte bu seri, trend oluşturmak yerine belirli bir seviye etrafında hareket eder. - Hareketli bir pencere kullanın.
w = spread[i - win + 1 : i + 1]ile pencere ortalamasımu = sum(w) / len(w), örneklem standart sapması isesd = math.sqrt(sum((x - mu) ** 2 for x in w) / (len(w) - 1))olur. Hareketli ifadesi, pencerenin değerlendirilen günde bittiğini ve sonrasındaki verileri içermediğini belirtir. - Puanlayın ve yazdırın.
z = (spread[i] - mu) / sd, ardındanabs(z) > 1.5olduğunda bir giriş satırı,abs(z) < 0.5olduğunda ise bir çıkış satırı yazdırılır. İki z değeri, spread'in kendi yakın dönem ortalamasının iki standart sapma üzerinde olduğunu gösterir.
Süreci izlemek için iki adet sabit fiyat listesi yeterlidir ve beş birimlik bir win, örnek uygulamanın okunabilir kalmasını sağlar. Ciddi çalışmalarda, yaklaşık bir çeyreğe denk gelen altmış üç seanslık bir süre kullanılır. Giriş için bir buçuk, çıkış için sıfır virgül beş olan bu eşikler, bir eğitimden diğerine aktarılan geleneksel değerlerdir. Bunlar birer bulgu değildir ve aşağıdaki panellerde yer alan hiçbir veri bu değerleri seçmemiştir.
Gerçek fiyatlar üzerinde pairs trading z-skoru nasıl görünür?
Aynı hesaplamayı iki hanehalkı içecek markası olan KO ve PEP üzerinde uygulayalım. Hedge oranı yalnızca 2023 kapanış verilerinden elde edilmiş olup, grafiğin kapsadığı 2024 ve 2025 yılları boyunca sabit tutulmuştur. Eğimi, skorlama yapacağınız örneklem üzerinde hesaplamak backtesting'de ileriye dönük önyargı (look-ahead bias) yaratır; uyum penceresi ile skorlama penceresini ayrı tutmak buna karşı alınabilecek en basit önlemdir.
Her verinin arkasındaki tam 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İzleme grafiği 105 haftalık okuma içerir. Pencereyi -1.53 z-skorunda açar ve -0.68 seviyesinde kapatır. Tek bir noktadan ziyade genel şekli okuyun. Stratejinin varsaydığı şekilde hareket eden bir çift, eşiğini geçer, birkaç hafta boyunca sıfıra dönmek için çaba sarf eder ve tekrar kesişir. Ortalama dönüşü (mean reversion) durmuş bir çift ise eşiğin ötesinde park eder ve orada kalır; bu durum grafikte orta çizgiden uzak, uzun ve düz bir hat olarak görünür.
Kointegre bir spread her zaman geri döner mi?
Hayır; bunu görmenin en dürüst yolu, her başlangıç noktasından sonra neyin gerçekleştiğini ölçmektir. Aşağıdaki panel, iki bin on dokuzdan iki bin yirmi beşin sonlarına kadar olan her seansı o günün z-skoruna göre gruplandırır ve ardından aynı spread’in yirmi seans sonraki ortalama z-skorunu raporlar. Regresyon sonrası tahminlerin grafiği etkilememesi için, uyarlanmış bir spread yerine fiyat oranının logaritması kullanılır.
Her verinin arkasındaki tam 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 grubunda başlayan seanslar gün içinde ortalama -2.42 değerini almış, aynı spread yirmi seans sonra 138 adet seans genelinde ortalama -0.84 seviyesinde gerçekleşmiştir. Diğer uçta ise z above 2 grubu 2.64 seviyesinden başlamış ve yirmi seans sonra 0.92 olarak ölçülmüştür. Her iki uçtan sıfıra doğru çekilen bir eğri, ortalamaya dönüşün (mean reversion) oluşturduğu şekildir.
Bunu, seans sayısı sütununu dikkate alarak okuyun. Dış gruplar en az sayıda seansı içerir ve bir grup içindeki seanslar büyük ölçüde örtüşür; bu nedenle satırların çoğunu az sayıda uzun dönem oluşturur. Bir ortalama, herhangi bir tekil giriş için bir vaat teşkil etmez.
Pairs trading neden işlevini yitirir?
Hedge oranı sabit değildir. Her takvim yılında yeniden hesaplandığında değişir.
Her verinin arkasındaki tam 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'in KO üzerindeki eğimi 2.338 döneminde 2019, -0.543 döneminde ise 2025 olarak ölçülmüştür; karşılaştırma için ikinci sektör çifti de yanına eklenmiştir. Tüm geçmişi kapsayan tek bir eğim belirleyen ve bunu ilk günden itibaren işleme koyan bir geriye dönük test (backtest), o dönemde kimsenin elinde tutamayacağı bir rakamı her erken işleme atfeder. Çözüm sıkıcı ancak etkilidir: Hareketli bir pencere üzerinde yeniden hesaplama yapın ve her günü, o gün mevcut olan parametrelerle puanlayın. Tekrarlanabilir bir backtest, bu disiplinin başkaları tarafından denetlenebilmesini sağlar.
Kurumsal aksiyonlar bir bacağı bir gecede yeniden yazar. Dört-bir oranındaki bir bölünme, bir hisseyi dörde böler ve fiyatı dörtte birine indirir; düzeltilmemiş fiyatlar üzerinden o tarih boyunca hesaplanan bir spread, hiç gerçekleşmemiş bir seviyeye sıçrar. Birleşmeler, bölünmeler (spin-off) ve endeks değişiklikleri bunun daha sessiz versiyonlarını gerçekleştirir. Bölünme düzeltmeli fiyat geçmişi ile başlayın ve bir ticker sembolünün tamamen farklı bir şirkete atanabileceğini unutmayın; ticker sembollerinin veri setlerini bozmasının nedeni budur.
Bir kırılma ile bir fırsat, gerçekleştiği sırada aynı görünür. Bir çiftin bugüne kadar verdiği en geniş z-skoru, ya sunduğu en iyi giriş noktasıdır ya da sona ermiş bir ilişkinin ilk haftasıdır. Her ikisi de o gün, genişlemiş bir spread gibi görünür. Pozisyon büyüklüğü, istatistiklerin taşıyamadığı yükü üstlenir: Kelly kriteri ile pozisyon büyüklüğü ve volatilite hedefli pozisyon büyüklüğü, bir spread'in hesapta ne kadar yer kaplayacağına dair iki çerçevedir; maksimum düşüş (drawdown) ise ortalamanın yanlış tarafında uzun süre kalmanın öz sermaye eğrisine etkisini ölçer.
Hareketli z-skoru bir eşbütünleşme (cointegration) testi değildir. Resmi testler mevcuttur. Engle-Granger prosedürü regresyonu çalıştırır, ardından kalan spread'in durağanlığını test eder; Johansen testi ise bu fikri iki ismin ötesine taşır. Z-skoru, bu testlerin kontrol ettiği özelliği varsayar ve trend gösteren bir seri kendi hareketli ortalamasından her zaman uzak kalacağı için, sabit bir ortalaması olmayan bir spread üzerinde de rahatlıkla büyük bir rakam üretir.
Veri notları ve bu rakamların dışarıda bıraktıkları
Korelasyon paneli, 01-01-2024 ile 31-12-2025 arasındaki günlük kapanışları kullanır ve her ismin ilk seansını hariç tutarak ardışık kapanışlardan getirileri hesaplar. Z-skoru izi, hedge oranını yalnızca 2023 kapanışlarına göre belirler; ardından 2024 ve 2025 verilerini, her haftanın son okumasına göre örneklenmiş 63 seanslık hareketli ortalama ve örneklem standart sapması ile puanlar. Geri dönüş paneli 2018'den itibaren geçmişi yükler ve 2019'dan itibaren raporlama yapar; böylece puanlanan her günün arkasında tam bir hareketli pencere bulunur. Kasım 2025 ortasında durur, böylece her günün örneklem içinde önünde yirmi seanslık bir alan kalır.
Bu panellerin hiçbiri bir strateji değildir. İşlem maliyetleri, bid-ask spread, kısa bacakta ödünç alma ücreti, temettüler veya finansman maliyetleri içermezler. Yalnızca kapanış fiyatları baz alınmıştır; bu da kapanışta işaretlenen bir girişin, kimsenin o seviyeden gerçekleştiremeyeceği bir giriş olduğu anlamına gelir.
Sıkça Sorulan Sorular
Korelasyon ve eşbütünleşme (cointegration) arasındaki fark nedir?
Korelasyon, iki hissenin aynı günlerde ve aynı yönde hareket edip etmediğini eksi bir ile artı bir ölçeğinde ölçer. Eşbütünleşme ise fiyatları arasındaki mesafenin istikrarlı bir aralıkta kalıp kalmadığını ölçer. Bir çift, ilkinde yüksek puan alıp ikincisinde başarısız olabilir; korelasyon taramalarının birbirinden uzaklaşan çiftleri getirmesinin yaygın nedeni budur.
Çift ticaretinde (pairs trading) hedge oranı nasıl hesaplanır?
Bir hissenin fiyatını diğerine göre doğrusal bir regresyona tabi tutun ve eğimi alın. Bu eğim, ikinci hissenin bir birimini dengelemek için gereken ilk hisse birimi sayısıdır. Bu değişken bir değer olduğundan, çoğu uygulama bunu tüm örneklem üzerinde tek seferde hesaplamak yerine hareketli bir pencere üzerinde yeniden hesaplar.
Çift ticareti yapanlar giriş ve çıkış için hangi z-skorunu kullanır?
Eğitim örneklerinde genellikle hareketli ortalamadan bir buçuk ila iki standart sapma uzaklıkta giriş yapılır ve sıfır virgül beş civarında çıkış yapılır. Bu sayılar ölçülmüş optimum değerlerden ziyade önceki çalışmalardan devralınan geleneklerdir; bu değerleri değiştirmek hem işlem sayısını hem de her bir işlemin elde tutulma süresini değiştirir.
İki hisse düşük korelasyonla eşbütünleşik olabilir mi?
Evet. Korelasyon günlük değişimler üzerinden, eşbütünleşme ise fiyat farkının seviyesi üzerinden hesaplanır. Bu nedenle günlük hareketleri nadiren örtüşen iki isim, uzun vadede istikrarlı bir mesafe koruyabilir. Bunun tersi de gerçekleşir: Yıllar geçtikçe genişleyen bir fiyat farkına rağmen yüksek günlük korelasyon görülebilir.
Eşbütünleşik bir çift neden çalışmayı durdurur?
Fiyat farkını bir arada tutan bağ değişebilir: Bir birleşme, bölünme (spin-off), şirketlerden birinin iş karmasındaki bir değişim veya hissenin sahiplik yapısını değiştiren bir endeks değişikliği buna neden olabilir. Kırılmadan önceki günlerdeki istatistikler, sıradan bir ortalamaya dönüşten önceki günlerle aynı görünür; bu durum tahmin edilmek yerine pozisyon büyüklüğü ayarlanarak yönetilmesi gereken kısımdır.
Buradaki her panel, altında yer alan SQL sorgusuyla birlikte sunulmaktadır; böylece pencereler, uyum dönemi ve aralık sınırlarının tümü görülebilir. Takip ettiğiniz bir çift üzerinde aynı spread ve z-skorunu çalıştırmak için Strasmore terminalinde sorunuzu yalın bir dille iletmeniz yeterlidir.