Auf GitHub ansehen

Bullische und bärische Harami-Stochastic-Strategie

Die Bullish & Bearish Harami Stochastic Strategy ist die StockSharp-Portierung des MetaTrader Expert Advisors expert_abh_bh_stoch.mq5 aus dem Ordner MQL/310. Der ursprüngliche Experte verwendet die Candlestick-Mustererkennung für bullische Harami- und bärische Harami-Setups und erfordert eine Bestätigung des stochastischen Oszillators. Die C#-Version behält die gleiche Logik bei und verwendet das übergeordnete StockSharp API und fügt detaillierte Protokollierung und Diagrammausgabe zur einfacheren Überwachung hinzu.

Kernideen

  • Erkennen Sie bullische Harami- und bärische Harami-Kerzenmuster anhand der beiden vorherigen abgeschlossenen Kerzen.
  • Bestätigen Sie bullische Setups mit der stochastischen %D-Linie unter einem überverkauften Schwellenwert und bärische Setups mit %D über einem überkauften Schwellenwert.
  • Schließen Sie Short-Positionen, wenn die stochastische %D-Linie über die untere oder obere Ausstiegsschwelle steigt, und schließen Sie Long-Positionen, wenn %D unter diese Schwellenwerte fällt.

Parameter

Parameter Beschreibung Standard
CandleType Zeitrahmen der zur Mustererkennung verwendeten Kerzenserie. 1 Hour
StochasticKPeriod Lookback-Zeitraum für die stochastische %K-Berechnung. 47
StochasticDPeriod Glättungszeitraum für die %D-Linie. 9
StochasticSlowing Zusätzliche Glättung auf %K angewendet (MT5 „Verlangsamung“). 13
MovingAveragePeriod Anzahl der Kerzen, die zur durchschnittlichen Körpergröße zur Mustervalidierung verwendet werden. 5
OversoldLevel Stochastic %D Schwelle zur Bestätigung bullischer Signale. 30
OverboughtLevel Stochastic %D Schwelle zur Bestätigung rückläufiger Signale. 70
ExitLowerLevel Unteres stochastisches Niveau, das Ausstiege auslöst. 20
ExitUpperLevel Oberes stochastisches Niveau, das Ausstiege auslöst. 80

Handelsregeln

Langer Eintrag

  1. Bei den beiden zuletzt abgeschlossenen Kerzen wird ein bullisches Harami-Muster erkannt (eine kleine bullische Kerze, die in einem Abwärtstrend von einer längeren bärischen Kerze verschlungen wird).
  2. Die stochastische %D-Linie der Bestätigungskerze liegt bei oder unter OversoldLevel.
  3. Derzeit ist keine Long-Position offen (Position <= 0).
  4. Die Strategie kauft zum Marktpreis für den konfigurierten Volume und fügt gegebenenfalls ein Short-Engagement hinzu, um die Position umzudrehen.

Kurzer Eintrag

  1. Es wurde ein bärisches Harami-Muster erkannt (kleine bärische Kerze innerhalb einer langen zinsbullischen Kerze während eines Aufwärtstrends).
  2. Der stochastische %D-Wert liegt bei oder über OverboughtLevel.
  3. Es existiert keine Kurzzeitbelichtung (Position >= 0).
  4. Die Strategie verkauft zum Marktwert und deckt bei Bedarf zunächst alle Long-Positionen ab.

Ausgänge

  • Shorts abdecken: Wenn der stochastische %D entweder ExitLowerLevel oder ExitUpperLevel nach oben kreuzt, deckt der Algorithmus die gesamte Short-Position ab.
  • Long-Positionen schließen: Wenn der stochastische %D durch ExitUpperLevel oder ExitLowerLevel nach unten kreuzt, wird die Long-Position geschlossen.

Dateien

  • CS/BullishBearishHaramiStochasticStrategy.cs – StockSharp Umsetzung der Strategie auf hoher Ebene.
  • README.md – Englische Dokumentation (diese Datei).
  • README_ru.md – Russische Dokumentation.
  • README_zh.md – Chinesische Dokumentation.

Hinweis: Die Python-Version ist gemäß den Konvertierungsanweisungen nicht enthalten.

namespace StockSharp.Samples.Strategies;

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

/// <summary>
/// Harami + Stochastic strategy: Bullish/bearish harami patterns with stochastic confirmation.
/// </summary>
public class BullishBearishHaramiStochasticStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _stochPeriod;
	private readonly StrategyParam<decimal> _oversold;
	private readonly StrategyParam<decimal> _overbought;
	private readonly StrategyParam<int> _signalCooldownCandles;

	private readonly List<ICandleMessage> _candles = new();
	private decimal _prevK;
	private bool _hasPrevK;
	private int _candlesSinceTrade;

	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 int SignalCooldownCandles { get => _signalCooldownCandles.Value; set => _signalCooldownCandles.Value = value; }

	public BullishBearishHaramiStochasticStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).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");
		_signalCooldownCandles = Param(nameof(SignalCooldownCandles), 6)
			.SetGreaterThanZero()
			.SetDisplay("Signal Cooldown", "Bars to wait between trades", "Trading");
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_candles.Clear();
		_prevK = 0m;
		_hasPrevK = false;
		_candlesSinceTrade = SignalCooldownCandles;
	}

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_candles.Clear();
		_hasPrevK = false;
		_candlesSinceTrade = SignalCooldownCandles;
		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;

		if (_candlesSinceTrade < SignalCooldownCandles)
			_candlesSinceTrade++;

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

		_candles.Add(candle);
		if (_candles.Count > 5) _candles.RemoveAt(0);

		if (_candles.Count >= 2)
		{
			var curr = _candles[^1];
			var prev = _candles[^2];

			// Bullish harami: prev bearish, curr bullish, curr body inside prev body
			var bullishHarami = prev.OpenPrice > prev.ClosePrice
				&& curr.ClosePrice > curr.OpenPrice
				&& curr.OpenPrice > prev.ClosePrice
				&& curr.ClosePrice < prev.OpenPrice;

			// Bearish harami: prev bullish, curr bearish, curr body inside prev body
			var bearishHarami = prev.ClosePrice > prev.OpenPrice
				&& curr.OpenPrice > curr.ClosePrice
				&& curr.ClosePrice > prev.OpenPrice
				&& curr.OpenPrice < prev.ClosePrice;

			if (bullishHarami && kValue < Oversold && Position <= 0 && _candlesSinceTrade >= SignalCooldownCandles)
			{
				BuyMarket();
				_candlesSinceTrade = 0;
			}
			else if (bearishHarami && kValue > Overbought && Position >= 0 && _candlesSinceTrade >= SignalCooldownCandles)
			{
				SellMarket();
				_candlesSinceTrade = 0;
			}
		}

		if (_hasPrevK)
		{
			if (Position > 0 && _prevK >= Overbought && kValue < Overbought && _candlesSinceTrade >= SignalCooldownCandles)
			{
				SellMarket();
				_candlesSinceTrade = 0;
			}
			else if (Position < 0 && _prevK <= Oversold && kValue > Oversold && _candlesSinceTrade >= SignalCooldownCandles)
			{
				BuyMarket();
				_candlesSinceTrade = 0;
			}
		}

		_prevK = kValue;
		_hasPrevK = true;
	}
}