Auf GitHub ansehen

Exp Cronex MFI-Strategie

Überblick

Die Strategie repliziert den Experten-Advisor Exp_CronexMFI. Er glättet den Money Flow Index (MFI) zweimal und handelt gegen den Crossover der resultierenden Linien. Der Port behält die ursprüngliche konträre Philosophie bei und macht jede Einstellung als StockSharp-Strategieparameter zugänglich.

Funktionsweise

  1. Abonnieren der ausgewählten Kerzenserie (der Standard ist ein 4-Stunden-Zeitrahmen).
  2. Berechnen des Money Flow Index mit der konfigurierten Periode.
  3. Anwenden der gewählten Glättungsmethode zweimal: Der erste Durchlauf erzeugt die schnelle Cronex-Linie, der zweite Durchlauf glättet die schnelle Linie erneut, um die langsame Linie aufzubauen.
  4. Speichern historischer Paare von schnellen und langsamen Werten mit einer einstellbaren Verzögerung (SignalShift).
  5. Wenn die schnelle Linie die langsame Linie nach unten kreuzt, werden Shorts geschlossen (wenn erlaubt) und eine Long-Position geöffnet/erweitert. Wenn die schnelle Linie nach oben kreuzt, werden Longs geschlossen und eine Short-Position geöffnet/erweitert.
  6. Orders werden mit dem Strategie-Volume gesendet und können für Long- und Short-Seiten unabhängig deaktiviert werden.

Die Strategie wertet nur abgeschlossene Kerzen aus, um das Timing der MetaTrader-Implementierung zu entsprechen.

Parameter

Name Typ Standard Beschreibung
MfiPeriod int 25 Länge des Money Flow Index.
FastPeriod int 14 Periode der ersten Glättungsstufe (schnelle Cronex-Linie).
SlowPeriod int 25 Periode der zweiten Glättungsstufe (langsame Cronex-Linie).
SignalShift int 1 Anzahl abgeschlossener Kerzen zur Verzögerung der Signalverarbeitung, reproduziert das SignalBar-Verhalten aus MQL.
Smoothing SmoothingMethod Simple Gleitender-Durchschnitt-Algorithmus für beide Glättungsstufen.
EnableLongEntries bool true Aktiviert Market-Orders, die Long-Positionen öffnen oder hinzufügen.
EnableShortEntries bool true Aktiviert Market-Orders, die Short-Positionen öffnen oder hinzufügen.
EnableLongExits bool true Erlaubt Signalen, bestehende Long-Exposition zu schließen.
EnableShortExits bool true Erlaubt Signalen, bestehende Short-Exposition zu schließen.
CandleType DataType TimeFrame(4h) Kerzenserie für Indikatorberechnungen.
Volume decimal 1 Ordergröße beim Öffnen neuer Positionen.

Glättungsoptionen

Der originale MQL-Indikator bietet mehrere proprietäre Glättungsmodi. Der StockSharp-Port ordnet sie integrierten gleitenden Durchschnitten zu:

MQL-Konzept SmoothingMethod-Wert Hinweise
SMA Simple Einfacher gleitender Durchschnitt.
EMA Exponential Exponentieller gleitender Durchschnitt.
SMMA Smoothed Geglätteter gleitender Durchschnitt (Wilder).
LWMA Weighted Linear gewichteter gleitender Durchschnitt.
JJMA / JurX / ParMA / T3 / VIDYA / AMA DoubleExponential, TripleExponential, Hull, ZeroLagExponential, ArnaudLegoux, KaufmanAdaptive Nächste Approximation für adaptives Glätten wählen.

Unterschiede zur MQL-Version

  • Tick-/Real-Volumen-Auswahl aus MQL ist nicht verfügbar; StockSharp-Kerzen liefern aggregierte Volumendaten.
  • Handelsverwaltung basiert ausschließlich auf Market-Orders. Der ursprüngliche Geldmanagement-Helfer, der die Ausführung bis zur nächsten Bar verzögerte, wird durch SignalShift emuliert.
  • Stop-Loss- und Take-Profit-Platzierung muss extern konfiguriert werden (z. B. über Risikoregeln oder Schutzmodule).

