Ver no GitHub

Demonstração de sinal universal

Esta estratégia replica o especialista MetaTrader 5 "Universal Signal" usando StockSharp APIs de alto nível. Avalia oito padrões de mercado ponderados e os agrega em uma única pontuação composta. Quando a pontuação ultrapassa limites configuráveis, a estratégia abre ou fecha posições longas e curtas, opcionalmente usando ordens de limite pendentes que expiram após um determinado número de barras.

Parâmetros de Estratégia

  • CandleType – dados de velas usados para a análise.
  • SignalThresholdOpen – pontuação composta mínima necessária para abrir uma posição.
  • SignalThresholdClose – pontuação adversária necessária para sair de uma posição existente.
  • PriceLevel – compensação de preço para colocação de entradas de limite pendentes (0 significa execução de mercado).
  • StopLevel / TakeLevel – distâncias absolutas de stop-loss e take-profit usadas pelo módulo de proteção integrado.
  • SignalExpiration – número de barras após as quais as entradas pendentes ainda ativas são canceladas.
  • Pattern0WeightPattern7Weight – peso aplicado a cada padrão antes da agregação.
  • UniversalWeight – multiplicador final aplicado à soma de todas as contribuições do padrão.
  • ShortMaPeriod, LongMaPeriod, RsiPeriod, BollingerPeriod, BollingerWidth, TrendSmaPeriod, VolumeSmaPeriod – configurações do indicador usadas nas verificações de padrão.

Lógica de negociação

  1. Assine o fluxo de vela configurado e vincule EMA, RSI, MACD sinal, Bollinger bandas e SMAs de suporte.
  2. Após cada vela concluída, calcule oito padrões booleanos (alinhamento de tendência, RSI impulso, MACD histograma, Bollinger posicionamento, direção da vela e expansão de volume).
  3. Multiplique cada padrão pelo seu peso, some as contribuições e aplique o peso global para obter a pontuação final.
  4. Feche as posições abertas quando a pontuação ultrapassar o limite de fechamento na direção oposta.
  5. Abra novas posições longas ou curtas quando a pontuação exceder o limite de abertura. Se PriceLevel for positivo, envie uma ordem de limite compensada pela distância configurada e cancele-a automaticamente após SignalExpiration barras.
  6. StartProtection define níveis fixos de stop-loss e take-profit para todas as posições usando os auxiliares de gerenciamento de risco de StockSharp.

A conversão mantém o fluxo de trabalho de ponderação flexível do especialista MQL5 original, ao mesmo tempo que segue as convenções de codificação StockSharp e o processamento baseado em indicadores.

namespace StockSharp.Samples.Strategies;

using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;

/// <summary>
/// Universal Signal Demo strategy: Multi-indicator scoring.
/// Combines RSI and EMA signals to generate aggregate score for entries.
/// </summary>
public class UniversalSignalDemoStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _rsiPeriod;
	private readonly StrategyParam<int> _emaPeriod;
	private readonly StrategyParam<int> _signalCooldownCandles;
	private int _prevScore;
	private int _candlesSinceTrade;
	private bool _hasPrevScore;

	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
	public int RsiPeriod { get => _rsiPeriod.Value; set => _rsiPeriod.Value = value; }
	public int EmaPeriod { get => _emaPeriod.Value; set => _emaPeriod.Value = value; }
	public int SignalCooldownCandles { get => _signalCooldownCandles.Value; set => _signalCooldownCandles.Value = value; }

	public UniversalSignalDemoStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
			.SetDisplay("Candle Type", "Candle timeframe", "General");
		_rsiPeriod = Param(nameof(RsiPeriod), 21)
			.SetGreaterThanZero()
			.SetDisplay("RSI Period", "RSI period", "Indicators");
		_emaPeriod = Param(nameof(EmaPeriod), 50)
			.SetGreaterThanZero()
			.SetDisplay("EMA Period", "EMA period", "Indicators");
		_signalCooldownCandles = Param(nameof(SignalCooldownCandles), 4)
			.SetGreaterThanZero()
			.SetDisplay("Signal Cooldown", "Bars to wait between trades", "Trading");
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevScore = 0;
		_candlesSinceTrade = SignalCooldownCandles;
		_hasPrevScore = false;
	}

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_prevScore = 0;
		_candlesSinceTrade = SignalCooldownCandles;
		_hasPrevScore = false;
		var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
		var ema = new ExponentialMovingAverage { Length = EmaPeriod };
		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(rsi, ema, ProcessCandle).Start();
	}

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

		if (_candlesSinceTrade < SignalCooldownCandles)
			_candlesSinceTrade++;

		var close = candle.ClosePrice;
		var score = 0;

		// RSI signal
		if (rsiValue < 30) score += 2;
		else if (rsiValue < 45) score += 1;
		else if (rsiValue > 70) score -= 2;
		else if (rsiValue > 55) score -= 1;

		// EMA signal
		if (close > emaValue) score += 1;
		else if (close < emaValue) score -= 1;

		// Candle direction
		if (candle.ClosePrice > candle.OpenPrice) score += 1;
		else if (candle.ClosePrice < candle.OpenPrice) score -= 1;

		var crossedUp = (!_hasPrevScore || _prevScore < 2) && score >= 2;
		var crossedDown = (!_hasPrevScore || _prevScore > -2) && score <= -2;

		if (crossedUp && Position <= 0 && _candlesSinceTrade >= SignalCooldownCandles)
		{
			BuyMarket();
			_candlesSinceTrade = 0;
		}
		else if (crossedDown && Position >= 0 && _candlesSinceTrade >= SignalCooldownCandles)
		{
			SellMarket();
			_candlesSinceTrade = 0;
		}

		_prevScore = score;
		_hasPrevScore = true;
	}
}