Открыть на GitHub

Стратегия Exp Color PEMA Digit Tm Plus

Описание

Exp Color PEMA Digit Tm Plus — порт советника MetaTrader 5 «Exp_ColorPEMA_Digit_Tm_Plus». Стратегия воссоздаёт оригинальный индикатор Pentuple Exponential Moving Average (PEMA) и сохраняет все флаги доступа к торговым операциям. Сделки выполняются по выбранной серии свечей только после смены цвета индикатора и выдержки, заданной параметром Signal Bar.

Версия для StockSharp сохраняет систему мани-менеджмента, контроль стопов/тейков и временной выход, присутствовавшие в MQL-версии. Все настройки оформлены через StrategyParam<T>, что облегчает конфигурирование и оптимизацию в интерфейсе.

Логика индикатора

  • Используются восемь каскадно соединённых экспоненциальных скользящих средних с длиной PEMA Length и ценой из параметра Applied Price.
  • Итоговое значение округляется до Rounding Digits, полностью повторяя работу оригинального индикатора.
  • Наклон округлённой линии задаёт три состояния:
    • Up (magenta) — бычье давление, потенциальный вход в покупки.
    • Flat (gray) — нейтральная зона, действий нет.
    • Down (dodger blue) — медвежье давление, потенциальный вход в продажи.
  • Состояние индикатора сохраняется для каждой закрытой свечи, что позволяет обращаться к истории при Signal Bar > 0.

Правила торговли

  1. Определение сигнала — на закрытой свече анализируется состояние индикатора, которое соответствует свече, отстоящей на Signal Bar баров, и сравнивается с предыдущим значением.
  2. Вход в покупки — при переходе состояния в Up:
    • добавляется запрос на открытие длинной позиции (если активен флаг Allow Long Entries);
    • формируется запрос на закрытие шортов (если активен Allow Short Exits).
  3. Вход в продажи — при переходе состояния в Down:
    • добавляется запрос на открытие короткой позиции (если активен Allow Short Entries);
    • формируется запрос на закрытие лонгов (если активен Allow Long Exits).
  4. Исполнение — отложенные действия выполняются только при условии, что
    • стратегия находится онлайн и разрешено торговать;
    • достигнуто время активации, связанное с исходной свечой;
    • расчёт мани-менеджмента даёт ненулевой объём сделки.
  5. Управление рисками
    • стоп-лосс и тейк-профит рассчитываются от цены входа по тем же «пойнтам», что и в MetaTrader;
    • опция Use Time Exit закрывает позиции, просидевшие дольше Holding Minutes минут;
    • встречные сигналы могут сразу закрывать позицию, если соответствующий флаг разрешён.

Параметры

Название Описание
Money Management Базовое значение для расчёта объёма сделки.
Money Mode Модель расчёта объёма (лоты или доля капитала).
Stop Loss (points) Расстояние до стоп-лосса в пунктах.
Take Profit (points) Расстояние до тейк-профита в пунктах.
Allowed Deviation Допустимое отклонение цены (сохранено для совместимости).
Allow Long/Short Entries Разрешение на открытие позиций в выбранном направлении.
Allow Long/Short Exits Разрешение на закрытие позиций по противоположным сигналам.
Use Time Exit Включает принудительное закрытие по времени.
Holding Minutes Максимальное время удержания позиции (в минутах).
Candle Type Тип обрабатываемых свечей (по умолчанию H4).
PEMA Length Длина всех восьми EMA в каскаде PEMA.
Applied Price Цена, подаваемая на вход индикатора.
Rounding Digits Количество знаков округления результата.
Signal Bar Число закрытых баров ожидания перед реакцией.

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

  • Добавьте стратегию в нужный коннектор StockSharp и подключите соответствующую свечную серию.
  • Настройте параметры под конфигурацию оригинального советника.
  • Стратегия реагирует только на полностью сформированные свечи, поэтому результаты идентичны логике MT5.

Статус конверсии

  • C#-версия — реализована (CS/ExpColorPemaDigitTmPlusStrategy.cs).
  • Версия на Python — не создавалась (по инструкции).
using System;
using System.Collections.Generic;

using Ecng.Common;

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

namespace StockSharp.Samples.Strategies;

public class ExpColorPemaDigitTmPlusStrategy : Strategy
{
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;
	private readonly StrategyParam<int> _stopLossPoints;
	private readonly StrategyParam<int> _takeProfitPoints;

	private ExponentialMovingAverage _fast;
	private ExponentialMovingAverage _slow;

	private decimal _prevFast;
	private decimal _prevSlow;
	private decimal _entryPrice;
	private int _cooldown;

	public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
	public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
	public int StopLossPoints { get => _stopLossPoints.Value; set => _stopLossPoints.Value = value; }
	public int TakeProfitPoints { get => _takeProfitPoints.Value; set => _takeProfitPoints.Value = value; }

	public ExpColorPemaDigitTmPlusStrategy()
	{
		_fastPeriod = Param(nameof(FastPeriod), 14).SetGreaterThanZero().SetDisplay("Fast Period", "Fast EMA period", "Indicator");
		_slowPeriod = Param(nameof(SlowPeriod), 50).SetGreaterThanZero().SetDisplay("Slow Period", "Slow EMA period", "Indicator");
		_stopLossPoints = Param(nameof(StopLossPoints), 200).SetNotNegative().SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk");
		_takeProfitPoints = Param(nameof(TakeProfitPoints), 400).SetNotNegative().SetDisplay("Take Profit", "Take-profit in price steps", "Risk");
	}

	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		yield return (Security, TimeSpan.FromMinutes(5).TimeFrame());
	}

	protected override void OnReseted()
	{
		base.OnReseted();
		_fast = null; _slow = null;
		_prevFast = 0; _prevSlow = 0; _entryPrice = 0; _cooldown = 0;
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_fast = new ExponentialMovingAverage { Length = FastPeriod };
		_slow = new ExponentialMovingAverage { Length = SlowPeriod };
		var subscription = SubscribeCandles(TimeSpan.FromMinutes(5).TimeFrame());
		subscription.Bind(_fast, _slow, ProcessCandle);
		subscription.Start();
	}

	private void ProcessCandle(ICandleMessage candle, decimal fastValue, decimal slowValue)
	{
		if (candle.State != CandleStates.Finished) return;
		if (!_fast.IsFormed || !_slow.IsFormed) { _prevFast = fastValue; _prevSlow = slowValue; return; }
		if (_cooldown > 0) { _cooldown--; _prevFast = fastValue; _prevSlow = slowValue; return; }

		var close = candle.ClosePrice;
		var step = Security?.PriceStep ?? 1m;

		if (Position > 0 && _entryPrice > 0)
		{
			if (StopLossPoints > 0 && close <= _entryPrice - StopLossPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
			if (TakeProfitPoints > 0 && close >= _entryPrice + TakeProfitPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
		}
		else if (Position < 0 && _entryPrice > 0)
		{
			if (StopLossPoints > 0 && close >= _entryPrice + StopLossPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
			if (TakeProfitPoints > 0 && close <= _entryPrice - TakeProfitPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
		}

		if (_prevFast <= _prevSlow && fastValue > slowValue && Position <= 0)
		{ if (Position < 0) BuyMarket(); BuyMarket(); _entryPrice = close; _cooldown = 100; }
		else if (_prevFast >= _prevSlow && fastValue < slowValue && Position >= 0)
		{ if (Position > 0) SellMarket(); SellMarket(); _entryPrice = close; _cooldown = 100; }

		_prevFast = fastValue; _prevSlow = slowValue;
	}
}