Ver en GitHub

Estrategia OsMaMaster

Descripción general

La estrategia OsMaMaster reproduce el comportamiento del experto original OsMaSter_V0 MetaTrader 4 basándose en el histograma MACD (OsMA) para detectar inversiones de impulso. La estrategia se suscribe a una única serie de velas y evalúa el punto de inflexión de OsMA más reciente una vez que se cierra una vela, lo que se alinea con la directriz del repositorio de trabajar únicamente con barras terminadas.

Lógica de trading

  • Pila de indicadores: se procesa un indicador MovingAverageConvergenceDivergence en cada vela terminada. Los períodos rápido, lento y de señal reflejan los parámetros de entrada MQL y el valor predeterminado es 26/09/5 respectivamente.
  • Precio aplicado: el parámetro AppliedPrice asigna las constantes clásicas MetaTrader PRICE_* (0 = cierre, 1 = apertura, 2 = alto, 3 = bajo, 4 = mediana, 5 = típico, 6 = ponderado). El precio seleccionado se introduce directamente en el indicador MACD.
  • Detección de señal: se comparan cuatro lecturas de OsMA según las compensaciones Shift1Shift4 suministradas. La configuración predeterminada (0,1,2,3) busca un mínimo o máximo local del histograma:
    • Configuración larga: OsMA[shift4] > OsMA[shift3], OsMA[shift3] < OsMA[shift2], OsMA[shift2] < OsMA[shift1].
    • Configuración breve: OsMA[shift4] < OsMA[shift3], OsMA[shift3] > OsMA[shift2], OsMA[shift2] > OsMA[shift1].
  • Política de posición única: se envía una nueva operación solo cuando no hay ninguna posición abierta actualmente que coincida con el EA original que verificó las órdenes existentes a través de ExistPositions.

Gestión de Puestos

  • Stop-lossStopLossPips define la distancia opcional (en pips) entre el precio de cumplimiento y el stop de protección. Un valor de 0 desactiva la parada.
  • Take-profit: TakeProfitPips refleja el parámetro de toma de ganancias de EA. Cuando se establece en 0, no se utiliza ningún objetivo fijo.
  • Modelo de ejecución: tanto el stop como el objetivo se evalúan frente a los extremos de las velas (HighPrice/LowPrice). Si se supera un umbral dentro de una vela, la posición se cierra al cierre de la vela utilizando órdenes de mercado.
  • Reinicio de estado: cada vez que se cierra la posición, todas las referencias de parada/objetivo pendientes se borran para que la siguiente entrada pueda configurarlas de nuevo.

Parámetros

Parámetro Descripción Predeterminado
CandleType Marco temporal de la serie de velas utilizado para todos los cálculos. 1 hora
FastEmaPeriod Longitud rápida EMA dentro del indicador MACD. 9
SlowEmaPeriod Longitud lenta de EMA dentro del indicador MACD. 26
SignalPeriod Longitud de la señal EMA utilizada para construir el histograma. 5
AppliedPrice MetaTrader PRICE_* código que define qué precio de vela alimenta el MACD. 0 (cerca)
Shift1 Primer cambio de OsMA (normalmente la barra actual). 0
Shift2 Segundo turno de OsMA. 1
Shift3 Tercer turno de OsMA. 2
Shift4 Cuarto turno de OsMA. 3
StopLossPips Distancia de parada de protección en pips. 50
TakeProfitPips Distancia objetivo de ganancias en pips. 50

Notas de conversión

  • La implementación StockSharp mantiene un búfer de anillo compacto de los valores recientes de OsMA en lugar de solicitar repetidamente el historial del indicador, lo que garantiza el cumplimiento de la regla del repositorio sobre evitar recopilaciones de datos personalizadas.
  • Todas las decisiones comerciales utilizan velas terminadas para evitar trabajar con valores de indicadores incompletos.
  • La lógica de stop-loss y take-profit emulan la colocación de órdenes MQL monitoreando los máximos y mínimos de las velas y cerrando posiciones con órdenes de mercado.
  • El volumen de estrategia predeterminado se establece en 0,01, lo que refleja el tamaño de lote predeterminado de EA.

