Υπάρχει μια ερώτηση που κάθε backtest αποφεύγει: ο ίδιος κώδικας, τροφοδοτούμενος με την ίδια αγορά ζωντανά, θα έκανε το ίδιο πράγμα; Δεν την απαντάς με περισσότερο backtesting. Την απαντάς μόνο τρέχοντας τη στρατηγική πάνω σε ζωντανά δεδομένα με πραγματική σημασιολογία εκτέλεσης, και ελέγχοντας μετά — συναλλαγή προς συναλλαγή — ότι οι δύο κόσμοι συμφωνούν. Αυτόν τον έλεγχο τον κάνουμε κάθε μέρα, αυτόματα, και είναι μακράν ο πιο παραγωγικός ανιχνευτής bugs σε όλη την πλατφόρμα.
Μέρα πρώτη: στήσε τον καθρέφτη
Κάθε προαχθείσα στρατηγική τρέχει στον δικό της απομονωμένο ζωντανό κόμβο, καταναλώνοντας πραγματικές ροές του exchange: ζωντανά quotes για τα fills, πραγματικά spreads, πραγματικές ώρες συνεδρίας. Καμία κοινή κατάσταση μεταξύ στρατηγικών (αυτό το μάθαμε με τον δύσκολο τρόπο — ένας κοινός κόμβος άφηνε τα position queries της μιας στρατηγικής να διαρρέουν στην άλλη). Κάθε fill καταγράφεται μαζί με την τιμή σήματος που το παρήγαγε.
Κάθε πρωί: replay και σύγκριση
Μια καθημερινή εργασία παίρνει το paper παράθυρο κάθε στρατηγικής, τρέχει τον πανομοιότυπο κώδικα μέσα από τη μηχανή backtest για την ίδια περίοδο πάνω σε δεδομένα καταλόγου, και αντιστοιχίζει τα fills ένα προς ένα: ίδια πλευρά, ίδια ανοχή χρονοσήμανσης, ίδιο μέγεθος. Το αποτέλεσμα δεν είναι κάποια συσχέτιση ή μια γενική αίσθηση. Είναι ένας πίνακας: αντιστοιχισμένα, μόνο-paper, μόνο-replay. Μια υγιής στρατηγική κάθεται στα 54 από 55 αντιστοιχισμένα. Μια ανθυγιεινή σου λέει ακριβώς ποια συναλλαγή απέκλινε και πότε.
Τι έσπασε, με τη σειρά που έσπασε
- Fills κατά το warmup. Ο ζωντανός κόμβος τροφοδοτούσε ιστορικό για να ζεστάνει τους δείκτες — και οι στρατηγικές με custom bar handlers έκαναν χαρούμενα συναλλαγές πάνω σε αυτό. Τα backtests δεν είδαν ποτέ αυτές τις φαντασματικές εισόδους. Η διόρθωση μπήκε στο επίπεδο υποβολής εντολών, όχι στη στρατηγική, γιατί αλλιώς κάθε στρατηγική κληρονομεί το bug.
- Σειριακό warmup πολλαπλών σκελών. Μια cross-sectional στρατηγική ζέσταινε ένα instrument τη φορά· κάθε σκέλος έβλεπε άδεια τα αδελφά του και το anchor δεν αρχικοποιούνταν ποτέ. Ζωντανά, δεν έκανε καμία συναλλαγή· στο replay, δούλευε μια χαρά. Μηδέν αντιστοιχισμένες συναλλαγές — αλλά μόνο η σύγκριση το είπε δυνατά.
- Crash loops από ακρίβεια tick. Τα ζωντανά aggTrade ticks φτάνουν με διαφορετική ακρίβεια από αυτήν που περίμενε το instrument του sandbox. Ο κόμβος έμπαινε σε crash loop πάνω σε ένα assertion που το backtest δεν θα μπορούσε ποτέ να ενεργοποιήσει, γιατί τα bars του καταλόγου είναι ήδη κανονικοποιημένα.
- Αμνησία μετά από restart. Οι επανεκκινήσεις της διεργασίας ξαναπυροδοτούσαν τη λογική εισόδου πάνω σε θέσεις που υπήρχαν ήδη — για μια στρατηγική εξισορρόπησης, ένα restart γινόταν σιωπηλά ένα rebalance. Στο ζωντανό trading αυτό δεν είναι υποσημείωση αντιστοιχίας· είναι κόκκινη σημαία με χρήματα από πάνω.
Πρόσεξε το μοτίβο: κανένα από αυτά δεν είναι bug σήματος. Είναι όλα bugs στο όριο της εκτέλεσης — warmup, κατάσταση, ακρίβεια, restarts. Είναι ακριβώς η κατηγορία αστοχίας που τα backtests, δομικά, δεν μπορούν να δουν, γιατί σε ένα backtest η ίδια η μηχανή backtest είναι το όριο εκτέλεσης.
Οι ασυμμετρίες που κρατάμε επίτηδες
Οι δύο κόσμοι δεν είναι πανομοιότυποι, και αυτό είναι σκόπιμο. Το backtest χρεώνει ένα μοντελοποιημένο μισό spread συν επίδραση τετραγωνικής ρίζας μέσα στο PnL· το paper πληρώνει το πραγματικό spread στην τιμή του fill και κανένα μοντέλο επίδρασης. Αν προσθέταμε το μοντελοποιημένο spread στο paper (ή το πραγματικό στα backtests) θα το μετρούσαμε δύο φορές. Αντιστοιχία σημαίνει ίδιες αποφάσεις, ίδια fills εντός ανοχής — όχι PnL πανομοιότυπο στο bit. Το να ξέρεις ποιες διαφορές είναι θεμιτές και ποιες είναι bugs αποτελεί το μεγαλύτερο μέρος της πειθαρχίας.
Το backtest είναι μια υπόθεση. Το paper trading είναι το πείραμα. Η αντιστοιχία replay είναι το εργαστηριακό ημερολόγιο που σε πιάνει να ξεγελάς τον εαυτό σου.
Αν τρέχεις στρατηγικές και δεν συγκρίνεις τη ζωντανή συμπεριφορά με τη συμπεριφορά στο replay σε τακτική βάση, έχεις μια ολόκληρη κατηγορία bugs που δεν έχεις δει ποτέ. Εμείς βρίσκουμε ένα περίπου κάθε δύο εβδομάδες, και το καθένα ήταν αόρατο από μέσα από το backtest.
← Όλα τα άρθρα
