Розробка рушія бектестингу на JavaScript/TypeScript для криптовалют

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

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

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

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

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

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

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

Що дає власний рушій бектестингу на JavaScript

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

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

Різниця не в «оптимізації», а в тому, що дослідник встигає перевірити десять варіантів параметрів, поки не втратив нитку.

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

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

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

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

Підходи до розрахунку: подієвий, векторний і потоковий

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

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

Подієвий розрахунок проганяє дані подія за подією — це той самий порядок, що й у режимі перевірки стратегій на живому ринку.

Вимоги до історичних даних у режимів різні.

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

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

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

Етапи розробки рушія перевірки торгових стратегій

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

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

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

Що залишається в репозиторії після здачі рушія

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

  • Конфігурації середовища — окремі набори для локального, тестового та робочого контуру: джерела котирувань, ліміти паралельних прогонів, шляхи до сховища результатів. Секрети підтягуються зі змінних середовища і в репозиторій не потрапляють.
  • Схема даних розрахунків — сутності свічок, угод, ордерів і прогонів із типами полів і зв'язками. Нова метрика вбудовується в неї без правки наявних таблиць.
  • Політики доступу до даних — ролі для сервісів і людей: читання історії, запис результатів, доступ до торгових ключів. Ключі підключаються лише на читання.
  • Регламент оновлення історії — як довантажуються пропущені свічки, чим перевіряються розриви та дублі, у якому порядку йде перерахунок. Неповний прогін позначається явно, а не видається за результат.
  • Документація рушія — точки розширення з прикладами на JavaScript і TypeScript: як додати індикатор, тип ордера, модель комісій і прослизання.
  • Тести та еталонні прогони — фіксований набір даних і очікувані метрики, за якими видно, що після правок результат не поїхав.
  • Інструкція із запуску та відкату — як підняти рушій з нуля і повернутися до попередньої версії.

Розбір по репозиторію проводимо в кінці проєкту: проходимо з вашою командою по кожному артефакту і показуємо, де що міняти.

Кейс: розрахунки прискорилися, розбіжності у звітах зникли

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

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

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

Що змінилося на замірах

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

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

Чим відрізняється перевірка на історії від демо-торгівлі?

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

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

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

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

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

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

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

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

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

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

Наскільки точні розрахунки?

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

Як враховуються комісії та прослизання?

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

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

Чи сумісно з поточним кодом?

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

Чи витримає розрахунковий контур навантаження?

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

Як не підігнати стратегію під історію?

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

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

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

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

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

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

Опишіть задачу у вільній формі — повернемося з оцінкою та планом робіт.

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

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

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