Ver no GitHub

Estratégia de Múltiplos Indicadores SSB5_123

Visão Geral

Esta estratégia é um port StockSharp do consultor especialista MetaTrader 5 "ssb5_123". O código original vem da coleção SSB (Step by Step) de Yury V. Reshetov e combina vários osciladores clássicos para confirmar rompimentos direcionais. A versão StockSharp mantém a mesma lógica usando a API de assinatura de velas de alto nível e implementações de indicadores nativos.

O algoritmo trabalha exclusivamente com velas concluídas. Compara o preço de abertura da barra atual com a barra anterior, verifica o momentum e a direção do Awesome Oscillator, MACD e histograma OsMA, e verifica se o preço está sendo negociado acima ou abaixo de uma média móvel suavizada. Confirmação adicional é obtida do oscilador estocástico exigindo que tanto %K quanto %D estejam acima ou abaixo do nível 50.

Indicadores e Sinais

Os seguintes indicadores são empregados exatamente como na versão MetaTrader:

  • Média Móvel Suavizada (SMMA): média móvel suavizada de 45 períodos calculada a partir das aberturas de velas. A direção de entrada requer que o preço de abertura esteja no lado correto da média.
  • MACD (rápido 47, lento 95, sinal 74): a linha principal deve ser positiva para trades longos (negativa para trades curtos) e deve estar subindo (caindo) em comparação com a vela anterior.
  • Histograma OsMA: calculado como MACD menos sua linha de sinal. O histograma deve diminuir para trades longos e aumentar para trades curtos, espelhando a função original fosma1().
  • Awesome Oscillator: usa as médias móveis suavizadas padrão 5/34 do preço mediano. O valor do oscilador deve ser positivo para longos (negativo para curtos) e seu momentum entre as últimas duas barras deve apontar na direção do trade.
  • Oscilador Estocástico (K=25, D=12, Slowing=56): tanto as linhas %K quanto %D devem estar acima de 50 para trades longos e abaixo de 50 para trades curtos, fornecendo um filtro de regime.

Lógica de Negociação

  1. Aguardar uma nova vela concluída.
  2. Avaliar a configuração longa. Todas as seguintes condições devem ser verdadeiras:
    • A abertura da vela atual é menor ou igual à abertura da vela anterior.
    • O Awesome Oscillator é positivo e está caindo em relação ao valor anterior.
    • A linha principal MACD é positiva e está subindo em relação ao valor anterior.
    • O histograma OsMA não está aumentando (histograma atual menos histograma anterior é menor ou igual a zero).
    • A abertura da vela atual está acima da média móvel suavizada.
    • As linhas estocásticas %K e %D estão em ou acima de 50.
  3. Avaliar a configuração curta. Todas as seguintes condições devem ser verdadeiras:
    • A abertura da vela atual é maior ou igual à abertura da vela anterior.
    • O Awesome Oscillator é negativo e está subindo em relação ao valor anterior.
    • A linha principal MACD é negativa e está caindo em relação ao valor anterior.
    • O histograma OsMA não está diminuindo (histograma atual menos histograma anterior é maior ou igual a zero).
    • A abertura da vela atual está abaixo da média móvel suavizada.
    • As linhas estocásticas %K e %D estão em ou abaixo de 50.
  4. Se uma posição já existir, um sinal oposto a fecha imediatamente, replicando o gerenciamento de ordens original do MetaTrader.
  5. Quando plano, uma entrada longa tem prioridade: se ambos os sinais forem verdadeiros (possível quando todos os indicadores são exatamente zero), a estratégia abre uma posição longa. Caso contrário, abre uma posição curta quando apenas as condições curtas são satisfeitas.

Parâmetros

  • SMMA Period – comprimento do filtro de média móvel suavizada (padrão 45).
  • MACD Fast / Slow / Signal – períodos EMA para o indicador MACD (47 / 95 / 74).
  • Stochastic %K / %D / Slowing – período principal, período de suavização e suavização adicional para o oscilador estocástico (25 / 12 / 56).
  • Order Volume – quantidade usada para ordens de mercado (padrão 1).
  • Candle Type – período das velas de entrada (padrão 1 hora). Ajuste para corresponder ao período usado no MetaTrader.

