Ver en GitHub

Estrategia RDS de tendencia

Descripción general

Trend RDS es una estrategia de inversión basada en sesiones escrita originalmente para MetaTrader. Busca una formación de impulso de tres barras al comienzo de una ventana comercial específica y desvanece el movimiento ingresando en la dirección opuesta. El puerto StockSharp mantiene la lógica de administración de dinero original, incluida la inversión opcional de las señales, niveles fijos de stop-loss y take-profit, protección de equilibrio y un trailing stop con tamaño de paso ajustable.

Lógica de trading

  1. Ventana de señal: en el Start Time configurado, la estrategia inspecciona hasta 100 velas cerradas recientemente.
  2. Detección de patrones: busca la primera secuencia de tres barras consecutivas donde:
    • Los máximos aumentan mientras que los mínimos aumentan (High[n] < High[n+1] < High[n+2] y Low[n] > Low[n+1] > Low[n+2]).
    • Los máximos caen mientras que los mínimos caen (High[n] > High[n+1] > High[n+2] y Low[n] < Low[n+1] < Low[n+2]). Una expansión simétrica en ambas direcciones se trata como un conflicto y se ignora. La dirección de la señal se invierte opcionalmente cuando Reverse Signals está habilitado.
  3. Entradas: la estrategia envía una orden de mercado con el Trade Volume configurado si no hay ninguna posición abierta. Si la posición opuesta todavía está abierta, se cierra primero.
  4. Ventana de salida forzada – Entre Close Time y quince minutos después se liquida cualquier posición residual.
  5. Protección – Una vez abierta la posición, la estrategia registra:
    • Una orden de stop-loss y take-profit a las distancias de pips solicitadas.
    • Un disparador de equilibrio que mueve el stop al precio de entrada después de alcanzar Break-Even (pips).
    • Un trailing stop que mantiene una distancia de Trailing Stop (pips) del precio actual y avanza sólo después de un movimiento adicional de Trailing Step (pips).

Parámetros

Nombre Descripción
Volumen comercial Tamaño de la orden de mercado expresado en lotes o contratos.
Detener pérdidas (pips) Distancia al tope de protección. Establezca en cero para desactivar.
Obtener ganancias (pips) Distancia al objetivo de ganancias. Establezca en cero para desactivar.
Hora de inicio Hora del día (hora de intercambio) en la que comienza la búsqueda de patrones.
Hora de cierre Hora del día (hora de cambio) en la que todas las operaciones abiertas se cierran en 15 minutos.
Señales inversas Invierte entradas largas y cortas.
Parada dinámica (pips) Distancia de seguimiento de la base. Zero desactiva el seguimiento.
Paso final (pips) Se necesita movimiento adicional antes de que el trailing stop se actualice nuevamente.
** Punto de equilibrio (pips) ** Umbral de beneficio para mover el stop al precio de entrada. Zero desactiva la función.
Tipo de vela Serie de velas utilizadas para el análisis.

Notas prácticas

  • La estrategia se basa en el paso del precio del instrumento para calcular las distancias de los pips. Asegúrese de que la seguridad exponga un valor PriceStep o MinPriceStep válido.
  • Sólo se procesan velas terminadas, por lo que la señal puede aparecer como máximo una vez al día por período de tiempo.
  • Las órdenes stop y take-profit se actualizan cada vez que cambia el tamaño de la posición, lo que garantiza que las ejecuciones parciales mantengan una protección constante.
  • La lógica de seguimiento y de equilibrio se activa sólo mientras una posición está abierta y se conoce un precio de entrada válido.

Archivos

  • CS/TrendRdsStrategy.cs – StockSharp Implementación C# de la estrategia.
  • README_zh.md – Documentación china.
  • README_ru.md – Documentación rusa.
using System;
using System.Linq;
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>
/// Port of the MetaTrader Trend_RDS expert advisor.
/// Detects three-bar momentum patterns and reverses into the move.
/// Includes configurable stop-loss, take-profit, and trailing management.
/// </summary>
public class TrendRdsReversalStrategy : Strategy
{
	private readonly StrategyParam<decimal> _tradeVolume;
	private readonly StrategyParam<decimal> _stopLossPips;
	private readonly StrategyParam<decimal> _takeProfitPips;
	private readonly StrategyParam<bool> _reverseSignals;
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _maxPatternDepth;

	private readonly List<(decimal High, decimal Low)> _recentExtremes = new();

	/// <summary>
	/// Trading volume for market entries.
	/// </summary>
	public decimal TradeVolume
	{
		get => _tradeVolume.Value;
		set => _tradeVolume.Value = value;
	}

