Easy Robot — это импульсная стратегия, которая анализирует каждую завершённую часовую свечу. Если предыдущая свеча закрылась ростом, стратегия открывает длинную позицию; если падением — короткую. В любой момент времени разрешена только одна позиция, что полностью повторяет работу исходного советника для MetaTrader 4.
Правила торговли
Выполняется подписка на свечи таймфрейма, заданного параметром CandleType (по умолчанию H1).
После закрытия свечи сравниваются цена открытия и закрытия:
Close > Open — при отсутствии позиции совершается рыночная покупка.
Close < Open — при нулевой позиции отправляется рыночная продажа.
Объём сделки берётся из свойства Volume, аналогично функции CheckVolumeValue в MQL, где минимальный лот равен 0.01.
Стоп-лосс и тейк-профит рассчитываются по индикатору ATR с периодом AtrPeriod (по умолчанию 14):
Стоп-лосс = ATR * StopFactor.
Тейк-профит = ATR * TakeFactor.
Полученные расстояния нормализуются с учётом минимального шага цены, чтобы защитные приказы не располагались слишком близко к рынку.
Сразу после рыночной сделки вызываются SetStopLoss и SetTakeProfit, что соответствует заполнению полей sl и tp при OrderSend.
Если UseTrailingStop включён, то после достижения прибыли в TrailingStartPips (MetaTrader-пунктах) стоп переносится на TrailingStepPips пунктов ближе к цене и далее сопровождает позицию, соблюдая минимально допустимое расстояние брокера.
Для расчётов используются лучшие котировки 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;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import ExponentialMovingAverage, RelativeStrengthIndex
from StockSharp.Algo.Strategies import Strategy
class easy_robot_strategy(Strategy):
def __init__(self):
super(easy_robot_strategy, self).__init__()
self._ema_period = self.Param("EmaPeriod", 50) \
.SetDisplay("EMA Period", "EMA period", "Indicators")
self._rsi_period = self.Param("RsiPeriod", 14) \
.SetDisplay("RSI Period", "RSI period", "Indicators")
self._ema = None
self._rsi = None
self._was_bullish = False
self._has_prev_signal = False
@property
def ema_period(self):
return self._ema_period.Value
@property
def rsi_period(self):
return self._rsi_period.Value
def OnReseted(self):
super(easy_robot_strategy, self).OnReseted()
self._ema = None
self._rsi = None
self._was_bullish = False
self._has_prev_signal = False
def OnStarted2(self, time):
super(easy_robot_strategy, self).OnStarted2(time)
self._ema = ExponentialMovingAverage()
self._ema.Length = self.ema_period
self._rsi = RelativeStrengthIndex()
self._rsi.Length = self.rsi_period
self._has_prev_signal = False
subscription = self.SubscribeCandles(DataType.TimeFrame(TimeSpan.FromMinutes(30)))
subscription.Bind(self._ema, self._rsi, self._process_candle)
subscription.Start()
def _process_candle(self, candle, ema_value, rsi_value):
if candle.State != CandleStates.Finished:
return
if not self._ema.IsFormed or not self._rsi.IsFormed:
return
close = float(candle.ClosePrice)
ema_val = float(ema_value)
rsi_val = float(rsi_value)
is_bullish = close > ema_val and rsi_val > 50.0
if self._has_prev_signal and is_bullish != self._was_bullish:
if is_bullish and self.Position <= 0:
self.BuyMarket()
elif not is_bullish and close < ema_val and rsi_val < 50.0 and self.Position >= 0:
self.SellMarket()
self._was_bullish = is_bullish
self._has_prev_signal = True
def CreateClone(self):
return easy_robot_strategy()