This strategy uses a zero lag moving average (ZLMA) to detect trend reversals. It opens long positions when the ZLMA turns upward and opens short positions when the ZLMA turns downward. Existing positions are closed when the indicator slope reverses.
Parameters
Length: Period of the zero lag moving average.
Candle Type: Timeframe for candles used by the strategy.
Open Buy: Enable opening long positions.
Open Sell: Enable opening short positions.
Close Buy: Close long positions when ZLMA turns down.
Close Sell: Close short positions when ZLMA turns up.
Logic
Subscribe to candles of the selected timeframe.
Calculate the zero lag moving average.
Track the last two ZLMA values to determine slope direction.
If the slope changes from down to up, close short positions and open a long position.
If the slope changes from up to down, close long positions and open a short position.
This simple approach follows the color change of the zero lag moving average to capture potential trend reversals.
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>
/// Strategy that follows ZLEMA direction changes for trend signals.
/// </summary>
public class ColorZeroLagMaStrategy : Strategy
{
private readonly StrategyParam<int> _length;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevZlma;
private decimal _prevPrevZlma;
private int _count;
public int Length { get => _length.Value; set => _length.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public ColorZeroLagMaStrategy()
{
_length = Param(nameof(Length), 12)
.SetGreaterThanZero()
.SetDisplay("Length", "ZLEMA length", "Indicator");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevZlma = 0;
_prevPrevZlma = 0;
_count = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var zlma = new ZeroLagExponentialMovingAverage { Length = Length };
SubscribeCandles(CandleType)
.Bind(zlma, ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal zlmaValue)
{
if (candle.State != CandleStates.Finished)
return;
_count++;
if (_count < 3)
{
_prevPrevZlma = _prevZlma;
_prevZlma = zlmaValue;
return;
}
// Buy when ZLEMA turns up
var turnUp = _prevZlma < _prevPrevZlma && zlmaValue > _prevZlma;
// Sell when ZLEMA turns down
var turnDown = _prevZlma > _prevPrevZlma && zlmaValue < _prevZlma;
if (turnUp && Position <= 0)
{
if (Position < 0) BuyMarket();
BuyMarket();
}
else if (turnDown && Position >= 0)
{
if (Position > 0) SellMarket();
SellMarket();
}
_prevPrevZlma = _prevZlma;
_prevZlma = zlmaValue;
}
}
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 ZeroLagExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class color_zero_lag_ma_strategy(Strategy):
"""
Strategy that follows ZLEMA direction changes for trend signals.
"""
def __init__(self):
super(color_zero_lag_ma_strategy, self).__init__()
self._length = self.Param("Length", 12) \
.SetDisplay("Length", "ZLEMA length", "Indicator")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))) \
.SetDisplay("Candle Type", "Candle timeframe", "General")
self._prev_zlma = 0.0
self._prev_prev_zlma = 0.0
self._count = 0
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(color_zero_lag_ma_strategy, self).OnReseted()
self._prev_zlma = 0.0
self._prev_prev_zlma = 0.0
self._count = 0
def OnStarted2(self, time):
super(color_zero_lag_ma_strategy, self).OnStarted2(time)
zlma = ZeroLagExponentialMovingAverage()
zlma.Length = self._length.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(zlma, self.on_process).Start()
def on_process(self, candle, zlma_val):
if candle.State != CandleStates.Finished:
return
self._count += 1
if self._count < 3:
self._prev_prev_zlma = self._prev_zlma
self._prev_zlma = zlma_val
return
turn_up = self._prev_zlma < self._prev_prev_zlma and zlma_val > self._prev_zlma
turn_down = self._prev_zlma > self._prev_prev_zlma and zlma_val < self._prev_zlma
if turn_up and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif turn_down and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._prev_prev_zlma = self._prev_zlma
self._prev_zlma = zlma_val
def CreateClone(self):
return color_zero_lag_ma_strategy()