Стратегии
2MACDSTO от geraked (точный перенос): MACD(34,144) тренд + MACD(13,21) встречное движение + пересечение Stochastic(7,3,3) при выходе из зоны 20/80, расчёт риска по расстоянию колебания, отсутствие жёсткого SL/TP, трейлинг-стоп на 50% риска, усредняющая сетка с равными объёмами на 50 уровнях и корзиной TP, длинные и короткие позиции (ETHUSDT.OKX 4H)
Итог: Отменено
TwoMacdStoGridEthOkx
Сводка по итогам
Перенос TwoMacdStoGridEthOkx преобразовал советник 2MACDSTO от geraked для перпетуальных контрактов OKX ETH на барах 4H: вход по двум MACD с откатом стохастика, выход без стопа по трейлинг-стопу и усредняющая сетка с равными объёмами на 50 уровнях. За 3 итераций проверку пройти так и не удалось. Бэктест в песочнице был ликвидирован 2020-06-02 при значении -100%; одна сделка принесла убыток примерно в 29x от стартового капитала. QA установил, что причиной были расчёт размера сетки без учёта нереализованных убытков и отсутствие стопа корзины; стратегию забросили до этапов проверки бэктеста, оптимизации, анализа и оценки риска.
Гипотеза
Точное изложение логики советника с открытым исходным кодом MQL5 «2MACDSTO» v1.4 автора geraked (Copyright 2023, лицензия MIT, https://github.com/geraked/metatrader5/blob/d3eb29c382acf715727d5cd6a0414151e821fc2d/Experts/2MACDSTO.mq5), с его вспомогательными средствами управления сделками из Include/EAUtils.mqh в том же коммите. Авторство стратегии принадлежит geraked. Автор тестировал ее на NZDUSD 3H (2020-01-01–2023-10-08). Заявленную доходность следует считать непроверенной; решение принимается по результатам……Показать большеСвернуть
Точное изложение логики советника с открытым исходным кодом MQL5 «2MACDSTO» v1.4 автора geraked (Copyright 2023, лицензия MIT, https://github.com/geraked/metatrader5/blob/d3eb29c382acf715727d5cd6a0414151e821fc2d/Experts/2MACDSTO.mq5), с его вспомогательными средствами управления сделками из Include/EAUtils.mqh в том же коммите. Авторство стратегии принадлежит geraked. Автор тестировал ее на NZDUSD 3H (2020-01-01–2023-10-08). Заявленную доходность следует считать непроверенной; решение принимается по результатам нашего бэктеста с учетом комиссий. Это торговая стратегия, а не утилита. MECHANISM: вход на откате в рамках медленного тренда. Медленный MACD (разница 34/144 EMA) задает тренд. Быстрый MACD (13/21) должен быть направлен против него, обозначая откат. Пересечение стохастических %K и %D при выходе из зоны перепроданности или перекупленности определяет момент повторного входа. EA размещает на ордере стоп-лосс NO и тейк-профит NO (IgnoreSL=true, IgnoreTP=true). Одиночная позиция закрывается только по трейлинг-стопу. Стоп активируется, когда прибыль достигает половины амплитуды колебания. Если цена вместо этого движется против позиции, EA усредняет убыточную позицию по сетке EQUAL-SIZE (GridVolMult=1.0), добавляя одну позицию на каждую амплитуду колебания, максимум до 50 уровней. Затем вся корзина закрывается по общей цене тейк-профита, которая покрывает первоначальный риск и издержки. PLATFORM MAPPING: площадка — бессрочный своп OKX USDT ETHUSDT.OKX на счете MARGIN. Комиссии составляют 0.02% для мейкера и 0.05% для тейкера, около 0.10% за полный цикл сделки тейкера. Нужен именно бессрочный контракт, поскольку источник требует возможности открывать короткие позиции. Доля OKX в корпусе данных составляет 0.8% при целевом значении не менее 5%, тогда как BINANCE USD-M составляет 65.9% при предельном значении 40%. ETH — самый ликвидный бессрочный контракт OKX, кроме BTC. Механизм использует только цены, без дополнительных потоков данных, поэтому ограничение площадки L160 неприменимо. Таймфрейм: в нашем каталоге нет баров 3H, поэтому перенос использует ближайший встроенный интервал — бары 4-HOUR (ETHUSDT.OKX-4-HOUR-LAST-EXTERNAL). Код EA работает на любом таймфрейме, поскольку все его индикаторы используют таймфрейм графика. Это единственное отклонение от источника. Константы, заданные в пунктах, преобразуются в доли цены. На NZDUSD (пункт 0.00001, цена около 0.60) значение SLDev=60 пунктов составляет примерно 0.10% цены, а параметр minPoints=30 во вспомогательной функции — примерно 0.005% цены. IMPLEMENTATION CAUTION: более ранний точный перенос стратегии того же автора (3MAF) завершился сбоем на sandbox_timeout. Каждый индикатор должен обновляться INCREMENTALLY за O(1) на бар: - скользящие EMA для четырех составляющих MACD; - дековые структуры фиксированной длины для максимумов и минимумов за 7 баров и для сумм замедления за 3 баров; - буфер из 3 значений для %D; - состояние корзины, хранящееся в скалярных переменных: цена первого входа, pd, объем первой позиции, число уровней, общее количество, сумма входов, взвешенная по количеству, накопленные комиссии. Не сканируйте заново историю баров, список позиций или историю исполнений внутри on_bar.
Итерация 3 исправляет все пункты QA: (1) удалены жёсткие ограничения по просадке 30% и уровню маржи 50%; EquityDrawdownLimit перенесён как исходный параметр со значением по умолчанию 0 (отключён). (2) get_account_equity() считается mark-to-market; баланс = капитал - нереализованный результат, поэтому нереализованный PnL учитывается один раз при проверке просадки и лимите валового объёма сетки. (3) min_dist_frac повышен до 0.4%, чтобы движение следования за ценой 50% было >= 0.2%, выше примерно 0.10% круговой……Показать большеСвернуть
Итерация 3 исправляет все пункты QA: (1) удалены жёсткие ограничения по просадке 30% и уровню маржи 50%; EquityDrawdownLimit перенесён как исходный параметр со значением по умолчанию 0 (отключён). (2) get_account_equity() считается mark-to-market; баланс = капитал - нереализованный результат, поэтому нереализованный PnL учитывается один раз при проверке просадки и лимите валового объёма сетки. (3) min_dist_frac повышен до 0.4%, чтобы движение следования за ценой 50% было >= 0.2%, выше примерно 0.10% круговой комиссии тейкера OKX с учётом проскальзывания (отклонение от минимума помощника около 0.005%, нужное из-за комиссий крипторынка). (4) Stochastic теперь усредняет исходный %K за окно замедления, а %D усредняет замедленный %K (примечание: встроенный iStochastic в MT5 использует отношение сумм; переключено согласно QA). (5) Сетка добавляет ровно ONE уровень за проверку, отсчитывая от цены последнего уровня, как это делает EA, и только если полный уровень того же размера укладывается в лимит валового объёма: капитал x плечо; поэтому число уровней всегда равно числу исполненных. Плечо 3, а номинал каждого уровня ограничен величиной 0.25 x плеча x капитала, оставляя маржу для уровней сетки; расчёт размера использует self.config.leverage. Неизбежное отличие платформы: бары 4H вместо 3H, проверки при закрытии бара вместо таймера на 30 секунд.
verification_loop: проверка не пройдена (слой 4 — проверка QA) [класс=code_defect]: - [edge_concern] Даже после исправления размера равномерная усредняющая сетка из 50 уровней без стопа для корзины по своей структуре является мартингейлом с короткой волатильностью. На ETH (рост примерно на 20x за 2020-21 и падение на 80% за 2022) контртрендовая корзина, попавшая в устойчивый тренд, несёт неограниченный убыток после того, как лимит валового объёма блокирует дальнейшие добавления. Минимальную просадку для……Показать большеСвернуть
verification_loop: проверка не пройдена (слой 4 — проверка QA) [класс=code_defect]: - [edge_concern] Даже после исправления размера равномерная усредняющая сетка из 50 уровней без стопа для корзины по своей структуре является мартингейлом с короткой волатильностью. На ETH (рост примерно на 20x за 2020-21 и падение на 80% за 2022) контртрендовая корзина, попавшая в устойчивый тренд, несёт неограниченный убыток после того, как лимит валового объёма блокирует дальнейшие добавления. Минимальную просадку для прохождения отбора невозможно обеспечить, если не задать ненулевой стоп капитала на уровне корзины (исходный параметр EquityDrawdownLimit). Проверь худшую просадку корзины, прежде чем тратить средства на оптимизацию. - [critical] Лимит валового объёма сетки и проверка просадки основаны на неверной предпосылке. В комментарии сказано: «get_account_equity() уже включает нереализованный PnL (mark-to-market)». Это не так. resolve_account_equity() возвращает account.balances()[USDT].total, а в NT MarginAccount эта величина означает только реализованные средства; нереализованный PnL в балансе не отражён. Отсюда три последствия. (a) `balance = equity - unreal` завышает баланс на величину всего нереализованного убытка. (b) `room = max(equity,0)*lev - qty*c` ограничивает валовой объём величиной 3x реализованных средств REALIZED, а не реальным капиталом 3x. По мере роста убытка корзины фактическое плечо относительно реального капитала неограниченно увеличивается, а уровни сетки продолжают добавляться за счёт уже несуществующего капитала. (c) Если equity_drawdown_limit_pct когда-либо установлено выше 0, проверка сопоставляет реализованные средства с их значением за вычетом нереализованного PnL, поэтому знак и величина результата неверны. Это видно в песочнице: счёт ликвидирован (2020-06-02) на total_return -100%, max_drawdown 100%, а одна сделка принесла убыток $2,949,268 — примерно 29x от начального капитала. В пункте обоснования разработчика (2) заявлено, что проблема исправлена, но исправление основано на неверной предпосылке. (строка 270) — исправление: вычисляй реальный капитал в стратегии так: mtm_equity = get_account_equity() + d*(c - avg)*qty (реализованные средства плюс нереализованный PnL этой позиции). Используй mtm_equity при проверке свободного места для сетки (место = mtm_equity*lev - qty*c; запрещай добавление, если mtm_equity <= 0) и в _level_qty для расчёта размера. При проверке EquityDrawdownLimit используй непосредственно balance = get_account_equity() (это уже баланс). - [critical] Риск корзины неограничен: стопа нет, плечо 3x, убыток может превысить капитал (L148/L156). Когда лимит валового объёма блокирует дальнейшие добавления, ничто не ограничивает убыток корзины, движущейся против тренда. При росте рынка короткая корзина не освобождает место, поскольку qty*c увеличивается, поэтому она просто удерживается до ликвидации счёта. Крупнейший убыток в песочнице, около 29x начального капитала, доказывает, что такой сценарий возможен. Для этой конфигурации нельзя заявить ни «расстояние до стопа x размер <= 1-2% капитала», ни предельный валовой объём относительно капитала TRUE в худшем сценарии. В исходном коде для этого предусмотрен параметр EquityDrawdownLimit. Оставлять его на уровне 0 в криптопорте с плечом 3x — дефект расчёта размера и риска, а не сохранение исходной стратегии. (строка 60) — исправление: сохрани механизм без изменений, но задай equity_drawdown_limit_pct ненулевое значение (например, 20-30%), рассчитываемое от капитала MTM согласно исправлению выше. Или снизь плечо и max_level_notional_mult, чтобы предельный валовой объём = grid_max_lvl_reachable x level_notional <= mtm_equity x максимальное плечо площадки, и укажи этот предел в обосновании. Оба параметра есть в исходнике, поэтому порт останется верным оригиналу. - [warning] Базовый шаблон не вызывает calculate_signal(), пока len(self._bars) < min_bars_required() (200). Поэтому EMA начинают расчёт с бара 200, а EMA(144) и MACD(34,144) не сходятся примерно в течение следующих 150-300 баров; ранние показания тренда смещены к цене закрытия начального бара. (строка 112) — исправление: либо требуй около 3x m2_slow баров прогрева сигнала внутри calculate_signal до установки условий покупки/продажи, либо прими это смещение и опиши его. - [warning] Замедленный %K вычисляется как среднее исходных значений %K за окно замедления. iStochastic в MT5 (который вызывает EA) вычисляет его как 100*SUM(C-LL, slowing)/SUM(HH-LL, slowing), то есть как отношение сумм. Результаты различаются, когда диапазон меняется в пределах 3 баров, поэтому время пересечения 20/80 слегка смещается. (строка 139) — исправление: для точного порта храни в двусторонних очередях длиной 3 баров значения (c-ll) и (hh-ll), а %K вычисляй как отношение их сумм. - [warning] Журнал сделок песочницы непригоден для расчёта экономики каждой сделки (L140). avg_trade_return_pct — это -259% x 5 сделок, что не согласуется с total_return -100%. avg_holding_period — это 443 дней против data_days 162. Указано 5 сделок, но исполнений — 14. Уровни сетки объединяются в одну позицию, поэтому журнал считает корзины, а не отдельные уровни. — исправление: журнал менять не нужно. После исправлений сравнивай доходность на одно исполнение с минимальным уровнем комиссий по отдельным уровням, а не по корзине.
Реализация
Порт советника 2MACDSTO v1.4 от geraked на ETHUSDT.OKX 4H: тренд MACD(34,144), контртренд MACD(13,21), пересечение %K/%D Stochastic(7,3,3) при выходе из 20/80. Жёсткого SL/TP нет; единственная позиция следует за ценой на расстоянии 50% от движения свинга; при движении против позиции на расстояние одного свинга добавляется уровень сетки того же размера (максимум 50), а корзина закрывается по общей цене TP, покрывающей исходный риск и издержки.
Результаты верификации
Проверка не пройдена (слой 4 — проверка QA) [класс=code_defect]: - [edge_concern] Даже после исправления размера позиции усредняющая сетка с одинаковым размером позиции на каждом из 50 уровней без стопа корзины по своей структуре представляет собой мартингейл с короткой волатильностью. На ETH (который вырос примерно на 20x за 2020-21 и упал примерно на 80% за 2022) контртрендовая корзина, попавшая в устойчивый тренд, несет неограниченный убыток после того, как общий лимит останавливает дальнейшее добавление……Показать большеСвернуть
Проверка не пройдена (слой 4 — проверка QA) [класс=code_defect]: - [edge_concern] Даже после исправления размера позиции усредняющая сетка с одинаковым размером позиции на каждом из 50 уровней без стопа корзины по своей структуре представляет собой мартингейл с короткой волатильностью. На ETH (который вырос примерно на 20x за 2020-21 и упал примерно на 80% за 2022) контртрендовая корзина, попавшая в устойчивый тренд, несет неограниченный убыток после того, как общий лимит останавливает дальнейшее добавление позиций. Минимальный порог просадки для продвижения невозможно соблюсти, пока стоп по капиталу на уровне корзины (собственный входной параметр источника EquityDrawdownLimit) не установлен в ненулевое значение. Прежде чем тратить средства на оптимизацию, проверьте наихудшую просадку корзины. - [critical] Общий лимит сетки и проверка просадки основаны на ложной предпосылке. В комментарии сказано: «get_account_equity() уже включает нереализованный PnL (переоценку по рынку)». Это не так. resolve_account_equity() возвращает account.balances()[USDT].total, а для счета NT MarginAccount эта величина отражает только реализованные денежные средства; нереализованный PnL в балансах не учитывается. Отсюда следуют три последствия. (a) `balance = equity - unreal` завышает баланс на величину всего нереализованного убытка. (b) `room = max(equity,0)*lev - qty*c` ограничивает общий объем значением 3x от денежных средств REALIZED, а не от истинного капитала 3x. По мере того как корзина уходит в убыток, фактическое кредитное плечо относительно реального капитала неограниченно растет, а уровни сетки продолжают добавляться против капитала, которого уже не существует. (c) Если equity_drawdown_limit_pct когда-либо установить выше 0, проверка сравнивает реализованные денежные средства с реализованными денежными средствами за вычетом нереализованного убытка, поэтому знак и величина результата неверны. Результаты песочницы показывают последствия: liquidated=true на 2020-06-02, total_return -100%, max_drawdown 100%, и одна сделка принесла убыток $2,949,268, то есть примерно 29x от начального капитала. В пункте обоснования разработчика (2) утверждается, что это исправлено, но исправление основано на неверной предпосылке. (строка 270) — исправление: вычисляйте истинный капитал в стратегии как mtm_equity = get_account_equity() + d*(c - avg)*qty (реализованные денежные средства плюс нереализованный PnL этой позиции). Используйте mtm_equity при проверке доступного объема для сетки (room = mtm_equity*lev - qty*c и отказывайтесь от добавлений, когда mtm_equity <= 0), а также в _level_qty для определения размера позиции. В проверке EquityDrawdownLimit используйте баланс = get_account_equity() напрямую (это уже и есть баланс). - [critical] Риск корзины не ограничен: отсутствует стоп, кредитное плечо 3x, убыток может превысить капитал (L148/L156). Когда общий лимит блокирует дальнейшие добавления, ничто не ограничивает убыток корзины, если рынок движется против тренда. Короткая корзина при ралли не освобождает места, поскольку qty*c растет, поэтому она просто удерживается до ликвидации счета. Максимальный убыток в песочнице, составивший около 29x начального капитала, доказывает, что такой сценарий возможен. Для этой конфигурации нельзя утверждать ни что «расстояние до стопа x размер позиции <= 1-2% капитала», ни что худший сценарий общего объема относительно TRUE капитала ограничен. Источник предусматривает EquityDrawdownLimit именно для этой цели. Оставлять его равным 0 на криптовалютном портфеле с плечом 3x — это дефект определения размера позиции и управления риском, а не точное следование источнику. (строка 60) — исправление: оставьте механизм без изменений, но задайте для equity_drawdown_limit_pct ненулевое значение (например, 20-30%), рассчитанное исходя из капитала MTM согласно приведенному выше исправлению. Другой вариант — снизить кредитное плечо и max_level_notional_mult, чтобы наихудший общий объем = grid_max_lvl_reachable x level_notional <= mtm_equity x максимальное кредитное плечо площадки, и указать это ограничение в обосновании. Оба параметра задаются источником, поэтому перенос остается точным. - [warning] Базовый шаблон не вызывает calculate_signal(), пока len(self._bars) < min_bars_required() (200). Поэтому инициализация EMA происходит на баре 200, а EMA(144) и MACD(34,144) остаются несошедшимися примерно еще на 150-300 баров, из-за чего ранние показания тренда смещены в сторону цены закрытия при инициализации. (строка 112) — исправление: либо требуйте прогрева сигнала примерно на 3x m2_slow баров внутри calculate_signal до установки условий покупки/продажи, либо примите это смещение и задокументируйте его. - [warning] Замедленная %K вычисляется как среднее сырых значений %K за окно замедления. Функция iStochastic в MT5 (которую вызывает EA) вычисляет ее как 100*SUM(C-LL, slowing)/SUM(HH-LL, slowing), то есть как отношение сумм. Эти варианты различаются, когда диапазон меняется на протяжении 3 баров, что немного сдвигает время пересечения 20/80. (строка 139) — исправление: для точного переноса храните в деках длиной 3 бары значения (c-ll) и (hh-ll) и вычисляйте %K как отношение их сумм. - [warning] Журнал сделок песочницы непригоден для расчета экономики отдельных сделок (L140). avg_trade_return_pct составляет -259% x 5 сделок, что невозможно согласовать с total_return -100%. avg_holding_period составляет 443 дней против data_days 162. Указано 5 сделок, но исполнений — 14. Уровни сетки объединяются в одну позицию, поэтому журнал считает корзины, а не отдельные части позиции. — исправление: менять код журнала не нужно. После исправлений сравнивайте доходность на отдельную часть позиции с порогом комиссий в расчете на исполнение, а не на корзину.
История итераций
Проверка не пройдена (уровень 4 — проверка QA) [класс=code_defect]: - [edge_concern] Пути выхода асимметричны. Одиночная позиция закрывается только по трейлинг-стопу, установленному при входе на уровне входа + 0.5*pd, поэтому минимальная валовая прибыль составляет около 0.5*pd. Значение pd может быть всего ~0.1% цены (нижний порог SLDev), в результате чего минимальная валовая прибыль оказывается около 0.05%, что ниже примерно 0.10% OKX за полный цикл тейкерских комиссий. Убыточная сторона представляет собой……Показать большеСвернуть
Проверка не пройдена (уровень 4 — проверка QA) [класс=code_defect]: - [edge_concern] Пути выхода асимметричны. Одиночная позиция закрывается только по трейлинг-стопу, установленному при входе на уровне входа + 0.5*pd, поэтому минимальная валовая прибыль составляет около 0.5*pd. Значение pd может быть всего ~0.1% цены (нижний порог SLDev), в результате чего минимальная валовая прибыль оказывается около 0.05%, что ниже примерно 0.10% OKX за полный цикл тейкерских комиссий. Убыточная сторона представляет собой усредняющую корзину без ограничения убытка. Результат в песочнице это подтверждает: 3 из 4 сделок принесли небольшую прибыль (средняя прибыль $3.1 тыс.), а одна короткая корзина понесла убыток $5.25 млн. Даже после исправления ликвидации проверьте распределение pd/цены на входе и убедитесь, что выходы по трейлингу перекрывают 0.15% номинала. - [критично] Убыток не ограничен, и портфель может потерять намного больше средств, чем есть на счёте. Конструкция EA «без SL» работает только на MT5, поскольку принудительное закрытие корзины брокером происходит при ликвидации по марже. В переносе нет ничего, что выполняло бы эту функцию. Когда добавления в сетку достигают валового лимита (свободный объём <= 0), корзина остаётся открытой без выхода, кроме TP корзины. Трейлинг одиночной позиции отключён, поскольку _b_level > 1. Ликвидации по капиталу или марже нет, как нет и выхода по времени. Песочница показывает результат. Короткая корзина удерживалась 554 дней, с номиналом avg_trade_return_pct -290% и максимальным убытком -$5.25 млн при общей комиссии $3.2 тыс. Этот убыток во много раз превышает размер счёта, и стратегия продолжала работать после флага ликвидации от 2020-05-30. Все показатели после этой даты бессмысленны. В конструкции нет состояния без позиции и ограниченного риска — это в точности случай L148/L156: валовая экспозиция в худшем случае равна плечу (5), умноженному на капитал, без стопа. Движение на +20% ETH против полностью набранной короткой корзины уже обнуляет счёт, а в песочнице убыток вырос до многократного размера капитала. (строка 256) — исправление: Добавьте ликвидацию по марже, имитирующую поведение брокера MT5 (это поведение брокера, а не SL стратегии, поэтому перенос останется точным). На каждом баре рассчитывайте нереализованный PnL корзины по pos.avg_px_open и цене закрытия. Закрывайте всю корзину и сбрасывайте состояние, когда капитал с учётом нереализованного PnL падает до уровня ликвидации или ниже, например при уровне маржи <= 50%, либо когда нереализованный убыток >= X% капитала, где X задан согласно предварительно зарегистрированному max_drawdown. Сделайте этот уровень параметром. Также укажите наихудший сценарий в обосновании: максимальный убыток на корзину равен уровню ликвидации, а не «ограничивается плечом». - [критично] Свободный объём для добавлений в сетку рассчитывается на основе get_account_equity(). Это реализованный, стабильный относительно USD показатель BALANCE, исключающий нереализованный убыток открытой корзины. Пока корзина убыточна, каждое добавление по-прежнему рассчитывается относительно баланса до убытка: свободный объём = 5 x баланс - qty*c. Портфель продолжает наращивать плечо при просадке, уже поглотившей значительную часть реального капитала, поэтому фактическое плечо на реальный капитал может значительно превысить 5x до прекращения добавлений. Тот же устаревший баланс используется для _level_qty/_b_risk_amt корзины TP. (строка 265) — исправление: Используйте капитал по текущей рыночной оценке для валового лимита сетки: баланс + нереализованный PnL открытой позиции по цене закрытия c. Прекращайте добавления, когда плечо относительно реального капитала достигает лимита. - [предупреждение] Условия тренда и встречного движения MACD считывают бар [2] (_m2_prev/_m1_prev), тогда как пересечение стохастика считывается как [2]->[1]. В описании сказано, что это соответствует EA («MACD предыдущего бара»). В рамках этой проверки я не смог сверить точные индексы буфера с зафиксированным коммитом исходного кода. Если EA считывает MACD в [1], точки входа смещены на один бар. (строка 143) — исправление: Повторно проверьте индексы CopyBuffer в 2MACDSTO.mq5@d3eb29c и согласуйте сдвиг MACD. - [предупреждение] Трейлинг-стоп и TP корзины оцениваются только при закрытии баров, исполнение происходит по цене закрытия. Проверки EA выполняются по таймеру с интервалом 30 секунд. На барах 4H ETH выходы по трейлингу могут исполниться значительно хуже уровня трейлинга, а исполнения TP корзины могут выйти за заданный уровень. Разработчик задокументировал это отклонение. (строка 243) — исправление: Допустимо, если это задокументировано. Рассмотрите возможность размещения стоп-заявки только на сокращение позиции на уровне _b_trail с обновлением на каждом баре. - [предупреждение] В журнале каждая сеточная корзина учитывается как одна сделка в единой неттинговой позиции (разработчик отметил это в разделе L175). Поэтому total_trades и avg_trade_return_pct считают корзины, а не уровни, из-за чего сравнение минимальной комиссии за сделку занижает стоимость нескольких исполнений. В песочнице также указаны trades_count 15 против total_trades 4. — исправление: Указывайте число исполнений ордеров сетки рядом с числом корзин, чтобы аналитик мог учесть комиссию за каждое исполнение.
Проверка не пройдена (слой 4 — проверка QA) [класс=code_defect]: - [edge_concern] Дымовой тест теряет 36.0% при просадке 88.7% и PF 0.94; это рекомендация, а не вердикт о корректности. - [critical] Реализация добавляет жёсткие стопы по просадке капитала 30% и уровню маржи 50%, что противоречит гипотезе о конструкции без жёсткого SL/TP. (строка 254) — исправление: Удалить их или явно пересмотреть и повторно зарегистрировать гипотезу. - [critical] get_account_equity() уже включает нереализованный PnL, но код……Показать большеСвернуть
Проверка не пройдена (слой 4 — проверка QA) [класс=code_defect]: - [edge_concern] Дымовой тест теряет 36.0% при просадке 88.7% и PF 0.94; это рекомендация, а не вердикт о корректности. - [critical] Реализация добавляет жёсткие стопы по просадке капитала 30% и уровню маржи 50%, что противоречит гипотезе о конструкции без жёсткого SL/TP. (строка 254) — исправление: Удалить их или явно пересмотреть и повторно зарегистрировать гипотезу. - [critical] get_account_equity() уже включает нереализованный PnL, но код повторно добавляет нереализованный PnL для формирования true_eq. Поэтому расчёты просадки, стоп-аута по марже и доступного объёма сетки некорректны. (строка 255) — исправление: Получить баланс, вычтя текущий нереализованный PnL, а затем добавить его ровно один раз. - [critical] Минимальное расстояние колебания составляет 0.1%, но трейлинг-стоп 50% даёт лишь валовое движение 0.05%, ниже минимального уровня жизнеспособности 0.15% и приблизительно равное комиссии тейкера за полный цикл 0.10% OKX. (строка 79) — исправление: Установить минимальное эффективное движение трейлинг-стопа выше 0.15% с запасом на проскальзывание. - [critical] Для замедления стохастика используется отношение сумм исходных числителей и знаменателей вместо усреднения исходных значений %K, как того требует стандартная семантика Stochastic(7,3,3). (строка 140) — исправление: Усреднять исходные значения %K в окне замедления, затем усреднять замедленные значения %K для получения %D. - [critical] При гэпе через несколько расстояний сетки отправляется один совокупный ордер, но счётчик уровней увеличивается на n_add. Если лимит обрезает объём ордера, состояние показывает уровни, по которым не было исполнений, что нарушает учёт сетки с равными объёмами. (строка 306) — исправление: Отправлять и учитывать каждый уровень отдельно либо определять фактически исполненные уровни по отправленному объёму.
Сводка по итогам
Для переноса усредняющей сетки или мартингейла необходим стоп капитала на уровне корзины и расчёт размера сетки на основе реального капитала по рынку (реализованные денежные средства плюс нереализованный PnL); точный перенос с отключённым лимитом просадки исходной стратегии не способен пережить тренды криптовалют с плечом.
После 3 итераций стратегию забросили в цикле проверки, когда проверка слоя 4 QA признала её code_defect. Валовой лимит сетки и проверка просадки ошибочно считали, что get_account_equity() учитывает переоценку по рынку, хотя она отражает только реализованные денежные средства; кроме того, в сетке с одинаковыми размерами ордеров и плечом 3x не было стопа корзины (EquityDrawdownLimit оставили на уровне 0), поэтому убытки не были ограничены.
Точный перенос geraked's MQL5 EA 2MACDSTO на ETHUSDT.OKX 4H: входить на откатах при тренде MACD(34,144), когда MACD(13,21) указывает в противоположную сторону, а Stochastic(7,3,3) пересекает границу выхода из зоны 20/80; жёсткого SL/TP нет, используется скользящий стоп на уровне 50% риска и сетка усреднения с равными объёмами до 50 уровней, закрываемая как единая корзина по общей цели прибыли.
Полный бэктест и оптимизация не проводились. Единственное свидетельство о результатах — проверочный запуск в песочнице: ликвидация на 2020-06-02, общая доходность -100% и максимальная просадка 100%; одна сделка принесла убыток около $2,949,268, примерно 29x начального капитала.
Причина отказа
verification_loop: проверка не пройдена (слой 4 — проверка QA) [класс=code_defect]: - [edge_concern] Даже после исправления размера равномерная усредняющая сетка из 50 уровней без стопа для корзины по своей структуре является мартингейлом с короткой волатильностью. На ETH (рост примерно на 20x за 2020-21 и падение на 80% за 2022) контртрендовая корзина, попавшая в устойчивый тренд, несёт неограниченный убыток после того, как лимит валового объёма блокирует дальнейшие добавления. Минимальную просадку для……Показать большеСвернуть
verification_loop: проверка не пройдена (слой 4 — проверка QA) [класс=code_defect]: - [edge_concern] Даже после исправления размера равномерная усредняющая сетка из 50 уровней без стопа для корзины по своей структуре является мартингейлом с короткой волатильностью. На ETH (рост примерно на 20x за 2020-21 и падение на 80% за 2022) контртрендовая корзина, попавшая в устойчивый тренд, несёт неограниченный убыток после того, как лимит валового объёма блокирует дальнейшие добавления. Минимальную просадку для прохождения отбора невозможно обеспечить, если не задать ненулевой стоп капитала на уровне корзины (исходный параметр EquityDrawdownLimit). Проверь худшую просадку корзины, прежде чем тратить средства на оптимизацию. - [critical] Лимит валового объёма сетки и проверка просадки основаны на неверной предпосылке. В комментарии сказано: «get_account_equity() уже включает нереализованный PnL (mark-to-market)». Это не так. resolve_account_equity() возвращает account.balances()[USDT].total, а в NT MarginAccount эта величина означает только реализованные средства; нереализованный PnL в балансе не отражён. Отсюда три последствия. (a) `balance = equity - unreal` завышает баланс на величину всего нереализованного убытка. (b) `room = max(equity,0)*lev - qty*c` ограничивает валовой объём величиной 3x реализованных средств REALIZED, а не реальным капиталом 3x. По мере роста убытка корзины фактическое плечо относительно реального капитала неограниченно увеличивается, а уровни сетки продолжают добавляться за счёт уже несуществующего капитала. (c) Если equity_drawdown_limit_pct когда-либо установлено выше 0, проверка сопоставляет реализованные средства с их значением за вычетом нереализованного PnL, поэтому знак и величина результата неверны. Это видно в песочнице: счёт ликвидирован (2020-06-02) на total_return -100%, max_drawdown 100%, а одна сделка принесла убыток $2,949,268 — примерно 29x от начального капитала. В пункте обоснования разработчика (2) заявлено, что проблема исправлена, но исправление основано на неверной предпосылке. (строка 270) — исправление: вычисляй реальный капитал в стратегии так: mtm_equity = get_account_equity() + d*(c - avg)*qty (реализованные средства плюс нереализованный PnL этой позиции). Используй mtm_equity при проверке свободного места для сетки (место = mtm_equity*lev - qty*c; запрещай добавление, если mtm_equity <= 0) и в _level_qty для расчёта размера. При проверке EquityDrawdownLimit используй непосредственно balance = get_account_equity() (это уже баланс). - [critical] Риск корзины неограничен: стопа нет, плечо 3x, убыток может превысить капитал (L148/L156). Когда лимит валового объёма блокирует дальнейшие добавления, ничто не ограничивает убыток корзины, движущейся против тренда. При росте рынка короткая корзина не освобождает место, поскольку qty*c увеличивается, поэтому она просто удерживается до ликвидации счёта. Крупнейший убыток в песочнице, около 29x начального капитала, доказывает, что такой сценарий возможен. Для этой конфигурации нельзя заявить ни «расстояние до стопа x размер <= 1-2% капитала», ни предельный валовой объём относительно капитала TRUE в худшем сценарии. В исходном коде для этого предусмотрен параметр EquityDrawdownLimit. Оставлять его на уровне 0 в криптопорте с плечом 3x — дефект расчёта размера и риска, а не сохранение исходной стратегии. (строка 60) — исправление: сохрани механизм без изменений, но задай equity_drawdown_limit_pct ненулевое значение (например, 20-30%), рассчитываемое от капитала MTM согласно исправлению выше. Или снизь плечо и max_level_notional_mult, чтобы предельный валовой объём = grid_max_lvl_reachable x level_notional <= mtm_equity x максимальное плечо площадки, и укажи этот предел в обосновании. Оба параметра есть в исходнике, поэтому порт останется верным оригиналу. - [warning] Базовый шаблон не вызывает calculate_signal(), пока len(self._bars) < min_bars_required() (200). Поэтому EMA начинают расчёт с бара 200, а EMA(144) и MACD(34,144) не сходятся примерно в течение следующих 150-300 баров; ранние показания тренда смещены к цене закрытия начального бара. (строка 112) — исправление: либо требуй около 3x m2_slow баров прогрева сигнала внутри calculate_signal до установки условий покупки/продажи, либо прими это смещение и опиши его. - [warning] Замедленный %K вычисляется как среднее исходных значений %K за окно замедления. iStochastic в MT5 (который вызывает EA) вычисляет его как 100*SUM(C-LL, slowing)/SUM(HH-LL, slowing), то есть как отношение сумм. Результаты различаются, когда диапазон меняется в пределах 3 баров, поэтому время пересечения 20/80 слегка смещается. (строка 139) — исправление: для точного порта храни в двусторонних очередях длиной 3 баров значения (c-ll) и (hh-ll), а %K вычисляй как отношение их сумм. - [warning] Журнал сделок песочницы непригоден для расчёта экономики каждой сделки (L140). avg_trade_return_pct — это -259% x 5 сделок, что не согласуется с total_return -100%. avg_holding_period — это 443 дней против data_days 162. Указано 5 сделок, но исполнений — 14. Уровни сетки объединяются в одну позицию, поэтому журнал считает корзины, а не отдельные уровни. — исправление: журнал менять не нужно. После исправлений сравнивай доходность на одно исполнение с минимальным уровнем комиссий по отдельным уровням, а не по корзине.
Анализ
2MACDSTO
Stratmill — это инструмент для исследований и бумажной торговли, а не финансовая консультация или брокер. Результаты бэктестов и бумажной торговли являются гипотетическими. Торговля сопряжена с риском убытков.