Ver en GitHub

Estrategia BandOsMa

Descripción general

La Estrategia BandOsMa convierte el asesor experto MetaTrader 5 "BandOsMA" en una estrategia StockSharp. Evalúa el histograma MACD (OsMA) utilizando Bollinger bandas construidas directamente sobre los valores del histograma. Las rupturas por encima o por debajo de las bandas crean señales de entrada, mientras que una media móvil adicional del histograma gestiona las salidas de señales.

La estrategia opera con un solo símbolo y período de tiempo seleccionado por el usuario. Los valores del indicador se calculan sobre velas terminadas utilizando las suscripciones de velas de alto nivel de StockSharp.

Lógica de trading

  1. Indicadores
    • MovingAverageConvergenceDivergenceSignal proporciona el histograma MACD (OsMA).
    • BollingerBands se aplica a la secuencia OsMA para detectar desviaciones extremas.
    • Una media móvil configurable suaviza el histograma y actúa como filtro de salida.
  2. Entrada
    • Aparece una señal larga cuando el OsMA actual cierra por debajo de la banda inferior mientras que la barra anterior permaneció por encima de ella.
    • Aparece una señal corta cuando el OsMA actual cierra por encima de la banda superior mientras que la barra anterior permaneció por debajo de ella.
  3. Salir
    • Las señales se borran cuando el histograma cruza la media móvil en la dirección opuesta.
    • Cuando una posición abierta ya no coincide con la señal activa, la posición se cierra inmediatamente.
    • Se adjunta un stop-loss basado en pips a cada posición. La parada también actúa como una parada de seguimiento con la misma distancia y un paso de seguimiento igual a StopLossPoints / 50 (reflejando la clase auxiliar MetaTrader.

Gestión de Puestos

  • Stop Loss & Trailing: La distancia del stop se expresa en MetaTrader puntos y se convierte en unidades de precio utilizando el PriceStep del instrumento. La misma distancia se utiliza para el trailing stop, que avanza una vez que el precio de cierre mejora al menos el paso de seguimiento.
  • Una posición a la vez: Solo se mantiene una posición neta. Las señales opuestas cierran la posición actual antes de considerar una nueva entrada.

Parámetros

grupo Nombre Descripción Predeterminado
generales CandleType Plazo para la suscripción de velas y cálculo del indicador. H1
Riesgo LotSize Volumen comercial en lotes. 0.01
Riesgo StopLossPoints Distancia de stop-loss expresada en MetaTrader puntos (también utilizada para seguimiento). 1000
Indicadores MacdFastPeriod Longitud rápida de EMA en MACD. 12
Indicadores MacdSlowPeriod Longitud lenta de EMA en MACD. 26
Indicadores MacdSignalPeriod Longitud de la señal EMA en MACD. 9
Indicadores PriceType Precio aplicado para la entrada MACD (Close, Open, High, Low, Median, Typical, Weighted). Typical
Indicadores BollingerPeriod Período de Bollinger Bandas sobre la secuencia OsMA. 26
Indicadores BollingerShift Cambio aplicado a Bollinger buffers (no negativo). 0
Indicadores BollingerDeviation Multiplicador de desviación estándar para Bollinger bandas. 2
Indicadores MovingAveragePeriod Longitud de la media móvil aplicada a OsMA. 10
Indicadores MovingAverageShift Cambio aplicado al buffer de media móvil (no negativo). 0
Indicadores MovingAverageMethod Tipo de media móvil (Simple, Exponential, Smoothed, LinearWeighted). Simple

Notas de implementación

  • El procesamiento de velas utiliza WhenCandlesFinished para garantizar que solo las barras finales impulsen la lógica.
  • Los valores del indicador se almacenan en búferes históricos para emular cambios de búfer estilo MetaTrader. No se admiten cambios negativos; utilice valores cero o positivos como en los valores predeterminados originales del experto.
  • Las paradas dinámicas se basan en cierres de velas en lugar de actualizaciones paso a paso. Ajuste la distancia del pip si se requiere un seguimiento preciso del nivel de tick.

Uso

  1. Seleccione el símbolo y el período de tiempo deseados en StockSharp.
  2. Configure los parámetros, especialmente CandleType, LotSize y períodos del indicador.
  3. Iniciar la estrategia; se suscribirá a velas, calculará los indicadores y ejecutará operaciones de acuerdo con la lógica descrita.
using System;
using System.Collections.Generic;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Strategy combining the MACD histogram (OsMA) with Bollinger Bands to trade reversals.
/// When OsMA crosses below lower Bollinger band, buy signal is generated.
/// When OsMA crosses above upper Bollinger band, sell signal is generated.
/// </summary>
public class BandOsMaStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _macdFastPeriod;
	private readonly StrategyParam<int> _macdSlowPeriod;
	private readonly StrategyParam<int> _macdSignalPeriod;
	private readonly StrategyParam<int> _bollingerPeriod;
	private readonly StrategyParam<decimal> _bollingerDeviation;

	private decimal _prevOsma;
	private decimal _prevUpper;
	private decimal _prevLower;
	private bool _hasPrev;

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

	public int MacdFastPeriod
	{
		get => _macdFastPeriod.Value;
		set => _macdFastPeriod.Value = value;
	}

	public int MacdSlowPeriod
	{
		get => _macdSlowPeriod.Value;
		set => _macdSlowPeriod.Value = value;
	}

	public int MacdSignalPeriod
	{
		get => _macdSignalPeriod.Value;
		set => _macdSignalPeriod.Value = value;
	}

	public int BollingerPeriod
	{
		get => _bollingerPeriod.Value;
		set => _bollingerPeriod.Value = value;
	}

	public decimal BollingerDeviation
	{
		get => _bollingerDeviation.Value;
		set => _bollingerDeviation.Value = value;
	}

	public BandOsMaStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
			.SetDisplay("Candle Type", "Primary timeframe", "General");

		_macdFastPeriod = Param(nameof(MacdFastPeriod), 20)
			.SetDisplay("MACD Fast", "Fast EMA length", "Indicators");

		_macdSlowPeriod = Param(nameof(MacdSlowPeriod), 50)
			.SetDisplay("MACD Slow", "Slow EMA length", "Indicators");

		_macdSignalPeriod = Param(nameof(MacdSignalPeriod), 12)
			.SetDisplay("MACD Signal", "Signal EMA length", "Indicators");

		_bollingerPeriod = Param(nameof(BollingerPeriod), 14)
			.SetDisplay("Bollinger Period", "OsMA Bollinger Bands period", "Indicators");

		_bollingerDeviation = Param(nameof(BollingerDeviation), 2m)
			.SetDisplay("Bollinger Deviation", "Bollinger Bands deviation", "Indicators");
	}

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

		var macd = new MovingAverageConvergenceDivergenceSignal
		{
			Macd =
			{
				ShortMa = { Length = MacdFastPeriod },
				LongMa = { Length = MacdSlowPeriod }
			},
			SignalMa = { Length = MacdSignalPeriod }
		};

		var subscription = SubscribeCandles(CandleType);
		subscription
			.BindEx(macd, ProcessCandle)
			.Start();

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

	private BollingerBands _bollinger;

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

		var val = (IMovingAverageConvergenceDivergenceSignalValue)macdValue;
		if (val.Macd is not decimal macdLine || val.Signal is not decimal signalLine)
			return;

		var osma = macdLine - signalLine;

		_bollinger ??= new BollingerBands
		{
			Length = BollingerPeriod,
			Width = BollingerDeviation
		};

		var bbResult = (BollingerBandsValue)_bollinger.Process(new DecimalIndicatorValue(_bollinger, osma, candle.CloseTime));
		if (bbResult.UpBand is not decimal upper || bbResult.LowBand is not decimal lower)
		{
			return;
		}

		if (_hasPrev)
		{
			// Buy: OsMA crosses below lower band (reversal up expected)
			if (_prevOsma > _prevLower && osma <= lower && Position <= 0)
			{
				BuyMarket(Position < 0 ? Math.Abs(Position) + 1 : 1);
			}
			// Sell: OsMA crosses above upper band (reversal down expected)
			else if (_prevOsma < _prevUpper && osma >= upper && Position >= 0)
			{
				SellMarket(Position > 0 ? Math.Abs(Position) + 1 : 1);
			}
		}

		_prevOsma = osma;
		_prevUpper = upper;
		_prevLower = lower;
		_hasPrev = true;
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		_prevOsma = 0;
		_prevUpper = 0;
		_prevLower = 0;
		_hasPrev = false;
		_bollinger = null;

		base.OnReseted();
	}
}