Ver en GitHub

Estrategia de flecha de cuatro colores de OsMA

Descripción general

Esta estrategia recrea el comportamiento del asesor experto MetaTrader "OsMA Four Colors Arrow" dentro del marco StockSharp. El EA original reacciona a las flechas de colores producidas por el indicador que lo acompaña cada vez que el histograma OsMA (MACD) cambia de fase. En la versión StockSharp, el mismo comportamiento se modela monitoreando los cruces por cero del histograma MACD: un cruce alcista (el histograma se mueve de negativo a positivo) desencadena entradas largas, mientras que un cruce bajista desencadena entradas cortas. El modo inverso opcional invierte la lógica para pruebas de cobertura o reversión a la media.

La plantilla funciona solo con velas terminadas y puede imponer una sesión de negociación diaria similar al filtro de tiempo que ofrece la versión MQL. La gestión de dinero integrada incluye un volumen de operaciones configurable, un límite en el número de posiciones agregadas y una protección automática de stop-loss/take-profit/trailing expresada en pips.

Lógica de trading

  1. Suscríbase al período de tiempo seleccionado y calcule un histograma MACD (OsMA) utilizando longitudes configurables rápidas, lentas y de señal EMA.
  2. Cuando se cierra una vela, comprueba el signo del histograma:
    • Histograma cruzando por encima de cero → flecha alcista → señal de compra.
    • Histograma cruzando por debajo de cero → flecha bajista → señal de venta.
  3. Aplicar funciones opcionales antes de enviar un pedido:
    • Filtro de dirección (solo largo, solo corto o ambos).
    • Modo inverso para invertir señales.
    • Cierre la exposición opuesta existente antes de abrir la nueva operación.
    • Limite a una posición activa o acumule hasta la exposición máxima configurada.
  4. Las órdenes de mercado se envían con el tamaño de lote configurado. StartProtection convierte las entradas de pips en compensaciones de precios absolutos para ejecutar automáticamente la gestión de stop-loss, take-profit y trailing.
  5. Las operaciones se ignoran fuera de la sesión intradiaria permitida cuando el filtro de tiempo está habilitado.

Parámetros

Nombre Descripción
CandleType Plazo utilizado para los cálculos y la generación de señales.
FastPeriod / SlowPeriod / SignalPeriod EMA longitudes para el MACD histograma (OsMA).
StopLossPips / TakeProfitPips Objetivos de riesgo en pips. Establezca en cero para desactivar.
TrailingActivatePips Beneficio (en pips) requerido antes de que el trailing stop pueda moverse.
TrailingStopPips Distancia de seguimiento en pips. Zero desactiva el módulo de seguimiento.
TrailingStepPips Pips adicionales que se deben ganar antes de apretar nuevamente el trailing stop.
MaxPositions Unidades de posición agregadas máximas (TradeVolume múltiplos). Cero significa ilimitado.
ReverseSignals Invertir la dirección de entrada (compra ↔ venta).
DirectionMode Restrinja las señales a solo largas, solo cortas o ambas.
CloseOppositePositions Cierre cualquier exposición opuesta antes de actuar sobre la nueva señal.
OnlyOnePosition Si true, evita agregar a una posición ya abierta en la misma dirección.
UseTimeControl Habilite el filtro de sesión de negociación intradiaria.
StartHour, StartMinute, EndHour, EndMinute Límites de la sesión (el final puede ser antes del inicio para cubrir sesiones nocturnas).
TradeVolume Volumen de pedidos en lotes.

Notas

  • Las entradas de trailing-stop imitan el EA: el trailing está disponible solo después de TrailingActivatePips y se mueve en pasos definidos por TrailingStepPips.
  • La estrategia requiere que el valor tenga un PriceStep y un Decimals válidos para convertir pips en compensaciones de precios. Los incumplimientos se reducen a una unidad de precio absoluta si el instrumento no los proporciona.
  • Si MaxPositions es mayor que uno, la estrategia puede ampliarse gradualmente agregando TradeVolume repetidamente respetando el límite máximo de exposición.
  • Cuando UseTimeControl está habilitado y las horas de inicio y finalización coinciden, el comercio se deshabilita para evitar sesiones ambiguas.
  • La lógica actúa sólo sobre velas cerradas; no hay ningún envío de orden dentro de la barra, que coincida con el comportamiento de la plantilla MQL.
using System;
using System.Collections.Generic;

using Ecng.Common;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Simplified from "OsMA Four Colors Arrow" MetaTrader expert.
/// Uses MACD histogram (OsMA) zero-crossing as entry signal.
/// Buys when histogram crosses above zero, sells when it crosses below.
/// </summary>
public class OsMaFourColorsArrowStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;
	private readonly StrategyParam<int> _signalPeriod;

	private MovingAverageConvergenceDivergence _macd;
	private readonly Queue<decimal> _macdHistory = new();
	private decimal? _prevHistogram;

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

	public int FastPeriod
	{
		get => _fastPeriod.Value;
		set => _fastPeriod.Value = value;
	}

	public int SlowPeriod
	{
		get => _slowPeriod.Value;
		set => _slowPeriod.Value = value;
	}

	public int SignalPeriod
	{
		get => _signalPeriod.Value;
		set => _signalPeriod.Value = value;
	}

	public OsMaFourColorsArrowStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe used for signal generation", "General");

		_fastPeriod = Param(nameof(FastPeriod), 20)
			.SetGreaterThanZero()
			.SetDisplay("Fast EMA", "Fast EMA length for MACD", "Indicators");

		_slowPeriod = Param(nameof(SlowPeriod), 50)
			.SetGreaterThanZero()
			.SetDisplay("Slow EMA", "Slow EMA length for MACD", "Indicators");

		_signalPeriod = Param(nameof(SignalPeriod), 12)
			.SetGreaterThanZero()
			.SetDisplay("Signal Period", "Signal line smoothing period", "Indicators");
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		_prevHistogram = null;
		_macdHistory.Clear();

		_macd = new MovingAverageConvergenceDivergence
		{
			ShortMa = { Length = FastPeriod },
			LongMa = { Length = SlowPeriod },
		};

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

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

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

		if (!_macd.IsFormed)
			return;

		// Compute signal line as SMA of MACD values
		_macdHistory.Enqueue(macdValue);
		if (_macdHistory.Count > SignalPeriod)
			_macdHistory.Dequeue();

		if (_macdHistory.Count < SignalPeriod)
		{
			_prevHistogram = null;
			return;
		}

		decimal sum = 0;
		var history = _macdHistory.ToArray();
		foreach (var v in history)
			sum += v;
		var signal = sum / history.Length;

		// OsMA = MACD - Signal (histogram)
		var histogram = macdValue - signal;

		if (_prevHistogram is null)
		{
			_prevHistogram = histogram;
			return;
		}

		var volume = Volume;
		if (volume <= 0)
			volume = 1;

		var crossUp = _prevHistogram.Value <= 0 && histogram > 0;
		var crossDown = _prevHistogram.Value >= 0 && histogram < 0;

		if (crossUp)
		{
			if (Position <= 0)
				BuyMarket(Position < 0 ? Math.Abs(Position) + volume : volume);
		}
		else if (crossDown)
		{
			if (Position >= 0)
				SellMarket(Position > 0 ? Math.Abs(Position) + volume : volume);
		}

		_prevHistogram = histogram;
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		_macd = null;
		_prevHistogram = null;
		_macdHistory.Clear();

		base.OnReseted();
	}
}