متعصب نظر آگے بیک ٹیسٹ میں دھوکہ
متعصب نظر آگے مستقبل کے ڈیٹا کو بیک ٹیسٹ میں لیک کرتا ہے۔ اسی بار کے فیصلے، بقا کا تعصب، اور نظر ثانی شدہ اعداد و شمار نتائج کو بڑھا دیتے ہیں۔ اس کی جانچ کیسے کریں۔
متعصب نظر آگے (Look-ahead bias) ایک بیک ٹیسٹ میں اس معلومات کا استعمال ہے جو کوئی بھی اس وقت نہیں رکھ سکتا تھا جب نقلی ٹریڈ لگائی گئی تھی۔ ایکوئٹی کریو (equity curve) اوپر جاتی ہے، اعدادوشمار بہترین نظر آتے ہیں، اور ان میں سے کچھ بھی لائیو آرڈر کے ساتھ رابطے میں نہیں بچتا۔ یہ صفحہ اس تعصب کی تعریف کرتا ہے، تین میکانزم بیان کرتا ہے جو اسے پیدا کرتے ہیں، اور حقیقی مارکیٹ ڈیٹا پر ہر ایک کی پیمائش کرتا ہے۔
متعصب نظر آگے کیا ہے
ایک بیک ٹیسٹ ایک فیصلے کے بارے میں ایک دعویٰ ہے: اس ٹائم اسٹیمپ پر، اس معلومات کے ساتھ، قاعدہ یہ کرتا۔ دعویٰ صرف اس وقت درست ہوتا ہے جب قاعدہ کے ذریعے پڑھا جانے والا ہر ان پٹ اپنی حتمی شکل میں، اس ٹائم اسٹیمپ سے پہلے موجود ہو۔ متعصب نظر آگے اس شرط کی کوئی بھی خلاف ورزی ہے، اور یہ خاموش ہے۔ اسپریڈ شیٹ یا اسکرپٹ میں کوئی چیز شکایت نہیں کرتی جب ایک قطار اس فیصلے کو کھلانے والی تاریخ سے بعد میں اسٹیمپ کردہ قیمت واپس کرتی ہے۔
تین خلاف ورزیاں عملی طور پر سامنے آنے والی زیادہ تر چیزوں کا احاطہ کرتی ہیں۔ ایک فیصلہ جو ایک پرائس بار (price bar) کو پڑھتا ہے جس کے اندر وہ ٹریڈ بھی کرتا ہے۔ ایک یونیورس (universe) جو ان ناموں سے جمع کیا گیا ہے جو آج بھی درج ہیں۔ ایک ڈیٹا فیلڈ (data field) جو اس تاریخ کے بعد نظر ثانی شدہ تھا جسے وہ رکھتا ہے۔
میکانزم ایک: ایک بار پر فیصلہ کرنا جس پر آپ ٹریڈ بھی کرتے ہیں
ایک ایسے قاعدے سے شروع کریں جو بے ضرر لگتا ہے۔ طاقت پر خریدیں، یعنی ان سیشنز پر جہاں فنڈ اپنے کھلنے سے اوپر بند ہوتا ہے۔ لاپرواہی سے کوڈ کیا گیا، ٹیسٹ اس سیشن کے اوپن پر داخل ہوتا ہے اور اسی سیشن کے کلوز پر باہر نکلتا ہے، جبکہ جس شرط پر یہ اسکرین کرتا ہے وہ اسی بار کی کلوزنگ پرائس ہے۔ کوئی بھی اوپننگ بیل پر کلوزنگ پرائس نہیں جانتا۔
نیچے دیا گیا پینل دونوں ورژنز کو SPY، S&P 500 ٹریکر، پر دس کیلنڈر سالوں میں چلاتا ہے۔ پہلا کالم ناممکن والا ہے۔ دوسرا ایک ہی شرط کو ایک سیشن پیچھے کرتا ہے، جو کہ ایک فنڈڈ اکاؤنٹ اس پر عمل کرنے کا ابتدائی ترین وقت ہے۔
ہر عدد کے پیچھے موجود درست SQL
WITH bars AS (
SELECT date,
toFloat64(open) AS o,
toFloat64(close) AS c,
toFloat64(close) > toFloat64(open) AS up_day
FROM global_markets.stocks_daily_aggs
WHERE ticker = 'SPY'
AND date >= toDate('2015-12-01')
AND date <= toDate('2025-12-31')
),
lagged AS (
SELECT date, o, c, up_day,
any(up_day) OVER (ORDER BY date ROWS BETWEEN 1 PRECEDING AND 1 PRECEDING) AS prior_up
FROM bars
)
SELECT toYear(date) AS year,
countIf(up_day) AS signal_days,
round(100 * avgIf(c / o - 1, up_day), 3) AS same_bar_avg_pct,
round(100 * avgIf(c / o - 1, prior_up), 3) AS lagged_avg_pct,
round(100 * (avgIf(c / o - 1, up_day) - avgIf(c / o - 1, prior_up)), 3) AS gap_pp
FROM lagged
WHERE date >= toDate('2016-01-01')
GROUP BY year
ORDER BY yearفرق معمولی نہیں ہے۔ 2016 میں ایک ہی بار والے ورژن نے اوسطاً 0.447% فی کوالیفائنگ سیشن حاصل کیا جبکہ لیگڈ ورژن نے اوسطاً -0.008% حاصل کیا، جو کہ 0.455 فیصد پوائنٹس فی دن کا پھیلاؤ ہے۔ 2025 میں دونوں نے 0.636% اور -0.03% پڑھے۔ ایک سال میں تقریباً 140 کوالیفائنگ سیشنز کے ساتھ، فی سیشن آدھے فیصد پوائنٹ کا پھیلاؤ ایک ایسی ایکوئٹی کریو میں مرکب ہو جاتا ہے جو کسی بھی لائیو اکاؤنٹ نے کبھی پرنٹ نہیں کیا۔
پورا فائدہ تعریفی ہے۔ ان سیشنز کو منتخب کرنا جو اپنے اوپن سے اوپر بند ہوئے، پھر انہی سیشنز پر اوپن ٹو کلوز کی پیمائش کرنا، ایک ایسی مقدار کی پیمائش کرتا ہے جس کے مثبت ہونے کی ضمانت ہے۔ قاعدہ نے اپنا فلٹر خود دریافت کیا۔
اس کی مختلف شکلیں روزانہ ڈیٹا میں ہر وقت چھپی رہتی ہیں: ایک موونگ ایوریج (moving average) جس میں آج کا کلوز شامل ہے اور آج کی ٹریڈنگ کے لیے استعمال ہوتا ہے، ایک سگنل جو پہلے سے ایڈجسٹ شدہ قیمتوں پر شمار کیا گیا ہے ایک اسپلٹ (split) کے لیے جو ابھی ہوا نہیں تھا، ایک انٹراڈے سٹاپ (intraday stop) جو سیشن کی اونچائی پر رکھا گیا ہے جو ابھی پرنٹ نہیں ہوئی تھی۔ عام شکل ایک فیصلے کا ٹائم اسٹیمپ ہے جو اپنے ہی ان پٹس میں سے کسی ایک سے پہلے بیٹھا ہے۔
میکانزم دو: ایک یونیورس جو آج کے بچ جانے والوں سے تیار کیا گیا ہے
دوسرا میکانزم کبھی قاعدے کو نہیں چھوتا۔ یہ ان ناموں کی فہرست میں بیٹھتا ہے جنہیں قاعدہ دیکھ سکتا ہے۔
موجودہ ڈیٹا پرووائیڈر سے ایک ٹکر لسٹ (ticker list) کھینچیں، اسے دس سال پیچھے چلائیں، اور نمونہ خاموشی سے ہر اس کمپنی کو خارج کر دیتا ہے جو راستے میں دیوالیہ ہو گئی، حاصل کر لی گئی، یا ڈی لسٹ (delisted) ہو گئی۔ قاعدے کو کبھی ہارنے والوں کی پیشکش نہیں کی گئی۔ پینل اس اخراج کے سائز کی پیمائش کرتا ہے: ہر وہ نام جو امریکہ میں درج تھا اور جس نے کسی دیے گئے کیلنڈر سال میں $1 سے اوپر کم از کم 200 سیشنز پر ٹریڈ کیا، اس گروہ کا وہ حصہ جو جولائی 2026 میں اب بھی قیمتیں پرنٹ کر رہا ہے، اور پورے گروہ کی میڈین کیلنڈر-سال واپسی (median calendar-year return) کے ساتھ صرف بچ جانے والوں کی میڈین۔
ہر عدد کے پیچھے موجود درست SQL
WITH recent AS (
SELECT DISTINCT ticker
FROM global_markets.stocks_daily_aggs
WHERE date >= toDate('2026-06-15')
AND date <= toDate('2026-07-28')
),
per_name AS (
SELECT toYear(date) AS year,
ticker,
argMin(toFloat64(close), date) AS first_close,
argMax(toFloat64(close), date) AS last_close,
count() AS sessions
FROM global_markets.stocks_daily_aggs
WHERE date >= toDate('2015-01-01')
AND date <= toDate('2024-12-31')
AND close > 1
GROUP BY year, ticker
HAVING sessions >= 200
)
SELECT year,
uniqExact(ticker) AS names_trading,
round(100 * uniqExactIf(ticker, ticker IN (SELECT ticker FROM recent)) / uniqExact(ticker), 1) AS still_listed_pct,
round(100 * quantileDeterministic(0.5)(last_close / first_close - 1, cityHash64(ticker)), 2) AS median_return_all_pct,
round(100 * quantileDeterministicIf(0.5)(last_close / first_close - 1, cityHash64(ticker), ticker IN (SELECT ticker FROM recent)), 2) AS median_return_survivors_pct,
round(100 * (quantileDeterministicIf(0.5)(last_close / first_close - 1, cityHash64(ticker), ticker IN (SELECT ticker FROM recent))
- quantileDeterministic(0.5)(last_close / first_close - 1, cityHash64(ticker))), 2) AS survivor_gap_pp
FROM per_name
GROUP BY year
ORDER BY year2015 میں 7063 ناموں میں سے جو بار کو صاف کر گئے، 52.5% جولائی 2026 میں اب بھی ٹریڈ کر رہے تھے۔ 2024 گروہ کے لیے یہ اعداد و شمار 87.5% ہے، زیادہ تر گزرے ہوئے وقت کا معاملہ: 2024 کے نام کو غائب ہونے کے لیے دو سال ملے ہیں اور 2015 کے نام کو گیارہ سال۔
واپسی کے کالم خود تعصب کو لے کر چلتے ہیں۔ 2017 میں میڈین نام نے 7.51% واپس کیا جبکہ میڈین بچ جانے والے نے 11.32% واپس کیا، جو کہ مفت میں دیے گئے 3.81 فیصد پوائنٹس کا فرق ہے۔ چارٹ کیے گئے 10 سالوں میں سے ہر ایک میں فرق مثبت ہے۔ بچ جانے والوں پر آزمائے گئے ایک حکمت عملی کو ایک بھی فیصلہ کرنے سے پہلے یہ وراثت میں ملتا ہے، اور جو قواعد کمزوری کے لیے اسکرین کرتے ہیں انہیں میڈین سے زیادہ وراثت میں ملتا ہے، کیونکہ غائب ہونے والے نام غیر متناسب طور پر اس بالٹی میں بیٹھتے ہیں۔
اصلاح ایک پوائنٹ-ان-ٹائم یونیورس (point-in-time universe) ہے: ہر ری بیلنس (rebalance) تاریخ پر ناموں کی فہرست جیسی وہ تھی، ڈی لسٹنگز (delistings) سمیت، جس میں ڈی لسٹ شدہ پوزیشن کو ریکارڈ سے گرانے کے بجائے اس کے آخری پرنٹ پر بند کیا گیا ہے۔
میکانزم تین: ڈیٹا جس کی اس کی تاریخ کے بعد نظر ثانی کی گئی
قیمتیں ایک بار اسٹیمپ ہوتی ہیں۔ بنیادی اعداد و شمار (fundamentals) نہیں ہوتے۔ ایک سہ ماہی اعداد و شمار سہ ماہی کی اختتامی تاریخ رکھتا ہے، بعد میں فائلنگ کے ذریعے اس میں ترمیم کی جاتی ہے، اور ایک ڈیٹا بیس جو صرف موجودہ ورژن اسٹور کرتا ہے خوشی سے ترمیم شدہ نمبر کو اصل تاریخ کے خلاف پیش کرے گا۔ اس نمبر پر اسکرین کرنے والا قاعدہ ایک اصلاح پڑھ رہا ہے جسے آنے میں مہینے لگے۔
یہی نمونہ انڈیکس ممبرشپ لسٹوں (index membership lists) میں چلتا ہے جو موجودہ اجزاء پر دوبارہ بنائی گئی ہیں، تجزیہ کار کی تخمینوں کی تاریخوں (analyst estimate histories) کو حتمی اتفاق رائے (final consensus) سے اوور رائٹ (overwrite) کیا گیا ہے، اور کارپوریٹ ایکشن ایڈجسٹمنٹس (corporate action adjustments) کو پوری قیمت سیریز پر پیچھے کی طرف لاگو کیا گیا ہے۔ ہر معاملے میں ذخیرہ شدہ ریکارڈ ایک موجودہ دور کا سنیپ شاٹ (present-tense snapshot) ہے جو ماضی کے دور کی تاریخ (past-tense date) پہنے ہوئے ہے۔
دو طریقے اس پر قابو رکھتے ہیں۔ ایک ایسا ذریعہ استعمال کریں جو ونٹیجز (vintages) رکھتا ہو، یعنی ہر تاریخ پر جیسی قدر معلوم تھی نہ کہ جیسی قدر اب معلوم ہے۔ جہاں ونٹیجز دستیاب نہ ہوں، وہاں رپورٹنگ لیگ (reporting lag) کا اطلاق کریں جو حقیقی لیگ کو ڈھانپنے کے لیے کافی فراخ ہو، اور اس لیگ کی لمبائی کو ایک پیرامیٹر (parameter) کے طور پر علاج کریں جسے جانچنا ضروری ہے نہ کہ ایک تفصیل جس کا اندازہ لگانا ضروری ہے۔
جب مستقبل اندر جھانکتا ہے تو کریو کیسا لگتا ہے
متعصب نظر آگے کی ایک دستخط ہے: کارکردگی جو اس سے کہیں اوپر بیٹھتی ہے جو بنیادی مارکیٹ نے پیش کیا۔ ایک مفید حوالہ نقطہ ماضی کی چھت (hindsight ceiling) ہے، وہ نمو جو ایک کامل ایک دن آگے کی پیشن گوئی (perfect one-day-ahead forecast) نے ایک ہی انسٹرومنٹ پر پیدا کی ہوگی۔
ہر عدد کے پیچھے موجود درست SQL
WITH bars AS (
SELECT date,
toFloat64(close) AS c,
any(toFloat64(close)) OVER (ORDER BY date ROWS BETWEEN 1 PRECEDING AND 1 PRECEDING) AS prev_c
FROM global_markets.stocks_daily_aggs
WHERE ticker = 'SPY'
AND date >= toDate('2015-12-01')
AND date <= toDate('2025-12-31')
),
rets AS (
SELECT toYear(date) AS year,
c / prev_c - 1 AS r
FROM bars
WHERE date >= toDate('2016-01-01')
AND prev_c > 0
)
SELECT year,
count() AS sessions,
round(100 * (exp(sum(log(1 + r))) - 1), 1) AS buy_and_hold_pct,
round(100 * (exp(sumIf(log(1 + r), r < 0.02)) - 1), 1) AS without_big_up_days_pct,
round(exp(sum(log(1 + abs(r)))), 1) AS hindsight_ceiling_multiple
FROM rets
GROUP BY year
ORDER BY yearچھت بہت بڑی ہے۔ 2020 میں، SPY پر کامل ایک دن کی دور اندیشی نے 253 سیشنز پر سرمائے کو 27.7 گنا بڑھایا، جبکہ صرف فنڈ کو رکھنے پر 16.2% تھا۔ دس میں سے سب سے پرسکون سال، 2017 میں، اسی کامل پیشن گوئی نے سرمائے کا 2.2 گنا واپس کیا۔
درمیانی کالم دکھاتا ہے کہ یہ چھت کتنی مرتکز ہے۔ ان سیشنز کو ہٹا دیں جنہوں نے 2% سے زیادہ حاصل کیا، اور 2020 16.2% سے -44.9% میں بدل جاتا ہے۔ ایک رساو (leak) جو سال میں ان سیشنز میں سے صرف مٹھی بھر کے قابل ہے، بیک ٹیسٹ کو بہت دور لے جاتا ہے۔ ایک کریو جس میں کم ڈرا ڈاؤن (drawdowns)، ایک اعلی ہٹ ریٹ (hit rate)، اور اس کے بہترین دن مارکیٹ کے سب سے پرتشدد سیشنز پر جمع ہیں، اس نے آڈٹ (audit) حاصل کیا ہے۔
کیلیبریشن (Calibration) کسی ایک حد سے زیادہ اہمیت رکھتی ہے۔ ایک قاعدہ جو ایک دہائی میں 40% سالانہ ہموار نمو کا دعویٰ کرتا ہے، ماضی کی چھت کا ایک بڑا حصہ حاصل کرنے کا دعویٰ کر رہا ہے، اور ایماندارانہ سوال یہ ہے کہ کس ان پٹ نے اسے بتایا کہ کیا ہونے والا ہے۔
بیک ٹیسٹ میں متعصب نظر آگے کی جانچ کیسے کریں
- ہر چیز کو ایک بار پیچھے کریں۔ ہر سگنل کو ایک مکمل مدت بعد میں منتقل کریں اور دوبارہ چلائیں۔ حقیقی برتری (edges) تھوڑی کم ہوتی ہے۔ رساو (Leaks) گر جاتے ہیں، اکثر کچھ نہیں رہتا۔
- مستقبل میں خلل ڈالیں۔ ہر فیصلے کے ٹائم اسٹیمپ کے بعد کا ڈیٹا لیں، اسے شور (noise) یا دوبارہ پھینٹنے (reshuffle) سے بدلیں، اور فیصلے کی منطق کو دوبارہ چلائیں۔ ہر فیصلہ ایک جیسا نکلنا چاہیے۔ کوئی بھی فیصلہ جو حرکت کرتا ہے اس نے کچھ ایسا پڑھا ہے جو وہ نہیں جان سکتا تھا۔
- ٹائم اسٹیمپس کو ڈیٹا کے طور پر علاج کریں۔ ہر ان پٹ کے لیے، وہ لمحہ ذخیرہ کریں جب کوئی قدر دستیاب ہوئی اس کے ساتھ جس لمحے کو وہ بیان کرتی ہے۔ ایک جوائن (join) جو ان دو کالموں کا کبھی موازنہ نہیں کرتا، قاعدہ نافذ نہیں کر سکتا۔
- یونیورس کو تاریخ کے مطابق دوبارہ بنائیں۔ ڈی لسٹ شدہ اور حاصل شدہ ناموں کو شامل کریں، انہیں ان کے آخری پرنٹ پر بند کریں، اور بقا کے تعاون (survivorship contribution) کا سائز کرنے کے لیے ایک ہی قاعدہ دونوں یونیورسز پر چلائیں۔
- چھت کے خلاف پیمائش کریں۔ حکمت عملی کی واپسی کو اسی ونڈو کے لیے خرید اور ہولڈ (buy and hold) کے اعداد و شمار اور کامل دور اندیشی (perfect-foresight) کے اعداد و شمار کے ساتھ رکھیں۔ چھت سے فاصلہ وہ سیاق و سباق ہے جو اکیلے شارپ ریشو (Sharpe ratio) نہیں دیتا۔
پوزیشن سائزنگ (Position sizing) ان سب کے نیچے کی طرف بیٹھتی ہے۔ ایک پھولا ہوا جیت کی شرح ایک پھولے ہوئے شرط کے سائز کو کھلاتی ہے، جو وہ جگہ ہے جہاں کیلی معیار پوزیشن سائزنگ (Kelly criterion position sizing) اکاؤنٹنگ کی غلطی کو ڈرا ڈاؤن میں بدل دیتی ہے۔ اصلی سرمائے کے منتقل ہونے سے پہلے وہی نظم و ضبط لاگو ہوتا ہے: اصلی رقم سے پہلے پیپر ٹریڈنگ (paper trading before real money) آرڈر میکانکس کی جانچ کرتی ہے، اور خودکار اسٹیکس (automated stacks) مشینی رفتار پر ایک جیسا خطرہ رکھتے ہیں، جس کا احاطہ ملٹی ایجنٹ AI ٹریڈنگ سسٹمز (multi agent AI trading systems) میں کیا گیا ہے۔ وہ اثرات جو محتاط پوائنٹ-ان-ٹائم ٹیسٹنگ سے بچ جاتے ہیں، جیسے کم اتار چڑھاؤ کی بے ضابطگی (low volatility anomaly)، بالکل اسی وجہ سے دلچسپ ہیں۔
عمومی سوالات
بیک ٹیسٹنگ میں متعصب نظر آگے کیا ہے؟
یہ نقلی ٹریڈ میں اس ڈیٹا کا استعمال ہے جو اس وقت دستیاب نہیں تھا جب ٹریڈ لگائی جاتی۔ عام شکلیں ایک پرائس بار پر فیصلہ کرنا ہیں جس پر ٹریڈ بھی عمل کرتا ہے، ان کمپنیوں کے یونیورس کی اسکریننگ کرنا جو آج بھی درج ہیں، اور ایک مالیاتی اعداد و شمار کو پڑھنا جس کی اس سے منسلک تاریخ کے بعد نظر ثانی کی گئی۔
آپ متعصب نظر آگے کا پتہ کیسے لگا سکتے ہیں؟
ہر سگنل کو ایک مکمل مدت پیچھے کریں اور دوبارہ چلائیں: ایک رساو عام طور پر گر جاتا ہے جبکہ ایک حقیقی برتری آہستہ سے کم ہوتی ہے۔ ایک مضبوط ٹیسٹ ہر فیصلے کے ٹائم اسٹیمپ کے بعد کے تمام ڈیٹا کو شور سے بدل دیتا ہے اور تصدیق کرتا ہے کہ ہر فیصلہ تبدیل شدہ نکلتا ہے۔
کیا بقا کا تعصب (survivorship bias) متعصب نظر آگے جیسا ہی ہے؟
وہ الگ ہیں لیکن وہ ایک ساتھ سفر کرتے ہیں۔ بقا کا تعصب ان ناموں سے بنا ایک نمونہ ہے جو قائم رہے، اور یہ جاننا کہ کون سے نام قائم رہے خود مستقبل کی معلومات ہے، لہذا صرف بچ جانے والوں کا یونیورس ایک نظر آگے کا رساو ہے جو قاعدے کے بجائے ڈیٹا میں واقع ہے۔
متعصب نظر آگے والے بیک ٹیسٹ اتنے اچھے کیوں لگتے ہیں؟
رساو نتائج کو پیش گوئی کرنے کے بجائے منتخب کرتا ہے۔ اوپر والے پینل میں، سیشنز کو ان کی اپنی کلوزنگ پرائس پر اسکرین کرنے سے 2016 میں لیگڈ ورژن کے مقابلے میں اوسط سیشن حاصل تقریباً 0.455 فیصد پوائنٹس زیادہ پیدا ہوا، ایک فائدہ جو تعریفی ہے نہ کہ کمایا گیا۔
پوائنٹ-ان-ٹائم ڈیٹا کیا ہے؟
پوائنٹ-ان-ٹائم ڈیٹا ہر قدر کو اس طرح ذخیرہ کرتا ہے جیسے وہ ہر تاریخی تاریخ پر معلوم تھی، اصل اعداد و شمار اور ہر بعد کی نظر ثانی سمیت، اس دن موجود سیکیورٹیز کے یونیورس کے ساتھ۔ یہ وہ حوالہ ہے جس کی ایک بیک ٹیسٹ کو ضرورت ہے تاکہ یہ دکھایا جا سکے کہ اس کے ان پٹ اس کے فیصلوں سے پہلے موجود تھے۔
اوپر کا ہر اعداد و شمار حقیقی روزانہ بارز پر ایک ذخیرہ شدہ، ورژن شدہ استفسار (stored, versioned query) ہے۔ کسی بھی پینل کے SQL کو پھیلائیں، یا اسٹراسمور ٹرمینل (Strasmore terminal) پر اپنے قاعدے پر لیگ ٹیسٹ چلائیں۔