The Exp TEMA Strategy is a StockSharp port of the MetaTrader expert advisor Exp_TEMA.mq5. The original system scans multiple forex pairs and monitors the slope of the Triple Exponential Moving Average (TEMA). Whenever the slope flips its sign, the expert either enters a new trend-following position or exits the opposite one. This C# conversion keeps the same indicator logic while focusing on a single security that is assigned to the strategy in StockSharp.
Trading Logic
The strategy operates on finished candles produced by the selected CandleType parameter. A TEMA with the configurable TemaPeriod length is calculated on every candle close. Three consecutive TEMA readings are compared to reproduce the slope-detection scheme of the MQL5 expert:
Let tema[0] be the latest candle value, tema[1] the previous one and tema[2] the value two candles back.
The short-term slope is d1 = tema[1] - tema[2], while the older slope is d2 = tema[2] - tema[3].
A bullish entry is triggered when the slope turns up (d2 < 0 and d1 > 0). Any short position is closed first, then a long order of Volume + |Position| lots is placed.
A bearish entry is triggered when the slope turns down (d2 > 0 and d1 < 0). Any long position is flattened first, then a short order of Volume + |Position| lots is sent.
Protective exits mimic the original stop flags: if the current slope becomes negative the long position is closed, while a positive slope closes any short.
This reproduces the same signal timing as the source EA without using historical buffer access, staying within the high-level StockSharp API.
Parameters
Parameter
Default
Description
TemaPeriod
15
Length of the Triple Exponential Moving Average.
TradeVolume
1
Base order volume. The executed size becomes TradeVolume + |Position| when reversing.
StopLossPoints
1000
Stop-loss distance expressed in price steps. Passed to StartProtection if positive.
TakeProfitPoints
2000
Take-profit distance expressed in price steps. Passed to StartProtection if positive.
CandleType
15-minute candles
Candle type that feeds the indicator. Choose a timeframe that matches the chart used by the original expert.
All parameters are created with StrategyParam<T> so they can be optimized inside Designer.
Differences from the MQL5 Expert
The MQL version manages up to twelve symbols simultaneously. StockSharp strategies are bound to a specific Security, therefore this port trades the instrument that is assigned when the strategy is launched. Run several strategy instances if multi-symbol coverage is required.
Order management relies on BuyMarket/SellMarket and StartProtection, which map the original market orders, stops and targets to StockSharp's high-level API.
Indicator access is performed through SubscribeCandles().Bind(...), avoiding manual buffer copying and staying compliant with the repository guidelines.
Usage Tips
Attach the strategy to the desired security and set the CandleType that matches your analytical timeframe.
Tune the stop and take-profit distances in price steps according to the instrument's volatility.
Optional: run optimization on TemaPeriod, StopLossPoints and TakeProfitPoints to replicate the parameter sweeps performed in MetaTrader.
Monitor the included chart area to visualize candles, the TEMA line and the executed trades.
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()