The Basic CCI RSI strategy reproduces the original MetaTrader expert advisor that waits for both the Commodity Channel Index (CCI) and Relative Strength Index (RSI) to confirm momentum for two consecutive closed candles before entering a trade. The StockSharp version keeps the pip-based money management rules, converts them into price steps automatically, and adds the same trailing-stop behaviour that was implemented with position modifications in MQL5.
How the strategy trades
At the close of each candle (hourly by default) the strategy receives fresh CCI and RSI values.
Long entries require both indicators to stay above their respective upper thresholds for the current and the previous closed candle. Short entries require both to stay below their lower thresholds for the last two candles.
When a signal occurs the strategy opens a position with the configured volume (closing any opposite exposure) and immediately calculates fixed stop-loss and take-profit prices using the pip distances from the original script.
While the position is open the strategy constantly checks whether the candle range touched the stop or take levels and exits at market if either is hit.
A trailing stop replicates the MetaTrader implementation: once profit exceeds TrailingStopPips + TrailingStepPips, the protective stop is moved to TrailingStopPips behind the current close (for longs) or above it (for shorts). Further adjustments require an additional TrailingStepPips of profit before tightening again.
This flow keeps the logic close to the source MQL5 expert while using StockSharp's high-level candle subscriptions and indicators.
Risk management
Stop-loss: fixed pip distance converted to the instrument's price step. Disabled when set to zero.
Take-profit: fixed pip distance converted to the instrument's price step. Disabled when set to zero.
Trailing stop: optional pip distance with a step buffer that mimics the expert advisor's Trailing() function. Disabled when TrailingStopPips is zero.
Position sizing: controlled through the strategy Volume property; the default lot is one contract.
Parameters
Name
Description
StopLossPips
Distance in pips between the entry price and the stop-loss order.
TakeProfitPips
Distance in pips between the entry price and the take-profit target.
TrailingStopPips
Profit (in pips) required to start trailing the stop.
TrailingStepPips
Additional profit (in pips) required before each new trailing adjustment.
CciPeriod
Averaging period for the CCI indicator.
RsiPeriod
Averaging period for the RSI indicator.
RsiLevelUp
Overbought level that must be exceeded to validate long trades.
RsiLevelDown
Oversold level that must be broken to validate short trades.
CciLevelUp
Upper CCI threshold that confirms bullish momentum.
CciLevelDown
Lower CCI threshold that confirms bearish momentum.
CandleType
Timeframe used for candle aggregation and indicator calculations.
Default values
StopLossPips = 125
TakeProfitPips = 60
TrailingStopPips = 5
TrailingStepPips = 5
CciPeriod = 12
RsiPeriod = 15
RsiLevelUp = 75
RsiLevelDown = 30
CciLevelUp = 80
CciLevelDown = -95
CandleType = 1 hour candles
Additional notes
Pip distances are scaled automatically: if the instrument uses 3 or 5 decimal places the strategy multiplies the price step by ten, matching the MetaTrader "adjusted point" logic.
Entries are evaluated only on closed candles to avoid repainting and to mirror the original "new bar" condition in the expert advisor.
Exits always use market orders, providing deterministic behaviour inside the StockSharp backtesting environment.
Classification tags
Category: Oscillator confirmation
Direction: Bi-directional
Indicators: CCI, RSI
Stops: Fixed and trailing (pip based)
Complexity: Beginner
Timeframe: Intraday to swing (default 1 hour)
Seasonality: No
Neural networks: No
Divergence: No
Risk level: Moderate
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>
/// Basic CCI RSI strategy. Uses CCI zero-line crossover with RSI confirmation.
/// </summary>
public class BasicCciRsiStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _cciPeriod;
private decimal? _prevCci;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int CciPeriod { get => _cciPeriod.Value; set => _cciPeriod.Value = value; }
public BasicCciRsiStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame()).SetDisplay("Candle Type", "Timeframe", "General");
_cciPeriod = Param(nameof(CciPeriod), 20).SetGreaterThanZero().SetDisplay("CCI Period", "CCI lookback", "Indicators");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities() => [(Security, CandleType)];
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevCci = null;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevCci = null;
var cci = new CommodityChannelIndex { Length = CciPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(cci, ProcessCandle).Start();
var area = CreateChartArea();
if (area != null) { DrawCandles(area, subscription); DrawOwnTrades(area); }
}
private void ProcessCandle(ICandleMessage candle, decimal cciVal)
{
if (candle.State != CandleStates.Finished) return;
if (!IsFormedAndOnlineAndAllowTrading()) { _prevCci = cciVal; return; }
if (_prevCci == null) { _prevCci = cciVal; return; }
if (_prevCci.Value < 0m && cciVal >= 0m && Position <= 0) { if (Position < 0) BuyMarket(); BuyMarket(); }
else if (_prevCci.Value > 0m && cciVal <= 0m && Position >= 0) { if (Position > 0) SellMarket(); SellMarket(); }
_prevCci = cciVal;
}
}
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 basic_cci_rsi_strategy(Strategy):
def __init__(self):
super(basic_cci_rsi_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))) \
.SetDisplay("Candle Type", "Timeframe", "General")
self._cci_period = self.Param("CciPeriod", 20) \
.SetDisplay("CCI Period", "CCI lookback", "Indicators")
self._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
@property
def cci_period(self):
return self._cci_period.Value
@cci_period.setter
def cci_period(self, value):
self._cci_period.Value = value
def OnReseted(self):
super(basic_cci_rsi_strategy, self).OnReseted()
self._prev_cci = None
def OnStarted2(self, time):
super(basic_cci_rsi_strategy, self).OnStarted2(time)
self._prev_cci = None
cci = CommodityChannelIndex()
cci.Length = self.cci_period
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(cci, self.OnProcess).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
def OnProcess(self, candle, cci_val):
if candle.State != CandleStates.Finished:
return
if not self.IsFormedAndOnlineAndAllowTrading():
self._prev_cci = float(cci_val)
return
if self._prev_cci is None:
self._prev_cci = float(cci_val)
return
if self._prev_cci < 0 and cci_val >= 0 and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif self._prev_cci > 0 and cci_val <= 0 and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._prev_cci = float(cci_val)
def CreateClone(self):
return basic_cci_rsi_strategy()