Bir backtest çalıştırdıktan 6 hafta sonra, aynı kod, yapılandırma ve tarih aralığıyla tekrar çalıştırdık. Dönem sonu özsermayesi farklıydı. Fark çok büyük değildi ama Sharpe oranını 1.31’den 1.08’e düşürmeye ve en iyi görünen parametre kümesini değiştirmeye yetti.
Strateji değişmemişti. Geçmiş veriler değişmişti. Bir sağlayıcı birkaç günlük işlemleri ve barları revize etmişti; ilk çalıştırmamızda da kullanılan girdinin tam anlık görüntüsünü saklamamıştık. Sonraki birkaç günü, yeni sonucun bir veri düzeltmesinden mi, işlem hattı hatasından mı, yoksa yeniden üretemediğimiz bir araştırma sürecinden mi kaynaklandığını anlamaya çalışarak geçirdik.
Pazartesi: yeniden çalıştırma farklı sonuç verdi
İlk ipucu, likit bir spot paritedeki küçük bir farktı. İlk barımızın en yüksek değeri 62,418’di. Yeniden çalıştırmada 62,431 çıktı. Bu fark, stratejinin girişini izleyene kadar önemsiz görünüyordu: eşik bu iki fiyatın arasındaydı. Değişen birkaç bar farklı sinyaller, bu da birkaç gün sonra farklı pozisyonlar anlamına geliyordu.
Günlük işlem sayılarını karşılaştırdık ve uyuşmazlığın tek bir tarihte başladığını gördük. Ardından o tarihe girdi sağlayan ham satırları karşılaştırdık. Sağlayıcının güncel yanıtında birkaç düzeltilmiş işlem ve revize edilmiş bir toplulaştırılmış bar vardı. Kullandığımız yanıta herhangi bir değişiklik günlüğü eklenmemişti.
Bu, verilerde olağan bir durumdur. Borsalar kayıtları düzeltir; sağlayıcılar eksikleri tamamlar, hatalı işlemleri düzeltir ve toplulaştırma mantığını günceller. “Ocak verisi” sorgusu, Mart ayında farklı bir yanıt döndürebilir.
Salı: eksik makbuzu bulduk
Çalıştırma kaydında sağlayıcının adını, sembolü ve tarih aralığını saklamıştık. Yanıtın kendisini veya her girdi bölümünün içerik özetini saklamamıştık. Yani ne istediğimizi kanıtlayabiliyorduk ama sağlayıcının hangi baytları döndürdüğünü kanıtlayamıyorduk.
Bulabildiğimiz en eski önbellek dosyalarını aldık ve güncel yanıtla karşılaştırdık. Fark, bölünme düzeltmesi ya da saat dilimi dönüşümü değildi. Bar oluşturucumuzdan geçen az sayıda düzeltilmiş işlem kaydıydı. Bu, olasılıklardan birini eledi; ancak önbellek eksikti, dolayısıyla etkilenen her barı tam olarak yeniden oluşturamıyorduk.
| Kaydettiğimiz | Yanıtlamamızı sağladığı soru | Eksik olan |
|---|---|---|
| Sağlayıcı, sembol, tarih aralığı | Çalıştırmanın hangi isteği yaptığı | Yanıtın içeriği |
| İşlem hattı sürümü | Barları hangi kodun oluşturduğu | Tam girdi satırları |
| Çalıştırma zaman damgası | İşi ne zaman çalıştırdığımız | O sırada hangi sağlayıcı revizyonunun mevcut olduğu |
“Aynı sorgu”yu “aynı veri” olarak kabul etmiştik. Bu varsayım, deneyi gerçekte olduğundan daha yeniden üretilebilir göstermişti.
Çarşamba: düzeltme anlatıyı değiştirdi
Etkilenen tarihleri, mevcut verinin her iki sürümüyle yeniden oynattık. Revize edilmiş barlar iki girişi kaldırdı ve bir çıkışı 1 bar öne aldı. Sharpe değişiminin büyük kısmı bu 3 işlemden kaynaklanıyordu. Genel fiyat serisi grafikte neredeyse aynı görünse de strateji, tetikleyicisine yakın birkaç gözleme duyarlıydı.
Bu, ilk sonucun sahte olduğu ya da revize edilmiş sonucun otomatik olarak daha iyi olduğu anlamına gelmiyordu. İddianın kapsamını belirtmemiz gerektiği anlamına geliyordu: eski çalıştırma, o sırada elimizde bulunan veri anlık görüntüsünü; yeniden çalıştırma ise sağlayıcının güncel geçmiş verilerini yansıtıyordu. Birini diğerinin tekrarı olarak dürüstçe nitelendiremezdik.
Perşembe: araştırma kaydını değiştirdik
Yeni araştırma çalıştırmalarına değiştirilemez girdi anlık görüntüleri ekledik. Her bölüm için bir içerik özeti hesaplanıyor; çalıştırma manifestinde kaynak, verinin alınma zamanı, şema sürümü, düzeltme politikası ve dönüşüm kodunun sürümü kaydediliyor. Büyük veri kümelerinde, aynı bölümleri önceki sürümlerin üzerine yazmadan paylaşabilmek için dosyaları içerik adresli depolamada tutuyoruz.
Depolama veya lisans koşulları ham veriyi saklamamızı engellediğinde, koşulların izin verdiği en sağlam makbuzu koruyoruz: özetler, istek parametreleri, kaynak revizyon tanımlayıcıları ve tanılama için ayrıştırılmış satırlardan küçük bir örnek. Bir özet veriyi geri getiremez ama iki çalıştırmanın aynı baytları tüketmediğini gösterebilir.
Yeniden üretilebilir bir backtest için yalnızca veri URL’si değil, girdinin kimliği gerekir. Nelerin geldiğini, ne zaman geldiğini ve stratejinizin tükettiği satırlara nasıl dönüştüğünü kaydedin.
Cuma: bir dahaki sefere atlayacaklarımız
Yalnızca özet metrikleri karşılaştırmayı atlayacağız. Sharpe’ın değişmesi, bir şeylerin değiştiğini söyler; nedeni göstermez. Önce satır sayılarına ve bölüm özetlerine bakın, ardından farklılaşan ilk girdi tarihini bulun. Sonra dönüştürülmüş satırları, sinyalleri, emirleri ve gerçekleşen işlemleri bu sırayla karşılaştırın.
Eski verileri düzeltilmiş geçmişle sessizce değiştirmeyi de atlayacağız. Düzeltmeler yararlıdır ama eski çalıştırmalar özgün girdilerine bağlı kalmalıdır. Yeni bir veri kümesi, eskisiyle ilişkisi görünür olan yeni bir çalıştırma oluşturmalıdır.
Artık pratik kuralımız basit: yeniden çalıştırma bir deneyi tekrarlamak için yapılıyorsa veri anlık görüntüsünü sabitleyin. Düzeltilmiş geçmişten yararlanmak için yapılıyorsa yeni bir deney olarak etiketleyin. Bu ayrımı öğrenmemiz birkaç gün sürdü; şimdi çalıştırma manifestinde tek satırla belirtiyoruz.
← Tüm yazılar


