GitHub で見る

ピプソナイトブレイクアウト戦略

概要

Pipso は、MetaTrader エキスパート アドバイザー Pipso.mq4 から変換されたナイトセッション ブレークアウト システムです。戦略は次のことを測定します 以前に完成したローソク足の最高値と最低価格を表示し、市場がその範囲を外れると反応します。毎 ブレイクアウトはポジションを逆転させます。価格が最近の高値を上回るとロングポジションがクローズされ、ショートポジションがオープンされます。 ショートポジションはカバーされ、価格が最近の安値を突き抜けたときに新しいロングが確立されます。保護停止は以下から派生します。 ストップ距離が現在のボラティリティに自動的に適応するようにレンジの幅を設定します。

仕組み

  1. 設定された時間枠 (デフォルトでは 15 分) をサブスクライブし、インジケーターが完全な履歴を構築するまで待ちます。
  2. 新しい完了したローソク足ごとに、以前の BreakoutPeriod ローソク足の最高値と最低値を計算します。現在の 元の EA とまったく同様に、ローソク足はその範囲の一部ではありません。iHighest(..., shift = 1) は作業バーをスキップします。
  3. で定義された最小距離を適用しながら、停止距離を (high - low) * StopLossMultiplier として再計算します。 MinStopDistance
  4. SessionStartHourSessionLengthHours によって定義された取引ウィンドウを維持します。金曜の窓が真夜中を越えるとき MetaTrader と同様にオープンな取引が週末まで存続できるように、2 日間延長されます。
  5. ローソク足の高値が保存されているブレイクアウト高値を超えると、次のようになります。
    • 既存のロングポジションをすべてクローズし、取引が許可されている場合は、サイズ OrderVolume のショートポジションをオープンします。
    • 計算されたストップ距離を使用して、エントリー価格の上にストップロスを設定します。
  6. ローソク足の安値が保存されているブレイクアウト安値を下回った場合:
    • 既存のショート ポジションをすべてクローズし、取引が許可されている場合は、サイズ OrderVolume のロング ポジションをオープンします。
    • 計算されたストップ距離を使用して、エントリー価格の下にストップロスを設定します。
  7. 保護ストップは完成したキャンドルごとに評価されます。安値がロングストップに到達するか、高値がショートストップに到達すると、 ポジションはすぐにフラットになります。

取引セッションのロジック

  • SessionStartHour は交換時間で表されます。ウィンドウの長さは SessionLengthHours で設定されます。
  • セッションが 24 時間を超えて、現在の日が金曜日である場合、ウィンドウの終了は 48 時間繰り上げられます。 その取引は月曜日に再開され、MQL4 コードの週末の処理と一致します。
  • 取引ウィンドウの外では、この戦略は既存のポジションを決済するだけです。ウィンドウが開くと、新しい取引が再び許可されます。

パラメーター

名前 説明 デフォルト
CandleType 信号計算に使用されるキャンドルのデータ型。 15分の時間枠
OrderVolume すべての成行注文の固定注文サイズ。 1
SessionStartHour ブレークアウトウィンドウが始まる時刻。 21
SessionLengthHours 取引ウィンドウの期間 (時間単位)。 9
BreakoutPeriod ブレイクアウト範囲を定義する完了したローソク足の数。 36
StopLossMultiplier 停止距離を導出するために範囲幅に適用される乗数 (値 3 は元の SLpp = 300 に対応します)。 3
MinStopDistance 絶対価格単位での最小ストップロス距離。MetaTrader ストップレベル制限をエミュレートします。 0

注意事項

  • この戦略では成行注文のみを使用します。利食いはありません。保護的なストップロスは、それ以外の唯一の出口メカニズムです。 逆のブレイクアウトシグナル。
  • ロングからショートに切り替えるとき (またはその逆)、戦略は両方とも前の注文を閉じる単一の成行注文を送信します。 位置を決めて新しいものを開き、OrderClose を連続して呼び出したソース EA の動作をミラーリングし、 OrderSend
  • ブレイクアウト高値と安値の指標線は、実行された取引とともに戦略チャート上に自動的にプロットされます。
using System;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Range breakout strategy that uses Highest/Lowest channel.
/// Enters on breakouts above/below the channel and exits on reversion.
/// </summary>
public class PipsoNightBreakoutStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _breakoutPeriod;

	private decimal _entryPrice;
	private decimal _prevHighest;
	private decimal _prevLowest;
	private bool _hasPrev;

	public PipsoNightBreakoutStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe for analysis.", "General");

		_breakoutPeriod = Param(nameof(BreakoutPeriod), 36)
			.SetDisplay("Breakout Period", "Period for Highest/Lowest channel.", "Indicators");
	}

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

	public int BreakoutPeriod
	{
		get => _breakoutPeriod.Value;
		set => _breakoutPeriod.Value = value;
	}

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

		_entryPrice = 0;
		_prevHighest = 0;
		_prevLowest = 0;
		_hasPrev = false;
	}

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

		_entryPrice = 0;
		_prevHighest = 0;
		_prevLowest = 0;
		_hasPrev = false;

		var highest = new Highest { Length = BreakoutPeriod };
		var lowest = new Lowest { Length = BreakoutPeriod };
		var ema = new ExponentialMovingAverage { Length = BreakoutPeriod };

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

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

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

		var close = candle.ClosePrice;
		var mid = (highestValue + lowestValue) / 2m;

		// Exit conditions
		if (Position > 0)
		{
			// Exit when price reverts to middle or stop-loss
			if (close < mid || (_entryPrice > 0 && close < _entryPrice * 0.98m))
			{
				SellMarket();
			}
		}
		else if (Position < 0)
		{
			if (close > mid || (_entryPrice > 0 && close > _entryPrice * 1.02m))
			{
				BuyMarket();
			}
		}

		// Entry conditions: breakout above previous highest or below previous lowest
		if (Position == 0 && _hasPrev)
		{
			if (close > _prevHighest && close > emaValue)
			{
				_entryPrice = close;
				BuyMarket();
			}
			else if (close < _prevLowest && close < emaValue)
			{
				_entryPrice = close;
				SellMarket();
			}
		}

		_prevHighest = highestValue;
		_prevLowest = lowestValue;
		_hasPrev = true;
	}
}