Ver en GitHub

Estrategia de Líneas de Tendencia Automáticas

Construye líneas de tendencia dinámicas de soporte y resistencia conectando los máximos y mínimos pivot recientes. Se genera una señal larga cuando el precio cierra por encima de la línea de resistencia, mientras que una señal corta se activa cuando el precio cae por debajo de la línea de soporte.

Detalles

  • Criterios de entrada:
    • Largo: El cierre cruza por encima de la línea de tendencia de resistencia.
    • Corto: El cierre cruza por debajo de la línea de tendencia de soporte.
  • Criterios de salida:
    • Señal opuesta o reversión de posición.
  • Indicadores:
    • Líneas de tendencia basadas en pivots.
  • Stops: Ninguno.
  • Valores predeterminados:
    • LeftBars = 100
    • RightBars = 15
  • Filtros:
    • Seguimiento de tendencia
    • Marco temporal único
    • Indicadores: líneas de tendencia pivot
    • Stops: ninguno
    • Complejidad: Bajo
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>
/// Automatic Trendlines Strategy.
/// Uses Highest/Lowest channel breakouts with EMA trend filter.
/// </summary>
public class AutomaticTrendlinesStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _channelLength;
	private readonly StrategyParam<int> _emaLength;
	private readonly StrategyParam<int> _cooldownBars;

	private decimal _prevHighest;
	private decimal _prevLowest;
	private int _barIndex;
	private int _lastTradeBar;

	/// <summary>
	/// Candle type.
	/// </summary>
	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	/// <summary>
	/// Channel lookback length.
	/// </summary>
	public int ChannelLength
	{
		get => _channelLength.Value;
		set => _channelLength.Value = value;
	}

	/// <summary>
	/// EMA trend filter period.
	/// </summary>
	public int EmaLength
	{
		get => _emaLength.Value;
		set => _emaLength.Value = value;
	}

	/// <summary>
	/// Cooldown bars between trades.
	/// </summary>
	public int CooldownBars
	{
		get => _cooldownBars.Value;
		set => _cooldownBars.Value = value;
	}

	/// <summary>
	/// Constructor.
	/// </summary>
	public AutomaticTrendlinesStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(1).TimeFrame())
			.SetDisplay("Candle type", "Candle type for strategy calculation", "General");

		_channelLength = Param(nameof(ChannelLength), 30)
			.SetGreaterThanZero()
			.SetDisplay("Channel Length", "Lookback for Highest/Lowest", "Indicators");

		_emaLength = Param(nameof(EmaLength), 50)
			.SetGreaterThanZero()
			.SetDisplay("EMA Length", "EMA trend filter period", "Indicators");

		_cooldownBars = Param(nameof(CooldownBars), 350)
			.SetDisplay("Cooldown Bars", "Bars between trades", "Trading");
	}

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

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevHighest = 0;
		_prevLowest = 0;
		_barIndex = 0;
		_lastTradeBar = 0;
	}

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

		var highest = new Highest { Length = ChannelLength };
		var lowest = new Lowest { Length = ChannelLength };
		var ema = new ExponentialMovingAverage { Length = EmaLength };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(highest, lowest, ema, ProcessCandle)
			.Start();

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

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

		_barIndex++;

		var cooldownOk = _barIndex - _lastTradeBar > CooldownBars;

		// Breakout above resistance trendline with uptrend
		var breakUp = _prevHighest > 0 && candle.ClosePrice > _prevHighest && candle.ClosePrice > emaValue;
		// Breakdown below support trendline with downtrend
		var breakDown = _prevLowest > 0 && candle.ClosePrice < _prevLowest && candle.ClosePrice < emaValue;

		if (breakUp && Position <= 0 && cooldownOk)
		{
			BuyMarket();
			_lastTradeBar = _barIndex;
		}
		else if (breakDown && Position >= 0 && cooldownOk)
		{
			SellMarket();
			_lastTradeBar = _barIndex;
		}

		_prevHighest = highestValue;
		_prevLowest = lowestValue;
	}
}