Strasmore Research
Deep Dives · Matt ConnorBy Matt Connor ·

آیا LLM می‌تواند عوامل آلفا را پیدا کند؟

یک LLM می‌تواند در یک ساعت صد عامل آلفا بسازد. امتیاز 240 عامل تصادفی را روی ده سال قیمت واقعی ببینید و روش آزمون گزینه‌های برتر را بشناسید.

یک LLM می‌تواند تمام روز عوامل آلفا پیشنهاد دهد. یک مدل توانمند را به فرهنگ داده و سازوکار امتیازدهی مجهز کنید؛ پیش از ناهار صدها عبارت عاملیِ قابل‌قبول تولید می‌کند. پرسش دشوارتر این است: وقتی جست‌وجویی که آن را تولید کرده، عملاً ماشین ساختن برندگان از دل نویز است، چگونه می‌توان فهمید که یکی از آن‌ها واقعاً معتبر است؟

عامل آلفا چیست؟

عامل قاعده‌ای است که داده‌های بازار را به یک عدد برای هر سهم در هر تاریخ تبدیل می‌کند. تغییر قیمت دوازده‌ماهه یک عامل است. نسبت بدهی به حقوق صاحبان سهام نیز همین‌طور. عامل زمانی به استراتژی تبدیل می‌شود که بر اساس آن، یک مجموعه سهام را رتبه‌بندی کنید، بخش بالایی را بخرید، بخش پایینی را بفروشید و طبق برنامه بازتنظیم کنید. آلفا بازدهی‌ای است که پس از کسر بازدهی‌ای که صرفاً با داشتن یک موقعیت ساده در بازار به دست می‌آمد، باقی می‌ماند.

نامزدها با نسبت شارپ امتیازدهی می‌شوند: میانگین بازدهی تقسیم بر انحراف معیار آن بازدهی، با مقیاس‌گذاری سالانه. این معیار، بازدهی به ازای هر واحد نوسان است. نسبت شارپ بلندمدت نزدیک به 1 در یک استراتژی واقعی، قابل‌قبول است؛ این نکته را باید زمانی به یاد داشت که یک بک‌تست، نسبت شارپ 3 را گزارش می‌کند.

پژوهش واقعی عوامل با LLM چگونه انجام می‌شود

هر پروژه در این حوزه، نسخه‌ای از یک چرخه مشابه را اجرا می‌کند.

  1. مدل، عبارات عاملی را به زبان کوچکی می‌نویسد که سازوکار ارزیابی می‌تواند آن را اجرا کند.
  2. بک‌تستر، هر عبارت را بر اساس سابقه‌ای ثابت از قیمت‌ها و داده‌های بنیادی امتیازدهی می‌کند.
  3. عبارات بالاتر از آستانه امتیاز نگه داشته می‌شوند و بقیه کنار گذاشته می‌شوند.
  4. عبارات نگه‌داشته‌شده به‌عنوان نمونه‌های حل‌شده به زمینه مدل بازمی‌گردند و چرخه دوباره اجرا می‌شود.

سامانه‌های معاملاتی چندعاملی این وظایف را میان نقش‌های جداگانه تقسیم می‌کنند؛ یک نقش پیشنهاد می‌دهد و نقش دیگر آزمون می‌کند. زیرساخت این فرایند واقعاً مفید است و مهارت‌های داده‌های بازار که یک عامل هوش مصنوعی به آن نیاز دارد همان مهارت‌هایی است که یک انسان نیز به آن نیاز دارد.

هیچ‌چیز در این چرخه غیراخلاقی نیست. جست‌وجو بخشی از فرایند پژوهش است. مشکل از محاسبات آغاز می‌شود؛ درست از لحظه‌ای که مرحله 2 بیش از چند بار اجرا شود.

چرا جست‌وجوی عوامل آلفا با LLM برندگان مصنوعی می‌سازد

یک سابقه قیمتی. هزاران فرضیه ارزان. هر فرضیه در برابر همان نمونه محدود امتیازدهی می‌شود و این نمونه، مقدار زیادی شانس تصادفی در خود دارد. اگر قواعد کافی را آزمایش کنید، برخی از آن‌ها بیش از حد با همین شانس تصادفی منطبق می‌شوند. امتیاز نمی‌تواند بگوید با کدام نوع انطباق روبه‌رو هستید؛ زیرا قاعده‌ای که با نویز منطبق شده و قاعده‌ای که با بازار منطبق شده، همان عدد را گزارش می‌کنند.

