Открыть на GitHub

Стратегия FX Chaos Pyramid

Общее описание

FX Chaos Pyramid — это порт MetaTrader 4 советника «FX-CHAOS» из каталога MQL/8055. Стратегия использует связку дневного фильтра и рабочей 4-часовой разметки: входы совершаются на Н4, при этом дневные уровни задают контекст для прорыва. Первая сделка открывается только при подтверждении индикатором Awesome Oscillator, а дальнейшие сигналы усиливают позицию по принципу пирамидинга.

Реализация полностью базируется на высокоуровневом API StockSharp: подписки на свечи, привязка индикатора и стандартные помощники для заявок. Поэтому стратегию можно сразу использовать как в тестере, так и в онлайн-торговле.

Логика торговли

Дневной фильтр

  • Подписка на дневные свечи и вычисление последнего подтверждённого фрактала с помощью окна из пяти свечей.
  • Сохранение максимума и минимума предыдущего дня. Перед проверкой пробоя к уровням добавляется пользовательский буфер в шагах цены.

Основной таймфрейм

  • Подписка на 4-часовые свечи и привязка Awesome Oscillator (по умолчанию периоды 5 и 34).
  • Определение последнего фрактала на 4-часовом ряду — таким образом воссоздаётся работа оригинального индикатора zzf.
  • Для каждого нового торгового дня фиксируется цена открытия первой 4-часовой свечи, что соответствует вызову iOpen(NULL, 1440, 0).

Сигналы на вход

  • Покупка (этап 1): текущий день открылся ниже буферизированного максимума прошлого дня, 4-часовая свеча закрылась выше этого уровня, цена остаётся ниже последнего дневного восходящего фрактала, а значение AO отрицательное. Перед входом закрываются открытые продажи.
  • Продажа (этап 1): зеркальные условия с использованием минимума и положительного AO.

Пирамидинг

После открытия первой позиции каждая завершённая 4-часовая свеча проверяет возможность добавления:

  • Для продолжения покупок свеча должна открытьcя ниже и закрыться выше буферизированного максимума предыдущей 4-часовой свечи, оставаясь ниже последнего восходящего фрактала на Н4.
  • Для продолжения продаж используются минимум и нисходящий фрактал.
  • Дополнительно можно требовать, чтобы текущая стоимость портфеля превышала баланс (AccountEquity() > AccountBalance()), как это сделано в МТ4.

Количество ступеней ограничивается параметром (до пяти, как в исходнике). Счётчики сбрасываются при закрытии позиции или смене направления.

Управление объёмом

Советник на MT4 выбирает один из заранее заданных наборов объёмов в зависимости от величины MAX_Lots, которая растёт ступенчато по мере увеличения баланса. Порт использует те же таблицы и добавляет параметры для базового баланса, шага роста и общего множителя объёмов.

Диапазон MAX_Lots Этап 1 Этап 2 Этап 3 Этап 4 Этап 5
< 2 0.10 0.50 0.40 0.30 0.20
[2, 4) 0.20 1.00 0.80 0.60 0.40
[4, 5) 0.30 1.50 1.20 0.90 0.60
[5, 7) 0.40 2.00 1.60 1.20 0.80
[7, 8) 0.50 2.50 2.00 1.50 1.00
[8, 10) 0.60 3.00 2.40 1.80 1.20
[10, 11) 0.70 3.50 2.80 2.10 1.40
[11, 13) 0.80 4.00 3.20 2.40 1.60
[13, 14) 0.90 4.50 3.60 2.70 1.80
≥ 14 1.00 5.00 4.00 3.00 2.00

Параметр VolumeScale масштабирует весь набор, что удобно при смене инструмента или брокера.

Параметры

Название Описание
Primary Candle Рабочий таймфрейм для сигналов (по умолчанию 4 часа).
Daily Candle Таймфрейм старшего уровня для расчёта уровней (по умолчанию сутки).
AO Fast / AO Slow Быстрый и медленный периоды Awesome Oscillator.
Breakout Buffer Буфер в шагах цены, добавляемый к максимумам и минимумам.
Max Stages Максимальное число ступеней пирамиды (1–5).
Require Profit Требовать ли положительную плавающую прибыль перед добавлением.
Volume Scale Общий множитель для выбранного набора объёмов.
Base Balance Баланс, соответствующий минимальному набору объёмов.
Balance Step Прирост баланса, переводящий стратегию к следующему набору.

Отличия от MQL4-версии

  • Используются свечные подписки StockSharp, а не прямые функции iClose/iHigh; нужные уровни хранятся внутри стратегии.
  • Индикатор zzf заменён встроенным детектором фракталов на пять свечей.
  • Управление стоп-приказами в исходнике зависело от брокера, поэтому в порт не включено. Пользователь может добавить собственный модуль риска.
  • Исключены звуковые оповещения и работа с глобальными переменными терминала.

Рекомендации

  1. Подключайте стратегию к портфелю, где доступны показатели баланса и текущей стоимости — это обеспечит корректный выбор матрицы объёмов.
  2. Для тестов используйте синхронные данные по дневным и 4-часовым свечам. Несогласованные интервалы снижают точность сигналов.
  3. При работе с инструментами с другими шагами цены подбирайте параметр BreakoutBuffer.
  4. Для отладки включайте построение графика: стратегия отображает свечи, гистограмму AO и точки сделок.
using System;

using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;

namespace StockSharp.Samples.Strategies;

public class FxChaosPyramidStrategy : Strategy
{
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;
	private readonly StrategyParam<int> _cooldownCandles;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _prevFast;
	private decimal _prevSlow;
	private bool _hasPrev;
	private int _cooldownRemaining;

	public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
	public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
	public int CooldownCandles { get => _cooldownCandles.Value; set => _cooldownCandles.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public FxChaosPyramidStrategy()
	{
		_fastPeriod = Param(nameof(FastPeriod), 20).SetDisplay("Fast WMA", "Fast WMA period", "Indicators");
		_slowPeriod = Param(nameof(SlowPeriod), 80).SetDisplay("Slow WMA", "Slow WMA period", "Indicators");
		_cooldownCandles = Param(nameof(CooldownCandles), 150).SetDisplay("Cooldown", "Candles between signals", "General");
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame()).SetDisplay("Candle Type", "Candle timeframe", "General");
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevFast = default;
		_prevSlow = default;
		_hasPrev = default;
		_cooldownRemaining = default;
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_prevFast = 0;
		_prevSlow = 0;
		_hasPrev = false;
		_cooldownRemaining = 0;

		var fast = new WeightedMovingAverage { Length = FastPeriod };
		var slow = new WeightedMovingAverage { Length = SlowPeriod };
		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(fast, slow, ProcessCandle).Start();
	}

	private void ProcessCandle(ICandleMessage candle, decimal fast, decimal slow)
	{
		if (candle.State != CandleStates.Finished) return;
		if (!_hasPrev) { _prevFast = fast; _prevSlow = slow; _hasPrev = true; return; }

		if (_cooldownRemaining > 0)
		{
			_cooldownRemaining--;
			_prevFast = fast;
			_prevSlow = slow;
			return;
		}

		if (_prevFast <= _prevSlow && fast > slow && Position <= 0)
		{
			if (Position < 0) BuyMarket();
			BuyMarket();
			_cooldownRemaining = CooldownCandles;
		}
		else if (_prevFast >= _prevSlow && fast < slow && Position >= 0)
		{
			if (Position > 0) SellMarket();
			SellMarket();
			_cooldownRemaining = CooldownCandles;
		}
		_prevFast = fast;
		_prevSlow = slow;
	}
}