Strasmore Research
Deep Dives · Matt ConnorBy Matt Connor ·

LLM có tìm được yếu tố alpha không?

LLM có thể viết một trăm yếu tố alpha trong một giờ. Xem 240 yếu tố tung đồng xu đạt điểm ra sao trên mười năm giá thực và cách kiểm thử các yếu tố còn lại.

Một LLM có thể đề xuất các yếu tố alpha cả ngày. Chỉ cần cung cấp cho một mô hình đủ năng lực một từ điển dữ liệu và một bộ công cụ chấm điểm, mô hình có thể viết ra hàng trăm biểu thức yếu tố có vẻ hợp lý trước giờ ăn trưa. Câu hỏi khó hơn nằm ở phía sau: làm thế nào biết được một yếu tố trong số đó có thực sự hiệu quả, khi quá trình tìm kiếm tạo ra nó vốn là một cỗ máy sản xuất các yếu tố chiến thắng từ nhiễu?

Yếu tố alpha là gì?

Factor là một quy tắc biến dữ liệu thị trường thành một con số cho mỗi cổ phiếu vào mỗi ngày. Mức thay đổi giá trong mười hai tháng là một factor. Tỷ lệ nợ trên vốn chủ sở hữu cũng vậy. Một factor trở thành chiến lược khi bạn xếp hạng một tập cổ phiếu theo factor đó, mua nhóm đứng đầu, bán nhóm đứng cuối và tái cân bằng theo lịch. Alpha là phần lợi nhuận còn lại sau khi trừ đi lợi nhuận mà mức phân bổ đơn giản vào thị trường vốn đã mang lại.

Các ứng viên được chấm bằng Sharpe ratio: lợi nhuận bình quân chia cho độ lệch chuẩn của lợi nhuận đó, quy đổi theo năm. Đây là lợi nhuận trên mỗi đơn vị biến động. Sharpe dài hạn gần 1 đối với một chiến lược giao dịch thật là mức đáng ghi nhận. Bạn nên nhớ điều này vào lần tới khi một backtest đưa ra con số 3.

Nghiên cứu factor bằng LLM thực sự vận hành như thế nào

Mọi dự án trong lĩnh vực này đều vận hành theo một phiên bản của cùng một vòng lặp.

  1. Mô hình viết các biểu thức factor bằng một ngôn ngữ nhỏ mà bộ công cụ có thể đánh giá.
  2. Backtester chấm điểm từng biểu thức trên một giai đoạn lịch sử cố định của giá và các chỉ tiêu cơ bản.
  3. Các biểu thức vượt ngưỡng điểm được giữ lại. Phần còn lại bị loại.
  4. Các biểu thức được giữ lại quay trở lại context của mô hình dưới dạng ví dụ đã hoàn thiện, rồi vòng lặp chạy tiếp.

Hệ thống giao dịch đa tác tử phân chia các công việc đó cho những vai trò riêng biệt, trong đó một vai trò đề xuất và một vai trò kiểm định. Phần hạ tầng thực sự hữu ích, còn các kỹ năng dữ liệu thị trường mà một AI agent cần cũng chính là những kỹ năng một con người cần.

Không có gì trong vòng lặp này là gian dối. Tìm kiếm là cách nghiên cứu được tiến hành. Vấn đề nằm ở số học, và nó xuất hiện ngay khi bước 2 được thực hiện nhiều hơn một vài lần.

Vì sao tìm kiếm factor alpha bằng LLM tạo ra các yếu tố chiến thắng

Một chuỗi giá duy nhất. Hàng nghìn giả thuyết rẻ. Mọi giả thuyết đều được chấm trên cùng một mẫu hữu hạn, và mẫu đó chứa rất nhiều yếu tố may rủi. Kiểm định đủ nhiều quy tắc thì một số quy tắc sẽ khớp chặt với phần may rủi đó. Điểm số không thể cho bạn biết mình đang có loại khớp nào, vì một quy tắc khớp với nhiễu và một quy tắc khớp với thị trường đều cho ra cùng một con số.

