Converts the MQL5 utility Close all positions into a StockSharp high-level strategy.
Watches finished candles of the configured timeframe and accumulates the floating profit of every open position across the assigned portfolio.
When the floating profit equals or exceeds the threshold, market orders are sent to flatten all securities handled by the strategy (including child strategies) until the book is fully closed.
The _closeAllRequested flag mirrors the MQL m_close_all variable so that exit orders continue to be issued until no positions remain.
Parameters
Name
Type
Default
Description
ProfitThreshold
decimal
10
Floating profit (in account currency) required before the strategy flattens every open position. Mirrors InpProfit from the EA.
CandleType
DataType
1m timeframe
Candle series that defines the "new bar" moments. The profit check is executed only when a candle finishes, emulating the original PrevBars logic.
Trading Logic
The strategy subscribes to candles of CandleType and processes only finished bars, just like the EA evaluated profit only on a new bar.
On each finished bar the helper CalculateTotalProfit retrieves Portfolio.CurrentProfit (floating PnL including commission and swap). If the adapter cannot provide this value it falls back to summing individual position PnL values.
If the calculated floating profit is below ProfitThreshold, nothing happens.
As soon as the profit meets the threshold, _closeAllRequested is set to true and CloseAllPositions() is executed immediately.
CloseAllPositions() collects every security that has an exposure in the portfolio or in nested strategies and sends market orders in the opposite direction of the current volume (long → sell, short → buy).
The _closeAllRequested flag remains set until HasAnyOpenPosition() detects that the portfolio is flat, matching the MQL behaviour where m_close_all stayed true until all tickets were closed.
Additional Notes
Only the C# implementation is provided; the Python folder is intentionally left empty per the task requirements.
The strategy does not cancel pending orders because the original script only closed market positions.
Use SetOptimize on ProfitThreshold to explore alternative profit targets through the Designer optimizer if needed.
Files
CS/CloseAllPositionsStrategy.cs
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>
/// Opens positions based on SMA trend and closes when floating PnL reaches a profit threshold.
/// Simplified from the "Close all positions" utility expert.
/// </summary>
public class CloseAllPositionsStrategy : Strategy
{
private readonly StrategyParam<int> _smaPeriod;
private readonly StrategyParam<int> _stopLossPoints;
private readonly StrategyParam<int> _takeProfitPoints;
private SimpleMovingAverage _sma;
private decimal _entryPrice;
private decimal _prevSma;
private int _cooldown;
/// <summary>
/// SMA period for entry signals.
/// </summary>
public int SmaPeriod
{
get => _smaPeriod.Value;
set => _smaPeriod.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 strategy parameters.
/// </summary>
public CloseAllPositionsStrategy()
{
_smaPeriod = Param(nameof(SmaPeriod), 100)
.SetGreaterThanZero()
.SetDisplay("SMA Period", "Moving average period for entry signals", "Indicators");
_stopLossPoints = Param(nameof(StopLossPoints), 200)
.SetNotNegative()
.SetDisplay("Stop Loss", "Stop-loss distance in price steps", "Risk");
_takeProfitPoints = Param(nameof(TakeProfitPoints), 300)
.SetNotNegative()
.SetDisplay("Take Profit", "Take-profit distance 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();
_sma = null;
_entryPrice = 0;
_prevSma = 0;
_cooldown = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_sma = new SimpleMovingAverage { Length = SmaPeriod };
var subscription = SubscribeCandles(TimeSpan.FromMinutes(5).TimeFrame());
subscription.Bind(_sma, ProcessCandle);
subscription.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal smaValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!_sma.IsFormed)
{
_prevSma = smaValue;
return;
}
if (_cooldown > 0)
{
_cooldown--;
_prevSma = smaValue;
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 = 60;
_prevSma = smaValue;
return;
}
if (TakeProfitPoints > 0 && close >= _entryPrice + TakeProfitPoints * step)
{
SellMarket();
_entryPrice = 0;
_cooldown = 60;
_prevSma = smaValue;
return;
}
}
else if (Position < 0 && _entryPrice > 0)
{
if (StopLossPoints > 0 && close >= _entryPrice + StopLossPoints * step)
{
BuyMarket();
_entryPrice = 0;
_cooldown = 60;
_prevSma = smaValue;
return;
}
if (TakeProfitPoints > 0 && close <= _entryPrice - TakeProfitPoints * step)
{
BuyMarket();
_entryPrice = 0;
_cooldown = 60;
_prevSma = smaValue;
return;
}
}
// Crossover entry: price crosses above SMA -> buy
if (close > smaValue && candle.OpenPrice <= _prevSma && Position <= 0)
{
if (Position < 0)
BuyMarket();
BuyMarket();
_entryPrice = close;
_cooldown = 60;
}
// Price crosses below SMA -> sell
else if (close < smaValue && candle.OpenPrice >= _prevSma && Position >= 0)
{
if (Position > 0)
SellMarket();
SellMarket();
_entryPrice = close;
_cooldown = 60;
}
_prevSma = smaValue;
}
}
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 close_all_positions_strategy(Strategy):
"""
Opens positions based on SMA trend and closes when SL/TP reached.
"""
def __init__(self):
super(close_all_positions_strategy, self).__init__()
self._sma_period = self.Param("SmaPeriod", 100) \
.SetDisplay("SMA Period", "Moving average period for entry signals", "Indicators")
self._stop_loss_points = self.Param("StopLossPoints", 200) \
.SetDisplay("Stop Loss", "Stop-loss distance in price steps", "Risk")
self._take_profit_points = self.Param("TakeProfitPoints", 300) \
.SetDisplay("Take Profit", "Take-profit distance in price steps", "Risk")
self._entry_price = 0.0
self._prev_sma = 0.0
self._cooldown = 0
@property
def candle_type(self):
return DataType.TimeFrame(TimeSpan.FromMinutes(5))
def OnReseted(self):
super(close_all_positions_strategy, self).OnReseted()
self._entry_price = 0.0
self._prev_sma = 0.0
self._cooldown = 0
def OnStarted2(self, time):
super(close_all_positions_strategy, self).OnStarted2(time)
sma = SimpleMovingAverage()
sma.Length = self._sma_period.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(sma, self.on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, sma)
self.DrawOwnTrades(area)
def on_process(self, candle, sma_val):
if candle.State != CandleStates.Finished:
return
if self._prev_sma == 0.0:
self._prev_sma = sma_val
return
if self._cooldown > 0:
self._cooldown -= 1
self._prev_sma = sma_val
return
close = float(candle.ClosePrice)
open_price = float(candle.OpenPrice)
step = 1.0
if self.Security is not None and self.Security.PriceStep is not None and float(self.Security.PriceStep) > 0:
step = float(self.Security.PriceStep)
if self.Position > 0 and self._entry_price > 0:
if self._stop_loss_points.Value > 0 and close <= self._entry_price - self._stop_loss_points.Value * step:
self.SellMarket()
self._entry_price = 0.0
self._cooldown = 60
self._prev_sma = sma_val
return
if self._take_profit_points.Value > 0 and close >= self._entry_price + self._take_profit_points.Value * step:
self.SellMarket()
self._entry_price = 0.0
self._cooldown = 60
self._prev_sma = sma_val
return
elif self.Position < 0 and self._entry_price > 0:
if self._stop_loss_points.Value > 0 and close >= self._entry_price + self._stop_loss_points.Value * step:
self.BuyMarket()
self._entry_price = 0.0
self._cooldown = 60
self._prev_sma = sma_val
return
if self._take_profit_points.Value > 0 and close <= self._entry_price - self._take_profit_points.Value * step:
self.BuyMarket()
self._entry_price = 0.0
self._cooldown = 60
self._prev_sma = sma_val
return
if close > sma_val and open_price <= self._prev_sma and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
self._entry_price = close
self._cooldown = 60
elif close < sma_val and open_price >= self._prev_sma and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._entry_price = close
self._cooldown = 60
self._prev_sma = sma_val
def CreateClone(self):
return close_all_positions_strategy()