Ver en GitHub

Estrategia ReInitChart

Esta estrategia porta la utilidad ReInitChart de MetaTrader a StockSharp. El script original creaba un botón en cada gráfico que cambiaba temporalmente el período de tiempo para forzar el recálculo de los indicadores. La versión de StockSharp mantiene el mismo espíritu exponiendo un interruptor de actualización manual y un temporizador automático opcional que reinician el indicador SMA interno y registran el evento de actualización. Se aplica una regla simple de seguimiento de tendencia SMA para demostrar el trading una vez que el indicador se reconstruye.

Cómo funciona

  1. Fuente de datos principal – la estrategia se suscribe al período de tiempo definido por CandleType y calcula una media móvil simple con longitud SmaLength.
  2. Actualización manual – cuando ManualRefreshRequest se convierte en true, el estado de la media móvil se reinicia, el indicador se borra y la acción se reporta en el registro junto con los metadatos del botón preservados (RefreshCommandName, RefreshCommandText, TextColorName, BackgroundColorName).
  3. Actualización automática – habilitar AutoRefreshEnabled programa reinicios recurrentes cada AutoRefreshInterval, reproduciendo la reinicialización basada en temporizador de MetaTrader.
  4. Lógica de trading – después de que se forme el SMA, la estrategia mantiene como máximo una posición. Va largo cuando el precio de cierre está por encima del SMA y cambia a corto cuando el precio cae por debajo, cerrando primero el lado opuesto.

Este comportamiento refleja la idea de reinicializar todos los gráficos del Asesor Experto original mientras usa componentes idiomáticos de StockSharp (reinicio del indicador y registro) en lugar de cambiar los períodos de tiempo del gráfico.

Parámetros

Parámetro Descripción
CandleType Período de tiempo de trabajo para la suscripción de velas.
SmaLength Número de velas usadas para la media móvil que se reconstruye después de cada actualización.
AutoRefreshEnabled Habilita el temporizador de actualización periódica.
AutoRefreshInterval Intervalo entre eventos de actualización automática.
ManualRefreshRequest Establecer en true manualmente para activar una actualización inmediata. La estrategia lo borra después de procesarlo.
RefreshCommandName Metadatos que reflejan el nombre del botón de MetaTrader; reportado en los registros cuando ocurre una actualización.
RefreshCommandText Metadatos que reflejan el título del botón de MetaTrader; reportado en los registros cuando ocurre una actualización.
TextColorName Descripción del color del texto del botón preservada del script MQL.
BackgroundColorName Descripción del color de fondo del botón preservada del script MQL.

Uso

  1. Configure CandleType y SmaLength para que coincidan con el mercado y el período de tiempo que desea monitorear.
  2. Habilite AutoRefreshEnabled y elija AutoRefreshInterval si necesita reconstrucciones periódicas del indicador. Déjelo deshabilitado cuando quiera solo control manual.
  3. Cambie ManualRefreshRequest a true cuando quiera vaciar el estado del indicador. El indicador se establece automáticamente de vuelta a false una vez que la actualización está registrada.
  4. Inicie la estrategia para suscribirse a los datos del mercado. Dibuja velas, la curva SMA y sus propias operaciones en el gráfico, y ejecuta los trades básicos de seguimiento de tendencia SMA una vez que el indicador esté listo.