Dưới đây là giả thuyết không có hiệu quả, được rút thăm 240 lần. Mỗi “factor” bên dưới là một lần tung đồng xu: một hàm băm của ticker, tháng và số lần thử chia 40 cổ phiếu vốn hóa lớn của Mỹ thành hai nửa mỗi tháng. Chiến lược mua một nửa và bán khống nửa còn lại. Theo thiết kế, trong đó không có thông tin nào. Khi chấm điểm bằng lợi nhuận thực tế tại cuối tháng từ tháng 1 năm 2016 đến tháng 6 năm 2021, 240 lần thử có kết quả như sau.

Truy vấnĐánh giá 240 yếu tố coin flip trên giá thực: Sharpe quy đổi theo năm, từ tháng 1/2016 đến tháng 6/2021
Câu lệnh SQL chính xác đằng sau mỗi con số
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

Độ phân tán mới là điểm chính. Không có yếu tố nào trên biểu đồ dự báo được điều gì, nhưng 1 lần thử vẫn rơi vào nhóm cao nhất (1.2 and above), chiếm 0.4% trong toàn bộ quá trình tìm kiếm, còn 1 lần rơi vào nhóm thấp nhất (below -1.2). Một nhà nghiên cứu chỉ chạy một lần thử may mắn rồi dừng lại sẽ có một biểu đồ và một Sharpe ratio, nhưng không có cách nào biết đó là phát hiện thực sự hay không. Lợi nhuận ở đây được tính từ giá đóng cửa cuối tháng này đến giá đóng cửa cuối tháng sau; cách tính lợi nhuận tháng trình bày phép tính đó.

Con số quan trọng là số lần bạn đã thử

Một kết quả backtest được báo cáo riêng lẻ đang thiếu mẫu số. Hãy đọc cùng 240 lần thử đó như một quá trình tìm kiếm liên tục mở rộng: tại mỗi bước, so sánh điểm cao nhất trên bảng với mức bình quân của toàn bộ các lần đã thử cho đến thời điểm đó.

Truy vấnĐiểm cao nhất tăng theo quy mô tìm kiếm: Sharpe cao nhất và trung bình theo số lần thử
Câu lệnh SQL chính xác đằng sau mỗi con số
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

Giá trị cực đại lũy kế chỉ có thể tăng, và đó chính là cái bẫy. Quy tắc đầu tiên được kiểm định đạt 0.44. Sau 240 lần thử, điểm cao nhất trên bảng là 1.59, trong khi mức bình quân của tất cả các lần thử là 0.01. Tiêu đề báo cáo được cải thiện dù không có quy tắc nào thực sự tốt lên. Một bộ công cụ đánh giá mười nghìn biểu thức đang chạy đường cong này xa hơn nhiều về bên phải so với biểu đồ trên, và con số nó báo cáo chính là điểm cao nhất trên đường cong đó.

Giai đoạn giữ lại tác động thế nào đến các yếu tố chiến thắng

Cách phòng vệ tiêu chuẩn là holdout: chấm điểm trên một giai đoạn, sau đó chấm lại các yếu tố còn lại trên một giai đoạn muộn hơn mà quá trình tìm kiếm chưa từng sử dụng. Chọn mười hai lần tung đồng xu tốt nhất trong giai đoạn huấn luyện rồi chạy đúng các quy tắc đó trên năm năm tiếp theo, từ tháng 7 năm 2021 đến tháng 6 năm 2026.

Truy vấn12 lần thử tốt nhất trong tập huấn luyện, chấm lại trên 5 năm chưa từng sử dụng (tháng 7/2021 đến tháng 6/2026)
Câu lệnh SQL chính xác đằng sau mỗi con số
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

