Renko Level — это перенос советника MetaTrader 5 «Renko Level EA» на платформу StockSharp. Стратегия полностью повторяет логику оригинала: каждый раз, когда округлённый уровень Renko перескакивает на новый блок, фиксируются противоположные позиции и открывается сделка в направлении изменения (либо в обратном направлении при активном реверсе).
Для работы используются обычные свечи (по умолчанию 1 минута) — они служат только источником цен. Цена закрытия каждой завершённой свечи округляется до ближайшего шага, соответствующего размеру кирпича Renko. Это позволяет эмулировать Renko-график без отдельной подписки. При каждом изменении округлённого уровня стратегия синхронизирует позиции с новым направлением.
Логика торговли
Инициализация
Определяется минимальный шаг цены (PriceStep) и автоматически вычисляется величина «пункта».
Параметр Block Size задаётся в пунктах и переводится в ценовое значение. Для инструментов с 3 или 5 знаками после запятой шаг умножается на 10.
Первая завершённая свеча используется для расчёта стартовых границ: цена закрытия округляется к ближайшему блоку, формируя верхнюю и нижнюю границу.
Поддержание уровней
На каждой завершённой свече цена закрытия округляется к размеру кирпича.
Если цена остаётся в диапазоне текущего блока, уровни не меняются.
При выходе ниже нижней границы блок сдвигается вниз (lower = round, upper = round + size).
При выходе выше верхней границы блок сдвигается вверх (upper = round, lower = round - size).
Формирование сигналов
Рост верхней границы означает пробой блока вверх, снижение — пробой вниз.
При выключенном Reverse стратегия покупает на пробое вверх и продаёт на пробое вниз. Если Reverse включён, действия меняются местами.
Перед открытием новой позиции стратегия закрывает противоположные позиции. Если Allow Increase = false, то повторное наращивание уже открытого направления блокируется.
Исполнение ордеров
Размер заявок берётся из свойства Volume. При развороте позиции отправляется объём |Position| + Volume, что позволяет закрыть старое направление и открыть новое одной сделкой.
В методе OnStarted вызывается StartProtection(), благодаря чему можно подключить штатные защитные механизмы StockSharp.
Параметры
Параметр
Описание
Значение по умолчанию
Block Size
Размер блока Renko в пунктах. При больших значениях сделок меньше, блоки шире.
30
Reverse
Инверсия сигналов. При true покупка выполняется на снижении уровня, продажа — на росте.
false
Allow Increase
Разрешение пирамидинга. При false стратегия ждёт полного выхода из позиции перед новой заявкой.
false
Candle Type
Тип исходных свечей. По умолчанию используется тайм-фрейм 1 минута, но можно указать любой поддерживаемый DataType.
TimeFrame(1m)
Volume(унаследовано)
Торговый объём. Установите его перед запуском стратегии в Designer или коде.
Зависит от портфеля
Практические рекомендации
Подбирайте размер блока под волатильность инструмента: для основных валютных пар обычно достаточно 30–50 пунктов, для индексов и криптовалют используют более крупные значения.
Стратегия одинаково хорошо работает с любыми свечами: временными, объёмными, диапазонными. При наличии готовых Renko-свечей можно просто поменять Candle Type.
Включите Reverse, если хотите протестировать контртрендовую логику, в которой каждая смена уровня торгуется против направления движения.
Опция Allow Increase повторяет параметр «Increase» в оригинальном советнике, разрешая добавлять позицию на каждом новом уровне в ту же сторону.
Управление рисками (стоп-лосс, тейк-профит, ограничения просадки) реализуется через стандартные механизмы StockSharp. Пример сохраняет исходную логику MT5 и не вводит дополнительных фильтров выхода.
Требования к данным
Исторические и потоковые свечи выбранного типа (Candle Type).
Желательно наличие корректных PriceStep и Decimals в описании инструмента; если данных нет, используется запасной шаг 0.0001.
Как работать со стратегией
Добавьте RenkoLevelStrategy в Designer или создайте экземпляр в коде.
Укажите Security, выберите Portfolio, задайте Volume и измените параметры по необходимости.
Запустите стратегию. Она дождётся первой завершённой свечи и построит стартовые уровни Renko.
Отслеживайте сделки через встроенные графики или журналы, чтобы убедиться, что входы происходят только при смене округлённого уровня.
Данная документация подробно описывает поведение оригинального Renko Level EA в экосистеме StockSharp и помогает адаптировать его под собственные задачи.
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Renko level breakout strategy. Emulates Renko bricks on time-based candles
/// and trades when the rounded level shifts up or down.
/// </summary>
public class RenkoLevelStrategy : Strategy
{
private readonly StrategyParam<int> _blockSize;
private readonly StrategyParam<DataType> _candleType;
private decimal _upperLevel;
private decimal _lowerLevel;
private bool _hasLevels;
public int BlockSize
{
get => _blockSize.Value;
set => _blockSize.Value = value;
}
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public RenkoLevelStrategy()
{
_blockSize = Param(nameof(BlockSize), 5000)
.SetGreaterThanZero()
.SetDisplay("Block Size", "Renko block size in price steps", "Renko");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Candles", "General");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_upperLevel = 0m;
_lowerLevel = 0m;
_hasLevels = false;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var subscription = SubscribeCandles(CandleType);
subscription.Bind(ProcessCandle).Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
var brickSize = GetBrickSize();
if (brickSize <= 0m)
return;
var close = candle.ClosePrice;
if (!_hasLevels)
{
InitializeLevels(close, brickSize);
return;
}
if (!IsFormedAndOnlineAndAllowTrading())
return;
var previousUpper = _upperLevel;
var moved = false;
if (close < _lowerLevel)
{
var (round, _, ceil) = CalculateLevels(close, brickSize);
if (Math.Abs(round - _lowerLevel) > brickSize * 0.01m)
{
_lowerLevel = round;
_upperLevel = ceil;
moved = true;
}
}
else if (close > _upperLevel)
{
var (round, floor, _) = CalculateLevels(close, brickSize);
if (Math.Abs(round - _upperLevel) > brickSize * 0.01m)
{
_lowerLevel = floor;
_upperLevel = round;
moved = true;
}
}
if (!moved)
return;
if (_upperLevel > previousUpper && Position <= 0)
BuyMarket();
else if (_upperLevel < previousUpper && Position >= 0)
SellMarket();
}
private void InitializeLevels(decimal price, decimal brickSize)
{
var (round, floor, _) = CalculateLevels(price, brickSize);
_upperLevel = round;
_lowerLevel = floor;
_hasLevels = true;
}
private (decimal round, decimal floor, decimal ceil) CalculateLevels(decimal price, decimal brickSize)
{
var ratio = price / brickSize;
var rounded = Math.Round(ratio, 0, MidpointRounding.AwayFromZero);
var priceRound = rounded * brickSize;
var priceFloor = priceRound - brickSize;
var priceCeil = priceRound + brickSize;
return (priceRound, priceFloor, priceCeil);
}
private decimal GetBrickSize()
{
var step = Security?.PriceStep ?? 0.01m;
return step * BlockSize;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Math
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Strategies import Strategy
class renko_level_strategy(Strategy):
def __init__(self):
super(renko_level_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Candles", "General")
self._block_size = self.Param("BlockSize", 5000) \
.SetDisplay("Block Size", "Renko block size in price steps", "Renko")
self._upper_level = 0.0
self._lower_level = 0.0
self._has_levels = False
@property
def CandleType(self):
return self._candle_type.Value
@property
def BlockSize(self):
return self._block_size.Value
def OnReseted(self):
super(renko_level_strategy, self).OnReseted()
self._upper_level = 0.0
self._lower_level = 0.0
self._has_levels = False
def OnStarted2(self, time):
super(renko_level_strategy, self).OnStarted2(time)
self._upper_level = 0.0
self._lower_level = 0.0
self._has_levels = False
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(self._on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
def _on_process(self, candle):
if candle.State != CandleStates.Finished:
return
brick_size = self._get_brick_size()
if brick_size <= 0:
return
close = float(candle.ClosePrice)
if not self._has_levels:
self._initialize_levels(close, brick_size)
return
previous_upper = self._upper_level
moved = False
if close < self._lower_level:
rnd, _, ceil = self._calculate_levels(close, brick_size)
if abs(rnd - self._lower_level) > brick_size * 0.01:
self._lower_level = rnd
self._upper_level = ceil
moved = True
elif close > self._upper_level:
rnd, floor, _ = self._calculate_levels(close, brick_size)
if abs(rnd - self._upper_level) > brick_size * 0.01:
self._lower_level = floor
self._upper_level = rnd
moved = True
if not moved:
return
if self._upper_level > previous_upper and self.Position <= 0:
self.BuyMarket()
elif self._upper_level < previous_upper and self.Position >= 0:
self.SellMarket()
def _initialize_levels(self, price, brick_size):
rnd, floor, _ = self._calculate_levels(price, brick_size)
self._upper_level = rnd
self._lower_level = floor
self._has_levels = True
def _calculate_levels(self, price, brick_size):
ratio = price / brick_size
rounded = round(ratio)
price_round = rounded * brick_size
price_floor = price_round - brick_size
price_ceil = price_round + brick_size
return (price_round, price_floor, price_ceil)
def _get_brick_size(self):
sec = self.Security
step = float(sec.PriceStep) if sec is not None and sec.PriceStep is not None else 0.01
return step * self.BlockSize
def CreateClone(self):
return renko_level_strategy()