	/// <summary>
	/// Stop-loss distance in absolute price units.
	/// </summary>
	public decimal StopLossPips
	{
		get => _stopLossPips.Value;
		set => _stopLossPips.Value = value;
	}

	/// <summary>
	/// Take-profit distance in absolute price units.
	/// </summary>
	public decimal TakeProfitPips
	{
		get => _takeProfitPips.Value;
		set => _takeProfitPips.Value = value;
	}

	/// <summary>
	/// Inverts the buy and sell conditions when enabled.
	/// </summary>
	public bool ReverseSignals
	{
		get => _reverseSignals.Value;
		set => _reverseSignals.Value = value;
	}

	/// <summary>
	/// Candle type processed by the strategy.
	/// </summary>
	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	/// <summary>
	/// Maximum number of swings tracked when validating the pattern.
	/// </summary>
	public int MaxPatternDepth
	{
		get => _maxPatternDepth.Value;
		set => _maxPatternDepth.Value = value;
	}

	/// <summary>
	/// Initializes a new instance of the <see cref="TrendRdsReversalStrategy"/> class.
	/// </summary>
	public TrendRdsReversalStrategy()
	{
		_tradeVolume = Param(nameof(TradeVolume), 1m)
			.SetGreaterThanZero()
			.SetDisplay("Trade Volume", "Market order volume", "General");

		_stopLossPips = Param(nameof(StopLossPips), 500m)
			.SetDisplay("Stop Loss", "Stop-loss distance", "Risk");

		_takeProfitPips = Param(nameof(TakeProfitPips), 500m)
			.SetDisplay("Take Profit", "Take-profit distance", "Risk");

		_reverseSignals = Param(nameof(ReverseSignals), false)
			.SetDisplay("Reverse Signals", "Invert buy and sell signals", "Filters");

		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(8).TimeFrame())
			.SetDisplay("Candle Type", "Working timeframe", "General");

		_maxPatternDepth = Param(nameof(MaxPatternDepth), 10)
			.SetGreaterThanZero()
			.SetDisplay("Max Pattern Depth", "Maximum candles tracked for pattern detection", "General");
	}

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

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

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		// Use a dummy EMA to ensure candle callbacks fire in the backtester
		var ema = new EMA { Length = 5 };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(ema, ProcessCandle)
			.Start();

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

		// Use StartProtection for SL/TP
		var tp = TakeProfitPips > 0 ? new Unit(TakeProfitPips, UnitTypes.Absolute) : null;
		var sl = StopLossPips > 0 ? new Unit(StopLossPips, UnitTypes.Absolute) : null;
		StartProtection(tp, sl);

		base.OnStarted2(time);
	}

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

		// Track recent highs and lows
		_recentExtremes.Insert(0, (candle.HighPrice, candle.LowPrice));
		if (_recentExtremes.Count > MaxPatternDepth + 2)
			_recentExtremes.RemoveAt(_recentExtremes.Count - 1);

		if (!IsFormedAndOnlineAndAllowTrading())
			return;

		// Need at least 3 bars for the pattern
		if (_recentExtremes.Count < 3)
			return;

		var (buySignal, sellSignal) = DetectSignals();

		if (buySignal)
		{
			if (Position < 0)
				BuyMarket(Math.Abs(Position));
			if (Position <= 0)
				BuyMarket(Volume);
		}
		else if (sellSignal)
		{
			if (Position > 0)
				SellMarket(Position);
			if (Position >= 0)
				SellMarket(Volume);
		}
	}

	private (bool Buy, bool Sell) DetectSignals()
	{
		var depth = Math.Min(_recentExtremes.Count - 2, MaxPatternDepth);
		if (depth <= 0)
			return (false, false);

		for (var index = 0; index < depth; index++)
		{
			if (index + 2 >= _recentExtremes.Count)
				break;

			var first = _recentExtremes[index];
			var second = _recentExtremes[index + 1];
			var third = _recentExtremes[index + 2];

			// Conflict: both highs and lows rising simultaneously
			var conflict = first.High < second.High && second.High < third.High &&
				first.Low > second.Low && second.Low > third.Low;

			// Rising lows pattern -> buy
			if (!conflict && first.Low > second.Low && second.Low > third.Low)
			{
				return ReverseSignals ? (false, true) : (true, false);
			}

			// Rising highs pattern -> sell
			if (!conflict && first.High < second.High && second.High < third.High)
			{
				return ReverseSignals ? (true, false) : (false, true);
			}
		}

		return (false, false);
	}
}