Flat Trend EA Strategy ist ein StockSharp-Port des MQL5-Expert-Advisors "Flat Trend EA". Der Algorithmus kombiniert den Parabolic SAR-Indikator mit dem Average Directional Index (ADX), um vier Marktzustände zu erkennen: Aufwärtstrend, Abwärtstrend, Ende des Kaufs und Ende des Verkaufs. Die Strategie reagiert nur auf abgeschlossene Kerzen aus dem konfigurierten Zeitrahmen und spiegelt die ursprüngliche Logik wider, entgegengesetzte Positionen zu schließen, bevor eine neue eröffnet wird.
Handelslogik
Kaufsignal: der Parabolic SAR-Punkt druckt unter dem Schlusskurs und die ADX +DI-Linie liegt über der -DI-Linie. Jede Short-Exposition wird sofort geschlossen, und ein neues Long wird eröffnet, wenn keine Position aktiv ist.
Verkaufssignal: der Parabolic SAR-Punkt druckt über dem Schlusskurs und +DI ist kleiner oder gleich -DI. Jede Long-Exposition wird geschlossen, bevor ein Short-Trade eröffnet wird.
Trendende-Filter: wenn der SAR über dem Preis liegt, während +DI größer als -DI ist, markiert die Strategie das Ende eines Short-Trends; wenn SAR unter dem Preis liegt, während +DI kleiner oder gleich -DI ist, markiert es das Ende eines Long-Trends. Beide Ereignisse erzwingen das Schließen bestehender Positionen ohne Eröffnung eines neuen Trades.
Handelsfenster: optionale Sitzungsfilter beschränken Einstiege auf das Intervall [StartHour, EndHour). Signale außerhalb der Sitzung können Trades noch schließen, aber neue Einstiege werden übersprungen.
Risikomanagement
Stop-Loss und Take-Profit-Abstände werden in Pips gemessen (automatisch für drei- und fünfstellige Instrumente skaliert). Preise werden auf den Wertpapierschritt normalisiert.
Der Trailing Stop aktiviert sich, nachdem die Position mehr als TrailingStopPips + TrailingStepPips gewinnt. Long-Positionen trailern unterhalb des letzten Schlusskurses, Shorts darüber. Wenn Trailing deaktiviert ist, bleibt das Stop-Niveau fest.
Schutzausstiege: bei jeder abgeschlossenen Kerze prüft die Strategie Tief-/Hochpreise gegen Stop-Loss-, Take-Profit- und Trailing-Niveaus. Jede Verletzung schließt die Position und setzt die Risikoverfolgung zurück.
Parameter
StopLossPips – Abstand zum Schutz-Stop in Pips.
TakeProfitPips – Abstand zum Ziel in Pips.
TrailingStopPips – Trailing-Stop-Abstand in Pips (auf 0 setzen um Trailing zu deaktivieren).
TrailingStepPips – zusätzlicher Fortschritt erforderlich bevor der Trailing Stop bewegt wird; muss positiv sein wenn Trailing aktiviert ist.
UseTradingHours – aktiviert den Handelsfenster-Filter.
StartHour / EndHour – inklusive Startstunde und exklusive Endstunde für Einstiege (Börsenzeit).
AdxPeriod – Glättungsperiode für ADX, die die +DI- und -DI-Empfindlichkeit steuert.
CandleType – Zeitrahmen für Kerzen-Abonnements und Indikatorberechnungen.
Volume – von Strategy geerbt, repräsentiert die Ordergröße beim Einstieg in neue Positionen.
Indikatoren
Average Directional Index (ADX) liefert die +DI- und -DI-Komponenten zur Bestimmung der aktuellen Trendrichtung.
Parabolic SAR definiert ob die Marktstruktur bullisch oder bärisch ist und liefert das Punkt-Niveau für die Trailing-Logik.
Weitere Hinweise
Die Pip-Größe wird aus den Wertpapiereinstellungen berechnet: Für drei- und fünfstellige Instrumente wird der Preisschritt mit zehn multipliziert, um die MQL-Definition eines Pips zu entsprechen.
Die Strategie schließt immer bestehende Positionen, wenn entgegengesetzte oder Endsignale erscheinen, bevor neue Einstiege ausgewertet werden, und reproduziert den ursprünglichen EA-Workflow.
Nur die C#-Implementierung wird bereitgestellt; keine Python-Version oder -Ordner wird wie gewünscht erstellt.
using System;
using System.Collections.Generic;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Flat Trend EA strategy. Uses DEMA crossover to distinguish flat from trend.
/// </summary>
public class FlatTrendEaStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private decimal? _prevFast;
private decimal? _prevSlow;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int FastPeriod
{
get => _fastPeriod.Value;
set => _fastPeriod.Value = value;
}
public int SlowPeriod
{
get => _slowPeriod.Value;
set => _slowPeriod.Value = value;
}
public FlatTrendEaStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Timeframe", "General");
_fastPeriod = Param(nameof(FastPeriod), 10)
.SetGreaterThanZero()
.SetDisplay("Fast DEMA", "Fast DEMA period", "Indicators");
_slowPeriod = Param(nameof(SlowPeriod), 30)
.SetGreaterThanZero()
.SetDisplay("Slow DEMA", "Slow DEMA period", "Indicators");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevFast = null;
_prevSlow = null;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevFast = null;
_prevSlow = null;
var fast = new DoubleExponentialMovingAverage { Length = FastPeriod };
var slow = new DoubleExponentialMovingAverage { Length = SlowPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(fast, slow, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, fast);
DrawIndicator(area, slow);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal fastVal, decimal slowVal)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
{
_prevFast = fastVal;
_prevSlow = slowVal;
return;
}
if (_prevFast == null || _prevSlow == null)
{
_prevFast = fastVal;
_prevSlow = slowVal;
return;
}
var prevAbove = _prevFast.Value > _prevSlow.Value;
var currAbove = fastVal > slowVal;
_prevFast = fastVal;
_prevSlow = slowVal;
if (!prevAbove && currAbove && Position <= 0)
{
if (Position < 0)
BuyMarket();
BuyMarket();
}
else if (prevAbove && !currAbove && Position >= 0)
{
if (Position > 0)
SellMarket();
SellMarket();
}
}
}
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 DoubleExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class flat_trend_ea_strategy(Strategy):
def __init__(self):
super(flat_trend_ea_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))) \
.SetDisplay("Candle Type", "Timeframe", "General")
self._fast_period = self.Param("FastPeriod", 10) \
.SetDisplay("Fast DEMA", "Fast DEMA period", "Indicators")
self._slow_period = self.Param("SlowPeriod", 30) \
.SetDisplay("Slow DEMA", "Slow DEMA period", "Indicators")
self._prev_fast = None
self._prev_slow = None
@property
def CandleType(self):
return self._candle_type.Value
@property
def FastPeriod(self):
return self._fast_period.Value
@property
def SlowPeriod(self):
return self._slow_period.Value
def OnReseted(self):
super(flat_trend_ea_strategy, self).OnReseted()
self._prev_fast = None
self._prev_slow = None
def OnStarted2(self, time):
super(flat_trend_ea_strategy, self).OnStarted2(time)
self._prev_fast = None
self._prev_slow = None
fast = DoubleExponentialMovingAverage()
fast.Length = self.FastPeriod
slow = DoubleExponentialMovingAverage()
slow.Length = self.SlowPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(fast, slow, self._on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, fast)
self.DrawIndicator(area, slow)
self.DrawOwnTrades(area)
def _on_process(self, candle, fast_value, slow_value):
if candle.State != CandleStates.Finished:
return
fv = float(fast_value)
sv = float(slow_value)
if self._prev_fast is None or self._prev_slow is None:
self._prev_fast = fv
self._prev_slow = sv
return
prev_above = self._prev_fast > self._prev_slow
curr_above = fv > sv
self._prev_fast = fv
self._prev_slow = sv
if not prev_above and curr_above and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif prev_above and not curr_above and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
def CreateClone(self):
return flat_trend_ea_strategy()