فرض صفر را 240 بار ترسیم کنید. هر «عامل» زیر یک شیر یا خط است: هشِ نماد سهم، ماه و شماره آزمون، 40 سهم بزرگ آمریکایی را هر ماه به دو نیمه تقسیم می‌کند و استراتژی، یک نیمه را خرید و نیمه دیگر را فروش استقراضی می‌گیرد. طبق تعریف، هیچ اطلاعاتی در آن وجود ندارد. وقتی این 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 above0.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، اجرا کنید.

پرس‌وجودوازده آزمون برتر در آموزش، امتیازدهی مجدد روی پنج سال دست‌نخورده (ژوئیه ۲۰۲۱ تا ژوئن ۲۰۲۶)
کد دقیق 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 آزمون را بر اساس امتیاز آموزشی به پنجک تقسیم و امتیاز خارج از نمونه هر پنجک را میانگین‌گیری کنیم، تصویر دقیق‌تری به دست می‌آید.

پرس‌وجورتبه در آموزش در برابر نتیجه دوره نگه‌داشته: ۲۴۰ آزمون تقسیم‌شده به پنجک‌ها
کد دقیق 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 است. نردبان مسطح می‌شود. داده خارج از نمونه تنها بخش فرایند است که در برابر آن بهینه‌سازی نشده؛ به همین دلیل باید با دقت و صرفه‌جویی از آن استفاده کرد.

روش‌های دفاعی که واقعاً مؤثرند

داده خارج از نمونه‌ای که فقط یک‌بار مصرف شود. هر بار مشاهده آن، داده را به داده آموزشی تبدیل می‌کند. آزمون پیش‌رونده، که در آن پنجره زمانی حرکت می‌کند و هر امتیاز از داده‌های پس از برازش به دست می‌آید، نسخه‌ای است که در برابر استفاده مکرر دوام می‌آورد.

تعدیل بابت آزمون‌های متعدد. نسبت شارپ تعدیل‌شده، که بیلی و لوپز د پرادو در سال 2014 معرفی کردند، نسبت شارپ مشاهده‌شده را بر اساس تعداد آزمون‌ها، طول نمونه، چولگی بازدهی‌ها و ضخامت دنباله‌های توزیع تعدیل می‌کند. اگر تعداد واقعی آزمون‌ها را وارد کنید، یک نسبت شارپ پررنگ که از جست‌وجوی ده‌هزارعبارتی به دست آمده، اغلب به هیچ تبدیل می‌شود.

ردپای حسابرسی که همه عبارات آزمایش‌شده، از جمله موارد کنار گذاشته‌شده، را پوشش دهد. این بخش ستون اصلی کار است و به همین دلیل واژه «قابل حسابرسی» در توضیح یک پروژه پژوهش عوامل اهمیت دارد. تعدیل نسبت شارپ به تعداد آزمون‌ها نیاز دارد. خط لوله‌ای که فقط برندگان را ثبت می‌کند، ورودی اصلاح خودش را از بین برده است. پیش‌نویس‌های حذف‌شده، جست‌وجوهای پارامتری رهاشده، شروع‌های دوباره پژوهشگر و هر نسخه قبلی از کد امتیازدهی، همگی در این عدد محاسبه می‌شوند.

بررسی هزینه‌ها و سوگیری نگاه به آینده پیش از پذیرش امتیاز. عاملی که بر اساس داده بنیادی با تاریخی که فروشنده آن را بارگذاری کرده رتبه‌بندی شود، نه تاریخی که بازار می‌توانسته آن را ببیند، در بک‌تست درخشان ظاهر می‌شود اما در معامله عملکرد ضعیفی خواهد داشت.

خواندن واژه «قابل حسابرسی»

