Der Breakeven V3 Manager ist eine Konvertierung des MetaTrader 5 Expertenberaters Breakeven v3 (barabashkakvn's edition).
Das ursprüngliche Skript eröffnet keine Trades. Stattdessen berechnet es kontinuierlich das Portfolio-Break-Even-Level für das
ausgewählte Symbol und verschiebt Schutzorders (Stop-Loss oder Take-Profit) für jede offene Long- und Short-Position,
sodass das gesamte Buch rund um diesen Break-Even-Preis mit einem optionalen Puffer geschlossen wird.
Strategielogik
Break-Even-Rekonstruktion – jedes Mal, wenn ein Trade ausgeführt wird oder neue Kurse eintreffen, rekonstruiert die Strategie den gewichteten
durchschnittlichen Eröffnungspreis für Long- und Short-Exposition separat. Sie berücksichtigt die positions-bezogenen Provisionen, die StockSharp
in den MyTrade-Objekten meldet, um die MQL-Implementierung widerzuspiegeln.
Zielpreisberechnung – der Break-Even-Preis wird um Delta (points) MetaTrader-Punkte verschoben. Die Verschiebung wird
addiert, wenn die Nettoposition long ist, und subtrahiert, wenn sie short ist, und repliziert damit den ursprünglichen "Delta"-Parameter.
Schutzorder-Platzierung –
Wenn die Nettoposition long ist, wird ein Sell-Limit Take-Profit für das gesamte Long-Volumen und ein Buy-Stop
Stop-Loss an das aggregierte Short-Volumen am selben Preis angehängt.
Wenn die Nettoposition short ist, wird ein Buy-Limit Take-Profit für das gesamte Short-Volumen und ein Sell-Stop
Stop-Loss für etwaige Long-Absicherungen platziert.
Wenn beide Seiten flat sind, werden alle Schutzorders storniert.
Kursüberwachung und Diagnose – die Strategie abonniert Level1-Updates. Das neueste Bid/Ask wird verwendet, um
Abstands-zum-Ziel-Statistiken und einen geschätzten schwebenden Gewinn zu berechnen. Wenn Enable Logging true ist, werden diese Werte
in das Strategie-Log geschrieben, um die On-Chart-Kommentare der MQL-Version zu emulieren.
Parameter
Delta (points) – Offset, der auf den berechneten Break-Even-Preis angewendet wird. Der Wert wird in MetaTrader-Punkten ausgedrückt,
d.h. ein Zehntel Pip bei fünfstelligen FX-Symbolen. Standard: 100.
Enable Logging – schaltet die detaillierte Log-Ausgabe um, die das aktuelle Break-Even-Level, den Abstand zum Ziel und
den schwebenden PnL beschreibt. Standard: true.
Verwendungshinweise
Die Strategie ist ein Trade-Manager. Sie sollte auf einer bestehenden Strategie oder manuellen Position aufgesetzt werden. Sie wird
selbst keine Market-Orders öffnen.
Beim Start inspiziert der Code das Portfolio und rekonstruiert ein einzelnes synthetisches Lot für jede Seite der Position unter Verwendung
des von StockSharp gemeldeten Durchschnittspreises. Für beste Genauigkeit die Strategie immer laufen lassen, wenn neue Trades eröffnet werden.
Swap-Gebühren sind von StockSharp nicht verfügbar, daher wird beim Neuaufbau des Break-Even-Preises nur die Provisionsinfo berücksichtigt.
Falls der Broker Overnight-Swaps anwendet, müssen diese manuell behandelt werden.
Das Skript setzt voraus, dass das Konto Hedging (gleichzeitige Long- und Short-Positionen) erlaubt. Wenn der Broker Positionen nettet,
reduzieren sich die Long- und Short-Aggregate genau wie in MetaTrader auf eine einzelne Nettoexposition.
Es gibt keine Python-Version dieses Ports. Nur die C#-Implementierung wird bereitgestellt.
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()