Є питання, від якого ухиляється будь-який бектест: чи зробив би той самий код те саме, якби годувати його живим ринком? Відповіді на нього не дасть іще один бектест. Її можна отримати лише тоді, коли ви запускаєте стратегію на живих даних із реальною семантикою виконання, а потім перевіряєте — угода за угодою, — що обидва світи збігаються. Ми робимо цю перевірку щодня, автоматично, і вона стала найпродуктивнішим шукачем багів у всій платформі.
День перший: будуємо дзеркало
Кожна просунута стратегія працює у власному ізольованому живому вузлі й споживає реальні біржові потоки: живі котирування для виконань, реальні спреди, реальні години сесії. Жодного спільного стану між стратегіями (цей урок ми засвоїли на власних синцях — у спільному вузлі запити позицій однієї стратегії протікали в іншу). Кожне виконання записується разом зі значенням сигналу, яке його породило.
Щоранку: реплей і diff
Щоденне завдання бере паперове вікно кожної стратегії, проганяє ідентичний код через бектест-двигун за той самий період на даних каталогу й зіставляє виконання один до одного: той самий бік, той самий допуск за часовою міткою, той самий розмір. На виході — не кореляція і не «загальне відчуття». Це таблиця: зіставлені, лише в папері, лише в реплеї. Здорова стратегія тримається на рівні 54 із 55 зіставлених. Нездорова прямо каже вам, яка саме угода розійшлася і коли.
Що ламалося — у тому порядку, в якому ламалося
- Виконання на прогріві. Живий вузол згодовував історію, щоб прогріти індикатори, — і стратегії з власними обробниками барів радо на ній торгували. Бектести цих фантомних входів ніколи не бачили. Виправлення зробили на рівні шару подання заявок, а не в самій стратегії, бо інакше цей баг успадковує кожна стратегія.
- Послідовний прогрів кількох ніг. Крос-секційна стратегія прогрівала по одному інструменту за раз; кожна нога бачила порожніх сусідів, і якір так і не ініціалізувався. Наживо вона не торгувала нічого; у реплеї торгувала нормально. Нуль зіставлених угод — але сказав про це вголос лише diff.
- Краш-цикли через точність тіків. Живі тіки aggTrade приходять з іншою точністю, ніж очікує інструмент у пісочниці. Вузол зациклювався на падінні через асерт, який бектест не міг би викликати в принципі, бо бари в каталозі вже нормалізовані.
- Амнезія після перезапуску. Перезапуски процесу повторно запускали логіку входу на вже наявних позиціях — для ребалансуючої стратегії перезапуск тихцем перетворювався на ребалансування. У живій торгівлі це вже не виноска про паритет; це червоний прапорець із реальними грошима.
Зверніть увагу на закономірність: жоден із цих багів не стосується сигналу. Усі вони — баги межі виконання: прогрів, стан, точність, перезапуски. Це рівно той клас відмов, до якого бектести структурно сліпі, бо в бектесті сам двигун і є межею виконання.
Асиметрії, які ми лишаємо навмисно
Ці два світи свідомо не ідентичні. Бектест закладає в PnL модельований половинний спред плюс вплив за кореневим законом; папір платить реальний спред у ціні виконання й не має моделі впливу. Додати модельований спред у папір (або реальний — у бектести) означало б порахувати його двічі. Паритет — це ті самі рішення, ті самі виконання в межах допуску, а не побітово однаковий PnL. Розуміти, які розбіжності принципові, а які є багами, — це й становить більшу частину дисципліни.
Бектест — це гіпотеза. Паперова торгівля — експеримент. Паритет реплею — лабораторний журнал, який ловить вас на самообмані.
Якщо ви запускаєте стратегії й не порівнюєте живу поведінку з реплейною за розкладом, у вас є цілий клас багів, якого ви ніколи не бачили. Ми знаходимо по одному приблизно раз на кілька тижнів — і кожен був невидимим зсередини бектесту.
← Усі статті
