Открыть на GitHub

Стратегия CDC PL MFI

Обзор

CDC PL MFI — перенос на StockSharp советника MetaTrader Expert_ADC_PL_MFI (MQL/299). Стратегия отслеживает разворотные свечные модели Dark Cloud Cover и Piercing Line и подтверждает каждую из них осциллятором Money Flow Index (MFI). Реализованы исходные периоды индикаторов и пороги, добавлены опциональные стоп-лосс и тейк-профит в пунктах, а выход из позиции происходит при пересечении MFI заданных уровней разворота.

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

  1. Подписка на выбранный тип свечей (по умолчанию часовые) и расчёт Money Flow Index с заданным периодом. Дополнительно поддерживаются простые скользящие средние для размера тела свечей и цен закрытия, что воспроизводит фильтры тренда и импульса оригинала.
  2. При формировании бычьей модели Piercing Line (гэп ниже минимума предыдущей свечи, закрытие выше середины тела медвежьей свечи, обе свечи длиннее среднего тела, а предыдущее закрытие ниже трендовой средней) и значении MFI ниже LongEntryLevel (по умолчанию 40) стратегия открывает или переворачивает позицию в лонг.
  3. При появлении медвежьей модели Dark Cloud Cover (гэп выше максимума предыдущей свечи, закрытие ниже середины тела бычьей свечи, обе свечи длиннее среднего тела, а предыдущее закрытие выше трендовой средней) и значении MFI выше ShortEntryLevel (по умолчанию 60) стратегия открывает или переворачивает позицию в шорт.
  4. MFI контролирует выходы:
    • Шорты закрываются, когда MFI пересекает снизу вверх ExitLowerLevel (30) или ExitUpperLevel (70).
    • Лонги закрываются, когда MFI пересекает сверху вниз ExitUpperLevel (70) или ExitLowerLevel (30).
  5. Защитные ордера опциональны. Если TakeProfitPips или StopLossPips больше нуля, вызывается StartProtection, а расстояние переводится из пунктов в цену (пункт умножается на шаг цены инструмента).

Параметры

Параметр Описание Значение по умолчанию
CandleType Тип свечей для поиска моделей. Таймфрейм 1 час
MfiPeriod Период расчёта Money Flow Index. 49
BodyAveragePeriod Количество свечей для среднего размера тела. 11
LongEntryLevel Уровень MFI, подтверждающий бычью модель. 40
ShortEntryLevel Уровень MFI, подтверждающий медвежью модель. 60
ExitLowerLevel Нижний уровень MFI для закрытия шортов. 30
ExitUpperLevel Верхний уровень MFI для закрытия лонгов. 70
StopLossPips Стоп-лосс в пунктах (0 — отключено). 50
TakeProfitPips Тейк-профит в пунктах (0 — отключено). 50

Примечания

  • Базовый объём — 1 лот. При перевороте позиции отправляется один рыночный ордер, перекрывающий текущий объём и открывающий новую позицию, как в оригинальном советнике.
  • Распознавание моделей повторяет логику MetaTrader: анализируются только завершённые свечи, гэпы должны выходить за пределы предыдущего максимума/минимума, а простая скользящая средняя подтверждает преобладающий тренд.
  • Значения Money Flow Index получаются напрямую от индикатора, стратегия хранит только последние значения для отслеживания пересечений порогов.
  • Версия на Python отсутствует, представлен только C#-код.
namespace StockSharp.Samples.Strategies;

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

/// <summary>
/// CDC PL MFI strategy: Dark Cloud Cover and Piercing Line candlestick patterns
/// confirmed by Money Flow Index levels.
/// </summary>
public class CdcPlMfiStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _mfiPeriod;
	private readonly StrategyParam<decimal> _longLevel;
	private readonly StrategyParam<decimal> _shortLevel;
	private readonly StrategyParam<int> _signalCooldownCandles;

	private readonly List<ICandleMessage> _candles = new();
	private decimal _prevMfi;
	private bool _hasPrevMfi;
	private int _candlesSinceTrade;

	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
	public int MfiPeriod { get => _mfiPeriod.Value; set => _mfiPeriod.Value = value; }
	public decimal LongLevel { get => _longLevel.Value; set => _longLevel.Value = value; }
	public decimal ShortLevel { get => _shortLevel.Value; set => _shortLevel.Value = value; }
	public int SignalCooldownCandles { get => _signalCooldownCandles.Value; set => _signalCooldownCandles.Value = value; }

	public CdcPlMfiStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
			.SetDisplay("Candle Type", "Candle timeframe", "General");
		_mfiPeriod = Param(nameof(MfiPeriod), 14)
			.SetGreaterThanZero()
			.SetDisplay("MFI Period", "Money Flow Index period", "Indicators");
		_longLevel = Param(nameof(LongLevel), 40m)
			.SetDisplay("Long Level", "MFI below this for long entry", "Signals");
		_shortLevel = Param(nameof(ShortLevel), 60m)
			.SetDisplay("Short Level", "MFI above this for short entry", "Signals");
		_signalCooldownCandles = Param(nameof(SignalCooldownCandles), 6)
			.SetGreaterThanZero()
			.SetDisplay("Signal Cooldown", "Bars to wait between trades", "Trading");
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_candles.Clear();
		_prevMfi = 0m;
		_hasPrevMfi = false;
		_candlesSinceTrade = SignalCooldownCandles;
	}

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_candles.Clear();
		_hasPrevMfi = false;
		_candlesSinceTrade = SignalCooldownCandles;
		var mfi = new MoneyFlowIndex { Length = MfiPeriod };
		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(mfi, ProcessCandle).Start();

		StartProtection(
			takeProfit: new Unit(2, UnitTypes.Percent),
			stopLoss: new Unit(1, UnitTypes.Percent)
		);
	}

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

		if (_candlesSinceTrade < SignalCooldownCandles)
			_candlesSinceTrade++;

		_candles.Add(candle);
		if (_candles.Count > 5)
			_candles.RemoveAt(0);

		if (_candles.Count >= 2 && _hasPrevMfi)
		{
			var curr = _candles[^1];
			var prev = _candles[^2];

			// Piercing Line: prev bearish, curr bullish, opens below prev low, closes above midpoint
			var isPiercing = prev.OpenPrice > prev.ClosePrice
				&& curr.ClosePrice > curr.OpenPrice
				&& curr.OpenPrice < prev.LowPrice
				&& curr.ClosePrice > (prev.OpenPrice + prev.ClosePrice) / 2m;

			// Dark Cloud Cover: prev bullish, curr bearish, opens above prev high, closes below midpoint
			var isDarkCloud = prev.ClosePrice > prev.OpenPrice
				&& curr.OpenPrice > curr.ClosePrice
				&& curr.OpenPrice > prev.HighPrice
				&& curr.ClosePrice < (prev.OpenPrice + prev.ClosePrice) / 2m;

			if (isPiercing && mfiValue < LongLevel && Position == 0 && _candlesSinceTrade >= SignalCooldownCandles)
			{
				BuyMarket();
				_candlesSinceTrade = 0;
			}
			else if (isDarkCloud && mfiValue > ShortLevel && Position == 0 && _candlesSinceTrade >= SignalCooldownCandles)
			{
				SellMarket();
				_candlesSinceTrade = 0;
			}
		}

		_prevMfi = mfiValue;
		_hasPrevMfi = true;
	}
}