Esta estrategia replica el experto MetaTrader "Expert_ABE_BE_MFI" al combinar patrones envolventes de velas japonesas con la confirmación del oscilador del índice de flujo de dinero (MFI). Se abre una posición larga cuando aparece una vela envolvente alcista mientras el flujo de dinero permanece en una zona de sobreventa. Se abre una posición corta cuando se forma una vela envolvente bajista en condiciones de flujo de dinero de sobrecompra. Las posiciones se cierran cuando las IMF cruzan los umbrales de salida dinámicos, lo que indica cambios de impulso.
Idea central
Detección de patrón: el cuerpo de la vela terminada actual debe envolver completamente la vela anterior en la dirección de la operación.
Confirmación de volumen: el indicador MFI (longitud configurable, predeterminado 37) debe estar por debajo del nivel de sobreventa (40) para entradas largas o por encima del nivel de sobrecompra (60) para entradas cortas.
Salidas de impulso: las posiciones abiertas se cierran cuando MFI cruza niveles de reversión clave (30 y 70) en la dirección opuesta, imitando la lógica de votación original del experto MQL.
Indicadores
Money Flow Index (MFI) – calculates volume-adjusted momentum. La estrategia almacena las dos últimas lecturas de MFI para detectar pasos a nivel.
Análisis del cuerpo de velas – no se registra ningún indicador adicional; La detección envolvente utiliza las dos últimas velas completadas.
Reglas de trading
Entrada larga
La vela anterior es bajista y la vela actual es alcista.
El cuerpo de la vela actual se abre por debajo o igual al cierre anterior y cierra por encima o igual al cierre anterior (envolvente estricta).
El último valor de MFI está por debajo del OversoldLevel configurable (predeterminado 40).
Entrada corta
La vela anterior es alcista y la vela actual es bajista.
El cuerpo de la vela actual se abre por encima o igual al cierre anterior y cierra por debajo o igual al cierre anterior.
Latest MFI value is above the configurable OverboughtLevel (default 60).
Condiciones de salida
Cierre Corto cuando MFI cruza por encima de ExitLongLevel (30) o ExitShortLevel (70) desde abajo.
Cierre largo cuando MFI cruza por debajo de ExitShortLevel (70) o ExitLongLevel (30) desde arriba.
Estos umbrales de salida recrean la lógica de doble votación del experto original, asegurando que movimientos prolongados en el flujo de dinero desencadenen la liquidación oportuna de posiciones.
Gestión Comercial
Las órdenes de mercado (BuyMarket / SellMarket) se utilizan para entradas y salidas.
No se utiliza ningún límite de pérdidas ni toma de ganancias explícito; La gestión de riesgos se basa en las señales de reversión de las IMF.
Parámetros
Nombre
Descripción
Predeterminado
Rango / Notas
CandleType
Plazo de vela utilizado para el análisis.
1 minuto
Cualquier tipo de vela admitida.
MfiPeriod
Longitud del índice de flujo de dinero.
37
Debe ser > 0; coincide con el valor predeterminado original EA.
OversoldLevel
Nivel de IMF que confirma configuraciones envolventes alcistas.
40
Habilite la optimización si es necesario.
OverboughtLevel
MFI level that confirms bearish engulfing setups.
60
Habilite la optimización si es necesario.
ExitLongLevel
Límite inferior de las IMF para detectar reversiones.
30
Se utiliza tanto para salidas largas como para confirmaciones cortas.
ExitShortLevel
Límite superior de la IMF para detectar reversiones.
70
Se utiliza tanto para salidas cortas como para confirmaciones largas.
Notas sobre la conversión
El experto original de MQL agregó “votos” de patrones envolventes y filtros de IMF. La estrategia de C# reproduce el mismo flujo de decisiones al convertir directamente las reglas de votación en condiciones de entrada y salida discretas.
Money management and trailing modules from the MQL version are omitted; El tamaño de la posición StockSharp está controlado por el volumen de la estrategia.
Todos los enlaces de indicadores aprovechan el API (SubscribeCandles().Bind(...)) de alto nivel según sea necesario.
Consejos de uso
Optimice MfiPeriod, OversoldLevel y OverboughtLevel para adaptar la estrategia a mercados específicos.
Combínelo con controles de riesgo (paradas de protección) a través de StartProtection en la aplicación host si se requiere seguridad adicional.
Asegúrese de tener suficientes datos históricos para que el índice de flujo de dinero esté completamente formado antes de permitir el comercio.
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()