The Lego EA Strategy is a direct port of the MetaTrader "Lego EA" expert advisor. It uses a configurable combination of technical filters—Commodity Channel Index, dual moving averages, stochastic oscillator, Accelerator Oscillator, DeMarker and Awesome Oscillator—to validate entries and exits. Each filter can be toggled on or off independently for entries and exits, allowing you to rebuild the original "Lego" block-by-block or experiment with custom setups.
Parameters
Volume – base trading volume used when the previous trade was profitable.
LotMultiplier – multiplier applied to the last executed volume after a losing trade (martingale-style recovery).
StopLossPips – protective stop expressed in pips (converted internally using the symbol’s tick size).
TakeProfitPips – profit target in pips.
UseCciForEntry / UseCciForExit – enable the CCI filter when opening or closing positions.
UseMaForEntry / UseMaForExit – use the fast/slow moving-average crossover for confirmations.
CandleType – timeframe of the candle series used by all indicators.
Trading workflow
On every completed candle the strategy collects indicator values from the selected filters.
Each filter computes buy/sell readiness based on the previous fully formed bar (matching the original EA’s iGetArray(..., 1) offset).
A long entry is permitted only when all enabled entry filters agree on a bullish signal. Likewise, a short entry requires unanimous bearish confirmation.
If the account is flat and a valid entry signal appears, a market order is sent using either the base Volume or the last losing trade volume multiplied by LotMultiplier.
When already in position, the enabled exit filters are evaluated the same way. The position is closed only when all exit filters agree on an opposing signal.
Stop-loss and take-profit protection is automatically installed using StartProtection, converting pip inputs into absolute price distances based on the symbol’s tick size.
Money management
After a winning trade the next order reverts to the base Volume.
After a losing trade the volume is multiplied by LotMultiplier, emulating the original EA’s lot escalation logic.
Exchange-imposed volume bounds (step, min and max) are enforced before each order.
Notes and differences vs. MetaTrader version
Indicator price sources map to StockSharp equivalents. CCI uses the typical price internally and moving averages use the selected MaPrice source.
All indicator calculations rely on fully closed candles. This avoids partially formed data and mimics the EA’s "new bar" processing.
Freeze-level checks and manual SL/TP price placement are handled by StockSharp’s StartProtection service.
Partial position exits update the loss-tracking state only when the entire position is flat, matching the EA’s DEAL_ENTRY_OUT logic.
Usage tips
Start with the original configuration (MA filter enabled, other filters disabled) to reproduce baseline behaviour, then enable additional filters to tighten signal quality.
Monitor account exposure when using high LotMultiplier values; risk grows quickly during streaks of losses.
Combine the strategy with the Backtester to confirm whether your chosen filter mix aligns with the instruments you plan to trade.
This strategy currently has no 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()