Porta do consultor especialista MetaTrader "Macd diver rsi mt4" para o StockSharp API de alto nível.
Negocia um único símbolo usando filtros RSI combinados com reconhecimento de divergência MACD para reversões de tempo.
Apenas uma posição de mercado pode ser aberta por vez; a estratégia espera pelo estado plano antes de emitir um novo sinal.
Lógica de Sinais
Cada vela finalizada no período selecionado alimenta quatro indicadores vinculados à estratégia:
Duas instâncias independentes de RelativeStrengthIndex (para filtros de sobrevenda e sobrecompra) amostraram uma barra atrás.
Dois indicadores MovingAverageConvergenceDivergence com EMA rápido/lento configurável e comprimentos de sinal.
Configuração de alta
A barra anterior RSI deve estar abaixo do limite de sobrevenda configurável.
Os valores MACD mais recentes devem formar uma queda local abaixo de um limite dinâmico (equivalente a 3 pips no instrumento atual).
Os dados históricos são verificados para localizar uma queda anterior de MACD e a oscilação de preço associada. A divergência é confirmada quando
o vale MACD sobe enquanto o preço atinge um mínimo mais baixo (divergência regular) ou o vale MACD cai enquanto o preço sobe
baixo (divergência oculta), correspondendo à lógica MQL original.
Quando confirmada e a estratégia não tem posição aberta, uma compra de mercado é enviada com volume específico e configurações de risco.
Configuração de baixa reflete as regras de alta com o filtro de sobrecompra RSI e picos de MACD. A divergência é validada por
comparando os máximos de swing anteriores com os atuais.
Imediatamente após uma entrada, a estratégia converte as distâncias configuradas de stop-loss e take-profit de pips em unidades de preço
(respeitando as regras originais de formato de ponto) e as aplica através de SetStopLoss / SetTakeProfit.
Parâmetros
LowerRsiPeriod, LowerRsiThreshold – mapeia para inp1_Lo_RSIperiod / inp1_Ro_Value.
BearishVolume, BearishStopLossPips, BearishTakeProfitPips – mapear para inp6_VolumeSize, inp6_StopLossPips, inp6_TakeProfitPips.
CandleType – fonte do período para todos os cálculos.
Notas de implementação
O limite de divergência MACD é derivado do tamanho atual do ponto do instrumento e é igual a 3 pips, correspondendo ao padrão 0,0003
usado pela versão MQL.
Candle, MACD e histórico de preços são armazenados em listas limitadas (600 elementos) para reproduzir as janelas de varredura de divergência sem
alocando grandes matrizes.
A estratégia usa SubscribeCandles(...).Bind(...) para atualizar todos os indicadores em uma única passagem e os processos só são finalizados
velas, assim como a execução original do bloco uma vez por barra.
As distâncias pip são convertidas em compensações de preço absoluto antes de chamar SetStopLoss e SetTakeProfit, reproduzindo o
regras de formato de ponto declaradas no topo da fonte MQL.
namespace StockSharp.Samples.Strategies;
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
/// <summary>
/// MACD Divergence RSI strategy: RSI filter + MACD signal line crossover.
/// Buys when RSI below threshold and MACD crosses above signal.
/// Sells when RSI above threshold and MACD crosses below signal.
/// </summary>
public class MacdDivergenceRsiStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _rsiPeriod;
private decimal _prevMacd;
private decimal _prevSignal;
private decimal _prevRsi;
private bool _hasPrev;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int RsiPeriod { get => _rsiPeriod.Value; set => _rsiPeriod.Value = value; }
public MacdDivergenceRsiStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
_rsiPeriod = Param(nameof(RsiPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("RSI Period", "RSI period", "Indicators");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevMacd = 0;
_prevSignal = 0;
_prevRsi = 0;
_hasPrev = false;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_hasPrev = false;
var macd = new MovingAverageConvergenceDivergenceSignal
{
Macd = { ShortMa = { Length = 12 }, LongMa = { Length = 26 } },
SignalMa = { Length = 9 }
};
var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.BindEx(macd, rsi, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue macdValue, IIndicatorValue rsiValue)
{
if (candle.State != CandleStates.Finished) return;
if (!macdValue.IsFinal || !rsiValue.IsFinal) return;
if (macdValue is not MovingAverageConvergenceDivergenceSignalValue typed) return;
if (typed.Macd is not decimal macdMain || typed.Signal is not decimal signal) return;
var rsi = rsiValue.ToDecimal();
if (_hasPrev)
{
if (_prevMacd <= _prevSignal && macdMain > signal && rsi < 40 && Position <= 0)
BuyMarket();
else if (_prevMacd >= _prevSignal && macdMain < signal && rsi > 60 && Position >= 0)
SellMarket();
}
_prevMacd = macdMain;
_prevSignal = signal;
_prevRsi = rsi;
_hasPrev = 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 MovingAverageConvergenceDivergenceSignal, RelativeStrengthIndex
from StockSharp.Algo.Strategies import Strategy
class macd_divergence_rsi_strategy(Strategy):
def __init__(self):
super(macd_divergence_rsi_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5)))
self._rsi_period = self.Param("RsiPeriod", 14)
self._prev_macd = 0.0
self._prev_signal = 0.0
self._prev_rsi = 0.0
self._has_prev = False
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def RsiPeriod(self):
return self._rsi_period.Value
@RsiPeriod.setter
def RsiPeriod(self, value):
self._rsi_period.Value = value
def OnReseted(self):
super(macd_divergence_rsi_strategy, self).OnReseted()
self._prev_macd = 0.0
self._prev_signal = 0.0
self._prev_rsi = 0.0
self._has_prev = False
def OnStarted2(self, time):
super(macd_divergence_rsi_strategy, self).OnStarted2(time)
self._has_prev = False
macd = MovingAverageConvergenceDivergenceSignal()
macd.Macd.ShortMa.Length = 12
macd.Macd.LongMa.Length = 26
macd.SignalMa.Length = 9
rsi = RelativeStrengthIndex()
rsi.Length = self.RsiPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.BindEx(macd, rsi, self._process_candle).Start()
def _process_candle(self, candle, macd_value, rsi_value):
if candle.State != CandleStates.Finished:
return
if not macd_value.IsFinal or not rsi_value.IsFinal:
return
if macd_value.Macd is None or macd_value.Signal is None:
return
macd_main = float(macd_value.Macd)
signal = float(macd_value.Signal)
rsi_val = float(rsi_value)
if self._has_prev:
if self._prev_macd <= self._prev_signal and macd_main > signal and rsi_val < 40 and self.Position <= 0:
self.BuyMarket()
elif self._prev_macd >= self._prev_signal and macd_main < signal and rsi_val > 60 and self.Position >= 0:
self.SellMarket()
self._prev_macd = macd_main
self._prev_signal = signal
self._prev_rsi = rsi_val
self._has_prev = True
def CreateClone(self):
return macd_divergence_rsi_strategy()