GitHub で見る

Expert610 ブレイクアウト戦略

概要

Expert610 ブレイクアウト戦略は、MetaTrader 4 エキスパート アドバイザー Expert610.mq4 の C# ポートです。オリジナルのロボットは待機します。 幅の広いキャンドルを設定し、前のバーの周りに買いストップ注文と売りストップ注文の両方をパークします。ポジションサイズは次から導出されます。 トレーダーがリスクを冒すことをいとわない自由資本の割合、ストップロス/テイクプロフィットの距離はpipsで表されます。これ StockSharp バージョンは、高レベルの API を使用してその動作を反映し、すべてのチューニング ノブをストラテジ パラメーターとして公開します。

取引ロジック

  1. データ収集
    • このストラテジーは、構成可能なローソク足タイプをサブスクライブし、最新の完成したバーを保存します。
    • オーダーブックの更新は、現在のビッド/アスクスプレッドを推定するために監視されます。利用可能な深度がない場合、スプレッドの寄与 デフォルトはゼロで、ライブスプレッドのないブローカーで元の EA の動作を再現します。
  2. ボラティリティフィルター
    • 前回のローソク足の高値から現在の終値を引いた値と、現在の終値から前の安値を引いた値が両方とも超えている必要があります ThresholdPips (絶対価格単位に変換)。
    • 現在のローソク足の始値は、買いのセットアップを可能にするためには前の高値を厳密に下回る必要があり、購入のセットアップを可能にするためには前の安値を厳密に上回る必要があります。 販売設定を許可します。両方の条件が満たされる場合、アルゴリズムは対称未決注文をステージングします。
  3. 注文の発注
    • 買いストップは previous high + BreakoutOffset + spread に配置され、売値が使用される MT4 コードと一致します。
    • 売りストップは previous low - BreakoutOffset に配置され、これも無視する元のスクリプトに忠実です。 入札側で広がります。
    • 一度にアクティブにできる未決注文のペアは 1 つだけです。注文がすでに機能している場合、新しいシグナルはスキップされます。
  4. リスク管理
    • ロットサイズは、フリーキャピタル(Portfolio.CurrentValue - Portfolio.BlockedValue)に次の値を乗算して算出されます。 RiskPercent / 100。金額は RoundingDigits に四捨五入され、MT4 と同じヒューリスティックを使用してロットに変換されます コード: lot = risk / stopPips * 0.1、0.1 ロットの 1 ピップがアカウント通貨の 1 単位に等しいと想定します。
    • 計算されたロットは、会場に送信される前に、為替制限と MinimumVolume パラメーターに合わせて調整されます。
    • StartProtection は、結果として得られるすべてのポジションに価格ベースのストップとターゲットを付加するため、約定はすぐに StopLossPips および TakeProfitPips オフセットを構成しました。

パラメーター

名前 説明 デフォルト 注意事項
RoundingDigits リスクとボリュームの計算を四捨五入するときに使用される小数点以下の桁数。 2 負ではない必要があります。
RiskPercent 各エントリーでリスクが生じる自由資本の割合。 1 動的サイジングを無効にし、MinimumVolume にフォールバックするには、0 に設定します。
MinimumVolume 未決注文量の厳密な下限。 0.1 セキュリティの MinVolumeVolumeStep も尊重されます。
ThresholdPips 最後の終値から前のローソク足の極値までの最小距離。 5 ピップ単位で測定され、検出されたピップ サイズで変換されます。
BreakoutOffsetPips 注文をステージングするときに、以前の高値/安値を超えてバッファが追加されました。 2 両側に対称的に適用されます。
StopLossPips 約定した注文に付加されるストップロス距離。 5 ピップで表現され、StartProtection に送信されます。
TakeProfitPips 約定注文に付随するテイクプロフィットディスタンス。 10 pips で表現されます。ターゲットを無効にするには、0 に設定します。
CandleType ブレイクアウトを評価するために使用されるローソク足シリーズ。 1 hour 時間枠 StockSharp でサポートされているあらゆる DataType を受け入れます。

