Strasmore Research
Deep Dives · Matt ConnorBy Matt Connor ·

هل يستطيع نموذج لغوي كبير العثور على عوامل ألفا؟

يمكن لنموذج لغوي كبير كتابة مئة عامل ألفا في ساعة. تعرّف إلى أداء 240 عاملًا مبنيًا على رمي العملة خلال عشر سنوات من الأسعار الحقيقية وكيفية اختبار الناجين.

يمكن لنموذج لغوي كبير أن يقترح عوامل ألفا طوال اليوم. امنح نموذجًا قادرًا قاموسَ بيانات وأداةً لتقييم النتائج، وسيكتب مئة تعبير عامل معقول قبل الغداء. لكن السؤال الأصعب هو: كيف سيعرف أيّ شخص أن أحدها حقيقي، عندما يكون البحث الذي أنتجه آلةً لتصنيع الفائزين من الضوضاء؟

ما عامل ألفا؟

العامل هو قاعدة تحوّل بيانات السوق إلى رقم واحد لكل سهم في كل تاريخ. تغيّر السعر خلال اثني عشر شهرًا عامل. وكذلك نسبة الدين إلى حقوق الملكية. يصبح العامل استراتيجية عندما ترتّب به مجموعةً من الأسهم، وتشتري الشريحة العليا، وتبيع الشريحة السفلى، ثم تعيد الموازنة وفق جدول محدد. ألفا هي العائد المتبقي بعد طرح ما كان سيوفّره لك أصلًا التعرض العادي للسوق.

تُقيَّم المرشحات باستخدام نسبة شارب: متوسط العائد مقسومًا على الانحراف المعياري لذلك العائد، بعد تحويله إلى أساس سنوي. إنها العائد لكل وحدة من التذبذب. تُعد نسبة شارب طويلة الأجل قريبة من 1 في استراتيجية حية نتيجةً محترمة، وهذا أمر يجدر تذكّره في المرة التالية التي يورد فيها الاختبار التاريخي نسبة 3.

كيف تُجرى أبحاث العوامل باستخدام النماذج اللغوية الكبيرة فعليًا

تسير كل المشاريع في هذا المجال وفق نسخة من الحلقة نفسها.

  1. يكتب النموذج تعبيرات عوامل بلغة صغيرة تستطيع أداة التقييم تنفيذها.
  2. يقيّم الاختبار التاريخي كل تعبير على فترة ثابتة من أسعار السوق والبيانات الأساسية.
  3. تُحتفظ بالتعبيرات التي تتجاوز عتبة النتيجة، بينما تُستبعد البقية.
  4. تعود التعبيرات المحتفظ بها إلى سياق النموذج بوصفها أمثلة محلولة، ثم تُعاد الحلقة.

توزّع أنظمة التداول متعددة الوكلاء هذه المهام على أدوار منفصلة، يتولى أحدها الاقتراح ويتولى الآخر الاختبار. البنية التشغيلية مفيدة فعلًا، كما أن مهارات بيانات السوق التي يحتاج إليها وكيل الذكاء الاصطناعي هي نفسها التي يحتاج إليها الإنسان.

لا يوجد في هذه الحلقة ما ينطوي على خداع. فالبحث هو طريقة إجراء الأبحاث. لكن المشكلة حسابية، وتظهر فور تشغيل الخطوة 2 أكثر من بضع مرات.

لماذا يصنّع بحث عوامل ألفا باستخدام نموذج لغوي كبير فائزين وهميين

سجل سعري واحد. وآلاف الفرضيات الرخيصة. تُقيَّم كل فرضية مقابل العينة المحدودة نفسها، وتحمل هذه العينة قدرًا كبيرًا من الحظ. اختبر عددًا كافيًا من القواعد، وستجد بعضها قد طابق الحظ عن قرب. ولا تستطيع النتيجة أن تخبرك بنوع المطابقة التي حصلت عليها، لأن القاعدة التي طابقت الضوضاء والقاعدة التي طابقت السوق تطبعان الرقم نفسه.

