Breakeven v3 Manager is a conversion of the MetaTrader 5 expert advisor Breakeven v3 (barabashkakvn's edition).
The original script does not open trades. Instead it continuously computes the portfolio break-even level for the
selected symbol and moves protective orders (stop-loss or take-profit) for every open long and short position
so that the whole book is closed around that break-even price with an optional buffer.
Strategy logic
Break-even reconstruction – each time a trade fills or new quotes arrive, the strategy rebuilds the weighted
average open price for long and short exposure separately. It includes the per-position commissions that StockSharp
reports in the MyTrade objects to mirror the MQL implementation.
Target price calculation – the break-even price is shifted by Delta (points) MetaTrader points. The shift is
added when the net exposure is long and subtracted when it is short, replicating the original "Delta" parameter.
Protective order placement –
When the net exposure is long, a sell limit take-profit is placed for the total long volume and a buy stop
stop-loss is attached to the aggregate short volume at the same price.
When the net exposure is short, a buy limit take-profit is placed for the full short volume and a sell stop
stop-loss protects any long hedges.
If both sides are flat, all protective orders are cancelled.
Quote monitoring and diagnostics – the strategy subscribes to Level1 updates. The latest bid/ask are used to
compute distance-to-target statistics and an estimated floating profit. When Enable Logging is true these values
are written to the strategy log to emulate the on-chart comments of the MQL version.
Parameters
Delta (points) – offset applied to the calculated break-even price. The value is expressed in MetaTrader points,
i.e. one-tenth of a pip on five-digit FX symbols. Default: 100.
Enable Logging – toggles detailed log output describing the current break-even level, distance to target and
floating PnL. Default: true.
Usage notes
The strategy is a trade manager. It should be launched on top of an existing strategy or manual position. It will not
open market orders by itself.
On start the code inspects the portfolio and reconstructs a single synthetic lot for each side of the position using
the average price reported by StockSharp. For best accuracy keep the strategy running whenever new trades are opened.
Swap charges are not available from StockSharp, therefore only the commission information is included when rebuilding
the break-even price. If the broker applies overnight swaps they must be handled manually.
The script assumes the account allows hedging (simultaneous long and short positions). If the broker nets positions,
the long and short aggregates will reduce to a single net exposure just like in MetaTrader.
There is no Python version of this port. Only the C# implementation is provided.
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>
/// Break-even management strategy that enters on EMA crossover and moves
/// the exit level to break-even once price moves a configurable distance in favor.
/// </summary>
public class BreakevenV3Strategy : Strategy
{
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private readonly StrategyParam<int> _activationPoints;
private readonly StrategyParam<int> _deltaPoints;
private ExponentialMovingAverage _fast;
private ExponentialMovingAverage _slow;
private decimal _prevFast;
private decimal _prevSlow;
private decimal _entryPrice;
private decimal _breakEvenPrice;
private bool _breakEvenActivated;
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 ActivationPoints { get => _activationPoints.Value; set => _activationPoints.Value = value; }
public int DeltaPoints { get => _deltaPoints.Value; set => _deltaPoints.Value = value; }
public BreakevenV3Strategy()
{
_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");
_activationPoints = Param(nameof(ActivationPoints), 200).SetNotNegative().SetDisplay("Activation", "Distance price must move before break-even activates", "Risk");
_deltaPoints = Param(nameof(DeltaPoints), 100).SetNotNegative().SetDisplay("Delta", "Offset from entry for break-even stop", "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; _breakEvenPrice = 0;
_breakEvenActivated = false; _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;
// Manage break-even for open position
if (Position != 0 && _entryPrice > 0)
{
var activationDistance = ActivationPoints * step;
var deltaOffset = DeltaPoints * step;
if (Position > 0)
{
if (!_breakEvenActivated && activationDistance > 0 && close >= _entryPrice + activationDistance)
{
_breakEvenActivated = true;
_breakEvenPrice = _entryPrice + deltaOffset;
}
if (_breakEvenActivated && close <= _breakEvenPrice)
{
SellMarket();
_entryPrice = 0; _breakEvenPrice = 0; _breakEvenActivated = false;
_cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue;
return;
}
}
else if (Position < 0)
{
if (!_breakEvenActivated && activationDistance > 0 && close <= _entryPrice - activationDistance)
{
_breakEvenActivated = true;
_breakEvenPrice = _entryPrice - deltaOffset;
}
if (_breakEvenActivated && close >= _breakEvenPrice)
{
BuyMarket();
_entryPrice = 0; _breakEvenPrice = 0; _breakEvenActivated = false;
_cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue;
return;
}
}
}
// Entry: EMA crossover
if (_prevFast <= _prevSlow && fastValue > slowValue && Position <= 0)
{
if (Position < 0) BuyMarket();
BuyMarket();
_entryPrice = close; _breakEvenActivated = false; _cooldown = 100;
}
else if (_prevFast >= _prevSlow && fastValue < slowValue && Position >= 0)
{
if (Position > 0) SellMarket();
SellMarket();
_entryPrice = close; _breakEvenActivated = false; _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 breakeven_v3_strategy(Strategy):
def __init__(self):
super(breakeven_v3_strategy, self).__init__()
self._fast_period = self.Param("FastPeriod", 14) \
.SetDisplay("Fast Period", "Fast EMA period", "Indicator")
self._slow_period = self.Param("SlowPeriod", 50) \
.SetDisplay("Slow Period", "Slow EMA period", "Indicator")
self._activation_points = self.Param("ActivationPoints", 200) \
.SetDisplay("Activation", "Distance price must move before break-even activates", "Risk")
self._delta_points = self.Param("DeltaPoints", 100) \
.SetDisplay("Delta", "Offset from entry for break-even stop", "Risk")
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
self._break_even_price = 0.0
self._break_even_activated = False
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 activation_points(self):
return self._activation_points.Value
@property
def delta_points(self):
return self._delta_points.Value
def OnReseted(self):
super(breakeven_v3_strategy, self).OnReseted()
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
self._break_even_price = 0.0
self._break_even_activated = False
self._cooldown = 0
def OnStarted2(self, time):
super(breakeven_v3_strategy, self).OnStarted2(time)
fast = ExponentialMovingAverage()
fast.Length = self.fast_period
slow = ExponentialMovingAverage()
slow.Length = self.slow_period
subscription = self.SubscribeCandles(DataType.TimeFrame(TimeSpan.FromMinutes(5)))
subscription.Bind(fast, slow, self.OnProcess).Start()
def OnProcess(self, candle, fast_value, slow_value):
if candle.State != CandleStates.Finished:
return
fast_val = float(fast_value)
slow_val = float(slow_value)
if fast_val == 0 or slow_val == 0:
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.PriceStep is not None else 1.0
if self.Position != 0 and self._entry_price > 0:
activation_distance = float(self.activation_points) * step
delta_offset = float(self.delta_points) * step
if self.Position > 0:
if not self._break_even_activated and activation_distance > 0 and close >= self._entry_price + activation_distance:
self._break_even_activated = True
self._break_even_price = self._entry_price + delta_offset
if self._break_even_activated and close <= self._break_even_price:
self.SellMarket()
self._entry_price = 0.0
self._break_even_price = 0.0
self._break_even_activated = False
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
elif self.Position < 0:
if not self._break_even_activated and activation_distance > 0 and close <= self._entry_price - activation_distance:
self._break_even_activated = True
self._break_even_price = self._entry_price - delta_offset
if self._break_even_activated and close >= self._break_even_price:
self.BuyMarket()
self._entry_price = 0.0
self._break_even_price = 0.0
self._break_even_activated = False
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._break_even_activated = False
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._break_even_activated = False
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
def CreateClone(self):
return breakeven_v3_strategy()