Подборки/13 частей/203 мин. всего

Быстрые движки бэктеста

Как построить движок бэктеста, который считает в сотни раз быстрее без изменения PnL: раскладка данных, кэширование, адаптивное разрешение и архитектура - от первых ускорений до внутренностей продакшена.

01

Polars vs Pandas для алготрейдинга: бенчмарки на реальных данных

Детальное сравнение Polars и Pandas на задачах алготрейдинга: бенчмарки фильтрации, агрегации, rolling-расчётов сигналов, I/O, потребления памяти. Гибридная архитектура Polars + Numba для максимальной производительности бэктеста.

02

VectorBT: Самый быстрый фреймворк для бэктестинга на Python

Обзор VectorBT - инновационной библиотеки для количественного анализа, которая меняет подход к бэктестингу благодаря мощи NumPy и Numba.

03

Лесенка скорости бэктест-движка: 298x на CPU ноутбука, идентичный PnL до последней сделки

Пять реализаций одного и того же перебора 80 комбинаций параметров, каждая проверена на идентичность PnL: pandas rolling.apply занимает 69.9 секунды, numpy - 3.1, numba - 2.0, параллельная numba - 0.23 - измеренное ускорение 298x на Apple M2 Max без единого изменения в железе, и все еще ~13x против добротной векторизованной базовой реализации. Что дает каждая ступень, почему GPU - не то недостающее звено, и где на самом деле находится узкое место в массовом переборе параметров.

04

Налог на фреймворк: когда ваша библиотека для бэктестов медленнее наивного цикла на pandas

Мы прогнали восемь движков для бэктестов через один и тот же перебор параметров - 150 тысяч баров, 80 комбинаций HMA-пересечения, паритет по числу сделок закреплен на 2707. Два самых популярных событийно-ориентированных фреймворка оказались медленнее, чем написанный вручную цикл на pandas, а векторизованный/компилируемый движок выполнил ту же работу примерно в 13 000 раз быстрее. Исследование накладных расходов на каждый бар, которые популярные библиотеки никогда не были рассчитаны амортизировать.

05

Агрегированный Parquet-кэш: как ускорить мультитаймфрейм-бэктест в сотни раз

Как предвычислить таймфреймы и индикаторы из минутных свечей, сохранить в parquet и использовать при массовом тестировании стратегий без повторных пересчётов.

06

Двухосевое пространство параметров: почему большая часть вашего перебора должна быть почти бесплатной

Не все параметры одинаково дорого перебирать. Параметры стратегии делятся на дорогую ось (индикаторы - пересчитываются по всему ряду) и дешевую ось (пороги принятия решений - проход O(n) по уже посчитанным сигналам). Поскольку индикаторы не зависят от порогов, их можно посчитать один раз и перебрать тысячи конфигураций порогов на скорости ~5600 конфиг/с - примерно в 1600 раз дешевле, чем пересчитывать на каждую конфигурацию. Переоценка проклятия размерности.

07

Adaptive drill-down: бэктест с переменной гранулярностью от минут до сырых сделок

Как адаптивная гранулярность данных ускоряет бэктесты и экономит хранилище: drill-down от 1m к 1s, 100ms и сырым сделкам только там, где цена двигалась значительно или объём аномально вырос.

08

Фиделити-гейт: поиск от грубого к точному обманывает быстрее, если дешевый прокси не ранжирует так же, как дорогой

Drill-down / мультификсиделити-поиск (ASHA, successive halving, Hyperband) дешево отсеивает тысячи конфигураций и продвигает к дорогой полной оценке только выживших. Это настоящее ускорение - но оно тихо ломается, если ранжирование на низкой фиделити расходится с ранжированием на высокой. Мы измерили корреляцию рангов по фолдам: на одном фолде спирменовское ρ может быть 0.03 (ранги почти случайны), поднимаясь до 0.43, 0.67, 0.78, 0.91 по мере накопления фолдов. Решение - один обязательный гейт: сначала измерить ρ(дешевое, полное), а затем автоматически поднять минимальную фиделити до первой ступени, где ρ ≥ 0.5.

09

Случайный поиск против умного: переломный момент задает стоимость оценки, а не алгоритм

Когда один бэктест дешев, тупой скремблированный Sobol выигрывает по чистой пропускной способности - умные сэмплеры (TPE, CMA-ES, ASHA) платят Python-налог на ask/tell, который замедляет их в 20 раз, поэтому при равном wall-clock они оценивают намного меньше точек и проигрывают. Сделайте каждую оценку дорогой (multi-TF + walk-forward фолды) - и точка пересечения переворачивается. Мы измерили оба режима и разобрались, почему fold-rank fidelity (ρ@1 растет с 0.03 до 0.43) - необходимое условие, чтобы прунинг окупался.

10

Координатный спуск vs Bayesian optimization: что находит лучшие параметры

Почему полный перебор невозможен для 12+ параметров, как координатный спуск пропускает взаимодействия, и как Optuna с TPE-сэмплером за 500 итераций находит то, что OAT не может за 96. Практические примеры кода, сравнение сэмплеров и многокритериальная оптимизация.

11

Ловушка точности GPU: как fp32-бэктест на Apple Metal незаметно возвращает мусор

GPU Apple Metal не имеет float64. Наивно перенесите на него векторизованный бэктест - и соблазнительная WMA на префиксных суммах переполняет fp32: максимальная относительная ошибка 211× - но при этом все отрабатывает и выдает правдоподобные числа. Решение - не в дополнительной точности, а в другой формуле: прямая оконная свертка, безопасная для fp32 с точностью до 8×10⁻⁷ и быстрее однопоточной numba в 55.9 раза. Ловушка, арифметика и как доказать, что вы в нее не попали.

12

Когда GPU окупается: roofline перебора параметров, где заголовочные 167x - на самом деле 27x алгоритма, умноженные на 6.2x железа

Отрыв GPU от CPU растет с размером батча - от 54.5x при одной комбинации на вызов до 359.6x при 61 на нашем мультитаймфреймовом предрасчете индикаторов, - потому что маленький перебор не может амортизировать накладные расходы на запуск ядер и пересылку данных. Мы раскладываем заголовочные 167x на алгоритмический выигрыш 27x, который ускоряет и CPU, и аппаратный выигрыш 6.2x, показываем, что истинный отрыв GPU от лучшего CPU - лишь 3.2x на одном таймфрейме и 6.2x на нескольких, и даем руководство к решению: насколько широким должен быть перебор, чтобы GPU стоил вложений.

13

IPC-налог: спрячьте бэктест-движок за сокетом и потеряйте 13% - при этом сокет почти ни при чем

Мы перенесли numba-ядро бэктеста построчно на Rust и вызывали его через границу процесса четырьмя способами, а проверка эквивалентности подтвердила идентичный PnL вплоть до последней сделки. Передача всего ценового ряда в 1.2 MB через Unix-сокет стоит ~2 мс - около 0.1% всей работы. JSON-кодирование того же payload стоит 1348x дороже, чем сырые байты, болтливые вызовы на каждую комбинацию пересылают данные заново 80 раз, а паттерн вызова на каждый бар обошелся бы в 2.1 с чистого IPC на задаче длиной 2.0 с. Граница дешева; налог - в том, как вы ее пересекаете.