A Estratégia MA RSI EA reproduz a lógica do assessor especializado original do MetaTrader que combina uma média móvel rápida com um filtro RSI de período curto. A estratégia opera na série de velas selecionada, avalia novas ordens apenas em barras terminadas e usa dimensionamento de posição dinâmico baseado no saldo ou patrimônio da conta. Quando o lucro flutuante de todas as posições abertas se torna positivo, cada posição é fechada imediatamente para assegurar o ganho.
Indicadores
Moving Average – método configurável (simples, exponencial, suavizado, ponderado linearmente) com seleção de fonte de preço e deslocamento opcional.
Relative Strength Index (RSI) – oscilador de curto prazo que lê da mesma família de preços de velas da versão MQL.
Lógica de trading
Para cada vela concluída, a estratégia calcula os valores de média móvel e RSI usando as fontes de preço configuradas.
O valor de média móvel mais recente pode ser deslocado por um número de barras definido pelo usuário para corresponder ao comportamento MQL.
Ela avalia o PnL flutuante da posição líquida atual:
Se o resultado flutuante de todas as posições abertas for maior que zero, a estratégia fecha a posição inteira para realizar o lucro.
Se o resultado flutuante for negativo, o lado com a menor perda (lado comprador vs. lado vendedor) é reforçado abrindo uma operação adicional nessa direção.
Se não houver sinal de média, o filtro RSI + MA é aplicado:
Entrada vendido – RSI ≥ RsiOverbought e o preço de abertura da vela está abaixo da média móvel deslocada.
Entrada comprado – RSI ≤ RsiOversold e o preço de abertura da vela está acima da média móvel deslocada.
Lógica de saída
PnL flutuante positivo aciona CloseAllPositions, zerando a estratégia imediatamente.
Sinais de reversão manual da lógica de média fecham a exposição oposta porque o StockSharp trabalha com posições líquidas.
Dimensionamento de posição
LotSizingModes espelha a seleção OptLot do EA:
Fixed – sempre envia volume LotSize.
Balance – converte PercentOfBalance do valor da carteira em volume usando o preço de fechamento da vela.
Equity – converte PercentOfEquity do patrimônio atual da carteira em volume.
O volume calculado é arredondado para o Security.VolumeStep mais próximo (quando disponível) para que as ordens cumpram com o tamanho de lote do instrumento.
Parâmetros
Parâmetro
Descrição
Padrão
LotOption
Modo de cálculo de volume (Fixed, Balance, Equity).
Balance
LotSize
Valor de lote fixo para o modo Fixed.
0.01
PercentOfBalance
Porcentagem do saldo usada no modo Balance.
2
PercentOfEquity
Porcentagem do patrimônio usada no modo Equity.
3
FastMaPeriod
Comprimento da média móvel.
4
FastMaShift
Deslocamento aplicado ao resultado da média móvel.
0
FastMaMethod
Método de cálculo da média móvel (Simple, Exponential, Smoothed, LinearWeighted).
LinearWeighted
FastMaPrice
Fonte de preço de vela para a média móvel.
Open
RsiPeriod
Comprimento do RSI.
4
RsiPrice
Fonte de preço de vela para o RSI.
Open
RsiOverbought
Nível RSI que define um mercado sobrecomprado.
80
RsiOversold
Nível RSI que define um mercado sobrevendido.
20
CandleType
Série de velas usada pela estratégia.
Período de 15 minutos
Fontes de preço de vela
CandlePriceSources replica a lista de preços aplicados MQL:
Open, High, Low, Close
Median = (High + Low) / 2
Typical = (High + Low + Close) / 3
Weighted = (High + Low + Close + Close) / 4
Notas
As ordens são geradas apenas quando a estratégia está online e a vela terminou, correspondendo ao EA original que aciona em novas barras.
Como o StockSharp mantém uma posição líquida, os sinais de média automaticamente reduzem ou invertem a exposição atual em vez de criar posições de hedge.
A implementação em Python é intencionalmente omitida conforme solicitado.
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>
/// MA + RSI strategy. Uses EMA trend direction with RSI momentum confirmation.
/// </summary>
public class MaRsiEaStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _maPeriod;
private readonly StrategyParam<int> _rsiPeriod;
private readonly StrategyParam<decimal> _rsiOverbought;
private readonly StrategyParam<decimal> _rsiOversold;
private decimal? _prevRsi;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int MaPeriod
{
get => _maPeriod.Value;
set => _maPeriod.Value = value;
}
public int RsiPeriod
{
get => _rsiPeriod.Value;
set => _rsiPeriod.Value = value;
}
public decimal RsiOverbought
{
get => _rsiOverbought.Value;
set => _rsiOverbought.Value = value;
}
public decimal RsiOversold
{
get => _rsiOversold.Value;
set => _rsiOversold.Value = value;
}
public MaRsiEaStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Timeframe", "General");
_maPeriod = Param(nameof(MaPeriod), 20)
.SetGreaterThanZero()
.SetDisplay("MA Period", "EMA period for trend", "Indicators");
_rsiPeriod = Param(nameof(RsiPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("RSI Period", "RSI calculation period", "Indicators");
_rsiOverbought = Param(nameof(RsiOverbought), 65m)
.SetDisplay("Overbought", "RSI overbought level", "Levels");
_rsiOversold = Param(nameof(RsiOversold), 35m)
.SetDisplay("Oversold", "RSI oversold level", "Levels");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevRsi = null;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevRsi = null;
var ema = new ExponentialMovingAverage { Length = MaPeriod };
var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(ema, rsi, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, ema);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal emaValue, decimal rsiValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
{
_prevRsi = rsiValue;
return;
}
var close = candle.ClosePrice;
if (_prevRsi == null)
{
_prevRsi = rsiValue;
return;
}
// Buy: price above EMA and RSI crosses above oversold
if (close > emaValue && _prevRsi.Value <= RsiOversold && rsiValue > RsiOversold && Position <= 0)
{
if (Position < 0)
BuyMarket();
BuyMarket();
}
// Sell: price below EMA and RSI crosses below overbought
else if (close < emaValue && _prevRsi.Value >= RsiOverbought && rsiValue < RsiOverbought && Position >= 0)
{
if (Position > 0)
SellMarket();
SellMarket();
}
_prevRsi = rsiValue;
}
}
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 ma_rsi_ea_strategy(Strategy):
def __init__(self):
super(ma_rsi_ea_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))) \
.SetDisplay("Candle Type", "Timeframe", "General")
self._ma_period = self.Param("MaPeriod", 20) \
.SetDisplay("MA Period", "EMA period for trend", "Indicators")
self._rsi_period = self.Param("RsiPeriod", 14) \
.SetDisplay("RSI Period", "RSI calculation period", "Indicators")
self._rsi_overbought = self.Param("RsiOverbought", 65.0) \
.SetDisplay("Overbought", "RSI overbought level", "Levels")
self._rsi_oversold = self.Param("RsiOversold", 35.0) \
.SetDisplay("Oversold", "RSI oversold level", "Levels")
self._prev_rsi = None
@property
def CandleType(self):
return self._candle_type.Value
@property
def MaPeriod(self):
return self._ma_period.Value
@property
def RsiPeriod(self):
return self._rsi_period.Value
@property
def RsiOverbought(self):
return self._rsi_overbought.Value
@property
def RsiOversold(self):
return self._rsi_oversold.Value
def OnReseted(self):
super(ma_rsi_ea_strategy, self).OnReseted()
self._prev_rsi = None
def OnStarted2(self, time):
super(ma_rsi_ea_strategy, self).OnStarted2(time)
self._prev_rsi = None
ema = ExponentialMovingAverage()
ema.Length = self.MaPeriod
rsi = RelativeStrengthIndex()
rsi.Length = self.RsiPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(ema, rsi, self._on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, ema)
self.DrawOwnTrades(area)
def _on_process(self, candle, ema_value, rsi_value):
if candle.State != CandleStates.Finished:
return
rv = float(rsi_value)
if not self.IsFormedAndOnlineAndAllowTrading():
self._prev_rsi = rv
return
close = float(candle.ClosePrice)
ev = float(ema_value)
if self._prev_rsi is None:
self._prev_rsi = rv
return
ob = float(self.RsiOverbought)
os_level = float(self.RsiOversold)
# Buy: price above EMA and RSI crosses above oversold
if close > ev and self._prev_rsi <= os_level and rv > os_level and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
# Sell: price below EMA and RSI crosses below overbought
elif close < ev and self._prev_rsi >= ob and rv < ob and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._prev_rsi = rv
def CreateClone(self):
return ma_rsi_ea_strategy()