Открыть на GitHub

Стратегия RobotPowerM5 Meta4 V12

Обзор

RobotPowerM5 Meta4 V12 — это порт на C# советника MetaTrader 4 RobotPowerM5_meta4V12.mq4. Изначально робот работал на пятиминутных графиках и сопоставлял показатели индикаторов Bulls Power и Bears Power, чтобы определить, стоит ли открывать лонг или шорт. Реализация на StockSharp сохраняет режим «одна позиция», повторяет настройку стоп-лосса и тейк-профита в "поинтах" MetaTrader, а также восстанавливает логику трейлинг-стопа, который фиксирует прибыль при движении цены в нужную сторону.

Торговая логика

  1. Индикаторы
    • По умолчанию подключаются пятиминутные свечи (тип можно изменить параметром CandleType).
    • Два индикатора StockSharp — BullsPower и BearsPower — обновляются на каждой завершённой свече с заданным периодом.
    • Сумма BullsPower + BearsPower сохраняется с задержкой в одну свечу, чтобы воспроизвести вызовы shift=1 из MQL, где используется только полностью закрытый бар.
  2. Правила входа
    • Когда позиция отсутствует и отложенная сумма Bulls/Bears Power положительна, отправляется рыночная покупка.
    • Когда позиция отсутствует и сумма отрицательна, отправляется рыночная продажа.
    • Пока позиция открыта, новые сигналы игнорируются — управление осуществляется только защитными выходами.
  3. Объём
    • Параметр Volume задаёт запрашиваемый лот. Значение напрямую передаётся в BuyMarket / SellMarket, брокерский коннектор округлит объём с учётом шага лота.

Управление рисками

  • Стоп-лосс — первоначальный стоп отстоит от цены входа на StopLossPoints поинтов MetaTrader. Уровень контролируется минимумом свечи (для лонга) или максимумом (для шорта); при касании стратегия закрывает позицию по рынку.
  • Тейк-профит — цель располагается на расстоянии TakeProfitPoints поинтов. Срабатывание проверяется по экстремумам свечи, что соответствует поведению MT4 при исполнении тейка внутри бара.
  • Трейлинг-стоп — после прохождения ценой более TrailingStopPoints поинтов в прибыльную сторону активируется трейлинг. Для покупок стоп переносится на referencePrice - trailingDistance, где referencePrice — максимум между закрытием и максимумом свечи. Для продаж применяется формула referencePrice + trailingDistance с минимумом между закрытием и минимумом свечи. Таким образом воссоздаётся логика OrderModify из исходного советника.

Параметры

Название Описание Значение по умолчанию Примечания
BullBearPeriod Период усреднения индикаторов Bulls/Bears Power. 5 Увеличение сглаживает моментум-фильтр.
Volume Запрашиваемый объём сделки. 1 Фактический объём определяется шагом и лимитами инструмента.
StopLossPoints Дистанция начального стоп-лосса в поинтах. 45 0 отключает защитный стоп.
TakeProfitPoints Дистанция тейк-профита в поинтах. 150 0 — торговля без фиксированного тейка.
TrailingStopPoints Дистанция трейлинг-стопа. 15 0 отключает трейлинг.
CandleType Тип свечей для расчётов. таймфрейм 5 минут Можно выбрать любой другой DataType.

Особенности реализации

  • Все уровни управления позицией (стоп, тейк, трейлинг) хранятся внутри стратегии. Закрытие выполняется рыночными заявками, когда свечи подтверждают пробой уровня — аналогично поведению MT4.
  • Подписка на индикаторы оформлена через Subscription.Bind, поэтому оба индикатора обрабатываются в одном колбэке.
  • Размер поинта вычисляется из Security.PriceStep, что делает параметры совместимыми с инструментами, котирующимися в тиках, пунктах или копейках.
  • Для исключения ложных входов стратегия использует только значения индикаторов с предыдущей свечи.

Отличия от версии MQL

  • Вместо модификации стоп-заявок используются явные рыночные выходы — это надёжнее для разных коннекторов StockSharp при сохранении логики результата.
  • Параметры проверяются через StrategyParam, что предотвращает ввод некорректных значений (например, отрицательных расстояний).
  • Для визуализации и подписок используются средства высокоуровневого API StockSharp, нет ручного перебора тиков.
  • Строка-идентификатор советника, применявшаяся в MT4, здесь не нужна и опущена.
using System;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// RobotPowerM5: RSI momentum with EMA filter and ATR stops.
/// </summary>
public class RobotPowerM5Meta4V12Strategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _rsiLength;
	private readonly StrategyParam<int> _emaLength;
	private readonly StrategyParam<int> _atrLength;

	private decimal _prevRsi;
	private decimal _entryPrice;
	private int _cooldown;

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

		_rsiLength = Param(nameof(RsiLength), 14)
			.SetDisplay("RSI Length", "RSI period.", "Indicators");

		_emaLength = Param(nameof(EmaLength), 50)
			.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 RsiLength
	{
		get => _rsiLength.Value;
		set => _rsiLength.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();

		_prevRsi = 0;
		_entryPrice = 0;
		_cooldown = 0;
	}

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

		_prevRsi = 0;
		_entryPrice = 0;
		_cooldown = 0;

		var rsi = new RelativeStrengthIndex { Length = RsiLength };
		var ema = new ExponentialMovingAverage { Length = EmaLength };
		var atr = new AverageTrueRange { Length = AtrLength };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(rsi, ema, atr, ProcessCandle)
			.Start();

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

	private void ProcessCandle(ICandleMessage candle, decimal rsiVal, decimal emaVal, decimal atrVal)
	{
		if (candle.State != CandleStates.Finished)
			return;

		if (_prevRsi == 0 || atrVal <= 0)
		{
			_prevRsi = rsiVal;
			return;
		}

		if (_cooldown > 0) { _cooldown--; _prevRsi = rsiVal; return; }

		var close = candle.ClosePrice;

		if (Position > 0)
		{
			if (close >= _entryPrice + atrVal * 2.5m || close <= _entryPrice - atrVal * 1.5m || rsiVal > 80)
			{
				SellMarket();
				_entryPrice = 0;
				_cooldown = 10;
			}
		}
		else if (Position < 0)
		{
			if (close <= _entryPrice - atrVal * 2.5m || close >= _entryPrice + atrVal * 1.5m || rsiVal < 20)
			{
				BuyMarket();
				_entryPrice = 0;
				_cooldown = 10;
			}
		}

		if (Position == 0)
		{
			if (rsiVal > 65 && _prevRsi <= 65 && close > emaVal)
			{
				_entryPrice = close;
				BuyMarket();
				_cooldown = 10;
			}
			else if (rsiVal < 35 && _prevRsi >= 35 && close < emaVal)
			{
				_entryPrice = close;
				SellMarket();
				_cooldown = 10;
			}
		}

		_prevRsi = rsiVal;
	}
}