Ver en GitHub

Órdenes de días y horas específicas

Esta estrategia replica el experto MetaTrader "Día y hora específicos del Asesor Experto". Coloca órdenes de compra y/o venta en una marca de tiempo programada y, opcionalmente, elimina cada exposición en otra marca de tiempo. La versión StockSharp mantiene el comportamiento original de gestión de riesgos, incluidos trailingstops opcionales y movimientos de equilibrio.

Lógica central

  1. Programación

    • OpenTime – momento en el que se crean las órdenes.
    • CloseTime – momento en el que las posiciones se aplanan y las órdenes pendientes se pueden eliminar. Ambas comprobaciones aceptan una ventana de un minuto, que coincide con la comparación TimeToString(..., TIME_MINUTES) utilizada en el código MT4.
  2. Realización de pedidos

    • OrderPlacement elige entre órdenes de mercado, stop o límite.
    • OpenBuyOrders / OpenSellOrders habilita las direcciones deseadas.
    • OrderDistancePoints compensa el precio de las órdenes pendientes en una cantidad de puntos (pips).
    • PendingExpireMinutes cancela los pedidos pendientes automáticamente cuando finaliza su ventana de validez.
  3. Gestión de volumen

    • LotSizing = Manual envía el ManualVolume fijo.
    • LotSizing = Automatic calcula el volumen a partir del valor actual de la cartera y el tamaño del contrato del instrumento: volume = (portfolio / contractSize) * RiskFactor. El resultado se alinea con Security.VolumeStep y se fija entre MinVolume/MaxVolume cuando esté disponible.
  4. Lógica de protección

    • StopLossPoints y TakeProfitPoints traducen las distancias originales basadas en puntos a precios absolutos utilizando el tamaño del pip del instrumento.
    • TrailingStopEnabled + TrailingStepPoints y BreakEvenEnabled mueven la parada de protección exactamente como el script MQL, utilizando actualizaciones de oferta/demanda como activadores.
    • Cuando se alcanzan las condiciones de límite de pérdidas o toma de ganancias, la posición se cierra con una orden de mercado, reflejando el comportamiento de MT4 de modificar los límites a un nuevo precio.
  5. Fase de cierre

    • Cuando CloseOwnOrders o CloseAllOrders está habilitado, la estrategia sale de cualquier posición abierta en la ventana de cierre.
    • DeletePendingOrders elimina todas las órdenes pendientes restantes al mismo tiempo.

Parámetros

Nombre Descripción
OpenTime, CloseTime Marcas de tiempo UTC para entrar y salir del mercado.
OrderPlacement Colocación de órdenes de mercado, stop o límite.
OpenBuyOrders, OpenSellOrders Instrucciones para activar.
TakeProfitPoints, StopLossPoints Distancias de protección expresadas en puntos (0 inhabilitaciones).
TrailingStopEnabled, TrailingStepPoints Habilite el trailing stop y defina el avance mínimo antes de moverlo.
BreakEvenEnabled, BreakEvenAfterPoints Cambie el límite al punto de equilibrio una vez que la ganancia supere el umbral.
OrderDistancePoints Compensación utilizada para órdenes pendientes.
PendingExpireMinutes Ventana de vencimiento para órdenes pendientes.
LotSizing Dimensionamiento de volumen manual o automático.
RiskFactor, ManualVolume Entradas para los modos de dimensionamiento.
CloseOwnOrders, CloseAllOrders, DeletePendingOrders Controla cómo se cierran al final las posiciones y órdenes pendientes.

Notas

  • La clase reside en el espacio de nombres StockSharp.Samples.Strategies con sangría de tabulación como lo exigen las pautas del proyecto.
  • Los datos de nivel 1 se utilizan para reproducir la lógica sensible a la oferta y la demanda de la versión MQL (parada dinámica, colocación de orden pendiente).
  • La configuración de MagicNumber de MT4 no es necesaria porque StockSharp ya aísla las órdenes estratégicas.

Uso

  1. Compile el proyecto a través de AlgoTrading.sln y adjunte la estrategia a un par de valores/cartera.
  2. Ajuste el cronograma, el tipo de orden y los parámetros de riesgo según sea necesario.
  3. Inicie la estrategia antes de OpenTime; Los pedidos se enviarán automáticamente una vez que comience la ventana.
  4. Mantenga la estrategia ejecutándose hasta después de CloseTime si desea que se active el paso de aplanamiento automático.
namespace StockSharp.Samples.Strategies;

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

/// <summary>
/// Specific Day Time strategy: SMA crossover with time filter.
/// Trades only during specific hours, using fast/slow SMA crossover.
/// </summary>
public class SpecificDayTimeStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;
	private readonly StrategyParam<int> _tradeHour;
	private readonly StrategyParam<int> _cooldownBars;

	private int _cooldown;

	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
	public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
	public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
	public int TradeHour { get => _tradeHour.Value; set => _tradeHour.Value = value; }
	public int CooldownBars { get => _cooldownBars.Value; set => _cooldownBars.Value = value; }

	public SpecificDayTimeStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
			.SetDisplay("Candle Type", "Candle timeframe", "General");
		_fastPeriod = Param(nameof(FastPeriod), 8)
			.SetGreaterThanZero()
			.SetDisplay("Fast SMA", "Fast SMA period", "Indicators");
		_slowPeriod = Param(nameof(SlowPeriod), 21)
			.SetGreaterThanZero()
			.SetDisplay("Slow SMA", "Slow SMA period", "Indicators");
		_tradeHour = Param(nameof(TradeHour), 12)
			.SetDisplay("Trade Hour", "Hour when entries are allowed", "Trading")
			.SetRange(0, 23);
		_cooldownBars = Param(nameof(CooldownBars), 8)
			.SetGreaterThanZero()
			.SetDisplay("Cooldown Bars", "Bars to wait between orders", "Trading");
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_cooldown = 0;
	}

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_cooldown = 0;
		var fast = new SimpleMovingAverage { Length = FastPeriod };
		var slow = new SimpleMovingAverage { Length = SlowPeriod };
		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(fast, slow, ProcessCandle).Start();
	}

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

		if (_cooldown > 0)
			_cooldown--;

		var bullishTrend = fastValue > slowValue;
		var bearishTrend = fastValue < slowValue;

		if (_cooldown == 0 && candle.OpenTime.Hour == TradeHour)
		{
			if (bullishTrend && Position <= 0)
			{
				BuyMarket();
				_cooldown = CooldownBars;
			}
			else if (bearishTrend && Position >= 0)
			{
				SellMarket();
				_cooldown = CooldownBars;
			}
		}
		else if (_cooldown == 0)
		{
			if (Position > 0 && bearishTrend)
			{
				SellMarket();
				_cooldown = CooldownBars;
			}
			else if (Position < 0 && bullishTrend)
			{
				BuyMarket();
				_cooldown = CooldownBars;
			}
		}
	}
}