A Estratégia Exp TEMA é uma versão StockSharp do MetaTrader consultor especialista Exp_TEMA.mq5. O sistema original verifica vários pares de divisas e monitora a inclinação da média móvel exponencial tripla (TEMA). Sempre que a inclinação muda de sinal, o especialista entra em uma nova posição de acompanhamento de tendência ou sai da posição oposta. Esta conversão C# mantém a mesma lógica do indicador enquanto se concentra em um único título atribuído à estratégia em StockSharp.
Lógica de negociação
A estratégia opera em velas finalizadas produzidas pelo parâmetro CandleType selecionado. Um TEMA com comprimento TemaPeriod configurável é calculado em cada fechamento de vela. Três leituras consecutivas de TEMA são comparadas para reproduzir o esquema de detecção de inclinação do especialista MQL5:
Seja tema[0] o valor da vela mais recente, tema[1] o anterior e tema[2] o valor duas velas atrás.
A inclinação de curto prazo é d1 = tema[1] - tema[2], enquanto a inclinação mais antiga é d2 = tema[2] - tema[3].
Uma entrada de alta é acionada quando a inclinação aumenta (d2 < 0 e d1 > 0). Qualquer posição curta é fechada primeiro e, em seguida, uma ordem longa de Volume + |Position| lotes é colocada.
Uma entrada de baixa é acionada quando a inclinação diminui (d2 > 0 e d1 < 0). Qualquer posição longa é achatada primeiro e, em seguida, uma ordem curta de Volume + |Position| lotes é enviada.
As saídas de proteção imitam os sinalizadores de parada originais: se a inclinação atual se tornar negativa, a posição longa é fechada, enquanto uma inclinação positiva fecha qualquer posição curta.
Isso reproduz o mesmo tempo de sinal da fonte EA sem usar o acesso histórico ao buffer, permanecendo dentro do StockSharp API de alto nível.
Parâmetros
Parâmetro
Padrão
Descrição
TemaPeriod
15
Comprimento da média móvel exponencial tripla.
TradeVolume
1
Volume básico do pedido. O tamanho executado torna-se TradeVolume + |Posição| ao inverter.
StopLossPoints
1000
Distância de stop-loss expressa em etapas de preço. Passado para StartProtection se positivo.
TakeProfitPoints
2000
Distância de lucro expressa em etapas de preço. Passado para StartProtection se positivo.
CandleType
Velas de 15 minutos
Tipo de vela que alimenta o indicador. Escolha um prazo que corresponda ao gráfico usado pelo especialista original.
Todos os parâmetros são criados com StrategyParam<T> para que possam ser otimizados dentro do Designer.
Diferenças do especialista MQL5
A versão MQL gerencia até doze símbolos simultaneamente. As estratégias StockSharp estão vinculadas a um Security específico, portanto esta porta negocia o instrumento que é atribuído quando a estratégia é lançada. Execute várias instâncias de estratégia se for necessária cobertura multissímbolo.
O gerenciamento de pedidos depende de BuyMarket/SellMarket e StartProtection, que mapeiam as ordens de mercado originais, paradas e metas para o API de alto nível de StockSharp.
O acesso ao indicador é realizado através de SubscribeCandles().Bind(...), evitando a cópia manual do buffer e mantendo a conformidade com as diretrizes do repositório.
Dicas de uso
Anexe a estratégia à segurança desejada e defina o CandleType que corresponda ao seu prazo analítico.
Ajuste as distâncias de stop e take-profit nas etapas de preço de acordo com a volatilidade do instrumento.
Opcional: execute a otimização em TemaPeriod, StopLossPoints e TakeProfitPoints para replicar as varreduras de parâmetros executadas em MetaTrader.
Monitore a área incluída do gráfico para visualizar velas, a linha TEMA e as negociações executadas.
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()