Ver en GitHub

Estrategia de intercambio de símbolos

La Estrategia de intercambio de símbolos es el puerto StockSharp de la utilidad MetaTrader 5 "Symbol Swap". El programa MQL5 original abre un panel donde un operador puede ingresar cualquier ticker, cambiar inmediatamente el gráfico actual a ese símbolo y monitorear una ventana de datos compacta con la última hora, precios de OHLC, volumen de ticks y spread. Esta conversión de C# mantiene las mismas responsabilidades y depende exclusivamente de la suscripción de alto nivel de StockSharp API.

Comportamiento

  1. Al inicio, la estrategia resuelve el instrumento a observar. Primero intenta WatchedSecurityId; si el campo está vacío, vuelve a Strategy.Security que está configurado en el iniciador.
  2. Los datos de la vela del CandleType elegido se transmiten a través de SubscribeCandles(...). Las barras terminadas brindan el volumen de apertura, máximo, mínimo, cierre y tick que puebla el panel.
  3. Los mejores valores de oferta/demanda en tiempo real llegan a través de SubscribeLevel1(...). El diferencial se recalcula en cada actualización de cotización para reflejar la ventana de datos MQL.
  4. El bloque formateado se escribe en el registro de estrategia (OutputMode = Log) o se representa en un gráfico (OutputMode = Chart) con DrawText(...), recreando el panel flotante de MetaTrader.
  5. Llamar a SwapSecurity("TICKER") durante la ejecución resuelve la nueva seguridad a través de SecurityProvider.LookupById y vuelve a suscribir sin problemas tanto la vela como los feeds de Nivel 1 al instrumento solicitado.

La estrategia es sólo informativa; no realiza pedidos. Puede ejecutarse de forma independiente como un panel de mercado o junto con otros robots comerciales.

Parámetros

Nombre Descripción Predeterminado
CandleType Marco de tiempo que define la suscripción de vela utilizada para generar OHLC y datos de volumen de ticks. TimeFrame(1 minute)
WatchedSecurityId Identificador de instrumento opcional. Déjelo vacío para usar Strategy.Security. vacío
OutputMode Destino de renderizado del bloque de información. Elija entre Chart (superposición cerca del precio) o Log (registro de estrategia). Chart

Métodos públicos

Método Descripción
SwapSecurity(string securityId) Resuelve el ticker proporcionado a través del SecurityProvider activo e inmediatamente cambia el panel a ese símbolo. El método se puede llamar varias veces; cada llamada borra las suscripciones anteriores de vela/Nivel 1 antes de agregar las nuevas fuentes.

Notas de uso

  • Asegúrese de que el conector exponga el identificador solicitado; de lo contrario, SecurityProvider.LookupById genera una excepción.
  • Cuando OutputMode = Chart, la estrategia crea automáticamente un área de gráfico, dibuja las velas suscritas y superpone el bloque de estado. Para el modo de registro sólo se producen las actualizaciones textuales.
  • El volumen de ticks es igual al TotalVolume de la vela, que es como MetaTrader informa su recuento de ticks por barra.
  • El diferencial se muestra solo cuando están disponibles tanto la mejor oferta como la mejor demanda. De lo contrario, el campo muestra n/a.

Detalles de conversión

  • El bucle del temporizador MetaTrader se reemplaza con suscripciones StockSharp. Las velas se activan una vez por barra terminada y las cotizaciones de Nivel 1 actualizan el diferencial en tiempo real.
  • Las etiquetas del panel MQL están representadas por un único bloque de texto de varias líneas. El texto utiliza el orden exacto de la herramienta original: tiempo, período, símbolo, cierre, apertura, máximo, mínimo, volumen de tick, extensión.
  • Los intercambios de símbolos en tiempo de ejecución ya no necesitan una gestión manual de Market Watch: la estrategia resuelve los instrumentos directamente a través del proveedor de seguridad StockSharp.
  • Solo se utilizan llamadas API de alto nivel (SubscribeCandles, SubscribeLevel1, DrawText, AddInfo). No hay cálculos manuales de indicadores ni manipulaciones directas del conector, lo que satisface las reglas de codificación del repositorio.
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>
/// Market monitoring strategy that tracks price metrics and trades on significant
/// spread changes. Simplified from the MetaTrader "Symbol Swap" display panel.
/// </summary>
public class SymbolSwapStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _smaPeriod;
	private readonly StrategyParam<decimal> _spreadThreshold;

	private SimpleMovingAverage _sma;
	private decimal _entryPrice;

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

	/// <summary>
	/// SMA period for trend detection.
	/// </summary>
	public int SmaPeriod
	{
		get => _smaPeriod.Value;
		set => _smaPeriod.Value = value;
	}

	/// <summary>
	/// Price deviation threshold for entry signals.
	/// </summary>
	public decimal SpreadThreshold
	{
		get => _spreadThreshold.Value;
		set => _spreadThreshold.Value = value;
	}

	/// <summary>
	/// Initializes strategy parameters.
	/// </summary>
	public SymbolSwapStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
			.SetDisplay("Candle Type", "Candle series for signals", "General");

		_smaPeriod = Param(nameof(SmaPeriod), 20)
			.SetGreaterThanZero()
			.SetDisplay("SMA Period", "Moving average period", "Indicators");

		_spreadThreshold = Param(nameof(SpreadThreshold), 3m)
			.SetGreaterThanZero()
			.SetDisplay("Spread Threshold", "Price deviation from SMA to trigger entry", "Signals");
	}

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

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_sma = null;
		_entryPrice = 0m;
	}

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

		_sma = new SimpleMovingAverage { Length = SmaPeriod };

		SubscribeCandles(CandleType)
			.Bind(_sma, ProcessCandle)
			.Start();
	}

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

		if (!IsFormed)
			return;

		var price = candle.ClosePrice;

		// Exit on mean reversion
		if (Position != 0 && _entryPrice > 0m)
		{
			var pnl = Position > 0
				? price - _entryPrice
				: _entryPrice - price;

			// Exit on profit or loss threshold
			if (pnl >= SpreadThreshold || pnl <= -SpreadThreshold * 2m)
			{
				if (Position > 0)
					SellMarket(Math.Abs(Position));
				else
					BuyMarket(Math.Abs(Position));

				_entryPrice = 0m;
				return;
			}
		}

		// Entry on deviation
		if (Position == 0)
		{
			var deviation = price - smaValue;

			if (deviation > SpreadThreshold)
			{
				SellMarket();
				_entryPrice = price;
			}
			else if (deviation < -SpreadThreshold)
			{
				BuyMarket();
				_entryPrice = price;
			}
		}
	}
}