Ми повторно запустили збережений бектест і отримали іншу криву капіталу. Той самий код стратегії, той самий діапазон дат, той самий символ. Кінцевий баланс відрізнявся на 1.8%, а три угоди зсунулися на один бар.
Цього достатньо, щоб результатам дослідження стало важко довіряти. Якщо колега, ви самі в майбутньому або сервіс паперової торгівлі не можуть відтворити запуск, неможливо зрозуміти, чи поліпшила зміна стратегію, чи просто змінила експеримент. Ось послідовність, за якою ми шукали джерело розбіжностей.
День 1: Ми визначили, що означає «той самий запуск»
Нашою першою помилкою було вважати файл стратегії самим експериментом. Це було не так. Запуск також залежав від вхідних даних, версії рушія, календаря, метаданих інструментів і налаштувань виконання. Код описував лише одну частину розрахунку.
Перш ніж щось змінювати, ми склали маніфест запуску. У ньому зафіксували коміт стратегії, ідентифікатори знімків даних, діапазон дат, майданчик, тариф комісій, джерело даних про фінансування, модель виконання та версії програмного забезпечення. Ми також зберегли ордери й виконання, адже сама крива капіталу не показує, де саме два запуски вперше розійшлися.
| Артефакт | Що фіксувати | Чому це важливо |
|---|---|---|
| Ринкові дані | ID знімка, версія схеми, коригування | Постачальники виправляють історію та переглядають корпоративні події |
| Виконання ордерів | Рівень комісій, ряд даних про фінансування, налаштування виконання й впливу на ринок | Значення за замовчуванням і припущення щодо рахунку змінюють результати |
| Середовище виконання | Коміт коду, версії рушія та залежностей | Бібліотеки можуть змінювати порядок, округлення або індикатори |
| Результат | Ордери, виконання, позиції та метрики | Показує, де запуски починають розходитися |
День 2: Ми порівняли угоди, а не Sharpe
Підсумкові метрики відвертали увагу. Значення Sharpe в обох запусках були майже однаковими, але журнали виконання показали першу невідповідність під час розрахунку фінансування. В одному запуску ставку застосували до позиції, відкритої на момент розрахунку, а в іншому — до позиції після ребалансування на цій часовій позначці.
Код стратегії не змінювався. Змінився порядок подій у рушії. Невелике оновлення версії зробило послідовність явною — раніше вона залежала від того, як випадково сортувалися дві події.
Ми уточнили контракт запуску, зафіксувавши порядок: спершу застосовувати фінансування до позиції, перенесеної на момент розрахунку, а потім обробляти рішення стратегії для цієї часової позначки. Точна домовленість може відрізнятися залежно від майданчика й рушія. Помилка — залишати її неявною.
День 3: Файл даних, який мав бути «тим самим», виявився іншим
Після фіксації порядку подій решта невідповідностей зосередилася в кількох угодах з акціями. Постачальник скоригував історичні дані про спліт. Наш файл мав ту саму назву й кількість рядків, що й раніше, тому здавався незмінним.
Тепер ми створюємо відбиток кожного незмінного знімка даних і зберігаємо поруч політику коригувань. Хеш показує, чи змінилися байти, але не пояснює причину. Тому в маніфесті також зазначаємо джерело, час отримання й версію перетворення. Для даних, які переглядають, ці деталі є частиною результату.
Для відтворюваного бектесту потрібна відповідь на запитання: «Яку саме версію минулого він бачив?»
День 4: Ми знайшли непомітне значення за замовчуванням
Останньою відмінністю була комісія maker, встановлена на 0, оскільки в конфігурації стратегії це поле було пропущене. Новіша версія рушія застосувала комісію за замовчуванням для рахунку. Це єдине значення змінило граничні угоди настільки, що пояснило більшу частину різниці в кінцевому балансі.
Ми явно вказали економічно значущі налаштування й налаштували рушій так, щоб він записував остаточну конфігурацію до журналу запуску. Значення за замовчуванням зручні під час досліджень. Але коли порівнюєш результати в різний час, на них не можна покладатися як на доказ.
Що наступного разу ми пропустили б
Ми витратили пів дня на порівняння сукупних метрик, перш ніж подивитися на перше виконання, що відрізнялося. Не починайте з цього. Відсортуйте обидва журнали подій за часовою позначкою й порівняйте першу розбіжність: подальші відмінності часто є її наслідком.
Ми також відмовилися б від думки, що сам по собі образ контейнера робить запуск відтворюваним. Він фіксує більшу частину програмного середовища, але не зовнішній файл даних, тариф комісій, отриманий під час виконання, чи переглянуту постачальником історію.
Коли бектест змінюється, збережіть маніфести й журнали обох запусків, а потім виправляйте джерела розбіжностей по одному. Корисний результат — це не лише крива, яку можна відтворити повторним запуском. Це запис, що пояснює, які дані й припущення її сформували та чому наступний запуск може відрізнятися.
← Усі статті