Mỗi cặp cột là một quy tắc. Cột bên trái là điểm giúp quy tắc đó được đưa vào báo cáo. Cột bên phải là điểm của chính quy tắc đó trong năm năm tiếp theo. Lần thử xếp hạng cao nhất đạt 1.59 trong giai đoạn huấn luyện và -0.51 sau đó; lần thử xếp hạng thứ mười hai đạt 0.74 rồi còn 0.49.

Mười hai quy tắc cũng là một mẫu nhỏ. Nếu chia toàn bộ 240 lần thử thành năm nhóm theo điểm huấn luyện, rồi tính điểm holdout bình quân của từng nhóm, ta sẽ có góc nhìn rõ hơn.

Truy vấnXếp hạng huấn luyện so với kết quả holdout: 240 lần thử chia thành 5 nhóm
Câu lệnh SQL chính xác đằng sau mỗi con số
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

Trong giai đoạn huấn luyện, các nhóm trải từ 0.66 ở nhóm đầu đến -0.63 ở nhóm cuối. Đây là một bậc thang rộng và hoàn toàn có trật tự, vì các nhóm được chia chính theo điểm đó. Trong giai đoạn holdout, hai đầu tương ứng có mức bình quân là 0.010.13. Bậc thang bị san phẳng. Holdout là phần duy nhất trong quy trình chưa bị tối ưu hóa theo, và đó là lý do cần sử dụng nó một cách thận trọng.

Các biện pháp phòng vệ thực sự hiệu quả

Chỉ sử dụng holdout một lần. Mỗi lần xem holdout sẽ biến nó thành dữ liệu huấn luyện. Kiểm định walk-forward, trong đó cửa sổ dữ liệu dịch chuyển và mỗi điểm số được tính từ dữ liệu sau giai đoạn khớp mô hình, là phiên bản có thể chịu được việc sử dụng lặp lại.

Điều chỉnh multiple testing. Deflated Sharpe ratio, được Bailey và López de Prado giới thiệu năm 2014, chiết khấu Sharpe quan sát được dựa trên số lần thử, độ dài mẫu, độ lệch của lợi nhuận và độ dày của các đuôi phân phối. Khi đưa vào số lần thử trung thực, một Sharpe ratio nổi bật từ quá trình tìm kiếm mười nghìn biểu thức thường bị giảm về gần như bằng không.

Lưu vết kiểm toán cho mọi biểu thức đã thử, kể cả những biểu thức bị loại. Đây là phần cốt lõi. Vì vậy, “có thể kiểm toán” là từ đáng chú ý trong mô tả một dự án nghiên cứu factor. Phép điều chỉnh cần số lần thử. Một pipeline chỉ ghi lại các yếu tố chiến thắng đã tự phá hủy dữ liệu đầu vào cho phép điều chỉnh của chính nó. Các bản nháp bị loại, các lần quét tham số bị bỏ dở, những lần nhà nghiên cứu tự khởi động lại và mọi phiên bản trước đó của mã chấm điểm đều phải được tính vào con số này.

Kiểm tra chi phí và look-ahead bias trước khi tin vào điểm số. Một factor được xếp hạng theo trường dữ liệu cơ bản có ngày nhà cung cấp tải dữ liệu, thay vì ngày thị trường có thể tiếp cận dữ liệu đó, sẽ cho backtest đẹp nhưng giao dịch kém.

Đọc từ “có thể kiểm toán”