Diferencias con el script MQL original

  • StockSharp no expone botones de gráfico de la misma manera, por lo que el activador de actualización se implementa a través de parámetros de estrategia.
  • En lugar de saltar entre los períodos de tiempo M1 y M5, el port de StockSharp reinicia sus indicadores directamente, lo que es más confiable dentro del framework.
  • Las etiquetas y colores de los botones se conservan como metadatos para el registro para mantener un vínculo con la interfaz de MetaTrader aunque no se creen controles en el gráfico.
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 mimics the MetaTrader ReInitChart utility by resetting indicators on demand.
/// It resets a moving average either manually or on a timer and uses the SMA for simple trend-following entries.
/// </summary>
public class ReInitChartStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _smaLength;
	private readonly StrategyParam<bool> _autoRefreshEnabled;
	private readonly StrategyParam<TimeSpan> _autoRefreshInterval;
	private readonly StrategyParam<bool> _manualRefreshRequest;
	private readonly StrategyParam<string> _refreshCommandName;
	private readonly StrategyParam<string> _refreshCommandText;
	private readonly StrategyParam<string> _textColorName;
	private readonly StrategyParam<string> _backgroundColorName;

	private SimpleMovingAverage _sma = null!;
	private bool _manualRefreshArmed;
	private DateTimeOffset? _nextAutoRefreshTime;
	private int _previousRelation;

	/// <summary>
	/// Primary candle type used to drive the strategy.
	/// </summary>
	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	/// <summary>
	/// Length of the moving average that is recalculated after each refresh.
	/// </summary>
	public int SmaLength
	{
		get => _smaLength.Value;
		set => _smaLength.Value = value;
	}

	/// <summary>
	/// Enables or disables automatic refresh events.
	/// </summary>
	public bool AutoRefreshEnabled
	{
		get => _autoRefreshEnabled.Value;
		set => _autoRefreshEnabled.Value = value;
	}

	/// <summary>
	/// Interval between automatic refresh operations.
	/// </summary>
	public TimeSpan AutoRefreshInterval
	{
		get => _autoRefreshInterval.Value;
		set => _autoRefreshInterval.Value = value;
	}

	/// <summary>
	/// Manual refresh flag that emulates the original MetaTrader button press.
	/// </summary>
	public bool ManualRefreshRequest
	{
		get => _manualRefreshRequest.Value;
		set => _manualRefreshRequest.Value = value;
	}

	/// <summary>
	/// Identifier of the refresh command, matching the MetaTrader button name.
	/// </summary>
	public string RefreshCommandName
	{
		get => _refreshCommandName.Value;
		set => _refreshCommandName.Value = value;
	}

	/// <summary>
	/// Text displayed for the refresh command.
	/// </summary>
	public string RefreshCommandText
	{
		get => _refreshCommandText.Value;
		set => _refreshCommandText.Value = value;
	}

	/// <summary>
	/// Text color descriptor preserved from the original script.
	/// </summary>
	public string TextColorName
	{
		get => _textColorName.Value;
		set => _textColorName.Value = value;
	}

	/// <summary>
	/// Background color descriptor preserved from the original script.
	/// </summary>
	public string BackgroundColorName
	{
		get => _backgroundColorName.Value;
		set => _backgroundColorName.Value = value;
	}

	/// <summary>
	/// Initializes strategy parameters.
	/// </summary>
	public ReInitChartStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
			.SetDisplay("Candle Type", "Time frame used for the primary chart subscription.", "Data");

		_smaLength = Param(nameof(SmaLength), 20)
			.SetGreaterThanZero()
			.SetDisplay("SMA Length", "Number of candles for the recalculated moving average.", "Reinitialization");

		_autoRefreshEnabled = Param(nameof(AutoRefreshEnabled), false)
			.SetDisplay("Auto Refresh", "Enable periodic indicator reinitialization.", "Reinitialization");

		_autoRefreshInterval = Param(nameof(AutoRefreshInterval), TimeSpan.FromMinutes(5))
			.SetDisplay("Refresh Interval", "Time interval between automatic refresh operations.", "Reinitialization");

		_manualRefreshRequest = Param(nameof(ManualRefreshRequest), false)
			.SetDisplay("Manual Refresh", "Set to true to trigger a one-time indicator reset.", "Reinitialization");

		_refreshCommandName = Param(nameof(RefreshCommandName), "ButtonReDraw")
			.SetDisplay("Command Name", "Identifier that matches the MetaTrader button name.", "Appearance");

		_refreshCommandText = Param(nameof(RefreshCommandText), "Recalculate")
			.SetDisplay("Command Text", "Text shown on logs to mirror the MetaTrader button caption.", "Appearance");

		_textColorName = Param(nameof(TextColorName), "NavajoWhite")
			.SetDisplay("Text Color", "Original MetaTrader button text color.", "Appearance");

		_backgroundColorName = Param(nameof(BackgroundColorName), "SlateGray")
			.SetDisplay("Background Color", "Original MetaTrader button background color.", "Appearance");
	}

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

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_manualRefreshArmed = false;
		_nextAutoRefreshTime = null;
		_previousRelation = 0;
	}

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

		_sma = new SMA
		{
			Length = SmaLength,
		};

		// Subscribe to the primary candle stream and bind the moving average.
		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(_sma, ProcessCandle)
			.Start();

		// Draw candles, indicator and executed trades when charting is available.
		var area = CreateChartArea();
		if (area != null)
		{
			DrawCandles(area, subscription);
			DrawIndicator(area, _sma);
			DrawOwnTrades(area);
		}

		if (AutoRefreshEnabled)
		{
			_nextAutoRefreshTime = time + AutoRefreshInterval;
		}
	}

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

		// Handle manual or automatic refresh triggers using the candle close time.
		CheckManualRefresh(candle.CloseTime);
		CheckAutoRefresh(candle.CloseTime);

		// Synchronize the moving average length if the parameter changed on the fly.
		if (_sma.Length != SmaLength)
		{
			_sma.Length = SmaLength;
			_sma.Reset();
			this.LogInfo($"[{RefreshCommandName}] SMA length changed to {SmaLength}. Indicator state reset.");
			return;
		}

		if (!_sma.IsFormed)
			return;

		if (!IsFormedAndOnlineAndAllowTrading())
			return;

		if (Volume <= 0)
			return;

		var relation = candle.ClosePrice > smaValue ? 1 : candle.ClosePrice < smaValue ? -1 : 0;
		if (relation == 0 || relation == _previousRelation)
		{
			_previousRelation = relation;
			return;
		}

		if (relation > 0)
		{
			if (Position < 0)
				BuyMarket(Math.Abs(Position));

			if (Position <= 0)
				BuyMarket(Volume);
		}
		else if (relation < 0)
		{
			if (Position > 0)
				SellMarket(Position);

			if (Position >= 0)
				SellMarket(Volume);
		}

		_previousRelation = relation;
	}

	private void CheckManualRefresh(DateTimeOffset currentTime)
	{
		if (ManualRefreshRequest)
		{
			if (!_manualRefreshArmed)
			{
				PerformRefresh(currentTime, "manual request");
				ManualRefreshRequest = false;
				_manualRefreshArmed = true;
			}
		}
		else
		{
			_manualRefreshArmed = false;
		}
	}

	private void CheckAutoRefresh(DateTimeOffset currentTime)
	{
		if (!AutoRefreshEnabled)
		{
			_nextAutoRefreshTime = null;
			return;
		}

		if (_nextAutoRefreshTime is null)
			_nextAutoRefreshTime = currentTime + AutoRefreshInterval;

		if (currentTime < _nextAutoRefreshTime.Value)
			return;

		PerformRefresh(currentTime, "automatic schedule");
		_nextAutoRefreshTime = currentTime + AutoRefreshInterval;
	}

	private void PerformRefresh(DateTimeOffset time, string reason)
	{
		// Reset the moving average so that future candles rebuild the indicator state.
		_sma.Reset();
		_previousRelation = 0;

		this.LogInfo($"[{RefreshCommandName}] {RefreshCommandText} triggered by {reason} at {time:O}. TextColor={TextColorName}, BackgroundColor={BackgroundColorName}.");
	}
}