A No Nonsense Tester Strategy é uma versão StockSharp do consultor especialista MQL4 "NoNonsenseTester". A implementação se concentra no fluxo de trabalho principal do NNFX que valida uma linha de base de tendência, aguarda dois indicadores de confirmação, verifica a volatilidade usando ATR e supervisiona negociações com lógica de saída estrita. A estratégia é projetada para experimentação multiparâmetro e, portanto, expõe todos os limites importantes por meio de objetos StrategyParam para que possam ser otimizados dentro de StockSharp.
Lógica de negociação
Filtro de linha de base – um EMA com comprimento configurável define a direção da tendência primária. As entradas só são consideradas quando o preço fecha na linha de base.
Confirmação #1 – um RSI deve estar no lado de alta (acima do limite) ou de baixa (abaixo do limite complementar) para confirmar a quebra da linha de base.
Confirmação #2 – um CCI deve concordar com a tendência e exceder a magnitude absoluta configurada para bloquear sinais fracos.
Filtro de volatilidade – ATR deve ser maior que o valor AtrMinimum, garantindo que as negociações sejam realizadas apenas quando o mercado mostrar faixa suficiente.
Entrada – quando o cruzamento da linha de base, as duas confirmações e o filtro de volatilidade estão alinhados, a estratégia abre uma posição na direção do movimento. O tamanho da posição pode opcionalmente ser dimensionado com ATR por meio do parâmetro AtrEntryMultiplier.
Stop e meta – imediatamente após a entrada, a estratégia calcula os níveis de stop loss e takeprofit baseados em ATR. O rastreamento opcional ATR continua atualizando o stop de proteção enquanto a negociação se move a favor.
Sobreposição de saída – um RSI adicional com período mais curto supervisiona as negociações abertas. Se cruzar abaixo da banda inferior para posições compradas ou acima da banda superior para posições vendidas, a posição será fechada mesmo que o preço não tenha atingido os níveis de proteção.
Parâmetros
Parâmetro
Descrição
BaselineLength
Período da linha de base EMA.
ConfirmationRsiLength
Comprimento do indicador de confirmação RSI.
ConfirmationRsiThreshold
Nível RSI separando confirmações de alta e baixa.
ConfirmationCciLength
Comprimento do indicador de confirmação CCI.
ConfirmationCciThreshold
Magnitude absoluta mínima CCI para aceitar um sinal.
AtrPeriod
período ATR de retrospectiva.
AtrEntryMultiplier
Multiplicador ATR opcional que dimensiona o volume negociado.
AtrTakeProfitMultiplier
Multiplicador de ATR para o nível de lucro.
AtrStopLossMultiplier
Multiplicador ATR para o nível de stop loss.
AtrTrailingMultiplier
Multiplicador ATR usado para rastreamento dinâmico. Defina como 0 para desativar.
AtrMinimum
Valor mínimo de ATR exigido antes de abrir negociações.
ExitRsiLength
Comprimento da sobreposição de saída RSI.
ExitRsiUpperLevel
Nível RSI que força saídas curtas.
ExitRsiLowerLevel
Nível RSI que força saídas longas.
CandleType
Tipo de vela (período de tempo) usado para cálculos.
Objetos de gráfico
A estratégia desenha automaticamente:
Velas de origem.
EMA linha de base.
Marcadores de negociações executadas.
Notas de otimização
Cada StrategyParam usado na lógica expõe intervalos de otimização que refletem a flexibilidade do testador original. Use ferramentas de otimização StockSharp para varrer comprimentos de linha de base, limites de confirmação e configurações de risco para reproduzir os testes de grade de parâmetros fornecidos pela versão MQL.
Dicas de uso
Combine a estratégia com predefinições de indicadores NNFX ajustando os limites para corresponder às suas ferramentas personalizadas.
Fique de olho no filtro ATR; um AtrMinimum diferente de zero impede negociações durante sessões de baixa volatilidade.
Ao testar as negociações de continuação, defina AtrTrailingMultiplier maior que zero para permitir que as posições lucrativas respirem enquanto bloqueiam os ganhos.
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()