GitHub で見る

Blau Ergodic MDI戦略

概要

Blau Ergodic Market Directional Indicator (MDI) 戦略は、MetaTraderのエキスパートアドバイザー Exp_BlauErgodicMDI の動作を再現します。アルゴリズムは高い時間軸のローソク足ストリーム (デフォルト4H) で動作し、選択された価格入力に三重スムージングパイプラインを適用してモメンタムヒストグラムとシグナルラインを構築します。トレードの決定は、3つの設定可能なエントリーモードの1つを使用してそのヒストグラムから導き出されます:

  1. Breakdown – ヒストグラムがゼロラインを越えるときに取引します。
  2. Twist – ヒストグラムの傾きの逆転に反応します (モメンタムが方向を変える)。
  3. CloudTwist – ヒストグラム/シグナルラインのクロスオーバーで行動します。

各シグナルは、ユーザーが提供する許可フラグに応じて、オプションで反対ポジションを閉じたり、新しいトレードを開いたりできます。

インジケーターロジック

  1. 設定された移動平均タイプと PrimaryLength で選択した適用価格をスムージングし、ベースライン価格を得る。
  2. モメンタム差分 (price - baseline) / point_value を計算する。
  3. そのモメンタムを FirstSmoothingLengthSecondSmoothingLength でスムージングしてヒストグラムを構築する。
  4. ヒストグラムを SignalLength でもう一度スムージングしてシグナルラインを得る。
  5. シグナルが終値済みローソク足で確認できるよう、SignalBarShift に従って過去の値をバッファリングする。

サポートされているスムージングファミリーは EMASMASMMA/RMAWMA です。適用価格の選択はMetaTrader実装を反映します (終値、始値、高値、安値、中間値、標準値、加重値、単純値、四分の一値、トレンドフォロービリアント)。

パラメーター

名前 説明
Volume ポジションを開く際に使用する注文サイズ。
StopLossPoints インストゥルメントポイントでのストップロス距離 (0は無効)。
TakeProfitPoints インストゥルメントポイントでのテイクプロフィット距離 (0は無効)。
SlippagePoints 成行注文に適用される最大価格スリッページ (ポイント単位)。
AllowLongEntries / AllowShortEntries 各方向へのポジション開始を許可する。
AllowLongExits / AllowShortExits 反対シグナルで既存ポジションを閉じることを許可する。
Mode エントリーモード (Breakdown / Twist / CloudTwist)。
CandleType 計算に使用するローソク足の時間軸 (デフォルト4H)。
SmoothingMethods すべてのスムージングステップで使用する移動平均ファミリー。
PrimaryLength 適用価格のベーススムージング長。
FirstSmoothingLength モメンタムに適用する第1スムージング長。
SecondSmoothingLength ヒストグラムを形成する第2スムージング長。
SignalLength シグナルラインを作成するためのヒストグラムのスムージング長。
AppliedPrices インジケーター計算で使用する価格ソース。
SignalBarShift シグナル評価時に振り返る終値済みバーの数。
Phase 互換性のために予約されたパラメーター (現在の実装では使用されていない)。

シグナル条件

  • Breakdown
    • ロング: SignalBarShift のヒストグラムが正で、前のバーはそうでない。
    • ショート: SignalBarShift のヒストグラムが負で、前のバーはそうでない。
  • Twist
    • ロング: SignalBarShift のヒストグラムが下落期間後に上昇している (前 < 最新 かつ 2バー前 > 前)。
    • ショート: SignalBarShift のヒストグラムが上昇期間後に下落している (前 > 最新 かつ 2バー前 < 前)。
  • CloudTwist
    • ロング: ヒストグラムがシグナルラインを上回るクロス (最新ヒストグラム > 最新シグナル、前のヒストグラム <= 前のシグナル)。
    • ショート: ヒストグラムがシグナルラインを下回るクロス。

各シグナルは反対側のエクスポージャーをフラット化する (退場が許可されている場合) とともに、設定されたボリュームで新しいトレードを開くことができます。

リスク管理

StartProtection は指定されたストップロスとテイクプロフィット距離 (インストゥルメントのティックサイズを使ってポイントから価格単位に変換) で初期化されます。いずれかの距離がゼロの場合、それぞれの保護は省略されます。スリッページも同じティックサイズを使って価格単位に変換されます。

メモ

  • 元のMetaTraderの動作を反映するため、シグナルは完了したローソク足のみで処理されます。
  • SignalBarShift により、最新のバーでの行動を避けるためにトレード確認を遅らせることができます。
  • Phase パラメーターは完全性のために保持されていますが、サポートされているスムージング方法使用時は効果がありません。
  • すべてのコードコメントは将来のメンテナンスを簡略化するために英語で提供されています。
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
	}
}