La estrategia Nevalyashka Breakdown Level es una conversión directa del asesor experto MT4 Nevalyashka_BreakdownLevel. El sistema construye un rango de apertura entre dos momentos configurables y comercializa rupturas de ese rango. Cuando falla una ruptura y se detiene la operación, la estrategia inmediatamente invierte la dirección utilizando un multiplicador martingala para recuperar la pérdida. Las operaciones rentables bloquean cualquier entrada adicional durante el resto del día de negociación, coincidiendo con el comportamiento original de EA.
Conceptos clave
Rango de apertura: El máximo más alto y el mínimo más bajo impresos entre RangeStart y RangeEnd definen el canal de ruptura para el día actual.
Entradas de ruptura: Se abre una posición larga cuando el precio de cierre excede el máximo del rango; Se abre una posición corta cuando cae por debajo del mínimo del rango.
Órdenes de protección: El stop-loss siempre se coloca en el lado opuesto del rango. La toma de ganancias se coloca a una distancia igual al ancho del rango.
Movimiento de equilibrio: Cuando está habilitado, el stop se mueve al precio de entrada una vez que la operación avanza hasta la mitad del camino hacia el objetivo.
Martingale recuperación: Después de un stop-loss, la estrategia invierte la dirección, multiplica el volumen de la orden por MartingaleMultiplier y utiliza un tamaño objetivo/stop simétrico para recuperar la pérdida anterior.
Bloqueo diario: Cualquier cierre rentable (toma de ganancias o salida manual por encima de cero) evita nuevas operaciones hasta que cambie el día de negociación.
Plano forzado: Cuando OrdersCloseTime es posterior a RangeEnd, todas las posiciones abiertas se cierran en ese momento y las nuevas entradas se bloquean durante el resto del día.
Parámetros
Nombre
Descripción
Predeterminado
RangeStart
Hora de inicio (inclusive) del rango de referencia.
04:00
RangeEnd
Hora de finalización (inclusive) del rango de referencia.
09:00
OrdersCloseTime
Hora del día para cerrar posiciones con fuerza. Cuando esta hora es posterior a RangeEnd, también bloquea nuevas operaciones posteriores.
23:30
OrderVolume
Volumen utilizado para cada operación de ruptura.
0.1
MartingaleMultiplier
Multiplicador aplicado a la siguiente orden después de un stop-loss para recuperar la pérdida anterior.
2
UseBreakeven
Permite mover el stop al punto de equilibrio una vez que la operación ha recorrido la mitad de la distancia objetivo.
true
CandleType
Tipo de vela utilizado para construir el rango y generar señales.
1 hour velas
Reglas de trading
Cálculo de rango: Para cada nuevo día de negociación, la estrategia registra los máximos y mínimos de las velas terminadas entre RangeStart y RangeEnd (inclusive).
Condiciones de entrada:
Vaya en largo cuando el precio de cierre de la vela actual esté por encima del máximo del rango registrado.
Vaya en corto cuando el precio de cierre de la vela actual esté por debajo del mínimo del rango registrado.
Las entradas se omiten si hay pendiente una reversión de martingala, si ya se produjo una operación rentable el mismo día o si la hora actual es pasada OrdersCloseTime (cuando OrdersCloseTime > RangeEnd).
Gestión de riesgos:
El stop-loss está anclado en el lado opuesto del rango de apertura.
La toma de ganancias se establece en el precio de entrada más/menos el ancho del rango de apertura.
Cuando UseBreakeven está habilitado, el stop se mueve al precio de entrada después de que se haya cubierto la mitad de la distancia objetivo.
Martingale reversión:
Si se alcanza el stop-loss, la posición se cierra, el volumen se multiplica por MartingaleMultiplier y se envía una orden de mercado inmediata en la dirección opuesta.
La nueva parada y el objetivo se colocan a una distancia igual a la pérdida por lote dividida por el multiplicador, coincidiendo con la lógica de recuperación del EA original.
Bloqueo comercial diario:
Si una operación se cierra con una ganancia no negativa o se alcanza el objetivo, no se permiten nuevas operaciones hasta que cambie la fecha de negociación.
Salida forzada:
Cuando OrdersCloseTime está después de la ventana de rango y la hora actual alcanza este valor, todas las posiciones abiertas se aplanan y el día se bloquea.
Notas
La estrategia utiliza el StockSharp API (Strategy.SubscribeCandles().Bind(...)) de alto nivel para mantenerse cerca de las convenciones del marco.
Todos los cálculos con estado (límites de rango, órdenes de martingala pendientes, estado de equilibrio) se almacenan dentro de la clase de estrategia para evitar búsquedas históricas.
La conversión conserva el comportamiento original del EA de contar los días de negociación por fecha del calendario y gestionar los pasos de martingala inmediatamente después de una parada.
using System;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Nevalyashka BreakdownLevel: Previous candle breakout with EMA filter and ATR stops.
/// </summary>
public class NevalyashkaBreakdownLevelStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _emaLength;
private readonly StrategyParam<int> _atrLength;
private decimal _prevHigh;
private decimal _prevLow;
private decimal _entryPrice;
public NevalyashkaBreakdownLevelStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(8).TimeFrame())
.SetDisplay("Candle Type", "Timeframe.", "General");
_emaLength = Param(nameof(EmaLength), 30)
.SetDisplay("EMA Length", "Trend filter.", "Indicators");
_atrLength = Param(nameof(AtrLength), 14)
.SetDisplay("ATR Length", "ATR period.", "Indicators");
}
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int EmaLength { get => _emaLength.Value; set => _emaLength.Value = value; }
public int AtrLength { get => _atrLength.Value; set => _atrLength.Value = value; }
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevHigh = 0; _prevLow = 0; _entryPrice = 0;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevHigh = 0; _prevLow = 0; _entryPrice = 0;
var ema = new ExponentialMovingAverage { Length = EmaLength };
var atr = new AverageTrueRange { Length = AtrLength };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(ema, atr, ProcessCandle).Start();
var area = CreateChartArea();
if (area != null) { DrawCandles(area, subscription); DrawIndicator(area, ema); DrawOwnTrades(area); }
}
private void ProcessCandle(ICandleMessage candle, decimal emaVal, decimal atrVal)
{
if (candle.State != CandleStates.Finished) return;
var close = candle.ClosePrice;
if (_prevHigh == 0 || atrVal <= 0) { _prevHigh = candle.HighPrice; _prevLow = candle.LowPrice; return; }
if (Position > 0)
{
if (close <= _entryPrice - atrVal * 1.5m || close >= _entryPrice + atrVal * 2.5m) { SellMarket(); _entryPrice = 0; }
}
else if (Position < 0)
{
if (close >= _entryPrice + atrVal * 1.5m || close <= _entryPrice - atrVal * 2.5m) { BuyMarket(); _entryPrice = 0; }
}
if (Position == 0)
{
if (close > _prevHigh && close > emaVal) { _entryPrice = close; BuyMarket(); }
else if (close < _prevLow && close < emaVal) { _entryPrice = close; SellMarket(); }
}
_prevHigh = candle.HighPrice; _prevLow = candle.LowPrice;
}
}
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.Strategies import Strategy
from StockSharp.Algo.Indicators import ExponentialMovingAverage, AverageTrueRange
class nevalyashka_breakdown_level_strategy(Strategy):
def __init__(self):
super(nevalyashka_breakdown_level_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(8))) \
.SetDisplay("Candle Type", "Timeframe.", "General")
self._ema_length = self.Param("EmaLength", 30) \
.SetDisplay("EMA Length", "Trend filter.", "Indicators")
self._atr_length = self.Param("AtrLength", 14) \
.SetDisplay("ATR Length", "ATR period.", "Indicators")
self._prev_high = 0.0
self._prev_low = 0.0
self._entry_price = 0.0
@property
def CandleType(self):
return self._candle_type.Value
@property
def EmaLength(self):
return self._ema_length.Value
@property
def AtrLength(self):
return self._atr_length.Value
def OnStarted2(self, time):
super(nevalyashka_breakdown_level_strategy, self).OnStarted2(time)
self._prev_high = 0.0
self._prev_low = 0.0
self._entry_price = 0.0
self._ema = ExponentialMovingAverage()
self._ema.Length = self.EmaLength
self._atr = AverageTrueRange()
self._atr.Length = self.AtrLength
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(self._ema, self._atr, self.ProcessCandle).Start()
def ProcessCandle(self, candle, ema_val, atr_val):
if candle.State != CandleStates.Finished:
return
ev = float(ema_val)
av = float(atr_val)
close = float(candle.ClosePrice)
if self._prev_high == 0 or av <= 0:
self._prev_high = float(candle.HighPrice)
self._prev_low = float(candle.LowPrice)
return
if self.Position > 0:
if close <= self._entry_price - av * 1.5 or close >= self._entry_price + av * 2.5:
self.SellMarket()
self._entry_price = 0.0
elif self.Position < 0:
if close >= self._entry_price + av * 1.5 or close <= self._entry_price - av * 2.5:
self.BuyMarket()
self._entry_price = 0.0
if not self.IsFormedAndOnlineAndAllowTrading():
self._prev_high = float(candle.HighPrice)
self._prev_low = float(candle.LowPrice)
return
if self.Position == 0:
if close > self._prev_high and close > ev:
self._entry_price = close
self.BuyMarket()
elif close < self._prev_low and close < ev:
self._entry_price = close
self.SellMarket()
self._prev_high = float(candle.HighPrice)
self._prev_low = float(candle.LowPrice)
def OnReseted(self):
super(nevalyashka_breakdown_level_strategy, self).OnReseted()
self._prev_high = 0.0
self._prev_low = 0.0
self._entry_price = 0.0
def CreateClone(self):
return nevalyashka_breakdown_level_strategy()