Diese Strategie ist eine C#-Konvertierung des MetaTrader 5 Expert Advisors Exp_TDI-2_ReOpen. Sie handelt mit dem Trend Direction Index (TDI-2)-Indikator und wendet die ursprüngliche Positions-Wiedereinstiegslogik an. Der C#-Port verwendet die High-Level-StockSharp-API und behält das Kernverhalten der MQL-Version bei: Er reagiert auf Kreuzungen zwischen der TDI-Momentum-Linie und der TDI-Indexlinie, skaliert bei profitablen Positionen nach einem konfigurierbaren Preisanstieg und verwaltet Trades mit optionalen Schutzstops.
Indikatoren
TDI-2-Indikator – ein benutzerdefinierter momentum-basierter Indikator, der in diesem Repository implementiert ist. Er erstellt zwei Linien:
Direktionale Linie: Periode × GeglättetenMomentum, wobei das Momentum dem angewendeten Preis minus dem Preis Periode Bars zuvor entspricht.
Der Indikator unterstützt folgende Glättungsmethoden: Einfacher, Exponentieller, Geglätteter (RMA) und Lineare Gewichteter gleitender Durchschnitt.
Die unterstützten angewendeten Preisoptionen replizieren die ursprüngliche MQL-Implementierung, einschließlich der TrendFollow- und Demark-Formeln.
Handelslogik
Bei jeder abgeschlossenen Kerze wertet die Strategie die TDI-2-Werte an der durch Signal Bar angegebenen Bar (Standard: vorherige geschlossene Kerze) und einer Bar früher aus.
Wenn die Direktionallinie über der Indexlinie war und dann darunter kreuzt:
Wenn Allow Long Entries aktiviert ist und keine Long-Position aktiv ist, bereitet die Strategie einen neuen Long-Einstieg vor.
Wenn eine Short-Position besteht und Allow Short Exits aktiviert ist, schließt sie die Short-Position.
Wenn die Direktionallinie unter der Indexlinie war und dann darüber kreuzt:
Wenn Allow Short Entries aktiviert ist und keine Short-Position aktiv ist, bereitet die Strategie einen neuen Short-Einstieg vor.
Wenn eine Long-Position besteht und Allow Long Exits aktiviert ist, schließt sie die Long-Position.
Wiedereinstiegslogik (Skalierung):
Beim Halten einer Long-Position verfolgt die Strategie den Ausführungspreis des letzten Long-Trades. Wenn sich der Markt um Re-entry Step (points) günstig bewegt und die Anzahl der ausgeführten Long-Trades noch unter Max Entries liegt, öffnet sie eine zusätzliche Long-Order mit dem Basisvolumen.
Die gleiche Logik gilt für Short-Positionen unter Verwendung des letzten Short-Ausführungspreises.
Beim Öffnen einer Position, während eine entgegengesetzte Position besteht, sendet die Strategie eine kombinierte Marktorder, die so dimensioniert ist, dass sie sowohl das entgegengesetzte Exposure schließt als auch die neue Position mit dem konfigurierten Basisvolumen aufbaut.
Optionale Stop-Loss- und Take-Profit-Level werden über StartProtection unter Verwendung des PriceStep-Multiplikators des Instruments aktiviert.
Parameter
Name
Beschreibung
Standardwerte
Money Management
Basis-Ordervolumen.
0.1
Max Entries
Maximale Anzahl von Einstiegen pro Richtung (Ersthandel + Wiedereinstiege).
10
Stop Loss (points)
Stop-Loss-Distanz in Instrument-Punkten.
1000
Take Profit (points)
Take-Profit-Distanz in Instrument-Punkten.
2000
Slippage (points)
Zur Kompatibilität beibehalten; wird in der StockSharp-Implementierung nicht verwendet.
10
Re-entry Step (points)
Minimale günstige Bewegung, bevor in eine bestehende Position skaliert wird.
300
Allow Long Entries / Allow Short Entries
Long-/Short-Positionen öffnen aktivieren.
true
Allow Long Exits / Allow Short Exits
Long-/Short-Positionen schließen aktivieren.
true
Candle Type
Für Berechnungen verwendete Kerzenreihe.
H4-Kerzen
TDI Smoothing
Glättungsmethode für den TDI-2-Indikator.
Einfacher MA
TDI Period
Momentum-Lookback-Periode.
20
TDI Phase
Zur Kompatibilität mit dem MQL-Input reserviert (kein Effekt in unterstützten Glättungsmodi).
15
Applied Price
Von TDI-2 verwendete Preisquelle.
Close
Signal Bar
Anzahl der geschlossenen Kerzen, die bei der Auswertung von Kreuzungen zurückgeschaut werden.
1
Zusätzliche Hinweise
Nur die von StockSharp-Indikatoren unterstützten Glättungsmethoden (SMA, EMA, SMMA, LWMA) sind implementiert. Andere MQL-Modi wie JJMA oder T3 sind nicht verfügbar.
Der Parameter TDI Phase wird zur Vollständigkeit beibehalten. Er beeinflusst die unterstützten Glättungsmethoden nicht und kann auf seinem Standardwert belassen werden.
Der Parameter Slippage (points) wird zur Parität mit dem ursprünglichen Expert Advisor bereitgestellt, wird aber nicht von der High-Level-API verwendet.
Die Skalierungszähler werden automatisch zurückgesetzt, wenn die Nettoposition auf null zurückkehrt.
using System;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Trend Direction Index re-entry strategy.
/// Trades based on crossings between the TDI momentum line and the TDI index line.
/// </summary>
public class Tdi2ReOpenStrategy : Strategy
{
private readonly StrategyParam<int> _tdiPeriod;
private readonly StrategyParam<DataType> _candleType;
private decimal? _lastClose;
private decimal? _directional;
private decimal? _index;
private decimal? _prevDirectional;
private decimal? _prevIndex;
public int TdiPeriod { get => _tdiPeriod.Value; set => _tdiPeriod.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public Tdi2ReOpenStrategy()
{
_tdiPeriod = Param(nameof(TdiPeriod), 10)
.SetGreaterThanZero()
.SetDisplay("TDI Period", "Momentum lookback period", "Indicator")
.SetOptimize(5, 30, 5);
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Data series", "General");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_lastClose = null;
_directional = null;
_index = null;
_prevDirectional = null;
_prevIndex = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_lastClose = null;
_directional = null;
_index = null;
_prevDirectional = null;
_prevIndex = null;
var subscription = SubscribeCandles(CandleType);
subscription.Bind(ProcessCandle).Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
var close = candle.ClosePrice;
if (_lastClose is not decimal lastClose)
{
_lastClose = close;
return;
}
var momentum = close - lastClose;
_lastClose = close;
var alpha = 2m / (TdiPeriod + 1m);
if (_directional is not decimal prevDirectionalLine || _index is not decimal prevIndexLine)
{
_directional = momentum;
_index = momentum;
return;
}
var directional = prevDirectionalLine + alpha * (momentum - prevDirectionalLine);
var index = prevIndexLine + alpha * (directional - prevIndexLine);
if (_prevDirectional is not decimal prevDir || _prevIndex is not decimal prevIdx)
{
_directional = directional;
_index = index;
_prevDirectional = prevDirectionalLine;
_prevIndex = prevIndexLine;
return;
}
var crossUp = prevDir <= prevIdx && directional > index;
var crossDown = prevDir >= prevIdx && directional < index;
if (crossUp && Position <= 0)
BuyMarket();
else if (crossDown && Position >= 0)
SellMarket();
_directional = directional;
_index = index;
_prevDirectional = directional;
_prevIndex = index;
}
}
}
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 tdi_2_re_open_strategy(Strategy):
"""TDI momentum/index crossover: custom EMA-smoothed momentum lines."""
def __init__(self):
super(tdi_2_re_open_strategy, self).__init__()
self._tdi_period = self.Param("TdiPeriod", 10).SetGreaterThanZero().SetDisplay("TDI Period", "Momentum lookback period", "Indicator")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1)))
@property
def CandleType(self): return self._candle_type.Value
@CandleType.setter
def CandleType(self, value): self._candle_type.Value = value
def OnReseted(self):
super(tdi_2_re_open_strategy, self).OnReseted()
self._last_close = 0
self._directional = None
self._index = None
self._prev_dir = None
self._prev_idx = None
def OnStarted2(self, time):
super(tdi_2_re_open_strategy, self).OnStarted2(time)
self._last_close = 0
self._directional = None
self._index = None
self._prev_dir = None
self._prev_idx = None
sub = self.SubscribeCandles(self.CandleType)
sub.Bind(self.OnProcess).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, sub)
self.DrawOwnTrades(area)
def OnProcess(self, candle):
if candle.State != CandleStates.Finished:
return
close = float(candle.ClosePrice)
if self._last_close == 0:
self._last_close = close
return
momentum = close - self._last_close
self._last_close = close
alpha = 2.0 / (self._tdi_period.Value + 1.0)
if self._directional is None or self._index is None:
self._directional = momentum
self._index = momentum
return
directional = self._directional + alpha * (momentum - self._directional)
index = self._index + alpha * (directional - self._index)
if self._prev_dir is None or self._prev_idx is None:
self._directional = directional
self._index = index
self._prev_dir = self._directional
self._prev_idx = self._index
return
cross_up = self._prev_dir <= self._prev_idx and directional > index
cross_down = self._prev_dir >= self._prev_idx and directional < index
if cross_up and self.Position <= 0:
self.BuyMarket()
elif cross_down and self.Position >= 0:
self.SellMarket()
self._directional = directional
self._index = index
self._prev_dir = directional
self._prev_idx = index
def CreateClone(self):
return tdi_2_re_open_strategy()