Ver en GitHub

FATL MACD Trend Strategy

This strategy implements a trend-following system based on the FATL MACD indicator. FATL (Fast Adaptive Trend Line) is subtracted from price to produce a MACD-like oscillator which is then smoothed by an adaptive moving average. Positive values indicate bullish momentum, negative values indicate bearish momentum.

The algorithm analyses the slope of this oscillator on each finished candle:

  • When the previous value is lower than the value before it, the oscillator has turned upward. If the current value rises further, the strategy opens a long position and closes any short positions.
  • When the previous value is higher than the value before it, the oscillator has turned downward. If the current value continues to fall, the strategy opens a short position and closes any long positions.

All main parameters are configurable:

  • Fast EMA – MACD fast moving average period (default 12).
  • Slow EMA – MACD slow moving average period (default 26).
  • Signal EMA – MACD signal line period (default 9).
  • Candle Type – candle series used for indicator calculation.

Positions are opened with market orders and are closed when an opposite signal appears.

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>
/// FATL MACD trend-following strategy.
/// Opens long positions when the indicator turns upward
/// and short positions when it turns downward.
/// </summary>
public class FatlMacdStrategy : Strategy
{
	private readonly StrategyParam<int> _fastLength;
	private readonly StrategyParam<int> _slowLength;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _prev1;
	private decimal _prev2;
	private bool _isInitialized;

	public int FastLength { get => _fastLength.Value; set => _fastLength.Value = value; }
	public int SlowLength { get => _slowLength.Value; set => _slowLength.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public FatlMacdStrategy()
	{
		_fastLength = Param(nameof(FastLength), 12)
			.SetDisplay("Fast EMA", "Period of the fast moving average", "MACD")
			.SetGreaterThanZero();

		_slowLength = Param(nameof(SlowLength), 26)
			.SetDisplay("Slow EMA", "Period of the slow moving average", "MACD")
			.SetGreaterThanZero();

		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Type of candles for processing", "General");
	}

	/// <inheritdoc />
	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		return [(Security, CandleType)];
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prev1 = default;
		_prev2 = default;
		_isInitialized = default;
	}

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		var macd = new MovingAverageConvergenceDivergence
		{
			ShortMa = { Length = FastLength },
			LongMa = { Length = SlowLength },
		};

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(macd, Process)
			.Start();
	}

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

		if (!IsFormedAndOnlineAndAllowTrading())
			return;

		if (!_isInitialized)
		{
			_prev2 = _prev1 = macdValue;
			_isInitialized = true;
			return;
		}

		// Indicator turned upward
		if (_prev1 < _prev2)
		{
			if (Position < 0)
				BuyMarket();

			if (macdValue > _prev1 && Position <= 0)
				BuyMarket();
		}
		// Indicator turned downward
		else if (_prev1 > _prev2)
		{
			if (Position > 0)
				SellMarket();

			if (macdValue < _prev1 && Position >= 0)
				SellMarket();
		}

		_prev2 = _prev1;
		_prev1 = macdValue;
	}
}