Открыть на GitHub

Стратегия Close Profit End Of Week

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

Close Profit End Of Week Strategy автоматизирует работу скрипта MetaTrader Closeprofitendofweek.mq5. Стратегия следит за выбранным инструментом и по пятницам после настраиваемого контрольного времени закрывает каждую прибыльную позицию. Цель — зафиксировать плавающий результат перед выходными и снизить разрывный риск.

Поведение оригинального MQL-советника

Исходный эксперт работал в таймере: каждую итерацию он проверял, настала ли пятница и наступило ли заданное время окончания торгов. Если условия выполнялись, советник проходил по всем позициям по текущему символу и закрывал те из них, что имели положительный результат. Для криптовалютных инструментов логика отключалась, поскольку они торгуются без выходных.

Реализация в StockSharp

Перенос на C# сохраняет исходную защиту, используя высокоуровневый API StockSharp:

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

Параметры

Имя Описание Значение по умолчанию
StartTradeTime Начало окна мониторинга (оставлено ради соответствия входам MQL). 00:00
EndTradeTime Время, после которого по пятницам необходимо закрыть прибыльные позиции. 20:00
CloseTradesAtEndTime Включает или отключает автоматическое закрытие. true
CandleType Тип данных, используемый для контроля времени (по умолчанию минутные свечи). TimeFrameCandle(1m)

Последовательность работы

  1. При запуске стратегия проверяет, не относится ли выбранный инструмент к классу криптовалют. Для крипто-активов защита не активируется, повторяя логику исходного советника.
  2. Создаётся подписка на свечи, чтобы получать сигналы после их завершения.
  3. Каждая завершённая свеча проходит фильтр по дню недели и времени закрытия. Дальнейшие действия выполняются только по пятницам после заданного времени.
  4. Стратегия анализирует подключённый портфель, находит позицию по нужному инструменту и считывает её плавающую прибыль.
  5. Если прибыль положительна, отправляется рыночный ордер противоположного направления для полного закрытия позиции.
  6. Перед отправкой ордера проверяется отсутствие уже активных заявок на закрытие, чтобы избежать дублирования.

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

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

Ограничения

  • Расчёт прибыли опирается на оперативные данные портфеля брокера. Если PnL обновляется с задержкой, команды на закрытие могут прийти позже.
  • Закрываются только позиции по настроенному инструменту; остальные активы остаются нетронутыми.
  • Проверка выполняется по завершению свечи. Подбирайте таймфрейм, соответствующий требуемой точности расписания.
namespace StockSharp.Samples.Strategies;

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

/// <summary>
/// Close Profit End Of Week strategy: Momentum + EMA trend following.
/// Buys when momentum positive and close above EMA, sells when momentum negative and close below EMA.
/// </summary>
public class CloseProfitEndOfWeekStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _momPeriod;
	private readonly StrategyParam<int> _emaPeriod;
	private readonly StrategyParam<decimal> _momentumLevel;

	private decimal _prevMom;
	private bool _hasPrev;

	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
	public int MomPeriod { get => _momPeriod.Value; set => _momPeriod.Value = value; }
	public int EmaPeriod { get => _emaPeriod.Value; set => _emaPeriod.Value = value; }
	public decimal MomentumLevel { get => _momentumLevel.Value; set => _momentumLevel.Value = value; }

	public CloseProfitEndOfWeekStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
			.SetDisplay("Candle Type", "Candle timeframe", "General");
		_momPeriod = Param(nameof(MomPeriod), 20)
			.SetGreaterThanZero()
			.SetDisplay("Momentum Period", "Momentum period", "Indicators");
		_emaPeriod = Param(nameof(EmaPeriod), 50)
			.SetGreaterThanZero()
			.SetDisplay("EMA Period", "EMA filter period", "Indicators");
		_momentumLevel = Param(nameof(MomentumLevel), 101m)
			.SetDisplay("Momentum Level", "Momentum threshold", "Signals");
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevMom = 0;
		_hasPrev = false;
	}

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_prevMom = 0;
		_hasPrev = false;
		var mom = new Momentum { Length = MomPeriod };
		var ema = new ExponentialMovingAverage { Length = EmaPeriod };
		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(mom, ema, ProcessCandle).Start();
	}

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

		if (_hasPrev)
		{
			if (_prevMom <= MomentumLevel && momValue > MomentumLevel && candle.ClosePrice > emaValue && Position <= 0)
				BuyMarket();
			else if (_prevMom >= 200m - MomentumLevel && momValue < 200m - MomentumLevel && candle.ClosePrice < emaValue && Position >= 0)
				SellMarket();
		}

		_prevMom = momValue;
		_hasPrev = true;
	}
}