Die Exp TEMA-Strategie ist eine StockSharp-Portierung des MetaTrader-Expertenberaters Exp_TEMA.mq5. Das ursprüngliche System scannt mehrere Forex-Paare und überwacht die Steigung des Triple Exponential Moving Average (TEMA). Immer wenn die Steigung ihr Vorzeichen umkehrt, betritt der Experte entweder eine neue Trendfolgeposition oder verlässt die entgegengesetzte. Diese C#-Konvertierung behält die gleiche Indikatorlogik bei und konzentriert sich dabei auf ein einzelnes Wertpapier, das der Strategie in StockSharp zugewiesen ist.
Handelslogik
Die Strategie arbeitet mit fertigen Kerzen, die durch den ausgewählten Parameter CandleType erzeugt wurden. Bei jedem Kerzenschluss wird ein TEMA mit der konfigurierbaren Länge TemaPeriod berechnet. Drei aufeinanderfolgende TEMA-Messwerte werden verglichen, um das Steigungserkennungsschema des MQL5-Experten zu reproduzieren:
Sei tema[0] der letzte Kerzenwert, tema[1] der vorherige und tema[2] der Wert zwei Kerzen zurück.
Die kurzfristige Steigung beträgt d1 = tema[1] - tema[2], während die ältere Steigung d2 = tema[2] - tema[3] beträgt.
Ein bullischer Einstieg wird ausgelöst, wenn die Steigung ansteigt (d2 < 0 und d1 > 0). Jede Short-Position wird zuerst geschlossen, dann wird eine Long-Order von Volume + |Position| Lots platziert.
Ein bärischer Einstieg wird ausgelöst, wenn die Steigung nach unten geht (d2 > 0 und d1 < 0). Jede Long-Position wird zuerst abgeflacht, dann wird eine Short-Order von Volume + |Position| Lots gesendet.
Schutzausgänge ahmen die ursprünglichen Stop-Flags nach: Wenn die aktuelle Steigung negativ wird, wird die Long-Position geschlossen, während eine positive Steigung jede Short-Position schließt.
Dies reproduziert das gleiche Signaltiming wie die Quelle EA, ohne historischen Pufferzugriff zu verwenden, und bleibt innerhalb des High-Level-StockSharp API.
Parameter
Parameter
Standard
Beschreibung
TemaPeriod
15
Länge des dreifach exponentiellen gleitenden Durchschnitts.
TradeVolume
1
Grundauftragsvolumen. Die ausgeführte Größe wird zu „TradeVolume +“.
Position
` beim Rückwärtsfahren.
StopLossPoints
1000
Stop-Loss-Distanz ausgedrückt in Preisschritten. Wird an StartProtection übergeben, wenn positiv.
TakeProfitPoints
2000
Take-Profit-Distanz, ausgedrückt in Preisschritten. Wird an StartProtection übergeben, wenn positiv.
CandleType
15-Minuten-Kerzen
Kerzentyp, der den Indikator speist. Wählen Sie einen Zeitrahmen, der dem vom ursprünglichen Experten verwendeten Diagramm entspricht.
Alle Parameter werden mit StrategyParam<T> erstellt, sodass sie im Designer optimiert werden können.
Unterschiede zum MQL5 Expert
Die Version MQL verwaltet bis zu zwölf Symbole gleichzeitig. StockSharp-Strategien sind an einen bestimmten Security gebunden, daher handelt dieser Port mit dem Instrument, das beim Start der Strategie zugewiesen wurde. Führen Sie mehrere Strategieinstanzen aus, wenn eine Abdeckung mit mehreren Symbolen erforderlich ist.
Die Auftragsverwaltung basiert auf BuyMarket/SellMarket und StartProtection, die die ursprünglichen Marktaufträge, Stopps und Ziele dem übergeordneten API von StockSharp zuordnen.
Der Indikatorzugriff erfolgt über SubscribeCandles().Bind(...), wodurch manuelles Pufferkopieren vermieden wird und die Repository-Richtlinien eingehalten werden.
Nutzungstipps
Hängen Sie die Strategie an das gewünschte Wertpapier an und legen Sie den CandleType fest, der Ihrem analytischen Zeitrahmen entspricht.
Passen Sie die Stop- und Take-Profit-Abstände in Preisschritten entsprechend der Volatilität des Instruments an.
Optional: Führen Sie die Optimierung für TemaPeriod, StopLossPoints und TakeProfitPoints aus, um die in MetaTrader durchgeführten Parameter-Sweeps zu replizieren.
Überwachen Sie den enthaltenen Diagrammbereich, um Kerzen, die TEMA-Linie und die ausgeführten Trades zu visualisieren.
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Strategy that trades TEMA slope reversals from the original Exp_TEMA expert advisor.
/// Enters long when TEMA slope turns positive, short when negative.
/// </summary>
public class ExpTemaStrategy : Strategy
{
private readonly StrategyParam<int> _temaPeriod;
private readonly StrategyParam<DataType> _candleType;
private ExponentialMovingAverage _tema;
private decimal? _prev1;
private decimal? _prev2;
private decimal? _prev3;
public int TemaPeriod
{
get => _temaPeriod.Value;
set => _temaPeriod.Value = value;
}
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public ExpTemaStrategy()
{
_temaPeriod = Param(nameof(TemaPeriod), 40)
.SetGreaterThanZero()
.SetDisplay("TEMA Period", "Length of Triple Exponential Moving Average", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
.SetDisplay("Candle Type", "Timeframe for TEMA calculation", "General");
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_tema = new ExponentialMovingAverage { Length = TemaPeriod };
_prev1 = null;
_prev2 = null;
_prev3 = null;
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(_tema, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, _tema);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal temaValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!_tema.IsFormed)
{
_prev1 = temaValue;
return;
}
if (_prev1 is null)
{
_prev1 = temaValue;
return;
}
if (_prev2 is null)
{
_prev2 = _prev1;
_prev1 = temaValue;
return;
}
if (_prev3 is null)
{
_prev3 = _prev2;
_prev2 = _prev1;
_prev1 = temaValue;
return;
}
var volume = Volume;
if (volume <= 0)
volume = 1;
var dtema1 = _prev1.Value - _prev2.Value;
var dtema2 = _prev2.Value - _prev3.Value;
// Entry on slope reversal
var turnedUp = dtema2 < 0 && dtema1 > 0;
var turnedDown = dtema2 > 0 && dtema1 < 0;
if (turnedUp && Position <= 0)
{
BuyMarket(Position < 0 ? Math.Abs(Position) + volume : volume);
}
else if (turnedDown && Position >= 0)
{
SellMarket(Position > 0 ? Math.Abs(Position) + volume : volume);
}
_prev3 = _prev2;
_prev2 = _prev1;
_prev1 = temaValue;
}
/// <inheritdoc />
protected override void OnReseted()
{
_tema = null;
_prev1 = null;
_prev2 = null;
_prev3 = null;
base.OnReseted();
}
}
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 exp_tema_strategy(Strategy):
def __init__(self):
super(exp_tema_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(60)))
self._tema_period = self.Param("TemaPeriod", 40)
self._prev1 = None
self._prev2 = None
self._prev3 = None
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def TemaPeriod(self):
return self._tema_period.Value
@TemaPeriod.setter
def TemaPeriod(self, value):
self._tema_period.Value = value
def OnReseted(self):
super(exp_tema_strategy, self).OnReseted()
self._prev1 = None
self._prev2 = None
self._prev3 = None
def OnStarted2(self, time):
super(exp_tema_strategy, self).OnStarted2(time)
self._prev1 = None
self._prev2 = None
self._prev3 = None
tema = ExponentialMovingAverage()
tema.Length = self.TemaPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(tema, self._process_candle).Start()
def _process_candle(self, candle, tema_value):
if candle.State != CandleStates.Finished:
return
val = float(tema_value)
if self._prev1 is None:
self._prev1 = val
return
if self._prev2 is None:
self._prev2 = self._prev1
self._prev1 = val
return
if self._prev3 is None:
self._prev3 = self._prev2
self._prev2 = self._prev1
self._prev1 = val
return
dtema1 = self._prev1 - self._prev2
dtema2 = self._prev2 - self._prev3
turned_up = dtema2 < 0 and dtema1 > 0
turned_down = dtema2 > 0 and dtema1 < 0
if turned_up and self.Position <= 0:
self.BuyMarket()
elif turned_down and self.Position >= 0:
self.SellMarket()
self._prev3 = self._prev2
self._prev2 = self._prev1
self._prev1 = val
def CreateClone(self):
return exp_tema_strategy()