This strategy is a direct StockSharp conversion of the "Sensitive" MACD expert advisor for MetaTrader 5. It combines MACD crossovers with configurable risk management tools (fixed stop loss, take profit, and pip-based trailing stops). The algorithm works exclusively on completed candles and uses the high-level API to subscribe to the desired timeframe.
Indicators and Data
MACD (Moving Average Convergence Divergence) – configured with independent fast, slow, and signal EMA lengths.
Candles – user-selectable timeframe provided through the CandleType parameter.
Entry Conditions
A new candle must close to avoid intrabar noise.
MACD values are processed from the indicator binding:
macd represents the MACD main line.
signal is the signal line (EMA of the MACD difference).
Long entry requirements:
MACD crosses above the signal line (macd > signal while the previous values satisfied macd < signal).
MACD remains in negative territory (macd < 0).
The absolute MACD magnitude is greater than MacdOpenLevel * Point, ensuring a meaningful displacement.
No open long position is active (net position is less than or equal to zero). Existing shorts are reversed by sending the necessary quantity.
Short entry requirements mirror the long setup:
MACD crosses below the signal line while remaining positive.
Absolute MACD magnitude exceeds the configured threshold.
No open short position exists (net position is greater than or equal to zero). Existing longs are flattened before opening the short.
Exit Management
Take Profit: Once the trade is opened, the strategy stores a target level defined by TakeProfitPips. If a long candle's high or a short candle's low reaches this level, the position is closed at market.
Stop Loss: A protective stop is calculated from StopLossPips. For longs, a price drop to the stop level triggers a market exit. Shorts react to price increases reaching the stop.
Trailing Stop: When TrailingStopPips is non-zero, the algorithm activates a trailing logic after the price advances by at least TrailingStopPips + TrailingStepPips pips from the entry. Subsequent movements tighten the stop level by always keeping the specified trailing distance from the latest close. The trailing step must be positive whenever the trailing stop is enabled; otherwise, the strategy stops with an error message.
When no position is active, internal tracking variables are reset to prepare for the next trade.
Position Sizing
Order quantities are controlled through the built-in Volume strategy parameter (default: 0.1). Reversals automatically add the absolute value of the current position to the desired volume to switch directions in a single market order.
Parameters
Parameter
Description
Default
FastLength
Fast EMA period used by the MACD main line.
12
SlowLength
Slow EMA period used by the MACD main line.
26
SignalLength
Signal EMA period for the MACD.
9
MacdOpenLevel
Minimum MACD magnitude (in price points) required to trigger trades.
3
StopLossPips
Distance of the protective stop in pips.
35
TakeProfitPips
Take-profit distance in pips.
75
TrailingStopPips
Trailing stop distance in pips (0 disables trailing).
5
TrailingStepPips
Additional distance price must move before the trailing stop updates.
5
CandleType
Source candle type (timeframe).
1-minute candles
Volume
Order volume, expressed in lots/contracts depending on the instrument.
0.1
Additional Notes
Pips and MACD point values are derived from the instrument's price step and decimal precision. The code adjusts for 3- and 5-digit forex symbols by scaling the pip size accordingly.
All comments inside the source are written in English, and the implementation uses only high-level StockSharp APIs in line with the project guidelines.
The strategy intentionally avoids partial fills management and assumes market orders are filled immediately when running in the simulator or real trading. Further safeguards can be added if needed.
using System;
using System.Collections.Generic;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Sensitive MACD Trailing strategy. Uses EMA crossover (5/15).
/// </summary>
public class SensitiveMacdTrailingStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private decimal? _prevFast;
private decimal? _prevSlow;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
public SensitiveMacdTrailingStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame()).SetDisplay("Candle Type", "Timeframe", "General");
_fastPeriod = Param(nameof(FastPeriod), 5).SetGreaterThanZero().SetDisplay("Fast EMA", "Fast EMA period", "Indicators");
_slowPeriod = Param(nameof(SlowPeriod), 15).SetGreaterThanZero().SetDisplay("Slow EMA", "Slow EMA period", "Indicators");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities() => [(Security, CandleType)];
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevFast = null;
_prevSlow = null;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevFast = null; _prevSlow = null;
var fast = new ExponentialMovingAverage { Length = FastPeriod };
var slow = new ExponentialMovingAverage { Length = SlowPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(fast, slow, ProcessCandle).Start();
var area = CreateChartArea();
if (area != null) { DrawCandles(area, subscription); DrawIndicator(area, fast); DrawIndicator(area, slow); DrawOwnTrades(area); }
}
private void ProcessCandle(ICandleMessage candle, decimal fast, decimal slow)
{
if (candle.State != CandleStates.Finished) return;
if (!IsFormedAndOnlineAndAllowTrading()) { _prevFast = fast; _prevSlow = slow; return; }
if (_prevFast == null || _prevSlow == null) { _prevFast = fast; _prevSlow = slow; return; }
var prevAbove = _prevFast.Value > _prevSlow.Value;
var currAbove = fast > slow;
_prevFast = fast; _prevSlow = slow;
if (!prevAbove && currAbove && Position <= 0) { if (Position < 0) BuyMarket(); BuyMarket(); }
else if (prevAbove && !currAbove && Position >= 0) { if (Position > 0) SellMarket(); SellMarket(); }
}
}
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 ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class sensitive_macd_trailing_strategy(Strategy):
def __init__(self):
super(sensitive_macd_trailing_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))) \
.SetDisplay("Candle Type", "Timeframe", "General")
self._fast_period = self.Param("FastPeriod", 5) \
.SetDisplay("Fast EMA", "Fast EMA period", "Indicators")
self._slow_period = self.Param("SlowPeriod", 15) \
.SetDisplay("Slow EMA", "Slow EMA period", "Indicators")
self._prev_fast = None
self._prev_slow = None
@property
def CandleType(self):
return self._candle_type.Value
@property
def FastPeriod(self):
return self._fast_period.Value
@property
def SlowPeriod(self):
return self._slow_period.Value
def OnReseted(self):
super(sensitive_macd_trailing_strategy, self).OnReseted()
self._prev_fast = None
self._prev_slow = None
def OnStarted2(self, time):
super(sensitive_macd_trailing_strategy, self).OnStarted2(time)
self._prev_fast = None
self._prev_slow = None
fast = ExponentialMovingAverage()
fast.Length = self.FastPeriod
slow = ExponentialMovingAverage()
slow.Length = self.SlowPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(fast, slow, self._on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, fast)
self.DrawIndicator(area, slow)
self.DrawOwnTrades(area)
def _on_process(self, candle, fast_value, slow_value):
if candle.State != CandleStates.Finished:
return
fv = float(fast_value)
sv = float(slow_value)
if self._prev_fast is None or self._prev_slow is None:
self._prev_fast = fv
self._prev_slow = sv
return
prev_above = self._prev_fast > self._prev_slow
curr_above = fv > sv
self._prev_fast = fv
self._prev_slow = sv
if not prev_above and curr_above and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif prev_above and not curr_above and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
def CreateClone(self):
return sensitive_macd_trailing_strategy()