Открыть на GitHub

Стратегия AML CCI Meeting Lines

Эта стратегия переносит советник MetaTrader 5 "Expert_AML_CCI" в высокоуровневый фреймворк StockSharp. Исходный робот объединяет японскую свечную модель «Meeting Lines» с фильтром Commodity Channel Index (CCI) и использует механизм Expert Advisor для взвешивания бычьих и медвежьих сигналов. Порт на StockSharp сохраняет ту же логику подтверждения, переписывает распознавание свечных моделей через арифметику свечей и делает все пороговые уровни доступными для оптимизации.

Как это работает

  • Источник данных – Стратегия подписывается на свечи выбранного таймфрейма (по умолчанию 30 минут) с помощью SubscribeCandles. Каждый завершённый бар поступает вместе с синхронизированным значением CCI через высокоуровневый конвейер Bind, поэтому ручное сопровождение индикатора не требуется.
  • Основной индикатор – Один CommodityChannelIndex с периодом CciPeriod полностью повторяет осциллятор из MetaTrader. Значения сохраняются во внутреннем буфере, чтобы сравнивать два последних завершённых чтения, тем самым имитируя вызовы CCI(1) и CCI(2) в MQL.
  • Логика свечей – Вспомогательные методы воспроизводят проверки "Bullish Meeting Lines" и "Bearish Meeting Lines". Они вычисляют скользящее среднее длины тел за AverageBodyPeriod свечей (по умолчанию 3) и соблюдают требования к длинным телам и почти равным закрытиям, заложенные в фильтре CML_CCI. StockSharp работает с закрытыми свечами, поэтому модель оценивается в тот же момент, когда закрывается вторая свеча паттерна – именно тогда MQL-советник отдаёт свои 80 голосов.
  • Правила входа
    • Для открытия лонга необходим бычий паттерн Meeting Lines и последнее завершённое значение CCI, не превышающее LongEntryCciLevel (по умолчанию −50). Если в рынке уже есть шорт, объём заявки автоматически включает абсолютную величину текущей позиции, чтобы перевернуться, как в оригинальном роботе.
    • Для шорта условия зеркальные: медвежий Meeting Lines и значение CCI не ниже ShortEntryCciLevel (по умолчанию +50).
  • Правила выхода – Вместо голосов Expert Advisor используются явные команды на закрытие позиции. Выход выполняется, когда CCI пересекает экстремальную границу ExtremeCciLevel (по умолчанию 80):
    • Шорты закрываются, когда CCI пробивает снизу вверх уровень −Extreme или возвращается ниже +Extreme.
    • Лонги закрываются, когда CCI опускается ниже +Extreme или прорывает вниз уровень −Extreme. Эти условия повторяют ветку с весом 40 в методах LongCondition и ShortCondition класса сигнала MQL.
  • Управление рисками – Защитные стопы и тейк-профиты оставлены на усмотрение пользователя. При необходимости можно подключить стандартный StartProtection из StockSharp.

Параметры

Параметр Описание Значение по умолчанию
CandleType Таймфрейм исходных свечей. 30 минут
CciPeriod Период осциллятора CCI. 18
AverageBodyPeriod Количество свечей для расчёта средней длины тела. 3
LongEntryCciLevel Уровень перепроданности для подтверждения бычьего паттерна. −50
ShortEntryCciLevel Уровень перекупленности для подтверждения медвежьего паттерна. +50
ExtremeCciLevel Абсолютное значение полосы CCI для выходов. 80

Все числовые параметры имеют диапазоны оптимизации, соответствующие настройкам оригинального советника, поэтому стратегию можно тонко настраивать через инструменты оптимизации StockSharp.

Рекомендации по использованию

  1. Перед запуском привяжите стратегию к инструменту и задайте желаемый Volume.
  2. При необходимости скорректируйте пороговые значения под свою модель управления капиталом или под требуемую чувствительность.
  3. Графический модуль отображает свечи, кривую CCI и совершённые сделки, что упрощает визуальную проверку работы фильтра свечей.

Сохраняя ту же комбинацию свечных моделей и CCI, порт на StockSharp обеспечивает точное соответствие советнику Expert_AML_CCI и следует рекомендациям по использованию высокоуровневого API.

namespace StockSharp.Samples.Strategies;

using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;

/// <summary>
/// Meeting Lines + CCI strategy.
/// Buys on bullish meeting lines with low CCI, sells on bearish meeting lines with high CCI.
/// </summary>
public class AmlCciMeetingLinesStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _cciPeriod;
	private readonly StrategyParam<decimal> _cciLow;
	private readonly StrategyParam<decimal> _cciHigh;

	private ICandleMessage _prevCandle;

	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
	public int CciPeriod { get => _cciPeriod.Value; set => _cciPeriod.Value = value; }
	public decimal CciLow { get => _cciLow.Value; set => _cciLow.Value = value; }
	public decimal CciHigh { get => _cciHigh.Value; set => _cciHigh.Value = value; }

	public AmlCciMeetingLinesStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
			.SetDisplay("Candle Type", "Candle timeframe", "General");
		_cciPeriod = Param(nameof(CciPeriod), 14)
			.SetGreaterThanZero()
			.SetDisplay("CCI Period", "CCI period", "Indicators");
		_cciLow = Param(nameof(CciLow), -50m)
			.SetDisplay("CCI Low", "CCI level for bullish entry", "Signals");
		_cciHigh = Param(nameof(CciHigh), 50m)
			.SetDisplay("CCI High", "CCI level for bearish entry", "Signals");
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevCandle = null;
	}

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_prevCandle = null;
		var cci = new CommodityChannelIndex { Length = CciPeriod };
		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(cci, ProcessCandle).Start();
	}

	private void ProcessCandle(ICandleMessage candle, decimal cciValue)
	{
		if (candle.State != CandleStates.Finished) return;

		if (_prevCandle != null)
		{
			var avgBody = (Math.Abs(candle.ClosePrice - candle.OpenPrice) +
						   Math.Abs(_prevCandle.ClosePrice - _prevCandle.OpenPrice)) / 2m;

			if (avgBody > 0)
			{
				var prevBearish = _prevCandle.OpenPrice > _prevCandle.ClosePrice;
				var currBullish = candle.ClosePrice > candle.OpenPrice;
				var closesNear = Math.Abs(candle.ClosePrice - _prevCandle.ClosePrice) < avgBody * 0.3m;

				// Bullish meeting lines
				if (prevBearish && currBullish && closesNear && cciValue < CciLow && Position <= 0)
					BuyMarket();

				var prevBullish = _prevCandle.ClosePrice > _prevCandle.OpenPrice;
				var currBearish = candle.OpenPrice > candle.ClosePrice;
				var closesNear2 = Math.Abs(candle.ClosePrice - _prevCandle.ClosePrice) < avgBody * 0.3m;

				// Bearish meeting lines
				if (prevBullish && currBearish && closesNear2 && cciValue > CciHigh && Position >= 0)
					SellMarket();
			}
		}

		_prevCandle = candle;
	}
}