Ver no GitHub

Estratégia de reversão de pullback TST

Visão geral

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

    1. A vela fecha abaixo de sua abertura (Open > Close).
    2. A distância entre o máximo e o fechamento da vela é maior que GapPoints * PriceStep.
    3. 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

    1. A vela fecha acima de sua abertura (Close > Open).
    2. A distância entre o fechamento e a mínima da vela é maior que GapPoints * PriceStep.
    3. 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();
			}
		}
	}
}