La Estrategia de probador sin tonterías es una versión StockSharp del asesor experto MQL4 "NoNonsenseTester". La implementación se centra en el flujo de trabajo principal de NNFX que valida una línea base de tendencia, espera dos indicadores de confirmación, verifica la volatilidad usando ATR y supervisa las operaciones con una lógica de salida estricta. La estrategia está diseñada para la experimentación con múltiples parámetros y, por lo tanto, expone todos los umbrales importantes a través de objetos StrategyParam para que puedan optimizarse dentro de StockSharp.
Lógica de trading
Filtro de línea de base: un EMA con longitud configurable define la dirección de la tendencia principal. Las entradas solo se consideran cuando el precio cierra en la línea de base.
Confirmación n.º 1: un RSI debe estar en el lado alcista (por encima del umbral) o bajista (por debajo del umbral complementario) para confirmar la ruptura de la línea base.
Confirmación n.° 2: un CCI debe estar de acuerdo con la tendencia y exceder la magnitud absoluta configurada para bloquear señales débiles.
Filtro de volatilidad: ATR debe ser mayor que el valor de AtrMinimum, lo que garantiza que las operaciones se realicen solo cuando el mercado muestre un rango suficiente.
Entrada – cuando la línea base se cruza, las dos confirmaciones y el filtro de volatilidad están alineados, la estrategia abre una posición en la dirección del movimiento. El tamaño de la posición puede escalar opcionalmente con ATR a través del parámetro AtrEntryMultiplier.
Stop and target: inmediatamente después de la entrada, la estrategia calcula los niveles de stop loss y takeprofit basados en ATR. El seguimiento opcional ATR sigue actualizando el stop de protección mientras la operación se mueve a favor.
Superposición de salida: un RSI adicional con un período más corto supervisa las operaciones abiertas. Si cruza por debajo de la banda inferior para largos o por encima de la banda superior para cortos, la posición se cierra incluso si el precio no ha tocado los niveles de protección.
Parámetros
Parámetro
Descripción
BaselineLength
Período de la línea base EMA.
ConfirmationRsiLength
Longitud del indicador de confirmación RSI.
ConfirmationRsiThreshold
RSI nivel que separa las confirmaciones alcistas y bajistas.
ConfirmationCciLength
Longitud del indicador de confirmación CCI.
ConfirmationCciThreshold
Magnitud mínima absoluta CCI para aceptar una señal.
AtrPeriod
periodo ATR retrospectivo.
AtrEntryMultiplier
Multiplicador ATR opcional que escala el volumen negociado.
AtrTakeProfitMultiplier
multiplicador ATR para el nivel de obtención de beneficios.
AtrStopLossMultiplier
multiplicador ATR para el nivel de stop loss.
AtrTrailingMultiplier
multiplicador ATR utilizado para el seguimiento dinámico. Establezca en 0 para desactivar.
AtrMinimum
Valor mínimo de ATR requerido antes de abrir operaciones.
ExitRsiLength
Longitud de la superposición de salida RSI.
ExitRsiUpperLevel
RSI nivel que obliga a salidas cortas.
ExitRsiLowerLevel
RSI nivel que obliga a salidas largas.
CandleType
Tipo de vela (marco de tiempo) utilizado para los cálculos.
Objetos de gráfico
La estrategia dibuja automáticamente:
Velas de origen.
EMA línea base.
Marcadores de operaciones ejecutadas.
Notas de optimización
Cada StrategyParam utilizado en la lógica expone rangos de optimización que reflejan la flexibilidad del probador original. Utilice las herramientas de optimización StockSharp para barrer las longitudes de las líneas de base, los umbrales de confirmación y las configuraciones de riesgo para reproducir las pruebas de cuadrícula de parámetros proporcionadas por la versión MQL.
Consejos de uso
Combine la estrategia con los ajustes preestablecidos del indicador NNFX ajustando los umbrales para que coincidan con sus herramientas personalizadas.
Esté atento al filtro ATR; un AtrMinimum distinto de cero impide las operaciones durante sesiones de baja volatilidad.
Al probar las operaciones de continuación, establezca AtrTrailingMultiplier mayor que cero para permitir que las posiciones rentables respiren mientras se aseguran las ganancias.
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()