Открыть на GitHub

Стратегия Renko Level

Обзор

Renko Level — это перенос советника MetaTrader 5 «Renko Level EA» на платформу StockSharp. Стратегия полностью повторяет логику оригинала: каждый раз, когда округлённый уровень Renko перескакивает на новый блок, фиксируются противоположные позиции и открывается сделка в направлении изменения (либо в обратном направлении при активном реверсе).

Для работы используются обычные свечи (по умолчанию 1 минута) — они служат только источником цен. Цена закрытия каждой завершённой свечи округляется до ближайшего шага, соответствующего размеру кирпича Renko. Это позволяет эмулировать Renko-график без отдельной подписки. При каждом изменении округлённого уровня стратегия синхронизирует позиции с новым направлением.

Логика торговли

  1. Инициализация
    • Определяется минимальный шаг цены (PriceStep) и автоматически вычисляется величина «пункта».
    • Параметр Block Size задаётся в пунктах и переводится в ценовое значение. Для инструментов с 3 или 5 знаками после запятой шаг умножается на 10.
    • Первая завершённая свеча используется для расчёта стартовых границ: цена закрытия округляется к ближайшему блоку, формируя верхнюю и нижнюю границу.
  2. Поддержание уровней
    • На каждой завершённой свече цена закрытия округляется к размеру кирпича.
    • Если цена остаётся в диапазоне текущего блока, уровни не меняются.
    • При выходе ниже нижней границы блок сдвигается вниз (lower = round, upper = round + size).
    • При выходе выше верхней границы блок сдвигается вверх (upper = round, lower = round - size).
  3. Формирование сигналов
    • Рост верхней границы означает пробой блока вверх, снижение — пробой вниз.
    • При выключенном Reverse стратегия покупает на пробое вверх и продаёт на пробое вниз. Если Reverse включён, действия меняются местами.
    • Перед открытием новой позиции стратегия закрывает противоположные позиции. Если Allow Increase = false, то повторное наращивание уже открытого направления блокируется.
  4. Исполнение ордеров
    • Размер заявок берётся из свойства 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.

Как работать со стратегией

  1. Добавьте RenkoLevelStrategy в Designer или создайте экземпляр в коде.
  2. Укажите Security, выберите Portfolio, задайте Volume и измените параметры по необходимости.
  3. Запустите стратегию. Она дождётся первой завершённой свечи и построит стартовые уровни Renko.
  4. Отслеживайте сделки через встроенные графики или журналы, чтобы убедиться, что входы происходят только при смене округлённого уровня.

Данная документация подробно описывает поведение оригинального 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;
	}
}