Открыть на GitHub

Boring EA2 Alert

Обзор

Boring EA2 Alert переносит логику уведомлений эксперта MetaTrader 4 boring-ea2. Стратегия обрабатывает закрытые свечи, рассчитывает три простые скользящие средние (SMA 3, SMA 20, SMA 150) и пишет детальные сообщения каждый раз, когда между ними происходит пересечение. Реализация намеренно не торгует — цель состоит в оперативных подсказках, которые можно сочетать с ручным исполнением или другими автоматизированными системами.

Логика стратегии

Отслеживание скользящих средних

  • Краткосрочный импульс – SMA с периодом 3 мгновенно реагирует на локальное движение цены.
  • Среднесрочный фильтр – SMA с периодом 20 сглаживает колебания внутри текущего свинга.
  • Долгосрочный фон – SMA с периодом 150 описывает господствующую тенденцию.

Фиксация пересечений

  • SMA3 против SMA20 – сообщает о "crossed up", когда SMA3 поднимается выше SMA20, и о "crossed down", когда опускается ниже. Внутренние флаги исключают повторные сообщения при неизменном соотношении.
  • SMA3 против SMA150 – повторяет те же правила относительно долгосрочной средней, что помогает распознавать импульсы и возможные развороты глобального тренда.
  • SMA20 против SMA150 – дополнительный слой подтверждения, который выделяет перестройку средне- и долгосрочной структуры.
  • Инициализационный барьер – первая закрытая свеча только инициализирует исходное состояние, а уведомления появляются со второй закрытой свечи, когда выявляется реальное изменение отношений.

Формат уведомлений

  • Формат сообщений совпадает с оригиналом: Alert!!! - SYMBOL - TF - description.
  • Таймфрейм вычисляется из выбранного типа свечей. Если интервал совпадает с популярными значениями, используется метатрейдеровское обозначение (M1, M5, H1 и т.п.); иначе применяется компактное представление, например M45 или D2.
  • Логи пишутся через AddInfoLog, поэтому их легко перенаправить в просмотрщик, файл или пользовательский интерфейс.

Параметры

  • Short SMA Length – период быстрой скользящей средней (по умолчанию 3).
  • Medium SMA Length – период средней скользящей (по умолчанию 20).
  • Long SMA Length – период медленной скользящей (по умолчанию 150).
  • Candle Type – таймфрейм, на основе которого рассчитываются средние. Значение по умолчанию — минутные свечи, что обеспечивает высокую чувствительность, сопоставимую с тиковой проверкой оригинального советника.

Дополнительные замечания

  • Стратегия не выставляет, не изменяет и не отменяет заявки — она служит исключительно для сигнализации.
  • Благодаря Bind расчёты выполняются по закрытым свечам, что избавляет от шумовых ложных пересечений, которые исходный эксперт сглаживал подсчётом тиков.
  • При необходимости сообщения можно обрабатывать в прикладном коде, подписавшись на события журнала стратегии.
  • В составе пакета присутствует только C# версия; Python-реализация отсутствует.
using System;

using Ecng.Common;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Boring EA2 strategy: Triple SMA crossover.
/// Buys when fast crosses above medium while medium above slow.
/// Sells when fast crosses below medium while medium below slow.
/// </summary>
public class BoringEa2Strategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;

	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	public BoringEa2Strategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(15).TimeFrame())
			.SetDisplay("Candle Type", "Candle timeframe", "General");
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		var fast = new SimpleMovingAverage { Length = 10 };
		var med = new SimpleMovingAverage { Length = 20 };
		var slow = new SimpleMovingAverage { Length = 40 };

		decimal? prevFast = null;
		decimal? prevMed = null;

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(fast, med, slow, (candle, fastVal, medVal, slowVal) =>
			{
				if (candle.State != CandleStates.Finished)
					return;

				if (!IsFormedAndOnlineAndAllowTrading())
					return;

				if (prevFast.HasValue && prevMed.HasValue)
				{
					var fastCrossUp = prevFast.Value <= prevMed.Value && fastVal > medVal;
					var fastCrossDown = prevFast.Value >= prevMed.Value && fastVal < medVal;

					if (fastCrossUp && medVal > slowVal && Position <= 0)
						BuyMarket();
					else if (fastCrossDown && medVal < slowVal && Position >= 0)
						SellMarket();
				}

				prevFast = fastVal;
				prevMed = medVal;
			})
			.Start();

		var area = CreateChartArea();
		if (area != null)
		{
			DrawCandles(area, subscription);
			DrawIndicator(area, fast);
			DrawIndicator(area, med);
			DrawIndicator(area, slow);
			DrawOwnTrades(area);
		}
	}
}