Ver en GitHub

Estrategia de Compra por Ruptura de Precio y Volumen

La estrategia entra cuando precio y volumen rompen simultáneamente por encima de sus respectivos máximos del período de lookback mientras el precio se mantiene sobre la SMA de tendencia. Las operaciones cortas se activan cuando el precio cae por debajo del mínimo del lookback bajo la misma condición de volumen y filtro SMA. Las posiciones se cierran tras cinco cierres consecutivos en el lado opuesto de la SMA.

Detalles

  • Criterios de entrada:
    • Largo: Close > máximo más alto anterior && Volume > volumen más alto anterior && Close > SMA
    • Corto: Close < mínimo más bajo anterior && Volume > volumen más alto anterior && Close < SMA
  • Largo/Corto: Configurable
  • Criterios de salida:
    • Tendencia: Cinco cierres más allá de la SMA
  • Stops: No
  • Valores predeterminados:
    • PriceBreakoutPeriod = 60
    • VolumeBreakoutPeriod = 60
    • TrendlineLength = 200
    • OrderDirection = "Long"
    • CandleType = TimeSpan.FromDays(1)
  • Filtros:
    • Categoría: Ruptura
    • Dirección: Configurable
    • Indicadores: Highest, SMA, Volume
    • Stops: No
    • Complejidad: Básico
    • Marco temporal: Cualquiera
    • 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>
/// Price and volume breakout strategy using EMA crossover.
/// </summary>
public class PriceAndVolumeBreakoutBuyStrategy : Strategy
{
	private readonly StrategyParam<int> _slowLength;
	private readonly StrategyParam<DataType> _candleType;

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

	public PriceAndVolumeBreakoutBuyStrategy()
	{
		_slowLength = Param(nameof(SlowLength), 40)
			.SetGreaterThanZero()
			.SetDisplay("Slow Length", "Slow EMA period", "General");

		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
			.SetDisplay("Candle Type", "Candle type", "General");
	}

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

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

		var fast = new ExponentialMovingAverage { Length = 14 };
		var slow = new ExponentialMovingAverage { Length = SlowLength };

		var prevF = 0m;
		var prevS = 0m;
		var init = false;
		var lastSignal = DateTimeOffset.MinValue;
		var cooldown = TimeSpan.FromMinutes(360);

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(fast, slow, (candle, f, s) =>
			{
				if (candle.State != CandleStates.Finished)
					return;

				if (!fast.IsFormed || !slow.IsFormed)
					return;

				if (!init)
				{
					prevF = f;
					prevS = s;
					init = true;
					return;
				}

				if (candle.OpenTime - lastSignal >= cooldown)
				{
					if (prevF <= prevS && f > s && Position <= 0)
					{
						BuyMarket();
						lastSignal = candle.OpenTime;
					}
					else if (prevF >= prevS && f < s && Position >= 0)
					{
						SellMarket();
						lastSignal = candle.OpenTime;
					}
				}

				prevF = f;
				prevS = s;
			})
			.Start();

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