Открыть на GitHub

Стратегия Exp Rj SlidingRangeRj Digit System Tm Plus

Описание

Стратегия представляет собой перенос советника MetaTrader Exp_Rj_SlidingRangeRj_Digit_System_Tm_Plus на платформу StockSharp. Логика полностью повторяет оригинал: используются сигналы пользовательского индикатора Rj_SlidingRangeRj_Digit, а также настройки отложенного входа, временного контроля и остановок по пунктам. Стратегия анализирует закрытые свечи выбранного таймфрейма, выявляет выход цены за границы канала и управляет позицией согласно правилам исходного эксперта.

Индикатор

Индикатор формирует адаптивный ценовой коридор по следующему алгоритму:

  1. Для верхней границы вычисляется максимум в каждом из UpCalcPeriodRange скользящих окон длиной UpCalcPeriodRange, сдвинутых на UpCalcPeriodShift баров. Значения максимума усредняются и округляются до UpDigit знаков.
  2. Нижняя граница рассчитывается аналогично по минимумам с параметрами DnCalcPeriodRange, DnCalcPeriodShift, DnDigit.
  3. Закрытие свечи выше верхней границы помечается цветами 2 или 3, ниже нижней границы — 0 или 1, внутри канала — 4.

Для воспроизведения логики MQL стратегия хранит историю цветовых кодов и обращается к сигналу на баре, заданном параметром SignalBar.

Правила торговли

  • Отложенный вход. Оценка сигнала производится на баре SignalBar (по умолчанию предыдущий). Сделка открывается только при появлении нового цвета-прорыва и отсутствии такого же цвета на предыдущем баре.
  • Покупка. При включённом EnableBuyEntries бычий выход (цвет 2 или 3) инициирует покупку по рынку, если нет открытой длинной позиции (короткая позиция при этом закрывается).
  • Продажа. При включённом EnableSellEntries медвежий выход (цвет 0 или 1) вызывает продажу по рынку.
  • Выход из позиции.
    • EnableBuyExits — закрывать лонг при появлении цветов 0/1.
    • EnableSellExits — закрывать шорт при появлении цветов 2/3.
    • UseTimeExit — закрыть любую позицию после истечения ExitMinutes минут удержания.
    • StopLossPoints и TakeProfitPoints задают уровни стоп-лосса и тейк-профита в пунктах и автоматически преобразуются в цену через PriceStep инструмента.

Все сделки отправляются методами BuyMarket и SellMarket, поэтому стратегия умеет развернуться из противоположной позиции одной заявкой.

Параметры

Параметр Назначение Значение по умолчанию
CandleType Тип/таймфрейм свечей для сигналов 8-часовые свечи
EnableBuyEntries / EnableSellEntries Разрешение входов в лонг/шорт true
EnableBuyExits / EnableSellExits Разрешение индикаторных выходов true
UseTimeExit Использовать выход по времени true
ExitMinutes Максимальное время удержания позиции (минуты) 1920
UpCalcPeriodRange, UpCalcPeriodShift, UpDigit Параметры верхней границы канала 5, 0, 2
DnCalcPeriodRange, DnCalcPeriodShift, DnDigit Параметры нижней границы канала 5, 0, 2
SignalBar Номер бара для анализа сигнала 1
StopLossPoints, TakeProfitPoints Стоп-лосс / тейк-профит в пунктах (× PriceStep) 1000, 2000

Размер позиции задаётся через свойство Volume. Чтобы отключить стоп или тейк, установите соответствующий параметр в 0.

Дополнительно

  • Для корректного расчёта канала необходим достаточный объём истории (примерно max(shift + 2 × range) свечей). До накопления данных сигналы игнорируются.
  • Округление значений производится по количеству знаков после запятой, что повторяет поведение индикатора в MetaTrader.
  • По требованию проекта Python-реализация не создаётся, в каталоге присутствует только версия на C#.
using System;
using System.Collections.Generic;

using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Sliding range breakout strategy using Highest/Lowest channel.
/// Enters on breakout above/below the channel, exits on opposite breakout.
/// </summary>
public class ExpRjSlidingRangeRjDigitSystemTmPlusStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _period;

	private decimal? _prevUpper;
	private decimal? _prevLower;

	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	public int Period
	{
		get => _period.Value;
		set => _period.Value = value;
	}

	public ExpRjSlidingRangeRjDigitSystemTmPlusStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe", "General");

		_period = Param(nameof(Period), 10)
			.SetGreaterThanZero()
			.SetDisplay("Period", "Channel lookback", "Indicators");
	}

	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		return [(Security, CandleType)];
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevUpper = null;
		_prevLower = null;
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		_prevUpper = null;
		_prevLower = null;

		var highest = new Highest { Length = Period };
		var lowest = new Lowest { Length = Period };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(highest, lowest, ProcessCandle)
			.Start();

		var area = CreateChartArea();
		if (area != null)
		{
			DrawCandles(area, subscription);
			DrawIndicator(area, highest);
			DrawIndicator(area, lowest);
			DrawOwnTrades(area);
		}
	}

	private void ProcessCandle(ICandleMessage candle, decimal upper, decimal lower)
	{
		if (candle.State != CandleStates.Finished)
			return;

		if (!IsFormedAndOnlineAndAllowTrading())
		{
			_prevUpper = upper;
			_prevLower = lower;
			return;
		}

		var close = candle.ClosePrice;

		if (_prevUpper == null || _prevLower == null)
		{
			_prevUpper = upper;
			_prevLower = lower;
			return;
		}

		// Breakout above previous upper → buy
		if (close > _prevUpper.Value && Position <= 0)
		{
			if (Position < 0)
				BuyMarket();
			BuyMarket();
		}
		// Breakdown below previous lower → sell
		else if (close < _prevLower.Value && Position >= 0)
		{
			if (Position > 0)
				SellMarket();
			SellMarket();
		}

		_prevUpper = upper;
		_prevLower = lower;
	}
}