آموزش معاملات جفتارز و همانباشتگی
معاملات جفتارز بر پایه همانباشتگی استوار است و با همبستگی تفاوت دارد. در این راهنما نحوه محاسبه دستی نسبت پوشش ریسک، اسپرد و نمره زد بر اساس قیمتهای پایانی را میآموزید.
معاملات جفتارز و همانباشتگی
معاملات جفتارز (Pairs trading) و همانباشتگی (cointegration) با یکدیگر پیوند دارند: این استراتژی بر پایه شکافی میان قیمت دو سهم استوار است که همواره به سطحی باثبات بازمیگردد، و همانباشتگی ویژگی آماری است که وجود چنین شکافی را اثبات میکند. همبستگی (Correlation) معیاری متفاوت است. دو سهم میتوانند همبستگی بالایی داشته باشند اما برای همیشه از یکدیگر فاصله بگیرند، و دو سهم که حرکات روزانه آنها بهندرت همراستا است، ممکن است سالها شکافی پایدار را حفظ کنند. این صفحه به محاسبه دستی نسبت پوشش ریسک (hedge ratio)، اسپرد (spread) و نمره زد (z-score) میپردازد، هر سه مورد را بر اساس قیمتهای پایانی واقعی اندازهگیری میکند و سپس به همان اندازه به بررسی دلایل شکست این ساختار اختصاص میدهد.
همانباشتگی (Cointegration) در معاملات جفتارز چیست؟
همبستگی (Correlation) نشاندهنده میزان نزدیکی تغییرات درصدی روزانه دو سهم است. این شاخص بین 1- تا 1+ متغیر است، که در آن 1+ به معنای صعود و سقوط همزمان در تمامی جلسات معاملاتی دوره نمونه است. این شاخص هیچ اطلاعاتی درباره فاصله میان قیمتهای دو سهم ارائه نمیدهد.
همانباشتگی، بیانی درباره همان فاصله است. سهم B را در نظر بگیرید، مضرب ثابتی از سهم A را از آن کسر کنید و به باقیمانده نگاه کنید. اگر آن سری باقیمانده، یعنی اسپرد (spread)، بهجای واگرایی، در یک محدوده مشخص باقی بماند، آن دو نماد همانباشته هستند. قیمتها بهتنهایی آزادند تا به هر سمتی حرکت کنند، اما ترکیب آنها چنین آزادیای ندارد.
تصویری که کتابهای درسی استفاده میکنند، سگی با قلاده است. هم صاحب سگ و هم سگ مسیرهای غیرقابلپیشبینی را در خیابان طی میکنند، اما قلاده باعث میشود فاصله میان آنها محدود بماند. همبستگی میپرسد که آیا این دو در یک لحظه گام برمیدارند یا خیر؛ همانباشتگی میپرسد که آیا قلاده همچنان آنها را به هم متصل نگه میدارد یا نه.
پنل زیر ایده نخست را برای پنج جفتارز آشنا در طول سالهای 2024 و 2025 اندازهگیری میکند. ستون 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 است. هیچکدام از این دو ستون به پرسشی که یک معاملهگر جفتارز مطرح میکند، پاسخ نمیدهند. هر دو ستون همحرکتی را اندازهگیری میکنند، در حالی که این معامله نیازمند معیاری برای سنجش فاصله است.
چگونه نسبت پوشش ریسک (Hedge Ratio) و اسپرد را محاسبه کنیم؟
پنج گام، به ترتیب، روی دو فهرست از قیمتهای پایانی. پایتون ساده تمام این مراحل را تنها با 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))]. در یک جفت همانباشته (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-score برابر با 2، اسپرد را دو انحراف معیار بالاتر از میانگین اخیر خود قرار میدهد.
دو فهرست قیمت ثابت برای مشاهده اجرای این کد کافی است و یک win برابر با 5، مثال نمونه را خوانا نگه میدارد. در کارهای جدی، از مقداری نزدیک به 63 جلسه معاملاتی، یعنی حدود یک فصل (Q1–Q4)، استفاده میشود. آن آستانهها، یعنی 1.5 برای ورود و 0.5 برای خروج، قراردادهایی هستند که از یک آموزش به آموزش دیگر منتقل شدهاند. آنها یافتههای علمی نیستند و هیچکدام از پنلهای زیر آنها را انتخاب نکردهاند.
نمره Z در معاملات جفتارزی روی قیمتهای واقعی چگونه به نظر میرسد؟
در اینجا همان محاسبات را روی دو نام تجاری شناختهشده نوشیدنی، یعنی KO و PEP انجام میدهیم. نسبت پوشش ریسک (hedge ratio) تنها از قیمتهای پایانی سال 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 برابر با -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 بودند و همان اسپرد بیست جلسه بعد، در مجموع 138 جلسه، بهطور میانگین به -0.84 رسید. در سوی دیگر، بازه z above 2 از 2.64 شروع شد و بیست جلسه بعد به 0.92 رسید. منحنیای که از هر دو سو به سمت صفر کشیده میشود، همان شکلی است که بازگشت به میانگین ایجاد میکند.
این دادهها را با در نظر گرفتن ستون تعداد (count) مطالعه کنید. بازههای بیرونی کمترین تعداد جلسات را در خود جای دادهاند و جلسات درون هر بازه همپوشانی شدیدی دارند، بنابراین بخش عمدهای از سطرها توسط تعداد انگشتشماری از دورههای طولانی تأمین میشود. یک میانگین، وعدهای درباره هیچ ورودی واحدی نیست.
چرا معاملات جفتارز (Pairs Trading) کارایی خود را از دست میدهند؟
نسبت پوشش ریسک (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 yearشیب PEP نسبت به KO که در 2.338 در طول 2019 و در -0.543 در طول 2025 اندازهگیری شده است، به همراه جفتارز بخش دوم برای مقایسه ارائه شده است. بکتستی که یک شیب واحد را برای کل تاریخچه برازش داده و از روز نخست معامله میکند، به هر معامله اولیه عددی را نسبت میدهد که هیچکس در آن زمان قادر به دستیابی به آن نبوده است. راهکار این مسئله ساده و در عین حال مؤثر است: بازنگری در یک پنجره زمانی متحرک (trailing window) و امتیازدهی به هر روز با استفاده از پارامترهای در دسترس در همان روز. یک بکتست قابلبازتولید باعث میشود این انضباط توسط دیگران قابلبررسی باشد.
اقدامات شرکتی یک سمت معامله را یکشبه بازنویسی میکنند. یک تقسیم سهام 4 به 1، یک سهم را به چهار سهم تبدیل کرده و قیمت اعلامی را به یکچهارم کاهش میدهد؛ در نتیجه، اسپردی که در آن تاریخ بر اساس قیمتهای تعدیلنشده محاسبه شده باشد، به سطحی جهش میکند که هرگز در بازار معامله نشده است. ادغامها، تفکیک شرکتها (spin-offs) و تغییرات شاخص، نسخههای آرامتری از همین پدیده هستند. کار را با تاریخچه قیمت تعدیلشده برای تقسیم سهام آغاز کنید و توجه داشته باشید که یک نماد ممکن است به شرکتی کاملاً متفاوت اختصاص یابد، که این همان دلیل خرابی مجموعهدادهها توسط نمادهای معاملاتی (Ticker) است.
شکست در رابطه و فرصت معاملاتی در لحظه وقوع، یکسان به نظر میرسند. عریضترین Z-score که یک جفتارز تاکنون ثبت کرده، یا بهترین نقطه ورود ارائهشده توسط آن است و یا هفته نخستِ رابطهای که به پایان رسیده است. هر دو مورد در آن روز، مانند یک اسپرد کشیدهشده (stretched spread) به نظر میرسند. تعیین حجم موقعیت (Sizing) باری را به دوش میکشد که آمار از عهده آن برنمیآید: تعیین حجم موقعیت بر اساس معیار کلی و تعیین حجم موقعیت بر اساس هدفگذاری نوسان دو چارچوب برای تعیین میزان مجاز حرکت یک اسپرد در حساب هستند و حداکثر افت سرمایه (Maximum Drawdown) اندازهگیری میکند که یک دوره طولانی در سمت اشتباه میانگین، چه تأثیری بر منحنی حقوق صاحبان سهام (Equity Curve) دارد.
یک Z-score متحرک، آزمون همانباشتگی (Cointegration) نیست. آزمونهای رسمی برای این کار وجود دارند. روش انگل-گرنجر (Engle-Granger) رگرسیون را اجرا کرده و سپس اسپرد باقیمانده را برای ایستا بودن (stationarity) میآزماید، و آزمون یوهانسن (Johansen) این ایده را فراتر از دو نام گسترش میدهد. Z-score ویژگیهایی را که آن آزمونها بررسی میکنند مفروض میگیرد و با خوشحالی برای اسپردی که اصلاً میانگین پایداری ندارد، عدد بزرگی را ثبت میکند، زیرا یک سری زمانی دارای روند، همیشه فاصله زیادی از میانگین متحرک خود دارد.
یادداشتهای داده و آنچه این ارقام نادیده میگیرند
پنل همبستگی از قیمتهای پایانی روزانه از 2024-01-01 تا 2025-12-31 استفاده کرده و بازدهیها را از قیمتهای پایانی متوالی محاسبه میکند، که در آن اولین جلسه معاملاتی هر نماد حذف شده است. نمودار Z-score، نسبت پوشش ریسک را تنها بر اساس قیمتهای پایانی 2023 برازش داده و سپس سالهای 2024 و 2025 را با میانگین متحرک 63 جلسهای و انحراف معیار نمونه، که تا آخرین خوانش هر هفته نمونهبرداری شده، امتیازدهی میکند. پنل بازگشت به میانگین، تاریخچه را از سال 2018 بارگذاری کرده و گزارشها را از سال 2019 به بعد ارائه میدهد، بنابراین هر روز امتیازدهیشده دارای یک پنجره زمانی کامل در پشت سر خود است و در اواسط نوامبر 2025 متوقف میشود تا هر روز بیست جلسه معاملاتی پیش رو در داخل نمونه داشته باشد.
هیچکدام از این پنلها یک استراتژی نیستند. آنها فاقد هزینههای معاملاتی، اسپرد خریدوفروش، کارمزد استقراض برای سمت فروش (short leg)، سود سهام و هزینههای تأمین مالی هستند. تنها قیمتهای پایانی لحاظ شدهاند، به این معنی که نقطه ورود مشخصشده در قیمت پایانی، نقطهای است که هیچکس نمیتوانسته در آن قیمت معامله را تکمیل کند.
پرسشهای متداول
تفاوت بین همبستگی (Correlation) و همانباشتگی (Cointegration) چیست؟
همبستگی، همجهت بودن و همزمان بودن حرکت دو سهم را در مقیاسی از منفی یک تا مثبت یک اندازهگیری میکند. همانباشتگی بررسی میکند که آیا فاصله بین قیمتهای دو سهم در یک محدوده پایدار باقی میماند یا خیر. یک جفتسهم ممکن است در شاخص اول امتیاز بالایی بگیرد اما در دومی شکست بخورد؛ این همان دلیل اصلی است که فیلترهای مبتنی بر همبستگی، جفتهایی را شناسایی میکنند که در نهایت از یکدیگر فاصله میگیرند.
نسبت پوشش ریسک (Hedge Ratio) در معاملات جفتسهم چگونه محاسبه میشود؟
یک خط مستقیم برای قیمت یک سهم نسبت به دیگری برازش دهید و شیب آن را محاسبه کنید. این شیب، تعداد واحدهای سهم اول است که یک واحد از سهم دوم را پوشش میدهد. از آنجا که این مقدار متغیر است، در اکثر پیادهسازیها، بهجای محاسبه یکباره برای کل نمونه، آن را در یک پنجره زمانی متحرک بازبینی میکنند.
معاملهگران جفتسهم از چه Z-score برای ورود و خروج استفاده میکنند؟
در مثالهای آموزشی، معمولاً ورود در حدود 1.5 تا 2 انحراف معیار از میانگین متحرک و خروج در نزدیکی 0.5 انجام میشود. این اعداد قراردادهایی هستند که از نوشتههای قدیمی به ارث رسیدهاند و نه مقادیر بهینه اندازهگیریشده؛ تغییر این اعداد هم تعداد معاملات و هم مدت زمان نگهداری هر موقعیت را تغییر میدهد.
آیا دو سهم میتوانند همانباشته باشند اما همبستگی پایینی داشته باشند؟
بله. همبستگی بر اساس تغییرات روزانه محاسبه میشود و همانباشتگی بر اساس سطح شکاف قیمتی؛ بنابراین دو نماد که حرکات روزانه آنها بهندرت همراستا است، همچنان میتوانند فاصله بلندمدت پایداری داشته باشند. عکس این موضوع نیز رخ میدهد: همبستگی روزانه بالا در کنار شکافی که سالبهسال عمیقتر میشود.
چرا یک جفتسهم همانباشته از کار میافتد؟
پیوندی که شکاف قیمتی را حفظ میکند ممکن است تغییر کند: ادغام، تفکیک شرکت (Spin-off)، تغییر در ترکیب کسبوکار یکی از شرکتها، یا تغییر در شاخص که مالکیت سهم را دگرگون میکند. آمارهای روزهای پیش از شکست، مشابه روزهای پیش از بازگشت به میانگین عادی است؛ این بخشی از ریسک است که باید بهجای پیشبینی، برای آن مدیریت سرمایه (Sizing) در نظر گرفت.
هر پنل در اینجا به همراه SQL دقیق زیرساختی آن ارائه شده است، بنابراین پنجرههای زمانی، دوره برازش و مرزهای دستهبندی همگی قابل مشاهده هستند. برای اجرای همان اسپرد و Z-score روی جفتسهم مورد نظر خود، پرسش را به زبان ساده در ترمینال Strasmore مطرح کنید.