Herkunft: MetaTrader 4 Fachberater et4_MTC_v1.mq4 aus der GlobeInvestFund-Sammlung.
Zweck: Bereitstellung einer StockSharp-nativen Vorlage, die die Money-Management-Helfer und Timing-Sicherheitsmaßnahmen des ursprünglichen Beraters widerspiegelt und gleichzeitig die Handelseinstiegs-/-ausstiegslogik für die weitere Entwicklung offen lässt.
Handelsstil: Skelettstrategie – standardmäßig werden keine automatischen Einträge generiert. Die Klasse konzentriert sich auf die Durchsetzung von Zeitbeschränkungen und die Replikation der Parameterschnittstelle des MQL4-Skripts, damit sie als Grundlage für benutzerdefinierte Regeln dienen kann.
Kernfunktionen
Parameterparität
Macht die Eigenschaften TakeProfit, StopLoss, Slippage, Lots und EnableLogging verfügbar, die den externen Variablen des Experten eins zu eins zugeordnet sind.
Fügt TradeCooldown hinzu, um die hartcodierte 30-Sekunden-Verzögerung zwischen Vorgängen im Quellcode zu beschreiben.
Veröffentlicht den Diagrammdatenkontext über CandleType, um das Verhalten des „aktuellen Zeitrahmens“ von MetaTrader-Diagrammen zu emulieren.
Balance-basierte Positionsgrößenbestimmung
Unterstützt negative Lot-Eingaben (ursprüngliche Skript-Standardeinstellung), um das Bestellvolumen aus dem Kontostand abzuleiten: floor((balance / 1000 * |Lots|) / 10) / 10, mit einem Minimum von 0,1 Lot.
Durchsetzung der Handelsabklingzeit
Blockiert alle weiteren Handelsversuche, bis TradeCooldown nach der letzten Auftragsaktivität (Registrierung, Änderung, Stornierung oder ausgeführter Handel) verstrichen ist. Dies spiegelt den CurTime() - LastTradeTime < 30-Wächter in start() wider.
Erkennung neuer Kerzen
Behält die CheckLevels-Semantik bei, indem IsNewCandle durch einen Zeitvergleich zwischen aufeinanderfolgenden fertigen Kerzen markiert wird. Während das Flag intern ist, können die Hooks in OpenPosition, ManagePosition und ClosePosition es verwenden, wenn benutzerdefinierte Logik hinzugefügt wird.
Hochrangige StockSharp API-Nutzung
Verwendet SubscribeCandles().Bind(...) für die Datenbereitstellung.
Wendet StartProtection() einmal beim Start an und befolgt dabei die Best Practices des Frameworks.
Weist nicht explizit benutzerdefinierte Sammlungen zu und fordert den Indikatorverlauf nicht explizit an, was den projektweiten Richtlinien entspricht.
Parameterreferenz
Eigentum
Standard
Optimierbar
Beschreibung
TakeProfit
150
✔️
Zielentfernung in Punkten (Platzhalter für benutzerdefinierte Ausgangsregeln).
Lots
-10
✔️
Feste Lose bei ≥ 0; Balance-proportionale Größe, wenn negativ.
StopLoss
50
✔️
Stoppdistanz in Punkten, bereit für Erweiterungslogik.
Slippage
3
✖️
Ausführungstoleranz in Punkten; aus Kompatibilitätsgründen aufbewahrt.
EnableLogging
false
✖️
Druckt Informationsmeldungen, wenn die Abklingzeit den Handel blockiert.
TradeCooldown
30 Sekunden
✖️
Minimale Verzögerung zwischen aufeinanderfolgenden Trades.
CandleType
1-Minuten-Zeitrahmenkerzen
✖️
Marktdatenabonnement, das für das Candle-Timing verwendet wird.
Ausführungsablauf
Startup
Berechnet den anfänglichen Volume mithilfe des ausgleichsbewussten Größenhilfsgeräts.
Abonniert den konfigurierten Kerzenstrom und startet Schutzmechanismen.
Bei Kerzenschluss
Bestätigt, dass die Kerze fertig ist, bevor fortgefahren wird (entspricht dem Schließen von Time[0] in MT4).
Aktualisiert den New-Candle-Tracker (_isNewCandle).
Überprüft IsFormedAndOnlineAndAllowTrading(), um den Engine-Status zu berücksichtigen.
Bricht ab, wenn die Handelsabklingzeit aktiv ist, und protokolliert die nächste verfügbare Zeit, wenn sie aktiviert ist.
Führt Platzhalter-Hooks (OpenPosition, ManagePosition, ClosePosition aus und kehrt früh zurück, wenn ein Schritt eine Aktion ausführt.
Rückrufe bestellen und handeln
OnOrderRegistered, OnOrderChanged, OnOrderCanceled und OnNewMyTrade aktualisieren _lastTradeTime und stellen sicher, dass jede Art von Vorgang die Abklingzeit zurücksetzt, genau wie es die Wrapper-Funktionen (MOrderSend, MOrderModify usw.) im Originalcode getan haben.
Erweitern der Vorlage
Implementieren Sie die Eingabelogik in OpenPosition (geben Sie true zurück, nachdem Sie Befehle gesendet haben, um die weitere Verarbeitung derselben Kerze zu stoppen).
Fügen Sie das Stop-Management-Verhalten in ManagePosition ein, indem Sie die beibehaltenen Parameter verwenden.
Füllen Sie ClosePosition mit Exit-Regeln. Die Methode gibt derzeit false zurück, um dem ruhenden Verhalten des Quellskripts zu entsprechen.
Verwenden Sie _isNewCandle, wenn die Regeln einmal pro Balken ausgelöst werden müssen.
Portierungshinweise
Der MQL4-Experte wurde ohne Handelsregeln versendet; Es waren nur Infrastrukturroutinen vorhanden. Folglich priorisiert die StockSharp-Konvertierung die Parität unterstützender Funktionen, anstatt spekulative Indikatoren hinzuzufügen.
Alle Kommentare sind in englischer Sprache verfasst und entsprechen den Repository-Standards.
Tabulatoren werden zum Einrücken verwendet, um den in AGENTS.md definierten Stilrichtlinien zu entsprechen.
Gemäß der Konvertierungsanforderung wird absichtlich auf die Python-Übersetzung verzichtet.
Nutzungsschritte
Referenzieren Sie Et4MtcV1Strategy in einem StockSharp-Projekt und weisen Sie vor dem Start ein Security und ein Portfolio zu.
Passen Sie Lots oder andere Parameter über die bereitgestellten Eigenschaften oder UI-Bindungen an.
Überschreiben Sie die Platzhaltermethoden oder erben Sie von der Klasse, um konkrete Handelslogik einzufügen.
Führen Sie die Strategie aus. Der Abklingschutz stellt sicher, dass innerhalb des angegebenen Intervalls keine aufeinanderfolgenden Vorgänge stattfinden.
Testen
Dieser Vorlage liegen keine automatisierten Tests bei, da in der Upstream-Quelle auch ausführbare Regeln fehlten. Manuelle Strategieerweiterungen sollten relevante Tests einführen, wenn konkretes Handelsverhalten implementiert wird.
using System;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
public class Et4MtcV1Strategy : Strategy
{
private readonly StrategyParam<int> _emaPeriod;
private readonly StrategyParam<int> _momentumPeriod;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevMom;
private bool _hasPrev;
private int _cooldown;
public int EmaPeriod { get => _emaPeriod.Value; set => _emaPeriod.Value = value; }
public int MomentumPeriod { get => _momentumPeriod.Value; set => _momentumPeriod.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public Et4MtcV1Strategy()
{
_emaPeriod = Param(nameof(EmaPeriod), 20).SetDisplay("EMA Period", "EMA trend filter", "Indicators");
_momentumPeriod = Param(nameof(MomentumPeriod), 14).SetDisplay("Momentum", "Momentum period", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(15).TimeFrame()).SetDisplay("Candle Type", "Candle timeframe", "General");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevMom = default;
_hasPrev = default;
_cooldown = default;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_hasPrev = false;
var ema = new ExponentialMovingAverage { Length = EmaPeriod };
var mom = new Momentum { Length = MomentumPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(ema, mom, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, decimal ema, decimal mom)
{
if (candle.State != CandleStates.Finished) return;
if (!IsFormedAndOnlineAndAllowTrading()) return;
var close = candle.ClosePrice;
if (!_hasPrev) { _prevMom = mom; _hasPrev = true; return; }
if (_cooldown > 0)
{
_cooldown--;
_prevMom = mom;
return;
}
if (close > ema && _prevMom <= 0 && mom > 0 && Position <= 0)
{
var volume = Volume + Math.Abs(Position);
BuyMarket(volume);
_cooldown = 2;
}
else if (close < ema && _prevMom >= 0 && mom < 0 && Position >= 0)
{
var volume = Volume + Math.Abs(Position);
SellMarket(volume);
_cooldown = 2;
}
_prevMom = mom;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Math
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import ExponentialMovingAverage, Momentum
from StockSharp.Algo.Strategies import Strategy
class et4_mtc_v1_strategy(Strategy):
"""
EMA + Momentum crossover strategy.
Buys when price > EMA and momentum crosses above 0.
Sells when price < EMA and momentum crosses below 0.
"""
def __init__(self):
super(et4_mtc_v1_strategy, self).__init__()
self._ema_period = self.Param("EmaPeriod", 20) \
.SetDisplay("EMA Period", "EMA trend filter", "Indicators")
self._momentum_period = self.Param("MomentumPeriod", 14) \
.SetDisplay("Momentum", "Momentum period", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(15))) \
.SetDisplay("Candle Type", "Candle timeframe", "General")
self._prev_mom = 0.0
self._has_prev = False
self._cooldown = 0
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(et4_mtc_v1_strategy, self).OnReseted()
self._prev_mom = 0.0
self._has_prev = False
self._cooldown = 0
def OnStarted2(self, time):
super(et4_mtc_v1_strategy, self).OnStarted2(time)
self._has_prev = False
ema = ExponentialMovingAverage()
ema.Length = self._ema_period.Value
mom = Momentum()
mom.Length = self._momentum_period.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(ema, mom, self._process_candle).Start()
def _process_candle(self, candle, ema_val, mom_val):
if candle.State != CandleStates.Finished:
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
close = float(candle.ClosePrice)
ema_val = float(ema_val)
mom_val = float(mom_val)
if not self._has_prev:
self._prev_mom = mom_val
self._has_prev = True
return
if self._cooldown > 0:
self._cooldown -= 1
self._prev_mom = mom_val
return
if close > ema_val and self._prev_mom <= 0 and mom_val > 0 and self.Position <= 0:
volume = self.Volume + abs(self.Position)
self.BuyMarket(volume)
self._cooldown = 2
elif close < ema_val and self._prev_mom >= 0 and mom_val < 0 and self.Position >= 0:
volume = self.Volume + abs(self.Position)
self.SellMarket(volume)
self._cooldown = 2
self._prev_mom = mom_val
def CreateClone(self):
return et4_mtc_v1_strategy()