Strasmore Research
Siasatan Matt ConnorOleh Matt Connor

Cara Pairs Trading dan Kointegrasi Berfungsi

Kointegrasi adalah kunci utama dalam pairs trading dan ia berbeza daripada korelasi. Bina hedge ratio, spread serta z score menggunakan harga penutup sebenar secara manual.

Pairs trading dan kointegrasi

Pairs trading dan kointegrasi saling berkait rapat. Dagangan ini bergantung pada jurang antara dua harga saham yang sentiasa kembali ke tahap yang stabil. Kointegrasi ialah sifat statistik yang mengesahkan kewujudan jurang tersebut. Korelasi pula mengukur sesuatu yang berbeza. Dua saham boleh menunjukkan korelasi yang tinggi namun terus menyimpang antara satu sama lain selama-lamanya. Sebaliknya, dua saham yang pergerakan hariannya hampir tidak selari boleh mengekalkan jurang yang stabil selama bertahun-tahun.

Pembinaan model dan batasan

Halaman ini membina hedge ratio, spread, dan z score secara manual. Ia mengukur ketiga-tiga metrik tersebut berdasarkan harga penutup sebenar. Seterusnya, ia memperuntukkan ruang yang sama untuk membincangkan bagaimana pembinaan model ini boleh gagal.

Apakah itu kointegrasi dalam dagangan pasangan (pairs trading)?

Korelasi ialah tahap keakraban pergerakan peratusan harian dua saham. Ia berjulat daripada -1 hingga +1, dengan +1 bermaksud kedua-duanya naik dan turun bersama-sama pada setiap sesi dalam sampel. Ia tidak memberikan sebarang maklumat mengenai jarak antara kedua-dua harga tersebut.

Kointegrasi ialah pernyataan mengenai jarak tersebut. Ambil saham B, tolak gandaan tetap saham A, dan lihat baki yang tinggal. Jika siri baki tersebut, iaitu spread, kekal dalam julat yang terhad dan tidak melencong jauh, maka kedua-dua nama tersebut adalah berkointegrasi. Harga saham itu sendiri bebas untuk bergerak ke mana-mana. Gabungan kedua-duanya pula tidak.

Gambaran yang digunakan dalam buku teks ialah seekor anjing bertali. Pejalan kaki dan anjing itu masing-masing mengambil laluan yang tidak dapat diramal di sepanjang jalan, dan tali tersebut memastikan jarak antara mereka kekal terhad. Korelasi bertanya sama ada kedua-duanya melangkah pada saat yang sama. Kointegrasi bertanya sama ada tali tersebut masih memegang.

Panel di bawah mengukur idea pertama bagi lima pasangan yang lazim sepanjang tahun 2024 dan 2025. Lajur return_corr ialah korelasi pergerakan peratusan harian, yang biasanya dimaksudkan oleh orang ramai dengan perkataan tersebut. Lajur price_corr ialah korelasi harga penutup mentah, satu angka yang kelihatan baik bagi hampir mana-mana dua nama yang kedua-duanya meningkat.

PertanyaanKorelasi pulangan harian berbanding korelasi paras harga, lima pasangan lazim (2024-2025)
SQL tepat di sebalik setiap nombor
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
Run this yourself

Disusun mengikut korelasi pergerakan harian, HD / LOW berada di kedudukan teratas panel pada 0.868, manakala korelasi bagi dua tahap harga sepanjang tempoh yang sama mencatatkan 0.849. Pada baris bawah, AAPL / MSFT membawa korelasi pulangan sebanyak 0.479 di samping korelasi harga sebanyak 0.508. Tiada satu pun daripada lajur tersebut menjawab soalan yang ditanya oleh pedagang pasangan. Kedua-duanya mengukur pergerakan bersama, sedangkan dagangan tersebut memerlukan ukuran jarak.

Bagaimanakah anda mengira hedge ratio dan spread?

