Ver en GitHub

Estrategia de Trailing Stop Trigger Manager

Descripción general

La Estrategia Trailing Stop Trigger Manager es una StockSharp adaptación del MetaTrader asesor experto Trailing Sl.mq5. El EA original no abrió operaciones por sí solo. En lugar de ello, supervisó las posiciones ya abiertas con un número mágico coincidente y reforzó sus niveles de stop-loss cuando el mercado se movía en la dirección deseada. Esta implementación de C# reproduce ese comportamiento usando La estrategia de alto nivel de StockSharp API, que ofrece una gestión transparente de trailing-stop que funciona con cualquier instrumento compatible con StockSharp.

Lógica final

  1. Suscríbete al libro de pedidos para leer las últimas mejores ofertas y mejores cotizaciones.
  2. Detecta si la estrategia mantiene actualmente una posición neta larga o corta.
  3. Calcula el beneficio flotante utilizando el lado apropiado del mercado (mejor oferta para posiciones largas, mejor demanda para posiciones cortas).
  4. Activa el modo de seguimiento una vez que la ganancia excede TriggerPoints (convertida a unidades de precio hasta PriceStep).
  5. Establece el trailing stop a la distancia configurada TrailingPoints de la cotización de mercado actual.
  6. Mueve el trailing stop solo hacia el mercado para seguir obteniendo ganancias adicionales.
  7. Envía una orden de mercado para aplanar la posición tan pronto como la mejor cotización toque el nivel de trailing stop calculado.

Gestión de pedidos y riesgos.

  • La estrategia no envía órdenes de entrada iniciales. Solo gestiona una posición existente que puede haber sido abierta manualmente. o por otra estrategia.
  • Las salidas de mercado se colocan con BuyMarket/SellMarket, reflejando las llamadas PositionModify del código MetaTrader original.
  • La distancia de parada escala automáticamente con el PriceStep del instrumento, lo que preserva la configuración basada en puntos de el EA.
  • Una vez que se cierra la posición, el estado final se restablece para que las nuevas posiciones comiencen desde cero.

Parámetros

Nombre Tipo Predeterminado Descripción
TrailingPoints int 1000 Distancia entre el precio actual y el trailing stop, medida en incrementos de precio.
TriggerPoints int 1500 Beneficio mínimo en los pasos de precio requeridos para comenzar a rastrear la posición.

Notas de uso

  • Adjunte la estrategia al valor cuya posición desea supervisar. Inmediatamente comenzará a rastrear los existentes. exposición.
  • Configure el Volume inicial de la estrategia para que coincida con el tamaño de su posición abierta. StockSharp utiliza posiciones netas, por lo que el La estrategia saldrá de todo el lote cuando se active el trailing stop.
  • Si el corredor ofrece incrementos de precios aproximados, ajuste TrailingPoints y TriggerPoints en consecuencia para evitar salidas prematuras.
  • La estrategia mantiene su estado completamente dentro de StockSharp, por lo que se puede combinar con cualquier sistema discrecional o automatizado que deja la ejecución real de la orden en StockSharp.

Diferencias con el experto MetaTrader original

  • MetaTrader gestionó posiciones separadas por ticket y las filtró por número mágico. StockSharp trabaja con una posición neta por seguridad, eliminando la necesidad de filtrar tickets.
  • Las entradas Setloss, TakeProfit y Lots no se usaron en el EA original. Por lo tanto, se omiten en el StockSharp versión para mantener la configuración centrada en el comportamiento de seguimiento.
  • Las modificaciones de órdenes se reemplazan por salidas directas del mercado, que es el enfoque idiomático para compensar cuentas en StockSharp.
using System;
using System.Linq;
using System.Collections.Generic;

using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;