Verwendungshinweise

  • Eine Kerzenserie wählen, die zur Liquidität des Instruments passt; das Standard-4-Stunden-Intervall spiegelt den Quell-EA wider.
  • SignalShift anpassen, wenn ein Crossover mit zusätzlichen Kerzen bestätigt werden soll.
  • Die Strategie mit Risikoverwaltungsregeln (z. B. StartProtection) kombinieren, um Verluste zu begrenzen.
using System;
using System.Collections.Generic;

using Ecng.Common;

using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;

namespace StockSharp.Samples.Strategies;

public class ExpCronexMfiStrategy : Strategy
{
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;
	private readonly StrategyParam<int> _stopLossPoints;
	private readonly StrategyParam<int> _takeProfitPoints;

	private ExponentialMovingAverage _fast;
	private ExponentialMovingAverage _slow;

	private decimal _prevFast;
	private decimal _prevSlow;
	private decimal _entryPrice;
	private int _cooldown;

	public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
	public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
	public int StopLossPoints { get => _stopLossPoints.Value; set => _stopLossPoints.Value = value; }
	public int TakeProfitPoints { get => _takeProfitPoints.Value; set => _takeProfitPoints.Value = value; }

	public ExpCronexMfiStrategy()
	{
		_fastPeriod = Param(nameof(FastPeriod), 14).SetGreaterThanZero().SetDisplay("Fast Period", "Fast EMA period", "Indicator");
		_slowPeriod = Param(nameof(SlowPeriod), 50).SetGreaterThanZero().SetDisplay("Slow Period", "Slow EMA period", "Indicator");
		_stopLossPoints = Param(nameof(StopLossPoints), 200).SetNotNegative().SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk");
		_takeProfitPoints = Param(nameof(TakeProfitPoints), 400).SetNotNegative().SetDisplay("Take Profit", "Take-profit in price steps", "Risk");
	}

	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		yield return (Security, TimeSpan.FromMinutes(5).TimeFrame());
	}

	protected override void OnReseted()
	{
		base.OnReseted();
		_fast = null; _slow = null;
		_prevFast = 0; _prevSlow = 0; _entryPrice = 0; _cooldown = 0;
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_fast = new ExponentialMovingAverage { Length = FastPeriod };
		_slow = new ExponentialMovingAverage { Length = SlowPeriod };
		var subscription = SubscribeCandles(TimeSpan.FromMinutes(5).TimeFrame());
		subscription.Bind(_fast, _slow, ProcessCandle);
		subscription.Start();
	}

	private void ProcessCandle(ICandleMessage candle, decimal fastValue, decimal slowValue)
	{
		if (candle.State != CandleStates.Finished) return;
		if (!_fast.IsFormed || !_slow.IsFormed) { _prevFast = fastValue; _prevSlow = slowValue; return; }
		if (_cooldown > 0) { _cooldown--; _prevFast = fastValue; _prevSlow = slowValue; return; }

		var close = candle.ClosePrice;
		var step = Security?.PriceStep ?? 1m;

		if (Position > 0 && _entryPrice > 0)
		{
			if (StopLossPoints > 0 && close <= _entryPrice - StopLossPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
			if (TakeProfitPoints > 0 && close >= _entryPrice + TakeProfitPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
		}
		else if (Position < 0 && _entryPrice > 0)
		{
			if (StopLossPoints > 0 && close >= _entryPrice + StopLossPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
			if (TakeProfitPoints > 0 && close <= _entryPrice - TakeProfitPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
		}

		if (_prevFast <= _prevSlow && fastValue > slowValue && Position <= 0)
		{ if (Position < 0) BuyMarket(); BuyMarket(); _entryPrice = close; _cooldown = 100; }
		else if (_prevFast >= _prevSlow && fastValue < slowValue && Position >= 0)
		{ if (Position > 0) SellMarket(); SellMarket(); _entryPrice = close; _cooldown = 100; }

		_prevFast = fastValue; _prevSlow = slowValue;
	}
}