Nevalyashka Breakdown Level — это конвертация советника MT4 Nevalyashka_BreakdownLevel на платформу StockSharp. Стратегия строит утренний диапазон между двумя настраиваемыми метками времени и торгует пробои этого диапазона. Если пробой оказывается ложным и срабатывает стоп, позиция немедленно переворачивается в противоположную сторону с увеличением объёма по мартингейлу, чтобы компенсировать убыток. Любая прибыльная сделка блокирует дальнейшие входы до конца торгового дня, что полностью соответствует оригинальному алгоритму.
Основные идеи
Диапазон открытия: Максимум и минимум свечей между RangeStart и RangeEnd задают границы канала на текущий день.
Входы по пробою: Покупка выполняется, когда цена закрытия пересекает верхнюю границу диапазона, продажа — когда закрытие опускается ниже нижней границы.
Защитные уровни: Стоп-лосс устанавливается на противоположной границе диапазона, тейк-профит располагается на расстоянии, равном ширине диапазона.
Перевод в безубыток: При включённом параметре UseBreakeven стоп переносится в точку входа после прохождения половины пути к цели.
Мартингейл: При срабатывании стопа стратегия сразу переворачивается, умножает объём на MartingaleMultiplier и выставляет симметричные уровни стопа/тейка, рассчитанные на возврат предыдущего убытка.
Блокировка на день: Прибыльная или неубыточная фиксация позиции запрещает новые сделки до смены календарного дня.
Принудительное закрытие: Если OrdersCloseTime больше RangeEnd, то по достижении этого времени все позиции закрываются и новые входы блокируются до следующего дня.
Параметры
Имя
Описание
Значение по умолчанию
RangeStart
Время начала построения диапазона (включительно).
04:00
RangeEnd
Время окончания построения диапазона (включительно).
09:00
OrdersCloseTime
Время принудительного закрытия позиций. Если больше RangeEnd, то после этого момента новые входы запрещены.
23:30
OrderVolume
Объём каждой сделки по пробою.
0.1
MartingaleMultiplier
Множитель объёма следующей сделки после стоп-лосса.
2
UseBreakeven
Переводить ли стоп в безубыток после прохождения половины дистанции до тейка.
true
CandleType
Тип свечей для построения диапазона и сигналов.
Свечи 1 часа
Правила торговли
Формирование диапазона. Каждый торговый день стратегия собирает максимум и минимум всех завершённых свечей между RangeStart и RangeEnd.
Условия входа.
Длинная позиция открывается, если закрытие свечи выше верхней границы диапазона.
Короткая позиция открывается, если закрытие ниже нижней границы.
Входы пропускаются, если ожидается мартингейл-переворот, в текущий день уже была прибыльная сделка или текущее время позже OrdersCloseTime (при OrdersCloseTime > RangeEnd).
Управление риском.
Стоп всегда выставляется на противоположной границе диапазона.
Тейк располагается на расстоянии ширины диапазона от цены входа.
При активном UseBreakeven стоп переносится в точку входа, когда цена проходит половину пути к цели.
Мартингейл-переворот.
При стопе позиция закрывается, объём умножается на MartingaleMultiplier, и сразу отправляется заявка в противоположном направлении.
Новые уровни стопа и тейка рассчитываются из величины убытка на один лот, делённой на множитель, что повторяет логику оригинального советника.
Блокировка дня.
Любая сделка с неотрицательным результатом блокирует открытия до наступления следующего календарного дня.
Принудительный выход.
Если OrdersCloseTime находится после диапазона, то по достижении этого времени стратегия закрывает все позиции и прекращает торговлю до завтра.
Дополнительные замечания
Для подписки на данные используются высокоуровневые методы StockSharp (SubscribeCandles().Bind(...)).
Вся необходимая оперативная информация (границы диапазона, состояние мартингейла, признак безубытка) хранится внутри стратегии, что устраняет обращения к истории.
Поведение по календарным дням и немедленный мартингейл после стопа полностью повторяют исходный MT4 советник.
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()