GitHub で見る

ボラティリティ・ピボット戦略

概要

ボラティリティ・ピボット戦略は、元のエキスパートアドバイザーExp_VolatilityPivot.mq5のStockSharp高レベルポートです。Average True Range(ATR)のボラティリティまたは固定価格偏差を使用して価格をトレールする2つの適応ストップラインを投影することで、カスタムのVolatility Pivotインジケーターを再現します。トレンドが反転すると、インジケーターはポジションの反転を引き起こす単一バーのブレイクアウト矢印を発します。この戦略はそれらのシグナルに従う(WithTrend)か、それらに逆らって取引する(CounterTrend)かを選択でき、ブレイクアウトや平均回帰スタイルの柔軟性を提供します。

MQL実装とは異なり、このバージョンはCandleTypeによって提供された完了ローソク足のみに依存します。ATRモードは平滑化ATR(ATRのEMA)をAtrMultiplierで乗算し、価格モードは生のDeltaPriceオフセットを使用します。結果として得られるピボットラインは、エントリーとエグジットを管理する強気と弱気のトレーリングレベルを定義します。

市場データとインジケーター

  • 一次ローソク足(CandleType – すべての計算はこの時間軸で実行されます。デフォルトは元のエキスパートアドバイザーに合わせた4時間バーです。
  • ATR + EMA平滑化Atrモードでは、戦略は長さAtrPeriodAverageTrueRangeを処理し、次に長さSmoothingPeriodExponentialMovingAverageで平滑化します。
  • 価格偏差モードPriceDeviationモードでは、トレーリングオフセットは固定のDeltaPrice量で、ボラティリティ平滑化が不要な場合に確定的なストップ距離を可能にします。
  • ピボット状態追跡 – 戦略は最新の強気/弱気トレール値を保持し、トレールが価格の一方から他方に切り替わるバーにのみ「シグナル」を発し、MQLバージョンのインジケーターバッファを反映します。

トレードロジック

  1. ピボット計算 – 各完了ローソク足について、戦略はVolatility Pivotのルールに従ってトレーリングストップ価格を更新します。強気のトレールは価格が計算されたストップより上でクローズしたときアクティブです;弱気のトレールは下でクローズしたときアクティブです。
  2. シグナル検出 – 強気(弱気)のトレールが前のバーで非アクティブだった後にアクティブになったとき、新しい強気(弱気)シグナルが発せられます。SignalBarパラメーターは要求された完了バー数だけ実行を遅延させ、MQLスクリプトのSignalBar入力を複製します。
  3. 方向フィルター(TradeDirectionWithTrendに設定すると戦略は強気シグナルで買い、弱気シグナルで売ります。CounterTrendに設定すると解釈が反転されます:強気の矢印がショートを決済して新しいショートを開き、その逆も同様です。
  4. エントリー許可EnableBuyEntriesEnableSellEntriesが新しいロングまたはショートポジションを開けるかどうかを制御します。
  5. エグジット許可AllowLongExitsAllowShortExitsが直接シグナルまたはアクティブのままの反対のトレールによって既存ポジションを決済できるかどうかを制御します。
  6. ポジション調整 – 戦略はロングに+Volume、ショートに-Volume、フラット時に0のネットポジションを目標とします。注文は新しい方向を確立する前に反対のエクスポージャーを決済するよう自動的にサイズが決められます。
  7. 保護ストップ – オプションのStopLossおよびTakeProfit距離(絶対価格単位で表現)は各完了ローソク足を監視します。バーの高値/安値がそれらのレベルを突破すると、戦略はすぐにポジションを終了します。

パラメーター

パラメーター 説明 デフォルト
CandleType インジケーター処理と実行に使用されるローソク足シリーズ。 4時間ローソク足
AtrPeriod ATRコンポーネントの長さ。 100
SmoothingPeriod ATR値に適用されるEMA平滑化長さ。 10
AtrMultiplier 平滑化されたATRに適用される乗数。 3.0
DeltaPrice PivotMode = PriceDeviationの場合に使用される固定価格オフセット。 0.002
PivotMode ATRベースまたは固定偏差ピボットを選択します。 Atr
TradeDirection ピボットブレイクアウトに従う(WithTrend)かフェードアウト(CounterTrend)するかを選択します。 WithTrend
SignalBar シグナルに対して行動する前に待つ完了バー数。 1
EnableBuyEntries 新しいロングポジションの開設を許可します。 true
EnableSellEntries 新しいショートポジションの開設を許可します。 true
AllowLongExits 弱気状態が続くときに既存のロングポジションの決済を許可します。 true
AllowShortExits 強気状態が続くときに既存のショートポジションの決済を許可します。 true
StopLoss オプションのストップロス距離(絶対価格単位)。無効にするには0に設定します。 0
TakeProfit オプションのテイクプロフィット距離(絶対価格単位)。無効にするには0に設定します。 0

注: StockSharpのStrategy.Volumeプロパティがポジションサイズを定義します。銘柄のコントラクトまたは株式サイズに合わせて戦略を開始する前に設定します。

使用ガイドライン

  1. 希望するSecurityPortfolioに戦略をアタッチし、意図するロットサイズにVolumeを設定します。
  2. データソースが選択したCandleTypeを提供できることを確認します。完了ローソク足の継続的なフィードなしに、ATR平滑化とシグナル遅延ロジックは形成できません。
  3. 市場動向に基づいてPivotModeを選択します:ATRモードはボラティリティに適応し、価格偏差モードはトレールを固定に保ちます。
  4. 元のエキスパートアドバイザーの正確なタイミングを再現するためにSignalBarを調整します(デフォルトで1バーのラグ)。0に設定すると最新の完了バーで実行されます。
  5. StopLoss/TakeProfitを使用する場合、銘柄のボラティリティに距離を調整します(絶対価格であり、ポイントやパーセントではありません)。
  6. ピボットの変化によって引き起こされたエントリー、エグジット、保護ストップに関する情報メッセージのログを監視します。

元のエキスパートアドバイザーとの違い

  • アカウント残高/空き証拠金に基づくマネー管理オプションは削除されました。ポジションサイズはStrategy.Volumeのみで制御されます。
  • StockSharpは完了ローソク足に成行注文を使用するため、注文価格の「偏差」とMQL補助ライブラリの手動時間同期は不要です。
  • MQLスクリプトに存在する通知機能、グローバル変数、手動履歴ロードは省略されています。
  • 保護ストップとテイクプロフィットの処理はローソク足ベースのチェックに簡素化されており、バー内注文配置はありません。

推奨される機能拡張

  • 低流動性時間帯のトレーディングを一時停止するために、日次セッションフィルターやボラティリティフィルターを追加します。
  • ピボットラインを反映するトレーリングストップ管理で戦略を拡張するか、視覚化のために計算されたラインをチャートにエクスポートします。
  • 複数の銘柄が同じ戦略インスタンスを使用する場合は、ポートフォリオレベルのリスク管理を組み込みます。
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>
/// Volatility pivot strategy using ATR-based trailing stop.
/// Follows trend by flipping long/short when price crosses the ATR-based pivot line.
/// </summary>
public class VolatilityPivotStrategy : Strategy
{
	private readonly StrategyParam<int> _atrPeriod;
	private readonly StrategyParam<decimal> _atrMultiplier;
	private readonly StrategyParam<int> _emaPeriod;

	private AverageTrueRange _atr;
	private ExponentialMovingAverage _ema;

	private decimal _pivotStop;
	private decimal _prevClose;
	private bool _isLong;
	private bool _initialized;
	private int _cooldown;

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

	/// <summary>
	/// Multiplier applied to ATR for pivot distance.
	/// </summary>
	public decimal AtrMultiplier
	{
		get => _atrMultiplier.Value;
		set => _atrMultiplier.Value = value;
	}

	/// <summary>
	/// EMA period for trend confirmation.
	/// </summary>
	public int EmaPeriod
	{
		get => _emaPeriod.Value;
		set => _emaPeriod.Value = value;
	}

	/// <summary>
	/// Initializes strategy parameters.
	/// </summary>
	public VolatilityPivotStrategy()
	{
		_atrPeriod = Param(nameof(AtrPeriod), 14)
			.SetGreaterThanZero()
			.SetDisplay("ATR Period", "ATR calculation period", "Indicator");

		_atrMultiplier = Param(nameof(AtrMultiplier), 5m)
			.SetGreaterThanZero()
			.SetDisplay("ATR Multiplier", "Multiplier for pivot distance", "Indicator");

		_emaPeriod = Param(nameof(EmaPeriod), 100)
			.SetGreaterThanZero()
			.SetDisplay("EMA Period", "EMA trend filter period", "Indicator");
	}

	/// <inheritdoc />
	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		yield return (Security, TimeSpan.FromMinutes(5).TimeFrame());
	}

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

		_atr = null;
		_ema = null;
		_pivotStop = 0;
		_prevClose = 0;
		_isLong = true;
		_initialized = false;
		_cooldown = 0;
	}

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

		_atr = new AverageTrueRange { Length = AtrPeriod };
		_ema = new ExponentialMovingAverage { Length = EmaPeriod };

		var subscription = SubscribeCandles(TimeSpan.FromMinutes(5).TimeFrame());
		subscription.Bind(_atr, _ema, ProcessCandle);
		subscription.Start();
	}

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

		if (!_atr.IsFormed || !_ema.IsFormed)
		{
			_prevClose = candle.ClosePrice;
			return;
		}

		if (_cooldown > 0)
		{
			_cooldown--;
			_prevClose = candle.ClosePrice;
			return;
		}

		var close = candle.ClosePrice;
		var delta = atrValue * AtrMultiplier;

		if (!_initialized)
		{
			_pivotStop = close > emaValue ? close - delta : close + delta;
			_isLong = close > emaValue;
			_initialized = true;
			_prevClose = close;
			return;
		}

		// Update pivot stop
		if (_isLong)
		{
			var newStop = close - delta;
			if (newStop > _pivotStop)
				_pivotStop = newStop;

			// Check for reversal
			if (close < _pivotStop)
			{
				_isLong = false;
				_pivotStop = close + delta;

				if (Position > 0)
					SellMarket();

				SellMarket();
				_cooldown = 60;
			}
		}
		else
		{
			var newStop = close + delta;
			if (newStop < _pivotStop)
				_pivotStop = newStop;

			// Check for reversal
			if (close > _pivotStop)
			{
				_isLong = true;
				_pivotStop = close - delta;

				if (Position < 0)
					BuyMarket();

				BuyMarket();
				_cooldown = 60;
			}
		}

		_prevClose = close;
	}
}