The No Nonsense Tester Strategy is a StockSharp port of the MQL4 "NoNonsenseTester" expert advisor. The implementation focuses on the core NNFX workflow that validates a trend baseline, waits for two confirmation indicators, checks volatility using ATR and supervises trades with strict exit logic. The strategy is designed for multi-parameter experimentation and therefore exposes all important thresholds through StrategyParam objects so they can be optimized inside StockSharp.
Trading Logic
Baseline filter – an EMA with configurable length defines the primary trend direction. Entries are only considered when the price closes across the baseline.
Confirmation #1 – an RSI must be on the bullish (above threshold) or bearish (below complementary threshold) side to confirm the baseline break.
Confirmation #2 – a CCI must agree with the trend and exceed the configured absolute magnitude to block weak signals.
Volatility filter – ATR must be greater than the AtrMinimum value, ensuring that trades are taken only when the market shows sufficient range.
Entry – when the baseline cross, the two confirmations and the volatility filter are aligned, the strategy opens a position in the direction of the move. Position size can optionally scale with ATR through the AtrEntryMultiplier parameter.
Stop and target – immediately after entry the strategy computes ATR-based stop loss and take profit levels. Optional ATR trailing keeps updating the protective stop while the trade moves in favour.
Exit overlay – an additional RSI with shorter period supervises open trades. If it crosses under the lower band for longs or over the upper band for shorts the position is closed even if price has not touched protective levels.
Parameters
Parameter
Description
BaselineLength
Period of the EMA baseline.
ConfirmationRsiLength
Length of the RSI confirmation indicator.
ConfirmationRsiThreshold
RSI level separating bullish and bearish confirmations.
ConfirmationCciLength
Length of the CCI confirmation indicator.
ConfirmationCciThreshold
Minimal absolute CCI magnitude to accept a signal.
AtrPeriod
ATR lookback period.
AtrEntryMultiplier
Optional ATR multiplier that scales the traded volume.
AtrTakeProfitMultiplier
ATR multiplier for the take profit level.
AtrStopLossMultiplier
ATR multiplier for the stop loss level.
AtrTrailingMultiplier
ATR multiplier used for dynamic trailing. Set to 0 to disable.
AtrMinimum
Minimum ATR value required before opening trades.
ExitRsiLength
Length of the exit RSI overlay.
ExitRsiUpperLevel
RSI level that forces short exits.
ExitRsiLowerLevel
RSI level that forces long exits.
CandleType
Candle type (time-frame) used for calculations.
Chart Objects
The strategy automatically draws:
Source candles.
EMA baseline.
Executed trades markers.
Optimization Notes
Every StrategyParam used in the logic exposes optimization ranges mirroring the flexibility of the original tester. Use StockSharp optimization tools to sweep baseline lengths, confirmation thresholds and risk settings to reproduce the parameter grid tests provided by the MQL version.
Usage Tips
Combine the strategy with NNFX indicator presets by adjusting the thresholds to match your custom tools.
Keep an eye on the ATR filter; a non-zero AtrMinimum prevents trades during low-volatility sessions.
When testing continuation trades set AtrTrailingMultiplier greater than zero to let profitable positions breathe while locking in gains.
namespace StockSharp.Samples.Strategies;
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
/// <summary>
/// No Nonsense Tester strategy: EMA baseline + RSI confirmation + CCI confirmation.
/// Buys when price above EMA, RSI above 50, CCI above 0.
/// Sells when price below EMA, RSI below 50, CCI below 0.
/// </summary>
public class NoNonsenseTesterStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _emaPeriod;
private readonly StrategyParam<int> _rsiPeriod;
private readonly StrategyParam<int> _cciPeriod;
private bool _wasBullish;
private bool _hasPrevSignal;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int EmaPeriod { get => _emaPeriod.Value; set => _emaPeriod.Value = value; }
public int RsiPeriod { get => _rsiPeriod.Value; set => _rsiPeriod.Value = value; }
public int CciPeriod { get => _cciPeriod.Value; set => _cciPeriod.Value = value; }
public NoNonsenseTesterStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(15).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
_emaPeriod = Param(nameof(EmaPeriod), 25)
.SetGreaterThanZero()
.SetDisplay("EMA Period", "EMA baseline period", "Indicators");
_rsiPeriod = Param(nameof(RsiPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("RSI Period", "RSI confirmation period", "Indicators");
_cciPeriod = Param(nameof(CciPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("CCI Period", "CCI confirmation period", "Indicators");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_wasBullish = false;
_hasPrevSignal = false;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_hasPrevSignal = false;
var ema = new ExponentialMovingAverage { Length = EmaPeriod };
var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
var cci = new CommodityChannelIndex { Length = CciPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(ema, rsi, cci, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, decimal ema, decimal rsi, decimal cci)
{
if (candle.State != CandleStates.Finished) return;
var close = candle.ClosePrice;
var isBullish = close > ema && rsi > 50 && cci > 0;
if (_hasPrevSignal && isBullish != _wasBullish)
{
if (isBullish && Position <= 0)
BuyMarket();
else if (!isBullish && close < ema && rsi < 50 && cci < 0 && Position >= 0)
SellMarket();
}
_wasBullish = isBullish;
_hasPrevSignal = true;
}
}
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, RelativeStrengthIndex, CommodityChannelIndex
from StockSharp.Algo.Strategies import Strategy
class no_nonsense_tester_strategy(Strategy):
def __init__(self):
super(no_nonsense_tester_strategy, self).__init__()
self._ema_period = self.Param("EmaPeriod", 25) \
.SetDisplay("EMA Period", "EMA baseline period", "Indicators")
self._rsi_period = self.Param("RsiPeriod", 14) \
.SetDisplay("RSI Period", "RSI confirmation period", "Indicators")
self._cci_period = self.Param("CciPeriod", 14) \
.SetDisplay("CCI Period", "CCI confirmation period", "Indicators")
self._ema = None
self._rsi = None
self._cci = None
self._was_bullish = False
self._has_prev_signal = False
@property
def ema_period(self):
return self._ema_period.Value
@property
def rsi_period(self):
return self._rsi_period.Value
@property
def cci_period(self):
return self._cci_period.Value
def OnReseted(self):
super(no_nonsense_tester_strategy, self).OnReseted()
self._ema = None
self._rsi = None
self._cci = None
self._was_bullish = False
self._has_prev_signal = False
def OnStarted2(self, time):
super(no_nonsense_tester_strategy, self).OnStarted2(time)
self._ema = ExponentialMovingAverage()
self._ema.Length = self.ema_period
self._rsi = RelativeStrengthIndex()
self._rsi.Length = self.rsi_period
self._cci = CommodityChannelIndex()
self._cci.Length = self.cci_period
self._has_prev_signal = False
subscription = self.SubscribeCandles(DataType.TimeFrame(TimeSpan.FromMinutes(15)))
subscription.Bind(self._ema, self._rsi, self._cci, self._process_candle)
subscription.Start()
def _process_candle(self, candle, ema_value, rsi_value, cci_value):
if candle.State != CandleStates.Finished:
return
if not self._ema.IsFormed or not self._rsi.IsFormed or not self._cci.IsFormed:
return
close = float(candle.ClosePrice)
ema_val = float(ema_value)
rsi_val = float(rsi_value)
cci_val = float(cci_value)
is_bullish = close > ema_val and rsi_val > 50.0 and cci_val > 0.0
if self._has_prev_signal and is_bullish != self._was_bullish:
if is_bullish and self.Position <= 0:
self.BuyMarket()
elif not is_bullish and close < ema_val and rsi_val < 50.0 and cci_val < 0.0 and self.Position >= 0:
self.SellMarket()
self._was_bullish = is_bullish
self._has_prev_signal = True
def CreateClone(self):
return no_nonsense_tester_strategy()