This strategy is a StockSharp implementation of the "ColorXMACDCandle" expert advisor. It trades using the MACD indicator and interprets color changes of the histogram or its signal line as entry signals.
Idea
The strategy analyzes the slope of a MACD component:
Histogram mode – A new histogram bar that rises above the previous bar signals growing bullish momentum. A new bar that falls below the previous bar signals bearish momentum.
Signal line mode – The slope of the MACD signal line is used instead. An upward slope acts as a buy signal, while a downward slope acts as a sell signal.
When the chosen component turns upward and was not rising previously, any short position can be closed and a new long position may be opened. When the component turns downward and was not falling previously, any long position can be closed and a short position may be opened.
The behaviour of opening and closing positions is controlled by separate parameters, allowing the user to enable or disable each action independently.
Parameters
Mode – Source of signals: Histogram or SignalLine.
FastPeriod – Fast EMA period for MACD.
SlowPeriod – Slow EMA period for MACD.
SignalPeriod – MACD signal smoothing period.
EnableBuyOpen – Allow opening long positions.
EnableSellOpen – Allow opening short positions.
EnableBuyClose – Allow closing long positions.
EnableSellClose – Allow closing short positions.
CandleType – Candle type for calculations.
Trading Rules
Subscribe to the selected candle series and calculate the MACD indicator.
Track the slope of the histogram or signal line depending on the selected mode.
When the slope turns upward, close any short position (if allowed) and optionally open a long position.
When the slope turns downward, close any long position (if allowed) and optionally open a short position.
The strategy does not include stop loss or take profit mechanisms. Risk management can be added separately if required.
using System;
using System.Linq;
using System.Collections.Generic;
using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Strategy that reacts to slope changes of the MACD histogram.
/// Buys when histogram slope turns up, sells when it turns down.
/// </summary>
public class ColorXMacdCandleStrategy : Strategy
{
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private readonly StrategyParam<int> _signalPeriod;
private readonly StrategyParam<DataType> _candleType;
private ExponentialMovingAverage _signalMa;
private decimal? _prevHist;
private decimal? _prevPrevHist;
public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
public int SignalPeriod { get => _signalPeriod.Value; set => _signalPeriod.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public ColorXMacdCandleStrategy()
{
_fastPeriod = Param(nameof(FastPeriod), 12)
.SetGreaterThanZero()
.SetDisplay("Fast Period", "Fast EMA period", "MACD");
_slowPeriod = Param(nameof(SlowPeriod), 26)
.SetGreaterThanZero()
.SetDisplay("Slow Period", "Slow EMA period", "MACD");
_signalPeriod = Param(nameof(SignalPeriod), 9)
.SetGreaterThanZero()
.SetDisplay("Signal Period", "Signal line period", "MACD");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Candle type for calculations", "Common");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
protected override void OnReseted()
{
base.OnReseted();
_signalMa = null;
_prevHist = null;
_prevPrevHist = null;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var macd = new MovingAverageConvergenceDivergence();
macd.ShortMa.Length = FastPeriod;
macd.LongMa.Length = SlowPeriod;
_signalMa = new ExponentialMovingAverage { Length = SignalPeriod };
Indicators.Add(_signalMa);
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(macd, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, macd);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue macdValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!macdValue.IsFormed)
return;
var macdLine = macdValue.GetValue<decimal>();
var signalResult = _signalMa.Process(macdValue);
if (!signalResult.IsFormed)
return;
var signalLine = signalResult.GetValue<decimal>();
var hist = macdLine - signalLine;
if (!IsFormedAndOnlineAndAllowTrading())
{
_prevPrevHist = _prevHist;
_prevHist = hist;
return;
}
if (_prevHist is decimal ph && _prevPrevHist is decimal pph)
{
var wasRising = ph > pph;
var nowRising = hist > ph;
// Histogram slope turns up -> buy
if (!wasRising && nowRising && Position <= 0)
BuyMarket();
// Histogram slope turns down -> sell
else if (wasRising && !nowRising && Position >= 0)
SellMarket();
}
_prevPrevHist = _prevHist;
_prevHist = hist;
}
}
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, ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class color_xmacd_candle_strategy(Strategy):
def __init__(self):
super(color_xmacd_candle_strategy, self).__init__()
self._fast_period = self.Param("FastPeriod", 12) \
.SetDisplay("Fast Period", "Fast EMA period", "MACD")
self._slow_period = self.Param("SlowPeriod", 26) \
.SetDisplay("Slow Period", "Slow EMA period", "MACD")
self._signal_period = self.Param("SignalPeriod", 9) \
.SetDisplay("Signal Period", "Signal line period", "MACD")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Candle type for calculations", "Common")
self._signal_ma = None
self._prev_hist = None
self._prev_prev_hist = None
@property
def fast_period(self):
return self._fast_period.Value
@property
def slow_period(self):
return self._slow_period.Value
@property
def signal_period(self):
return self._signal_period.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(color_xmacd_candle_strategy, self).OnReseted()
self._signal_ma = None
self._prev_hist = None
self._prev_prev_hist = None
def OnStarted2(self, time):
super(color_xmacd_candle_strategy, self).OnStarted2(time)
macd = MovingAverageConvergenceDivergence()
macd.ShortMa.Length = self.fast_period
macd.LongMa.Length = self.slow_period
self._signal_ma = ExponentialMovingAverage()
self._signal_ma.Length = self.signal_period
self.Indicators.Add(self._signal_ma)
subscription = self.SubscribeCandles(self.candle_type)
subscription.BindEx(macd, self.process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, macd)
self.DrawOwnTrades(area)
def process_candle(self, candle, macd_value):
if candle.State != CandleStates.Finished:
return
if not macd_value.IsFormed:
return
macd_line = float(macd_value)
signal_result = self._signal_ma.Process(macd_value)
if not signal_result.IsFormed:
return
signal_line = float(signal_result)
hist = macd_line - signal_line
if self._prev_hist is not None and self._prev_prev_hist is not None:
was_rising = self._prev_hist > self._prev_prev_hist
now_rising = hist > self._prev_hist
if not was_rising and now_rising and self.Position <= 0:
self.BuyMarket()
elif was_rising and not now_rising and self.Position >= 0:
self.SellMarket()
self._prev_prev_hist = self._prev_hist
self._prev_hist = hist
def CreateClone(self):
return color_xmacd_candle_strategy()