El Gestor Breakeven V3 es una conversión del asesor experto de MetaTrader 5 Breakeven v3 (edición de barabashkakvn).
El script original no abre trades. En cambio, calcula continuamente el nivel de break-even del portfolio para el
símbolo seleccionado y mueve las órdenes de protección (stop-loss o take-profit) para cada posición larga y corta abierta
de modo que todo el libro se cierre alrededor de ese precio de break-even con un buffer opcional.
Lógica de la estrategia
Reconstrucción del break-even – cada vez que se ejecuta un trade o llegan nuevas cotizaciones, la estrategia reconstruye el
precio promedio ponderado de apertura para la exposición larga y corta por separado. Incluye las comisiones por posición que StockSharp
informa en los objetos MyTrade para reflejar la implementación MQL.
Cálculo del precio objetivo – el precio de break-even se desplaza por Delta (points) puntos MetaTrader. El desplazamiento se
agrega cuando la exposición neta es larga y se resta cuando es corta, replicando el parámetro "Delta" original.
Colocación de órdenes de protección –
Cuando la exposición neta es larga, se coloca un sell limit de take-profit para el volumen largo total y un buy stop
de stop-loss se adjunta al volumen corto agregado al mismo precio.
Cuando la exposición neta es corta, se coloca un buy limit de take-profit para el volumen corto completo y un sell stop
de stop-loss protege cualquier cobertura larga.
Si ambos lados están planos, todas las órdenes de protección se cancelan.
Monitoreo de cotizaciones y diagnósticos – la estrategia se suscribe a actualizaciones de Nivel 1. El bid/ask más reciente se usa para
calcular estadísticas de distancia al objetivo y un beneficio flotante estimado. Cuando Enable Logging es true, estos valores
se escriben en el log de la estrategia para emular los comentarios en gráfico de la versión MQL.
Parámetros
Delta (points) – offset aplicado al precio de break-even calculado. El valor se expresa en puntos MetaTrader,
es decir, una décima de pip en símbolos FX de cinco dígitos. Por defecto: 100.
Enable Logging – activa la salida de log detallada describiendo el nivel de break-even actual, la distancia al objetivo y
el PnL flotante. Por defecto: true.
Notas de uso
La estrategia es un gestor de trades. Debe lanzarse sobre una estrategia existente o posición manual. No
abrirá órdenes de mercado por sí misma.
Al inicio el código inspecciona el portfolio y reconstruye un lote sintético para cada lado de la posición usando
el precio promedio informado por StockSharp. Para mayor precisión, mantener la estrategia en ejecución cuando se abren nuevos trades.
Los cargos de swap no están disponibles desde StockSharp, por lo que solo se incluye la información de comisión al reconstruir
el precio de break-even. Si el broker aplica swaps nocturnos, deben manejarse manualmente.
El script asume que la cuenta permite cobertura (posiciones largas y cortas simultáneas). Si el broker neta posiciones,
los agregados largo y corto se reducirán a una única exposición neta igual que en MetaTrader.
No hay versión Python de este port. Solo se proporciona la implementación C#.
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()