Ver en GitHub

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;
	}
}