Розробка системи бектестингу з підтримкою multi-timeframe

Сигнали на різних таймфреймах розходяться, і результат прогону не збігається з реальною торгівлею. Ми розробляємо системи мультитаймфреймового бектестингу під ключ: узгоджуємо розрахунок за всіма періодами та скорочуємо час підготовки прогонів у рази. Обговоримо задачу й повернемося з планом робіт.
Часті запитання

Чому multi-timeframe бектестинг ламається на реальних даних

Найчастіша причина — старший таймфрейм читається як уже закритий. Стратегія ухвалює рішення за баром H4, але на цей момент бар ще формується, і частина руху, на якому «спрацював» сигнал, з’явилася вже після входу.

На історії така логіка дає рівну висхідну криву, у робочому контурі — входи за ціною, якої на той момент не існувало.

Друге джерело — розбіжність таймфреймів. Межі барів старшого й молодшого ряду не збігаються: різні торгові сесії, вихідні, пропуски в котируваннях, переходи на літній час.

Вирівнювання за міткою відкриття або підстановка останнього відомого значення затягують у розрахунок дані з майбутнього, а один зсунутий бар змінює не лише вхід, а й усі залежні індикатори.

Третій — підгонка під історію. Чим більше комбінацій параметрів проганяється на одному відрізку, тим вищий шанс, що найкращий результат — випадковість: про це докладно писав Лопес де Прадо.

На старшому таймфреймі угод мало, і «прибуткова» конфігурація часто тримається на десятку входів, які не переживають перенесення на іншу ділянку даних.

Четверта група — помилки прогону стратегій у виконанні та даних: момент спрацювання всередині бару, комісії та прослизання, розриви котирувань, розбіжність історичного й робочого джерела цін за часом надходження.

Розбираємо, як це закривається: від суворого вирівнювання рядів і заборони незакритих барів до перевірки конфігурації на стійкість поза вибіркою.

Ефект від узгодженого розрахунку на кількох таймфреймах

Поки стратегія ухвалює рішення за одним таймфреймом, розрахунок прозорий: один потік свічок, одна часова шкала.

Але щойно додається підтвердження зі старшого періоду, з’являється джерело розбіжностей — молодший бар устигає закритися кілька разів усередині одного старшого, і вхід може спиратися на дані, яких на момент розрахунку ще не було.

Ми збираємо multi-timeframe бектестинг в одному ядрі подій (в основі — Backtrader і власні розширення), тому узгодженість сигналів перевіряється відтворюваним прогоном на історії, а не очима.

Перемальовування індикаторів закриваємо режимом підтверджених барів: значення старшого таймфрейму перераховуються лише в момент його закриття, молодші свічки вирівнюються за межею старшого, а незакритий старший бар виключається з вікна розрахунку.

Це прибирає клас відмов, який у звітах виглядає як гладка крива дохідності й розходиться з реальними угодами.

Час прогону стратегії змінюється нелінійно. Старші серії агрегуються один раз і кешуються, стратегія звертається до готових зрізів, а не перераховує їх на кожному кроці: прогон на трьох таймфреймах дорожчий за одиночний приблизно на 20–40%, а не втричі.

Частка хибних входів падає завдяки фільтру: сигнал молодшого таймфрейму приймається лише за збігу напрямку старшого.

За нашими прогонами таке правило відсікає 30–50% входів проти старшого тренду — але частину прибуткових угод воно теж зрізає, тому поріг підтвердження добирається за метриками, а не вмикається «про всяк випадок».

Формати прогону multi-timeframe бектестингу: історія, потік, гібрид

Режим прогону задає, як стратегія отримує свічки молодшого й старших таймфреймів і в який момент вони стають видимими. За пакетного розрахунку архів котирувань завантажується повністю, старші ряди агрегуються заздалегідь, а цикл іде за загальним масивом. Це найшвидший варіант на довгій історії, але саме тут найчастіше протікає інформація з майбутнього.

