Ver en GitHub

Estrategia Premarket Gap MomoTrader

Esta estrategia opera una única ruptura larga durante la sesión de premarket cuando la vela actual gana al menos un porcentaje especificado por encima del cierre anterior, imprime una vela alcista con volumen suficiente y el cuerpo de la vela ocupa una gran parte de su rango. El tamaño de la posición se escala según el tamaño del cuerpo.

Tras la entrada, la estrategia mantiene la posición mientras las siguientes velas permanezcan alcistas y su volumen aumente. Una vela roja o un volumen que no aumenta cierra la posición. Solo se permite una operación por día y el trading puede restringirse a la sesión 04:00–09:30.

Detalles

  • Criterios de entrada:
    • Ganancia de la vela actual ≥ MinGainPct comparada con el cierre anterior.
    • La vela es verde y Volume > MinVolume.
    • El porcentaje del cuerpo define el tamaño de la posición: ≥90% → 100%, ≥85% → 50%, ≥75% → 25%.
    • Filtro de sesión opcional 04:00–09:30 si UseSession está habilitado.
  • Criterios de salida:
    • Primera vela roja o vela con volumen no creciente después de la entrada.
  • Stops: No.
  • Valores predeterminados:
    • MinGainPct = 5.
    • MinVolume = 15000.
    • UseSession = true.
  • Filtros:
    • Categoría: Momentum
    • Dirección: Largo
    • Indicadores: Ninguno
    • Stops: No
    • Complejidad: Moderado
    • Marco temporal: Intradía
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>
/// Premarket Gap MomoTrader strategy using EMA crossover.
/// </summary>
public class PremarketGapMomoTraderStrategy : Strategy
{
	private readonly StrategyParam<int> _slowLength;
	private readonly StrategyParam<DataType> _candleType;

	/// <summary>
	/// Slow EMA period.
	/// </summary>
	public int SlowLength
	{
		get => _slowLength.Value;
		set => _slowLength.Value = value;
	}

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

	/// <summary>
	/// Initializes a new instance.
	/// </summary>
	public PremarketGapMomoTraderStrategy()
	{
		_slowLength = Param(nameof(SlowLength), 40)
			.SetGreaterThanZero()
			.SetDisplay("Slow Length", "Slow EMA period", "General");

		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
			.SetDisplay("Candle Type", "Candle type", "General");
	}

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

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

		var fast = new ExponentialMovingAverage { Length = 14 };
		var slow = new ExponentialMovingAverage { Length = SlowLength };

		var prevF = 0m;
		var prevS = 0m;
		var init = false;
		var lastSignal = DateTimeOffset.MinValue;
		var cooldown = TimeSpan.FromMinutes(360);

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(fast, slow, (candle, f, s) =>
			{
				if (candle.State != CandleStates.Finished)
					return;

				if (!fast.IsFormed || !slow.IsFormed)
					return;

				if (!init)
				{
					prevF = f;
					prevS = s;
					init = true;
					return;
				}

				if (candle.OpenTime - lastSignal >= cooldown)
				{
					if (prevF <= prevS && f > s && Position <= 0)
					{
						BuyMarket();
						lastSignal = candle.OpenTime;
					}
					else if (prevF >= prevS && f < s && Position >= 0)
					{
						SellMarket();
						lastSignal = candle.OpenTime;
					}
				}

				prevF = f;
				prevS = s;
			})
			.Start();

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