Ver en GitHub

Demostración de señal universal

Esta estrategia replica el experto MetaTrader 5 "Señal universal" utilizando StockSharp API de alto nivel. Evalúa ocho patrones de mercado ponderados y los agrega en una única puntuación compuesta. Cuando la puntuación cruza umbrales configurables, la estrategia abre o cierra posiciones largas y cortas, utilizando opcionalmente órdenes de límite pendientes que vencen después de un número determinado de barras.

Parámetros de estrategia

  • CandleType: datos de velas utilizados para el análisis.
  • SignalThresholdOpen: puntuación compuesta mínima requerida para abrir una posición.
  • SignalThresholdClose: puntuación contraria necesaria para salir de una posición existente.
  • PriceLevel – compensación de precio para colocar entradas de límite pendientes (0 significa ejecución de mercado).
  • StopLevel / TakeLevel: distancias absolutas de stop-loss y take-profit utilizadas por el módulo de protección integrado.
  • SignalExpiration – número de barras después de las cuales se cancelan las entradas pendientes aún activas.
  • Pattern0WeightPattern7Weight: peso aplicado a cada patrón antes de la agregación.
  • UniversalWeight: multiplicador final aplicado a la suma de todas las contribuciones del patrón.
  • ShortMaPeriod, LongMaPeriod, RsiPeriod, BollingerPeriod, BollingerWidth, TrendSmaPeriod, VolumeSmaPeriod: configuraciones de indicadores utilizadas dentro de las comprobaciones de patrones.

Lógica de trading

  1. Suscríbase al flujo de velas configurado y vincule EMA, RSI, MACD señal, Bollinger bandas y SMA de soporte.
  2. Después de cada vela terminada, calcule ocho patrones booleanos (alineación de tendencia, RSI impulso, MACD histograma, Bollinger posicionamiento, dirección de la vela y expansión de volumen).
  3. Multiplica cada patrón por su peso, suma las contribuciones y aplica el peso global para obtener la puntuación final.
  4. Cierre las posiciones abiertas cuando la puntuación cruce el umbral de cierre en la dirección opuesta.
  5. Abra nuevas posiciones largas o cortas cuando la puntuación supere el umbral de apertura. Si PriceLevel es positivo, envíe una orden limitada compensada por la distancia configurada y cancélela automáticamente después de SignalExpiration barras.
  6. StartProtection establece niveles fijos de stop-loss y take-profit para todas las posiciones utilizando los asistentes de gestión de riesgos de StockSharp.

La conversión mantiene el flujo de trabajo de ponderación flexible del experto MQL5 original mientras sigue las convenciones de codificación StockSharp y el procesamiento basado en 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;
	}
}