Auf GitHub ansehen

MFI-Niveau-Kreuzungs-Strategie

Diese Strategie verwendet den Money Flow Index (MFI) Oszillator, um überkaufte und überverkaufte Bedingungen zu identifizieren. Wenn der MFI vordefinierte Schwellenniveaus kreuzt, eröffnet oder kehrt die Strategie Positionen um. Je nach ausgewähltem Trend-Modus kann sie in Richtung der Kreuzung oder in der entgegengesetzten Richtung operieren.

Die Standardkonfiguration überwacht Vier-Stunden-Kerzen und wertet den 14-Perioden-MFI aus. Die Strategie eröffnet eine Long-Position, wenn der MFI unter den unteren Schwellenwert fällt, und eine Short-Position, wenn er über den oberen Schwellenwert steigt. Im "Against"-Modus wird die Einstiegslogik umgekehrt, um gegen die Indikatorrichtung zu handeln.

Das Risikomanagement erfolgt über integrierte Stop-Loss- und Take-Profit-Parameter, die als Prozentsatz des Einstiegspreises ausgedrückt werden.

Details

  • Einstiegskriterien:
    • Trend Mode: Direct:
      • Long: Vorheriger MFI > Low-Niveau und aktueller MFI ≤ Low-Niveau.
      • Short: Vorheriger MFI < High-Niveau und aktueller MFI ≥ High-Niveau.
    • Trend Mode: Against:
      • Long: Vorheriger MFI < High-Niveau und aktueller MFI ≥ High-Niveau.
      • Short: Vorheriger MFI > Low-Niveau und aktueller MFI ≤ Low-Niveau.
  • Long/Short: Beide Richtungen.
  • Ausstiegskriterien: Position wird umgekehrt, wenn das entgegengesetzte Signal erscheint, oder vom Schutzmodul geschlossen.
  • Stops: Stop-Loss und Take-Profit in Prozent vom Einstiegspreis.
  • Standardwerte:
    • Candle Type = 4-Stunden-Kerzen.
    • MFI Period = 14.
    • Low Level = 40.
    • High Level = 60.
    • Stop Loss % = 1.
    • Take Profit % = 2.
  • Filter:
    • Kategorie: Oszillator
    • Richtung: Konfigurierbar
    • Indikatoren: Money Flow Index
    • Stops: Ja
    • Komplexität: Grundlegend
    • Zeitrahmen: Mittelfristig
    • Saisonalität: Nein
    • Neuronale Netze: Nein
    • Divergenz: Nein
    • Risikolevel: Mittel

Hinweise

Diese Implementierung basiert auf der High-Level-API von StockSharp. Sie abonniert Kerzendaten, bindet den MFI-Indikator direkt und führt Marktorders aus, wenn Kreuzungsbedingungen erfüllt sind. Der Positionsschutz wird einmal beim Start initialisiert, um das Risiko automatisch zu verwalten.

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