Esta estratégia implementa um sistema seguidor de tendência baseado no indicador FATL MACD. A FATL (Fast Adaptive Trend Line) é subtraída do preço para produzir um oscilador similar ao MACD, que é então suavizado por uma média móvel adaptativa. Valores positivos indicam momentum de alta; valores negativos indicam momentum de baixa.
O algoritmo analisa a inclinação deste oscilador em cada candle concluído:
Quando o valor anterior é inferior ao valor anterior a ele, o oscilador virou para cima. Se o valor atual subir ainda mais, a estratégia abre uma posição comprada e fecha quaisquer posições vendidas.
Quando o valor anterior é superior ao valor anterior a ele, o oscilador virou para baixo. Se o valor atual continuar caindo, a estratégia abre uma posição vendida e fecha quaisquer posições compradas.
Todos os parâmetros principais são configuráveis:
Fast EMA – período da média móvel rápida do MACD (padrão 12).
Slow EMA – período da média móvel lenta do MACD (padrão 26).
Signal EMA – período da linha de sinal do MACD (padrão 9).
Candle Type – série de candles utilizada para o cálculo do indicador.
As posições são abertas com ordens a mercado e são fechadas quando aparece um sinal oposto.
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;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import MovingAverageConvergenceDivergence
from StockSharp.Algo.Strategies import Strategy
class fatl_macd_strategy(Strategy):
def __init__(self):
super(fatl_macd_strategy, self).__init__()
self._fast_length = self.Param("FastLength", 12) \
.SetDisplay("Fast EMA", "Period of the fast moving average", "MACD")
self._slow_length = self.Param("SlowLength", 26) \
.SetDisplay("Slow EMA", "Period of the slow moving average", "MACD")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Type of candles for processing", "General")
self._prev1 = 0.0
self._prev2 = 0.0
self._is_initialized = False
@property
def FastLength(self):
return self._fast_length.Value
@FastLength.setter
def FastLength(self, value):
self._fast_length.Value = value
@property
def SlowLength(self):
return self._slow_length.Value
@SlowLength.setter
def SlowLength(self, value):
self._slow_length.Value = value
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
def OnStarted2(self, time):
super(fatl_macd_strategy, self).OnStarted2(time)
macd = MovingAverageConvergenceDivergence()
macd.ShortMa.Length = self.FastLength
macd.LongMa.Length = self.SlowLength
self.SubscribeCandles(self.CandleType) \
.Bind(macd, self.ProcessCandle) \
.Start()
def ProcessCandle(self, candle, macd_value):
if candle.State != CandleStates.Finished:
return
val = float(macd_value)
if not self._is_initialized:
self._prev2 = val
self._prev1 = val
self._is_initialized = True
return
if self._prev1 < self._prev2:
if self.Position < 0:
self.BuyMarket()
if val > self._prev1 and self.Position <= 0:
self.BuyMarket()
elif self._prev1 > self._prev2:
if self.Position > 0:
self.SellMarket()
if val < self._prev1 and self.Position >= 0:
self.SellMarket()
self._prev2 = self._prev1
self._prev1 = val
def OnReseted(self):
super(fatl_macd_strategy, self).OnReseted()
self._prev1 = 0.0
self._prev2 = 0.0
self._is_initialized = False
def CreateClone(self):
return fatl_macd_strategy()