Ver en GitHub

Estrategia Ingrit

Descripción general

Ingrit es una conversión del asesor experto de MetaTrader 5 Ingrit.mq5. La estrategia observa velas de cinco minutos y reacciona cuando una vela fuerte a contratendencia es seguida por un amplio breakout medido contra un swing de catorce barras atrás. Las órdenes se colocan a mercado con distancias configurables de stop-loss, take-profit y trailing stop expresadas en pips. Las señales pueden invertirse opcionalmente o forzarse a aplanar la exposición opuesta antes de entrar en una nueva operación.

Lógica de la estrategia

Detección de breakout

  • La estrategia procesa únicamente velas finalizadas del marco temporal seleccionado (por defecto 5 minutos).
  • Para una configuración long, la vela anterior debe cerrar bajista y la distancia entre el máximo de la vela 14 barras atrás y el mínimo de la vela anterior debe superar StepPips (tras convertir pips a unidades de precio).
  • Para una configuración short, la vela anterior debe cerrar alcista y la distancia entre el máximo de la vela anterior y el mínimo de la vela 14 barras atrás debe superar StepPips.
  • Habilitar ReverseSignals intercambia las condiciones long y short, recreando el modo de reversión opcional del robot original.

Gestión de operaciones

  • Las órdenes de mercado se envían usando el Volume de la estrategia. Cuando CloseOppositePositions está habilitado, el tamaño solicitado se incrementa en el valor absoluto de la posición actual para que las reversiones cierren la exposición existente en la misma operación.
  • Un stop-loss fijo y take-profit (si es mayor que cero) se adjuntan inmediatamente después de la entrada. Ambas distancias se convierten desde pips usando el paso de precio del instrumento y se adaptan automáticamente a cotizaciones FX de tres y cinco dígitos.
  • El trailing stop se activa una vez que el beneficio no realizado supera TrailingStopPips + TrailingStepPips. Para posiciones long el stop sigue por debajo del cierre; para posiciones short sigue por encima del cierre. Cada actualización mantiene el stop al menos TrailingStepPips lejos del nivel de trailing anterior para evitar modificaciones rápidas.

Comportamiento adicional

  • El trailing puede desactivarse estableciendo TrailingStopPips en cero. Si el trailing está activo, el paso debe permanecer positivo (la estrategia realiza la misma validación que la versión MQL).
  • Todos los cálculos se ejecutan sobre velas completadas; no se requiere procesamiento intrabar en StockSharp.
  • La estrategia no crea órdenes pendientes: cada señal se ejecuta con una orden de mercado y los niveles de protección se simulan internamente.

Parámetros

Parámetro Descripción
CandleType Marco temporal utilizado para construir velas para la lógica de breakout. Por defecto: marco temporal de 5 minutos.
StopLossPips Distancia del stop-loss en pips. Un valor de 0 deshabilita el stop fijo.
TakeProfitPips Distancia del take-profit en pips. Un valor de 0 deshabilita el objetivo fijo.
TrailingStopPips Distancia base del trailing stop en pips. Establecer en 0 para deshabilitar el trailing.
TrailingStepPips Distancia extra en pips que debe ganarse antes de que el trailing stop se mueva de nuevo. Debe ser positivo cuando el trailing está habilitado.
StepPips Distancia mínima de swing en pips entre la vela de referencia y la última vela antes de que se active una señal.
ReverseSignals Si es true, intercambia las condiciones long y short (modo de reversión).
CloseOppositePositions Si es true, amplía la orden de mercado para aplanar cualquier exposición opuesta antes de abrir la nueva posición.
Volume Propiedad de la estrategia que define el tamaño base de la orden. Combinar con CloseOppositePositions para controlar el comportamiento de reversión.

Notas

  • Los valores de pip se derivan del paso de precio del instrumento. Cuando el instrumento usa tres o cinco decimales, la estrategia multiplica el paso por diez para que un pip sea igual a la definición estándar de FX.
  • No hay una versión en Python para esta estrategia en el repositorio.
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;

public class IngritStrategy : Strategy
{
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;
	private readonly StrategyParam<int> _stopLossPoints;
	private readonly StrategyParam<int> _takeProfitPoints;

	private ExponentialMovingAverage _fast;
	private ExponentialMovingAverage _slow;

	private decimal _prevFast;
	private decimal _prevSlow;
	private decimal _entryPrice;
	private int _cooldown;

	public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
	public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
	public int StopLossPoints { get => _stopLossPoints.Value; set => _stopLossPoints.Value = value; }
	public int TakeProfitPoints { get => _takeProfitPoints.Value; set => _takeProfitPoints.Value = value; }

	public IngritStrategy()
	{
		_fastPeriod = Param(nameof(FastPeriod), 14).SetGreaterThanZero().SetDisplay("Fast Period", "Fast EMA period", "Indicator");
		_slowPeriod = Param(nameof(SlowPeriod), 50).SetGreaterThanZero().SetDisplay("Slow Period", "Slow EMA period", "Indicator");
		_stopLossPoints = Param(nameof(StopLossPoints), 200).SetNotNegative().SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk");
		_takeProfitPoints = Param(nameof(TakeProfitPoints), 400).SetNotNegative().SetDisplay("Take Profit", "Take-profit in price steps", "Risk");
	}

	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		yield return (Security, TimeSpan.FromMinutes(5).TimeFrame());
	}

	protected override void OnReseted()
	{
		base.OnReseted();
		_fast = null; _slow = null;
		_prevFast = 0; _prevSlow = 0; _entryPrice = 0; _cooldown = 0;
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_fast = new ExponentialMovingAverage { Length = FastPeriod };
		_slow = new ExponentialMovingAverage { Length = SlowPeriod };
		var subscription = SubscribeCandles(TimeSpan.FromMinutes(5).TimeFrame());
		subscription.Bind(_fast, _slow, ProcessCandle);
		subscription.Start();
	}

	private void ProcessCandle(ICandleMessage candle, decimal fastValue, decimal slowValue)
	{
		if (candle.State != CandleStates.Finished) return;
		if (!_fast.IsFormed || !_slow.IsFormed) { _prevFast = fastValue; _prevSlow = slowValue; return; }
		if (_cooldown > 0) { _cooldown--; _prevFast = fastValue; _prevSlow = slowValue; return; }

		var close = candle.ClosePrice;
		var step = Security?.PriceStep ?? 1m;

		if (Position > 0 && _entryPrice > 0)
		{
			if (StopLossPoints > 0 && close <= _entryPrice - StopLossPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
			if (TakeProfitPoints > 0 && close >= _entryPrice + TakeProfitPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
		}
		else if (Position < 0 && _entryPrice > 0)
		{
			if (StopLossPoints > 0 && close >= _entryPrice + StopLossPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
			if (TakeProfitPoints > 0 && close <= _entryPrice - TakeProfitPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
		}

		if (_prevFast <= _prevSlow && fastValue > slowValue && Position <= 0)
		{ if (Position < 0) BuyMarket(); BuyMarket(); _entryPrice = close; _cooldown = 100; }
		else if (_prevFast >= _prevSlow && fastValue < slowValue && Position >= 0)
		{ if (Position > 0) SellMarket(); SellMarket(); _entryPrice = close; _cooldown = 100; }

		_prevFast = fastValue; _prevSlow = slowValue;
	}
}