GitHub で見る

CCI Expert Strategy

Overview

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

  1. Subscribe to the configured candle series and calculate a CCI with the chosen period.
  2. 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.
  3. Open only one market position at a time when no position is active and the spread filter allows trading.
  4. 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;
	}
}