Ver no GitHub

Estratégia de Cruzamento de Nível MFI

Esta estratégia usa o oscilador Money Flow Index (MFI) para identificar condições de sobrecompra e sobrevenda. Quando o MFI cruza níveis de limite predefinidos, a estratégia entra ou reverte posições. Pode operar na direção do cruzamento ou na direção oposta, dependendo do modo de tendência selecionado.

A configuração padrão monitora velas de quatro horas e avalia o MFI de 14 períodos. A estratégia abre uma posição comprada quando o MFI cai abaixo do limite inferior e uma posição vendida quando sobe acima do limite superior. Quando definido para o modo "Against", a lógica de entrada é invertida para negociar contra a direção do indicador.

O gerenciamento de risco é feito através de parâmetros integrados de stop-loss e take-profit expressos como porcentagens do preço de entrada.

Detalhes

  • Critérios de entrada:
    • Trend Mode: Direct:
      • Comprado: MFI anterior > nível baixo e MFI atual ≤ nível baixo.
      • Vendido: MFI anterior < nível alto e MFI atual ≥ nível alto.
    • Trend Mode: Against:
      • Comprado: MFI anterior < nível alto e MFI atual ≥ nível alto.
      • Vendido: MFI anterior > nível baixo e MFI atual ≤ nível baixo.
  • Comprado/Vendido: Ambas as direções.
  • Critérios de saída: A posição é revertida quando o sinal oposto aparece ou fechada pelo módulo de proteção.
  • Stops: Stop-loss e take-profit expressos em percentual do preço de entrada.
  • Valores padrão:
    • Candle Type = velas de 4 horas.
    • MFI Period = 14.
    • Low Level = 40.
    • High Level = 60.
    • Stop Loss % = 1.
    • Take Profit % = 2.
  • Filtros:
    • Categoria: Oscilador
    • Direção: Configurável
    • Indicadores: Money Flow Index
    • Stops: Sim
    • Complexidade: Básico
    • Período: Médio prazo
    • Sazonalidade: Não
    • Redes neurais: Não
    • Divergência: Não
    • Nível de risco: Médio

Notas

Esta implementação depende da API de alto nível do StockSharp. Assina dados de velas, vincula o indicador MFI diretamente e executa ordens de mercado quando as condições de cruzamento são atendidas. A proteção de posição é inicializada uma vez na inicialização para gerenciar o risco automaticamente.

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