Lima langkah, mengikut urutan, merentasi dua senarai harga penutup. Python biasa merangkumi kesemuanya dengan math sebagai satu-satunya import: tiada pakej, tiada vendor data, tiada rangkaian.

  1. Pusatkan setiap siri. mean_a = sum(a) / len(a), dan perkara yang sama untuk senarai b.
  2. Sesuaikan hedge ratio. Ia adalah cerun garis lurus B berbanding 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). Baca ia sebagai bilangan unit A yang mengimbangi satu unit B.
  3. Bina spread. spread = [b[i] - beta * a[i] for i in range(len(a))]. Pada pasangan yang berintegrasi bersama (cointegrated), siri ini berlegar di sekitar satu tahap dan bukannya menunjukkan arah aliran.
  4. Ambil tetingkap susulan (trailing window). Dengan w = spread[i - win + 1 : i + 1], min tetingkap ialah mu = sum(w) / len(w) dan sisihan piawai sampel ialah sd = math.sqrt(sum((x - mu) ** 2 for x in w) / (len(w) - 1)). Susulan bermaksud tetingkap berakhir pada hari yang dinilai dan tidak menggunakan apa-apa selepasnya.
  5. Skor dan cetak. z = (spread[i] - mu) / sd, kemudian cetak baris masuk semasa abs(z) > 1.5 dan baris keluar sebaik sahaja abs(z) < 0.5. Z sebanyak dua meletakkan spread dua sisihan piawai di atas purata terkini sendiri.

Dua senarai harga yang dikodkan secara tetap sudah memadai untuk melihat proses ini berjalan, dan win sebanyak lima memastikan contoh mainan boleh dibaca. Kerja yang serius menggunakan sesuatu yang lebih hampir kepada enam puluh tiga sesi, kira-kira satu suku tahun. Ambang tersebut, satu perpuluhan lima untuk masuk dan sifar perpuluhan lima untuk keluar, adalah konvensyen yang diwariskan daripada satu tutorial kepada tutorial seterusnya. Ia bukanlah penemuan, dan tiada apa-apa dalam panel di bawah yang memilihnya.

Bagaimanakah skor z dagangan pasangan kelihatan pada harga sebenar?

Berikut adalah pengiraan yang sama bagi dua nama minuman isi rumah, KO dan PEP. Nisbah lindung nilai (hedge ratio) diperoleh daripada harga tutup tahun 2023 sahaja, kemudian ditetapkan kekal sepanjang tahun 2024 dan 2025, iaitu tempoh yang diliputi oleh carta tersebut. Menetapkan cerun pada sampel yang sama yang anda gunakan untuk membuat skor adalah bias pandang ke hadapan dalam ujian semula, dan memisahkan tempoh penetapan dengan tempoh pemarkahan adalah cara paling murah untuk menanganinya.

PertanyaanSkor z mingguan bagi spread KO/PEP, nisbah lindung nilai diselaraskan pada 2023 sahaja
SQL tepat di sebalik setiap nombor
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
Run this yourself

Jejak tersebut membawa 105 bacaan mingguan. Ia membuka tetingkap pada skor z sebanyak -1.53 dan menutupnya pada -0.68. Baca bentuknya dan bukannya mana-mana titik tunggal. Pasangan yang berkelakuan seperti yang diandaikan oleh strategi akan melintasi ambangnya, menghabiskan beberapa minggu untuk kembali ke arah sifar, dan melintasinya semula. Pasangan yang telah berhenti kembali kepada purata akan kekal di luar ambang tersebut dan terus berada di sana, yang pada carta kelihatan seperti garis rata yang panjang jauh dari bahagian tengah.

Adakah spread yang terkointegrasi sentiasa kembali ke tahap asal?

Tidak, dan cara yang jujur untuk melihatnya adalah dengan mengukur apa yang berlaku selepas setiap titik permulaan. Panel di bawah mengumpulkan setiap sesi dari tahun 2019 hingga lewat 2025 mengikut skor z hari tersebut, kemudian melaporkan purata skor z bagi spread yang sama dua puluh sesi kemudian. Ia menggunakan log nisbah harga dan bukannya spread yang disesuaikan, jadi tiada regresi yang dianggarkan selepas fakta menyentuh carta ini.

PertanyaanKedudukan spread KO/PEP selepas dua puluh sesi, mengikut skor z permulaan (2019-2025)
SQL tepat di sebalik setiap nombor
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
Run this yourself

