Saya Membiarkan Masa Depan Merembes ke Masa Lalu

Ada satu hasil backtest, di masa-masa awal, yang begitu bagus sampai seharusnya membuat saya senang. Sebaliknya, setelah beberapa menit menatapnya, hasil itu justru membuat saya sangat gelisah. Keuntungan dalam simulasi itu besar, mulus, dan terlalu bersih — jenis performa yang tidak terjadi di pasar nyata yang penuh derau dan saling sikut. Dan alasan kenapa itu tidak terjadi di pasar nyata adalah karena tes saya, secara diam-diam dan tanpa saya sadari, bisa melihat masa depan.

Bukan dengan sengaja. Saya tidak menulis kalau kamu tahu apa yang terjadi berikutnya, curang saja. Masa depan telah merembes ke masa lalu lewat selusin celah kecil yang tampak tak berbahaya, dan setiap celah itu memberi imbalan kepada sistem saya atas semacam kemampuan meramal yang tidak akan pernah, sama sekali tidak akan, ia miliki saat uang sungguhan dipertaruhkan.

Bug paling menggoda dalam backtesting

Nama umum untuk hal ini adalah look-ahead bias, atau kebocoran (leakage). Ini terjadi setiap kali sebuah keputusan dalam simulasi Anda dibiarkan menggunakan informasi yang, dalam kehidupan nyata, belum akan ada pada saat keputusan itu dibuat.

Ini layak direnungkan, karena lebih halus daripada kedengarannya. Sebuah backtest seharusnya menjadi pemeranan ulang sejarah yang setia: pada setiap momen, sistem hanya boleh tahu apa yang sungguh-sungguh dapat diketahui pada momen itu, dan ia harus bertindak hanya berdasarkan itu. Kebocoran adalah setiap retakan pada dinding tersebut — setiap tempat di mana secuil informasi hari esok menyelinap ke dalam keputusan hari ini. Dan begitu hal itu terjadi, backtest Anda berhenti mengukur “bagaimana hasilnya seandainya ini dijalankan” dan mulai mengukur “bagaimana hasilnya seandainya ini bisa mengintip.”

Bagaimana masa depan menyelinap masuk

Saya ingin berhati-hati di sini untuk tidak menjelaskan rincian sistem saya sendiri, jadi izinkan saya menjaga pembahasan ini pada tingkat bentuk-bentuk umum yang diambil kebocoran semacam ini, karena bentuk-bentuk itu sangat lazim.

Satu bentuk klasik: menggunakan sebuah nilai dalam suatu keputusan, padahal nilai itu baru benar-benar difinalisasi setelah momen di mana Anda berpura-pura mengambil keputusan. Bentuk lain: menyiapkan data Anda dengan menskalakan atau menormalisasinya menggunakan statistik — sebuah rata-rata, rentang, ukuran tipikal — yang dihitung atas seluruh riwayat, termasuk bagian yang, pada momen simulasi Anda, belum terjadi. Bentuk lain lagi: menyaring atau melabeli data Anda dengan keuntungan tinjauan ke belakang, secara diam-diam mengecualikan kasus-kasus dengan cara yang hanya bisa Anda lakukan jika Anda sudah tahu bagaimana akhirnya.

Masing-masing ini adalah satu baris kode yang tampak masuk akal. Tak satu pun terasa seperti kecurangan saat Anda menulisnya. Dan setiap satunya menyodorkan kepada sistem Anda sebuah aliran kecil informasi yang stabil dari masa depan.

Mengapa ini begitu sulit ditangkap

Hal paling kejam tentang kebocoran adalah ia tidak tampak seperti bug. Kode berjalan tanpa error. Tidak ada yang crash. Dan hasil yang dihasilkannya bukanlah tanda bahaya — melainkan angka yang luar biasa. Angka yang luar biasa tidak memicu kecurigaan pada kebanyakan orang. Angka itu memicu perayaan, sebuah tangkapan layar, perasaan tenang bahwa Anda mungkin sedang menemukan sesuatu.

Itulah persisnya yang membuat kelas bug ini begitu berbahaya. Ia bersembunyi di dalam hasil yang tampak seperti keberhasilan, yang merupakan tempat paling buruk bagi sebuah bug untuk bersembunyi, karena keberhasilan adalah satu-satunya hasil yang paling tidak Anda termotivasi untuk Anda interogasi. Sebuah crash menuntut untuk diperbaiki. Sebuah equity curve yang indah mengundang Anda untuk berhenti memeriksa.

