Strasmore Research
Deep Dives · Matt ConnorBy Matt Connor ·

LLM உண்மையான Alpha Factors-ஐ கண்டறியுமா?

LLM ஒரு மணி நேரத்தில் நூறு alpha factors எழுதலாம். பத்து ஆண்டுகால உண்மையான விலைகளில் 240 coin flip factors-ன் முடிவுகளையும், வெற்றி பெற்றவற்றைச் சோதிக்கும் முறையையும் அறியுங்கள்.

ஒரு LLM நாள் முழுவதும் alpha factors-ஐ முன்மொழியலாம். திறன் வாய்ந்த ஒரு model-க்கு data dictionary மற்றும் scoring harness வழங்கினால், மதிய உணவுக்கு முன்பே நம்பத்தகுந்ததாகத் தோன்றும் நூறு factor expressions-ஐ அது எழுதிவிடும். ஆனால் அதைவிடக் கடினமான கேள்வி அடிப்படையில் உள்ளது: அவற்றில் ஒன்று உண்மையானது என்பதை எப்படித் தெரிந்துகொள்வது? அதை உருவாக்கிய search, noise-இலிருந்து winners-ஐ உற்பத்தி செய்யும் இயந்திரமாக இருந்தால், இதை எவ்வாறு தீர்மானிப்பது?

alpha factor என்றால் என்ன?

Factor என்பது market data-ஐ ஒவ்வொரு தேதியிலும் ஒவ்வொரு stock-க்கும் ஒரு எண்ணாக மாற்றும் விதிமுறை. பன்னிரண்டு மாத price change ஒரு factor. Debt-to-equity ratio-வும் அதேபோல். ஒரு universe-ஐ அதன்படி rank செய்து, மேல்பகுதியை வாங்கி, கீழ்ப்பகுதியை விற்று, நிர்ணயிக்கப்பட்ட அட்டவணைப்படி rebalance செய்தால், அந்த factor ஒரு strategy ஆகிறது. Alpha என்பது, சாதாரண market exposure மூலம் இயல்பாகக் கிடைத்திருக்கும் return-ஐ கழித்த பின் மீதமிருக்கும் return ஆகும்.

Candidates, Sharpe ratio மூலம் மதிப்பிடப்படுகின்றன: சராசரி return-ஐ அந்த return-ன் standard deviation-ஆல் வகுத்து, ஆண்டளவுக்கு scale செய்வது. இது volatility-யின் ஒவ்வொரு அலகிற்கும் கிடைக்கும் return ஆகும். Live strategy-யில் நீண்டகால Sharpe சுமார் 1 இருப்பது மதிப்புக்குரியது. அடுத்த முறை backtest 3 என்று காட்டும்போது இதை நினைவில் கொள்ள வேண்டும்.

LLM factor research உண்மையில் எவ்வாறு செயல்படுகிறது

இந்தத் துறையில் உள்ள ஒவ்வொரு project-மும் இதே loop-ன் ஒரு வடிவத்தை இயக்குகிறது.

  1. Harness மதிப்பிடக்கூடிய சிறிய language-ல் model factor expressions-ஐ எழுதுகிறது.
  2. Backtester, prices மற்றும் fundamentals-ன் நிர்ணயிக்கப்பட்ட வரலாற்றைப் பயன்படுத்தி ஒவ்வொரு expression-ஐயும் மதிப்பிடுகிறது.
  3. Score threshold-ஐ மீறும் expressions வைத்துக்கொள்ளப்படுகின்றன. மற்றவை நீக்கப்படுகின்றன.
  4. வைத்துக்கொள்ளப்பட்ட expressions, worked examples ஆக model-ன் context-க்கு திரும்புகின்றன. பின்னர் loop மீண்டும் இயங்குகிறது.

