GitHub で見る

マルチブレイクアウト V001k 戦略

概要

MultiBreakout V001k ストラテジーは、古典的な MT4 エキスパート アドバイザ「Multibreakout_v001k」を再現します。基準時間が終了したら買いストップ注文と売りストップ注文を積み重ねることにより、前の時間セッションからのブレイクアウトを取引します。ポジション管理は、最新の時間ごとの安値/高値を使用してストップを追跡するオプションの移動損益分岐点を含む、独自の段階的なテイクプロフィットおよび損益分岐点ロジックに従います。

取引ルール

  1. 基準時間 – 最大 4 つの取引セッションを定義できます。有効な各セッション時間が終了すると、ストラテジーは終了した時間ごとのローソク足を測定し、次の時間の注文を準備します。
  2. エントリの配置
    • 買いストップ注文は、前の時間の高値に現在のスプレッドと追加のエントリーバッファー (PipsForEntry) を加えた位置に配置されます。
    • 売りストップ注文は、前の時間の安値からエントリーバッファーを引いた位置に配置されます。
    • 双方とも同じ量の未決注文 NumberOfOrdersPerSide を出します。
  3. 利食いラダー – すべてのエントリーには、TakeProfitIncrement ポイント間隔の個別の利益目標が与えられます。市場が各レベルに達すると、この戦略は元の MT4 利食いキューを模倣するために市場で 1 つのトランシェを閉じます。
  4. ストップロス管理 – 最初のストップはエントリー価格から StopLoss ポイント離れたところに設定されます。価格が BreakEven ポイント有利に動くと、ストップは損益分岐点にジャンプします。 MovingBreakEven が有効になっており、設定された遅延が経過すると、ストップは、直近の 1 時間当たりの安値 (ロングの場合) または高値 (ショートの場合) を使用して、これらのレベルが引き続き引き締められるときに追跡します。
  5. セッション終了 – 設定されたセッション時間内の ExitMinute に、戦略はすべてのポジションを完全にクローズし、すべての未決注文を削除します。

パラメーター

パラメータ 説明
TradeVolume 各ブレイクアウト注文の出来高。
NumberOfOrdersPerSide 両方向のスタックされた未決注文の数量。
TakeProfitIncrement 連続するテイクプロフィットターゲット間の距離(ポイント単位)。
PipsForEntry セッション範囲の上下でブレイクアウトトリガーに追加ポイントが追加されました。
StopLoss エントリー価格からの最初のストップ距離。
BreakEven ストップが損益分岐点に移行する前に必要な利益 (ポイント単位)。
MovingBreakEven 移動損益分岐点トレーリング ロジックを有効にします。
MovingBreakEvenHoursToStart 基準セッション後、移動損益分岐点までの遅延 (時間単位) が遅れる場合があります。
BrokerOffsetToGmt 損益分岐点移動スケジューラによって使用されるブローカー時間と GMT の間の時間オフセット。
TradeSession1..4 4 つの独立した取引セッションを切り替えます。
SessionHour1..4 各参照セッションを定義する時間 (0 ~ 23)。
ExitMinute ポジションを清算して注文をキャンセルするためのセッション時間内の分。
CandleType 基準時間を測定するために使用されるローソクのタイプ (デフォルトは 1 時間ローソク)。

使用上の注意

  • ポイント値の計算が MT4 バージョンと一致するように、商品に有効な PriceStep があることを確認してください。
  • この戦略では、ブローカーの時間がローソク足のタイムスタンプと一致していることを前提としています。過去に異なる MT4 サーバー オフセットが使用されていた場合は、BrokerOffsetToGmt を調整します。
  • 損益分岐点の移動では、ストップを締める前に、元のエキスパートアドバイザーの動作と一致するように、直近で終了した 2 つの時間足ローソク足を評価します。
using System;
using System.Collections.Generic;

using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Multi-breakout strategy - Highest/Lowest channel breakout.
/// Buys when price breaks above the channel high, sells when below channel low.
/// Reverses position on opposite breakout.
/// </summary>
public class MultiBreakoutV001kStrategy : Strategy
{
	private readonly StrategyParam<int> _channelPeriod;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _prevClose;
	private decimal _prevHigh;
	private decimal _prevLow;
	private bool _hasPrev;

	public int ChannelPeriod { get => _channelPeriod.Value; set => _channelPeriod.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public MultiBreakoutV001kStrategy()
	{
		_channelPeriod = Param(nameof(ChannelPeriod), 20)
			.SetDisplay("Channel Period", "Lookback for breakout channel", "Indicators");

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

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

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevClose = 0m;
		_prevHigh = 0m;
		_prevLow = 0m;
		_hasPrev = false;
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		_hasPrev = false;

		var highest = new Highest { Length = ChannelPeriod };
		var lowest = new Lowest { Length = ChannelPeriod };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(highest, lowest, ProcessCandle)
			.Start();
	}

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

		var close = candle.ClosePrice;
		var mid = (high + low) / 2m;

		if (!_hasPrev)
		{
			_prevClose = close;
			_prevHigh = mid;
			_prevLow = mid;
			_hasPrev = true;
			return;
		}

		// Cross above midpoint - go long
		if (_prevClose <= _prevHigh && close > mid && Position <= 0)
		{
			if (Position < 0)
				BuyMarket();
			BuyMarket();
		}
		// Cross below midpoint - go short
		else if (_prevClose >= _prevLow && close < mid && Position >= 0)
		{
			if (Position > 0)
				SellMarket();
			SellMarket();
		}

		_prevClose = close;
		_prevHigh = mid;
		_prevLow = mid;
	}
}