A Estratégia de reversão de pullback TST observa reversões intrabarras agressivas. Ele foi convertido do MetaTrader 4 consultor especialista original TST.mq4 e reconstruído usando o StockSharp API de alto nível. O método procura velas onde o preço se afastou drasticamente da abertura da vela após definir um extremo intradiário e, em seguida, desvanece esse movimento esperando uma reversão à média. A estratégia é negociada tanto longa quanto curta e usa níveis estáticos de stop-loss e take-profit medidos em etapas de preços.
Lógica de Sinais
Configuração longa
A vela fecha abaixo de sua abertura (Open > Close).
A distância entre o máximo e o fechamento da vela é maior que GapPoints * PriceStep.
Nenhuma negociação foi executada anteriormente na mesma barra.
Quando satisfeita, a estratégia fecha qualquer exposição curta e compra OrderVolume unidades (mais o tamanho necessário para passar de uma posição curta para uma posição longa).
Configuração curta
A vela fecha acima de sua abertura (Close > Open).
A distância entre o fechamento e a mínima da vela é maior que GapPoints * PriceStep.
Nenhuma negociação foi executada anteriormente na mesma barra.
Quando satisfeita, a estratégia fecha qualquer exposição longa e vende OrderVolume unidades (mais o tamanho necessário para passar de uma posição longa para uma posição curta).
Gerenciamento de posição
Uma nova negociação atribui imediatamente níveis estáticos de stop-loss e take-profit calculados a partir do preço de preenchimento e dos parâmetros StopLossPoints/TakeProfitPoints.
Em cada vela finalizada, a estratégia verifica a máxima/mínima da vela para ver se o stop ou alvo foi tocado e sai da posição se for acionado. As verificações de stop-loss têm precedência sobre as verificações de take-profit.
Após uma saída, os níveis de risco armazenados são apagados, mas a estratégia ainda lembra o tempo da barra para evitar a reentrada durante a mesma vela (reproduzindo a guarda NevBar() da versão MQL4).
Parâmetros
StopLossPoints (padrão 500): distância da entrada até a parada de proteção, expressa em etapas de preço.
TakeProfitPoints (padrão 100): distância da entrada até a meta de lucro, expressa em etapas de preço.
GapPoints (padrão 500): pullback mínimo entre o extremo da vela e o fechamento necessário para gerar um sinal.
OrderVolume (padrão 0.1): quantidade enviada a cada nova ordem de mercado.
CandleType (padrão 1 hour): prazo das velas fornecidas através de SubscribeCandles.
Todas as configurações baseadas em distância são multiplicadas pelo PriceStep do instrumento. Se a segurança não relatar uma etapa, a estratégia volta para 1.
Notas de implementação
A conversão usa StockSharp de alto nível API e não cria coleções de indicadores personalizados.
Apenas velas finalizadas são processadas para permanecerem compatíveis com o Strategy Designer; isso aproxima as decisões intrabarras do robô MT4 usando dados de barras completos.
Um sinalizador dedicado _lastSignalBarTime replica a proteção NevBar() do código MQL4 para que apenas um pedido possa ser aberto por vela.
O tratamento do volume de ordens reflete o comportamento do MT4: as posições opostas existentes são achatadas antes de estabelecer a nova direção em uma única ordem de mercado.
As ordens stop-loss e take-profit são simuladas dentro da lógica da estratégia (em vez de ordens do lado do servidor) para corresponder às distâncias originais, mantendo o controle dentro de StockSharp.
Dicas de uso
Escolha GapPoints em relação à volatilidade do instrumento negociado; valores maiores reduzem a frequência de negociação, mas filtram retrocessos menores.
Como as verificações de stop e alvo dependem de velas concluídas, considere usar velas de duração mais curta se precisar de uma execução mais rigorosa.
Combine a estratégia com filtros adicionais (tendência, hora do dia, volume) ao implantar em mercados ativos para reduzir negociações de chicote.
using System;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// TST Pullback Reversal: buys after deep pullback from candle high,
/// sells after rally from candle low. Uses ATR for thresholds.
/// </summary>
public class TstStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _atrLength;
private readonly StrategyParam<decimal> _pullbackMultiplier;
private readonly StrategyParam<decimal> _stopMultiplier;
private readonly StrategyParam<decimal> _takeMultiplier;
private decimal _entryPrice;
private decimal _stopPrice;
private decimal _takePrice;
public TstStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(15).TimeFrame())
.SetDisplay("Candle Type", "Timeframe.", "General");
_atrLength = Param(nameof(AtrLength), 14)
.SetDisplay("ATR Length", "ATR period.", "Indicators");
_pullbackMultiplier = Param(nameof(PullbackMultiplier), 0.5m)
.SetDisplay("Pullback Mult", "ATR multiplier for pullback threshold.", "Signals");
_stopMultiplier = Param(nameof(StopMultiplier), 2.0m)
.SetDisplay("Stop Mult", "ATR multiplier for stop loss.", "Risk");
_takeMultiplier = Param(nameof(TakeMultiplier), 1.0m)
.SetDisplay("Take Mult", "ATR multiplier for take profit.", "Risk");
}
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int AtrLength
{
get => _atrLength.Value;
set => _atrLength.Value = value;
}
public decimal PullbackMultiplier
{
get => _pullbackMultiplier.Value;
set => _pullbackMultiplier.Value = value;
}
public decimal StopMultiplier
{
get => _stopMultiplier.Value;
set => _stopMultiplier.Value = value;
}
public decimal TakeMultiplier
{
get => _takeMultiplier.Value;
set => _takeMultiplier.Value = value;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_entryPrice = 0;
_stopPrice = 0;
_takePrice = 0;
var atr = new AverageTrueRange { Length = AtrLength };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(atr, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal atrVal)
{
if (candle.State != CandleStates.Finished)
return;
if (atrVal <= 0)
return;
var close = candle.ClosePrice;
var open = candle.OpenPrice;
var high = candle.HighPrice;
var low = candle.LowPrice;
var threshold = atrVal * PullbackMultiplier;
var stopDist = atrVal * StopMultiplier;
var takeDist = atrVal * TakeMultiplier;
// Risk management
if (Position > 0)
{
if (_stopPrice > 0 && close <= _stopPrice)
{
SellMarket();
_entryPrice = 0;
_stopPrice = 0;
_takePrice = 0;
return;
}
if (_takePrice > 0 && close >= _takePrice)
{
SellMarket();
_entryPrice = 0;
_stopPrice = 0;
_takePrice = 0;
return;
}
}
else if (Position < 0)
{
if (_stopPrice > 0 && close >= _stopPrice)
{
BuyMarket();
_entryPrice = 0;
_stopPrice = 0;
_takePrice = 0;
return;
}
if (_takePrice > 0 && close <= _takePrice)
{
BuyMarket();
_entryPrice = 0;
_stopPrice = 0;
_takePrice = 0;
return;
}
}
// Entry: deep pullback from high = buy reversal
if (Position == 0)
{
if (open > close && high - close > threshold)
{
_entryPrice = close;
_stopPrice = close - stopDist;
_takePrice = close + takeDist;
BuyMarket();
}
else if (close > open && close - low > threshold)
{
_entryPrice = close;
_stopPrice = close + stopDist;
_takePrice = close - takeDist;
SellMarket();
}
}
}
}
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
from StockSharp.Algo.Indicators import AverageTrueRange
class tst_strategy(Strategy):
def __init__(self):
super(tst_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(15))) \
.SetDisplay("Candle Type", "Timeframe", "General")
self._atr_length = self.Param("AtrLength", 14) \
.SetDisplay("ATR Length", "ATR period", "Indicators")
self._pullback_multiplier = self.Param("PullbackMultiplier", 0.5) \
.SetDisplay("Pullback Mult", "ATR multiplier for pullback threshold", "Signals")
self._stop_multiplier = self.Param("StopMultiplier", 2.0) \
.SetDisplay("Stop Mult", "ATR multiplier for stop loss", "Risk")
self._take_multiplier = self.Param("TakeMultiplier", 1.0) \
.SetDisplay("Take Mult", "ATR multiplier for take profit", "Risk")
self._entry_price = 0.0
self._stop_price = 0.0
self._take_price = 0.0
@property
def CandleType(self):
return self._candle_type.Value
@property
def AtrLength(self):
return self._atr_length.Value
@property
def PullbackMultiplier(self):
return self._pullback_multiplier.Value
@property
def StopMultiplier(self):
return self._stop_multiplier.Value
@property
def TakeMultiplier(self):
return self._take_multiplier.Value
def OnStarted2(self, time):
super(tst_strategy, self).OnStarted2(time)
self._entry_price = 0.0
self._stop_price = 0.0
self._take_price = 0.0
self._atr = AverageTrueRange()
self._atr.Length = self.AtrLength
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(self._atr, self.ProcessCandle).Start()
def ProcessCandle(self, candle, atr_val):
if candle.State != CandleStates.Finished:
return
av = float(atr_val)
if av <= 0:
return
close = float(candle.ClosePrice)
open_p = float(candle.OpenPrice)
high = float(candle.HighPrice)
low = float(candle.LowPrice)
threshold = av * float(self.PullbackMultiplier)
stop_dist = av * float(self.StopMultiplier)
take_dist = av * float(self.TakeMultiplier)
# Risk management
if self.Position > 0:
if self._stop_price > 0 and close <= self._stop_price:
self.SellMarket()
self._entry_price = 0.0
self._stop_price = 0.0
self._take_price = 0.0
return
if self._take_price > 0 and close >= self._take_price:
self.SellMarket()
self._entry_price = 0.0
self._stop_price = 0.0
self._take_price = 0.0
return
elif self.Position < 0:
if self._stop_price > 0 and close >= self._stop_price:
self.BuyMarket()
self._entry_price = 0.0
self._stop_price = 0.0
self._take_price = 0.0
return
if self._take_price > 0 and close <= self._take_price:
self.BuyMarket()
self._entry_price = 0.0
self._stop_price = 0.0
self._take_price = 0.0
return
# Entry: deep pullback from high = buy reversal
if self.Position == 0:
if open_p > close and high - close > threshold:
self._entry_price = close
self._stop_price = close - stop_dist
self._take_price = close + take_dist
self.BuyMarket()
elif close > open_p and close - low > threshold:
self._entry_price = close
self._stop_price = close + stop_dist
self._take_price = close - take_dist
self.SellMarket()
def OnReseted(self):
super(tst_strategy, self).OnReseted()
self._entry_price = 0.0
self._stop_price = 0.0
self._take_price = 0.0
def CreateClone(self):
return tst_strategy()