Ver en GitHub

Estrategia de Tendencia de Velas

Descripción general

Esta estrategia abre posiciones basándose en la dirección de velas consecutivas. Se abre una posición larga después de que aparezca un número especificado de velas alcistas seguidas, mientras que se abre una posición corta después del mismo número de velas bajistas. Las posiciones existentes pueden cerrarse cuando ocurra la señal opuesta.

Parámetros

  • Candle Type: Marco temporal de las velas utilizadas para el análisis.
  • Trend Candles: Número de velas consecutivas en una dirección necesarias para activar una acción.
  • Take Profit %: Take-profit opcional expresado como porcentaje del precio de entrada.
  • Stop Loss %: Stop-loss opcional expresado como porcentaje del precio de entrada.
  • Enable Long Entry: Permitir abrir posiciones largas.
  • Enable Short Entry: Permitir abrir posiciones cortas.
  • Enable Long Exit: Permitir cerrar posiciones largas en señal opuesta.
  • Enable Short Exit: Permitir cerrar posiciones cortas en señal opuesta.

Lógica

  1. Suscribirse a los datos de velas del marco temporal seleccionado.
  2. Seguir el número de velas alcistas y bajistas consecutivas.
  3. Cuando el contador alcista alcanza el número requerido:
    • Cerrar posiciones cortas si está permitido.
    • Abrir una posición larga si está permitido.
  4. Cuando el contador bajista alcanza el número requerido:
    • Cerrar posiciones largas si está permitido.
    • Abrir una posición corta si está permitido.
  5. Las órdenes de protección opcionales se establecen usando StartProtection.

Notas

  • Las señales se procesan solo en velas completadas.
  • La estrategia usa BuyMarket y SellMarket para entradas y salidas.
  • Todos los comentarios en el código están escritos en inglés según lo requerido.
using System;
using System.Linq;
using System.Collections.Generic;

using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;

using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Strategy that trades based on consecutive candle directions.
/// Enters long after several bullish candles in a row and short after several bearish candles.
/// </summary>
public class CandleTrendStrategy : Strategy
{
	private readonly StrategyParam<int> _trendCandles;
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<decimal> _takeProfitPercent;
	private readonly StrategyParam<decimal> _stopLossPercent;
	private readonly StrategyParam<bool> _enableLongEntry;
	private readonly StrategyParam<bool> _enableShortEntry;
	private readonly StrategyParam<bool> _enableLongExit;
	private readonly StrategyParam<bool> _enableShortExit;

	private int _upCount;
	private int _downCount;

	/// <summary>
	/// Number of consecutive candles required to trigger an action.
	/// </summary>
	public int TrendCandles
	{
	    get => _trendCandles.Value;
	    set => _trendCandles.Value = value;
	}

	/// <summary>
	/// Type of candles used for analysis.
	/// </summary>
	public DataType CandleType
	{
	    get => _candleType.Value;
	    set => _candleType.Value = value;
	}

	/// <summary>
	/// Take profit as percentage from entry price.
	/// </summary>
	public decimal TakeProfitPercent
	{
	    get => _takeProfitPercent.Value;
	    set => _takeProfitPercent.Value = value;
	}

	/// <summary>
	/// Stop loss as percentage from entry price.
	/// </summary>
	public decimal StopLossPercent
	{
	    get => _stopLossPercent.Value;
	    set => _stopLossPercent.Value = value;
	}

	/// <summary>
	/// Allow opening long positions.
	/// </summary>
	public bool EnableLongEntry
	{
	    get => _enableLongEntry.Value;
	    set => _enableLongEntry.Value = value;
	}

	/// <summary>
	/// Allow opening short positions.
	/// </summary>
	public bool EnableShortEntry
	{
	    get => _enableShortEntry.Value;
	    set => _enableShortEntry.Value = value;
	}

	/// <summary>
	/// Allow closing long positions.
	/// </summary>
	public bool EnableLongExit
	{
	    get => _enableLongExit.Value;
	    set => _enableLongExit.Value = value;
	}

	/// <summary>
	/// Allow closing short positions.
	/// </summary>
	public bool EnableShortExit
	{
	    get => _enableShortExit.Value;
	    set => _enableShortExit.Value = value;
	}

	/// <summary>
	/// Initializes a new instance of <see cref="CandleTrendStrategy"/>.
	/// </summary>
	public CandleTrendStrategy()
	{
	    _trendCandles = Param(nameof(TrendCandles), 3)
	        .SetGreaterThanZero()
	        .SetDisplay("Trend Candles", "Number of candles in one direction", "General")
	        ;

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

	    _takeProfitPercent = Param(nameof(TakeProfitPercent), 0m)
	        .SetDisplay("Take Profit %", "Take profit percentage", "Risk Management")
	        ;
	    _stopLossPercent = Param(nameof(StopLossPercent), 0m)
	        .SetDisplay("Stop Loss %", "Stop loss percentage", "Risk Management")
	        ;

	    _enableLongEntry = Param(nameof(EnableLongEntry), true)
	        .SetDisplay("Enable Long Entry", "Permission to enter long", "General");

	    _enableShortEntry = Param(nameof(EnableShortEntry), true)
	        .SetDisplay("Enable Short Entry", "Permission to enter short", "General");

	    _enableLongExit = Param(nameof(EnableLongExit), true)
	        .SetDisplay("Enable Long Exit", "Permission to exit long", "General");

	    _enableShortExit = Param(nameof(EnableShortExit), true)
	        .SetDisplay("Enable Short Exit", "Permission to exit short", "General");
	}

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

	/// <inheritdoc />
	protected override void OnReseted()
	{
	    base.OnReseted();
	    _upCount = 0;
	    _downCount = 0;
	}

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

	    var tp = TakeProfitPercent > 0 ? new Unit(TakeProfitPercent, UnitTypes.Percent) : null;
	    var sl = StopLossPercent > 0 ? new Unit(StopLossPercent, UnitTypes.Percent) : null;
	    StartProtection(tp, sl);

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

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

	    if (!IsFormedAndOnlineAndAllowTrading())
	        return;

	    var isBull = candle.ClosePrice > candle.OpenPrice;
	    var isBear = candle.ClosePrice < candle.OpenPrice;

	    if (isBull)
	    {
	        _upCount++;
	        _downCount = 0;
	    }
	    else if (isBear)
	    {
	        _downCount++;
	        _upCount = 0;
	    }
	    else
	    {
	        _upCount = 0;
	        _downCount = 0;
	    }

	    if (_upCount >= TrendCandles)
	    {
	        if (Position < 0 && EnableLongExit)
	            BuyMarket();

	        if (Position <= 0 && EnableLongEntry)
	            BuyMarket();
	    }
	    else if (_downCount >= TrendCandles)
	    {
	        if (Position > 0 && EnableShortExit)
	            SellMarket();

	        if (Position >= 0 && EnableShortEntry)
	            SellMarket();
	    }
	}
}