Ver en GitHub

Estrategia de Cruce TRIX

Esta estrategia utiliza dos indicadores TRIX (Oscilador de Media Móvil Triple Exponencial) con diferentes períodos para detectar posibles reversiones. Se abre una posición larga cuando el TRIX rápido forma un mínimo local mientras el TRIX lento está subiendo. Se abre una posición corta cuando el TRIX rápido forma un máximo local mientras el TRIX lento está bajando.

Parámetros

  • Fast TRIX Period – período del indicador TRIX rápido.
  • Slow TRIX Period – período del indicador TRIX lento.
  • Take Profit – objetivo de beneficio en unidades de precio absolutas.
  • Stop Loss – pérdida máxima en unidades de precio absolutas.
  • Candle Type – marco temporal o tipo de datos para las velas.

Lógica de Trading

  1. Suscribirse al tipo de vela seleccionado.
  2. Calcular los valores de TRIX rápido y lento en cada vela finalizada.
  3. Entrar largo cuando el valor del TRIX rápido es mayor que su valor anterior, el valor anterior es menor que el valor previo a él, y el TRIX lento está subiendo.
  4. Entrar corto cuando el valor del TRIX rápido es menor que su valor anterior, el valor anterior es mayor que el valor previo a él, y el TRIX lento está bajando.
  5. Solo se mantiene una posición a la vez.
  6. Las protecciones de stop loss y take profit se aplican automáticamente.

Notas

La estrategia es una adaptación de un script MQL5 y demuestra cómo trabajar con indicadores TRIX dentro de StockSharp.

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 fast and slow TRIX indicator signals.
/// A long position opens when the fast TRIX forms a local bottom and the slow TRIX is rising.
/// A short position opens when the fast TRIX forms a local top and the slow TRIX is falling.
/// </summary>
public class TrixCrossoverStrategy : Strategy
{
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;
	private readonly StrategyParam<decimal> _minTrix;
	private readonly StrategyParam<decimal> _takeProfit;
	private readonly StrategyParam<decimal> _stopLoss;
	private readonly StrategyParam<DataType> _candleType;

	// Store previous TRIX values for decision making
	private decimal _fastTrixPrev1;
	private decimal _fastTrixPrev2;
	private decimal _slowTrixPrev;
	private decimal _prevFastTema;
	private decimal _prevSlowTema;
	private TripleExponentialMovingAverage _fastTema = null!;
	private TripleExponentialMovingAverage _slowTema = null!;

	/// <summary>
	/// Fast TRIX period.
	/// </summary>
	public int FastPeriod
	{
		get => _fastPeriod.Value;
		set => _fastPeriod.Value = value;
	}

	/// <summary>
	/// Slow TRIX period.
	/// </summary>
	public int SlowPeriod
	{
		get => _slowPeriod.Value;
		set => _slowPeriod.Value = value;
	}

	/// <summary>
	/// Minimum TRIX value required for a signal.
	/// </summary>
	public decimal MinTrix
	{
		get => _minTrix.Value;
		set => _minTrix.Value = value;
	}

	/// <summary>
	/// Take profit size in absolute price units.
	/// </summary>
	public decimal TakeProfit
	{
		get => _takeProfit.Value;
		set => _takeProfit.Value = value;
	}

	/// <summary>
	/// Stop loss size in absolute price units.
	/// </summary>
	public decimal StopLoss
	{
		get => _stopLoss.Value;
		set => _stopLoss.Value = value;
	}

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

	/// <summary>
	/// Initializes <see cref="TrixCrossoverStrategy"/>.
	/// </summary>
	public TrixCrossoverStrategy()
	{
		_fastPeriod = Param(nameof(FastPeriod), 9)
			.SetGreaterThanZero()
			.SetDisplay("Fast TRIX Period", "Period for the fast TRIX indicator", "Indicators");
		_slowPeriod = Param(nameof(SlowPeriod), 21)
			.SetGreaterThanZero()
			.SetDisplay("Slow TRIX Period", "Period for the slow TRIX indicator", "Indicators");
		_minTrix = Param(nameof(MinTrix), 0.0005m)
			.SetGreaterThanZero()
			.SetDisplay("Min TRIX", "Minimum TRIX magnitude for signals", "Indicators");
		_takeProfit = Param(nameof(TakeProfit), 1500m)
			.SetNotNegative()
			.SetDisplay("Take Profit", "Take profit in absolute price units", "Risk Management");
		_stopLoss = Param(nameof(StopLoss), 500m)
			.SetNotNegative()
			.SetDisplay("Stop Loss", "Stop loss in absolute price units", "Risk Management");
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Type of candles to use", "General");
	}

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

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();

		_fastTrixPrev1 = 0m;
		_fastTrixPrev2 = 0m;
		_slowTrixPrev = 0m;
		_prevFastTema = 0m;
		_prevSlowTema = 0m;
		_fastTema = null!;
		_slowTema = null!;
	}

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

		_fastTrixPrev1 = 0m;
		_fastTrixPrev2 = 0m;
		_slowTrixPrev = 0m;
		_prevFastTema = 0m;
		_prevSlowTema = 0m;
		_fastTema = new TripleExponentialMovingAverage { Length = FastPeriod };
		_slowTema = new TripleExponentialMovingAverage { Length = SlowPeriod };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(_fastTema, _slowTema, ProcessCandle)
			.Start();

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

		StartProtection(new Unit(TakeProfit, UnitTypes.Absolute), new Unit(StopLoss, UnitTypes.Absolute));
	}

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

		if (_prevFastTema == 0m || _prevSlowTema == 0m)
		{
			_prevFastTema = fastTemaValue;
			_prevSlowTema = slowTemaValue;
			return;
		}

		var fastTrix = (fastTemaValue - _prevFastTema) / _prevFastTema;
		var slowTrix = (slowTemaValue - _prevSlowTema) / _prevSlowTema;

		_prevFastTema = fastTemaValue;
		_prevSlowTema = slowTemaValue;

		var prevFastTrix = _fastTrixPrev1;
		_fastTrixPrev2 = _fastTrixPrev1;
		_fastTrixPrev1 = fastTrix;

		var slowTrixPrev = _slowTrixPrev;
		_slowTrixPrev = slowTrix;

		if (_fastTrixPrev2 == 0m || slowTrixPrev == 0m)
			return;

		if (!IsFormedAndOnlineAndAllowTrading())
			return;

		var crossUp = prevFastTrix <= 0 && fastTrix > 0;
		var crossDown = prevFastTrix >= 0 && fastTrix < 0;

		if (crossUp && slowTrix > MinTrix && Position <= 0)
			BuyMarket();
		else if (crossDown && slowTrix < -MinTrix && Position >= 0)
			SellMarket();
	}
}