Ver no GitHub

Estratégia de Secwenta MultiBar Signals

Visão Geral

Esta estratégia é um port do StockSharp do consultor especializado MetaTrader "Secwenta" (ID MQL 22977). O algoritmo escaneia candles concluídos e conta quantos fecharam em alta (fechamento > abertura) ou em baixa (fechamento < abertura) dentro de um histórico rolante curto. Dependendo da configuração, pode operar nos modos somente compra, somente venda ou reversão bidirecional. Quando o número necessário de barras de alta ou baixa aparece, a estratégia abre ou fecha posições de mercado usando um volume fixo que espelha a configuração de lote original.

Avaliação de sinais

  • Apenas candles terminados do CandleType selecionado são processados via API de assinatura de alto nível.
  • Para cada candle a estratégia registra se foi de alta, baixa ou neutro (doji). O buffer interno mantém as últimas N direções, onde N é o maior entre BullishBarCount e BearishBarCount entre os lados habilitados (compra e/ou venda).
  • O contador de alta incrementa quando um candle fecha acima de sua abertura, enquanto o contador de baixa incrementa em fechamentos abaixo da abertura. Candles neutros não afetam os contadores.
  • Um sinal é acionado uma vez que o contador correspondente atinge seu limiar configurado dentro da janela rolante. Isso reproduz a lógica MQL original que iterava pelas barras mais recentes até encontrar o número solicitado de candles de alta ou baixa.

Regras de negociação

  1. Modo somente compra (UseBuySignals = true, UseSellSignals = false):
    • Quando o contador de baixa atinge BearishBarCount, qualquer posição comprada existente é fechada com uma ordem de venda a mercado.
    • Quando o contador de alta atinge BullishBarCount e a estratégia está zerada, uma nova posição comprada é aberta usando OrderVolume.
  2. Modo somente venda (UseBuySignals = false, UseSellSignals = true):
    • Quando o contador de alta atinge BullishBarCount, uma posição vendida aberta é coberta com uma ordem de compra a mercado.
    • Quando o contador de baixa atinge BearishBarCount e a estratégia está zerada, uma nova posição vendida é aberta usando OrderVolume.
  3. Modo de reversão (UseBuySignals = true e UseSellSignals = true):
    • Um gatilho de alta fecha qualquer exposição vendida e, se a estratégia não estiver já comprada, abre uma nova posição comprada comprando OrderVolume mais o tamanho absoluto da posição vendida. Isso imita a sequência original de fechar vendas antes de abrir compras.
    • Um gatilho de baixa fecha qualquer exposição comprada e, se a estratégia não estiver já vendida, abre uma nova posição vendida vendendo OrderVolume mais o tamanho absoluto da posição comprada.

Todas as operações de mercado reutilizam os helpers BuyMarket e SellMarket do StockSharp, e a estratégia chama StartProtection() para que proteções no nível de conta possam ser sobrepostas se desejado.

Parâmetros

Parâmetro Descrição Padrão Notas
CandleType Tipo de dados de candle (período) usado para avaliar sequências. Período de 1 hora Qualquer tipo de candle suportado pelo StockSharp pode ser selecionado.
OrderVolume Volume base da ordem de mercado que espelha o tamanho de lote MQL. 1 Adicionado ao volume de fechamento ao reverter uma posição.
UseBuySignals Habilita o processamento de sinais de alta. true Quando desabilitado, nenhum novo trade comprado é aberto.
BullishBarCount Número de candles de alta necessários para acionar um evento de alta. 2 Deve permanecer consistente com o limiar de fechamento ao executar no modo somente compra.
UseSellSignals Habilita o processamento de sinais de baixa. false Quando desabilitado, nenhum novo trade vendido é aberto.
BearishBarCount Número de candles de baixa necessários para acionar um evento de baixa. 1 Atua tanto como limiar de abertura para vendidos quanto como limiar de saída para comprados.

Notas de implementação

  • A janela rolante usa uma fila para manter as últimas direções de candles e garante que os contadores correspondam ao tamanho da janela mesmo após mudanças de parâmetros.
  • Apenas candles terminados são processados para manter fidelidade ao tratamento original de eventos "nova barra".
  • Candles neutros (doji) deixam os contadores inalterados, exatamente como no código MQL.
  • As reversões são executadas com uma única ordem de mercado que combina o volume de fechamento e abertura, mantendo mudanças de exposição deterministas.
  • O comprimento do buffer é igual ao maior limiar ativo; se um lado está desabilitado, apenas o limiar correspondente contribui para o comprimento do lookback, correspondendo ao comportamento de CopyRates na versão MQL.

Arquivos

  • CS/SecwentaMultiBarSignalsStrategy.cs – implementação principal em C# construída sobre a API de estratégia de alto nível do StockSharp.

Nota: Nenhuma tradução para Python é fornecida para este ID; apenas a versão C# solicitada está disponível.

using System;
using System.Collections.Generic;

using Ecng.Common;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Secwenta MultiBar Signals strategy using SmoothedMA crossover.
/// Buys when fast SmoothedMA crosses above slow SmoothedMA, sells on reverse.
/// </summary>
public class SecwentaMultiBarSignalsStrategy : Strategy
{
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;
	private readonly StrategyParam<int> _stopLossPoints;
	private readonly StrategyParam<int> _takeProfitPoints;

