Ver no GitHub

Estratégia Blau Ergodic MDI

Visão geral

A estratégia Blau Ergodic Market Directional Indicator (MDI) reproduz o comportamento do consultor especialista do MetaTrader Exp_BlauErgodicMDI. O algoritmo opera em um fluxo de velas de período superior (padrão 4H) e aplica um pipeline de suavização tripla à entrada de preço selecionada para construir um histograma de momentum e uma linha de sinal. As decisões de trading são derivadas desse histograma usando um de três modos de entrada configuráveis:

  1. Breakdown – opera quando o histograma cruza a linha zero.
  2. Twist – reage a reversões na inclinação do histograma (momentum mudando de direção).
  3. CloudTwist – atua em cruzamentos do histograma/linha de sinal.

Cada sinal pode opcionalmente fechar posições opostas e/ou abrir novas negociações dependendo dos sinalizadores de permissão fornecidos pelo usuário.

Lógica do indicador

  1. Suavizar o preço aplicado escolhido com o tipo de média móvel configurado e PrimaryLength para obter o preço base.
  2. Calcular a diferença de momentum (price - baseline) / point_value.
  3. Suavizar esse momentum com FirstSmoothingLength e SecondSmoothingLength para construir o histograma.
  4. Suavizar o histograma mais uma vez com SignalLength para obter a linha de sinal.
  5. Armazenar em buffer valores históricos de acordo com SignalBarShift para que os sinais possam ser confirmados em velas fechadas.

As famílias de suavização suportadas são EMA, SMA, SMMA/RMA e WMA. A seleção do preço aplicado espelha a implementação do MetaTrader (fechamento, abertura, máximo, mínimo, mediana, típico, ponderado, simples, quarto, variantes de acompanhamento de tendência).

Parâmetros

Nome Descrição
Volume Tamanho da ordem usado ao abrir posições.
StopLossPoints Distância do stop-loss em pontos do instrumento (0 desativa).
TakeProfitPoints Distância do take-profit em pontos do instrumento (0 desativa).
SlippagePoints Derrapagem de preço máxima em pontos aplicada a ordens a mercado.
AllowLongEntries / AllowShortEntries Permitir abrir posições na respectiva direção.
AllowLongExits / AllowShortExits Permitir fechar posições existentes em sinais opostos.
Mode Modo de entrada (Breakdown / Twist / CloudTwist).
CandleType Período das velas usadas para cálculos (padrão 4H).
SmoothingMethods Família de média móvel usada em todos os passos de suavização.
PrimaryLength Comprimento de suavização base para o preço aplicado.
FirstSmoothingLength Primeiro comprimento de suavização aplicado ao momentum.
SecondSmoothingLength Segundo comprimento de suavização formando o histograma.
SignalLength Comprimento de suavização do histograma para criar a linha de sinal.
AppliedPrices Fonte de preço usada nos cálculos do indicador.
SignalBarShift Número de barras fechadas a serem analisadas ao avaliar sinais.
Phase Parâmetro reservado para compatibilidade (não usado na implementação atual).

Condições de sinal

  • Breakdown
    • Comprado: histograma em SignalBarShift é positivo enquanto a barra anterior não é.
    • Vendido: histograma em SignalBarShift é negativo enquanto a barra anterior não é.
  • Twist
    • Comprado: histograma em SignalBarShift está subindo após um período de queda (anterior < mais recente e duas barras atrás > anterior).
    • Vendido: histograma em SignalBarShift está caindo após um período de subida (anterior > mais recente e duas barras atrás < anterior).
  • CloudTwist
    • Comprado: histograma cruza acima da linha de sinal (histograma mais recente > sinal mais recente, histograma anterior <= sinal anterior).
    • Vendido: histograma cruza abaixo da linha de sinal.

Cada sinal pode tanto nivelar a exposição oposta (se saídas forem permitidas) quanto abrir uma nova negociação com o volume configurado.

Gestão de risco

StartProtection é inicializado com as distâncias de stop-loss e take-profit especificadas (convertidas de pontos para unidades de preço usando o tamanho de tick do instrumento). Se qualquer distância for zero, a proteção respectiva é omitida. A derrapagem também é convertida para unidades de preço usando o mesmo tamanho de tick.

