Ver en GitHub

Estrategia de Ejecución Instantánea

Esta estrategia entra inmediatamente en una única posición en la primera vela completada y la gestiona con reglas simples de beneficio y riesgo. La dirección de la posición es seleccionable mediante parámetros. Una vez que se abre una operación, el algoritmo rastrea el beneficio y la pérdida y puede seguir el precio para proteger las ganancias.

La lógica reproduce el comportamiento del script MQL original que permitía la ejecución instantánea de órdenes de mercado con valores opcionales de take profit, stop loss y trailing stop.

Detalles

  • Criterios de entrada: abre una posición de mercado en la primera vela finalizada tras el inicio. La dirección está definida por el parámetro Direction.
  • Largo/Corto: Ambos lados soportados.
  • Criterios de salida:
    • Take profit alcanzado.
    • Stop loss alcanzado.
    • Trailing stop activado y el precio alcanza el nivel de trailing.
  • Stops: Están disponibles take profit, stop loss y trailing stop.
  • Valores predeterminados:
    • TakeProfit = 70 unidades de precio.
    • StopLoss = 0 (deshabilitado).
    • TrailingStart = 5 unidades de precio.
    • TrailingSize = 5 unidades de precio.
  • Filtros:
    • Categoría: Utilidad
    • Dirección: Ambos
    • Indicadores: Ninguno
    • Stops: Sí
    • Complejidad: Simple
    • Marco temporal: Cualquiera
    • Estacionalidad: No
    • Redes neuronales: No
    • Divergencia: No
    • Nivel de riesgo: Medio
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>
/// Strategy that opens a position based on EMA direction and manages it with
/// take profit, stop loss and trailing stop rules.
/// </summary>
public class InstantExecutionStrategy : Strategy
{
	private readonly StrategyParam<decimal> _takeProfitPct;
	private readonly StrategyParam<decimal> _stopLossPct;
	private readonly StrategyParam<int> _emaPeriod;
	private readonly StrategyParam<DataType> _candleType;

	private decimal? _prevEma;

	public decimal TakeProfitPct
	{
		get => _takeProfitPct.Value;
		set => _takeProfitPct.Value = value;
	}

	public decimal StopLossPct
	{
		get => _stopLossPct.Value;
		set => _stopLossPct.Value = value;
	}

	public int EmaPeriod
	{
		get => _emaPeriod.Value;
		set => _emaPeriod.Value = value;
	}

	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	public InstantExecutionStrategy()
	{
		_takeProfitPct = Param(nameof(TakeProfitPct), 3m)
			.SetDisplay("Take Profit %", "Take profit percentage", "Risk");

		_stopLossPct = Param(nameof(StopLossPct), 2m)
			.SetDisplay("Stop Loss %", "Stop loss percentage", "Risk");

		_emaPeriod = Param(nameof(EmaPeriod), 20)
			.SetGreaterThanZero()
			.SetDisplay("EMA Period", "EMA trend filter period", "Indicator");

		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(8).TimeFrame())
			.SetDisplay("Candle Type", "Type of candles to use", "General");
	}

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

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

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

		var ema = new ExponentialMovingAverage { Length = EmaPeriod };

		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(ema, (candle, emaValue) =>
		{
			if (candle.State != CandleStates.Finished)
				return;

			if (_prevEma.HasValue)
			{
				var rising = emaValue > _prevEma.Value;
				var falling = emaValue < _prevEma.Value;

				if (rising && candle.ClosePrice > emaValue && Position <= 0)
				{
					if (Position < 0) BuyMarket();
					BuyMarket();
				}
				else if (falling && candle.ClosePrice < emaValue && Position >= 0)
				{
					if (Position > 0) SellMarket();
					SellMarket();
				}
			}

			_prevEma = emaValue;
		}).Start();

		StartProtection(
			takeProfit: new Unit(TakeProfitPct, UnitTypes.Percent),
			stopLoss: new Unit(StopLossPct, UnitTypes.Percent),
			isStopTrailing: true,
			useMarketOrders: true);

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