பல-agent trading systems இந்தப் பணிகளைத் தனித்தனி roles-க்கு பிரிக்கின்றன. ஒன்று முன்மொழிகிறது; மற்றொன்று சோதிக்கிறது. இந்த plumbing உண்மையாகவே பயனுள்ளது. மேலும் AI agent-க்கு தேவையான market data skills மனிதருக்குத் தேவையானவையே.

இந்த loop-ல் எதுவும் நேர்மையற்றது அல்ல. Research நடைபெறும் முறையே search ஆகும். பிரச்சினை arithmetic-ல் உள்ளது. Step 2 சில முறை மீறி இயங்கும் தருணத்திலேயே அது தோன்றுகிறது.

LLM alpha factor search ஏன் winners-ஐ உருவாக்குகிறது

ஒரே price history. ஆயிரக்கணக்கான குறைந்த செலவிலான hypotheses. ஒவ்வொரு hypothesis-மும் ஒரே finite sample-க்கு எதிராக மதிப்பிடப்படுகிறது. அந்த sample-ல் அதிர்ஷ்டத்தின் தாக்கம் அதிகம். போதுமான rules-ஐ சோதித்தால், சில rules அந்த அதிர்ஷ்டத்துடன் நெருக்கமாகப் பொருந்தும். கிடைத்த fit எந்த வகையைச் சேர்ந்தது என்பதை score கூற முடியாது. Noise-ஐப் பொருத்திய rule-க்கும், market-ஐப் பொருத்திய rule-க்கும் அது ஒரே எண்ணைக் காட்டும்.

இங்கே null hypothesis 240 முறை வரையப்பட்டுள்ளது. கீழே உள்ள ஒவ்வொரு “factor”-மும் ஒரு coin flip: ticker, month மற்றும் trial number ஆகியவற்றின் hash, ஒவ்வொரு மாதமும் 40 பெரிய US names-ஐ இரண்டு பகுதிகளாகப் பிரிக்கிறது. Strategy, ஒரு பகுதியை long-ஆகவும் மற்றொன்றை short-ஆகவும் வைத்திருக்கிறது. உருவாக்கப்பட்ட விதிப்படி இதில் எந்தத் தகவலும் இல்லை. January 2016 முதல் June 2021 வரையிலான உண்மையான month-end returns-ல் மதிப்பிட்டபோது, 240 trials இவ்வாறு அமைந்தன.

வினவவும்உண்மையான விலைகளில் மதிப்பிடப்பட்ட 240 coin flip factors: ஆண்டு அடிப்படையிலான Sharpe, ஜனவரி 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

இந்த spread-தான் முக்கியம். அந்த chart-ல் எதுவும் எதையும் முன்னறிவிக்கவில்லை. இருந்தாலும் 1 trials top band-ல் (1.2 and above), search-ன் 0.4% பகுதியில், மேலும் 1 bottom band-ல் (below -1.2) முடிந்தன. ஒரு researcher அதிர்ஷ்டமான ஒரு trial-ஐ மட்டும் இயக்கி நிறுத்தியிருந்தால், அவரிடம் ஒரு chart மற்றும் Sharpe ratio இருக்கும். ஆனால் அவை discovery-யிலிருந்து வேறுபட்டவை என்பதைத் தீர்மானிக்க வழி இருக்காது. இங்குள்ள returns month-end close முதல் அடுத்த month-end close வரை அளவிடப்படுகின்றன. அந்தக் கணக்கீட்டை monthly returns எவ்வாறு அளவிடப்படுகின்றன என்பதில் காணலாம்.

முக்கியமான எண்ணிக்கை: நீங்கள் எத்தனை சோதனைகள் செய்தீர்கள் என்பதே

ஒரு backtest தனியாக வெளியிடப்பட்டால், அதில் denominator காணாமல் போயிருக்கும். அதே 240 trials-ஐ search தொடர்ந்து விரிவடையும் ஒன்றாகப் பாருங்கள்: ஒவ்வொரு கட்டத்திலும், இதுவரை முயற்சித்த அனைத்தின் average-க்கு அருகில் board-ல் உள்ள சிறந்த score.

