Ver en GitHub

Estrategia Rnd Trade

Descripción general

  • Conversión del asesor experto de MetaTrader 5 RndTrade.mq5 a la API de estrategia de alto nivel de StockSharp.
  • Cierra cualquier posición existente en un intervalo de tiempo fijo y abre inmediatamente una nueva posición de mercado en una dirección seleccionada aleatoriamente.
  • Usa suscripciones de velas basadas en tiempo como reemplazo determinista de las callbacks de temporizador originales.

Parámetros

Nombre Tipo Predeterminado Descripción
IntervalMinutes int 60 Número de minutos entre el cierre de la posición actual y la apertura de una nueva posición aleatoria. Debe ser mayor que cero.
Volume decimal 1 Tamaño de posición usado para entradas a mercado. Derivado de la clase base Strategy.

Suscripciones de datos

  • Se suscribe a velas de marco temporal cuya longitud coincide con IntervalMinutes (p. ej., 60 → velas de 60 minutos).
  • El evento de cierre de vela (CandleStates.Finished) se usa para activar la lógica exactamente una vez por intervalo.

Lógica de trading

  1. Esperar la finalización de cada vela de intervalo.
  2. Omitir el procesamiento hasta que la estrategia esté formada, en línea y se permita el trading.
  3. Cerrar cualquier posición abierta creada durante el intervalo anterior.
  4. Generar un valor aleatorio para decidir entre una entrada larga o corta.
  5. Enviar una orden de mercado (BuyMarket o SellMarket) con el volumen configurado en la dirección seleccionada.

Notas de implementación

  • Se basa en SubscribeCandles().Bind(ProcessCandle) para evitar el sondeo manual de valores de indicadores o colecciones.
  • Llama a StartProtection() durante el inicio para que el módulo de riesgo integrado esté activo, aunque no se configure ningún stop-loss o take-profit explícito.
  • Usa Random de la biblioteca estándar para imitar el comportamiento MathRand() encontrado en la estrategia MQL original.
  • El código contiene comentarios en inglés que explican cómo cada paso de conversión se mapea a las características de StockSharp.

Diferencias con la estrategia MQL original

  • Los eventos de temporizador (OnTimer) se emulan mediante suscripciones de velas en lugar de la API de temporizador de MetaTrader.
  • El cierre de posición se maneja con ClosePosition() en lugar de iterar sobre listas de posiciones y llamar PositionClose para cada ticket.
  • La versión de StockSharp se basa en la propiedad integrada Volume para el dimensionamiento de posiciones en lugar de la consulta del lote mínimo del símbolo.
  • Las reglas de llenado de órdenes y la configuración de deslizamiento son gestionadas por el bróker o simulador conectado, por lo que no se configuran explícitamente en la estrategia.

Uso

  1. Adjuntar la estrategia a una cartera y un instrumento dentro del entorno StockSharp.
  2. Configurar IntervalMinutes y Volume según la frecuencia de trading y el tamaño deseados.
  3. Iniciar la estrategia. Aplanará y reabrirá posiciones automáticamente en cada intervalo sin ninguna entrada adicional.
  4. No se proporciona implementación en Python en este momento; solo está disponible la versión en C#.
using System;
using System.Linq;
using System.Collections.Generic;

using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Random direction trading strategy converted from the MetaTrader RndTrade EA.
/// The strategy closes any open position on each interval and immediately opens a new random position.
/// </summary>
public class RndTradeStrategy : Strategy
{
	private readonly StrategyParam<int> _intervalMinutes;

	/// <summary>
	/// Interval in minutes between closing the current position and opening a new random one.
	/// </summary>
	public int IntervalMinutes
	{
		get => _intervalMinutes.Value;
		set => _intervalMinutes.Value = value;
	}

	/// <summary>
	/// Initializes a new instance of the <see cref="RndTradeStrategy"/> class.
	/// </summary>
	public RndTradeStrategy()
	{
		_intervalMinutes = Param(nameof(IntervalMinutes), 360)
			.SetGreaterThanZero()
			.SetDisplay("Interval Minutes", "Minutes between closing and opening positions", "General");

		Volume = 1;
	}

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

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

		// Use time-based candles as a deterministic timer replacement.
		var timeFrame = TimeSpan.FromMinutes(IntervalMinutes).TimeFrame();

		var subscription = SubscribeCandles(timeFrame);
		subscription
			.Bind(ProcessCandle)
			.Start();

	}

	private void ProcessCandle(ICandleMessage candle)
	{
		// Process only final candles to execute logic exactly once per interval.
		if (candle.State != CandleStates.Finished)
			return;

		// Always close the existing position before selecting a new random direction.
		if (Position > 0)
			SellMarket(Position);
		else if (Position < 0)
			BuyMarket(Math.Abs(Position));

		// Derive a deterministic pseudo-random direction from the candle data.
		if (ShouldBuy(candle))
		{
			// Enter long after flattening the previous position.
			if (Position <= 0)
				BuyMarket(Volume);
		}
		else
		{
			// Enter short after flattening the previous position.
			if (Position >= 0)
				SellMarket(Volume);
		}
	}

	private static bool ShouldBuy(ICandleMessage candle)
	{
		var hash = HashCode.Combine(candle.OpenTime.Ticks, candle.ClosePrice, candle.TotalVolume);
		return (hash & 1) == 0;
	}
}