Estrategia de Cruce de Nivel MFI
Esta estrategia utiliza el oscilador Money Flow Index (MFI) para identificar condiciones de sobrecompra y sobreventa. Cuando el MFI cruza niveles de umbral predefinidos, la estrategia entra o revierte posiciones. Puede operar en la dirección del cruce o en la dirección opuesta, dependiendo del modo de tendencia seleccionado.
La configuración predeterminada monitorea velas de cuatro horas y evalúa el MFI de 14 períodos. La estrategia abre una posición larga cuando el MFI cae por debajo del umbral inferior y una posición corta cuando sube por encima del umbral superior. Cuando se establece en modo "Against", la lógica de entrada se invierte para operar contra la dirección del indicador.
La gestión de riesgos se maneja a través de parámetros integrados de stop-loss y take-profit expresados como porcentajes del precio de entrada.
Detalles
- Criterios de entrada:
- Trend Mode: Direct:
- Largo: MFI anterior > nivel bajo y MFI actual ≤ nivel bajo.
- Corto: MFI anterior < nivel alto y MFI actual ≥ nivel alto.
- Trend Mode: Against:
- Largo: MFI anterior < nivel alto y MFI actual ≥ nivel alto.
- Corto: MFI anterior > nivel bajo y MFI actual ≤ nivel bajo.
- Largo/Corto: Ambas direcciones.
- Criterios de salida: La posición se revierte cuando aparece la señal opuesta o se cierra por el módulo de protección.
- Stops: Stop-loss y take-profit expresados en porcentaje del precio de entrada.
- Valores predeterminados:
Candle Type = velas de 4 horas.
MFI Period = 14.
Low Level = 40.
High Level = 60.
Stop Loss % = 1.
Take Profit % = 2.
- Filtros:
- Categoría: Oscilador
- Dirección: Configurable
- Indicadores: Money Flow Index
- Stops: Sí
- Complejidad: Básico
- Marco temporal: Medio plazo
- Estacionalidad: No
- Redes neuronales: No
- Divergencia: No
- Nivel de riesgo: Medio
Notas
Esta implementación se basa en la API de alto nivel de StockSharp. Se suscribe a datos de velas, vincula el indicador MFI directamente y ejecuta órdenes de mercado cuando se cumplen las condiciones de cruce. La protección de posición se inicializa una vez al inicio para gestionar el riesgo automáticamente.
using System;
using System.Linq;
using System.Collections.Generic;
using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Money Flow Index based strategy that opens positions when the indicator crosses predefined levels.
/// The strategy can trade in the direction of the crossing or in the opposite direction based on Trend Mode.
/// </summary>
public class MfiLevelCrossStrategy : Strategy
{
public enum TrendModes
{
Direct,
Against
}
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _mfiPeriod;
private readonly StrategyParam<decimal> _lowLevel;
private readonly StrategyParam<decimal> _highLevel;
private readonly StrategyParam<TrendModes> _trend;
private readonly StrategyParam<decimal> _stopLossPercent;
private readonly StrategyParam<decimal> _takeProfitPercent;
private decimal _prevMfi;
private bool _isFirst;
/// <summary>
/// Candle type used by the strategy.
/// </summary>
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
/// <summary>
/// Period for the Money Flow Index indicator.
/// </summary>
public int MfiPeriod { get => _mfiPeriod.Value; set => _mfiPeriod.Value = value; }
/// <summary>
/// Oversold threshold for the MFI.
/// </summary>
public decimal LowLevel { get => _lowLevel.Value; set => _lowLevel.Value = value; }
/// <summary>
/// Overbought threshold for the MFI.
/// </summary>
public decimal HighLevel { get => _highLevel.Value; set => _highLevel.Value = value; }
/// <summary>
/// Trading mode selection.
/// </summary>
public TrendModes Trend { get => _trend.Value; set => _trend.Value = value; }
/// <summary>
/// Stop loss in percent from entry price.
/// </summary>
public decimal StopLossPercent { get => _stopLossPercent.Value; set => _stopLossPercent.Value = value; }
/// <summary>
/// Take profit in percent from entry price.
/// </summary>
public decimal TakeProfitPercent { get => _takeProfitPercent.Value; set => _takeProfitPercent.Value = value; }
/// <summary>
/// Initializes a new instance of the <see cref="MfiLevelCrossStrategy"/>.
/// </summary>
public MfiLevelCrossStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Timeframe of candles used", "General");
_mfiPeriod = Param(nameof(MfiPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("MFI Period", "Period of the Money Flow Index indicator", "Indicator");
_lowLevel = Param(nameof(LowLevel), 30m)
.SetRange(0m, 100m)
.SetDisplay("Low Level", "Oversold threshold for MFI", "Signal");
_highLevel = Param(nameof(HighLevel), 70m)
.SetRange(0m, 100m)
.SetDisplay("High Level", "Overbought threshold for MFI", "Signal");
_trend = Param(nameof(Trend), TrendModes.Direct)
.SetDisplay("Trend Mode", "Trade with trend (Direct) or against it (Against)", "Signal");
_stopLossPercent = Param(nameof(StopLossPercent), 1m)
.SetRange(0m, 100m)
.SetDisplay("Stop Loss %", "Stop loss as percent from entry price", "Risk");
_takeProfitPercent = Param(nameof(TakeProfitPercent), 2m)
.SetRange(0m, 100m)
.SetDisplay("Take Profit %", "Take profit as percent from entry price", "Risk");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevMfi = 0m;
_isFirst = true;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
StartProtection(
new Unit(TakeProfitPercent, UnitTypes.Percent),
new Unit(StopLossPercent, UnitTypes.Percent));
var mfi = new MoneyFlowIndex { Length = MfiPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(mfi, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, mfi);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal mfiValue)
{
if (candle.State != CandleStates.Finished)
return;
if (_isFirst)
{
_prevMfi = mfiValue;
_isFirst = false;
return;
}
var crossBelowLow = _prevMfi > LowLevel && mfiValue <= LowLevel;
var crossAboveHigh = _prevMfi < HighLevel && mfiValue >= HighLevel;
if (Trend == TrendModes.Direct)
{
if (crossBelowLow && Position <= 0)
BuyMarket();
else if (crossAboveHigh && Position >= 0)
SellMarket();
}
else
{
if (crossBelowLow && Position >= 0)
SellMarket();
else if (crossAboveHigh && Position <= 0)
BuyMarket();
}
_prevMfi = mfiValue;
}
}
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, Unit, UnitTypes
from StockSharp.Algo.Indicators import MoneyFlowIndex
from StockSharp.Algo.Strategies import Strategy
class mfi_level_cross_strategy(Strategy):
DIRECT = 0
AGAINST = 1
def __init__(self):
super(mfi_level_cross_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1)))
self._mfi_period = self.Param("MfiPeriod", 14)
self._low_level = self.Param("LowLevel", 30.0)
self._high_level = self.Param("HighLevel", 70.0)
self._trend = self.Param("Trend", 0)
self._stop_loss_percent = self.Param("StopLossPercent", 1.0)
self._take_profit_percent = self.Param("TakeProfitPercent", 2.0)
self._prev_mfi = 0.0
self._is_first = True
@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 LowLevel(self):
return self._low_level.Value
@LowLevel.setter
def LowLevel(self, value):
self._low_level.Value = value
@property
def HighLevel(self):
return self._high_level.Value
@HighLevel.setter
def HighLevel(self, value):
self._high_level.Value = value
@property
def Trend(self):
return self._trend.Value
@Trend.setter
def Trend(self, value):
self._trend.Value = value
@property
def StopLossPercent(self):
return self._stop_loss_percent.Value
@StopLossPercent.setter
def StopLossPercent(self, value):
self._stop_loss_percent.Value = value
@property
def TakeProfitPercent(self):
return self._take_profit_percent.Value
@TakeProfitPercent.setter
def TakeProfitPercent(self, value):
self._take_profit_percent.Value = value
def OnStarted2(self, time):
super(mfi_level_cross_strategy, self).OnStarted2(time)
self._prev_mfi = 0.0
self._is_first = True
self.StartProtection(
Unit(self.TakeProfitPercent, UnitTypes.Percent),
Unit(self.StopLossPercent, UnitTypes.Percent))
mfi = MoneyFlowIndex()
mfi.Length = self.MfiPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(mfi, self.ProcessCandle).Start()
def ProcessCandle(self, candle, mfi_value):
if candle.State != CandleStates.Finished:
return
mfi_val = float(mfi_value)
if self._is_first:
self._prev_mfi = mfi_val
self._is_first = False
return
cross_below_low = self._prev_mfi > float(self.LowLevel) and mfi_val <= float(self.LowLevel)
cross_above_high = self._prev_mfi < float(self.HighLevel) and mfi_val >= float(self.HighLevel)
if self.Trend == self.DIRECT:
if cross_below_low and self.Position <= 0:
self.BuyMarket()
elif cross_above_high and self.Position >= 0:
self.SellMarket()
else:
if cross_below_low and self.Position >= 0:
self.SellMarket()
elif cross_above_high and self.Position <= 0:
self.BuyMarket()
self._prev_mfi = mfi_val
def OnReseted(self):
super(mfi_level_cross_strategy, self).OnReseted()
self._prev_mfi = 0.0
self._is_first = True
def CreateClone(self):
return mfi_level_cross_strategy()