வினவவும்தேடலின் அளவுடன் சிறந்த மதிப்பெண் உயர்கிறது: இயக்கப்பட்ட trials அடிப்படையிலான சிறந்த மற்றும் சராசரி Sharpe
ஒவ்வொரு எண்ணின் பின்னணியில் உள்ள துல்லியமான 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

Running maximum உயர மட்டுமே முடியும். இதுவே சிக்கல். முதலில் சோதிக்கப்பட்ட rule-ன் score 0.44. 240 trials முடிந்தபின் board-ல் உள்ள சிறந்த score 1.59 ஆகும். அதேசமயம், அவற்றின் முழு average 0.01 ஆக உள்ளது. எந்த ஒரு rule-மும் மேம்படாமல் headline மேம்பட்டது. பத்தாயிரம் expressions-ஐ மதிப்பிடும் harness, இங்கே காட்டப்பட்டுள்ளதைவிட மிகவும் வலப்புறம் இந்த curve-ஐத் தொடர்கிறது. அது அறிக்கையிடும் எண்ணிக்கை அந்த curve-ன் உச்சமாகும்.

Held-out period winners-க்கு என்ன செய்கிறது

பொதுவான பாதுகாப்பு முறை holdout ஆகும்: ஒரு period-ல் score செய்து, search ஒருபோதும் பயன்படுத்தாத பின்னைய period-ல் survivors-ஐ மீண்டும் score செய்வது. Training window-ல் சிறந்த 12 coin flips-ஐ எடுத்துக்கொண்டு, அதே rules-ஐ அடுத்த ஐந்து ஆண்டுகளில், July 2021 முதல் June 2026 வரை, இயக்கிப் பாருங்கள்.

