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
Abonnieren der ausgewählten Kerzenserie (der Standard ist ein 4-Stunden-Zeitrahmen).
Berechnen des Money Flow Index mit der konfigurierten Periode.
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.
Speichern historischer Paare von schnellen und langsamen Werten mit einer einstellbaren Verzögerung (SignalShift).
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.
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:
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;
}
}
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
from StockSharp.Algo.Indicators import ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class exp_cronex_mfi_strategy(Strategy):
def __init__(self):
super(exp_cronex_mfi_strategy, self).__init__()
self._fast_period = self.Param("FastPeriod", 14) \
.SetDisplay("Fast Period", "Fast MA period", "Indicator")
self._slow_period = self.Param("SlowPeriod", 50) \
.SetDisplay("Slow Period", "Slow MA period", "Indicator")
self._stop_loss_points = self.Param("StopLossPoints", 200) \
.SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk")
self._take_profit_points = self.Param("TakeProfitPoints", 400) \
.SetDisplay("Take Profit", "Take-profit in price steps", "Risk")
self._fast = None
self._slow = None
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
self._cooldown = 0
@property
def fast_period(self):
return self._fast_period.Value
@property
def slow_period(self):
return self._slow_period.Value
@property
def stop_loss_points(self):
return self._stop_loss_points.Value
@property
def take_profit_points(self):
return self._take_profit_points.Value
def OnReseted(self):
super(exp_cronex_mfi_strategy, self).OnReseted()
self._fast = None
self._slow = None
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
self._cooldown = 0
def OnStarted2(self, time):
super(exp_cronex_mfi_strategy, self).OnStarted2(time)
self._fast = ExponentialMovingAverage()
self._fast.Length = self.fast_period
self._slow = ExponentialMovingAverage()
self._slow.Length = self.slow_period
subscription = self.SubscribeCandles(DataType.TimeFrame(TimeSpan.FromMinutes(5)))
subscription.Bind(self._fast, self._slow, self._process_candle)
subscription.Start()
def _process_candle(self, candle, fast_value, slow_value):
if candle.State != CandleStates.Finished:
return
fast_val = float(fast_value)
slow_val = float(slow_value)
if not self._fast.IsFormed or not self._slow.IsFormed:
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self._cooldown > 0:
self._cooldown -= 1
self._prev_fast = fast_val
self._prev_slow = slow_val
return
close = float(candle.ClosePrice)
step = float(self.Security.PriceStep) if self.Security is not None and self.Security.PriceStep is not None else 1.0
if self.Position > 0 and self._entry_price > 0:
if self.stop_loss_points > 0 and close <= self._entry_price - self.stop_loss_points * step:
self.SellMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self.take_profit_points > 0 and close >= self._entry_price + self.take_profit_points * step:
self.SellMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
elif self.Position < 0 and self._entry_price > 0:
if self.stop_loss_points > 0 and close >= self._entry_price + self.stop_loss_points * step:
self.BuyMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self.take_profit_points > 0 and close <= self._entry_price - self.take_profit_points * step:
self.BuyMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self._prev_fast <= self._prev_slow and fast_val > slow_val and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
self._entry_price = close
self._cooldown = 100
elif self._prev_fast >= self._prev_slow and fast_val < slow_val and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._entry_price = close
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
def CreateClone(self):
return exp_cronex_mfi_strategy()