Die Lego EA-Strategie ist ein direkter Port des MetaTrader-Expertenberaters "Lego EA". Sie verwendet eine konfigurierbare Kombination technischer Filter—Commodity Channel Index, duale gleitende Durchschnitte, stochastischer Oszillator, Accelerator Oscillator, DeMarker und Awesome Oscillator—zur Validierung von Ein- und Ausstiegen. Jeder Filter kann für Einstiege und Ausstiege unabhängig ein- oder ausgeschaltet werden, was es ermöglicht, das Original-"Lego" Block für Block nachzubauen oder mit eigenen Setups zu experimentieren.
Parameter
Volume – Basishandelsvolumen, das verwendet wird, wenn der vorherige Trade profitabel war.
LotMultiplier – Multiplikator, der nach einem Verlust-Trade auf das zuletzt ausgeführte Volumen angewendet wird (Martingale-ähnliche Erholung).
StopLossPips – Schutz-Stop in Pips (intern anhand der Tick-Größe des Symbols umgerechnet).
TakeProfitPips – Gewinnziel in Pips.
UseCciForEntry / UseCciForExit – CCI-Filter beim Öffnen oder Schließen von Positionen aktivieren.
UseMaForEntry / UseMaForExit – Schnelle/langsame gleitende Durchschnitt-Kreuzung für Bestätigungen verwenden.
UseStochasticForEntry / UseStochasticForExit – Stochastische %K/%D-Ausrichtung innerhalb konfigurierter Schwellenwerte erfordern.
CandleType – Zeitrahmen der Kerzenserie, die von allen Indikatoren verwendet wird.
Handels-Workflow
Bei jeder abgeschlossenen Kerze sammelt die Strategie Indikatorwerte aus den ausgewählten Filtern.
Jeder Filter berechnet die Kauf-/Verkaufsbereitschaft basierend auf dem vorherigen vollständig geformten Bar (entspricht dem iGetArray(..., 1)-Offset des ursprünglichen EA).
Ein Long-Einstieg ist nur zulässig, wenn alle aktivierten Einstiegsfilter ein bullisches Signal bestätigen. Ebenso erfordert ein Short-Einstieg einstimmige bearische Bestätigung.
Wenn das Konto flat ist und ein gültiges Eintrittssignal erscheint, wird eine Marktorder mit entweder dem Basis-Volume oder dem letzten Verlust-Trade-Volumen multipliziert mit LotMultiplier gesendet.
Bei bestehender Position werden die aktivierten Exit-Filter auf dieselbe Weise ausgewertet. Die Position wird nur geschlossen, wenn alle Exit-Filter ein entgegengesetztes Signal bestätigen.
Stop-Loss- und Take-Profit-Schutz wird automatisch mit StartProtection installiert, wobei Pip-Eingaben in absolute Preisabstände basierend auf der Tick-Größe des Symbols umgerechnet werden.
Geldmanagement
Nach einem gewinnbringenden Trade kehrt die nächste Order zum Basis-Volume zurück.
Nach einem Verlust-Trade wird das Volumen mit LotMultiplier multipliziert, entsprechend der Lot-Eskalationslogik des ursprünglichen EA.
Exchange-Volumensgrenzen (Schritt, Min. und Max.) werden vor jeder Order durchgesetzt.
Hinweise und Unterschiede zur MetaTrader-Version
Indikatorpreisquellen werden StockSharp-Äquivalenten zugeordnet. CCI verwendet intern den typischen Preis und gleitende Durchschnitte verwenden die ausgewählte MaPrice-Quelle.
Alle Indikatorberechnungen basieren auf vollständig geschlossenen Kerzen. Dies vermeidet teilweise geformte Daten und imitiert die "neue Bar"-Verarbeitung des EA.
Freeze-Level-Prüfungen und manuelle SL/TP-Preisplatzierung werden von StockSharp's StartProtection-Dienst behandelt.
Partielle Positions-Exits aktualisieren den Verlustverfolgungsstatus nur, wenn die gesamte Position flat ist, entsprechend der DEAL_ENTRY_OUT-Logik des EA.
Verwendungshinweise
Beginnen Sie mit der Originalkonfiguration (MA-Filter aktiviert, andere Filter deaktiviert), um das Basisverhalten zu reproduzieren, und aktivieren Sie dann zusätzliche Filter, um die Signalqualität zu verbessern.
Überwachen Sie die Kontoexposition bei hohen LotMultiplier-Werten; das Risiko wächst schnell während Verlustserien.
Kombinieren Sie die Strategie mit dem Backtester, um zu überprüfen, ob Ihre gewählte Filterkombination zu den Instrumenten passt, die Sie handeln möchten.
Diese Strategie hat aktuell keine Python-Version.
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>
/// Lego EA multi-indicator trend following strategy using SMA crossover.
/// Buys when fast SMA crosses above slow SMA, sells on reverse.
/// </summary>
public class LegoEaStrategy : Strategy
{
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private readonly StrategyParam<int> _stopLossPoints;
private readonly StrategyParam<int> _takeProfitPoints;
private SimpleMovingAverage _fast;
private SimpleMovingAverage _slow;
private decimal _prevFast;
private decimal _prevSlow;
private decimal _entryPrice;
private int _cooldown;
/// <summary>
/// Fast SMA period.
/// </summary>
public int FastPeriod
{
get => _fastPeriod.Value;
set => _fastPeriod.Value = value;
}
/// <summary>
/// Slow SMA period.
/// </summary>
public int SlowPeriod
{
get => _slowPeriod.Value;
set => _slowPeriod.Value = value;
}
/// <summary>
/// Stop-loss distance in price steps.
/// </summary>
public int StopLossPoints
{
get => _stopLossPoints.Value;
set => _stopLossPoints.Value = value;
}
/// <summary>
/// Take-profit distance in price steps.
/// </summary>
public int TakeProfitPoints
{
get => _takeProfitPoints.Value;
set => _takeProfitPoints.Value = value;
}
/// <summary>
/// Initializes a new instance of the <see cref="LegoEaStrategy"/> class.
/// </summary>
public LegoEaStrategy()
{
_fastPeriod = Param(nameof(FastPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("Fast Period", "Fast SMA period", "Indicator");
_slowPeriod = Param(nameof(SlowPeriod), 67)
.SetGreaterThanZero()
.SetDisplay("Slow Period", "Slow SMA 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");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
yield return (Security, TimeSpan.FromMinutes(5).TimeFrame());
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_fast = null;
_slow = null;
_prevFast = 0;
_prevSlow = 0;
_entryPrice = 0;
_cooldown = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_fast = new SimpleMovingAverage { Length = FastPeriod };
_slow = new SimpleMovingAverage { 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;
// Check SL/TP
if (Position > 0 && _entryPrice > 0)
{
if (StopLossPoints > 0 && close <= _entryPrice - StopLossPoints * step)
{
SellMarket();
_entryPrice = 0;
_cooldown = 80;
_prevFast = fastValue;
_prevSlow = slowValue;
return;
}
if (TakeProfitPoints > 0 && close >= _entryPrice + TakeProfitPoints * step)
{
SellMarket();
_entryPrice = 0;
_cooldown = 80;
_prevFast = fastValue;
_prevSlow = slowValue;
return;
}
}
else if (Position < 0 && _entryPrice > 0)
{
if (StopLossPoints > 0 && close >= _entryPrice + StopLossPoints * step)
{
BuyMarket();
_entryPrice = 0;
_cooldown = 80;
_prevFast = fastValue;
_prevSlow = slowValue;
return;
}
if (TakeProfitPoints > 0 && close <= _entryPrice - TakeProfitPoints * step)
{
BuyMarket();
_entryPrice = 0;
_cooldown = 80;
_prevFast = fastValue;
_prevSlow = slowValue;
return;
}
}
// SMA crossover
if (_prevFast <= _prevSlow && fastValue > slowValue && Position <= 0)
{
if (Position < 0)
BuyMarket();
BuyMarket();
_entryPrice = close;
_cooldown = 80;
}
else if (_prevFast >= _prevSlow && fastValue < slowValue && Position >= 0)
{
if (Position > 0)
SellMarket();
SellMarket();
_entryPrice = close;
_cooldown = 80;
}
_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 SimpleMovingAverage
from StockSharp.Algo.Strategies import Strategy
class lego_ea_strategy(Strategy):
"""
Lego EA: SMA crossover with SL/TP in price steps and cooldown.
"""
def __init__(self):
super(lego_ea_strategy, self).__init__()
self._fast_period = self.Param("FastPeriod", 14) \
.SetDisplay("Fast Period", "Fast SMA period", "Indicator")
self._slow_period = self.Param("SlowPeriod", 67) \
.SetDisplay("Slow Period", "Slow SMA 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._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))) \
.SetDisplay("Candle Type", "Type of candles", "General")
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
self._cooldown = 0
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(lego_ea_strategy, self).OnReseted()
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
self._cooldown = 0
def OnStarted2(self, time):
super(lego_ea_strategy, self).OnStarted2(time)
fast = SimpleMovingAverage()
fast.Length = self._fast_period.Value
slow = SimpleMovingAverage()
slow.Length = self._slow_period.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(fast, slow, self._process_candle).Start()
def _process_candle(self, candle, fast_val, slow_val):
if candle.State != CandleStates.Finished:
return
fast = float(fast_val)
slow = float(slow_val)
if self._cooldown > 0:
self._cooldown -= 1
self._prev_fast = fast
self._prev_slow = slow
return
close = float(candle.ClosePrice)
step = 1.0
if self.Security is not None and self.Security.PriceStep is not None:
step = float(self.Security.PriceStep)
if step <= 0:
step = 1.0
sl = self._stop_loss_points.Value
tp = self._take_profit_points.Value
if self.Position > 0 and self._entry_price > 0:
if sl > 0 and close <= self._entry_price - sl * step:
self.SellMarket()
self._entry_price = 0
self._cooldown = 80
self._prev_fast = fast
self._prev_slow = slow
return
if tp > 0 and close >= self._entry_price + tp * step:
self.SellMarket()
self._entry_price = 0
self._cooldown = 80
self._prev_fast = fast
self._prev_slow = slow
return
elif self.Position < 0 and self._entry_price > 0:
if sl > 0 and close >= self._entry_price + sl * step:
self.BuyMarket()
self._entry_price = 0
self._cooldown = 80
self._prev_fast = fast
self._prev_slow = slow
return
if tp > 0 and close <= self._entry_price - tp * step:
self.BuyMarket()
self._entry_price = 0
self._cooldown = 80
self._prev_fast = fast
self._prev_slow = slow
return
if self._prev_fast <= self._prev_slow and fast > slow and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
self._entry_price = close
self._cooldown = 80
elif self._prev_fast >= self._prev_slow and fast < slow and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._entry_price = close
self._cooldown = 80
self._prev_fast = fast
self._prev_slow = slow
def CreateClone(self):
return lego_ea_strategy()