Esta estratégia replica o especialista MetaTrader "Expert_ABE_BE_MFI" combinando padrões de engolfo de velas japonesas com a confirmação do oscilador Money Flow Index (MFI). Uma posição longa é aberta quando uma vela envolvente de alta aparece enquanto o fluxo de dinheiro permanece em uma zona de sobrevenda. Uma posição curta é aberta quando uma vela de baixa se forma sob condições de fluxo de dinheiro sobrecomprado. As posições são fechadas quando a IMF ultrapassa os limites de saída dinâmicos, sinalizando reversões de impulso.
Ideia Central
Pattern detection – the body of the current finished candle must fully engulf the previous candle in the direction of the trade.
Confirmação de volume – o indicador MFI (comprimento configurável, padrão 37) deve estar abaixo do nível de sobrevenda (40) para entradas longas ou acima do nível de sobrecompra (60) para entradas curtas.
Saídas dinâmicas – as posições abertas são fechadas quando a IMF cruza os principais níveis de reversão (30 e 70) na direção oposta, imitando a lógica de votação original do especialista MQL.
Indicadores
Índice de fluxo de dinheiro (MFI) – calcula o momentum ajustado pelo volume. A estratégia armazena as duas últimas leituras da MFI para detectar passagens de nível.
Análise Corporal de Vela – nenhum indicador adicional é registrado; a detecção de engolfamento usa as duas últimas velas concluídas.
Regras de negociação
Entrada longa
A vela anterior é de baixa e a vela atual é de alta.
O corpo da vela atual abre abaixo ou igual ao fechamento anterior e fecha acima ou igual à abertura anterior (engolfo estrito).
Latest MFI value is below the configurable OversoldLevel (default 40).
Entrada curta
A vela anterior é de alta e a vela atual é de baixa.
Current candle body opens above or equal to the previous close and closes below or equal to the previous open.
O valor MFI mais recente está acima do configurável OverboughtLevel (padrão 60).
Condições de saída
Fechar Short quando a IMF cruza acima de ExitLongLevel (30) ou ExitShortLevel (70) de baixo.
Fechar Long quando a IMF cruza abaixo de ExitShortLevel (70) ou ExitLongLevel (30) de cima.
Estes limiares de saída recriam a lógica de voto duplo do perito original, garantindo que movimentos prolongados no fluxo de dinheiro desencadeiam a liquidação atempada de posições.
Gestão Comercial
As ordens de mercado (BuyMarket / SellMarket) são utilizadas para entradas e saídas.
No explicit stop-loss or take-profit is used; a gestão do risco depende dos sinais de reversão das IMFs.
Parâmetros
Nome
Descrição
Padrão
Faixa/Notas
CandleType
Candle timeframe used for analysis.
1 minuto
Qualquer tipo de vela compatível.
MfiPeriod
Length of the Money Flow Index.
37
Deve ser > 0; matches original EA default.
OversoldLevel
Nível de IMF que confirma configurações de alta envolvente.
40
Ative a otimização, se necessário.
OverboughtLevel
Nível de MFI que confirma configurações de baixa.
60
Enable optimization if needed.
ExitLongLevel
Lower MFI boundary for detecting reversals.
30
Usado para saídas longas e confirmações curtas.
ExitShortLevel
Upper MFI boundary for detecting reversals.
70
Used for both short exits and long confirmations.
Notas sobre conversão
O especialista original MQL agregou “votos” de padrões envolventes e filtros MFI. A estratégia C# reproduz o mesmo fluxo de decisão convertendo diretamente as regras de votação em condições discretas de entrada e saída.
Money management and trailing modules from the MQL version are omitted; O dimensionamento da posição StockSharp é controlado pelo volume da estratégia.
Todas as vinculações de indicadores aproveitam o API (SubscribeCandles().Bind(...)) de alto nível conforme necessário.
Dicas de uso
Otimize MfiPeriod, OversoldLevel e OverboughtLevel para adaptar a estratégia a mercados específicos.
Combine com controles de risco (paradas de proteção) via StartProtection no aplicativo host se segurança adicional for necessária.
Garanta dados históricos suficientes para que o Índice de Fluxo de Dinheiro esteja totalmente formado antes de permitir a negociação.
namespace StockSharp.Samples.Strategies;
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
/// <summary>
/// Engulfing MFI Confirmation strategy: Engulfing pattern with MFI filter.
/// Bullish engulfing + oversold MFI for long, bearish engulfing + overbought MFI for short.
/// </summary>
public class EngulfingMfiConfirmationStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _mfiPeriod;
private readonly StrategyParam<decimal> _oversold;
private readonly StrategyParam<decimal> _overbought;
private readonly StrategyParam<int> _signalCooldownCandles;
private readonly List<ICandleMessage> _candles = new();
private decimal _prevMfi;
private bool _hasPrevMfi;
private int _candlesSinceTrade;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int MfiPeriod { get => _mfiPeriod.Value; set => _mfiPeriod.Value = value; }
public decimal Oversold { get => _oversold.Value; set => _oversold.Value = value; }
public decimal Overbought { get => _overbought.Value; set => _overbought.Value = value; }
public int SignalCooldownCandles { get => _signalCooldownCandles.Value; set => _signalCooldownCandles.Value = value; }
public EngulfingMfiConfirmationStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
_mfiPeriod = Param(nameof(MfiPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("MFI Period", "Money Flow Index period", "Indicators");
_oversold = Param(nameof(Oversold), 30m)
.SetDisplay("Oversold", "MFI oversold level", "Signals");
_overbought = Param(nameof(Overbought), 70m)
.SetDisplay("Overbought", "MFI overbought level", "Signals");
_signalCooldownCandles = Param(nameof(SignalCooldownCandles), 6)
.SetGreaterThanZero()
.SetDisplay("Signal Cooldown", "Bars to wait between trades", "Trading");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_candles.Clear();
_prevMfi = 0m;
_hasPrevMfi = false;
_candlesSinceTrade = SignalCooldownCandles;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_candles.Clear();
_hasPrevMfi = false;
_candlesSinceTrade = SignalCooldownCandles;
var mfi = new MoneyFlowIndex { Length = MfiPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(mfi, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, decimal mfiValue)
{
if (candle.State != CandleStates.Finished) return;
if (_candlesSinceTrade < SignalCooldownCandles)
_candlesSinceTrade++;
_candles.Add(candle);
if (_candles.Count > 5)
_candles.RemoveAt(0);
if (_candles.Count >= 2)
{
var curr = _candles[^1];
var prev = _candles[^2];
if (curr is null || prev is null)
return;
var bullishEngulfing = prev.OpenPrice > prev.ClosePrice
&& curr.ClosePrice > curr.OpenPrice
&& curr.OpenPrice <= prev.ClosePrice
&& curr.ClosePrice >= prev.OpenPrice;
var bearishEngulfing = prev.ClosePrice > prev.OpenPrice
&& curr.OpenPrice > curr.ClosePrice
&& curr.OpenPrice >= prev.ClosePrice
&& curr.ClosePrice <= prev.OpenPrice;
if (bullishEngulfing && mfiValue < Oversold && Position <= 0 && _candlesSinceTrade >= SignalCooldownCandles)
{
BuyMarket();
_candlesSinceTrade = 0;
}
else if (bearishEngulfing && mfiValue > Overbought && Position >= 0 && _candlesSinceTrade >= SignalCooldownCandles)
{
SellMarket();
_candlesSinceTrade = 0;
}
}
// Exit on MFI crossing
if (_hasPrevMfi)
{
if (Position > 0 && _prevMfi >= Overbought && mfiValue < Overbought && _candlesSinceTrade >= SignalCooldownCandles)
{
SellMarket();
_candlesSinceTrade = 0;
}
else if (Position < 0 && _prevMfi <= Oversold && mfiValue > Oversold && _candlesSinceTrade >= SignalCooldownCandles)
{
BuyMarket();
_candlesSinceTrade = 0;
}
}
_prevMfi = mfiValue;
_hasPrevMfi = 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 MoneyFlowIndex
from StockSharp.Algo.Strategies import Strategy
class engulfing_mfi_confirmation_strategy(Strategy):
def __init__(self):
super(engulfing_mfi_confirmation_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(30)))
self._mfi_period = self.Param("MfiPeriod", 14)
self._oversold = self.Param("Oversold", 30.0)
self._overbought = self.Param("Overbought", 70.0)
self._signal_cooldown_candles = self.Param("SignalCooldownCandles", 6)
self._candles = []
self._prev_mfi = 0.0
self._has_prev_mfi = False
self._candles_since_trade = 6
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def MfiPeriod(self):
return self._mfi_period.Value
@MfiPeriod.setter
def MfiPeriod(self, value):
self._mfi_period.Value = value
@property
def Oversold(self):
return self._oversold.Value
@Oversold.setter
def Oversold(self, value):
self._oversold.Value = value
@property
def Overbought(self):
return self._overbought.Value
@Overbought.setter
def Overbought(self, value):
self._overbought.Value = value
@property
def SignalCooldownCandles(self):
return self._signal_cooldown_candles.Value
@SignalCooldownCandles.setter
def SignalCooldownCandles(self, value):
self._signal_cooldown_candles.Value = value
def OnReseted(self):
super(engulfing_mfi_confirmation_strategy, self).OnReseted()
self._candles.clear()
self._prev_mfi = 0.0
self._has_prev_mfi = False
self._candles_since_trade = self.SignalCooldownCandles
def OnStarted2(self, time):
super(engulfing_mfi_confirmation_strategy, self).OnStarted2(time)
self._candles.clear()
self._has_prev_mfi = False
self._candles_since_trade = self.SignalCooldownCandles
mfi = MoneyFlowIndex()
mfi.Length = self.MfiPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(mfi, self._process_candle).Start()
def _process_candle(self, candle, mfi_value):
if candle.State != CandleStates.Finished:
return
if self._candles_since_trade < self.SignalCooldownCandles:
self._candles_since_trade += 1
mfi_val = float(mfi_value)
self._candles.append(candle)
if len(self._candles) > 5:
self._candles.pop(0)
if len(self._candles) >= 2:
curr = self._candles[-1]
prev = self._candles[-2]
if curr is None or prev is None:
return
bullish_engulfing = (float(prev.OpenPrice) > float(prev.ClosePrice)
and float(curr.ClosePrice) > float(curr.OpenPrice)
and float(curr.OpenPrice) <= float(prev.ClosePrice)
and float(curr.ClosePrice) >= float(prev.OpenPrice))
bearish_engulfing = (float(prev.ClosePrice) > float(prev.OpenPrice)
and float(curr.OpenPrice) > float(curr.ClosePrice)
and float(curr.OpenPrice) >= float(prev.ClosePrice)
and float(curr.ClosePrice) <= float(prev.OpenPrice))
if bullish_engulfing and mfi_val < self.Oversold and self.Position <= 0 and self._candles_since_trade >= self.SignalCooldownCandles:
self.BuyMarket()
self._candles_since_trade = 0
elif bearish_engulfing and mfi_val > self.Overbought and self.Position >= 0 and self._candles_since_trade >= self.SignalCooldownCandles:
self.SellMarket()
self._candles_since_trade = 0
if self._has_prev_mfi:
if self.Position > 0 and self._prev_mfi >= self.Overbought and mfi_val < self.Overbought and self._candles_since_trade >= self.SignalCooldownCandles:
self.SellMarket()
self._candles_since_trade = 0
elif self.Position < 0 and self._prev_mfi <= self.Oversold and mfi_val > self.Oversold and self._candles_since_trade >= self.SignalCooldownCandles:
self.BuyMarket()
self._candles_since_trade = 0
self._prev_mfi = mfi_val
self._has_prev_mfi = True
def CreateClone(self):
return engulfing_mfi_confirmation_strategy()