Открыть на GitHub

Стратегия BrainTrend2 + AbsolutelyNoLagLWMA

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

Стратегия переносит два советника из MetaTrader 5 — BrainTrend2_V2 и AbsolutelyNoLagLWMA. Каждый модуль подписывается на собственные свечи, самостоятельно определяет направление и формирует желаемый объем. В версии для StockSharp оба потока решений сохранены, а итоговая позиция рассчитывается как сумма целей двух модулей.

  • Модуль BrainTrend2. Использует цветовые состояния индикатора BrainTrend2. Индикатор строит ATR-подобный канал и меняет цвет, когда цена пробивает противоположную границу.
  • Модуль AbsolutelyNoLagLWMA. Рассчитывает двойное линейно-взвешенное среднее по выбранной цене и оценивает знак наклона полученной кривой.

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

Индикаторы

BrainTrend2

Индикатор заново реализован в C#, чтобы повторить пятицветную раскраску:

  • Вычисляется треугольная скользящая сумма истинного диапазона с заданным периодом, умноженная на коэффициент 0.7 (widcha).
  • Плавающее значение Emaxtra следует за экстремумами внутри текущего режима.
  • При пробое low < Emaxtra - widcha режим меняется на медвежий, при high > Emaxtra + widcha — на бычий.
  • Значения 0 и 1 означают бычий цвет, 3 и 4 — медвежий, 2 — индикатор еще не готов.

AbsolutelyNoLagLWMA

Модуль применяет два последовательных линейно-взвешенных скользящих средних к выбранной ценовой серии:

  • 2 (синий) — линия растет.
  • 1 (серый) — линия горизонтальна.
  • 0 (фиолетовый) — линия падает.

Оба индикатора выставляют IsFormed, поэтому стратегия начинает реагировать только когда собрана достаточная история.

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

Внутри стратегии поддерживаются переменные _brainTrendTarget и _lwmaTarget, задающие желаемый объем для каждого модуля. После изменения любой из целей вызывается RebalancePosition, который доводит фактическую позицию до суммы этих значений.

Модуль BrainTrend2

  • Анализирует цвет свечи на расстоянии SignalBar (по умолчанию одна свеча) и цвет перед ней.
  • Если текущий цвет бычий (< 2), а предыдущий не был бычьим (> 1):
    • Закрываются короткие позиции, открытые этим модулем.
    • При разрешенных входах открывается лонг объемом BrainTrendVolume.
  • Если текущий цвет медвежий (> 2), а предыдущий не был медвежьим (< 3):
    • Закрываются лонги модуля.
    • При разрешенных входах открывается шорт объемом BrainTrendVolume.

Модуль AbsolutelyNoLagLWMA

  • Реагирует только на смену цветов 2 (вверх) и 0 (вниз) с тем же смещением SignalBar.
  • При появлении цвета 2 и изменении цвета относительно предыдущей свечи:
    • При LwmaCloseShortAllowed = true закрывается шорт этого модуля.
    • При LwmaBuyAllowed = true открывается лонг объемом LwmaVolume.
  • При появлении цвета 0 и изменении цвета:
    • При LwmaCloseLongAllowed = true закрывается лонг модуля.
    • При LwmaSellAllowed = true открывается шорт объемом LwmaVolume.

Модули воздействуют только на собственные целевые объемы, поэтому могут работать одновременно. Например, BrainTrend2 удерживает трендовую позицию, а LWMA временно хеджирует ее короткими сделками.

Параметры

Параметр Описание
BrainTrendAtrPeriod Период треугольного ATR для BrainTrend2.
BrainTrendSignalBar Сколько завершенных свечей ждать перед сигналом BrainTrend2. Значение 1 означает работу по предыдущей свече.
BrainTrendBuyAllowed / BrainTrendSellAllowed Разрешение на лонги/шорты для модуля BrainTrend2.
BrainTrendVolume Объем позиции BrainTrend2 при входе.
BrainTrendCandleType Таймфрейм свечей, которые использует BrainTrend2.
LwmaLength Длина линейно-взвешенного среднего в индикаторе AbsolutelyNoLagLWMA.
LwmaSignalBar Смещение сигналов LWMA.
LwmaAppliedPrice Тип цены для LWMA (close, open, median, Demark и т.д.).
LwmaBuyAllowed / LwmaSellAllowed Разрешение на лонги/шорты для LWMA.
LwmaCloseLongAllowed / LwmaCloseShortAllowed Разрешение закрывать противоположные позиции при смене цвета.
LwmaVolume Объем сделок LWMA.
LwmaCandleType Таймфрейм свечей для LWMA.