Consejos de uso

  • Ajuste los períodos CandleType y MACD para que coincidan con la volatilidad del instrumento. Los mercados más rápidos pueden beneficiarse de longitudes EMA más cortas.
  • Considere deshabilitar la toma de ganancias configurando TakeProfitPips en 0 si desea aprovechar las tendencias extendidas y administrar las salidas manualmente.
  • Cuando experimente con diferentes valores de Shift, asegúrese de que el cambio más grande no sea excesivamente grande; la estrategia mantiene solo tantos valores de histograma como requiere el cambio máximo.
  • Debido a que las salidas se evalúan en función de los datos de las velas, el uso de marcos de tiempo más cortos reduce el retraso entre el incumplimiento del umbral real y la ejecución de la salida.
using System;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// OsMA Master: Dual EMA crossover with RSI confirmation and ATR stops.
/// </summary>
public class OsMaMasterStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _fastEmaLength;
	private readonly StrategyParam<int> _slowEmaLength;
	private readonly StrategyParam<int> _rsiLength;
	private readonly StrategyParam<int> _atrLength;

	private decimal _prevFast;
	private decimal _prevSlow;
	private decimal _entryPrice;

	public OsMaMasterStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(2).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe.", "General");
		_fastEmaLength = Param(nameof(FastEmaLength), 9)
			.SetDisplay("Fast EMA Length", "Fast EMA period.", "Indicators");
		_slowEmaLength = Param(nameof(SlowEmaLength), 26)
			.SetDisplay("Slow EMA Length", "Slow EMA period.", "Indicators");
		_rsiLength = Param(nameof(RsiLength), 14)
			.SetDisplay("RSI Length", "RSI period.", "Indicators");
		_atrLength = Param(nameof(AtrLength), 14)
			.SetDisplay("ATR Length", "ATR period.", "Indicators");
	}

	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
	public int FastEmaLength { get => _fastEmaLength.Value; set => _fastEmaLength.Value = value; }
	public int SlowEmaLength { get => _slowEmaLength.Value; set => _slowEmaLength.Value = value; }
	public int RsiLength { get => _rsiLength.Value; set => _rsiLength.Value = value; }
	public int AtrLength { get => _atrLength.Value; set => _atrLength.Value = value; }

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();

		_prevFast = 0; _prevSlow = 0; _entryPrice = 0;
	}

		protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_prevFast = 0; _prevSlow = 0; _entryPrice = 0;
		var fastEma = new ExponentialMovingAverage { Length = FastEmaLength };
		var slowEma = new ExponentialMovingAverage { Length = SlowEmaLength };
		var rsi = new RelativeStrengthIndex { Length = RsiLength };
		var atr = new AverageTrueRange { Length = AtrLength };
		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(fastEma, slowEma, rsi, atr, ProcessCandle).Start();
		var area = CreateChartArea();
		if (area != null) { DrawCandles(area, subscription); DrawIndicator(area, fastEma); DrawIndicator(area, slowEma); DrawOwnTrades(area); }
	}

	private void ProcessCandle(ICandleMessage candle, decimal fastVal, decimal slowVal, decimal rsiVal, decimal atrVal)
	{
		if (candle.State != CandleStates.Finished) return;
		if (_prevFast == 0 || _prevSlow == 0 || atrVal <= 0) { _prevFast = fastVal; _prevSlow = slowVal; return; }
		var close = candle.ClosePrice;

		if (Position > 0)
		{
			if ((fastVal < slowVal && _prevFast >= _prevSlow) || close <= _entryPrice - atrVal * 2m) { SellMarket(); _entryPrice = 0; }
		}
		else if (Position < 0)
		{
			if ((fastVal > slowVal && _prevFast <= _prevSlow) || close >= _entryPrice + atrVal * 2m) { BuyMarket(); _entryPrice = 0; }
		}

		if (Position == 0)
		{
			if (fastVal > slowVal && _prevFast <= _prevSlow && rsiVal > 50) { _entryPrice = close; BuyMarket(); }
			else if (fastVal < slowVal && _prevFast >= _prevSlow && rsiVal < 50) { _entryPrice = close; SellMarket(); }
		}
		_prevFast = fastVal; _prevSlow = slowVal;
	}
}