実装メモ

  • ピップサイズは、商品の PriceStepDecimals から導出されます (5 桁と 3 桁の外国為替シンボルは ×10 を受け取ります) 調整) を使用して、変換を MQL4 式と同一に保ちます。
  • 注文サイズの四捨五入は VolumeStep を尊重し、MinVolume/MaxVolume に固定し、最後に戦略レベルを適用します MinimumVolume により、結果として得られるリクエストは常に取引可能になります。
  • スプレッド補償は、購読されたオーダーブックから抽出された最良の買値/売値を使用します。これにより、 プラットフォームがライブ スプレッドを提供する場合は MT4 を実装し、それ以外の場合は正常に機能を低下させます。
  • 保留中の注文は、StockSharp が注文を約定、キャンセル、または失敗として報告すると内部状態からクリアされ、 次の適格なローソク足で新しい注文を送信するロジック。

MQL バージョンとの違い

  • 元の EA は、Digits2Round を使用してリスクとボリュームの両方を四捨五入しました。ポートはその機能を維持しますが、さらに 結果は取引所固有のボリュームステップになります。
  • 未決注文に保護価格を直接付ける代わりに、StockSharp 戦略は StartProtection に依存しているため、 すべての約定ポジションは自動的にストップロス注文とテイクプロフィット注文を受け取ります。
  • ポートフォリオ情報は、MT4 関数 AccountBalance() および AccountMargin() を置き換えて、自由資本を取得します。このデータであれば 使用できない場合、戦略は正常に MinimumVolume のサイジングに戻ります。
  • すべての計算は完了したローソク足に対してのみ実行され、バー内の再描画と start() ティックベースのループの一致を防ぎます。 バーが閉まったら。
using System;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Expert610 Breakout: Previous candle high/low breakout with ATR stops.
/// </summary>
public class Expert610BreakoutStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _emaLength;
	private readonly StrategyParam<int> _atrLength;

	private decimal _prevHigh;
	private decimal _prevLow;
	private decimal _entryPrice;

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

		_emaLength = Param(nameof(EmaLength), 50)
			.SetDisplay("EMA Length", "Trend filter.", "Indicators");

		_atrLength = Param(nameof(AtrLength), 14)
			.SetDisplay("ATR Length", "ATR period.", "Indicators");
	}

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

	public int EmaLength
	{
		get => _emaLength.Value;
		set => _emaLength.Value = value;
	}

	public int AtrLength
	{
		get => _atrLength.Value;
		set => _atrLength.Value = value;
	}

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

		_prevHigh = 0;
		_prevLow = 0;
		_entryPrice = 0;
	}

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

		_prevHigh = 0;
		_prevLow = 0;
		_entryPrice = 0;

		var ema = new ExponentialMovingAverage { Length = EmaLength };
		var atr = new AverageTrueRange { Length = AtrLength };

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

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

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

		var close = candle.ClosePrice;

		if (_prevHigh == 0 || _prevLow == 0 || atrVal <= 0)
		{
			_prevHigh = candle.HighPrice;
			_prevLow = candle.LowPrice;
			return;
		}

		if (Position > 0)
		{
			if (close >= _entryPrice + atrVal * 2.5m || close <= _entryPrice - atrVal * 1.5m)
			{
				SellMarket();
				_entryPrice = 0;
			}
		}
		else if (Position < 0)
		{
			if (close <= _entryPrice - atrVal * 2.5m || close >= _entryPrice + atrVal * 1.5m)
			{
				BuyMarket();
				_entryPrice = 0;
			}
		}

		if (Position == 0)
		{
			if (close > _prevHigh && close > emaVal)
			{
				_entryPrice = close;
				BuyMarket();
			}
			else if (close < _prevLow && close < emaVal)
			{
				_entryPrice = close;
				SellMarket();
			}
		}

		_prevHigh = candle.HighPrice;
		_prevLow = candle.LowPrice;
	}
}