Перейти к содержимому
Все стратегии

Стратегии

Портфель Double-7s (pinkfish, F. Aultman по Connors и Alvarez): покупать при минимуме закрытия за 7 дней выше SMA за 200 дней, продавать при максимуме закрытия за 7 дней; равные веса для SPY/QQQ/DIA/IWM, дневные бары USEQ, только лонг

Итог: Отменено

Double7sPortfolioUseq

Сводка по итогам

Double7sPortfolioUseq применяет правило Double-7s Connors и Alvarez к четырём широким индексным ETF US на площадке USEQ с нулевой комиссией; стратегия работает только в лонг и использует равные веса, а также режимный фильтр SMA из 200. Проверка не пройдена: дымовые тесты бэктеста в изолированной среде на слое 3 завершались тайм-аутом через 300 с во всех 3 итерациях, включая итерацию 2, где обработка каждого бара была инкрементальной. Согласно заметкам профилирования итерации -3, время уходило на сканирование инструментов каталога в runner бэктеста, а не на стратегию. Работу прекратили до бэктеста, оптимизации, проверки аналитиком или оценки рисков, поэтому преимущество стратегии так и не было измерено.

Гипотеза

Точное изложение примера портфеля «double-7s-portfolio» из pinkfish (Farrell Aultman, лицензия MIT; https://github.com/fja05680/pinkfish/blob/18a0d557ead25e0e82de3ece86bcab6c325a59ed/examples/portfolios/double-7s-portfolio/strategy.py). Он применяет правило Double 7s Ларри Коннорса и Сезара Альвареса из «Short Term Strategies that Work» к портфелю ETF. Это лонговая стратегия возврата к среднему по дневным ценам закрытия: купить ETF, когда цена закрытия достигает минимума закрытия за 7 дней и остаётся выше……Показать большеСвернуть

Точное изложение примера портфеля «double-7s-portfolio» из pinkfish (Farrell Aultman, лицензия MIT; https://github.com/fja05680/pinkfish/blob/18a0d557ead25e0e82de3ece86bcab6c325a59ed/examples/portfolios/double-7s-portfolio/strategy.py). Он применяет правило Double 7s Ларри Коннорса и Сезара Альвареса из «Short Term Strategies that Work» к портфелю ETF. Это лонговая стратегия возврата к среднему по дневным ценам закрытия: купить ETF, когда цена закрытия достигает минимума закрытия за 7 дней и остаётся выше 200-дневной SMA, а продать, когда цена закрытия достигает максимума за 7 дней. Источник предназначен для ETF, поэтому стратегия использует площадку USEQ с нулевой комиссией и барами DAILY, по которым доступны данные за несколько десятилетий. Исходный код получает список тикеров от вызывающего кода и не задаёт его жёстко. Мы используем четыре широких индексных ETF US, на которых Коннорс проверял правило: SPY, QQQ, DIA и IWM. Это 4 инструмента, в пределах лимита примерно в 10 инструментов из урока 173. Список выбран заранее, но все четыре ETF отслеживают индексы, существуют и сохраняют ликвидность с 1993-2000; таким образом, отбора отдельных бумаг по выживанию нет. Параметры по умолчанию точно скопированы из источника: period=7, stop_loss_pct=1.0 (в источнике это читается как 100%, поэтому стоп установлен на 0 и никогда не срабатывает; параметр оставлен), margin=1 (без кредитного плеча), use_regime_filter=True, use_vola_weight=False (равные веса 1/N), use_adj=False. Здесь нельзя соблюсти use_adj: наши цены USEQ скорректированы с учётом дробления акций, а дивиденды не включены в PnL. Это известное небольшое отклонение от источника: он использует нескорректированные цены закрытия, и собственный учёт pinkfish также не учитывает дивиденды. Расчёт комиссий: на USEQ комиссия нулевая, а спред и рыночное воздействие для этих ETF обходятся примерно в 0.02-0.05% за полный цикл сделки. Опубликованные результаты Double-7s на SPY показывают среднюю валовую прибыль сделки примерно от +0.6 до +1.0% при удержании позиции 3-8 сессий. Даже если после публикации этот результат снизится вдвое (примерно до 0.4%), он будет примерно в 10x раза выше издержек. Ожидаемое число сделок за весь срок для 4 ETF составляет примерно 8-12 сделок за ETF в год на протяжении примерно 25 лет, то есть около 800-1,100 сделок. У стратегии есть состояние без позиции. Каждый ETF находится в рынке примерно 25-35% времени. Портфель полностью вне рынка, когда ни один ETF не достигает минимума за 7 дней при цене выше своей 200-SMA; он также остаётся вне рынка во время медвежьих режимов, когда цены закрытия ниже 200-SMA.

Итерация 3 Layer-3 sandbox_timeout. Правила торговли не изменились с итерации 2; изменилась только строка документации, в которой зафиксирован диагноз. Я запустил точный код итерации 2 на том же окне из 2400 дней и 4 сегментов через run_backtest_in_subprocess, затем снял профиль дочернего процесса с помощью py-spy. Всё его время работы ушло на src/backtesting/runner.py:535 -> ParquetDataCatalog.instruments(instrument_ids=...) -> fsspec glob, который обходит каталоги всех классов инструментов в data/catalog/data,……Показать большеСвернуть

Итерация 3 Layer-3 sandbox_timeout. Правила торговли не изменились с итерации 2; изменилась только строка документации, в которой зафиксирован диагноз. Я запустил точный код итерации 2 на том же окне из 2400 дней и 4 сегментов через run_backtest_in_subprocess, затем снял профиль дочернего процесса с помощью py-spy. Всё его время работы ушло на src/backtesting/runner.py:535 -> ParquetDataCatalog.instruments(instrument_ids=...) -> fsspec glob, который обходит каталоги всех классов инструментов в data/catalog/data, включая 56,006 каталоги binary_option (Polymarket). Нагрузка на хост составляла примерно 77 на 18 ядрах. Дочерний процесс использовал около 9% CPU, ожидал дисковый ввод-вывод и всё ещё сканировал каталоги, не обработав ни одного бара, когда достиг лимита в 900 секунд (3x бюджета песочницы). Затраты стратегии на обработку каждого бара уже постоянны: deque с накопительной суммой SMA200 и вычислением максимума/минимума за O(7) для каждого сегмента, примерно по 2.4 тыс. дневных баров на сегмент. Следовательно, тайм-аут вызван обходом каталога и инфраструктурой хоста (урок 155 (b)), а не кодом стратегии; исправить его изменением кода стратегии нельзя. Исправление нужно внести в runner: искать инструмент по классу или идентификатору, а не обходить весь каталог, либо удалить каталоги Polymarket. Отклонения от источника прежние: нельзя соблюсти use_adj (USEQ цены скорректированы с учётом дробления акций, а дивиденды не включены в PnL); принудительный выход в конце данных оставлен механизму закрытия позиций при остановке; use_vola_weight=False (равные веса), как и в параметрах источника по умолчанию.

verification_loop: sandbox_timeout: Проверка не пройдена (слой 3 — бэктест в изолированной среде): дымовой тест превысил лимит времени 300 с на окне около 20000 баров (2400 дней с SPY.USEQ-1-DAY-LAST-EXTERNAL). Почти всегда причина — работа на каждом баре, масштаб которой зависит от длины истории, например повторный просмотр всего ряда данных о финансировании и дополнительных данных либо повторное создание списка и вызов min()/sorted() внутри calculate_signal()/on_bar() на каждом баре. Предварительно рассчитайте отсортированные массивы временных меток ONCE в __init__ и используйте bisect либо кэшируйте результаты поиска по временной метке, чтобы затраты на обработку одного бара составляли O(log n), а не O(n).

Реализация

Перевод pinkfish стратегии double-7s-portfolio от F. Aultman (MIT). Правило Double 7s Connors и Alvarez применяется к дневным барам USEQ SPY/QQQ/DIA/IWM; стратегия работает только в лонг, веса равны 1/N. ETF покупается, когда цена закрывается на минимуме за 7 дней и выше SMA за 200 дней. Инструмент продаётся, когда цена закрывается на максимуме за 7 дней или ниже стопа (значение по умолчанию stop_loss_pct=1.0 задаёт стоп на уровне 0, поэтому он никогда не срабатывает, как и в исходном коде).

Результаты верификации

sandbox_timeout: Проверка не пройдена (слой 3 — бэктест в изолированной среде): дымовой тест превысил лимит времени 300 с на окне около 20000 баров (2400 дней с SPY.USEQ-1-DAY-LAST-EXTERNAL). Почти всегда причина — работа на каждом баре, масштаб которой зависит от длины истории, например повторный просмотр всего ряда данных о финансировании и дополнительных данных либо повторное создание списка и вызов min()/sorted() внутри calculate_signal()/on_bar() на каждом баре. Предварительно рассчитайте отсортированные массивы временных меток ONCE в __init__ и используйте bisect либо кэшируйте результаты поиска по временной метке, чтобы затраты на обработку одного бара составляли O(log n), а не O(n).

Сводка по итогам

Если тайм-аут в изолированной среде вызван сканированием каталога до первого бара, а не кодом стратегии, переписывание стратегии проблему не решит: требуется исправить инфраструктуру, а не продолжать циклы доработок кода.

После 3 итераций работу прекратили: проверка зашла в цикл, поскольку каждый бэктест в изолированной среде на слое 3 превышал лимит времени 300 с на дневном окне SPY.USEQ длиной 2400 дней. В заметках к итерации -3 говорится, что профилирование связало задержку со сканированием glob в ParquetDataCatalog.instruments() по каталогу (около 56 тыс. папок Polymarket), которое выполняется до запуска кода стратегии, а не с обработкой отдельных баров.

Лонговый портфель Double-7s с равными весами и возвратом к среднему на SPY/QQQ/DIA/IWM дневных барах USEQ (перевод примера pinkfish с правилом Connors и Alvarez): купить ETF на минимуме закрытия за 7 дней, если цена выше 200-дневной SMA, и продать на максимуме закрытия за 7 дней.

Данных о результатах нет. Отчёт бэктеста пуст, оптимизация не запускалась, а доходность, коэффициент Шарпа и число сделок не рассчитаны.

Анализ

double-7s-portfolio

Stratmill — это инструмент для исследований и бумажной торговли, а не финансовая консультация или брокер. Результаты бэктестов и бумажной торговли являются гипотетическими. Торговля сопряжена с риском убытков.