Потоковий розрахунок подає події послідовно, свічка за свічкою: старший таймфрейм закривається лише тоді, коли закрилася остання молодша свічка всередині нього.

Підглядання в майбутнє зникає, зате з’являється своя ціна — стан індикаторів доводиться зберігати й коректно перегравати під час переходу між рядами.

Варіант Коли підходить Обмеження
Пакетний розрахунок Налагодження правил входу, перевірка гіпотез на довгій історії, прогон за набором інструментів Витрати пам’яті зростають із числом таймфреймів; синхронізацію закриттів доводиться перевіряти вручну
Потоковий розрахунок Фінальна перевірка стратегії, де критична чесність порядку подій Помітно повільніше; складніше відтворити збійний прогон і налагодити логіку переходу
Гібридна схема Робочий режим multi-timeframe бектестингу: молодший ряд іде потоком, старші рахуються інкрементально Потребує явного правила, у який момент старший таймфрейм вважається доступним

Гібридна схема зазвичай і стає основним режимом: молодший ряд обробляється потоком, старші перераховуються в момент закриття, тому прогон не впирається в обсяг пам’яті й не втрачає достовірність порядку.

Пакетний залишається для швидких перевірок, потоковий — для звірки спірних ділянок на короткому відрізку, де розбіжність результатів видно відразу.

Етапи впровадження: від аудиту даних до передачі контуру

Мультитаймфреймовий бектестинг ламається не на логіці стратегії, а на даних: старші свічки збираються з молодших, і помилка в цьому складанні дає гарну, але хибну криву дохідності.

Тому впровадження починаємо з аудиту джерела, а не з коду, і лише після нього фіксуємо розрахункові правила.

  1. Аудит історичних даних — перевіряємо повноту рядів за інструментами та таймфреймами, шукаємо пропуски, дублі й розриви, звіряємо ціни закриття з незалежним джерелом.
  2. Схема перезбирання свічок — описуємо правила агрегації: межі старшого інтервалу, момент закриття бару, поведінку на неповних і аномальних ділянках.
  3. Налаштування контуру — розгортаємо розрахункове середовище, версіонуємо набори даних і конфігурації, розмежовуємо сховище історії та обчислювальну частину.
  4. Перевірка на стійкість — проганяємо правила на різних періодах і підвибірках, окремо контролюємо підглядання в майбутнє та розбіжність історії з онлайн-потоком.
  5. Приймання розрахунків — звіряємо контрольні приклади й вручну розібрану вибірку угод, фіксуємо допустимі відхилення й поріг, за яким результат вважається недостовірним.
  6. Передача контуру — віддаємо документацію, регламент оновлення даних і доступи, навчаємо команду повторювати розрахунок без нашої участі.

Ключовий принцип: правила агрегації та перевірки живуть в одному місці для історії й реального часу. Інакше результати на історії та в роботі розходитимуться, і довіри до системи не виникне.

Що передаємо на руки: конфігурації, схеми та регламенти

Здача — це не архів із кодом, а набір артефактів, за якими ваша команда сама проганяє тест, змінить параметри й отримає той самий результат. Нижче — те, що залишається у вашому репозиторії та внутрішній базі знань; кожен пункт перевіряємо на прийманні.

  • Конфігурації прогону — окремий профіль на кожен сценарій: склад таймфреймів, правило ресемплінгу старших інтервалів з молодших, вікно синхронізації, комісії та прослизання. Змінюються правкою одного файлу, без втручання в код.
  • Схема даних — джерело свічок, таймзони, момент закриття бару, обробка пропусків і корпоративних дій, плюс чек-ліст валідації на дублі та розриви історії.
  • Еталонний зріз історії — зафіксований набір даних, на якому прогон відтворюється до останньої угоди: за ним звіряють результат після будь-яких правок.
  • Регламент запуску — порядок кроків: підготовка даних, прогрів індикаторів, прогон, збір метрик, розбір розбіжностей; із позначками, де обчислення впирається в ресурси.
  • Політики доступу — ролі та права на зміну конфігурацій, ключі до ринкових даних лише на читання, журнал правок параметрів з автором і причиною.
  • Шаблони звітів — метрики за прогоном, включно з часткою угод, де вхід за молодшим таймфреймом підтверджено старшим, і розбір розбіжностей між інтервалами.
  • Документація — опис моделі даних і домовленостей про час закриття бару, інструкція «як додати новий таймфрейм», журнал змін методики.
  • План передачі — розбір із вашими інженерами та список відкритих питань, які закриваємо після здачі.