Notas de Uso

  • A estratégia opera apenas em velas terminadas; atualizações intrabarra são ignoradas.
  • Os valores de indicadores da vela anterior são armazenados em cache para que as comparações de momentum correspondam ao comportamento exato das funções auxiliares originais fao1, fmacd1 e fosma1.
  • Não há regras integradas de stop-loss ou take-profit no consultor especialista original. O gerenciamento de risco deve ser adicionado externamente se necessário.
  • As configurações padrão de indicadores correspondem aos parâmetros MQL fornecidos, mas todos os valores são expostos como objetos StrategyParam e podem ser otimizados através do otimizador StockSharp.

Considerações de Conversão

  • A versão MetaTrader usa um número mágico e validação manual de volume; essas partes não são necessárias no StockSharp e foram omitidas.
  • A lógica de fechamento de ordens segue a mesma precedência que o script MQL: as posições são fechadas primeiro, e novas entradas só são feitas quando a estratégia está plana.
  • As implementações do Awesome Oscillator e MACD vêm da biblioteca de indicadores StockSharp, eliminando a necessidade de manipulação manual de buffer presente no código original.
using System;
using System.Collections.Generic;

using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;

namespace StockSharp.Samples.Strategies;

/// <summary>
/// SSB5 123 strategy. Uses triple EMA alignment for 1-2-3 pattern detection.
/// </summary>
public class Ssb5123Strategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _midPeriod;
	private readonly StrategyParam<int> _slowPeriod;

	private decimal? _prevFast;
	private decimal? _prevMid;

	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	public int FastPeriod
	{
		get => _fastPeriod.Value;
		set => _fastPeriod.Value = value;
	}

	public int MidPeriod
	{
		get => _midPeriod.Value;
		set => _midPeriod.Value = value;
	}

	public int SlowPeriod
	{
		get => _slowPeriod.Value;
		set => _slowPeriod.Value = value;
	}

	public Ssb5123Strategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe", "General");

		_fastPeriod = Param(nameof(FastPeriod), 5)
			.SetGreaterThanZero()
			.SetDisplay("Fast EMA", "Fast EMA period", "Indicators");

		_midPeriod = Param(nameof(MidPeriod), 12)
			.SetGreaterThanZero()
			.SetDisplay("Mid EMA", "Middle EMA period", "Indicators");

		_slowPeriod = Param(nameof(SlowPeriod), 26)
			.SetGreaterThanZero()
			.SetDisplay("Slow EMA", "Slow EMA period", "Indicators");
	}

	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		return [(Security, CandleType)];
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevFast = null;
		_prevMid = null;
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		_prevFast = null;
		_prevMid = null;

		var fast = new ExponentialMovingAverage { Length = FastPeriod };
		var mid = new ExponentialMovingAverage { Length = MidPeriod };
		var slow = new ExponentialMovingAverage { Length = SlowPeriod };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(fast, mid, slow, ProcessCandle)
			.Start();

		var area = CreateChartArea();
		if (area != null)
		{
			DrawCandles(area, subscription);
			DrawIndicator(area, fast);
			DrawIndicator(area, mid);
			DrawIndicator(area, slow);
			DrawOwnTrades(area);
		}
	}

	private void ProcessCandle(ICandleMessage candle, decimal fastVal, decimal midVal, decimal slowVal)
	{
		if (candle.State != CandleStates.Finished)
			return;

		if (!IsFormedAndOnlineAndAllowTrading())
		{
			_prevFast = fastVal;
			_prevMid = midVal;
			return;
		}

		if (_prevFast == null || _prevMid == null)
		{
			_prevFast = fastVal;
			_prevMid = midVal;
			return;
		}

		// Fast crosses above mid while both above slow
		if (_prevFast.Value <= _prevMid.Value && fastVal > midVal && midVal > slowVal && Position <= 0)
		{
			if (Position < 0)
				BuyMarket();
			BuyMarket();
		}
		// Fast crosses below mid while both below slow
		else if (_prevFast.Value >= _prevMid.Value && fastVal < midVal && midVal < slowVal && Position >= 0)
		{
			if (Position > 0)
				SellMarket();
			SellMarket();
		}

		_prevFast = fastVal;
		_prevMid = midVal;
	}
}