Ver en GitHub

Estrategia ASCTrendND

Esta estrategia está inspirada en el asesor experto ASCTrendND de MQL5. Utiliza una Media Móvil Simple como señal principal de tendencia, un filtro RSI para confirmar la fuerza y un stop trailing basado en ATR para salir de las operaciones. El enfoque intenta replicar la lógica ASCTrend + NRTR + TrendStrength de forma simplificada en la API de alto nivel de StockSharp.

Detalles

  • Criterios de entrada:
    • Largo: El precio de cierre está por encima de la SMA y RSI > 50.
    • Corto: El precio de cierre está por debajo de la SMA y RSI < 50.
  • Criterios de salida:
    • Stop trailing basado en ATR * multiplicador o señal contraria.
  • Stops: Solo stop trailing basado en ATR.
  • Valores predeterminados:
    • SmaPeriod = 50
    • RsiPeriod = 14
    • AtrPeriod = 14
    • AtrMultiplier = 2.0
    • CandleType = velas de 5 minutos
  • Filtros:
    • Categoría: Seguimiento de tendencia
    • Dirección: Largo/Corto
    • Indicadores: SMA, RSI, ATR
    • Stops: Trailing
    • Complejidad: Bajo
    • Marco temporal: 5m
    • 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>
/// ASCTrendND-inspired strategy using SMA, RSI and ATR-based trailing stop.
/// </summary>
public class AscTrendNdStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _smaPeriod;
	private readonly StrategyParam<int> _rsiPeriod;
	private readonly StrategyParam<int> _atrPeriod;
	private readonly StrategyParam<decimal> _atrMultiplier;

	private SimpleMovingAverage _sma;
	private RelativeStrengthIndex _rsi;
	private AverageTrueRange _atr;

	private decimal? _stopPrice;

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

	/// <summary>
	/// SMA period.
	/// </summary>
	public int SmaPeriod { get => _smaPeriod.Value; set => _smaPeriod.Value = value; }

	/// <summary>
	/// RSI period.
	/// </summary>
	public int RsiPeriod { get => _rsiPeriod.Value; set => _rsiPeriod.Value = value; }

	/// <summary>
	/// ATR period for volatility estimate.
	/// </summary>
	public int AtrPeriod { get => _atrPeriod.Value; set => _atrPeriod.Value = value; }

	/// <summary>
	/// ATR multiplier for trailing stop distance.
	/// </summary>
	public decimal AtrMultiplier { get => _atrMultiplier.Value; set => _atrMultiplier.Value = value; }

	/// <summary>
	/// Initializes strategy parameters.
	/// </summary>
	public AscTrendNdStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Type of source candles", "General");

		_smaPeriod = Param(nameof(SmaPeriod), 50)
			.SetGreaterThanZero()
			.SetDisplay("SMA Period", "Length of simple moving average", "Indicators");

		_rsiPeriod = Param(nameof(RsiPeriod), 14)
			.SetGreaterThanZero()
			.SetDisplay("RSI Period", "Length of relative strength index", "Indicators");

		_atrPeriod = Param(nameof(AtrPeriod), 14)
			.SetGreaterThanZero()
			.SetDisplay("ATR Period", "Length of average true range", "Risk");

		_atrMultiplier = Param(nameof(AtrMultiplier), 2m)
			.SetGreaterThanZero()
			.SetDisplay("ATR Multiplier", "ATR multiplier for stop trailing", "Risk");
	}

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

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_sma = null;
		_rsi = null;
		_atr = null;
		_stopPrice = null;
	}

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

		_stopPrice = null;

		_sma = new SimpleMovingAverage { Length = SmaPeriod };
		_rsi = new RelativeStrengthIndex { Length = RsiPeriod };
		_atr = new AverageTrueRange { Length = AtrPeriod };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(_sma, _rsi, _atr, ProcessCandle)
			.Start();

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

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

		if (!IsFormedAndOnlineAndAllowTrading())
			return;

		var price = candle.ClosePrice;

		if (Position == 0)
		{
			if (price > smaValue && rsiValue > 50m)
			{
				_stopPrice = price - atrValue * AtrMultiplier;
				BuyMarket();
			}
			else if (price < smaValue && rsiValue < 50m)
			{
				_stopPrice = price + atrValue * AtrMultiplier;
				SellMarket();
			}
			return;
		}

		if (_stopPrice is null)
			return;

		if (Position > 0)
		{
			var newStop = price - atrValue * AtrMultiplier;
			if (newStop > _stopPrice)
				_stopPrice = newStop;

			if (price <= _stopPrice)
				SellMarket();
		}
		else
		{
			var newStop = price + atrValue * AtrMultiplier;
			if (newStop < _stopPrice)
				_stopPrice = newStop;

			if (price >= _stopPrice)
				BuyMarket();
		}
	}
}