using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Strategy that mirrors the MetaTrader "Trailing Sl" expert by managing trailing stops for existing positions.
/// Adds SMA crossover entries for backtesting.
/// </summary>
public class TrailingStopTriggerManagerStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _trailingPoints;
	private readonly StrategyParam<int> _triggerPoints;

	private decimal _lastEntryPrice;
	private decimal? _activeStopPrice;
	private bool _trailingEnabled;
	private decimal _trailingDistance;
	private decimal _triggerDistance;
	private decimal _prevFast;
	private decimal _prevSlow;
	private bool _hasPrev;

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

	/// <summary>
	/// Trailing stop distance in price steps.
	/// </summary>
	public int TrailingPoints
	{
		get => _trailingPoints.Value;
		set => _trailingPoints.Value = value;
	}

	/// <summary>
	/// Profit distance that activates trailing stop.
	/// </summary>
	public int TriggerPoints
	{
		get => _triggerPoints.Value;
		set => _triggerPoints.Value = value;
	}

	/// <summary>
	/// Initializes a new instance of the strategy.
	/// </summary>
	public TrailingStopTriggerManagerStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe", "General");

		_trailingPoints = Param(nameof(TrailingPoints), 1000)
			.SetGreaterThanZero()
			.SetDisplay("Trailing Points", "Trailing stop distance", "Trailing Management");

		_triggerPoints = Param(nameof(TriggerPoints), 1500)
			.SetGreaterThanZero()
			.SetDisplay("Trigger Points", "Profit to activate trailing", "Trailing Management");
	}

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

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_lastEntryPrice = 0m;
		_activeStopPrice = null;
		_trailingEnabled = false;
		_trailingDistance = 0m;
		_triggerDistance = 0m;
		_prevFast = 0m;
		_prevSlow = 0m;
		_hasPrev = false;
	}

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

		var step = Security?.PriceStep ?? 1m;
		if (step <= 0m) step = 1m;
		_trailingDistance = step * TrailingPoints;
		_triggerDistance = step * TriggerPoints;

		var smaFast = new SimpleMovingAverage { Length = 10 };
		var smaSlow = new SimpleMovingAverage { Length = 30 };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(smaFast, smaSlow, ProcessCandle)
			.Start();

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

	/// <inheritdoc />
	protected override void OnOwnTradeReceived(MyTrade trade)
	{
		base.OnOwnTradeReceived(trade);
		_lastEntryPrice = trade.Trade.Price;
	}

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

		var price = candle.ClosePrice;

		// Trailing stop management
		if (Position > 0 && _lastEntryPrice > 0)
		{
			var profit = price - _lastEntryPrice;
			if (!_trailingEnabled && profit >= _triggerDistance)
			{
				_trailingEnabled = true;
				_activeStopPrice = price - _trailingDistance;
			}
			else if (_trailingEnabled)
			{
				var desiredStop = price - _trailingDistance;
				if (!_activeStopPrice.HasValue || desiredStop > _activeStopPrice.Value)
					_activeStopPrice = desiredStop;
			}

			if (_trailingEnabled && _activeStopPrice.HasValue && price <= _activeStopPrice.Value)
			{
				SellMarket();
				ResetTrailingState();
				return;
			}
		}
		else if (Position < 0 && _lastEntryPrice > 0)
		{
			var profit = _lastEntryPrice - price;
			if (!_trailingEnabled && profit >= _triggerDistance)
			{
				_trailingEnabled = true;
				_activeStopPrice = price + _trailingDistance;
			}
			else if (_trailingEnabled)
			{
				var desiredStop = price + _trailingDistance;
				if (!_activeStopPrice.HasValue || desiredStop < _activeStopPrice.Value)
					_activeStopPrice = desiredStop;
			}

			if (_trailingEnabled && _activeStopPrice.HasValue && price >= _activeStopPrice.Value)
			{
				BuyMarket();
				ResetTrailingState();
				return;
			}
		}

		// SMA crossover entries
		if (_hasPrev)
		{
			var crossUp = _prevFast <= _prevSlow && fast > slow;
			var crossDown = _prevFast >= _prevSlow && fast < slow;

			if (crossUp && Position <= 0)
			{
				if (Position < 0)
					BuyMarket();
				BuyMarket();
				ResetTrailingState();
			}
			else if (crossDown && Position >= 0)
			{
				if (Position > 0)
					SellMarket();
				SellMarket();
				ResetTrailingState();
			}
		}

		_prevFast = fast;
		_prevSlow = slow;
		_hasPrev = true;
	}

	private void ResetTrailingState()
	{
		_trailingEnabled = false;
		_activeStopPrice = null;
	}
}