إليك الفرضية الصفرية، وقد سُحبت 240 مرة. كل «عامل» أدناه هو نتيجة رمية قطعة نقدية: إذ تقسم تجزئةٌ تعتمد على رمز السهم والشهر ورقم التجربة 40 سهمًا أمريكيًا كبيرًا إلى نصفين كل شهر، وتحتفظ الاستراتيجية بنصف في مركز شراء وبالنصف الآخر في مركز بيع على المكشوف. لا توجد أي معلومات فيها، بحكم التصميم. وعند تقييمها على العوائد الحقيقية في نهاية كل شهر من يناير 2016 إلى يونيو 2021، جاءت التجارب البالغ عددها 240 على النحو التالي.

الاستعلامتقييم 240 عاملًا عشوائيًا على أسعار فعلية: نسبة شارب السنوية، يناير 2016 إلى يونيو 2021
استعلام SQL الدقيق وراء كل رقم
WITH month_end AS (
    SELECT ticker,
           toStartOfMonth(toDate(toTimeZone(window_start, 'America/New_York'))) AS month_start,
           argMax(toFloat64(close), window_start) AS close_px
    FROM global_markets.delayed_stocks_minute_aggs
    WHERE ticker IN ('AAPL','ADBE','AMZN','BA','CAT','COST','CRM','CSCO','CVX','DE',
                     'DUK','GE','GOOGL','HD','HON','IBM','INTC','JNJ','JPM','KO',
                     'LMT','MCD','MMM','MRK','MSFT','NKE','NVDA','ORCL','PEP','PFE',
                     'PG','QCOM','SO','T','TGT','TXN','UNP','VZ','WMT','XOM')
      AND toDate(toTimeZone(window_start, 'America/New_York')) >= toDate('2015-12-01')
      AND toDate(toTimeZone(window_start, 'America/New_York')) <= toDate('2021-06-30')
      AND toDayOfMonth(toTimeZone(window_start, 'America/New_York')) >= 22
      AND (toHour(toTimeZone(window_start, 'America/New_York')) * 60
           + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959
    GROUP BY ticker, month_start
),
lagged AS (
    SELECT ticker,
           month_start,
           close_px,
           lagInFrame(close_px) OVER (PARTITION BY ticker ORDER BY month_start
                                      ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) AS prev_px
    FROM month_end
),
monthly_return AS (
    SELECT ticker, month_start, close_px / prev_px - 1 AS ret
    FROM lagged
    WHERE prev_px > 0
      AND month_start >= toDate('2016-01-01')
),
trial AS (
    SELECT arrayJoin(range(1, 241)) AS n
),
factor_month AS (
    SELECT t.n AS trial_id,
           m.month_start AS month_start,
           avgIf(m.ret, bitAnd(cityHash64(m.ticker, toString(m.month_start), t.n), 1) = 1)
         - avgIf(m.ret, bitAnd(cityHash64(m.ticker, toString(m.month_start), t.n), 1) = 0) AS long_short_ret
    FROM monthly_return AS m
    CROSS JOIN trial AS t
    GROUP BY trial_id, month_start
    HAVING countIf(bitAnd(cityHash64(m.ticker, toString(m.month_start), t.n), 1) = 1) > 0
       AND countIf(bitAnd(cityHash64(m.ticker, toString(m.month_start), t.n), 1) = 0) > 0
),
scored AS (
    SELECT trial_id,
           avg(long_short_ret) / stddevSamp(long_short_ret) * sqrt(12) AS sharpe
    FROM factor_month
    GROUP BY trial_id
    HAVING stddevSamp(long_short_ret) > 0
)
SELECT multiIf(sharpe < -1.2, 'below -1.2',
               sharpe < -0.8, '-1.2 to -0.8',
               sharpe < -0.4, '-0.8 to -0.4',
               sharpe <  0.0, '-0.4 to 0.0',
               sharpe <  0.4, '0.0 to 0.4',
               sharpe <  0.8, '0.4 to 0.8',
               sharpe <  1.2, '0.8 to 1.2',
               '1.2 and above') AS sharpe_bucket,
       count() AS factor_count,
       round(100 * count() / 240, 1) AS share_pct
FROM scored
GROUP BY sharpe_bucket
ORDER BY min(sharpe)
Run this yourself

الفارق هو جوهر المسألة. لا يتنبأ أي شيء في ذلك الرسم بأي شيء، ومع ذلك وصلت 1 تجربة إلى النطاق الأعلى (1.2 and above)، أي 0.4% من البحث، بينما وصلت 1 إلى النطاق الأدنى (below -1.2). كان الباحث الذي أجرى تجربة محظوظة واحدة ثم توقف سيملك رسمًا بيانيًا ونسبة شارب، من دون وسيلة لمعرفة ما إذا كان أي منهما اكتشافًا. العوائد هنا من إغلاق نهاية شهر إلى إغلاق نهاية الشهر التالي؛ وتشرح كيفية قياس العوائد الشهرية تلك الحسابات.

الرقم المهم هو عدد التجارب التي أجريتها

يفتقد الاختبار التاريخي المعروض بمفرده إلى مقامه. اقرأ التجارب البالغ عددها 240 بوصفها بحثًا يتسع باستمرار: في كل خطوة، تُعرض أفضل نتيجة مسجلة إلى جانب متوسط كل ما جرت تجربته حتى ذلك الحين.

الاستعلامترتفع أفضل نتيجة مع حجم البحث: أفضل ومتوسط نسبة شارب حسب عدد التجارب
استعلام SQL الدقيق وراء كل رقم
WITH month_end AS (
    SELECT ticker,
           toStartOfMonth(toDate(toTimeZone(window_start, 'America/New_York'))) AS month_start,
           argMax(toFloat64(close), window_start) AS close_px
    FROM global_markets.delayed_stocks_minute_aggs
    WHERE ticker IN ('AAPL','ADBE','AMZN','BA','CAT','COST','CRM','CSCO','CVX','DE',
                     'DUK','GE','GOOGL','HD','HON','IBM','INTC','JNJ','JPM','KO',
                     'LMT','MCD','MMM','MRK','MSFT','NKE','NVDA','ORCL','PEP','PFE',
                     'PG','QCOM','SO','T','TGT','TXN','UNP','VZ','WMT','XOM')
      AND toDate(toTimeZone(window_start, 'America/New_York')) >= toDate('2015-12-01')
      AND toDate(toTimeZone(window_start, 'America/New_York')) <= toDate('2021-06-30')
      AND toDayOfMonth(toTimeZone(window_start, 'America/New_York')) >= 22
      AND (toHour(toTimeZone(window_start, 'America/New_York')) * 60
           + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959
    GROUP BY ticker, month_start
),
lagged AS (
    SELECT ticker,
           month_start,
           close_px,
           lagInFrame(close_px) OVER (PARTITION BY ticker ORDER BY month_start
                                      ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) AS prev_px
    FROM month_end
),
monthly_return AS (
    SELECT ticker, month_start, close_px / prev_px - 1 AS ret
    FROM lagged
    WHERE prev_px > 0
      AND month_start >= toDate('2016-01-01')
),
trial AS (
    SELECT arrayJoin(range(1, 241)) AS n
),
factor_month AS (
    SELECT t.n AS trial_id,
           m.month_start AS month_start,
           avgIf(m.ret, bitAnd(cityHash64(m.ticker, toString(m.month_start), t.n), 1) = 1)
         - avgIf(m.ret, bitAnd(cityHash64(m.ticker, toString(m.month_start), t.n), 1) = 0) AS long_short_ret
    FROM monthly_return AS m
    CROSS JOIN trial AS t
    GROUP BY trial_id, month_start
    HAVING countIf(bitAnd(cityHash64(m.ticker, toString(m.month_start), t.n), 1) = 1) > 0
       AND countIf(bitAnd(cityHash64(m.ticker, toString(m.month_start), t.n), 1) = 0) > 0
),
scored AS (
    SELECT trial_id,
           avg(long_short_ret) / stddevSamp(long_short_ret) * sqrt(12) AS sharpe
    FROM factor_month
    GROUP BY trial_id
    HAVING stddevSamp(long_short_ret) > 0
),
ladder AS (
    SELECT arrayJoin([1, 2, 5, 10, 25, 50, 100, 160, 240]) AS n
)
SELECT l.n AS factors_tried,
       round(max(s.sharpe), 2) AS best_sharpe,
       round(avg(s.sharpe), 2) AS average_sharpe
FROM ladder AS l
CROSS JOIN scored AS s
WHERE s.trial_id <= l.n
GROUP BY factors_tried
ORDER BY factors_tried
Run this yourself

لا يمكن للحد الأقصى التراكمي إلا أن يرتفع، وهذه هي الخديعة تحديدًا. حققت القاعدة الأولى التي اختُبرت 0.44. وبعد 240 تجربة، أصبحت أفضل نتيجة مسجلة 1.59، في حين بلغ المتوسط عبر جميع التجارب 0.01. تحسّن العنوان الرئيسي من دون أن تتحسن أي قاعدة. وتنفّذ أداة تقييم تختبر عشرة آلاف تعبير هذا المنحنى إلى يمين ما هو مرسوم هنا بكثير، والرقم الذي تعرضه هو قمته.

ماذا تفعل فترة الاختبار المحتجزة بالفائزين؟

الدفاع المعتاد هو فترة اختبار محتجزة: التقييم على فترة واحدة، ثم إعادة تقييم الناجين على فترة لاحقة لم يلمسها البحث. خذ أفضل اثنتي عشرة رمية نقدية من نافذة التدريب، وشغّل القواعد نفسها عبر السنوات الخمس التالية، من يوليو 2021 إلى يونيو 2026.

الاستعلامأفضل 12 تجربة في التدريب، أُعيد تقييمها على خمس سنوات غير مستخدمة (يوليو 2021 إلى يونيو 2026)
استعلام SQL الدقيق وراء كل رقم
WITH month_end AS (
    SELECT ticker,
           toStartOfMonth(toDate(toTimeZone(window_start, 'America/New_York'))) AS month_start,
           argMax(toFloat64(close), window_start) AS close_px
    FROM global_markets.delayed_stocks_minute_aggs
    WHERE ticker IN ('AAPL','ADBE','AMZN','BA','CAT','COST','CRM','CSCO','CVX','DE',
                     'DUK','GE','GOOGL','HD','HON','IBM','INTC','JNJ','JPM','KO',
                     'LMT','MCD','MMM','MRK','MSFT','NKE','NVDA','ORCL','PEP','PFE',
                     'PG','QCOM','SO','T','TGT','TXN','UNP','VZ','WMT','XOM')
      AND toDate(toTimeZone(window_start, 'America/New_York')) >= toDate('2015-12-01')
      AND toDate(toTimeZone(window_start, 'America/New_York')) <= toDate('2026-06-30')
      AND toDayOfMonth(toTimeZone(window_start, 'America/New_York')) >= 22
      AND (toHour(toTimeZone(window_start, 'America/New_York')) * 60
           + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959
    GROUP BY ticker, month_start
),
lagged AS (
    SELECT ticker,
           month_start,
           close_px,
           lagInFrame(close_px) OVER (PARTITION BY ticker ORDER BY month_start
                                      ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) AS prev_px
    FROM month_end
),
monthly_return AS (
    SELECT ticker, month_start, close_px / prev_px - 1 AS ret
    FROM lagged
    WHERE prev_px > 0
      AND month_start >= toDate('2016-01-01')
),
trial AS (
    SELECT arrayJoin(range(1, 241)) AS n
),
factor_month AS (
    SELECT t.n AS trial_id,
           m.month_start AS month_start,
           avgIf(m.ret, bitAnd(cityHash64(m.ticker, toString(m.month_start), t.n), 1) = 1)
         - avgIf(m.ret, bitAnd(cityHash64(m.ticker, toString(m.month_start), t.n), 1) = 0) AS long_short_ret
    FROM monthly_return AS m
    CROSS JOIN trial AS t
    GROUP BY trial_id, month_start
    HAVING countIf(bitAnd(cityHash64(m.ticker, toString(m.month_start), t.n), 1) = 1) > 0
       AND countIf(bitAnd(cityHash64(m.ticker, toString(m.month_start), t.n), 1) = 0) > 0
),
scored AS (
    SELECT trial_id,
           avgIf(long_short_ret, month_start <  toDate('2021-07-01'))
             / stddevSampIf(long_short_ret, month_start <  toDate('2021-07-01')) * sqrt(12) AS in_sample_sharpe,
           avgIf(long_short_ret, month_start >= toDate('2021-07-01'))
             / stddevSampIf(long_short_ret, month_start >= toDate('2021-07-01')) * sqrt(12) AS out_of_sample_sharpe
    FROM factor_month
    GROUP BY trial_id
    HAVING countIf(month_start <  toDate('2021-07-01')) >= 24
       AND countIf(month_start >= toDate('2021-07-01')) >= 24
)
SELECT concat('trial ', toString(trial_id)) AS factor_label,
       round(in_sample_sharpe, 2) AS in_sample_sharpe,
       round(out_of_sample_sharpe, 2) AS out_of_sample_sharpe
FROM scored
ORDER BY in_sample_sharpe DESC
LIMIT 12
Run this yourself

يمثل كل زوج من الأعمدة قاعدة واحدة. العمود الأيسر هو النتيجة التي أكسبتها مكانًا في التقرير. والعمود الأيمن هو نتيجة القاعدة نفسها خلال السنوات الخمس التالية. حققت التجربة الأعلى ترتيبًا 1.59 في التدريب و-0.51 بعده؛ أما التجربة الثانية عشرة فحققت 0.74 ثم 0.49.

اثنتا عشرة قاعدة عينة صغيرة بحد ذاتها. ويعطي ترتيب جميع التجارب البالغ عددها 240 إلى أخماس وفق نتيجة التدريب، ثم حساب متوسط نتيجة الاختبار المحتجز لكل خمس، صورةً أوضح.

الاستعلامترتيب التدريب مقابل نتيجة الاختبار المحتجز: تقسيم 240 تجربة إلى أخماس
استعلام SQL الدقيق وراء كل رقم
WITH month_end AS (
    SELECT ticker,
           toStartOfMonth(toDate(toTimeZone(window_start, 'America/New_York'))) AS month_start,
           argMax(toFloat64(close), window_start) AS close_px
    FROM global_markets.delayed_stocks_minute_aggs
    WHERE ticker IN ('AAPL','ADBE','AMZN','BA','CAT','COST','CRM','CSCO','CVX','DE',
                     'DUK','GE','GOOGL','HD','HON','IBM','INTC','JNJ','JPM','KO',
                     'LMT','MCD','MMM','MRK','MSFT','NKE','NVDA','ORCL','PEP','PFE',
                     'PG','QCOM','SO','T','TGT','TXN','UNP','VZ','WMT','XOM')
      AND toDate(toTimeZone(window_start, 'America/New_York')) >= toDate('2015-12-01')
      AND toDate(toTimeZone(window_start, 'America/New_York')) <= toDate('2026-06-30')
      AND toDayOfMonth(toTimeZone(window_start, 'America/New_York')) >= 22
      AND (toHour(toTimeZone(window_start, 'America/New_York')) * 60
           + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959
    GROUP BY ticker, month_start
),
lagged AS (
    SELECT ticker,
           month_start,
           close_px,
           lagInFrame(close_px) OVER (PARTITION BY ticker ORDER BY month_start
                                      ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) AS prev_px
    FROM month_end
),
monthly_return AS (
    SELECT ticker, month_start, close_px / prev_px - 1 AS ret
    FROM lagged
    WHERE prev_px > 0
      AND month_start >= toDate('2016-01-01')
),
trial AS (
    SELECT arrayJoin(range(1, 241)) AS n
),
factor_month AS (
    SELECT t.n AS trial_id,
           m.month_start AS month_start,
           avgIf(m.ret, bitAnd(cityHash64(m.ticker, toString(m.month_start), t.n), 1) = 1)
         - avgIf(m.ret, bitAnd(cityHash64(m.ticker, toString(m.month_start), t.n), 1) = 0) AS long_short_ret
    FROM monthly_return AS m
    CROSS JOIN trial AS t
    GROUP BY trial_id, month_start
    HAVING countIf(bitAnd(cityHash64(m.ticker, toString(m.month_start), t.n), 1) = 1) > 0
       AND countIf(bitAnd(cityHash64(m.ticker, toString(m.month_start), t.n), 1) = 0) > 0
),
scored AS (
    SELECT trial_id,
           avgIf(long_short_ret, month_start <  toDate('2021-07-01'))
             / stddevSampIf(long_short_ret, month_start <  toDate('2021-07-01')) * sqrt(12) AS in_sample_sharpe,
           avgIf(long_short_ret, month_start >= toDate('2021-07-01'))
             / stddevSampIf(long_short_ret, month_start >= toDate('2021-07-01')) * sqrt(12) AS out_of_sample_sharpe
    FROM factor_month
    GROUP BY trial_id
    HAVING countIf(month_start <  toDate('2021-07-01')) >= 24
       AND countIf(month_start >= toDate('2021-07-01')) >= 24
),
ranked AS (
    SELECT trial_id,
           in_sample_sharpe,
           out_of_sample_sharpe,
           row_number() OVER (ORDER BY in_sample_sharpe DESC) AS in_sample_rank
    FROM scored
)
SELECT multiIf(in_sample_rank <=  48, 'best fifth in training',
               in_sample_rank <=  96, 'second fifth',
               in_sample_rank <= 144, 'middle fifth',
               in_sample_rank <= 192, 'fourth fifth',
               'worst fifth in training') AS training_group,
       round(avg(in_sample_sharpe), 2) AS avg_in_sample_sharpe,
       round(avg(out_of_sample_sharpe), 2) AS avg_out_of_sample_sharpe
FROM ranked
GROUP BY training_group
ORDER BY min(in_sample_rank)
Run this yourself

في التدريب، تمتد المجموعات من 0.66 في الأعلى إلى -0.63 في الأسفل، في سلّم واسع ومنظم تمامًا، وهذا مضمون لأن المجموعات قُطعت وفق تلك النتيجة نفسها. أما في الاختبار المحتجز، فيبلغ متوسط الطرفين نفسيهما 0.01 و0.13. يتسطح السلّم. وفترة الاختبار المحتجزة هي الجزء الوحيد من خط الأنابيب الذي لم يُحسَّن بناءً عليه، وهذا ما يجعل إنفاقها بحذر أمرًا مهمًا.

وسائل الدفاع التي تنجح فعلًا

فترة اختبار محتجزة تستخدمها مرة واحدة. كل نظرة إليها تحولها إلى بيانات تدريب. ويُعد الاختبار المتقدم زمنيًا، حيث تتحرك النافذة وتأتي كل نتيجة من بيانات تالية للملاءمة، النسخة التي تصمد أمام الاستخدام المتكرر.

تعديل للاختبارات المتعددة. تعمل نسبة شارب المخفَّضة، التي قدمها Bailey وLópez de Prado في 2014، على خصم نسبة شارب المرصودة وفق عدد التجارب المنفذة، وطول العينة، ومدى التواء العوائد، وسمك ذيولها. وإذا زوّدتها بعدد صادق للتجارب، فإن نسبة شارب رئيسية ناتجة عن بحث شمل عشرة آلاف تعبير غالبًا ما تنخفض إلى لا شيء.

سجل تدقيق يغطي كل تعبير جرت تجربته، بما في ذلك التعبيرات التي أُلقيت. هذا هو العنصر الحاسم، ولهذا فإن كلمة «قابل للتدقيق» هي الكلمة المهمة في وصف مشروع أبحاث العوامل. فالتخفيض يحتاج إلى عدد التجارب. وخط أنابيب لا يسجل إلا الفائزين يكون قد دمّر مدخلات التصحيح الخاص به. وتدخل المسودات المستبعدة، وعمليات مسح المعلمات المتروكة، وإعادات تشغيل الباحث نفسه، وكل نسخة سابقة من رمز التقييم، في ذلك العدد.

فحوصات التكلفة وانحياز النظر إلى المستقبل قبل تصديق النتيجة. فالعامل المرتب وفق حقل من البيانات الأساسية يحمل تاريخ إدخاله في نظام المورّد، بدلًا من التاريخ الذي كان يمكن للسوق أن يراه فيه، سيبدو ممتازًا في الاختبار التاريخي ويتداول بشكل سيئ.

قراءة كلمة «قابل للتدقيق»

تظهر مستودعات جديدة في هذا المجال معظم الأسابيع، والمشروع الذي يضم بضع عشرات من النجوم هو نموذج أولي لا سجل أداء. كما تتحرك أعداد النجوم أسرع من حركة الرمز البرمجي، ولهذا تقيّم هذه الصفحة النمط بدلًا من أي مشروع بعينه. إليك ما ينبغي فتحه أولًا في أي مشروع يقع أمامك.

  • هل يسجل كل مرشح مع تعبيره ونتيجته، مع ختم زمني، أم يسجل التعبيرات المحتفظ بها فقط؟
  • هل تفرض أداة التقييم فترة الاختبار المحتجزة، أم يعتمد الأمر على انضباط الباحث الذاتي؟
  • هل تحمل أي نتيجة معلنة عدد التجارب إلى جانبها؟
  • لأي سوق بُني؟ فالمكتبة المضبوطة على الأسهم الصينية من الفئة A ترث حدودًا يومية للأسعار وقيدًا على بيع الأسهم المشتراة في الجلسة نفسها، ولا ينتقل سلوك العامل في ظل تلك القواعد إلى الأسهم الأمريكية.
  • هل يمكنك إعادة تشغيله وإعادة إنتاج الأرقام؟ ثبّت الالتزام البرمجي الدقيق الذي قرأته، لأن مشروعًا في هذه المرحلة يعيد كتابة رمز التقييم بين عطلة نهاية أسبوع وأخرى.

لا يجعل أي من ذلك النموذج اللغوي الكبير عديم الفائدة في أبحاث العوامل. فإنتاج الفرضيات عنق زجاجة حقيقي، والنماذج جيدة فيه. لكن موضع العبء يتغير: إذ ينتقل إلى المحاسبة الخاصة بعدد الفرضيات المستهلكة. وقبل أن يلتقي أي منها بدفتر أوامر حي، تكون التداول الورقي المكان الذي يظهر فيه الفارق بين الاختبار التاريخي والتنفيذ الفعلي.

الأسئلة الشائعة حول عوامل ألفا باستخدام النماذج اللغوية الكبيرة

هل يستطيع نموذج لغوي كبير العثور على عوامل ألفا؟

يمكنه اقتراحها بالآلاف، لكن الاقتراح ليس اكتشافًا. تُطرح الدعوى عند خطوة التقييم، وتحمل النتيجة المستخرجة من بحث واسع مشكلة اختيار لا تستطيع النتيجة نفسها رؤيتها. قيّم انضباط فترة الاختبار المحتجزة وعدد التجارب المسجل قبل أن تقيّم التعبير.

ما نسبة شارب المخفَّضة؟

إنها تصحيح يحوّل نسبة شارب المرصودة إلى احتمال أن بحثًا بهذا الحجم كان سينتجها من دون وجود ميزة حقيقية. نشرها Bailey وLópez de Prado في 2014. ومدخلها المركزي هو عدد التجارب، وهو الرقم الذي لا تستطيع حلقة بحث غير خاضعة للتدقيق توفيره.

كم عدد الاختبارات التاريخية الذي يُعد مفرطًا؟

لا توجد عتبة محددة، بل يوجد تعديل يجب تطبيقه. يختلف اختبار تاريخي واحد يحقق 1.0 عن عشرة آلاف اختبار تاريخي تبلغ أفضل نتائجها 1.0؛ فهما ادعاءان مختلفان بشأن العالم. وصلت رميات القطعة النقدية أعلاه إلى 1.59 عبر 240 تجربة، من دون وجود أي معلومات في البيانات.

لماذا تضعف العوامل المنشورة بعد نشرها؟

تتبعت الأبحاث الأكاديمية تراجع قوة الشذوذات المنشورة خلال السنوات التي تلت ظهورها. ويُعد ازدحام التداول إحدى الآليات المقترحة لذلك، كما أن الإفراط في ملاءمة النتيجة الأصلية لعينة البحث نفسها آلية أخرى؛ وكلتاهما ترسمان الشكل نفسه على الرسم البياني. وتضع فرضية كفاءة السوق الآلية الأولى في إطارها، بينما توضح التجارب أعلاه الثانية.


كل لوحة هنا هي استعلام مخزّن على أسعار حقيقية في نهاية كل شهر، مع إتاحة SQL أسفلها. انسخ أحدها، وارفع عدد التجارب، وشاهد أفضل رقم يرتفع على منصة Strasmore.

#llm#factor research#overfitting#multiple testing#quant