Открыть на GitHub

Стратегия Easy Robot

Описание

Easy Robot — это импульсная стратегия, которая анализирует каждую завершённую часовую свечу. Если предыдущая свеча закрылась ростом, стратегия открывает длинную позицию; если падением — короткую. В любой момент времени разрешена только одна позиция, что полностью повторяет работу исходного советника для MetaTrader 4.

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

  1. Выполняется подписка на свечи таймфрейма, заданного параметром CandleType (по умолчанию H1).
  2. После закрытия свечи сравниваются цена открытия и закрытия:
    • Close > Open — при отсутствии позиции совершается рыночная покупка.
    • Close < Open — при нулевой позиции отправляется рыночная продажа.
  3. Объём сделки берётся из свойства Volume, аналогично функции CheckVolumeValue в MQL, где минимальный лот равен 0.01.
  4. Стоп-лосс и тейк-профит рассчитываются по индикатору ATR с периодом AtrPeriod (по умолчанию 14):
    • Стоп-лосс = ATR * StopFactor.
    • Тейк-профит = ATR * TakeFactor.
    • Полученные расстояния нормализуются с учётом минимального шага цены, чтобы защитные приказы не располагались слишком близко к рынку.
  5. Сразу после рыночной сделки вызываются SetStopLoss и SetTakeProfit, что соответствует заполнению полей sl и tp при OrderSend.
  6. Если UseTrailingStop включён, то после достижения прибыли в TrailingStartPips (MetaTrader-пунктах) стоп переносится на TrailingStepPips пунктов ближе к цене и далее сопровождает позицию, соблюдая минимально допустимое расстояние брокера.
  7. Для расчётов используются лучшие котировки bid/ask, при их отсутствии — последняя цена сделки либо цена закрытия свечи, как в оригинальном коде.

Параметры

Имя Значение по умолчанию Описание
TakeFactor 4.2 Множитель ATR для тейк-профита (соответствует входному параметру TakeFactor).
StopFactor 4.9 Множитель ATR для стоп-лосса (StopFactor).
UseTrailingStop true Включает трейлинг-стоп (UseTstop).
TrailingStartPips 40 Прибыль в пунктах, необходимая для запуска трейлинга (Tstart).
TrailingStepPips 19 Шаг перемещения трейлинг-стопа в пунктах (Tstep).
AtrPeriod 14 Период ATR.
CandleType H1 Таймфрейм, используемый для сигналов и расчёта ATR.

Дополнительные детали

  • После закрытия позиции внутренние переменные с ценой входа и уровнем стопа сбрасываются, что предотвращает повторное использование старых значений.
  • Минимальное допустимое расстояние до защитных приказов оценивается по размеру пункта (или шагу цены), аналогично функции SC в подключаемом MQL-файле.
  • В методе OnStarted вызывается StartProtection(), позволяя платформе активировать встроенные защитные механизмы при необходимости.
namespace StockSharp.Samples.Strategies;

using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;

/// <summary>
/// Easy Robot strategy: simple EMA + RSI trend following.
/// Buys when close above EMA and RSI above 50.
/// Sells when close below EMA and RSI below 50.
/// </summary>
public class EasyRobotStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _emaPeriod;
	private readonly StrategyParam<int> _rsiPeriod;
	private bool _wasBullish;
	private bool _hasPrevSignal;

	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
	public int EmaPeriod { get => _emaPeriod.Value; set => _emaPeriod.Value = value; }
	public int RsiPeriod { get => _rsiPeriod.Value; set => _rsiPeriod.Value = value; }

	public EasyRobotStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
			.SetDisplay("Candle Type", "Candle timeframe", "General");
		_emaPeriod = Param(nameof(EmaPeriod), 50)
			.SetGreaterThanZero()
			.SetDisplay("EMA Period", "EMA period", "Indicators");
		_rsiPeriod = Param(nameof(RsiPeriod), 14)
			.SetGreaterThanZero()
			.SetDisplay("RSI Period", "RSI period", "Indicators");
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_wasBullish = false;
		_hasPrevSignal = false;
	}

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_hasPrevSignal = false;
		var ema = new ExponentialMovingAverage { Length = EmaPeriod };
		var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(ema, rsi, ProcessCandle).Start();
	}

	private void ProcessCandle(ICandleMessage candle, decimal ema, decimal rsi)
	{
		if (candle.State != CandleStates.Finished) return;
		var close = candle.ClosePrice;
		var isBullish = close > ema && rsi > 50;

		if (_hasPrevSignal && isBullish != _wasBullish)
		{
			if (isBullish && Position <= 0)
				BuyMarket();
			else if (!isBullish && close < ema && rsi < 50 && Position >= 0)
				SellMarket();
		}

		_wasBullish = isBullish;
		_hasPrevSignal = true;
	}
}