Diese Strategie portiert den MetaTrader 5-Expertenberater Exp_ColorMETRO_MMRec_Duplex zu StockSharp. Der originale Roboter führt zwei unabhängige ColorMETRO-Indikatormodule (eines für Long, eines für Short) aus und wendet eine MMRec-Überlagerung (Geldverwaltungs-Neuberechnung) an, die die Positionsgröße nach wiederholten Verlusten reduziert. Die C#-Version spiegelt dieses Verhalten mit StockSharpss High-Level-API für Kerzenabonnements und Order-Routing wider.
Handelslogik
Zwei verschiedene ColorMETRO-Indikatoren operieren auf konfigurierbaren Kerzentypen. Das Long-Modul verwaltet nur Long-Exposition, während das Short-Modul die Short-Exposition kontrolliert.
Jeder Indikator erzeugt ein schnelles und ein langsames RSI-Stufenband. Die Strategie imitiert die MQL5-CopyBuffer-Aufrufe, indem sie historische Werte speichert und die durch SignalBar definierte Barre inspiziert.
Ein Long-Einstieg wird generiert, wenn das schnelle Band auf der inspizierten Barre die langsame Band von unten kreuzt, während die vorherige Barre das schnelle Band noch über dem langsamen hatte. Alle offenen Short-Positionen werden vor der neuen Long-Position abgeflacht.
Long-Ausstiege erfolgen, wenn das langsame Band auf der vorherigen inspizierten Barre über dem schnellen Band sitzt, was ein bärisches Regime im originalen EA signalisiert.
Short-Einstiege und -Ausstiege spiegeln die Long-Logik wider (Kreuzen nach oben für Einstiege, schnelle Linie über der langsamen auf der vorherigen Barre für Ausstiege).
Nur fertige Kerzen werden verarbeitet und der Handel wird blockiert, bis der Indikator beide Bänder als bereit meldet, was die MetaTrader-Aufwärmphase reproduziert.
Geldverwaltung (MMRec)
Strategy.Volume definiert die Referenz-Lotgröße. Die Long- und Short-Module multiplizieren sie mit ihren jeweiligen LongMm/ShortMm-Koeffizienten bei der Dimensionierung neuer Orders.
Nach jeder abgeschlossenen Trade zeichnet die Strategie auf, ob das Ergebnis ein Verlust war (basierend auf Kerzenschlusspreisen, genauso wie der EA, der historische Deals inspiziert).
Wenn die letzten TotalTrigger-Trades eines Moduls mindestens LossTrigger-Verlierer enthalten, wechselt das Modul zum reduzierten Multiplikator (SmallMm). Sobald die Verlustanzahl unter den Schwellenwert fällt, wird der Standard-Multiplikator automatisch wiederhergestellt.
Positionsumkehrungen finalisieren zuerst das Ergebnis des bestehenden Trades (Aktualisierung der MMRec-Zähler), bevor die entgegengesetzte Richtung dimensioniert und eröffnet wird.
Indikatorhinweise
ColorMetroMmrecIndicator ist ein treuer Port des benutzerdefinierten ColorMETRO-Indikators. Er speist dieselben schnellen/langsamen Bänder, die von einem RSI-Kern mit Schrittverfolgung und Trend-Gedächtnis angetrieben werden.
Der Indikator legt den internen RSI und ein Bereitschafts-Flag frei, sodass die Strategie unvollständige Werte genau wie die MQL-Implementierung ignorieren kann.
Parameter
Gruppe
Name
Beschreibung
Long
LongCandleType
Kerzentyp für das Long-ColorMETRO-Modul.
Long
LongTotalTrigger
Anzahl abgeschlossener Long-Trades, die bei der MMRec-Auswertung inspiziert werden.
Long
LongLossTrigger
Verlustanzahl, die den reduzierten Long-Multiplikator aktiviert.
Long
LongSmallMm
Reduzierter Multiplikator für Long-Trades nach einer Verlustserie.
Long
LongMm
Standard-Multiplikator für Long-Trades.
Long
LongEnableOpen
Öffnen von Long-Positionen aktivieren.
Long
LongEnableClose
Schließen von Long-Positionen aktivieren.
Long
LongPeriodRsi
RSI-Länge im Long-ColorMETRO-Indikator.
Long
LongStepSizeFast
Schnelle Band-Schrittgröße für das Long-Modul.
Long
LongStepSizeSlow
Langsame Band-Schrittgröße für das Long-Modul.
Long
LongSignalBar
Historischer Versatz (in geschlossenen Barren) beim Lesen von Indikatorwerten.
Long
LongMagic
Originale MT5-Magicnummer, als Referenz beibehalten.
Long
LongStopLossTicks
Stop-Loss-Abstand-Platzhalter aus dem EA (nicht durchgesetzt).
Long
LongTakeProfitTicks
Take-Profit-Abstand-Platzhalter aus dem EA (nicht durchgesetzt).
Long
LongDeviationTicks
Erlaubter Slippage-Platzhalter aus dem EA (nicht durchgesetzt).
Long
LongMarginMode
MM-Modus-Flag für Kompatibilität beibehalten (Logik verwendet rohe Multiplikatoren).
Short
ShortCandleType
Kerzentyp für das Short-ColorMETRO-Modul.
Short
ShortTotalTrigger
Anzahl abgeschlossener Short-Trades, die bei der MMRec-Auswertung inspiziert werden.
Short
ShortLossTrigger
Verlustanzahl, die den reduzierten Short-Multiplikator aktiviert.
Short
ShortSmallMm
Reduzierter Multiplikator für Short-Trades nach einer Verlustserie.
Short
ShortMm
Standard-Multiplikator für Short-Trades.
Short
ShortEnableOpen
Öffnen von Short-Positionen aktivieren.
Short
ShortEnableClose
Schließen von Short-Positionen aktivieren.
Short
ShortPeriodRsi
RSI-Länge im Short-ColorMETRO-Indikator.
Short
ShortStepSizeFast
Schnelle Band-Schrittgröße für das Short-Modul.
Short
ShortStepSizeSlow
Langsame Band-Schrittgröße für das Short-Modul.
Short
ShortSignalBar
Historischer Versatz (in geschlossenen Barren) beim Lesen von Indikatorwerten.
Short
ShortMagic
Originale MT5-Magicnummer, als Referenz beibehalten.
Short
ShortStopLossTicks
Stop-Loss-Abstand-Platzhalter aus dem EA (nicht durchgesetzt).
Short
ShortTakeProfitTicks
Take-Profit-Abstand-Platzhalter aus dem EA (nicht durchgesetzt).
Short
ShortDeviationTicks
Erlaubter Slippage-Platzhalter aus dem EA (nicht durchgesetzt).
Short
ShortMarginMode
MM-Modus-Flag für Kompatibilität beibehalten (Logik verwendet rohe Multiplikatoren).
Implementierungshinweise
Die Strategie verlässt sich auf SubscribeCandles(...).BindEx(...) und vermeidet direkten Pufferzugriff, konform mit den Konvertierungsrichtlinien.
Schutz-Stops aus dem EA bleiben nur als Parameter; Benutzer können StartProtection oder benutzerdefinierte Risikomodule bei Bedarf anhängen.
Beide Module teilen dieselbe Sicherheitsinstanz, behalten aber ihre eigenen Kerzenabonnements und MMRec-Zähler, entsprechend dem Duplex-Layout von MetaTrader.
Alle Code-Kommentare sind auf Englisch und die Logik vermeidet verbotene API-Aufrufe wie GetTrades.
Haftungsausschluss
Dieser Port reproduziert die logische Struktur des originalen EA, aber die Ausführungsqualität hängt vom verbundenen Broker, dem Datenfeed und der StockSharp-Konfiguration ab. Validieren Sie das Verhalten immer auf historischen und Demo-Daten, bevor Sie mit echtem Kapital handeln.
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;
/// <summary>
/// ColorMETRO MMRec Duplex strategy using EMA crossover.
/// Buys when fast EMA crosses above slow EMA, sells on reverse.
/// </summary>
public class ExpColorMetroMmrecDuplexStrategy : 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 ExpColorMetroMmrecDuplexStrategy()
{
_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_color_metro_mmrec_duplex_strategy(Strategy):
def __init__(self):
super(exp_color_metro_mmrec_duplex_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_color_metro_mmrec_duplex_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_color_metro_mmrec_duplex_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_color_metro_mmrec_duplex_strategy()