	private SmoothedMovingAverage _fast;
	private SmoothedMovingAverage _slow;

	private decimal _prevFast;
	private decimal _prevSlow;
	private decimal _entryPrice;
	private int _cooldown;

	/// <summary>
	/// Fast SmoothedMA period.
	/// </summary>
	public int FastPeriod
	{
		get => _fastPeriod.Value;
		set => _fastPeriod.Value = value;
	}

	/// <summary>
	/// Slow SmoothedMA period.
	/// </summary>
	public int SlowPeriod
	{
		get => _slowPeriod.Value;
		set => _slowPeriod.Value = value;
	}

	/// <summary>
	/// Stop-loss distance in price steps.
	/// </summary>
	public int StopLossPoints
	{
		get => _stopLossPoints.Value;
		set => _stopLossPoints.Value = value;
	}

	/// <summary>
	/// Take-profit distance in price steps.
	/// </summary>
	public int TakeProfitPoints
	{
		get => _takeProfitPoints.Value;
		set => _takeProfitPoints.Value = value;
	}

	/// <summary>
	/// Initializes a new instance of the <see cref="SecwentaMultiBarSignalsStrategy"/> class.
	/// </summary>
	public SecwentaMultiBarSignalsStrategy()
	{
		_fastPeriod = Param(nameof(FastPeriod), 15)
			.SetGreaterThanZero()
			.SetDisplay("Fast Period", "Fast SmoothedMA period", "Indicator");

		_slowPeriod = Param(nameof(SlowPeriod), 60)
			.SetGreaterThanZero()
			.SetDisplay("Slow Period", "Slow SmoothedMA period", "Indicator");

		_stopLossPoints = Param(nameof(StopLossPoints), 200)
			.SetNotNegative()
			.SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk");

		_takeProfitPoints = Param(nameof(TakeProfitPoints), 400)
			.SetNotNegative()
			.SetDisplay("Take Profit", "Take-profit in price steps", "Risk");
	}

	/// <inheritdoc />
	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		yield return (Security, TimeSpan.FromMinutes(5).TimeFrame());
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();

		_fast = null;
		_slow = null;
		_prevFast = 0;
		_prevSlow = 0;
		_entryPrice = 0;
		_cooldown = 0;
	}

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		_fast = new SmoothedMovingAverage { Length = FastPeriod };
		_slow = new SmoothedMovingAverage { Length = SlowPeriod };

		var subscription = SubscribeCandles(TimeSpan.FromMinutes(5).TimeFrame());
		subscription.Bind(_fast, _slow, ProcessCandle);
		subscription.Start();
	}

	private void ProcessCandle(ICandleMessage candle, decimal fastValue, decimal slowValue)
	{
		if (candle.State != CandleStates.Finished)
			return;

		if (!_fast.IsFormed || !_slow.IsFormed)
		{
			_prevFast = fastValue;
			_prevSlow = slowValue;
			return;
		}

		if (_cooldown > 0)
		{
			_cooldown--;
			_prevFast = fastValue;
			_prevSlow = slowValue;
			return;
		}

		var close = candle.ClosePrice;
		var step = Security?.PriceStep ?? 1m;

		// Check SL/TP
		if (Position > 0 && _entryPrice > 0)
		{
			if (StopLossPoints > 0 && close <= _entryPrice - StopLossPoints * step)
			{
				SellMarket();
				_entryPrice = 0;
				_cooldown = 80;
				_prevFast = fastValue;
				_prevSlow = slowValue;
				return;
			}

			if (TakeProfitPoints > 0 && close >= _entryPrice + TakeProfitPoints * step)
			{
				SellMarket();
				_entryPrice = 0;
				_cooldown = 80;
				_prevFast = fastValue;
				_prevSlow = slowValue;
				return;
			}
		}
		else if (Position < 0 && _entryPrice > 0)
		{
			if (StopLossPoints > 0 && close >= _entryPrice + StopLossPoints * step)
			{
				BuyMarket();
				_entryPrice = 0;
				_cooldown = 80;
				_prevFast = fastValue;
				_prevSlow = slowValue;
				return;
			}

			if (TakeProfitPoints > 0 && close <= _entryPrice - TakeProfitPoints * step)
			{
				BuyMarket();
				_entryPrice = 0;
				_cooldown = 80;
				_prevFast = fastValue;
				_prevSlow = slowValue;
				return;
			}
		}

		// SmoothedMA crossover
		if (_prevFast <= _prevSlow && fastValue > slowValue && Position <= 0)
		{
			if (Position < 0)
				BuyMarket();

			BuyMarket();
			_entryPrice = close;
			_cooldown = 80;
		}
		else if (_prevFast >= _prevSlow && fastValue < slowValue && Position >= 0)
		{
			if (Position > 0)
				SellMarket();

			SellMarket();
			_entryPrice = close;
			_cooldown = 80;
		}

		_prevFast = fastValue;
		_prevSlow = slowValue;
	}
}