Các repository mới trong lĩnh vực này xuất hiện gần như mỗi tuần. Một dự án có vài chục ngôi sao thường mới chỉ là prototype, chưa phải một thành tích đã được kiểm chứng. Số lượng ngôi sao cũng thay đổi nhanh hơn mã nguồn. Vì vậy, trang này đánh giá mô hình vận hành thay vì một dự án cụ thể. Dưới đây là những điều bạn nên kiểm tra đầu tiên ở bất kỳ dự án nào xuất hiện trước mắt.

  • Dự án có ghi lại mọi ứng viên cùng biểu thức, điểm số và thời gian hay chỉ ghi lại các yếu tố được giữ lại?
  • Holdout được bộ công cụ bắt buộc thực hiện hay phụ thuộc vào tính kỷ luật của nhà nghiên cứu?
  • Mỗi điểm số được báo cáo có đi kèm số lần thử không?
  • Dự án được xây dựng cho thị trường nào? Một thư viện được tinh chỉnh cho cổ phiếu A tại Trung Quốc sẽ kế thừa biên độ dao động giá hằng ngày và hạn chế bán cổ phiếu mua trong cùng phiên. Hành vi của factor dưới các quy tắc đó không thể chuyển nguyên vẹn sang cổ phiếu Mỹ.
  • Bạn có thể chạy lại và tái tạo các con số không? Hãy cố định đúng commit mà bạn đã đọc, vì một dự án ở giai đoạn này có thể viết lại mã chấm điểm giữa hai cuối tuần.

Không điều nào trong số này khiến LLM trở nên vô dụng trong nghiên cứu factor. Tạo giả thuyết là một điểm nghẽn thực sự, và mô hình làm tốt việc đó. Điều thay đổi là gánh nặng chuyển sang đâu: sang việc ghi nhận có bao nhiêu giả thuyết đã bị sử dụng hết. Trước khi bất kỳ yếu tố nào gặp sổ lệnh thực, paper trading là nơi khoảng cách giữa backtest và lệnh khớp trở nên rõ ràng.

Câu hỏi thường gặp về factor alpha của LLM

LLM có thể tìm ra factor alpha không?

LLM có thể đề xuất hàng nghìn factor, nhưng một đề xuất không phải là một phát hiện. Khẳng định chỉ xuất hiện ở bước chấm điểm, và một điểm số đến từ quá trình tìm kiếm rộng luôn chịu vấn đề lựa chọn mà bản thân điểm số không thể nhận biết. Hãy đánh giá kỷ luật holdout và số lần thử được ghi nhận trước khi xem xét biểu thức.

Deflated Sharpe ratio là gì?

Đây là một phép điều chỉnh biến Sharpe ratio quan sát được thành xác suất rằng một quá trình tìm kiếm có quy mô như vậy vẫn có thể tạo ra kết quả đó khi thực tế không có lợi thế nào. Bailey và López de Prado công bố phương pháp này năm 2014. Đầu vào cốt lõi là số lần thử, cũng chính là con số mà một vòng lặp nghiên cứu không được kiểm toán không thể cung cấp.

Bao nhiêu backtest là quá nhiều?

Không có ngưỡng cố định. Chỉ có một phép điều chỉnh cần được áp dụng. Một backtest đạt 1.0 và mười nghìn backtest có điểm tốt nhất là 1.0 là hai khẳng định khác nhau về thế giới. Các lần tung đồng xu ở trên đạt 1.59 qua 240 lần thử dù hoàn toàn không có thông tin nào trong dữ liệu.

Vì sao các factor được công bố thường suy yếu sau khi công bố?

Các nghiên cứu học thuật đã theo dõi mức suy giảm của những anomaly được công bố trong các năm sau khi chúng xuất hiện. Crowding là một trong những cơ chế được đưa ra để giải thích hiện tượng này. Một kết quả ban đầu bị overfit với chính mẫu dữ liệu của nó là một cơ chế khác. Cả hai đều tạo ra hình dạng tương tự trên biểu đồ. Giả thuyết thị trường hiệu quả lý giải cơ chế thứ nhất, còn các lần thử ở trên minh họa cơ chế thứ hai.


Mọi biểu đồ ở đây đều là một stored query trên giá đóng cửa cuối tháng thực tế, với SQL được hiển thị bên dưới. Hãy sao chép một truy vấn, tăng số lần thử và quan sát con số tốt nhất tăng lên trên terminal Strasmore.

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