Ver en GitHub

Estrategia de Operador por Hora Programada

Esta estrategia envía órdenes de mercado a una hora predefinida y las protege con niveles fijos de stop loss y toma de ganancias.

Reglas de Trading

  • Cuando la hora actual alcanza Trade Hour:Trade Minute:Trade Second, la estrategia se activa una vez por sesión.
  • Si Allow Buy está habilitado, se abre una posición larga con el Volume especificado.
  • Si Allow Sell está habilitado, se abre una posición corta con el mismo Volume.
  • Las órdenes protectoras se gestionan mediante StartProtection usando valores en puntos para el stop loss y la toma de ganancias.

Parámetros

Nombre Descripción
Volume Tamaño de la orden.
Take Profit (ticks) Distancia de la toma de ganancias desde la entrada en ticks.
Stop Loss (ticks) Distancia del stop loss desde la entrada en ticks.
Allow Buy Habilitar operaciones largas.
Allow Sell Habilitar operaciones cortas.
Trade Hour Hora del día para operar (0-23).
Trade Minute Minuto de la hora para operar (0-59).
Trade Second Segundo del minuto para operar (0-59).
Candle Type Serie de velas usadas para rastrear el tiempo, por defecto velas de 1 segundo.

Notas

La estrategia abre operaciones solo una vez por ejecución. Para operar de nuevo, reinicie la estrategia o ajuste la hora de operación.

using System;
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>
/// EMA trend-following strategy with RSI filter.
/// </summary>
public class ScheduledTimeTraderStrategy : Strategy
{
	private readonly StrategyParam<int> _emaPeriod;
	private readonly StrategyParam<int> _rsiPeriod;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _prevEma;
	private decimal _prevClose;
	private bool _hasPrev;

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

	public ScheduledTimeTraderStrategy()
	{
		_emaPeriod = Param(nameof(EmaPeriod), 20)
			.SetGreaterThanZero()
			.SetDisplay("EMA Period", "EMA period", "Indicators");
		_rsiPeriod = Param(nameof(RsiPeriod), 14)
			.SetGreaterThanZero()
			.SetDisplay("RSI Period", "RSI period", "Indicators");
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Type of candles", "General");
	}

	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
		=> [(Security, CandleType)];

	protected override void OnReseted()
	{
		base.OnReseted();
		_prevEma = 0;
		_prevClose = 0;
		_hasPrev = false;
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		var ema = new ExponentialMovingAverage { Length = EmaPeriod };
		var rsi = new RelativeStrengthIndex { Length = RsiPeriod };

		SubscribeCandles(CandleType).Bind(ema, rsi, ProcessCandle).Start();
	}

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

		var close = candle.ClosePrice;

		if (!_hasPrev) { _prevEma = emaValue; _prevClose = close; _hasPrev = true; return; }

		// Buy: close crosses above EMA and RSI confirms
		if (_prevClose <= _prevEma && close > emaValue && rsiValue < 65 && Position <= 0)
		{
			if (Position < 0) BuyMarket();
			BuyMarket();
		}
		// Sell: close crosses below EMA and RSI confirms
		else if (_prevClose >= _prevEma && close < emaValue && rsiValue > 35 && Position >= 0)
		{
			if (Position > 0) SellMarket();
			SellMarket();
		}

		_prevEma = emaValue;
		_prevClose = close;
	}
}