Ver en GitHub

Estrategia MMA de Rompimiento por Volumen I

Esta estrategia opera rompimientos cuando el precio de cierre cruza una Media Móvil Suavizada (SMMA) de largo plazo. Se abre una posición larga cuando el precio sube por encima de la SMMA y una posición corta cuando cae por debajo. Las posiciones se cierran cuando el precio se mueve en contra de la operación y cruza una Media Móvil Exponencial (EMA).

Detalles

  • Criterios de entrada:
    • Largo: El precio de cierre cruza por encima de SMMA(200).
    • Corto: El precio de cierre cruza por debajo de SMMA(200).
  • Criterios de salida:
    • Largo: El precio de cierre cae por debajo de EMA(5).
    • Corto: El precio de cierre sube por encima de EMA(5).
  • Largo/Corto: Ambos.
  • Stops: Sin stop-loss fijo, la salida está determinada por la señal EMA.
  • Valores predeterminados:
    • SMMA period = 200
    • EMA period = 5
    • Candle type = velas de 5 minutos
  • Filtros:
    • Categoría: Seguimiento de tendencia
    • Dirección: Ambos
    • Indicadores: Medias Móviles
    • Stops: No
    • Complejidad: Simple
    • Marco temporal: Corto plazo
    • Estacionalidad: No
    • Redes neuronales: No
    • Divergencia: No
    • Nivel de riesgo: Medio
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>
/// Strategy based on smoothed moving average breakout with EMA exit.
/// </summary>
public class MmaBreakoutVolumeIStrategy : Strategy
{
	private readonly StrategyParam<int> _slowPeriod;
	private readonly StrategyParam<int> _exitPeriod;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _prevPrice;
	private decimal _prevSlow;
	private bool _hasPrev;

	public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
	public int ExitPeriod { get => _exitPeriod.Value; set => _exitPeriod.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public MmaBreakoutVolumeIStrategy()
	{
		_slowPeriod = Param(nameof(SlowPeriod), 50)
			.SetDisplay("Slow EMA Period", "Period for long moving average", "Indicators");

		_exitPeriod = Param(nameof(ExitPeriod), 10)
			.SetDisplay("Exit EMA Period", "Period for exit EMA", "Indicators");

		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Type of candles to use", "General");
	}

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

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

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

		var slowEma = new ExponentialMovingAverage { Length = SlowPeriod };
		var exitEma = new ExponentialMovingAverage { Length = ExitPeriod };

		SubscribeCandles(CandleType)
			.Bind(slowEma, exitEma, ProcessCandle)
			.Start();
	}

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

		if (!_hasPrev)
		{
			_prevPrice = candle.ClosePrice;
			_prevSlow = slowValue;
			_hasPrev = true;
			return;
		}

		var isCrossAbove = _prevPrice <= _prevSlow && candle.ClosePrice > slowValue;
		var isCrossBelow = _prevPrice >= _prevSlow && candle.ClosePrice < slowValue;

		if (isCrossAbove && Position <= 0)
		{
			if (Position < 0) BuyMarket();
			BuyMarket();
		}
		else if (isCrossBelow && Position >= 0)
		{
			if (Position > 0) SellMarket();
			SellMarket();
		}
		else if (Position > 0 && candle.ClosePrice < exitValue)
			SellMarket();
		else if (Position < 0 && candle.ClosePrice > exitValue)
			BuyMarket();

		_prevPrice = candle.ClosePrice;
		_prevSlow = slowValue;
	}
}