Notas

  • Os sinais são processados apenas em velas finalizadas para espelhar o comportamento original do MetaTrader.
  • SignalBarShift permite atrasar a confirmação de negociações para evitar agir na barra mais recente.
  • O parâmetro Phase é mantido por completude, mas não tem efeito ao usar os métodos de suavização suportados.
  • Todos os comentários de código são fornecidos em inglês para simplificar a manutenção futura.
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>
/// Blau Ergodic Market Directional Indicator strategy converted from MetaTrader.
/// Uses a triple-smoothed momentum histogram with configurable entry confirmation modes.
/// </summary>
public class BlauErgodicMdiStrategy : Strategy
{
	private readonly StrategyParam<int> _stopLossPoints;
	private readonly StrategyParam<int> _takeProfitPoints;
	private readonly StrategyParam<int> _slippagePoints;
	private readonly StrategyParam<bool> _allowLongEntries;
	private readonly StrategyParam<bool> _allowShortEntries;
	private readonly StrategyParam<bool> _allowLongExits;
	private readonly StrategyParam<bool> _allowShortExits;
	private readonly StrategyParam<EntryModes> _entryMode;
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<SmoothingMethods> _smoothingMethod;
	private readonly StrategyParam<int> _primaryLength;
	private readonly StrategyParam<int> _firstSmoothingLength;
	private readonly StrategyParam<int> _secondSmoothingLength;
	private readonly StrategyParam<int> _signalLength;
	private readonly StrategyParam<AppliedPrices> _appliedPrice;
	private readonly StrategyParam<int> _signalBarShift;
	private readonly StrategyParam<int> _phase;

	private IIndicator _priceAverage = null!;
	private IIndicator _firstSmoothing = null!;
	private IIndicator _secondSmoothing = null!;
	private IIndicator _signalSmoothing = null!;

	private decimal[] _histogramBuffer = Array.Empty<decimal>();
	private decimal[] _signalBuffer = Array.Empty<decimal>();
	private int _bufferIndex;
	private int _bufferFilled;
	private decimal _pointValue = 1m;
	private decimal _entryPrice;
	private decimal? _stopPrice;
	private decimal? _takePrice;

	/// <summary>
	/// Initializes a new instance of <see cref="BlauErgodicMdiStrategy"/>.
	/// </summary>
	public BlauErgodicMdiStrategy()
	{
		_stopLossPoints = Param(nameof(StopLossPoints), 1000)
			.SetNotNegative()
			.SetDisplay("Stop Loss", "Stop loss in points", "Risk");

		_takeProfitPoints = Param(nameof(TakeProfitPoints), 2000)
			.SetNotNegative()
			.SetDisplay("Take Profit", "Take profit in points", "Risk");

		_slippagePoints = Param(nameof(SlippagePoints), 10)
			.SetNotNegative()
			.SetDisplay("Slippage", "Maximum slippage in points", "Risk");

		_allowLongEntries = Param(nameof(AllowLongEntries), true)
			.SetDisplay("Allow Long Entries", "Enable opening long positions", "Permissions");

		_allowShortEntries = Param(nameof(AllowShortEntries), true)
			.SetDisplay("Allow Short Entries", "Enable opening short positions", "Permissions");

		_allowLongExits = Param(nameof(AllowLongExits), true)
			.SetDisplay("Allow Long Exits", "Enable closing long positions", "Permissions");

		_allowShortExits = Param(nameof(AllowShortExits), true)
			.SetDisplay("Allow Short Exits", "Enable closing short positions", "Permissions");

		_entryMode = Param(nameof(Mode), EntryModes.Twist)
			.SetDisplay("Entry Mode", "Signal interpretation mode", "Strategy");

		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Indicator Timeframe", "Timeframe used for calculations", "Data");

		_smoothingMethod = Param(nameof(SmoothingMethod), SmoothingMethods.Exponential)
			.SetDisplay("Smoothing Method", "Type of moving average", "Indicator");

		_primaryLength = Param(nameof(PrimaryLength), 20)
			.SetGreaterThanZero()
			.SetDisplay("Primary Length", "Base smoothing length", "Indicator")
			
			.SetOptimize(5, 60, 1);

		_firstSmoothingLength = Param(nameof(FirstSmoothingLength), 5)
			.SetGreaterThanZero()
			.SetDisplay("Momentum Smoothing", "First smoothing length", "Indicator")
			
			.SetOptimize(2, 20, 1);

		_secondSmoothingLength = Param(nameof(SecondSmoothingLength), 3)
			.SetGreaterThanZero()
			.SetDisplay("Histogram Smoothing", "Second smoothing length", "Indicator")
			
			.SetOptimize(2, 20, 1);

		_signalLength = Param(nameof(SignalLength), 8)
			.SetGreaterThanZero()
			.SetDisplay("Signal Length", "Signal line smoothing", "Indicator")
			
			.SetOptimize(2, 30, 1);

		_appliedPrice = Param(nameof(AppliedPrice), AppliedPrices.Close)
			.SetDisplay("Applied Price", "Price source for calculations", "Indicator");

		_signalBarShift = Param(nameof(SignalBarShift), 1)
			.SetNotNegative()
			.SetDisplay("Signal Bar", "Shift of the bar used for signals", "Strategy");

		_phase = Param(nameof(Phase), 15)
			.SetDisplay("Phase", "Reserved smoothing phase parameter", "Indicator");
	}

