Convertido do consultor especialista MetaTrader 4 "Mais fácil RSI" localizado em MQL/9827/Easiest_RSI.mq4.
Visão geral
O EA original abre negociações quando o Índice de Força Relativa (RSI) sai das zonas de sobrevenda/sobrecompra e, opcionalmente, adiciona duas posições extras na mesma direção enquanto o preço continua se movendo favoravelmente. Cada ordem usa o mesmo volume, um stop loss fixo e um trailing stop que avança em pequenos passos quando a negociação atinge grandes lucros.
Esta porta StockSharp mantém o comportamento no nível da estratégia:
RSI(14) calculado na série de velas configurada aciona os sinais.
As negociações longas são acionadas quando RSI ultrapassa o limite de sobrevenda; as posições vendidas aparecem em cruzamentos descendentes através do limite de sobrecompra.
A escala de posição imita a lógica de média MT4 adicionando um novo pedido sempre que o preço avança em StepPips, limitado por MaxEntries.
Os stops iniciais e finais são gerenciados internamente com distâncias de preços medidas em pips (ajustadas automaticamente para cotações de câmbio de 4/5 dígitos).
Todo o estado (histórico RSI, preços da última entrada, trailing stops) é armazenado em campos primitivos para seguir as diretrizes da estrutura.
Parâmetros
Nome
Padrão
Descrição
LotSize
1
Volume de cada ordem de mercado.
StopLossPips
50
Parada protetora inicial em pips (definida como zero para desabilitar).
TrailingStopPips
50
Distância do trailing-stop em pips; zero desativa o rastreamento.
StepPips
20
Movimento favorável mínimo antes de uma posição adicional ser adicionada.
RsiPeriod
14
RSI comprimento.
OversoldLevel
30
Nível RSI que deve ser cruzado para cima para acionar entradas longas.
OverboughtLevel
70
Nível RSI que deve ser cruzado para baixo para acionar entradas curtas.
MaxEntries
3
Número máximo de entradas sequenciais por direção (correspondendo ao limite MT4).
CandleType
TimeFrame(5m)
Tipo de vela/período usado para calcular RSI.
Todas as distâncias expressas em pips são convertidas em preços absolutos usando o valor do instrumento Step. Para símbolos FX de 5 dígitos, o auxiliar dobra a etapa para que entradas como 50 sejam iguais a 5,0 pips, refletindo a orientação original EA.
Lógica de negociação
Detecção de sinal – A estratégia observa apenas velas acabadas. Ele armazena as duas últimas leituras RSI para replicar as chamadas MT4 iRSI(..., 1) e iRSI(..., 2). Atravessa o fogo OversoldLevel ou OverboughtLevel assim que a nova vela fecha.
Entradas primárias – Quando ocorre uma linha plana e de alta, uma ordem de compra ao mercado é enviada; cruzes de baixa quando planas acionam uma ordem de venda.
Scaling in – Enquanto uma posição está aberta, a estratégia compara o último fechamento/máximo (longo) ou fechamento/mínimo (curto) com o preço do preenchimento mais recente. Cada vez que o preço se move pelo menos StepPips a favor, uma nova ordem com tamanho LotSize é enviada, até MaxEntries posições totais nessa direção.
Stop-loss – Em cada preenchimento, um stop inicial é recalculado como o preço da posição menos/mais StopLossPips. A parada agregada mantém a distância mais distante (mais conservadora) para que toda a posição permaneça protegida.
Trailing – Depois que a negociação progride, o stop é avançado para mais perto usando a máxima da vela (longas) ou a mínima (vendidas). Um pequeno buffer equivalente a cinco etapas de preço mínimo emula o requisito MT4 OrderStopLoss() + 5*Point antes que o stop seja movido.
Saída – Quando o preço atinge o nível de stop gerenciado, a posição é fechada no mercado. Nenhuma meta de lucro é usada além do trailing stop.
Notas de implementação
Os pedidos são enviados por meio do pipeline SubscribeCandles().Bind(...) de alto nível e auxiliares de pedidos de mercado (BuyMarket / SellMarket).
A estratégia mantém _longOrderPending / _shortOrderPending e sinalizadores de saída para evitar inundar a exchange com solicitações duplicadas enquanto uma ordem de mercado aguarda confirmação.
StartProtection não é invocado porque toda a lógica de proteção é codificada explicitamente para corresponder ao comportamento do MT4.
Como StockSharp funciona com posições líquidas, o trailing stop é aplicado à exposição agregada. Isso significa que quando múltiplas entradas estão abertas, todos os lotes saem juntos assim que o stop combinado é tocado. O EA original moveu o stop de cada pedido individualmente; a abordagem agregada mantém o controlo do risco, mas pode fechar o cabaz um pouco mais cedo. A diferença está documentada para fins de transparência.
Dicas de uso
Atribua a segurança e o conector desejados e defina CandleType para corresponder ao período de tempo que você deseja negociar (por exemplo, velas EURUSD de 5 minutos, como nos comentários da fonte).
Ajuste os parâmetros baseados em pip de acordo com a volatilidade do instrumento. Lembre-se de multiplicar os padrões por 10 se preferir trabalhar em pontos brutos para cotações de 5 dígitos, refletindo a orientação do MT4.
Opcional: ajuste MaxEntries e StepPips para gerenciar a agressividade da estratégia em negociações vencedoras.
Execute primeiro a estratégia na negociação de papel para validar as conversões de pip e o comportamento de rastreamento nos símbolos do seu corretor.
Arquivos
CS/EasiestRsiStrategy.cs – Implementação da estratégia.
README.md – Este documento.
README_zh.md – tradução chinesa.
README_ru.md – Tradução russa.
A implementação do Python é omitida intencionalmente conforme solicitado.
using System;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Easiest RSI: RSI reversal with EMA filter and ATR stops.
/// </summary>
public class EasiestRsiStrategy : 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;
public EasiestRsiStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(8).TimeFrame())
.SetDisplay("Candle Type", "Timeframe.", "General");
_rsiLength = Param(nameof(RsiLength), 14)
.SetDisplay("RSI Length", "RSI period.", "Indicators");
_emaLength = Param(nameof(EmaLength), 20)
.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;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevRsi = 0; _entryPrice = 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; }
var close = candle.ClosePrice;
if (Position > 0)
{
if (close >= _entryPrice + atrVal * 2.5m || close <= _entryPrice - atrVal * 1.5m || rsiVal > 70) { SellMarket(); _entryPrice = 0; }
}
else if (Position < 0)
{
if (close <= _entryPrice - atrVal * 2.5m || close >= _entryPrice + atrVal * 1.5m || rsiVal < 30) { BuyMarket(); _entryPrice = 0; }
}
if (Position == 0)
{
if (rsiVal > 55 && _prevRsi <= 55 && close > emaVal) { _entryPrice = close; BuyMarket(); }
else if (rsiVal < 45 && _prevRsi >= 45 && close < emaVal) { _entryPrice = close; SellMarket(); }
}
_prevRsi = rsiVal;
}
}
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.Strategies import Strategy
from StockSharp.Algo.Indicators import RelativeStrengthIndex, ExponentialMovingAverage, AverageTrueRange
class easiest_rsi_strategy(Strategy):
def __init__(self):
super(easiest_rsi_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(8))) \
.SetDisplay("Candle Type", "Timeframe.", "General")
self._rsi_length = self.Param("RsiLength", 14) \
.SetDisplay("RSI Length", "RSI period.", "Indicators")
self._ema_length = self.Param("EmaLength", 20) \
.SetDisplay("EMA Length", "Trend filter.", "Indicators")
self._atr_length = self.Param("AtrLength", 14) \
.SetDisplay("ATR Length", "ATR period.", "Indicators")
self._prev_rsi = 0.0
self._entry_price = 0.0
@property
def CandleType(self):
return self._candle_type.Value
@property
def RsiLength(self):
return self._rsi_length.Value
@property
def EmaLength(self):
return self._ema_length.Value
@property
def AtrLength(self):
return self._atr_length.Value
def OnStarted2(self, time):
super(easiest_rsi_strategy, self).OnStarted2(time)
self._prev_rsi = 0.0
self._entry_price = 0.0
self._rsi = RelativeStrengthIndex()
self._rsi.Length = self.RsiLength
self._ema = ExponentialMovingAverage()
self._ema.Length = self.EmaLength
self._atr = AverageTrueRange()
self._atr.Length = self.AtrLength
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(self._rsi, self._ema, self._atr, self.ProcessCandle).Start()
def ProcessCandle(self, candle, rsi_val, ema_val, atr_val):
if candle.State != CandleStates.Finished:
return
rv = float(rsi_val)
ev = float(ema_val)
av = float(atr_val)
if self._prev_rsi == 0 or av <= 0:
self._prev_rsi = rv
return
close = float(candle.ClosePrice)
if self.Position > 0:
if close >= self._entry_price + av * 2.5 or close <= self._entry_price - av * 1.5 or rv > 70:
self.SellMarket()
self._entry_price = 0.0
elif self.Position < 0:
if close <= self._entry_price - av * 2.5 or close >= self._entry_price + av * 1.5 or rv < 30:
self.BuyMarket()
self._entry_price = 0.0
if not self.IsFormedAndOnlineAndAllowTrading():
self._prev_rsi = rv
return
if self.Position == 0:
if rv > 55 and self._prev_rsi <= 55 and close > ev:
self._entry_price = close
self.BuyMarket()
elif rv < 45 and self._prev_rsi >= 45 and close < ev:
self._entry_price = close
self.SellMarket()
self._prev_rsi = rv
def OnReseted(self):
super(easiest_rsi_strategy, self).OnReseted()
self._prev_rsi = 0.0
self._entry_price = 0.0
def CreateClone(self):
return easiest_rsi_strategy()