Ver en GitHub

Estrategia de Cierre por Cruce de MA

Esta estrategia monitorea una media móvil simple (MA) y cierra automáticamente cualquier posición abierta cuando el cierre de la vela cruza la línea de la MA. Está diseñada para traders que gestionan las entradas manualmente o con otros sistemas, pero quieren una salida automatizada cuando el tendencia se invierte.

La lógica rastrea la relación entre el precio de cierre y la MA. Cuando una nueva vela finalizada cruza de un lado de la MA al otro, la estrategia envía una orden de mercado para cerrar la posición. No se abren nuevas posiciones.

Detalles

  • Criterios de entrada: Ninguno. Las posiciones deben abrirse externamente.
  • Criterios de salida:
    • Largo: Cierre anterior por encima de la MA y cierre actual por debajo de la MA activa una venta para cerrar.
    • Corto: Cierre anterior por debajo de la MA y cierre actual por encima de la MA activa una compra para cerrar.
  • Largo/Corto: Se soportan ambas direcciones.
  • Stops: No se usan. El cruce de la MA actúa como señal de salida.
  • Valores predeterminados:
    • MA Period = 50.
    • Candle Type = Marco temporal de 1 minuto.
  • Filtros:
    • Categoría: Seguimiento de tendencia
    • Dirección: Ambos
    • Indicadores: Único
    • Stops: No
    • Complejidad: Simple
    • Marco temporal: Cualquiera
    • Estacionalidad: No
    • Redes neuronales: No
    • Divergencia: No
    • Nivel de riesgo: Moderado
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>
/// Price cross MA strategy.
/// </summary>
public class CloseCrossMaStrategy : Strategy
{
	private readonly StrategyParam<int> _maPeriod;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _prevDiff;
	private bool _hasPrev;

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

	public CloseCrossMaStrategy()
	{
		_maPeriod = Param(nameof(MaPeriod), 50)
			.SetGreaterThanZero()
			.SetDisplay("MA Period", "EMA period", "Parameters");
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Candle type", "General");
	}

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

	protected override void OnReseted()
	{
		base.OnReseted();
		_prevDiff = 0;
		_hasPrev = false;
	}

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

		var ema = new ExponentialMovingAverage { Length = MaPeriod };

		SubscribeCandles(CandleType)
			.Bind(ema, ProcessCandle)
			.Start();
	}

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

		var diff = candle.ClosePrice - emaVal;

		if (!_hasPrev)
		{
			_prevDiff = diff;
			_hasPrev = true;
			return;
		}

		// Price crosses above EMA
		if (_prevDiff <= 0 && diff > 0 && Position <= 0)
		{
			if (Position < 0) BuyMarket();
			BuyMarket();
		}
		// Price crosses below EMA
		else if (_prevDiff >= 0 && diff < 0 && Position >= 0)
		{
			if (Position > 0) SellMarket();
			SellMarket();
		}

		_prevDiff = diff;
	}
}