	/// <summary>
	/// Stop loss distance expressed in instrument points.
	/// </summary>
	public int StopLossPoints
	{
		get => _stopLossPoints.Value;
		set => _stopLossPoints.Value = value;
	}

	/// <summary>
	/// Take profit distance expressed in instrument points.
	/// </summary>
	public int TakeProfitPoints
	{
		get => _takeProfitPoints.Value;
		set => _takeProfitPoints.Value = value;
	}

	/// <summary>
	/// Allowed price slippage in points.
	/// </summary>
	public int SlippagePoints
	{
		get => _slippagePoints.Value;
		set => _slippagePoints.Value = value;
	}

	/// <summary>
	/// Enables opening long positions.
	/// </summary>
	public bool AllowLongEntries
	{
		get => _allowLongEntries.Value;
		set => _allowLongEntries.Value = value;
	}

	/// <summary>
	/// Enables opening short positions.
	/// </summary>
	public bool AllowShortEntries
	{
		get => _allowShortEntries.Value;
		set => _allowShortEntries.Value = value;
	}

	/// <summary>
	/// Enables closing existing long positions on opposite signals.
	/// </summary>
	public bool AllowLongExits
	{
		get => _allowLongExits.Value;
		set => _allowLongExits.Value = value;
	}

	/// <summary>
	/// Enables closing existing short positions on opposite signals.
	/// </summary>
	public bool AllowShortExits
	{
		get => _allowShortExits.Value;
		set => _allowShortExits.Value = value;
	}

	/// <summary>
	/// Selected entry confirmation mode.
	/// </summary>
	public EntryModes Mode
	{
		get => _entryMode.Value;
		set => _entryMode.Value = value;
	}

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

	/// <summary>
	/// Moving average family used for smoothing steps.
	/// </summary>
	public SmoothingMethods SmoothingMethod
	{
		get => _smoothingMethod.Value;
		set => _smoothingMethod.Value = value;
	}

	/// <summary>
	/// Length for the initial smoothing of price.
	/// </summary>
	public int PrimaryLength
	{
		get => _primaryLength.Value;
		set => _primaryLength.Value = value;
	}

	/// <summary>
	/// Length of the first smoothing applied to momentum.
	/// </summary>
	public int FirstSmoothingLength
	{
		get => _firstSmoothingLength.Value;
		set => _firstSmoothingLength.Value = value;
	}

	/// <summary>
	/// Length of the second smoothing forming the histogram.
	/// </summary>
	public int SecondSmoothingLength
	{
		get => _secondSmoothingLength.Value;
		set => _secondSmoothingLength.Value = value;
	}