Управление позицией

  • Всегда используются рыночные заявки BuyMarket / SellMarket для достижения целевого объема.
  • Объемы модулей суммируются. Если один модуль лонгует, а второй шортит на тот же объем, чистая позиция будет равна нулю.
  • Брокерские функции установки стоп-лоссов и тейк-профитов из оригинального советника не переносились. При необходимости можно подключить защитные механизмы StockSharp.
  • При работе на разных таймфреймах стратегия автоматически подписывается на обе серии свечей и отображает их на графике вместе со сделками.

Примечания

  • Расчеты индикаторов полностью реализованы внутри стратегии и не требуют внешних библиотек.
  • Значение SignalBar = 0 позволяет реагировать сразу после закрытия текущей свечи, большие значения добавляют подтверждение.
  • BrainTrend2 требует минимум AtrPeriod + 2 исторических свечей, AbsolutelyNoLagLWMA — не меньше Length.
  • Оба модуля работают с одним инструментом Strategy.Security, аналогично тому, как в MT5 позиции разделялись по различным magic number.

Рекомендации по доработке

  • При необходимости добавьте риск-менеджер или трейлинг-стопы из инфраструктуры StockSharp.
  • Настройте BrainTrendVolume и LwmaVolume отдельно, чтобы сместить баланс между трендовой и контртрендовой частью.
  • Используйте значения индикаторов в методах ProcessBrainTrend и ProcessLwma, чтобы ввести дополнительные фильтры или подтверждения.
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;

/// <summary>
/// BrainTrend2 + AbsolutelyNoLagLwma strategy (simplified). Uses ATR-based
/// trend detection combined with weighted MA direction for entries.
/// Implemented as EMA crossover with ATR channel filter.
/// </summary>
public class BrainTrend2AbsolutelyNoLagLwmaStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _emaFastLength;
	private readonly StrategyParam<int> _emaSlowLength;
	private readonly StrategyParam<int> _atrLength;
	private readonly StrategyParam<decimal> _atrCoefficient;

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

	public int EmaFastLength
	{
		get => _emaFastLength.Value;
		set => _emaFastLength.Value = value;
	}

	public int EmaSlowLength
	{
		get => _emaSlowLength.Value;
		set => _emaSlowLength.Value = value;
	}

	public int AtrLength
	{
		get => _atrLength.Value;
		set => _atrLength.Value = value;
	}

	public decimal AtrCoefficient
	{
		get => _atrCoefficient.Value;
		set => _atrCoefficient.Value = value;
	}

	public BrainTrend2AbsolutelyNoLagLwmaStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
			.SetDisplay("Candle Type", "Candles", "General");

		_emaFastLength = Param(nameof(EmaFastLength), 7)
			.SetGreaterThanZero()
			.SetDisplay("EMA Fast", "Fast EMA period", "Indicators");

		_emaSlowLength = Param(nameof(EmaSlowLength), 21)
			.SetGreaterThanZero()
			.SetDisplay("EMA Slow", "Slow EMA period", "Indicators");

		_atrLength = Param(nameof(AtrLength), 14)
			.SetGreaterThanZero()
			.SetDisplay("ATR Length", "ATR period", "Indicators");

		_atrCoefficient = Param(nameof(AtrCoefficient), 0.7m)
			.SetGreaterThanZero()
			.SetDisplay("ATR Coeff", "ATR multiplier for channel", "Logic");
	}

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

		var emaFast = new ExponentialMovingAverage { Length = EmaFastLength };
		var emaSlow = new ExponentialMovingAverage { Length = EmaSlowLength };

		decimal prevFast = 0, prevSlow = 0;
		var hasPrev = false;

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(emaFast, emaSlow, (ICandleMessage candle, decimal fastVal, decimal slowVal) =>
			{
				if (candle.State != CandleStates.Finished)
					return;

				if (!hasPrev)
				{
					prevFast = fastVal;
					prevSlow = slowVal;
					hasPrev = true;
					return;
				}

				if (!IsFormedAndOnlineAndAllowTrading())
				{
					prevFast = fastVal;
					prevSlow = slowVal;
					return;
				}

				var close = candle.ClosePrice;

				// Fast EMA crosses above slow - bullish
				var bullishCross = prevFast <= prevSlow && fastVal > slowVal;
				// Fast EMA crosses below slow - bearish
				var bearishCross = prevFast >= prevSlow && fastVal < slowVal;

				if (bullishCross && Position <= 0)
					BuyMarket();
				else if (bearishCross && Position >= 0)
					SellMarket();

				prevFast = fastVal;
				prevSlow = slowVal;
			})
			.Start();

		var area = CreateChartArea();
		if (area != null)
		{
			DrawCandles(area, subscription);
			DrawIndicator(area, emaFast);
			DrawIndicator(area, emaSlow);
			DrawOwnTrades(area);
		}
	}
}