Кейс: прибрали розбіжність сигналів на різних таймфреймах

Замовник прийшов із контуром, де стратегія на історії давала рівну криву, а на живих даних — угоди, яких у звіті не було.

Розбір показав розбіжність сигналів: підтвердження надходило зі старшого таймфрейму, а вхід виконувався за молодшим, і частина барів на момент рішення ще не була закрита.

У мультитаймфреймовому бектестингу це типова пастка — ряди склеєні в один прохід, момент закриття бару не враховується, а результат виглядає переконливіше, ніж є.

Що було на вході

Прогон однієї сітки параметрів займав близько трьох годин, тому гіпотези перевіряли пачками вночі. Частка угод, де сигнал старшого таймфрейму розходився з фактичним входом, сягала 6,4% — на дистанції в сотні угод це з’їдало перевагу стратегії.

Покриття обмежувалося двома таймфреймами: додавання третього подвоювало час прогону й ламало відтворюваність.

Що змінили

Розрахунок розвели на незалежні календарі таймфреймів, а рішення ухвалювали строго за фактом закриття бару — сигнал потрапляє у виконання з явним детермінованим лагом.

Агрегати старших рядів рахуються один раз і кладуться в кеш, тому додавання таймфрейму більше не перераховує всю історію. Ядро залишили на Backtrader: бібліотека дає подієву модель, але синхронізацію рядів і порядок виконання довелося вибудовувати вручну.

Що стало

Частка розбіжностей упала до 0,2% — це угоди на межі пропусків у даних, вони позначаються й розбираються окремо. Повний прогон займає 22 хвилини, у сітці тепер чотири таймфрейми замість двох.

Повторний запуск на тих самих даних відтворює результат до останньої угоди, а версія розрахункової конфігурації зберігається разом зі звітом — відкат до попередньої займає хвилини.

Робочий контур тепер один: тестова й жива торгівля читають ті самі правила закриття бару, тому розбіжності між ними перестали бути нормою.

Чим відрізняється перезбирання свічок від потокового розрахунку?

Різниця в тому, у який момент формується значення бару. Перезбирання свічок розгортає первинний потік угод в агрегати заново на кожному прогоні: змінюється таймфрейм, правило закриття бару або фільтр викидів — і вся історія перераховується, даючи відтворюваний результат.

Потоковий розрахунок тримає агрегат інкрементально: стан оновлюється в міру надходження даних, без повторного проходу по історії.

Перезбирання свічок платить за точність розрахунку затримкою даних — поки ряд не розгорнуто й не агреговано, multi-timeframe бектестинг не стартує, а на глибокій історії це помітна пауза.

Потоковий розрахунок відповідає майже миттєво, але його стан живе в пам’яті: у разі розриву каналу або перезапуску агрегатор потрібно відновлювати, інакше бар «поїде».

Підхід Коли підходить Обмеження
Перезбирання свічок Дослідження, зміна логіки, звірка та відтворюваність прогонів Затримка даних на старті, зростає з глибиною історії
Потоковий розрахунок Реальний час, тривалі прогони, інкрементальне оновлення Точність розрахунку залежить від відновлення стану після збою

Робоча схема — гібрид: історію віддаємо перезбиранню свічок, «живий» хвіст рахуємо потоково, а після закриття сесії звіряємо хвіст із повним перерахунком.

Розбіжність навіть в одну свічку на стику — перша ознака, що агрегатор втратив стан, і точність розрахунку на цій ділянці вже не гарантована.

Часті технічні сумніви перед стартом робіт