	/// <summary>
	/// Length of the signal line smoothing.
	/// </summary>
	public int SignalLength
	{
		get => _signalLength.Value;
		set => _signalLength.Value = value;
	}

	/// <summary>
	/// Applied price selection for calculations.
	/// </summary>
	public AppliedPrices AppliedPrice
	{
		get => _appliedPrice.Value;
		set => _appliedPrice.Value = value;
	}

	/// <summary>
	/// Offset of the bar used for signal confirmation.
	/// </summary>
	public int SignalBarShift
	{
		get => _signalBarShift.Value;
		set => _signalBarShift.Value = value;
	}

	/// <summary>
	/// Reserved phase parameter kept for compatibility with the original script.
	/// </summary>
	public int Phase
	{
		get => _phase.Value;
		set => _phase.Value = value;
	}

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

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

		_histogramBuffer = Array.Empty<decimal>();
		_signalBuffer = Array.Empty<decimal>();
		_bufferIndex = 0;
		_bufferFilled = 0;
		_entryPrice = 0m;
		_stopPrice = null;
		_takePrice = null;
	}

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

		_pointValue = Security?.PriceStep ?? 1m;
		if (_pointValue <= 0m)
			_pointValue = 1m;

		_priceAverage = CreateMovingAverage(SmoothingMethod, PrimaryLength);
		_firstSmoothing = CreateMovingAverage(SmoothingMethod, FirstSmoothingLength);
		_secondSmoothing = CreateMovingAverage(SmoothingMethod, SecondSmoothingLength);
		_signalSmoothing = CreateMovingAverage(SmoothingMethod, SignalLength);

		InitializeBuffers();

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

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

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

		ApplyRiskManagement(candle);

		var price = SelectPrice(candle);
		var time = candle.CloseTime;

		// Smooth the selected price to match the indicator baseline.
		var baseValue = _priceAverage.Process(new DecimalIndicatorValue(_priceAverage, price, time) { IsFinal = true });
		if (!baseValue.IsFormed)
			return;

		var basePrice = baseValue.ToDecimal();
		var momentum = _pointValue != 0m ? (price - basePrice) / _pointValue : 0m;

		// Apply the first momentum smoothing stage.
		var firstValue = _firstSmoothing.Process(new DecimalIndicatorValue(_firstSmoothing, momentum, time) { IsFinal = true });
		if (!firstValue.IsFormed)
			return;

		var first = firstValue.ToDecimal();

		// Build the histogram with the second smoothing stage.
		var secondValue = _secondSmoothing.Process(new DecimalIndicatorValue(_secondSmoothing, first, time) { IsFinal = true });
		if (!secondValue.IsFormed)
			return;

		var histogram = secondValue.ToDecimal();

		// Smooth the histogram to generate the signal line.
		var signalValue = _signalSmoothing.Process(new DecimalIndicatorValue(_signalSmoothing, histogram, time) { IsFinal = true });
		if (!signalValue.IsFormed)
			return;

		var signal = signalValue.ToDecimal();

		// Store values so that shifted comparisons work like in the MQL version.
		AddToBuffer(histogram, signal);

		if (!TryGetHist(SignalBarShift, out var latestHist) || !TryGetHist(SignalBarShift + 1, out var previousHist))
			return;

		var currentPosition = Position;
		var buySignal = false;
		var sellSignal = false;

		switch (Mode)
		{
			case EntryModes.Breakdown:
			{
				buySignal = latestHist > 0m && previousHist <= 0m;
				sellSignal = latestHist < 0m && previousHist >= 0m;
				break;
			}

			case EntryModes.Twist:
			{
				if (!TryGetHist(SignalBarShift + 2, out var olderHist))
					return;

				buySignal = previousHist < latestHist && olderHist > previousHist;
				sellSignal = previousHist > latestHist && olderHist < previousHist;
				break;
			}

			case EntryModes.CloudTwist:
			{
				if (!TryGetSignal(SignalBarShift, out var latestSignal) || !TryGetSignal(SignalBarShift + 1, out var previousSignal))
					return;

				buySignal = latestHist > latestSignal && previousHist <= previousSignal;
				sellSignal = latestHist < latestSignal && previousHist >= previousSignal;
				break;
			}
		}

		if (buySignal)
		{
			ExecuteBuy(currentPosition, candle.ClosePrice);
		}
		else if (sellSignal)
		{
			ExecuteSell(currentPosition, candle.ClosePrice);
		}
	}

	private void ExecuteBuy(decimal currentPosition, decimal price)
	{
		var volume = 0m;

		if (AllowShortExits && currentPosition < 0m)
			volume += Math.Abs(currentPosition);

		if (AllowLongEntries && (currentPosition <= 0m || (AllowShortExits && currentPosition < 0m)))
			volume += Volume;

		if (volume > 0m)
		{
			BuyMarket(volume);
			_entryPrice = price;
			var slDist = StopLossPoints > 0 ? StopLossPoints * _pointValue : 0m;
			var tpDist = TakeProfitPoints > 0 ? TakeProfitPoints * _pointValue : 0m;
			_stopPrice = slDist > 0m ? price - slDist : null;
			_takePrice = tpDist > 0m ? price + tpDist : null;
		}
	}

	private void ExecuteSell(decimal currentPosition, decimal price)
	{
		var volume = 0m;

		if (AllowLongExits && currentPosition > 0m)
			volume += Math.Abs(currentPosition);

		if (AllowShortEntries && (currentPosition >= 0m || (AllowLongExits && currentPosition > 0m)))
			volume += Volume;

		if (volume > 0m)
		{
			SellMarket(volume);
			_entryPrice = price;
			var slDist = StopLossPoints > 0 ? StopLossPoints * _pointValue : 0m;
			var tpDist = TakeProfitPoints > 0 ? TakeProfitPoints * _pointValue : 0m;
			_stopPrice = slDist > 0m ? price + slDist : null;
			_takePrice = tpDist > 0m ? price - tpDist : null;
		}
	}

	private void ApplyRiskManagement(ICandleMessage candle)
	{
		if (Position > 0)
		{
			if (_stopPrice.HasValue && candle.LowPrice <= _stopPrice.Value)
			{
				SellMarket(Position);
				ResetTargets();
				return;
			}
			if (_takePrice.HasValue && candle.HighPrice >= _takePrice.Value)
			{
				SellMarket(Position);
				ResetTargets();
			}
		}
		else if (Position < 0)
		{
			if (_stopPrice.HasValue && candle.HighPrice >= _stopPrice.Value)
			{
				BuyMarket(Math.Abs(Position));
				ResetTargets();
				return;
			}
			if (_takePrice.HasValue && candle.LowPrice <= _takePrice.Value)
			{
				BuyMarket(Math.Abs(Position));
				ResetTargets();
			}
		}
	}

	private void ResetTargets()
	{
		_entryPrice = 0m;
		_stopPrice = null;
		_takePrice = null;
	}

	private void InitializeBuffers()
	{
		var size = Math.Max(3, SignalBarShift + 3);
		_histogramBuffer = new decimal[size];
		_signalBuffer = new decimal[size];
		_bufferIndex = 0;
		_bufferFilled = 0;
	}

	private void AddToBuffer(decimal histogram, decimal signal)
	{
		if (_histogramBuffer.Length == 0)
			return;

		_histogramBuffer[_bufferIndex] = histogram;
		_signalBuffer[_bufferIndex] = signal;
		_bufferIndex = (_bufferIndex + 1) % _histogramBuffer.Length;
		if (_bufferFilled < _histogramBuffer.Length)
			_bufferFilled++;
	}

	private bool TryGetHist(int shift, out decimal value)
	{
		return TryGetBufferedValue(_histogramBuffer, shift, out value);
	}

	private bool TryGetSignal(int shift, out decimal value)
	{
		return TryGetBufferedValue(_signalBuffer, shift, out value);
	}

	private bool TryGetBufferedValue(decimal[] buffer, int shift, out decimal value)
	{
		value = default;

		if (shift < 0 || shift >= _bufferFilled)
			return false;

		var index = _bufferIndex - 1 - shift;
		if (index < 0)
			index += buffer.Length;

		value = buffer[index];
		return true;
	}

	private decimal SelectPrice(ICandleMessage candle)
	{
		return AppliedPrice switch
		{
			AppliedPrices.Open => candle.OpenPrice,
			AppliedPrices.High => candle.HighPrice,
			AppliedPrices.Low => candle.LowPrice,
			AppliedPrices.Median => (candle.HighPrice + candle.LowPrice) / 2m,
			AppliedPrices.Typical => (candle.ClosePrice + candle.HighPrice + candle.LowPrice) / 3m,
			AppliedPrices.Weighted => (2m * candle.ClosePrice + candle.HighPrice + candle.LowPrice) / 4m,
			AppliedPrices.Simple => (candle.OpenPrice + candle.ClosePrice) / 2m,
			AppliedPrices.Quarter => (candle.OpenPrice + candle.HighPrice + candle.LowPrice + candle.ClosePrice) / 4m,
			AppliedPrices.TrendFollow0 => candle.ClosePrice > candle.OpenPrice ? candle.HighPrice : candle.ClosePrice < candle.OpenPrice ? candle.LowPrice : candle.ClosePrice,
			AppliedPrices.TrendFollow1 => candle.ClosePrice > candle.OpenPrice ? (candle.HighPrice + candle.ClosePrice) / 2m : candle.ClosePrice < candle.OpenPrice ? (candle.LowPrice + candle.ClosePrice) / 2m : candle.ClosePrice,
			_ => candle.ClosePrice,
		};
	}

	private static IIndicator CreateMovingAverage(SmoothingMethods method, int length)
	{
		return method switch
		{
			SmoothingMethods.Simple => new SimpleMovingAverage { Length = length },
			SmoothingMethods.Smoothed => new SmoothedMovingAverage { Length = length },
			SmoothingMethods.Weighted => new WeightedMovingAverage { Length = length },
			_ => new ExponentialMovingAverage { Length = length },
		};
	}

	/// <summary>
	/// Entry confirmation modes replicated from the original expert advisor.
	/// </summary>
	public enum EntryModes
	{
		/// <summary>
		/// Histogram breaks above or below the zero line.
		/// </summary>
		Breakdown,

		/// <summary>
		/// Histogram changes slope direction.
		/// </summary>
		Twist,

		/// <summary>
		/// Histogram crosses the signal line.
		/// </summary>
		CloudTwist
	}

	/// <summary>
	/// Supported smoothing families.
	/// </summary>
	public enum SmoothingMethods
	{
		/// <summary>
		/// Exponential moving average.
		/// </summary>
		Exponential,

		/// <summary>
		/// Simple moving average.
		/// </summary>
		Simple,

		/// <summary>
		/// Smoothed (RMA) moving average.
		/// </summary>
		Smoothed,

		/// <summary>
		/// Weighted moving average.
		/// </summary>
		Weighted
	}

	/// <summary>
	/// Applied price sources identical to the MetaTrader version.
	/// </summary>
	public enum AppliedPrices
	{
		/// <summary>
		/// Close price.
		/// </summary>
		Close,

		/// <summary>
		/// Open price.
		/// </summary>
		Open,

		/// <summary>
		/// High price.
		/// </summary>
		High,

		/// <summary>
		/// Low price.
		/// </summary>
		Low,

		/// <summary>
		/// Median price (high + low) / 2.
		/// </summary>
		Median,

		/// <summary>
		/// Typical price (close + high + low) / 3.
		/// </summary>
		Typical,

		/// <summary>
		/// Weighted price (2 * close + high + low) / 4.
		/// </summary>
		Weighted,

		/// <summary>
		/// Simple price (open + close) / 2.
		/// </summary>
		Simple,

		/// <summary>
		/// Quarted price (open + high + low + close) / 4.
		/// </summary>
		Quarter,

		/// <summary>
		/// Trend-following price using candle extremes.
		/// </summary>
		TrendFollow0,

		/// <summary>
		/// Half-trend-following price.
		/// </summary>
		TrendFollow1
	}
}