Sesi yang bermula dalam baldi z below -2 mencatatkan purata -2.42 pada hari tersebut, dan spread yang sama mencatatkan purata -0.84 dua puluh sesi kemudian, merentasi 138 sesi. Pada hujung yang satu lagi, baldi z above 2 bermula pada 2.64 dan mencatatkan 0.92 selepas dua puluh sesi. Lengkung yang menarik ke arah sifar dari kedua-dua hujung adalah bentuk yang dihasilkan oleh pembalikan min (mean reversion).

Baca carta ini dengan mengambil kira lajur bilangan. Baldi luar memegang sesi paling sedikit, dan sesi di dalam baldi bertindih dengan banyak, jadi segelintir tempoh yang panjang membekalkan kebanyakan baris. Purata bukanlah satu janji mengenai mana-mana entri tunggal.

Mengapakah dagangan pasangan berhenti berfungsi?

Hedge ratio bukanlah satu pemalar. Laraskan semula nisbah ini pada setiap tahun kalendar dan ia akan berubah.

PertanyaanNisbah lindung nilai diselaraskan semula setiap tahun kalendar, dua pasangan sektor
SQL tepat di sebalik setiap nombor
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
Run this yourself

Kecerunan PEP terhadap KO diukur 2.338 merentasi 2019 dan -0.543 merentasi 2025, dengan pasangan sektor kedua disertakan sebagai perbandingan. Ujian ke belakang (backtest) yang menetapkan satu kecerunan sepanjang sejarah penuh dan mendagangkannya dari hari pertama memberikan setiap dagangan awal satu angka yang tidak mungkin dipegang oleh sesiapa pun pada masa itu. Penyelesaiannya membosankan namun berkesan: laraskan semula pada tetingkap bergerak (trailing window), dan nilai setiap hari dengan parameter yang tersedia pada hari tersebut. Ujian ke belakang yang boleh dihasilkan semula menjadikan disiplin itu boleh diperiksa oleh pihak lain.

Tindakan korporat menulis semula satu kaki (leg) dalam sekelip mata. Pecahan saham empat-untuk-satu menukarkan satu saham kepada empat dan membahagikan harga sebut harga kepada satu perempat, dan spread yang dikira merentasi tarikh tersebut pada harga yang tidak diselaraskan akan melonjak ke tahap yang tidak pernah didagangkan. Penggabungan, pecahan syarikat (spin-off) dan perubahan indeks melakukan versi yang lebih senyap bagi perkara yang sama. Mulakan dengan sejarah harga yang diselaraskan dengan pecahan, dan ambil perhatian bahawa simbol boleh diberikan semula kepada syarikat yang sama sekali berbeza, yang merupakan sebab ticker symbols merosakkan set data.

Satu kerosakan dan satu peluang kelihatan serupa semasa ia berlaku. Z score paling luas yang pernah dicatatkan oleh sesuatu pasangan sama ada merupakan penyertaan terbaik yang pernah ditawarkan atau minggu pertama bagi hubungan yang telah berakhir. Kedua-duanya kelihatan seperti spread yang tertegang pada hari tersebut. Penentuan saiz membawa beban yang tidak mampu dipikul oleh statistik: penentuan saiz posisi kriteria Kelly dan penentuan saiz posisi penyasaran volatiliti adalah dua rangka kerja bagi menentukan berapa banyak daripada akaun yang dibenarkan untuk digerakkan oleh satu spread, dan maximum drawdown mengukur kesan tempoh panjang di sebelah yang salah daripada purata terhadap lengkung ekuiti.

Z score bergerak bukanlah ujian kointegrasi. Ujian formal wujud. Prosedur Engle-Granger menjalankan regresi, kemudian menguji spread yang tertinggal untuk stationarity, dan ujian Johansen meluaskan idea tersebut melebihi dua nama. Z score mengandaikan sifat yang diperiksa oleh ujian tersebut, dan ia akan dengan gembira mencatatkan angka yang besar pada spread yang tidak mempunyai purata stabil langsung, memandangkan siri yang mempunyai trend sentiasa berada jauh daripada purata bergeraknya sendiri.

Nota data dan perkara yang ditinggalkan oleh angka-angka ini