வினவவும்Training-இல் சிறந்த பன்னிரண்டு trials, பயன்படுத்தப்படாத ஐந்து ஆண்டுகளில் மறுமதிப்பீடு (ஜூலை 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

ஒவ்வொரு bar pair-மும் ஒரு rule-ஐக் குறிக்கிறது. இடது bar, report-ல் அதற்கு இடம் கிடைத்த score. வலது bar, அடுத்த ஐந்து ஆண்டுகளில் அதே rule பெற்ற score. முதலிடம் பெற்ற trial training-ல் 1.59 score பெற்று, பின்னர் -0.51 பெற்றது. பன்னிரண்டாவது trial 0.74 பெற்று, அதன் பின் 0.49 பெற்றது.

Twelve rules என்பது தனிப்பட்ட முறையிலும் சிறிய sample. Training score அடிப்படையில் அனைத்து 240 rules-ஐ fifths-ஆகப் பிரித்து, ஒவ்வொரு fifth-ன் holdout score-ஐ average செய்தால், தெளிவான பார்வை கிடைக்கும்.

வினவவும்Training rank மற்றும் holdout முடிவு: 240 trials ஐ ஐந்திலொன்றுகளாகப் பிரித்தல்
ஒவ்வொரு எண்ணின் பின்னணியில் உள்ள துல்லியமான 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

Training-ல் groups, மேல்பகுதியில் 0.66 முதல் கீழ்ப்பகுதியில் -0.63 வரை செல்கின்றன. இது விரிவானதும் முற்றிலும் ஒழுங்கானதுமான ladder ஆகும். ஏனெனில் groups அந்த score-ஆல் வெட்டப்பட்டவை. Holdout-ல் அதே இரண்டு முனைகளின் average scores 0.01 மற்றும் 0.13 ஆகும். Ladder சமநிலையடைகிறது. Pipeline-ல் எதிராக optimize செய்யப்படாத ஒரே பகுதி holdout ஆகும். அதனால் அதைப் பயன்படுத்துவதில் கவனம் அவசியம்.

உண்மையில் செயல்படும் பாதுகாப்பு முறைகள்

ஒருமுறை மட்டுமே பயன்படுத்தப்படும் holdout. அதைப் பார்ப்பது ஒவ்வொரு முறையும், அதை training data-ஆக மாற்றுகிறது. Window உருளும் walk-forward testing முறைதான் மீண்டும் மீண்டும் பயன்படுத்தப்பட்ட பிறகும் நிலைத்திருக்கும் முறை. இதில் ஒவ்வொரு score-மும் fit செய்யப்பட்ட காலத்திற்குப் பிறகான data-யிலிருந்து பெறப்படுகிறது.

Multiple-testing adjustment. Bailey மற்றும் López de Prado 2014-ல் அறிமுகப்படுத்திய deflated Sharpe ratio, மேற்கொள்ளப்பட்ட trials-ன் எண்ணிக்கை, sample-ன் நீளம், returns-ன் skewness மற்றும் அவற்றின் tail thickness ஆகியவற்றைப் பொருத்து observed Sharpe-ஐக் குறைக்கிறது. Trial count-ஐ நேர்மையாக வழங்கினால், பத்தாயிரம் expressions கொண்ட search-ல் headline Sharpe பெரும்பாலும் பூஜ்யமாகக் குறையும்.

முயற்சிக்கப்பட்ட ஒவ்வொரு expression-ஐயும், நீக்கப்பட்டவற்றையும் உள்ளடக்கிய audit trail. இதுவே அடிப்படைத் தேவையாகும். அதனால்தான் factor-research project-ன் விளக்கத்தில் “auditable” என்பது முக்கியமான சொல். Deflation-க்கு trial count தேவை. Winners-ஐ மட்டும் log செய்யும் pipeline, தன் சொந்த correction-க்கான input-ஐ அழித்துவிட்டது. Discarded drafts, கைவிடப்பட்ட parameter sweeps, researcher-ன் சொந்த restarts, scoring code-ன் ஒவ்வொரு முந்தைய version ஆகிய அனைத்தும் அந்த எண்ணிக்கையில் சேரும்.

Score-ஐ நம்புவதற்கு முன் cost மற்றும் look-ahead bias checks. Vendor data-ஐ market அறிந்த தேதிக்குப் பதிலாக vendor load செய்த தேதியுடன் fundamentals field-ஐ timestamp செய்தால், backtest அழகாகத் தோன்றும். ஆனால் trading மோசமாக இருக்கும்.

“Auditable” என்ற சொல்லைப் புரிந்துகொள்வது

இந்தத் துறையில் புதிய repositories பெரும்பாலான வாரங்களிலும் தோன்றுகின்றன. சில டஜன் stars கொண்ட project, track record அல்ல; அது prototype. Star counts code-ஐவிட வேகமாக மாறுகின்றன. அதனால்தான் இந்தப் பக்கம் ஒரு குறிப்பிட்ட project-ஐ அல்ல, pattern-ஐ மதிப்பிடுகிறது. எந்த project முன் வந்தாலும் முதலில் பின்வருவனவற்றைத் திறந்து பாருங்கள்.

  • ஒவ்வொரு candidate-ஐயும் அதன் expression மற்றும் score உடன் timestamp செய்து log செய்கிறதா? அல்லது keepers-ஐ மட்டும் log செய்கிறதா?
  • Holdout-ஐ harness கட்டாயப்படுத்துகிறதா? அல்லது researcher-ன் சுயக்கட்டுப்பாட்டை நம்புகிறதா?
  • Report செய்யப்படும் ஒவ்வொரு score-க்கும் அருகில் trial count உள்ளதா?
  • எந்த market-க்காக அது உருவாக்கப்பட்டது? China A-shares-க்காக tune செய்யப்பட்ட library, daily price limits மற்றும் அதே session-ல் வாங்கிய shares-ஐ விற்கும் கட்டுப்பாடு ஆகியவற்றை உள்ளடக்கும். அந்த விதிகளின் கீழ் ஒரு factor-ன் நடத்தை US equities-க்கு பொருந்தாது.
  • அதை மீண்டும் இயக்கி numbers-ஐ reproduce செய்ய முடியுமா? நீங்கள் பார்த்த exact commit-ஐ pin செய்யுங்கள். இந்தக் கட்டத்தில் உள்ள project, வார இறுதிகளுக்கு இடையே scoring code-ஐ மாற்றக்கூடும்.

இவை எதுவும் factor research-ல் LLM-ஐ பயனற்றதாக்காது. Hypotheses உருவாக்குவது உண்மையான bottleneck. Models அதில் சிறப்பாக செயல்படுகின்றன. ஆனால் சுமை செல்லும் இடம் மாறுகிறது: எத்தனை hypotheses பயன்படுத்தப்பட்டன என்பதற்கான accounting-க்கு அது மாறுகிறது. இவற்றில் ஏதேனும் live order book-ஐ சந்திப்பதற்கு முன், paper trading-ல் backtest மற்றும் உண்மையான fill ஆகியவற்றுக்கிடையிலான இடைவெளி வெளிப்படும்.

LLM alpha factor FAQ

LLM alpha factors-ஐ கண்டறிய முடியுமா?

அது ஆயிரக்கணக்கில் அவற்றை முன்மொழிய முடியும். ஆனால் proposal என்பது finding அல்ல. Claim, scoring step-ல் உருவாகிறது. பரந்த search-லிருந்து பெறப்பட்ட score-ல், score தானாகக் காண முடியாத selection problem உள்ளது. Expression-ஐவிட முதலில் holdout discipline மற்றும் பதிவு செய்யப்பட்ட trial count-ஐ மதிப்பிடுங்கள்.

Deflated Sharpe ratio என்றால் என்ன?

உண்மையான edge இல்லாதபோதும் அந்த அளவிலான search ஒன்று அந்த Sharpe ratio-ஐ உருவாக்கியிருக்கக்கூடிய probability-யாக observed Sharpe ratio-ஐ மாற்றும் correction ஆகும். Bailey மற்றும் López de Prado இதை 2014-ல் வெளியிட்டனர். இதன் மைய input trials-ன் எண்ணிக்கை. Unaudited research loop வழங்க முடியாத எண்ணிக்கையும் அதுவே.

எத்தனை backtests அதிகமாகும்?

ஒரு threshold இல்லை. பயன்படுத்த வேண்டிய adjustment மட்டுமே உள்ளது. 1.0 score பெற்ற ஒரு backtest மற்றும் சிறந்த score 1.0 பெற்ற பத்தாயிரம் backtests ஆகியவை உலகைப் பற்றிய வேறுபட்ட claims. மேலுள்ள coin flips, data-வில் எந்தத் தகவலும் இல்லாமல் 1.59-ஐ 240 trials-ல் எட்டின.

Publication-க்குப் பிறகு published factors ஏன் பலவீனமடைகின்றன?

Published anomalies தோன்றிய பிந்தைய ஆண்டுகளில் அவற்றின் decay-ஐ academic research பதிவு செய்துள்ளது. Crowding அதற்கான ஒரு காரணமாக முன்வைக்கப்படுகிறது. தன் சொந்த sample-க்கு overfit செய்யப்பட்ட original result மற்றொரு காரணம். இரண்டும் chart-ல் ஒரே வடிவத்தை உருவாக்கும். efficient market hypothesis முதலாவது காரணத்தை விளக்குகிறது. மேலுள்ள trials இரண்டாவது காரணத்தை நிரூபிக்கின்றன.


இங்குள்ள ஒவ்வொரு panel-மும் உண்மையான month-end prices மீது இயக்கப்பட்ட stored query ஆகும். அதன் கீழ் SQL திறந்த நிலையில் உள்ளது. ஒன்றை copy செய்து, trial count-ஐ உயர்த்திப் பாருங்கள். Strasmore terminal-ல் சிறந்த number உயர்வதை கவனியுங்கள்.

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