GitHub で見る

Three Timeframes戦略

概要

Three Timeframes戦略は、StockSharpの高レベルAPIを使用してMetaTraderエキスパート Three timeframes.mq5 を複製します。システムは異なる時間軸から取得したモメンタムとトレンドフィルターを組み合わせます:

  • MACD (M5) がトレード時間軸での最近のモメンタム反転を検出します。
  • Alligator (H4) が上位時間軸の構造が意図したトレード方向と一致していることを確認します。
  • RSI (H1) が中間時間軸のモメンタムがブレイクアウトをサポートしていることを確認します。
  • オプションのセッションフィルタリングが設定された営業時間外のトレードをブロックします。

戦略はpipsベースのリスク管理を使用します。初期のストップロスとテイクプロフィットのレベルが各新しいポジションに付加されます。価格が前進すると、オプションのトレーリングストップが市場がトレーリング距離とトレーリングステップの両方をカバーした後に保護ストップを締め付けます。

シグナルロジック

  1. 価格は3つの異なるサブスクリプションで処理されます:トレードローソク足、Alligator用の高位時間軸ローソク足、RSI用の中間ローソク足。
  2. ロングセットアップには以下が必要です:
    • MACDメインラインが前のバーでシグナルラインを下方クロスし、その前のバーはシグナルラインの上にあった。MetaTraderの「青が赤を下方にクロス」ルールを再現。
    • H1フィードのRSIが50より上。
    • 前の完成したH4ローソク足でAlligator jaw > teeth > lips、上昇構造を示す。
  3. ショートセットアップはルールを反映します:MACDメインラインがシグナルラインを上方クロス、RSIが50未満、Alligatorで lips > teeth > jaw が下降構造を確認。
  4. 反対ポジションが存在する場合、戦略はEAオリジナルが新しいトレードを開く前と同様に、ネットサイズの成行注文を送信してクローズします。
  5. エントリー後、戦略は初期ストップロス/テイクプロフィット距離を適用し、価格がエントリーから TrailingStopPips + TrailingStepPips 移動するとストップのトレーリングを続けます。

トレードセッションフィルターはMetaTraderの実装を反映します。開始時間が終了時間より小さい場合、取引はその間隔内でのみ許可されます。開始時間が終了時間より大きい場合、アクティブウィンドウは深夜をまたぎます。

リスク管理

  • ストップロス / テイクプロフィット – 距離はpipsで表されます。戦略はシンボルの価格ステップを使用して価格単位に変換し、3桁または5桁のFX相場に調整します。
  • トレーリングストップ – トレードがトレーリングストップとトレーリングステップ距離の両方をカバーするとアクティブになります。ストップはロングでは price - trailing distance、ショートでは price + trailing distance に移動されます。
  • トレードボリューム – 新しい成行注文のベースロットサイズを指定します。反転前に反対のエクスポージャーが自動的に平らにされます。

MetaTraderバージョンとの違い

  • StockSharpの非同期注文モデルにより、明示的なトランザクション追跡フラグ(m_waiting_transaction)が不要になります。注文は内部で確認を待つ BuyMarket/SellMarket を使用して実行されます。
  • MQLバージョンのスリッページ、フィリングポリシー、マージンモード設定はStockSharpによって抽象化されています。これらのプラットフォーム固有のコントロールは.NET実装には不要です。
  • Alligatorインジケーターは元の期間とシフトを保持しながら平滑化移動平均から再構築されます。インジケーター値はMetaTraderの組み込みAlligatorのオフセット動作を再現するためにスライディングバッファに保存されます。

パラメーター

名前 説明 デフォルト
TradeVolume ロット/コントラクト単位の成行注文サイズ。 1
StopLossPips pipsでの初期ストップロス距離。 50
TakeProfitPips pipsでの初期テイクプロフィット距離。 140
TrailingStopPips pipsでのトレーリングストップ距離。 5
TrailingStepPips トレーリングストップを移動する前に必要な追加pip移動。 5
MacdFastPeriod MACDの速いEMAの長さ。 13
MacdSlowPeriod MACDの遅いEMAの長さ。 26
MacdSignalPeriod MACDのシグナル平滑化期間。 10
JawPeriod, TeethPeriod, LipsPeriod jaw/teeth/lipsのAlligator SMMAの期間。 13, 8, 5
JawShift, TeethShift, LipsShift Alligatorラインの前方シフト。 8, 5, 3
RsiPeriod 中間時間軸でのRSI平均長。 14
CandleType トレード時間軸(デフォルト5分足)。 M5
AlligatorCandleType Alligator計算の高位時間軸(デフォルト4時間足)。 H4
RsiCandleType RSI確認の中間時間軸(デフォルト1時間足)。 H1
UseTimeFilter セッションフィルターを有効にします。 true
StartHour セッション開始時間(含む)。 10
EndHour セッション終了時間(含まない)。 15