Сумніви перед стартом зазвичай інженерні: чи вистачить історії, чи не виявиться результат підгонкою під минуле, чи не впремося в контур, коли додадуться нові таймфрейми. Розбираємо чотири питання, які найчастіше вирішують, чи рухатися далі.

Як ви перевіряєте якість історичних даних?

Звіряємо джерело з незалежним, шукаємо пропуски, дублікати й розриви торгових сесій, приводимо бари до єдиного часового поясу.

Для multi-timeframe бектестингу критичне вирівнювання: старший таймфрейм збирається лише із закритих молодших барів, інакше в розрахунок просочується майбутнє. Дані з дірами та невірною агрегацією дають гарну криву на історії й нульовий результат на живому ринку.

Як переконатися, що результат не підігнано під минуле?

Ділимо історію на періоди: налаштування на одному, перевірка на даних, яких стратегія не бачила. Дивимося на стійкість параметрів — якщо результат тримається лише у вузькому коридорі значень, говоримо про це до виведення в роботу, а не після перших угод.

Що буде, якщо ми додамо новий таймфрейм або інструмент?

Стратегія описує правила, а не конкретний набір барів: таймфрейми, інструменти та джерела підключаються налаштуванням. Новий ряд додається без переписування логіки й тестів — контур розрахований на зростання числа таймфреймів та інструментів.

Чи можна перевірити стратегію на демо-рахунку?

Так. Той самий код стратегії запускається на живому потоці в демо-режимі, а сигнали звіряються з розрахунком на історії. Так видно розбіжність через затримки, комісії та прослизання — модель перестає бути відірваною від ринку.

Обговоримо задачу й повернемося з планом робіт

Щоб обговорення задачі було предметним, до нього варто зібрати вхідні дані, які визначають архітектуру: як зберігаються й синхронізуються дані різних таймфреймів, де вузькі місця за швидкістю й що вважається коректним результатом. Для системи бектестингу з підтримкою multi-timeframe це ядро майбутнього рішення.

  • Перелік інструментів і таймфреймів, які потрібно покрити, — від хвилинних до денних, із зазначенням старших серій, що впливають на рішення.
  • Джерело та глибина котирувань: тикові дані чи свічки, чи є пропуски й розриви, як їх відновлювати.
  • Логіка стратегії: на якому таймфреймі ухвалюється рішення, а на якому підтверджується сигнал, де допустима розбіжність за часом.
  • Як моделюються витрати — комісія, прослизання, затримка виконання ордера.
  • Що вважається результатом: набір метрик, форми звітів, вивантаження для подальшого аналізу.
  • Режим роботи: одиночні прогони чи перебір параметрів, скільки часу допустимо чекати один результат.
  • Обмеження за інфраструктурою та доступами: де розміщуємо систему й хто власник історичних даних.

З нашого боку перша відповідь — робочий документ, а не лист про наміри.

У ньому буде план робіт за етапами, оцінка строків на кожен етап, склад команди з ролями (архітектор, інженер з даних, розробник розрахункового ядра, тестувальник) і перелік ризиків із тим, як ми їх закриваємо.

Якщо під час розбору виявиться, що частина задачі розв’язується простіше, скажемо про це прямо. Опишіть задачу — повернемося з оцінкою та планом.

Напрямки блокчейн-розробки

Останні роботи

  • Розробка сайту компанії B2B ADVANCE
    Розробка сайту компанії B2B ADVANCE
    1542
  • Розробка веб-додатків для компанії FEEDME
    Розробка веб-додатків для компанії FEEDME
    1393
  • Розробка веб-сайту для компанії БЕЛФІНГРУП
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    1081
  • Розробка інтернет магазину для компанії FURNORO
    Розробка інтернет магазину для компанії FURNORO
    1368
  • Розробка логотипу компанії B2B Advance
    Розробка логотипу компанії B2B Advance
    815
  • Розробка веб-додатків для компанії Enviok
    Розробка веб-додатків для компанії Enviok
    1139