Die Strategie repliziert den MetaTrader OverHedge V2-Expertenberater auf der StockSharp High-Level-API. Sie baut ein gehedgtes Grid auf, indem sie der Richtung eines schnellen und eines langsamen EMA folgt, und wechselt dann zwischen Long- und Short-Orders innerhalb eines dynamischen Tunnels. Positionen werden gemäß einer geometrischen Lot-Progression hinzugefügt und der gesamte Korb wird liquidiert, sobald der aggregierte unrealisierte Gewinn das konfigurierte Ziel erreicht.
Handelslogik
Trend-Filter: Ein 8-Perioden-EMA muss mindestens MinDistancePips vom 21-Perioden-EMA abweichen. Der Filter entscheidet die Richtung des ersten Trades in jedem Zyklus.
Grid-Tunnel: Die Tunnelbreite entspricht dem aktuellen Spread multipliziert mit zwei plus TunnelWidthPips in Preiseinheiten umgerechnet. Sie definiert den Trigger der Gegenseite, sobald der Zyklus beginnt.
Order-Alternation: Die ersten drei Positionen werden in Trendrichtung eröffnet. Danach wechselt der Algorithmus die Seite, um die Exposition zu hedgen, wobei dieselben Tunnel-Anker als Referenz verwendet werden.
Lot-Eskalation: Jede nachfolgende Order multipliziert das vorherige Volumen mit BaseMultiplier, beginnend bei StartVolume. Die Größe wird auf die Volumenbeschränkungen des Instruments ausgerichtet.
Zyklusausstieg: Wenn der unrealisierte Nettogewinn pro Instrument-Lot über MinProfitTargetPips liegt und der gesamte Korbgewinn ProfitTargetPips übersteigt, schließt die Strategie alle offenen Positionen und setzt den Zustand zurück.
Manuelles Herunterfahren: Das Setzen von ShutdownGrid auf true schließt verbleibende Positionen und verhindert neue Orders, bis es umgeschaltet wird.
Einstiegsbedingungen
Long-Einstiege
Trend-Filter zeigt Aufwärtstrend an (EMA_short - EMA_long > MinDistancePips).
Ask-Preis ist größer oder gleich dem aktuellen Kaufanker.
Die Strategie ist nicht im Shutdown-Modus und der Korb hat sein Gewinnziel nicht erreicht.
Short-Einstiege
Trend-Filter zeigt Abwärtstrend an (EMA_long - EMA_short > MinDistancePips).
Ask-Preis ist kleiner oder gleich dem aktuellen Verkaufsanker.
Shutdown-Flag ist falsch und das Korbgewinnziel ist noch nicht erreicht.
Exit-Management
Gewinn-Exit: Wenn der unrealisierte Korbgewinn ProfitTargetPips erfüllt, wobei jede offene Seite mindestens MinProfitTargetPips pro Lot gewinnt, werden alle Positionen zum Marktpreis geschlossen.
Notfall-Exit: Das Setzen von ShutdownGrid auf true schließt sofort jede offene Exposition.
Indikatoren und Daten
8-Perioden-EMA (schnell) und 21-Perioden-EMA (langsam), berechnet auf der konfigurierten Kerzenreihe.
Level-1-Abonnement wird verwendet, um das beste Bid/Ask zu verfolgen, um den Tunnel zu erstellen und Einstiegsbedingungen mit Echtzeit-Spreads zu vergleichen.
Parameter
Parameter
Beschreibung
StartVolume
Anfangsvolumen der ersten Order in einem Zyklus.
BaseMultiplier
Geometrischer Multiplikator auf das Volumen jeder nachfolgenden Order angewendet.
TunnelWidthPips
Zusätzliche Tunnelbreite in Pips, die zum doppelten aktuellen Spread addiert wird.
ProfitTargetPips
Korbgewinnziel gemessen in Pips, umgerechnet in Preisabstand.
MinProfitTargetPips
Minimale günstige Bewegung pro Seite, bevor der Korb schließen kann.
ShortEmaPeriod
Periode des schnellen EMA zur Richtungsbestätigung.
LongEmaPeriod
Periode des langsamen EMA zur Richtungsbestätigung.
MinDistancePips
Minimale EMA-Trennung erforderlich, um einen Trend zu erklären.
CandleType
Zeitrahmen der Kerzen, die die EMAs und die Trading-Schleife speisen.
ShutdownGrid
Boolescher Schalter, der Liquidation erzwingt und neue Trades blockiert.
Praktische Hinweise
Die Standard-Kerzenperiode beträgt eine Stunde; passen Sie sie an den im ursprünglichen EA verwendeten Zeitrahmen an.
Die Strategie verlässt sich auf Beste-Bid/Ask-Daten; Level-1-Kurse beim Live-Trading oder Backtesting bereitstellen.
Da StockSharp eine Nettoposition pro Instrument hält, reduzieren oder drehen wechselnde Käufe und Verkäufe die Nettoexposition, anstatt unabhängige gehedgte Tickets zu halten, aber die Korblogik ahmt die beabsichtigte Gewinnerfassung dennoch nach.
Immer instrumentspezifische Volumenschritte und Tick-Größen überprüfen, damit der generierte Tunnel und die Lot-Skalierung zum gehandelten Markt passen.
using System;
using System.Collections.Generic;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Grid hedging strategy based on EMA crossover direction.
/// Opens positions on EMA trend, reverses on direction change.
/// </summary>
public class OverHedgeV2Strategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _shortEmaPeriod;
private readonly StrategyParam<int> _longEmaPeriod;
private int _prevSignal;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int ShortEmaPeriod
{
get => _shortEmaPeriod.Value;
set => _shortEmaPeriod.Value = value;
}
public int LongEmaPeriod
{
get => _longEmaPeriod.Value;
set => _longEmaPeriod.Value = value;
}
public OverHedgeV2Strategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
_shortEmaPeriod = Param(nameof(ShortEmaPeriod), 8)
.SetGreaterThanZero()
.SetDisplay("Short EMA", "Fast EMA length", "Indicators");
_longEmaPeriod = Param(nameof(LongEmaPeriod), 21)
.SetGreaterThanZero()
.SetDisplay("Long EMA", "Slow EMA length", "Indicators");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevSignal = 0;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevSignal = 0;
var shortEma = new ExponentialMovingAverage { Length = ShortEmaPeriod };
var longEma = new ExponentialMovingAverage { Length = LongEmaPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(shortEma, longEma, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, shortEma);
DrawIndicator(area, longEma);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal shortEma, decimal longEma)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var signal = shortEma > longEma ? 1 : shortEma < longEma ? -1 : _prevSignal;
if (signal == _prevSignal)
return;
var oldSignal = _prevSignal;
_prevSignal = signal;
if (signal == 1 && oldSignal <= 0)
{
if (Position < 0)
BuyMarket();
if (Position <= 0)
BuyMarket();
}
else if (signal == -1 && oldSignal >= 0)
{
if (Position > 0)
SellMarket();
if (Position >= 0)
SellMarket();
}
}
}
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 over_hedge_v2_strategy(Strategy):
def __init__(self):
super(over_hedge_v2_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))) \
.SetDisplay("Candle Type", "Candle timeframe", "General")
self._short_ema_period = self.Param("ShortEmaPeriod", 8) \
.SetDisplay("Short EMA", "Fast EMA length", "Indicators")
self._long_ema_period = self.Param("LongEmaPeriod", 21) \
.SetDisplay("Long EMA", "Slow EMA length", "Indicators")
self._prev_signal = 0
@property
def CandleType(self):
return self._candle_type.Value
@property
def ShortEmaPeriod(self):
return self._short_ema_period.Value
@property
def LongEmaPeriod(self):
return self._long_ema_period.Value
def OnReseted(self):
super(over_hedge_v2_strategy, self).OnReseted()
self._prev_signal = 0
def OnStarted2(self, time):
super(over_hedge_v2_strategy, self).OnStarted2(time)
self._prev_signal = 0
short_ema = ExponentialMovingAverage()
short_ema.Length = self.ShortEmaPeriod
long_ema = ExponentialMovingAverage()
long_ema.Length = self.LongEmaPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(short_ema, long_ema, self._on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, short_ema)
self.DrawIndicator(area, long_ema)
self.DrawOwnTrades(area)
def _on_process(self, candle, short_value, long_value):
if candle.State != CandleStates.Finished:
return
sv = float(short_value)
lv = float(long_value)
if sv > lv:
signal = 1
elif sv < lv:
signal = -1
else:
signal = self._prev_signal
if signal == self._prev_signal:
return
old_signal = self._prev_signal
self._prev_signal = signal
if signal == 1 and old_signal <= 0:
if self.Position < 0:
self.BuyMarket()
if self.Position <= 0:
self.BuyMarket()
elif signal == -1 and old_signal >= 0:
if self.Position > 0:
self.SellMarket()
if self.Position >= 0:
self.SellMarket()
def CreateClone(self):
return over_hedge_v2_strategy()