Ver en GitHub

Estrategia Above Below MA

La estrategia Above Below MA replica el asesor experto de MetaTrader Above Below MA (barabashkakvn's edition). Monitorea qué tan lejos se encuentran los precios actuales con respecto a una media móvil configurable y permite operaciones únicamente cuando el precio está en el lado "incorrecto" de la media por al menos una distancia definida, mientras que la propia media sigue la dirección anticipada. La lógica ha sido portada a la API de alto nivel de StockSharp y se ejecuta exclusivamente en velas completadas.

Descripción general

  • Régimen de mercado: Funciona mejor en instrumentos que frecuentemente retestean una media móvil antes de retomar la tendencia.
  • Instrumentos: Cualquier instrumento compatible con su conexión StockSharp. Los pares de Forex se benefician más porque el script original medía la distancia en pips.
  • Marco temporal: Ajustable mediante el parámetro Candle Type (marco temporal de 1 minuto por defecto).
  • Dirección de posición: Se admiten operaciones largas y cortas, pero solo puede existir una posición neta en un momento dado.

Lógica de la estrategia

  1. Se calcula una media móvil sobre la serie de velas seleccionada. El método de promediado (SMA, EMA, SMMA, WMA), el precio aplicado (close, open, high, low, median, typical, weighted) y el desplazamiento hacia adelante replican las entradas de MetaTrader.
  2. Se convierte la distancia mínima expresada en pips en un desplazamiento de precio real usando el PriceStep del instrumento. Si el broker no publica un paso de precio, el filtro de distancia se omite automáticamente.
  3. En cada vela finalizada:
    • Configuración larga:
      • La apertura y el cierre de la vela deben estar al menos a la distancia configurada por debajo de la media móvil desplazada.
      • La media móvil debe estar subiendo comparada con la vela anterior.
    • Configuración corta:
      • La apertura y el cierre de la vela deben estar al menos a la distancia configurada por encima de la media móvil desplazada.
      • La media móvil debe estar bajando comparada con la vela anterior.
  4. La estrategia cierra cualquier posición opuesta antes de enviar una nueva orden de mercado en la dirección de la señal. No se permite exposición simultánea larga/corta.

Todas las decisiones de trading se toman en velas completadas para evitar entradas repetidas dentro de una barra en formación. Las órdenes se ejecutan mediante BuyMarket o SellMarket con el volumen configurado.

Parámetros

Parámetro Descripción
MaPeriod Longitud de la media móvil. Por defecto 6.
MaShift Número de velas para desplazar la media móvil hacia adelante. Un valor de 0 usa la barra actual, n usa el valor de hace n barras. Por defecto 0.
MaMethod Tipo de media móvil: Simple, Exponential, Smoothed o Weighted. Por defecto Exponential.
AppliedPrice Fuente de precio: close, open, high, low, median, typical o weighted. Por defecto Typical.
MinimumDistancePips Distancia requerida en pips entre los precios de la vela y la media móvil. Se convierte usando PriceStep. Por defecto 5.
CandleType Tipo de vela que impulsa las actualizaciones del indicador. Marco temporal de 1 minuto por defecto.
TradeVolume Volumen de la orden para nuevas entradas. Por defecto 1.

Notas adicionales

  • No se incluye lógica de stop-loss ni take-profit. La gestión del riesgo debe implementarse mediante la configuración de la cartera o módulos externos.
  • El búfer de desplazamiento de la media móvil se mantiene mínimo y respeta la directriz de "sin colecciones" almacenando solo los valores requeridos para el desplazamiento especificado.
  • Cuando PriceStep no está disponible, el filtro de distancia mínima no puede evaluarse, por lo que las entradas dependen únicamente de las condiciones de la media móvil.
  • La estrategia dibuja la serie de velas, el indicador de media móvil y sus operaciones en el área del gráfico predeterminada cuando hay un contenedor de gráfico disponible.
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>
/// Above/Below MA strategy. Trades when price crosses above or below a moving average.
/// </summary>
public class AboveBelowMaStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _maPeriod;

	private decimal? _prevClose;
	private decimal? _prevMa;

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

	public int MaPeriod
	{
		get => _maPeriod.Value;
		set => _maPeriod.Value = value;
	}

	public AboveBelowMaStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe", "General");

		_maPeriod = Param(nameof(MaPeriod), 20)
			.SetGreaterThanZero()
			.SetDisplay("MA Period", "Moving average period", "Indicators");
	}

	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		return [(Security, CandleType)];
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevClose = null;
		_prevMa = null;
	}

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

		_prevClose = null;
		_prevMa = null;

		var sma = new SimpleMovingAverage { Length = MaPeriod };

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

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

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

		var close = candle.ClosePrice;

		if (!IsFormedAndOnlineAndAllowTrading())
		{
			_prevClose = close;
			_prevMa = maVal;
			return;
		}

		if (_prevClose == null || _prevMa == null)
		{
			_prevClose = close;
			_prevMa = maVal;
			return;
		}

		// Price crosses above MA → buy
		if (_prevClose.Value <= _prevMa.Value && close > maVal && Position <= 0)
		{
			if (Position < 0)
				BuyMarket();
			BuyMarket();
		}
		// Price crosses below MA → sell
		else if (_prevClose.Value >= _prevMa.Value && close < maVal && Position >= 0)
		{
			if (Position > 0)
				SellMarket();
			SellMarket();
		}

		_prevClose = close;
		_prevMa = maVal;
	}
}