使用上のノート

  • 選択したインストゥルメントが設定された3つのローソク足ストリーム(デフォルトM5、H1、H4)を提供することを確認してください。StockSharpは GetWorkingSecurities() を通じて必要なすべてのサブスクリプションを自動的に要求します。
  • pip変換は Security.PriceStep に依存します。異常なティックサイズを持つインストゥルメントはストップ/テイクパラメーターの手動調整が必要な場合があります。
  • トレーリングストップには TrailingStopPipsTrailingStepPips の両方がゼロより大きい必要があります。いずれかのパラメーターをゼロに設定すると、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;

public class ThreeTimeframesStrategy : Strategy
{
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;
	private readonly StrategyParam<int> _stopLossPoints;
	private readonly StrategyParam<int> _takeProfitPoints;

	private ExponentialMovingAverage _fast;
	private ExponentialMovingAverage _slow;

	private decimal _prevFast;
	private decimal _prevSlow;
	private decimal _entryPrice;
	private int _cooldown;

	public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
	public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
	public int StopLossPoints { get => _stopLossPoints.Value; set => _stopLossPoints.Value = value; }
	public int TakeProfitPoints { get => _takeProfitPoints.Value; set => _takeProfitPoints.Value = value; }

	public ThreeTimeframesStrategy()
	{
		_fastPeriod = Param(nameof(FastPeriod), 14).SetGreaterThanZero().SetDisplay("Fast Period", "Fast EMA period", "Indicator");
		_slowPeriod = Param(nameof(SlowPeriod), 50).SetGreaterThanZero().SetDisplay("Slow Period", "Slow EMA period", "Indicator");
		_stopLossPoints = Param(nameof(StopLossPoints), 200).SetNotNegative().SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk");
		_takeProfitPoints = Param(nameof(TakeProfitPoints), 400).SetNotNegative().SetDisplay("Take Profit", "Take-profit in price steps", "Risk");
	}

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

	protected override void OnReseted()
	{
		base.OnReseted();
		_fast = null; _slow = null;
		_prevFast = 0; _prevSlow = 0; _entryPrice = 0; _cooldown = 0;
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_fast = new ExponentialMovingAverage { Length = FastPeriod };
		_slow = new ExponentialMovingAverage { Length = SlowPeriod };
		var subscription = SubscribeCandles(TimeSpan.FromMinutes(5).TimeFrame());
		subscription.Bind(_fast, _slow, ProcessCandle);
		subscription.Start();
	}

	private void ProcessCandle(ICandleMessage candle, decimal fastValue, decimal slowValue)
	{
		if (candle.State != CandleStates.Finished) return;
		if (!_fast.IsFormed || !_slow.IsFormed) { _prevFast = fastValue; _prevSlow = slowValue; return; }
		if (_cooldown > 0) { _cooldown--; _prevFast = fastValue; _prevSlow = slowValue; return; }

		var close = candle.ClosePrice;
		var step = Security?.PriceStep ?? 1m;

		if (Position > 0 && _entryPrice > 0)
		{
			if (StopLossPoints > 0 && close <= _entryPrice - StopLossPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
			if (TakeProfitPoints > 0 && close >= _entryPrice + TakeProfitPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
		}
		else if (Position < 0 && _entryPrice > 0)
		{
			if (StopLossPoints > 0 && close >= _entryPrice + StopLossPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
			if (TakeProfitPoints > 0 && close <= _entryPrice - TakeProfitPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
		}

		if (_prevFast <= _prevSlow && fastValue > slowValue && Position <= 0)
		{ if (Position < 0) BuyMarket(); BuyMarket(); _entryPrice = close; _cooldown = 100; }
		else if (_prevFast >= _prevSlow && fastValue < slowValue && Position >= 0)
		{ if (Position > 0) SellMarket(); SellMarket(); _entryPrice = close; _cooldown = 100; }

		_prevFast = fastValue; _prevSlow = slowValue;
	}
}