Корисний тест бектесту не має стосунку до пошуку кращого параметра: зупиніть процес посеред роботи, відновіть його й завершіть те саме відтворення. За однакових вхідних даних і контрольованого симулятора виконання рішення, ордери та капітал мають збігатися з безперервним запуском.
Якщо це не так, ви виявили проблему керування станом. Стратегія залежить від чогось, що ви не зберегли або не змогли відновити. Ця залежність має значення, коли дослідницькі запуски продовжують, виконавців замінюють або сервіс паперової торгівлі розгортає новий код.
Мені подобається цей тест, бо очікувана відповідь тут напрочуд однозначна. Не потрібно сперечатися про те, чи змінився ринок. Обидва запуски отримують той самий ринок.
Ось три хибні способи перезапуску. Числа наведено для прикладу; кожен збій може статися в системі, яка в усьому іншому є детермінованою.
1. Завантажити кілька барів і вважати індикатори прогрітими
Припустімо, стратегія використовує експоненціальну ковзну середню з періодом 100. Її оновлення обчислюється так:
alpha = 2 / 101
ema_next = alpha * close + (1 - alpha) * ema_previous
Безперервно запущений процес зберігає накопичене значення EMA. Після перезапуску процес завантажує 100 барів, задає початкове значення EMA за ціною закриття першого й припускає, що для індикатора з періодом 100 достатньо 100 спостережень.
Це припущення плутає параметр згладжування індикатора з вікном скінченної пам’яті. EMA зберігає внесок початкового стану, що поступово згасає. Якщо початкові значення EMA у двох версіях відрізняються на 10 одиниць ціни, однакові наступні ціни зменшуватимуть цю різницю так:
| Оновлень після ініціалізації | Залишкова різниця | Частка початкової похибки |
|---|---|---|
| 100 | 1.353 | 13.53% |
| 250 | 0.0674 | 0.674% |
| 500 | 0.000454 | 0.00454% |
Розрахунок такий: 10 * (99 / 101)^k. Якщо перше спостереження задає початкове значення, завантаження 100 барів дає лише 99 оновлень.
Наслідки зазвичай проявляються поблизу порога ухвалення рішення. В одному запуску ціна вища за EMA, в іншому — нижча. Невелика числова різниця породжує цілу додаткову угоду. А далі можуть розійтися й періоди очікування, доступні кошти та наступні рішення.
Зберігайте рекурсивний стан індикатора, ознаку його ініціалізації та останню оброблену подію. Як варіант, відтворюйте дані від відомого початкового стану. Довший період прогріву може дати прийнятне наближення, але його тривалість слід обирати відповідно до чіткого допуску похибки й перевіряти, чи може ця похибка змінити рішення. «П’ять періодів» — це домовленість, а не доказ.
Та історія не обмежується індикаторами. Для ковзного процентиля потрібне його вікно. Онлайн-моделі може знадобитися стан оптимізатора. Правило, яке після збитку чекає 3 бари, має пам’ятати про збиток і лічильник.
2. Зберегти позиції й забути про активні ордери
Цільова позиція — 10 одиниць. Ордер на купівлю 10 одиниць виконано на 4, ще 6 залишаються в роботі. Ви зберігаєте позицію як 4, перезапускаєте процес і подаєте ще один ордер на купівлю відсутніх 6.
Якщо виконаються і початковий залишок, і новий ордер, ваша позиція становитиме 16 одиниць.
У бектесті ця помилка часто лишається непомітною, бо під час перезапуску рушій виконання мовчки видаляє активні ордери. У паперовій торгівлі симулятор або зовнішній сервіс може їх зберегти. Тоді той самий код відновлення дає різну експозицію залежно від того, який компонент пережив перезапуск.
| На момент перезапуску | Фактичний стан | Що бачить відновлення лише за позицією |
|---|---|---|
| Цільова позиція | 10 | 10 |
| Виконана позиція | 4 | 4 |
| Невиконана кількість за ордером на купівлю | 6 | 0 |
| Скільки ще потрібно докупити | 0 | 6 |
Наслідком стає незрозумілий сплеск ордерів одразу після відновлення. Іноді експозиція подвоюється. Іноді закривається позиція, хоча захисний ордер іще активний, тож згодом він може відкрити нову позицію.
Разом із позиціями контрольна точка має зберігати ідентифікатори ордерів та етапи їхнього життєвого циклу. Перш ніж генерувати нові дії, під час відновлення потрібно звірити ці записи із системою виконання. Якщо результат ордера невідомий, його треба з’ясувати: припущення, що «немає збереженого підтвердження» означає «ордер не подавався», і породжує дублікати.
Стабільні клієнтські ідентифікатори ордерів допомагають з’ясувати, що сталося. Вони запобігають дублюванню лише тоді, коли система-отримувач справді забезпечує потрібну унікальність або ідемпотентність. Зберігайте також ідентифікатори вже оброблених виконань, щоб повторно відтворений fill не збільшив позицію двічі.
Я небайдужий до нудного екрана зі статусами ордерів. У день перезапуску його непоказні рядки раптом стають найцікавішим інтерфейсом у всій будівлі.
3. Відновити позицію й почати новий журнал прибутку та збитку
Розгляньмо приклад із купівлею спотового активу без кредитного плеча та комісій. Маємо $10,000 готівкою, купуємо 10 одиниць по $100 і зберігаємо контрольну точку, коли поточна оціночна ціна сягає $110.
Правильний стан: $9,000 готівкою плюс позиція вартістю $1,100, тобто капітал становить $10,100. Якщо під час відновлення повернути 10 одиниць, але скинути готівку до початкових $10,000, система покаже $11,100. Перезапуск процесу створив вам $1,000 з повітря.
Інші варіанти менш разючі. Відновлення зберігає загальний капітал, але скидає ціну входу до $110. Загальний капітал може лишитися правильним, тоді як розподіл на реалізований і нереалізований прибуток зміниться. Якщо стоп або умова виходу залежить від ціни входу, цей бухгалтерський обхідний шлях змінює торгову поведінку.
Або система забуває попередній максимум капіталу. Припустімо, капітал сягнув піку $10,600, а потім упав до $10,100. Просадка становить близько 4.72%. Якщо під час відновлення скинути максимум капіталу, стратегія раптом вважатиме, що просадки немає. Будь-який контроль ризику, прив’язаний до просадки, щойно отримав несанкціоноване скидання.
Наслідком може бути стрибок капіталу, підозріле зменшення просадки або припинення спрацювання правила ризику після розгортання оновлень. Зберігайте журнал і залежний від обліку стан стратегії: рух коштів, позиції, відповідну собівартість, нараховані витрати та пам’ять контролю ризику. Звіряйте відновлений капітал із журналом на ту саму мить оцінки.
Контрольна точка має відповідати узгодженій межі. Якщо зберегти готівку після виконання, а кількість позиції — до нього, ви отримаєте стан, якого ніколи не існувало. Фіксуйте пов’язаний стан разом або записуйте надійну послідовність подій, з якої його можна відновити. Зберігайте курсор подій разом зі станом, щоб під час відновлення виконання не пропустити й не застосувати двічі.
У дослідницькому середовищі я б залишив тест із безперервним еталонним відтворенням, а потім перезапускав би другий запуск у навмисно незручні моменти: під час ініціалізації індикатора, після часткового виконання ордера та поки діє ліміт ризику. Використовуйте той самий порядок подій і зберігайте стан генератора випадкових чисел симулятора. Порівнюйте перше рішення після відновлення, записи ордерів і виконань та траєкторію капіталу. Однаковий кінцевий баланс може приховувати взаємно компенсовані помилки.
Щоб перевірити збій після подання ордера, але до отримання підтвердження, середовище має окремо зберігати стан сервісу виконання. Інакше воно видалить саме ту невизначеність, яку ви намагаєтеся перевірити.
Специфікація стратегії визначає і те, що вона пам’ятає. Опишіть цю пам’ять достатньо чітко, щоб можна було зупинити процес посеред відтворення й показати, як саме він повернеться до роботи.
← Усі статті


