La Estrategia Exp TEMA es una StockSharp versión del MetaTrader asesor experto Exp_TEMA.mq5. El sistema original escanea múltiples pares de divisas y monitorea la pendiente de la media móvil exponencial triple (TEMA). Cada vez que la pendiente cambia de signo, el experto entra en una nueva posición de seguimiento de tendencia o sale de la opuesta. Esta conversión de C# mantiene la misma lógica de indicador mientras se centra en un único valor asignado a la estrategia en StockSharp.
Lógica de trading
La estrategia opera en velas terminadas producidas por el parámetro CandleType seleccionado. Se calcula un TEMA con la longitud configurable TemaPeriod en cada cierre de vela. Se comparan tres lecturas TEMA consecutivas para reproducir el esquema de detección de pendientes del experto MQL5:
Sea tema[0] el último valor de la vela, tema[1] el anterior y tema[2] el valor dos velas atrás.
La pendiente a corto plazo es d1 = tema[1] - tema[2], mientras que la pendiente más antigua es d2 = tema[2] - tema[3].
Una entrada alcista se activa cuando la pendiente sube (d2 < 0 y d1 > 0). Cualquier posición corta se cierra primero y luego se coloca una orden larga de Volume + |Position| lotes.
Una entrada bajista se activa cuando la pendiente baja (d2 > 0 y d1 < 0). Cualquier posición larga se aplana primero y luego se envía una orden corta de Volume + |Position| lotes.
Las salidas protectoras imitan las banderas de parada originales: si la pendiente actual se vuelve negativa, la posición larga se cierra, mientras que una pendiente positiva cierra cualquier posición corta.
Esto reproduce la misma temporización de señal que la fuente EA sin utilizar el acceso histórico al búfer, manteniéndose dentro del nivel alto StockSharp API.
Parámetros
Parámetro
Predeterminado
Descripción
TemaPeriod
15
Longitud de la media móvil exponencial triple.
TradeVolume
1
Volumen base de pedidos. El tamaño ejecutado se convierte en TradeVolume + |Posición|al dar marcha atrás.
StopLossPoints
1000
Distancia de stop-loss expresada en pasos de precio. Pasado a StartProtection si es positivo.
TakeProfitPoints
2000
Distancia de obtención de beneficios expresada en incrementos de precio. Pasado a StartProtection si es positivo.
CandleType
velas de 15 minutos
Tipo de vela que alimenta el indicador. Elija un período de tiempo que coincida con el gráfico utilizado por el experto original.
Todos los parámetros se crean con StrategyParam<T> para que puedan optimizarse dentro de Designer.
Diferencias con el experto MQL5
La versión MQL gestiona hasta doce símbolos simultáneamente. Las estrategias StockSharp están vinculadas a un Security específico, por lo tanto, este puerto comercializa el instrumento que se asigna cuando se lanza la estrategia. Ejecute varias instancias de estrategia si se requiere cobertura de múltiples símbolos.
La gestión de órdenes se basa en BuyMarket/SellMarket y StartProtection, que asignan las órdenes de mercado originales, paradas y objetivos al nivel alto de StockSharp API.
El acceso al indicador se realiza a través de SubscribeCandles().Bind(...), evitando la copia manual del buffer y cumpliendo con las pautas del repositorio.
Consejos de uso
Adjunte la estrategia a la seguridad deseada y establezca el CandleType que coincida con su marco de tiempo analítico.
Ajuste las distancias de parada y toma de ganancias en incrementos de precios de acuerdo con la volatilidad del instrumento.
Opcional: ejecute la optimización en TemaPeriod, StopLossPoints y TakeProfitPoints para replicar los barridos de parámetros realizados en MetaTrader.
Supervise el área del gráfico incluida para visualizar velas, la línea TEMA y las operaciones ejecutadas.
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()