Идея коротко
Фильтр ничего не покупает сам. Он отвечает «да» или «нет» на вопрос, пропускать ли сегодня сигнал уже готового входа. В карточке два подхода к таким фильтрам от двух систематиков, которые строят внутридневные пробойные системы.
Brendan (Trivium System Trading) генерирует стратегии в StrategyQuant X и почти не пускает в построитель индикаторы с настройками. Вместо RSI и MACD он закодировал около сотни своих условий, в которых нечего оптимизировать. Два его примера: вчерашний день закрылся выше открытия; дневное закрытие выше 200-периодной средней, где 200 зафиксировано навсегда.
Andrea Unger, четырёхкратный чемпион World Cup Trading Championship, начинает с простого скелета: пробой максимума прошлой сессии, выход в конце дня, обязательный стоп. Если кривая растёт, но средняя сделка не покрывает издержки, он прогоняет скелет через библиотеку условий о вчерашнем дне: тихий день, большое движение, три закрытия подряд вверх, понедельник или пятница. Каждое условие проверяется отдельно.
Почему это может работать
Довод Brendan про степени свободы. У RSI период можно менять от двух почти до бесконечности, плюс порог. У MACD три настройки. Чем больше таких ручек, тем проще подогнать кривую под историю. Условие «вчера закрылось в плюсе» либо выполнено, либо нет, и подгонять в нём нечего.
Довод Unger про поведение рынка. Один и тот же вход работает по-разному в зависимости от того, что рынок сделал накануне. Фильтр отсекает дни, где пробой в среднем хуже, и поднимает среднюю сделку до уровня, где она покрывает комиссию и проскальзывание.
Оба довода не отменяют отбора. Условие без параметров становится параметром, как только его выбирают из сотни других. Unger защищается от этого так: не ищет лучший вариант, а смотрит, есть ли разница; оставляет условие, только если может его объяснить; слишком красивой кривой не верит. Про доработку ослабевшей системы новыми фильтрами он говорит прямо: это путь к подгонке, лучше собрать систему заново от исходного принципа.
Правила
Блоки Brendan (автор)
// условия считаются по закрытым дневным барам и применяются на внутридневном графике
// у автора графики 30 минут, CFD на индексы США, DAX, Nikkei, биткоин, золото, нефть
UpDay = Close[D1, 1] > Open[D1, 1] // автор: вчерашняя сессия закрылась в плюсе
Above200 = Close[D1, 1] > MA(Close[D1], 200)[1] // автор: период 200 не оптимизируется
// Finetiq: тип средней не назван, берём SMA
// Finetiq: зеркально для шортов Close[D1, 1] < Open[D1, 1] и закрытие ниже средней
// пример условия, которое находил генетический построитель (автор приводит его «из головы»)
SessHighVs3W = максимум окна сессии сегодня > Open[D1, 15]
// Finetiq: три недели = 15 торговых дней, окно = первые 2 часа, проверка после закрытия окна
// у этого условия уже два скрытых параметра: окно и глубина
Библиотека условий вчерашнего дня (Unger, пороги Finetiq)
Unger называет условия словами. Числовых определений в интервью нет, ниже стартовые значения для проверки.
// [1] = вчерашний закрытый дневной бар
// автор: дневной ряд из 1440-минутных баров, чтобы закрытием была последняя сделка, а не settlement
Range1 = High[1] - Low[1]
ATR20 = ATR(20)[1] // Finetiq
Quiet = Range1 < 0.7 * ATR20 // автор: «вчера был тихий день»; Finetiq: порог
Choppy = |Close[1] - Open[1]| < 0.25 * Range1 // автор: «рваный день»; Finetiq: тело меньше четверти диапазона
HugeMove = Range1 > 1.5 * ATR20 // автор: «большое движение»; Finetiq: порог
DownClose = Close[1] < Close[2] // автор: закрытие вниз «к уровню», уровень не назван
ThreeUp = Close[1] > Close[2] AND Close[2] > Close[3] AND Close[3] > Close[4] // автор
Monday = сегодня понедельник // автор
Friday = сегодня пятница // автор
HighVol = ATR(5)[1] > ATR(50)[1] // автор: «высокая волатильность»; Finetiq: сравнение
LowADX = ADX(5)[1] < 35 // автор: «ниже 40 или 35»
Процедура отбора (автор, ограничения Finetiq)
// скелет (автор): BUY STOP at PrevHigh, EXIT в конце дня (или через 2 дня, или по цели), стоп всегда
// скелет годится, если кривая растёт, а средняя сделка меньше издержек (автор)
FOR EACH P IN Library
On = сделки скелета в дни, где P = TRUE
Off = сделки скелета в дни, где P = FALSE
сравнить среднюю сделку, число сделок и форму кривой
KEEP P IF разница заметна AND есть объяснение, почему так // автор: здравый смысл против совпадения
// Finetiq: в On не меньше 100 сделок, в системе не больше двух условий
// Finetiq: условия выбираются только на in-sample, решение проверяется на out-of-sample
// Validator (автор): сдвинуть вчерашние High и Open на ±10 тиков, пересчитать систему много раз
// и посмотреть, в каком перцентиле лежит исходная кривая. Край распределения значит неустойчивость
Walk-forward к библиотеке Unger не применяет: список паттернов не непрерывный параметр, и выбирать «лучший паттерн недели» бессмысленно.
Подключение к карточкам базы (Finetiq)
// пример 1: prev-high-breakout-adx. Там фильтр с двумя параметрами: ADX(5) < 35
Allowed_A = ADX(5)[1] < 35 // как в карточке
Allowed_B = UpDay // фильтр без параметров вместо ADX
Allowed_C = ADX(5)[1] < 35 AND Above200
IF Allowed_x AND TradesToday = 0
BUY STOP at PrevHigh + 1 тик // вход и выход карточки без изменений
// пример 2: intraday-breakout-eod-exit. Там уже стоят UpDay AND Above200
Filter = UpDay AND Above200 // как в карточке
Filter_Test = Filter AND NOT HugeMove // одно новое условие за раз, по процедуре Unger
Параметры
| Параметр | Значение | Откуда |
|---|---|---|
| Период средней в Above200 | 200, не оптимизируется | автор (Brendan) |
| Тип средней | SMA | Finetiq |
| Окно сессии в SessHighVs3W | первые 2 часа | Finetiq |
| «Три недели назад» | 15 торговых дней | Finetiq |
| Дневной бар | 1440 минут, не settlement | автор (Unger) |
| Quiet | диапазон вчера < 0.7 ATR(20) | Finetiq |
| Choppy | тело < 25% диапазона | Finetiq |
| HugeMove | диапазон вчера > 1.5 ATR(20) | Finetiq |
| HighVol | ATR(5) > ATR(50) | Finetiq |
| LowADX | ADX(5) < 35 | автор (Unger: 40 или 35) |
| Сдвиг цен в Validator | ±10 тиков | автор (Unger) |
| Минимум сделок в On | 100 | Finetiq |
| Условий в одной системе | не больше 2 | Finetiq |
Что проверить
- Разница on и off для каждого условия. На одном скелете и одном рынке разбейте сделки по каждому условию и сравните среднюю сделку после издержек. Сводная таблица по всем условиям сразу показывает, сколько из них дают разницу случайно.
- Случайный фильтр той же частоты. Если условие истинно, скажем, в 40% дней, 200 раз разметьте дни случайно с той же долей и прогоните скелет. Если настоящий фильтр не выходит за верхние 5% случайных, его улучшение объясняется отбором.
- Сдвиг цен по Unger. Сдвиньте вчерашние High и Open на ±10 тиков (для CFD на 5% ATR) и посчитайте, как часто условие меняет значение и насколько падает результат.
- Окрестность скрытых параметров. 200 против 150 и 250, пороги 0.7 и 1.5 ATR против 0.5–0.9 и 1.2–2.0. Brendan считает 200 константой, но стоит убедиться, что результат не держится только на ней.
- Out-of-sample по времени. Выбирайте условия на первой половине истории, оценивайте на второй. Менять набор условий можно только до этого шага.
- Другие рынки. Brendan ждёт, что логика, найденная на NASDAQ, будет хотя бы прибыльной на Dow и S&P 500. Unger так не проверяет. Прогоните фильтр на соседних индексах.
- Издержки и число сделок. Проверьте, остаётся ли средняя сделка после фильтра выше двойных издержек и хватает ли сделок для выводов.
Особенности платформ
TradingView (Pine Script)
- Дневные значения на внутридневном графике:
request.security(syminfo.tickerid, "D", close[1] > open[1], lookahead = barmerge.lookahead_on). Без[1]в бэктест попадает сегодняшнее закрытие. - Дневной бар строится по сессии символа. У фьючерсов CME день начинается в 18:00 ET накануне, у CFD торговля почти круглосуточная. «Вчера» на кэш-индексе и на фьючерсе разное, и UpDay срабатывает в разные дни.
- Окно сессии для SessHighVs3W задавайте с поясом биржи:
time(timeframe.period, "0930-1130", "America/New_York"). Иначе окно съедет при переходе на летнее время.
MultiCharts и TradeStation (EasyLanguage)
- Unger берёт 1440-минутные бары вместо дневных. У фьючерса в TradeStation дневной бар закрывается по settlement, 1440-минутный по последней сделке. UpDay и ThreeUp на двух видах бара выпадут на разные дни.
- Дневной ряд подключается вторым потоком (
Close of Data2). Проверьте на графике, что во время сессии Data2 отдаёт вчерашний закрытый бар, а не текущий. - День недели:
DayOfWeek(Date), воскресенье 0, понедельник 1, пятница 5. AvgTrueRangeэто простое среднее TR, в Pine ATR по Уайлдеру. Пороги Quiet и HugeMove в долях ATR на двух платформах дадут разные дни.
MetaTrader 5 (MQL5)
- Вчерашний бар:
iOpen(_Symbol, PERIOD_D1, 1)иiClose(_Symbol, PERIOD_D1, 1). Дневной бар строится по времени сервера брокера, а не биржи. - У брокеров с сервером не в GMT+2/+3 бывают короткие воскресные бары. В понедельник «вчера» окажется воскресным обрывком, и UpDay, Quiet и ThreeUp посчитаются по нему.
iADXсглаживает не по Уайлдеру. Для совпадения LowADX с Pine и EasyLanguage беритеiADXWilder.iATRпростое среднее TR, как в EasyLanguage.- Сдвиг на ±10 тиков для Validator считайте через
SYMBOL_TRADE_TICK_SIZE. У CFD на индекс тик бывает 0.01 или 0.1, и 10 тиков фьючерса там соответствуют другому сдвигу.
Где идея может сломаться
- Интервью Brendan вышло на канале StrategyQuant, продавца софта, и в конце автор рекламирует свой курс. Цифр по отдельным блокам нет, только общий вывод, что они чаще проходят проверки.
- Ноль параметров внутри условия не значит ноль степеней свободы. Генетический построитель перебирает сотню блоков и их сочетания. Brendan сам приводит условие, которое выглядит случайным, и торгует такие, если они прошли проверки.
- Unger не даёт числовых определений. С порогами из этой карточки библиотека уже не беспараметрическая, и её нужно проверять на окрестность.
- Validator Unger описывает как рекомендацию ученикам, а сам полагается на опыт. Его здравый смысл механически не воспроизвести.
- Каждый фильтр уменьшает выборку, а Unger ещё и строит отдельную систему под каждый рынок, не проверяя её на других. Оба обстоятельства повышают риск подгонки.
- «Вчера» зависит от того, где кончается день: кэш-сессия, торговый день фьючерса, сервер брокера. Один и тот же фильтр на трёх платформах может выбрать разные дни.