GitHub で見る

ハンマーハンギング Stochastic

この戦略は、MetaTrader のエキスパート「Expert_AH_HM_Stoch」を StockSharp の高レベルの API に移植します。ハンマーとハンギングマンのローソク足パターンと確率的オシレーターの確認を組み合わせて、延長された動きの後の反転セットアップを捉えます。

この戦略は、行動する前にローソク足が完成するのを待ち、フィルタリングに確率的シグナルラインを使用し、勢いが極端なゾーンを出たときにポジションを閉じます。

詳細

  • エントリー基準:
    • ロング: 強気のハンマーローソク足と売られ過ぎレベルを下回る確率的 %D (前のバー)。
    • ショート: 弱気のハンギングマンローソク足と買われ過ぎレベルを上回る確率的 %D (前のバー)。
  • 長い/短い: 両方。
  • 終了基準: 確率的 %D が設定可能な回復レベルおよび極端なレベルを上下に交差したときにポジションを閉じます。
  • ストップ: 組み込みの StartProtection() フックを通じて有効になります (デフォルトはアカウント レベルの保護)。
  • デフォルト値:
    • CandleType = TimeSpan.FromHours(1)
    • StochPeriodK = 15
    • StochPeriodD = 49
    • StochPeriodSlow = 25
    • OversoldLevel = 30
    • OverboughtLevel = 70
    • ExitLowerLevel = 20
    • ExitUpperLevel = 80
    • MaxBodyRatio = 0.35
    • LowerShadowMultiplier = 2.5
    • UpperShadowMultiplier = 0.3
  • フィルター:
    • カテゴリ:パターン+オシレーター確認
    • 方向: 両方
    • インジケーター: ローソク足、Stochastic
    • 停止: StartProtection によるオプションのリスク管理
    • 複雑さ: 中級
    • 時間枠: スイング / 日中 (デフォルトは 1 時間)
    • 季節性: いいえ
    • ニューラルネットワーク: いいえ
    • 発散: いいえ
    • リスクレベル: 中程度

仕組み

  1. 高レベルの BindEx API を使用して、設定されたローソク足シリーズと確率オシレーターをサブスクライブします。
  2. 実体と影の比率に基づいてハンマーとハンギングマンのフォーメーションを検出します。
  3. 以前の閉じたバーの値を使用して、確率的 %D ラインでエントリーを確認します。
  4. 元の MQL エキスパートのロジックを反映して、ストキャスティクスが売られすぎ/買われすぎゾーンから抜け出すときの出口を管理します。
  5. チャート領域が使用可能な場合、ローソク足、ストキャスティクス、および独自の取引のチャート視覚化を提供します。
namespace StockSharp.Samples.Strategies;

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

/// <summary>
/// Hammer/Hanging Man + Stochastic strategy.
/// Buys on hammer in oversold, sells on hanging man in overbought.
/// </summary>
public class HammerHangingStochasticStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _stochPeriod;
	private readonly StrategyParam<decimal> _oversold;
	private readonly StrategyParam<decimal> _overbought;

	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
	public int StochPeriod { get => _stochPeriod.Value; set => _stochPeriod.Value = value; }
	public decimal Oversold { get => _oversold.Value; set => _oversold.Value = value; }
	public decimal Overbought { get => _overbought.Value; set => _overbought.Value = value; }

	public HammerHangingStochasticStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
			.SetDisplay("Candle Type", "Candle timeframe", "General");
		_stochPeriod = Param(nameof(StochPeriod), 14)
			.SetGreaterThanZero()
			.SetDisplay("Stoch Period", "Stochastic K period", "Indicators");
		_oversold = Param(nameof(Oversold), 30m)
			.SetDisplay("Oversold", "Stochastic oversold level", "Signals");
		_overbought = Param(nameof(Overbought), 70m)
			.SetDisplay("Overbought", "Stochastic overbought level", "Signals");
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		var stoch = new StochasticOscillator { K = { Length = StochPeriod }, D = { Length = 3 } };
		var subscription = SubscribeCandles(CandleType);
		subscription.BindEx(stoch, ProcessCandle).Start();
	}

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

		var stochTyped = stochValue as StochasticOscillatorValue;
		if (stochTyped?.K is not decimal kValue) return;

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

		var upperShadow = candle.HighPrice - Math.Max(candle.OpenPrice, candle.ClosePrice);
		var lowerShadow = Math.Min(candle.OpenPrice, candle.ClosePrice) - candle.LowPrice;

		// Hammer: small body at top, long lower shadow
		var isHammer = lowerShadow > body * 2 && upperShadow < body;

		// Hanging Man: small body at bottom, long upper shadow
		var isHangingMan = upperShadow > body * 2 && lowerShadow < body;

		if (isHammer && kValue < Oversold && Position <= 0)
			BuyMarket();
		else if (isHangingMan && kValue > Overbought && Position >= 0)
			SellMarket();
	}
}