This strategy is a StockSharp conversion of the original MetaTrader "CCI-Expert" robot. It uses the Commodity Channel Index (CCI) indicator on a single time frame and keeps the logic strictly sequential: the strategy waits for three completed candles before deciding to open or close a position.
Trading Logic
Subscribe to the configured candle series and calculate a CCI with the chosen period.
Evaluate the latest three finished CCI values:
Long setup: the current and previous CCI values are above +1, while the second previous value was below +1.
Short setup: the current and previous CCI values are below +1, while the second previous value was above +1.
Open only one market position at a time when no position is active and the spread filter allows trading.
Close an existing position only if the opposite signal appears and the trade is already profitable (close price is better than the entry price).
Risk Management
The strategy can use either a fixed lot or calculate the volume from the risk percentage and the configured stop-loss distance.
StartProtection automatically places stop-loss and take-profit brackets in price points.
An optional spread filter blocks trading until the current bid/ask difference is below the MaxSpreadPoints threshold.
Parameters
Parameter
Description
Default
FixedVolume
Fixed order size. Set to zero to activate risk-based sizing.
0.1
RiskPercent
Percentage of current portfolio value used to size orders when FixedVolume is zero.
0
TakeProfitPoints
Take-profit distance measured in price points.
150
StopLossPoints
Stop-loss distance measured in price points.
600
MaxSpreadPoints
Maximum allowed spread (in price points). Zero disables the filter.
30
CciPeriod
Lookback period of the CCI indicator.
14
CandleType
Time frame of the candles processed by the strategy.
15-minute candles
Notes
The CCI threshold remains constant at +1 and -1 just like the MQL source, so trades trigger only after a clear three-step pattern.
Because risk-based volume sizing relies on instrument metadata (PriceStep, StepPrice, VolumeStep, etc.), ensure those values are available from the connected board.
The strategy draws candles, the CCI indicator line, and executed trades on the chart for easier visual debugging.
namespace StockSharp.Samples.Strategies;
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
/// <summary>
/// CCI Expert strategy: CCI crossover with level-based signals.
/// Buys when CCI crosses above +1 from below, sells when crosses below -1 from above.
/// </summary>
public class CciExpertStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _cciPeriod;
private decimal? _prevCci;
private decimal? _prevPrevCci;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int CciPeriod { get => _cciPeriod.Value; set => _cciPeriod.Value = value; }
public CciExpertStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(15).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
_cciPeriod = Param(nameof(CciPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("CCI Period", "CCI period", "Indicators");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevCci = null;
_prevPrevCci = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevCci = null;
_prevPrevCci = null;
var cci = new CommodityChannelIndex { Length = CciPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(cci, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, decimal cciValue)
{
if (candle.State != CandleStates.Finished) return;
if (_prevCci is decimal prev && _prevPrevCci is decimal prev2)
{
// Long: CCI stayed above +100 for 2 bars while prior bar was below
var longSignal = cciValue > 100m && prev > 100m && prev2 < 100m;
// Short: CCI stayed below -100 for 2 bars while prior bar was above
var shortSignal = cciValue < -100m && prev < -100m && prev2 > -100m;
if (longSignal && Position <= 0)
BuyMarket();
else if (shortSignal && Position >= 0)
SellMarket();
}
_prevPrevCci = _prevCci;
_prevCci = cciValue;
}
}
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 CommodityChannelIndex
from StockSharp.Algo.Strategies import Strategy
class cci_expert_strategy(Strategy):
"""
CCI Expert strategy: CCI crossover with level-based signals.
Buys when CCI stays above +100 for 2 bars, sells when below -100 for 2 bars.
"""
def __init__(self):
super(cci_expert_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(15))) \
.SetDisplay("Candle Type", "Candle timeframe", "General")
self._cci_period = self.Param("CciPeriod", 14) \
.SetDisplay("CCI Period", "CCI period", "Indicators")
self._prev_cci = None
self._prev_prev_cci = None
@property
def candle_type(self):
return self._candle_type.Value
@candle_type.setter
def candle_type(self, value):
self._candle_type.Value = value
def OnReseted(self):
super(cci_expert_strategy, self).OnReseted()
self._prev_cci = None
self._prev_prev_cci = None
def OnStarted2(self, time):
super(cci_expert_strategy, self).OnStarted2(time)
self._prev_cci = None
self._prev_prev_cci = None
cci = CommodityChannelIndex()
cci.Length = self._cci_period.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(cci, self.on_process).Start()
def on_process(self, candle, cci_value):
if candle.State != CandleStates.Finished:
return
if self._prev_cci is not None and self._prev_prev_cci is not None:
long_signal = cci_value > 100 and self._prev_cci > 100 and self._prev_prev_cci < 100
short_signal = cci_value < -100 and self._prev_cci < -100 and self._prev_prev_cci > -100
if long_signal and self.Position <= 0:
self.BuyMarket()
elif short_signal and self.Position >= 0:
self.SellMarket()
self._prev_prev_cci = self._prev_cci
self._prev_cci = cci_value
def CreateClone(self):
return cci_expert_strategy()