Petunjuknya: hasil yang terlalu bagus untuk jadi kenyataan

Untuk waktu yang lama, satu-satunya alarm andal yang saya punya adalah ketidakpercayaan saya sendiri. Ketika sebuah backtest kembali dengan hasil yang jauh lebih baik daripada apa pun yang secara wajar bisa Anda harapkan — lebih mulus, lebih menguntungkan, lebih konsisten daripada yang seharusnya diizinkan oleh pasar — hipotesis pertama yang benar bukanlah “Saya telah menemukan sesuatu yang brilian.” Melainkan “informasi sedang bocor di suatu tempat, dan saya harus menemukannya.”

Ini adalah prior yang sungguh berguna, dan saya jadi memegangnya dengan kuat: dalam sebuah backtest, keunggulan jauh lebih sering merupakan gejala dari sebuah bug ketimbang bukti adanya keunggulan nyata. Pasar itu sulit. Hasil yang menyiratkan bahwa pasar itu mudah biasanya sedang memberi tahu Anda tentang kode Anda, bukan tentang pasar.

Menemukan kebocoran

Pekerjaan sesungguhnya untuk memburu kebocoran itu membosankan dan sama sekali tidak glamor, dan tidak ada jalan pintas cerdik yang saya temukan yang bisa menggantikannya. Disiplinnya begini: ambil setiap nilai yang masuk ke dalam sebuah keputusan, dan telusuri mundur ke momen persis ketika nilai itu akan menjadi diketahui dalam kehidupan nyata. Lalu tanyakan, terus terang, “pada saat saya berpura-pura bertindak, apakah saya benar-benar sudah bisa memiliki angka ini?”

Sebagian besar kebocoran, ketika akhirnya Anda sudutkan, ternyata hanya sebesar kecurangan senilai satu cap waktu — sebuah nilai yang dipakai sesaat sebelum ia benar-benar akan ada, sebuah perhitungan yang menjangkau satu langkah lebih jauh ke dalam data daripada yang diizinkan. Celah-celah kecil. Tapi sebuah celah kecil, yang diulang melintasi ribuan keputusan, sudah cukup untuk memproduksi seluruh kekayaan khayalan.

Prinsip yang lebih dalam: hormati anak panah waktu

Di balik semua ini ada satu prinsip yang kini saya perlakukan nyaris seperti sesuatu yang sakral: hormati anak panah waktu. Sebuah backtest, pada hakikatnya, adalah sebuah janji — janji bahwa Anda hanya pernah menggunakan masa lalu untuk bertindak di masa kini, tidak pernah masa depan. Setiap kebocoran adalah sebuah janji kecil yang dilanggar, sebuah tempat di mana kode Anda diam-diam menjangkau ke depan dalam waktu untuk menolong dirinya sendiri.

Jadi membangun sebuah simulasi yang tepercaya ternyata jauh lebih sedikit soal pemodelan yang cerdas dan jauh lebih banyak soal mempertahankan sebuah batas: garis antara apa yang diketahui pada suatu momen dan apa yang sekadar dapat diketahui belakangan. Sebagian besar upaya rekayasa, bagian yang tak seorang pun menulis utas penuh kekaguman tentangnya, hanyalah menjaga batas itu dari kecenderungan kode Anda sendiri yang konstan dan sembarangan untuk mengintip.

Mengapa kini saya tidak memercayai hasil terbaik saya

Perubahan yang bertahan dari semua ini adalah bahwa hubungan saya dengan kabar baik menjadi terbalik. Sebuah backtest yang mengecewakan ya sekadar mengecewakan; saya melihatnya, mengangkat bahu, dan melanjutkan. Sebuah backtest yang spektakuler kini membuat saya gugup sebelum membuat saya senang. Semakin bagus hasilnya, semakin keras saya mencari kebocoran yang menghasilkannya.

Kedengarannya tak menyenangkan, dan kadang memang begitu. Tapi itu lahir dari rasa hormat yang diperoleh dengan susah payah terhadap bagaimana permainan khusus ini menghukum penipuan diri. Kebohongan paling berbahaya yang akan pernah disampaikan sebuah sistem kepada Anda bukanlah kegagalan yang buruk rupa. Melainkan keberhasilan yang menawan — yang tampak persis seperti hal yang Anda harapkan untuk ditemukan, dan justru karena itu adalah yang terakhir Anda pikirkan untuk diragukan.

— Tanpa sinyal, tanpa imbal hasil, bukan nasihat investasi.