GitHub で見る

ローソク足パターンのテスト戦略

概要

Candle Patterns Test Strategy は、元の MetaTrader 5 エキスパート アドバイザー CandlePatternsTest EA の StockSharp の高レベルの変換です。この戦略は、完了したローソク足をスキャンして古典的な日本のローソク足形成の厳選されたリストを取得し、強気または弱気の構造が現れたときにロングまたはショートのポジションを入力することで反応します。この変換は、StockSharp リスク制御とデータ サブスクリプション API を活用しながら、ソース ロボットの任意のパターン ロジックに焦点を当てています。

取引ロジック

  1. ローソク足サブスクリプション – この戦略は、設定されたローソク足タイプをサブスクライブし、終了したバーを待ってからパターン認識を実行します。
  2. 平均実体フィルター – ローソク足の実体の単純な移動平均が動的正規化として機能します。構成要素のローソク足がこの平均を超えるパターンのみが有効とみなされ、MQL 実装の AvgBody 関数が反映されます。
  3. パターン認識 – 検出器は以下をチェックします。
    • 3 人の白い兵士 / 3 人の黒いカラス
    • ピアスライン / 暗雲覆い
    • 朝童子星・夕童子星
    • 強気と弱気の巻き込み
    • 強気ハラミと弱気ハラミ
    • 会議の列
  4. エントリー管理 – 強気パターンが確認されると、戦略により成行買い注文が開始されます。弱気パターンは市場の売り注文をトリガーします。反対の信号により、現在位置が自動的に逆転します。
  5. 出口管理 – 保護的なストップロスとテイクプロフィットのレベルは平均的なキャンドル本体から導出され、完成した各キャンドルで追跡されます。価格がいずれかのしきい値に達すると、ポジションはクローズされます。

パラメーター

パラメータ 説明
CandleType サブスクライブするローソク足のデータ タイプ (デフォルト: 1 時間の時間枠)。
AverageBodyPeriod 平均体の長さに使用されるキャンドルの数。パターンの正規化を制御します。
EnableBullishPatterns 長いエントリを有効または無効にします。
EnableBearishPatterns 短いエントリを有効または無効にします。
StopLossFactor ストップロス距離の平均ボディに適用される乗数。
TakeProfitFactor テイクプロフィットディスタンスの平均ボディに適用される乗数。

すべてのパラメータは、GUI 構成とオプティマイザの実行をサポートするために、StrategyParam<T> を通じて公開されます。

グラフ化

チャート領域が使用可能な場合、戦略は次のようにプロットします。

  • 購読したキャンドル
  • トレンドのコンテキストに使用される終値移動平均
  • 視覚的な検証のために取引を実行

オリジナルの EA との違い

  • 元の MQ5 ファイルに存在するニュース フィルター、タイム ウィンドウ、ヘッジ トグル、およびトレーリング グリッド管理は、ローソク足パターンの核心に焦点を当てるために意図的に省略されています。
  • リスク管理は、ローソク足のボラティリティから派生した対称的なストップ/ターゲット モデルに簡素化されています。
  • StockSharp バージョンでは、手動注文チケットの代わりにフレームワークのポジション管理と BuyMarket/SellMarket ヘルパーを使用します。

使用上の注意

  • 分析したい市場セッションに合わせて CandleType パラメータを設定します。タイムフレームが長くなると、生成される信号は少なくなりますが、より強力になります。
  • 平均実体が最近のボラティリティに近づくように AverageBodyPeriod を調整します。値を小さくすると反応が速くなりますが、ノイズが増加する可能性があります。
  • StopLossFactorTakeProfitFactor は、商品のリスク プロファイルに合わせて最適化できます。

要件

  • 構成されたローソク タイプを生成できる市場データ フィードを備えた StockSharp 環境。
  • この戦略では、連続した重複しないローソク足シリーズが期待されます。選択したボードが定期的なバー更新をサポートしていることを確認してください。
namespace StockSharp.Samples.Strategies;

using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;

/// <summary>
/// Candle Patterns Test strategy: Doji + trend reversal.
/// Buys on doji in downtrend (below EMA), sells on doji in uptrend (above EMA).
/// </summary>
public class CandlePatternsTestStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _emaPeriod;
	private readonly StrategyParam<int> _signalCooldownCandles;
	private int _candlesSinceTrade;

	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
	public int EmaPeriod { get => _emaPeriod.Value; set => _emaPeriod.Value = value; }
	public int SignalCooldownCandles { get => _signalCooldownCandles.Value; set => _signalCooldownCandles.Value = value; }

	public CandlePatternsTestStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
			.SetDisplay("Candle Type", "Candle timeframe", "General");
		_emaPeriod = Param(nameof(EmaPeriod), 50)
			.SetGreaterThanZero()
			.SetDisplay("EMA Period", "EMA trend filter", "Indicators");
		_signalCooldownCandles = Param(nameof(SignalCooldownCandles), 6)
			.SetGreaterThanZero()
			.SetDisplay("Signal Cooldown", "Bars to wait between trades", "Trading");
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_candlesSinceTrade = SignalCooldownCandles;
	}

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_candlesSinceTrade = SignalCooldownCandles;
		var ema = new ExponentialMovingAverage { Length = EmaPeriod };
		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(ema, ProcessCandle).Start();
	}

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

		if (_candlesSinceTrade < SignalCooldownCandles)
			_candlesSinceTrade++;

		var body = Math.Abs(candle.ClosePrice - candle.OpenPrice);
		var range = candle.HighPrice - candle.LowPrice;
		if (range <= 0) return;

		// Doji: body is very small relative to range
		var isDoji = body < range * 0.05m;

		var close = candle.ClosePrice;

		if (isDoji && close < emaValue && Position <= 0 && _candlesSinceTrade >= SignalCooldownCandles)
		{
			BuyMarket();
			_candlesSinceTrade = 0;
		}
		else if (isDoji && close > emaValue && Position >= 0 && _candlesSinceTrade >= SignalCooldownCandles)
		{
			SellMarket();
			_candlesSinceTrade = 0;
		}
	}
}