Diese Strategie portiert den MetaTrader-Expertenberater personal_assistant_codeBase_MNS auf StockSharp. Sie fungiert als manueller Trading-Helfer: Anstatt autonome Signale zu generieren, stellt sie C#-Methoden bereit, die die tastaturgesteuerten Aktionen des ursprünglichen EA replizieren (Trades öffnen/schließen, Volumen anpassen oder profitable Positionen liquidieren). Der Helfer protokolliert auch informative Metriken über das Symbol, aktive Orders und aktuell konfigurierte Risikoniveaus auf jeder abgeschlossenen Kerze.
Funktionsweise
Die Strategie abonniert eine konfigurierbare Kerzen-Serie (CandleType, standardmäßig 1 Minute).
Jede abgeschlossene Kerze löst ein Update aus, das druckt: aktuelle Position, PnL, Anzahl aktiver Stop/Take-Orders, Spread, Tick-Wert und die konfigurierte Magic-Nummer.
Manuelle Befehle (z. B. PressBuy() oder PressSell()) senden Marktorders mit dem aktuellen Helfer-Volumen. Optionale Stop-Loss- und Take-Profit-Niveaus werden aus Pip-Abständen übersetzt und intern in der Strategie gespeichert.
Schutzniveaus werden auf Kerzen-Daten emuliert: Wenn der Preis den gespeicherten Stop oder das Ziel berührt, gibt die Strategie Marktausstiege aus.
Eine optionale Regel zum Break-Even-Verschieben (UseTrailingStop) wird scharf geschaltet nachdem der Preis BreakEvenTriggerPips vorgerückt ist; einmal scharf geschaltet, liquidiert sie die Position wenn der Preis auf den Einstiegspreis plus BreakEvenOffsetPips zurückfällt.
Funktionen
Repliziert die Schaltflächen 1–8 des MQL-Assistenten via öffentlicher Methoden:
PressBuy() / PressSell() – Marktorders mit optionalen Schutzniveaus öffnen.
PressCloseAll() – alle Exposure glätten.
IncreaseVolume() / DecreaseVolume() – das Helfer-Volumen in 0,01-Los-Schritten anpassen.
CloseLongPositions() / CloseShortPositions() – nur eine Seite schließen.
CloseProfitablePositions() – die Position schließen wenn der schwebende PnL positiv ist.
Protokolliert bei aktiviertem DisplayLegend eine detaillierte Aktionslegende beim Start.
Konvertiert pip-basierte Risikoabstände in absolute Preise anhand des Preisschritts und der Dezimalgenauigkeit des Instruments.
Unterstützt Break-Even-Trailing für Long- und Short-Positionen, imitierend die ursprüngliche MOVETOBREAKEVEN()-Routine.
Hält unabhängige gespeicherte Stop/Take-Niveaus für Long- und Short-Trades, sodass beim Richtungswechsel obsolete Niveaus automatisch verworfen werden.
Parameter
Parameter
Beschreibung
MagicNumber
Informationeller Identifier aus dem MagicNo-Input des MQL.
DisplayLegend
Aktivieren, um die Steuerungslegende und kerzenbezogene Statusmeldungen zu drucken.
OrderVolume
Basis-Marktordervolumen (Lots) das von allen manuellen Aktionen wiederverwendet wird.
Slippage
Maximaler tolerierter Slippage (in Ticks), zur Referenz gespeichert.
TakeProfitPips
Pip-Abstand für das gespeicherte Take-Profit-Niveau (0 deaktiviert es).
StopLossPips
Pip-Abstand für das gespeicherte Stop-Loss-Niveau (0 deaktiviert es).
UseTrailingStop
Break-Even-Trailing-Logik aktivieren oder deaktivieren.
BreakEvenTriggerPips
Gewinnabstand (in Pips) erforderlich bevor der Break-Even-Stop scharf geschaltet wird.
BreakEvenOffsetPips
Offset (in Pips) zum Einstiegspreis hinzugefügt wenn der Stop scharf geschaltet ist.
CandleType
Kerzen-Serie für Überwachung und Niveauemulation.
Verwendungstipps
Hilfsmethoden aus Designer-Aktionen, Skripten oder UI-Steuerelementen aufrufen, um Tastendrücke aus dem ursprünglichen MetaTrader-Panel zu imitieren.
Schutzniveaus und Break-Even-Abstände setzen voraus, dass das Instrument PriceStep, StepPrice und Decimals bereitstellt. Für exotische Instrumente ohne diese Metadaten die Pip-Abstände manuell anpassen oder die Funktionen durch Setzen auf 0 deaktivieren.
Da Stop/Take-Niveaus mithilfe von Kerzen-Hochs und -Tiefs reproduziert werden, können sehr schnelle intra-bar Spitzen nicht erfasst werden, wenn der Kerzen-Zeitrahmen nicht klein genug ist. Den Zeitrahmen verkleinern wenn eine feinere Granularität erforderlich ist.
CloseProfitablePositions() repliziert das „Schaltfläche 8"-Verhalten: Es prüft den schwebenden PnL und schließt die gesamte Position nur wenn der Wert strikt positiv ist.
Unterschiede zur MetaTrader-Version
Chart-Labels werden durch Log-Einträge ersetzt, da StockSharp nicht dieselben Zeichnungsprimitive innerhalb von Strategien freilegt.
Stop-Loss- und Take-Profit-Orders werden durch Marktausstiege bei Kerzen-Ereignissen simuliert statt sofortiger ausstehender Orders.
Das Break-Even-Management wird mit StockSharp-Marktorders implementiert; es modifiziert keine bestehenden Schutzorders.
Slippage wird als informativer Parameter gehalten; die tatsächliche Ausführung wird vom StockSharp-Connector verwaltet.
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 PersonalAssistantMnsStrategy : 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 PersonalAssistantMnsStrategy()
{
_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 personal_assistant_mns_strategy(Strategy):
def __init__(self):
super(personal_assistant_mns_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(personal_assistant_mns_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(personal_assistant_mns_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 personal_assistant_mns_strategy()