Panel korelasi menggunakan harga tutup harian dari 2024-01-01 hingga 2025-12-31 dan mengira pulangan daripada harga tutup berturut-turut, dengan menggugurkan sesi pertama setiap nama. Jejak z score melaraskan hedge ratio pada harga tutup 2023 sahaja, kemudian memberi skor kepada 2024 dan 2025 dengan purata 63 sesi bergerak dan sisihan piawai sampel, yang disampelkan kepada bacaan terakhir setiap minggu. Panel pembalikan memuatkan sejarah dari 2018 dan melaporkan dari 2019 seterusnya, jadi setiap hari yang diberi skor mempunyai tetingkap bergerak penuh di belakangnya, dan ia berhenti pada pertengahan November 2025 supaya setiap hari mempunyai dua puluh sesi di hadapannya di dalam sampel.

Tiada satu pun daripada panel ini merupakan strategi. Ia tidak membawa kos dagangan, tiada bid-ask spread, tiada yuran pinjaman pada kaki pendek (short leg), tiada dividen dan tiada pembiayaan. Hanya harga tutup, yang bermaksud penyertaan yang ditandakan pada harga tutup adalah penyertaan yang tidak mungkin dapat diisi oleh sesiapa pun di situ.

Soalan Lazim

Apakah perbezaan antara korelasi dan kointegrasi?

Korelasi mengukur sama ada dua saham bergerak pada hari yang sama dan dalam arah yang sama, pada skala negatif satu hingga positif satu. Kointegrasi mengukur sama ada jarak antara harga kedua-duanya kekal dalam julat yang stabil. Sesebuah pasangan boleh mendapat skor tinggi pada ukuran pertama tetapi gagal pada ukuran kedua, yang merupakan sebab biasa mengapa saringan korelasi menghasilkan pasangan yang kemudiannya bergerak menjauhi antara satu sama lain.

Bagaimanakah anda mengira hedge ratio dalam dagangan pasangan?

Padankan garis lurus harga satu saham dengan harga saham yang satu lagi dan ambil kecerunannya. Kecerunan itu ialah bilangan unit saham pertama yang mengimbangi satu unit saham kedua, dan ia merupakan kuantiti yang berubah-ubah, jadi kebanyakan pelaksanaan menetapkan semula nilai tersebut pada tetingkap susulan (trailing window) dan bukannya sekali sahaja bagi keseluruhan sampel.

Apakah z score yang digunakan oleh pedagang pasangan untuk masuk dan keluar pasaran?

Contoh tutorial biasanya masuk sekitar satu per lima hingga dua sisihan piawai daripada min susulan dan keluar berhampiran sifar perpuluhan lima. Angka-angka tersebut adalah konvensyen yang diwarisi daripada penulisan terdahulu dan bukannya optimum yang diukur, dan mengubahnya akan mengubah bilangan dagangan serta tempoh pegangan bagi setiap dagangan.

Bolehkah dua saham menjadi kointegrasi dengan korelasi yang rendah?

Ya. Korelasi dikira berdasarkan perubahan harian manakala kointegrasi dikira berdasarkan tahap jurang, jadi dua nama yang pergerakan hariannya jarang selari masih boleh mengekalkan jarak jangka panjang yang stabil. Perkara sebaliknya juga berlaku: korelasi harian yang tinggi di samping jurang yang melebar dari tahun ke tahun.

Mengapa pasangan yang berkointegrasi berhenti berfungsi?

Hubungan yang mengekalkan jurang tersebut boleh berubah: penggabungan, pecahan syarikat (spin-off), perubahan dalam campuran perniagaan sesebuah syarikat, atau perubahan indeks yang mengubah pihak yang memiliki saham tersebut. Statistik pada hari-hari sebelum berlakunya perpecahan kelihatan sama seperti hari-hari sebelum berlakunya pembalikan biasa, iaitu bahagian yang perlu diselaraskan saiznya dan bukannya diramal.


Setiap panel di sini disertakan dengan SQL yang tepat di bawahnya, jadi tetingkap, tempoh padanan, dan had baldi semuanya boleh dilihat. Untuk menjalankan spread dan z score yang sama pada pasangan yang anda ikuti, ajukan soalan dalam bahasa Inggeris yang mudah pada terminal Strasmore.

#pairs trading#cointegration#mean reversion#backtesting#statistics