Die EES Hedger-Strategie spiegelt das Verhalten des klassischen MetaTrader Expert Advisors, der automatisch Positionen absichert, die von einem anderen Handelssystem oder von manuellen Tradern eröffnet wurden. Sobald das überwachte Konto eine Position eröffnet, die dem konfigurierten Filter entspricht, eröffnet die Strategie sofort eine Gegenposition mit eigenen Parametern. Dadurch wird das gerichtete Exposure neutralisiert, während der ursprüngliche Trade weiterläuft.
Der Algorithmus basiert auf der High-Level-StockSharp-API. Er überwacht Kontotrades, eröffnet Hedge-Positionen und verwaltet Schutzorders durch Stop-Loss-, Take-Profit- und Trailing-Stop-Logik. Das Trailing-Management folgt der Originalimplementierung eng und rückt den Stop nur dann vor, wenn die Preisbewegung sowohl die Stop-Distanz als auch das Trailing-Inkrement überschreitet.
Parameter
Name
Beschreibung
HedgeVolume
Fixes Volumen für die Hedge-Order. Hängt nicht von der externen Tradegröße ab.
StopLossPips
Abstand in Pips für den Schutz-Stop-Loss des Hedges. Auf null setzen, um den anfänglichen Stop zu überspringen.
TakeProfitPips
Abstand in Pips für die Take-Profit-Order. Auf null setzen, um das Ziel wegzulassen.
TrailingStopPips
Abstand in Pips, der für das Trailing verwendet wird, sobald sich der Preis günstig bewegt.
TrailingStepPips
Minimale Pip-Bewegung, die erforderlich ist, bevor der Trailing Stop erneut bewegt wird. Muss positiv sein, wenn Trailing aktiv ist.
OriginalOrderComment
Optionaler Kommentarfilter. Nur Trades, deren Kommentar mit diesem Wert übereinstimmt (Groß-/Kleinschreibung wird ignoriert), werden abgesichert. Leer lassen, um auf jeden Trade zu reagieren.
HedgerOrderComment
Optionaler Kommentar zur Identifizierung der eigenen Hedge-Trades der Strategie. Wenn angegeben, werden Trades mit demselben Kommentar ignoriert, um erneutes Hedging zu vermeiden.
Verhalten
Trade-Erkennung – die Strategie abonniert NewMyTrade-Ereignisse des Connectors. Jeder Trade, der vom ausgewählten Instrument kommt und die Kommentarfilter passiert, wird als externes Einstiegssignal behandelt.
Hedge-Ausführung – sobald ein qualifizierender Trade gesehen wird, sendet die Strategie eine Marktorder in der Gegenrichtung mit HedgeVolume.
Schutz-Setup – nach jeder eigenen Füllung storniert der Algorithmus bestehende Schutzorders und registriert neue Stop-Loss- und Take-Profit-Orders gemäß dem aktuellen durchschnittlichen Positionspreis.
Trailing Stop – jedes eingehende Trade-Tick wird zur Auswertung der Trailing-Regeln verwendet. Sobald sich der Preis um mindestens TrailingStopPips + TrailingStepPips zugunsten des Hedges bewegt hat, wird der Stop näher an den Preis gerückt. Bei Long-Positionen folgt der Stop unter dem Markt, bei Shorts über ihm.
Positions-Reset – wenn die Hedge-Position vollständig geschlossen ist (z. B. durch Stop oder Ziel), storniert die Strategie automatisch die verbleibenden Schutzorders und wartet auf den nächsten externen Trade.
Verwendungshinweise
Die Strategie setzt voraus, dass der Konto-Connector alle Kontotrades meldet, einschließlich der von anderen Systemen generierten.
Die Pip-Berechnung passt sich dem Instrument-Preisschritt an und multipliziert bei 3- oder 5-stelligen Kursen mit zehn, um die MQL-Punktanpassung nachzuahmen.
OriginalOrderComment so einstellen, dass er mit dem Kommentar des Primärsystems übereinstimmt, wenn nur bestimmte Trades gespiegelt werden sollen. Beim Absichern manueller Trades leer lassen.
Sicherstellen, dass TrailingStepPips größer als null bleibt, wann immer Trailing aktiviert ist, um vorzeitige Beendigung beim Start zu vermeiden.
Da der Hedger immer ein festes Volumen verwendet, empfiehlt es sich, HedgeVolume so anzupassen, dass der Hedge das durchschnittliche Exposure des Primärsystems abdeckt.
using System;
using System.Linq;
using System.Collections.Generic;
using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
using System.Globalization;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Mirrors trades by opening an opposite hedge position with trailing stop management.
/// Simplified from the EES Hedger expert advisor.
/// </summary>
public class EesHedgerStrategy : Strategy
{
private readonly StrategyParam<decimal> _hedgeVolume;
private readonly StrategyParam<int> _stopLossPips;
private readonly StrategyParam<int> _takeProfitPips;
private readonly StrategyParam<int> _trailingStopPips;
private readonly StrategyParam<int> _trailingStepPips;
private readonly StrategyParam<DataType> _candleType;
private decimal _entryPrice;
private decimal? _stopPrice;
private decimal _pipSize;
/// <summary>
/// Hedge position volume.
/// </summary>
public decimal HedgeVolume
{
get => _hedgeVolume.Value;
set => _hedgeVolume.Value = value;
}
/// <summary>
/// Stop-loss distance in pips.
/// </summary>
public int StopLossPips
{
get => _stopLossPips.Value;
set => _stopLossPips.Value = value;
}
/// <summary>
/// Take-profit distance in pips.
/// </summary>
public int TakeProfitPips
{
get => _takeProfitPips.Value;
set => _takeProfitPips.Value = value;
}
/// <summary>
/// Trailing stop distance in pips.
/// </summary>
public int TrailingStopPips
{
get => _trailingStopPips.Value;
set => _trailingStopPips.Value = value;
}
/// <summary>
/// Minimum step between trailing stop updates in pips.
/// </summary>
public int TrailingStepPips
{
get => _trailingStepPips.Value;
set => _trailingStepPips.Value = value;
}
/// <summary>
/// Initializes strategy parameters.
/// </summary>
public EesHedgerStrategy()
{
_hedgeVolume = Param(nameof(HedgeVolume), 0.1m)
.SetDisplay("Hedge Volume", "Volume used for hedge orders", "General");
_stopLossPips = Param(nameof(StopLossPips), 50)
.SetDisplay("Stop Loss (pips)", "Stop-loss distance per hedge", "Risk Management");
_takeProfitPips = Param(nameof(TakeProfitPips), 50)
.SetDisplay("Take Profit (pips)", "Take-profit distance per hedge", "Risk Management");
_trailingStopPips = Param(nameof(TrailingStopPips), 25)
.SetDisplay("Trailing Stop (pips)", "Trailing stop distance", "Risk Management");
_trailingStepPips = Param(nameof(TrailingStepPips), 5)
.SetDisplay("Trailing Step (pips)", "Minimum trailing stop increment", "Risk Management");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Time frame for processing", "General");
}
/// <summary>
/// Candle type used for processing.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
yield return (Security, CandleType);
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_entryPrice = 0m;
_stopPrice = null;
_pipSize = 0m;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_pipSize = CalculatePipSize();
var subscription = SubscribeCandles(CandleType);
subscription.Bind(ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
var price = candle.ClosePrice;
if (price <= 0m)
return;
// Entry: if no position, open based on tick direction
if (Position == 0 && _entryPrice == 0m)
{
var volume = HedgeVolume > 0m ? HedgeVolume : Volume;
if (volume <= 0m)
return;
BuyMarket();
_entryPrice = price;
_stopPrice = null;
return;
}
if (Position != 0 && _entryPrice == 0m)
_entryPrice = price;
// Check stop loss
if (Position != 0 && StopLossPips > 0 && _pipSize > 0m)
{
var stopDistance = StopLossPips * _pipSize;
if (Position > 0 && price <= _entryPrice - stopDistance)
{
SellMarket();
_entryPrice = 0m;
_stopPrice = null;
return;
}
else if (Position < 0 && price >= _entryPrice + stopDistance)
{
BuyMarket();
_entryPrice = 0m;
_stopPrice = null;
return;
}
}
// Check take profit
if (Position != 0 && TakeProfitPips > 0 && _pipSize > 0m)
{
var takeDistance = TakeProfitPips * _pipSize;
if (Position > 0 && price >= _entryPrice + takeDistance)
{
SellMarket();
_entryPrice = 0m;
_stopPrice = null;
return;
}
else if (Position < 0 && price <= _entryPrice - takeDistance)
{
BuyMarket();
_entryPrice = 0m;
_stopPrice = null;
return;
}
}
// Trailing stop
if (Position != 0 && TrailingStopPips > 0 && _pipSize > 0m)
{
var trailingDistance = TrailingStopPips * _pipSize;
var trailingStep = TrailingStepPips * _pipSize;
if (Position > 0)
{
var newStop = price - trailingDistance;
if (newStop > _entryPrice && (!_stopPrice.HasValue || newStop > _stopPrice.Value + trailingStep))
_stopPrice = newStop;
if (_stopPrice.HasValue && price <= _stopPrice.Value)
{
SellMarket();
_entryPrice = 0m;
_stopPrice = null;
}
}
else if (Position < 0)
{
var newStop = price + trailingDistance;
if (newStop < _entryPrice && (!_stopPrice.HasValue || newStop < _stopPrice.Value - trailingStep))
_stopPrice = newStop;
if (_stopPrice.HasValue && price >= _stopPrice.Value)
{
BuyMarket();
_entryPrice = 0m;
_stopPrice = null;
}
}
}
}
private decimal CalculatePipSize()
{
var step = Security?.PriceStep ?? 0m;
if (step <= 0m)
return 1m;
var decimals = GetDecimalPlaces(step);
return decimals == 3 || decimals == 5 ? step * 10m : step;
}
private static int GetDecimalPlaces(decimal value)
{
var text = Math.Abs(value).ToString(CultureInfo.InvariantCulture);
var index = text.IndexOf('.');
return index >= 0 ? text.Length - index - 1 : 0;
}
}
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.Strategies import Strategy
class ees_hedger_strategy(Strategy):
"""Hedge strategy with trailing stop management."""
def __init__(self):
super(ees_hedger_strategy, self).__init__()
self._hedge_volume = self.Param("HedgeVolume", 0.1) \
.SetDisplay("Hedge Volume", "Volume used for hedge orders", "General")
self._stop_loss_pips = self.Param("StopLossPips", 50) \
.SetDisplay("Stop Loss (pips)", "Stop-loss distance per hedge", "Risk Management")
self._take_profit_pips = self.Param("TakeProfitPips", 50) \
.SetDisplay("Take Profit (pips)", "Take-profit distance per hedge", "Risk Management")
self._trailing_stop_pips = self.Param("TrailingStopPips", 25) \
.SetDisplay("Trailing Stop (pips)", "Trailing stop distance", "Risk Management")
self._trailing_step_pips = self.Param("TrailingStepPips", 5) \
.SetDisplay("Trailing Step (pips)", "Minimum trailing stop increment", "Risk Management")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Time frame for processing", "General")
self._entry_price = 0.0
self._stop_price = None
self._pip_size = 1.0
@property
def HedgeVolume(self):
return self._hedge_volume.Value
@property
def StopLossPips(self):
return self._stop_loss_pips.Value
@property
def TakeProfitPips(self):
return self._take_profit_pips.Value
@property
def TrailingStopPips(self):
return self._trailing_stop_pips.Value
@property
def TrailingStepPips(self):
return self._trailing_step_pips.Value
@property
def CandleType(self):
return self._candle_type.Value
def _calc_pip_size(self):
sec = self.Security
if sec is None or sec.PriceStep is None or float(sec.PriceStep) <= 0:
return 1.0
step = float(sec.PriceStep)
decimals = sec.Decimals if sec.Decimals is not None else 0
if decimals == 3 or decimals == 5:
return step * 10.0
return step
def OnStarted2(self, time):
super(ees_hedger_strategy, self).OnStarted2(time)
self._pip_size = self._calc_pip_size()
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(self.process_candle).Start()
def process_candle(self, candle):
if candle.State != CandleStates.Finished:
return
price = float(candle.ClosePrice)
if price <= 0:
return
# Entry: if no position, open buy
if self.Position == 0 and self._entry_price == 0:
self.BuyMarket()
self._entry_price = price
self._stop_price = None
return
if self.Position != 0 and self._entry_price == 0:
self._entry_price = price
# Stop loss check
if self.Position != 0 and self.StopLossPips > 0 and self._pip_size > 0:
stop_dist = self.StopLossPips * self._pip_size
if self.Position > 0 and price <= self._entry_price - stop_dist:
self.SellMarket()
self._entry_price = 0.0
self._stop_price = None
return
elif self.Position < 0 and price >= self._entry_price + stop_dist:
self.BuyMarket()
self._entry_price = 0.0
self._stop_price = None
return
# Take profit check
if self.Position != 0 and self.TakeProfitPips > 0 and self._pip_size > 0:
take_dist = self.TakeProfitPips * self._pip_size
if self.Position > 0 and price >= self._entry_price + take_dist:
self.SellMarket()
self._entry_price = 0.0
self._stop_price = None
return
elif self.Position < 0 and price <= self._entry_price - take_dist:
self.BuyMarket()
self._entry_price = 0.0
self._stop_price = None
return
# Trailing stop
if self.Position != 0 and self.TrailingStopPips > 0 and self._pip_size > 0:
trail_dist = self.TrailingStopPips * self._pip_size
trail_step = self.TrailingStepPips * self._pip_size
if self.Position > 0:
new_stop = price - trail_dist
if new_stop > self._entry_price and (self._stop_price is None or new_stop > self._stop_price + trail_step):
self._stop_price = new_stop
if self._stop_price is not None and price <= self._stop_price:
self.SellMarket()
self._entry_price = 0.0
self._stop_price = None
elif self.Position < 0:
new_stop = price + trail_dist
if new_stop < self._entry_price and (self._stop_price is None or new_stop < self._stop_price - trail_step):
self._stop_price = new_stop
if self._stop_price is not None and price >= self._stop_price:
self.BuyMarket()
self._entry_price = 0.0
self._stop_price = None
def OnReseted(self):
super(ees_hedger_strategy, self).OnReseted()
self._entry_price = 0.0
self._stop_price = None
self._pip_size = 1.0
def CreateClone(self):
return ees_hedger_strategy()