Bisakah LLM Menemukan Alpha Factor?
LLM dapat menulis seratus alpha factor dalam satu jam. Uji 240 factor coin flip pada sepuluh tahun harga riil dan pelajari cara menguji factor yang bertahan.
LLM dapat mengusulkan alpha factor sepanjang hari. Berikan model yang kapabel sebuah kamus data dan scoring harness, lalu model itu akan menulis seratus ekspresi factor yang masuk akal sebelum makan siang. Pertanyaan yang lebih sulit ada di baliknya: bagaimana seseorang dapat mengetahui apakah salah satunya benar-benar valid, ketika proses pencarian tersebut merupakan mesin untuk menghasilkan pemenang dari noise?
Apa itu alpha factor?
Factor adalah aturan yang mengubah data pasar menjadi satu angka untuk setiap saham pada setiap tanggal. Perubahan harga selama dua belas bulan adalah factor. Begitu pula rasio utang terhadap ekuitas. Factor menjadi strategi ketika Anda mengurutkan suatu universe berdasarkan factor tersebut, membeli kelompok teratas, menjual kelompok terbawah, lalu melakukan rebalancing sesuai jadwal. Alpha adalah return yang tersisa setelah mengurangkan return yang secara alami akan diberikan oleh eksposur pasar biasa.
Kandidat dinilai menggunakan Sharpe ratio: average return dibagi standard deviation dari return tersebut, lalu disetahunkan. Ini adalah return per unit volatilitas. Sharpe jangka panjang mendekati 1 pada strategi live tergolong baik. Hal ini perlu diingat ketika backtest berikutnya menunjukkan angka 3.
Bagaimana riset factor oleh LLM sebenarnya bekerja
Setiap proyek di bidang ini menjalankan versi dari loop yang sama.
- Model menulis ekspresi factor dalam bahasa sederhana yang dapat dievaluasi oleh harness.
- Backtester menilai setiap ekspresi berdasarkan riwayat harga dan fundamental yang telah ditentukan.
- Ekspresi yang berada di atas ambang skor dipertahankan. Sisanya dibuang.
- Ekspresi yang dipertahankan dikembalikan ke context model sebagai contoh yang telah berhasil, lalu loop dijalankan lagi.
Sistem trading multi-agen membagi pekerjaan tersebut ke dalam peran terpisah: satu peran mengusulkan dan peran lainnya menguji. Infrastruktur ini memang berguna, dan keterampilan data pasar yang dibutuhkan agen AI sama dengan keterampilan yang dibutuhkan manusia.
Tidak ada yang tidak jujur dalam loop tersebut. Pencarian memang merupakan cara riset dilakukan. Masalahnya adalah aritmetika, dan masalah itu muncul segera setelah langkah 2 dijalankan lebih dari beberapa kali.
Mengapa pencarian alpha factor oleh LLM menghasilkan pemenang semu
Satu riwayat harga. Ribuan hipotesis murah. Setiap hipotesis dinilai berdasarkan sampel terbatas yang sama, dan sampel tersebut mengandung banyak faktor keberuntungan. Uji dengan aturan yang cukup banyak, dan sebagian aturan akan sangat cocok dengan keberuntungan tersebut. Skor tidak dapat membedakan jenis kecocokan yang terjadi, karena aturan yang cocok dengan noise dan aturan yang cocok dengan pasar menghasilkan angka yang sama.
Berikut hipotesis nol yang diambil sebanyak 240 kali. Setiap “factor” di bawah ini adalah lemparan koin: hash dari ticker, bulan, dan nomor percobaan membagi 40 saham besar AS menjadi dua kelompok setiap bulan. Strategi mengambil posisi long pada satu kelompok dan short pada kelompok lainnya. Berdasarkan konstruksinya, tidak ada informasi di dalamnya. Ketika dinilai menggunakan return riil akhir bulan dari Januari 2016 hingga Juni 2021, hasil 240 percobaan tersebut terlihat seperti ini.
SQL tepat di balik setiap angka
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)Sebaran tersebut adalah inti masalahnya. Tidak ada yang diprediksi oleh grafik itu, tetapi 1 percobaan masuk ke kelompok teratas (1.2 and above), 0.4% dari keseluruhan pencarian, dan 1 masuk ke kelompok terbawah (below -1.2). Peneliti yang menjalankan satu percobaan beruntung lalu berhenti akan memiliki grafik dan Sharpe ratio, tanpa cara untuk membedakan keduanya dari sebuah temuan. Return di sini dihitung dari penutupan akhir bulan ke penutupan akhir bulan; cara mengukur return bulanan menjelaskan aritmetikanya.
Angka yang penting adalah berapa banyak percobaan yang Anda lakukan
Backtest yang dilaporkan secara terpisah tidak memiliki penyebut. Baca 240 percobaan yang sama sebagai pencarian yang terus diperluas: pada setiap langkah, skor terbaik di papan dibandingkan dengan rata-rata seluruh percobaan hingga saat itu.
SQL tepat di balik setiap angka
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_triedRunning maximum hanya dapat meningkat, dan inilah jebakannya. Aturan pertama yang diuji menghasilkan skor 0.44. Setelah 240 percobaan, skor terbaik di papan menjadi 1.59, sedangkan rata-rata seluruhnya berada di 0.01. Headline membaik tanpa ada satu pun aturan yang membaik. Harness yang mengevaluasi sepuluh ribu ekspresi sedang menjalankan kurva ini jauh ke sebelah kanan dari apa yang terlihat di sini, dan angka yang dilaporkannya adalah titik tertinggi pada kurva tersebut.
Apa yang terjadi pada pemenang dalam periode holdout
Pertahanan standar adalah holdout: melakukan penilaian pada satu periode, lalu menilai ulang kandidat yang bertahan pada periode berikutnya yang tidak pernah disentuh oleh pencarian. Ambil dua belas coin flip terbaik dari periode training, lalu jalankan aturan yang sama selama lima tahun berikutnya, dari Juli 2021 hingga Juni 2026.
SQL tepat di balik setiap angka
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 12Setiap pasangan batang mewakili satu aturan. Batang kiri adalah skor yang membuat aturan tersebut masuk ke dalam laporan. Batang kanan adalah skor aturan yang sama selama lima tahun berikutnya. Percobaan dengan peringkat teratas menghasilkan 1.59 pada periode training dan -0.51 setelahnya; percobaan dengan peringkat kedua belas menghasilkan 0.74 lalu 0.49.
Dua belas aturan juga merupakan sampel yang kecil. Urutkan seluruh 240 aturan ke dalam kelompok seperlima berdasarkan skor training, lalu hitung rata-rata skor holdout setiap kelompok. Hasilnya lebih jelas.
SQL tepat di balik setiap angka
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)Pada periode training, kelompok-kelompok tersebut bergerak dari 0.66 di posisi teratas hingga -0.63 di posisi terbawah. Tangga yang lebar dan sepenuhnya teratur ini memang dijamin karena kelompok tersebut dibentuk berdasarkan skor itu sendiri. Pada periode holdout, kedua ujung yang sama rata-rata menghasilkan 0.01 dan 0.13. Tangga tersebut menjadi datar. Holdout adalah satu-satunya bagian pipeline yang belum dioptimalkan terhadap data. Karena itu, penggunaannya harus dilakukan secara hemat.
Pertahanan yang benar-benar efektif
Holdout yang digunakan satu kali. Setiap kali Anda melihat hasilnya, holdout berubah menjadi data training. Walk-forward testing, yaitu ketika window bergulir dan setiap skor berasal dari data setelah proses fitting, adalah versi yang dapat bertahan dari penggunaan berulang.
Penyesuaian untuk multiple testing. Deflated Sharpe ratio, yang diperkenalkan oleh Bailey dan López de Prado pada 2014, mendiskontokan Sharpe yang diamati berdasarkan jumlah percobaan, panjang sampel, skewness return, dan ketebalan tail return. Jika jumlah percobaan yang digunakan benar-benar dimasukkan, headline Sharpe dari pencarian sepuluh ribu ekspresi sering kali terdeflasi menjadi tidak berarti.
Audit trail yang mencakup setiap ekspresi yang diuji, termasuk ekspresi yang dibuang. Inilah komponen yang paling penting. Karena itu, kata “auditable” menarik dalam deskripsi proyek riset factor. Deflasi membutuhkan jumlah percobaan. Pipeline yang hanya mencatat pemenang telah menghancurkan input untuk koreksinya sendiri. Draf yang dibuang, parameter sweep yang ditinggalkan, pengulangan riset oleh peneliti, serta setiap versi sebelumnya dari scoring code semuanya harus dihitung dalam angka tersebut.
Pemeriksaan biaya dan look-ahead bias sebelum skor dipercaya. Factor yang diurutkan berdasarkan field fundamental dengan tanggal saat vendor memuat data, bukan tanggal saat pasar dapat melihatnya, akan menghasilkan backtest yang sangat baik tetapi trading yang buruk.
Memahami kata “auditable”
Repository baru di bidang ini muncul hampir setiap minggu. Proyek dengan beberapa lusin star lebih tepat disebut prototype daripada track record. Jumlah star juga berubah lebih cepat daripada kodenya. Karena itu, halaman ini menilai polanya, bukan proyek tertentu. Berikut hal pertama yang perlu diperiksa pada proyek mana pun yang Anda temukan.
- Apakah proyek tersebut mencatat setiap kandidat beserta ekspresi dan skornya, lengkap dengan timestamp, atau hanya mencatat kandidat yang dipertahankan?
- Apakah holdout diberlakukan oleh harness, atau hanya bergantung pada kedisiplinan peneliti?
- Apakah setiap skor yang dilaporkan disertai jumlah percobaan?
- Untuk pasar mana proyek tersebut dibuat? Library yang disesuaikan untuk saham A China membawa karakteristik batas harga harian dan larangan menjual saham yang dibeli pada sesi yang sama. Perilaku factor berdasarkan aturan tersebut tidak dapat diterapkan begitu saja pada saham AS.
- Dapatkah proyek tersebut dijalankan ulang dan menghasilkan angka yang sama? Simpan commit persis yang Anda baca, karena proyek pada tahap ini dapat mengubah scoring code-nya dari satu akhir pekan ke akhir pekan berikutnya.
Semua ini tidak membuat LLM menjadi tidak berguna dalam riset factor. Pembuatan hipotesis merupakan hambatan nyata, dan model mampu melakukannya dengan baik. Yang berubah adalah letak tanggung jawabnya: pada pencatatan berapa banyak hipotesis yang telah digunakan. Sebelum semuanya bertemu dengan order book live, paper trading adalah tempat jarak antara backtest dan fill mulai terlihat.
FAQ alpha factor LLM
Dapatkah LLM menemukan alpha factor?
LLM dapat mengusulkannya hingga ribuan, tetapi usulan bukanlah temuan. Klaim tersebut dibuat pada tahap penilaian, dan skor dari pencarian yang luas membawa masalah seleksi yang tidak dapat dilihat oleh skor itu sendiri. Nilai disiplin holdout dan pencatatan jumlah percobaan lebih tinggi daripada ekspresinya.
Apa itu deflated Sharpe ratio?
Deflated Sharpe ratio adalah koreksi yang mengubah Sharpe ratio yang diamati menjadi probabilitas bahwa pencarian dengan ukuran tersebut dapat menghasilkan angka itu tanpa adanya keunggulan riil. Bailey dan López de Prado menerbitkannya pada 2014. Input utamanya adalah jumlah percobaan, tepatnya angka yang tidak dapat disediakan oleh loop riset yang tidak diaudit.
Berapa banyak backtest yang terlalu banyak?
Tidak ada ambang batas. Yang ada adalah penyesuaian yang harus diterapkan. Satu backtest dengan skor 1.0 dan sepuluh ribu backtest yang menghasilkan skor terbaik 1.0 merupakan dua klaim yang berbeda tentang dunia. Coin flip di atas mencapai 1.59 dalam 240 percobaan tanpa informasi apa pun dari data.
Mengapa factor yang dipublikasikan melemah setelah publikasi?
Riset akademik telah melacak pelemahan anomali yang dipublikasikan selama beberapa tahun setelah kemunculannya. Crowding merupakan salah satu mekanisme yang diajukan, dan hasil awal yang overfit terhadap sampelnya sendiri merupakan mekanisme lainnya. Keduanya menghasilkan pola yang sama pada grafik. Efficient market hypothesis menjelaskan mekanisme pertama, sedangkan percobaan di atas menunjukkan mekanisme kedua.
Setiap panel di sini merupakan stored query atas harga riil akhir bulan, dengan SQL yang tersedia di bawahnya. Salin salah satunya, tingkatkan jumlah percobaan, dan lihat angka terbaik meningkat pada terminal Strasmore.