SMC Trader Camel CCI MACD Strategy
Overview
This strategy is a StockSharp port of the MetaTrader 4 expert advisor "Steve Cartwright Trader Camel CCI MACD".
It reproduces the original trading logic based on a camel-style exponential moving average channel,
a MACD trend filter and Commodity Channel Index (CCI) thresholds. Trades are executed on completed
candles to ensure deterministic behaviour and to stay close to the bar-by-bar workflow of the MQL version.
Trading Logic
- Indicators
- Two exponential moving averages (EMA) with the same period are applied to candle highs and lows to form the
camel channel. A breakout of the previous close beyond these envelopes signals momentum strength.
- A standard MACD indicator (fast EMA, slow EMA and signal line) is used to confirm the underlying trend direction.
- A CCI indicator validates momentum strength using overbought/oversold levels at ±100 by default.
- Long entries
- Previous candle close is above the camel high EMA.
- Previous MACD main value is above zero and above the signal line.
- Previous CCI value is above the positive threshold.
- No active position is open and no exit occurred within the current candle timeframe (prevents rapid re-entry).
- Short entries
- Previous candle close is below the camel low EMA.
- Previous MACD main value is below zero and below the signal line.
- Previous CCI value is below the negative threshold.
- Same flat-position and cooldown conditions as for long setups.
- Exits
- Long positions close when the previous MACD main value crosses below the signal line or when the previous CCI
value drops below the positive threshold.
- Short positions close when the previous MACD main value crosses above the signal line.
- After any exit, a cooldown equal to one candle duration is enforced before new entries.
The strategy trades once per bar at most because every decision is based on data from the previous completed candle.
Parameters
| Parameter |
Description |
Default |
CandleType |
Candle data type/timeframe used for all indicators. |
1-hour time frame |
CamelLength |
Length of the high/low EMA channel. |
34 |
CciPeriod |
Length of the CCI filter. |
20 |
MacdFastPeriod |
Fast EMA length for MACD. |
12 |
MacdSlowPeriod |
Slow EMA length for MACD. |
26 |
MacdSignalPeriod |
Signal smoothing period for MACD. |
9 |
CciThreshold |
Absolute CCI level that must be exceeded for entries (applied symmetrically). |
100 |
All parameters are optimizable through the StockSharp optimizer thanks to the SetOptimize calls.
Risk Management
- Orders are sent via
BuyMarket and SellMarket, inheriting the strategy Volume property.
StartProtection() is enabled to initialise standard StockSharp protection helpers.
- No fixed stop-loss or take-profit is defined in the original algorithm; exits rely solely on indicator signals.
Charting
The strategy automatically plots the camel EMA channel, MACD and CCI indicators, together with own trades,
which replicates the visual cues used in the MT4 implementation.
Notes
- The cooldown timer uses the candle duration derived from
CandleType.Arg. Ensure that CandleType contains a
TimeSpan argument when you change the timeframe.
- Because all decisions are based on previous-bar values, the order of operations mirrors the
iMACD, iCCI
and iMA (with shift=1) calls in the source EA.
namespace StockSharp.Samples.Strategies;
using System;
using System.Collections.Generic;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
/// <summary>
/// Strategy combining CCI and MACD signal crossover with EMA trend filter.
/// Buy when MACD crosses above signal with CCI positive and price above EMA.
/// Sell when MACD crosses below signal with CCI negative and price below EMA.
/// </summary>
public class SmcTraderCamelCciMacd1Strategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _emaLength;
private readonly StrategyParam<int> _macdFastPeriod;
private readonly StrategyParam<int> _macdSlowPeriod;
private readonly StrategyParam<int> _macdSignalPeriod;
private readonly StrategyParam<int> _cciPeriod;
private decimal? _prevMacdMain;
private decimal? _prevMacdSignal;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int EmaLength { get => _emaLength.Value; set => _emaLength.Value = value; }
public int MacdFastPeriod { get => _macdFastPeriod.Value; set => _macdFastPeriod.Value = value; }
public int MacdSlowPeriod { get => _macdSlowPeriod.Value; set => _macdSlowPeriod.Value = value; }
public int MacdSignalPeriod { get => _macdSignalPeriod.Value; set => _macdSignalPeriod.Value = value; }
public int CciPeriod { get => _cciPeriod.Value; set => _cciPeriod.Value = value; }
public SmcTraderCamelCciMacd1Strategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
_emaLength = Param(nameof(EmaLength), 34)
.SetDisplay("EMA Length", "Trend EMA period", "Indicators");
_macdFastPeriod = Param(nameof(MacdFastPeriod), 12)
.SetDisplay("MACD Fast", "Fast EMA for MACD", "Indicators");
_macdSlowPeriod = Param(nameof(MacdSlowPeriod), 26)
.SetDisplay("MACD Slow", "Slow EMA for MACD", "Indicators");
_macdSignalPeriod = Param(nameof(MacdSignalPeriod), 9)
.SetDisplay("MACD Signal", "Signal line period", "Indicators");
_cciPeriod = Param(nameof(CciPeriod), 20)
.SetDisplay("CCI Period", "CCI period", "Indicators");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevMacdMain = null;
_prevMacdSignal = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevMacdMain = null;
_prevMacdSignal = null;
var ema = new ExponentialMovingAverage { Length = EmaLength };
var macd = new MovingAverageConvergenceDivergenceSignal
{
Macd =
{
ShortMa = { Length = MacdFastPeriod },
LongMa = { Length = MacdSlowPeriod }
},
SignalMa = { Length = MacdSignalPeriod }
};
var cci = new CommodityChannelIndex { Length = CciPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(macd, cci, ema, ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue macdValue, IIndicatorValue cciValue, IIndicatorValue emaValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!macdValue.IsFinal || !cciValue.IsFinal || !emaValue.IsFinal)
return;
if (macdValue is not MovingAverageConvergenceDivergenceSignalValue macdData)
return;
if (macdData.Macd is not decimal macdMain || macdData.Signal is not decimal macdSignal)
return;
var cci = cciValue.ToDecimal();
var emaVal = emaValue.ToDecimal();
if (_prevMacdMain is not decimal prevMain || _prevMacdSignal is not decimal prevSignal)
{
_prevMacdMain = macdMain;
_prevMacdSignal = macdSignal;
return;
}
var macdBullCross = prevMain <= prevSignal && macdMain > macdSignal;
var macdBearCross = prevMain >= prevSignal && macdMain < macdSignal;
// Long: MACD bullish cross + CCI > 0 + price above EMA
if (Position <= 0 && macdBullCross && cci > 0 && candle.ClosePrice > emaVal)
{
if (Position < 0)
BuyMarket();
BuyMarket();
}
// Short: MACD bearish cross + CCI < 0 + price below EMA
else if (Position >= 0 && macdBearCross && cci < 0 && candle.ClosePrice < emaVal)
{
if (Position > 0)
SellMarket();
SellMarket();
}
_prevMacdMain = macdMain;
_prevMacdSignal = macdSignal;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Math
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import (
CommodityChannelIndex,
ExponentialMovingAverage,
MovingAverageConvergenceDivergenceSignal
)
from StockSharp.Algo.Strategies import Strategy
class smc_trader_camel_cci_macd1_strategy(Strategy):
"""Strategy combining CCI and MACD signal crossover with EMA trend filter.
Buy when MACD crosses above signal with CCI positive and price above EMA.
Sell when MACD crosses below signal with CCI negative and price below EMA."""
def __init__(self):
super(smc_trader_camel_cci_macd1_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))) \
.SetDisplay("Candle Type", "Candle timeframe", "General")
self._ema_length = self.Param("EmaLength", 34) \
.SetDisplay("EMA Length", "Trend EMA period", "Indicators")
self._macd_fast_period = self.Param("MacdFastPeriod", 12) \
.SetDisplay("MACD Fast", "Fast EMA for MACD", "Indicators")
self._macd_slow_period = self.Param("MacdSlowPeriod", 26) \
.SetDisplay("MACD Slow", "Slow EMA for MACD", "Indicators")
self._macd_signal_period = self.Param("MacdSignalPeriod", 9) \
.SetDisplay("MACD Signal", "Signal line period", "Indicators")
self._cci_period = self.Param("CciPeriod", 20) \
.SetDisplay("CCI Period", "CCI period", "Indicators")
self._prev_macd_main = None
self._prev_macd_signal = None
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def EmaLength(self):
return self._ema_length.Value
@property
def MacdFastPeriod(self):
return self._macd_fast_period.Value
@property
def MacdSlowPeriod(self):
return self._macd_slow_period.Value
@property
def MacdSignalPeriod(self):
return self._macd_signal_period.Value
@property
def CciPeriod(self):
return self._cci_period.Value
def OnReseted(self):
super(smc_trader_camel_cci_macd1_strategy, self).OnReseted()
self._prev_macd_main = None
self._prev_macd_signal = None
def OnStarted2(self, time):
super(smc_trader_camel_cci_macd1_strategy, self).OnStarted2(time)
self._prev_macd_main = None
self._prev_macd_signal = None
ema = ExponentialMovingAverage()
ema.Length = self.EmaLength
macd = MovingAverageConvergenceDivergenceSignal()
macd.Macd.ShortMa.Length = self.MacdFastPeriod
macd.Macd.LongMa.Length = self.MacdSlowPeriod
macd.SignalMa.Length = self.MacdSignalPeriod
cci = CommodityChannelIndex()
cci.Length = self.CciPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.BindEx(macd, cci, ema, self._process_candle).Start()
def _process_candle(self, candle, macd_value, cci_value, ema_value):
if candle.State != CandleStates.Finished:
return
if not macd_value.IsFinal or not cci_value.IsFinal or not ema_value.IsFinal:
return
macd_raw = macd_value.Macd if hasattr(macd_value, 'Macd') else None
signal_raw = macd_value.Signal if hasattr(macd_value, 'Signal') else None
if macd_raw is None or signal_raw is None:
return
macd_main = float(macd_raw)
macd_signal = float(signal_raw)
cci_val = float(cci_value)
ema_val = float(ema_value)
if self._prev_macd_main is None or self._prev_macd_signal is None:
self._prev_macd_main = macd_main
self._prev_macd_signal = macd_signal
return
prev_main = self._prev_macd_main
prev_signal = self._prev_macd_signal
macd_bull_cross = prev_main <= prev_signal and macd_main > macd_signal
macd_bear_cross = prev_main >= prev_signal and macd_main < macd_signal
close = float(candle.ClosePrice)
# Long: MACD bullish cross + CCI > 0 + price above EMA
if self.Position <= 0 and macd_bull_cross and cci_val > 0 and close > ema_val:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
# Short: MACD bearish cross + CCI < 0 + price below EMA
elif self.Position >= 0 and macd_bear_cross and cci_val < 0 and close < ema_val:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._prev_macd_main = macd_main
self._prev_macd_signal = macd_signal
def CreateClone(self):
return smc_trader_camel_cci_macd1_strategy()