Ver en GitHub

Estrategia BlauTvi

Esta estrategia convierte el experto MQL5 Exp_BlauTVI en una estrategia de alto nivel de StockSharp. Utiliza el Blau True Volume Index (TVI) para detectar reversiones en el flujo de volumen de ticks.

Idea

El True Volume Index separa los up-ticks y down-ticks y los suaviza con tres medias móviles exponenciales. El valor final oscila entre -100 y +100 y representa el dominio de compradores o vendedores. La estrategia abre una posición larga cuando el indicador gira hacia arriba tras un descenso y abre una posición corta cuando el indicador gira hacia abajo tras una subida. Las posiciones existentes en la dirección opuesta se cierran.

Parámetros

  • Length1 – primer período de suavizado para up-ticks y down-ticks.
  • Length2 – segundo período de suavizado.
  • Length3 – período de suavizado final aplicado al TVI.
  • CandleType – tipo de velas utilizado para los cálculos (por defecto: marco temporal de 4 horas).
  • Allow Buy Open – habilitar apertura de posiciones largas.
  • Allow Sell Open – habilitar apertura de posiciones cortas.
  • Allow Buy Close – habilitar cierre de posiciones largas cuando aparece una señal de venta.
  • Allow Sell Close – habilitar cierre de posiciones cortas cuando aparece una señal de compra.
  • Enable Stop Loss – usar protección de stop-loss en puntos.
  • Stop Loss – valor del stop-loss en puntos.
  • Enable Take Profit – usar protección de take-profit en puntos.
  • Take Profit – valor del take-profit en puntos.
  • Volume – volumen de la orden en lotes.

Señales

  1. Compra – cuando el valor anterior del TVI es menor que el de antes y el valor actual del TVI es mayor que el anterior. Si está habilitado, se cierran las posiciones cortas existentes.
  2. Venta – cuando el valor anterior del TVI es mayor que el de antes y el valor actual del TVI es menor que el anterior. Si está habilitado, se cierran las posiciones largas existentes.

Solo se procesan velas finalizadas y todos los cálculos usan el volumen de ticks de la vela. El stop-loss y el take-profit son opcionales y se expresan en puntos de precio.

Notas

La estrategia usa la API de alto nivel: se suscribe a velas, calcula el indicador internamente con instancias de ExponentialMovingAverage y gestiona posiciones con los métodos BuyMarket y SellMarket. El gráfico muestra el indicador TVI junto con las operaciones ejecutadas por la estrategia.

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 smoothed momentum direction changes (Blau TVI concept).
/// Uses triple-smoothed EMA direction changes for signals.
/// </summary>
public class BlauTviStrategy : Strategy
{
	private readonly StrategyParam<int> _length;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _prevEma;
	private decimal _prevPrevEma;
	private int _count;

	public int Length { get => _length.Value; set => _length.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public BlauTviStrategy()
	{
		_length = Param(nameof(Length), 12)
			.SetGreaterThanZero()
			.SetDisplay("Length", "Smoothing length", "Indicator");

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

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

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevEma = 0;
		_prevPrevEma = 0;
		_count = 0;
	}

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

		var ema = new ExponentialMovingAverage { Length = Length };

		SubscribeCandles(CandleType)
			.Bind(ema, ProcessCandle)
			.Start();
	}

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

		_count++;

		if (_count < 3)
		{
			_prevPrevEma = _prevEma;
			_prevEma = emaValue;
			return;
		}

		var turnUp = _prevEma < _prevPrevEma && emaValue > _prevEma;
		var turnDown = _prevEma > _prevPrevEma && emaValue < _prevEma;

		if (turnUp && Position <= 0)
		{
			if (Position < 0) BuyMarket();
			BuyMarket();
		}
		else if (turnDown && Position >= 0)
		{
			if (Position > 0) SellMarket();
			SellMarket();
		}

		_prevPrevEma = _prevEma;
		_prevEma = emaValue;
	}
}