Ver en GitHub

Estrategia Expotest

Descripción general

La Estrategia Expotest es una conversión directa a StockSharp del asesor experto original Expotest.mq5. Opera un único instrumento usando el indicador Parabolic SAR y una regla de gestión monetaria simple inspirada en el martingale. La estrategia abre solo una posición a la vez y depende de niveles de stop-loss y take-profit predefinidos para las salidas.

Lógica de trading

  • Indicador: Parabolic SAR calculado en la serie de velas seleccionada. Tanto el factor de aceleración (SarStep) como la aceleración máxima (SarMaximum) son configurables.
  • Condiciones de entrada: Cuando no hay posición abierta, la estrategia verifica la última vela cerrada.
    • Si el valor del Parabolic SAR está por debajo o igual al precio de cierre, se inicia una posición larga.
    • Si el valor del Parabolic SAR está por encima o igual al precio de cierre, se inicia una posición corta.
  • Condiciones de salida: Los niveles de stop-loss y take-profit se colocan a una distancia fija del precio de entrada, medida en pasos de precio. Durante cada nueva vela, la estrategia monitorea si el rango de la vela toca cualquiera de los niveles y cierra la posición en consecuencia. El tipo de salida (ganancia o pérdida) se recuerda para futuras decisiones de dimensionamiento de posición.

Dimensionamiento de posición

  • Volumen base: Definido por el parámetro FixedVolume cuando es mayor que cero. De lo contrario, la estrategia estima el tamaño a partir de los valores RiskPercent y StopLossPoints usando el capital actual del portafolio. Si ningún método devuelve un tamaño válido, se usa el Strategy.Volume predeterminado.
  • Paso martingale: Después de una operación perdedora, el siguiente tamaño de posición se duplica en comparación con el volumen de la posición perdedora. Una salida rentable restablece el multiplicador y la siguiente orden usa el volumen base nuevamente.

Parámetros configurables

  • CandleType – Tipo de datos para la agregación de velas (marco temporal u otro formato de vela).
  • SarStep – Factor de aceleración inicial para el Parabolic SAR.
  • SarMaximum – Factor de aceleración máximo para el Parabolic SAR.
  • StopLossPoints – Distancia del stop-loss desde la entrada expresada en pasos de precio.
  • TakeProfitPoints – Distancia del take-profit desde la entrada expresada en pasos de precio.
  • RiskPercent – Porcentaje del capital del portafolio a arriesgar por operación cuando el dimensionamiento dinámico está habilitado.
  • FixedVolume – Volumen de orden explícito. Establecer en 0 para habilitar el dimensionamiento basado en riesgo.

Notas adicionales

  • La estrategia procesa solo velas terminadas para mantenerse cerca de la implementación MQL original basada en ticks mientras permanece compatible con las suscripciones de StockSharp.
  • Los niveles de protección se rastrean internamente en lugar de órdenes stop/limit separadas, lo que mantiene la lógica transparente y fácil de backtestear.
  • La implementación Python se omite intencionalmente según lo solicitado.
namespace StockSharp.Samples.Strategies;

using System;

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

/// <summary>
/// Parabolic SAR based strategy converted from the Expotest MQL expert advisor.
/// Enters long when SAR is below price, short when SAR is above price.
/// </summary>
public class ExpotestStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<decimal> _sarStep;
	private readonly StrategyParam<decimal> _sarMaximum;

	private bool _prevSarBelow;
	private bool _initialized;

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

	public decimal SarStep
	{
		get => _sarStep.Value;
		set => _sarStep.Value = value;
	}

	public decimal SarMaximum
	{
		get => _sarMaximum.Value;
		set => _sarMaximum.Value = value;
	}

	public ExpotestStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
			.SetDisplay("Candle Type", "Candle type for signal generation", "General");

		_sarStep = Param(nameof(SarStep), 0.02m)
			.SetDisplay("SAR Step", "Acceleration factor for Parabolic SAR", "Indicators");

		_sarMaximum = Param(nameof(SarMaximum), 0.2m)
			.SetDisplay("SAR Maximum", "Maximum acceleration factor for Parabolic SAR", "Indicators");
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevSarBelow = false;
		_initialized = false;
	}

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

		_prevSarBelow = false;
		_initialized = false;

		var sar = new ParabolicSar
		{
			Acceleration = SarStep,
			AccelerationMax = SarMaximum
		};

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(sar, OnProcess)
			.Start();

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

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

		if (!IsFormedAndOnlineAndAllowTrading())
			return;

		var sarBelow = sarValue < candle.ClosePrice;

		if (!_initialized)
		{
			_prevSarBelow = sarBelow;
			_initialized = true;
			return;
		}

		// SAR flipped from above to below price => Buy signal
		if (sarBelow && !_prevSarBelow && Position <= 0)
		{
			BuyMarket();
		}
		// SAR flipped from below to above price => Sell signal
		else if (!sarBelow && _prevSarBelow && Position >= 0)
		{
			SellMarket();
		}

		_prevSarBelow = sarBelow;
	}
}