مخازن جدید در این حوزه تقریباً هر هفته ظاهر می‌شوند و پروژه‌ای با چند ده ستاره، بیشتر یک نمونه اولیه است تا سابقه عملکرد. تعداد ستاره‌ها نیز سریع‌تر از کد تغییر می‌کند؛ به همین دلیل این صفحه، الگو را ارزیابی می‌کند نه یک پروژه خاص را. در هر پروژه‌ای که پیش روی شما قرار گرفت، ابتدا این موارد را بررسی کنید.

  • آیا همه نامزدها را همراه با عبارت، امتیاز و زمان ثبت می‌کند، یا فقط موارد نگه‌داشته‌شده را؟
  • داده خارج از نمونه به‌وسیله سازوکار ارزیابی اعمال می‌شود، یا به انضباط شخصی پژوهشگر وابسته است؟
  • آیا هر امتیاز گزارش‌شده، تعداد آزمون‌ها را نیز کنار خود دارد؟
  • برای کدام بازار ساخته شده است؟ کتابخانه‌ای که برای سهام A چین تنظیم شده باشد، محدودیت‌های روزانه قیمت و ممنوعیت فروش سهامی را که در همان جلسه خریداری شده به ارث می‌برد؛ رفتار یک عامل تحت این قواعد به سهام آمریکا منتقل نمی‌شود.
  • آیا می‌توان آن را دوباره اجرا کرد و اعداد را بازتولید کرد؟ کامیت دقیق نسخه‌ای را که خوانده‌اید ثبت کنید، زیرا پروژه‌ای در این مرحله ممکن است کد امتیازدهی خود را از یک آخر هفته تا آخر هفته بعد تغییر دهد.

هیچ‌یک از این موارد، LLM را در پژوهش عوامل بی‌فایده نمی‌کند. تولید فرضیه یک گلوگاه واقعی است و مدل‌ها در آن عملکرد خوبی دارند. آنچه تغییر می‌کند، محل قرار گرفتن بار مسئولیت است: بر حسابداری تعداد فرضیه‌هایی که مصرف شده‌اند. پیش از آنکه هرکدام از این عوامل با دفتر سفارش واقعی روبه‌رو شوند، معاملات کاغذی جایی است که فاصله میان بک‌تست و اجرای سفارش آشکار می‌شود.

پرسش‌های متداول عوامل آلفا با LLM

آیا LLM می‌تواند عوامل آلفا پیدا کند؟

می‌تواند هزاران عامل پیشنهاد دهد، اما پیشنهاد با کشف تفاوت دارد. ادعا در مرحله امتیازدهی مطرح می‌شود و امتیازی که از یک جست‌وجوی گسترده به دست آمده، با مسئله انتخابی روبه‌روست که خود امتیاز قادر به مشاهده آن نیست. پیش از عبارت عامل، انضباط داده خارج از نمونه و تعداد ثبت‌شده آزمون‌ها را ارزیابی کنید.

نسبت شارپ تعدیل‌شده چیست؟

اصلاحی است که نسبت شارپ مشاهده‌شده را به احتمال این تبدیل می‌کند که جست‌وجویی با آن اندازه، بدون وجود برتری واقعی، به همان نتیجه می‌رسید. بیلی و لوپز د پرادو آن را در سال 2014 منتشر کردند. ورودی اصلی آن تعداد آزمون‌هاست؛ دقیقاً همان عددی که یک فرایند پژوهشی فاقد حسابرسی نمی‌تواند ارائه کند.

چند بک‌تست بیش از حد محسوب می‌شود؟

آستانه‌ای وجود ندارد؛ تنها تعدیلی وجود دارد که باید اعمال شود. یک بک‌تست با امتیاز 1.0 و ده‌هزار بک‌تست که بهترین امتیازشان 1.0 است، ادعاهای متفاوتی درباره جهان مطرح می‌کنند. شیر یا خط‌های بالا در میان 1.59 آزمون به 240 رسیدند، در حالی که هیچ اطلاعاتی در داده وجود نداشت.

چرا عوامل منتشرشده پس از انتشار تضعیف می‌شوند؟

پژوهش‌های دانشگاهی، کاهش اثر ناهنجاری‌های منتشرشده را در سال‌های پس از انتشار آن‌ها دنبال کرده‌اند. ازدحام معاملاتی یکی از سازوکارهای مطرح برای توضیح این روند است و بیش‌برازش نتیجه اولیه به نمونه خودش، توضیح دیگری؛ هر دو در نمودار شکلی مشابه ایجاد می‌کنند. فرضیه بازار کارا توضیح نخست را چارچوب‌بندی می‌کند و آزمون‌های بالا، دومی را به نمایش می‌گذارند.


هر پنل در اینجا یک پرس‌وجوی ذخیره‌شده بر مبنای قیمت‌های واقعی پایان ماه است و SQL آن در زیر قابل مشاهده است. یکی را کپی کنید، تعداد آزمون‌ها را افزایش دهید و بالا رفتن بهترین عدد را در پایانه Strasmore ببینید.

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