Auf GitHub ansehen

BullsBearsEyes EA-Strategie

Überblick

Diese Strategie ist ein StockSharp-Port des BullsBearsEyes EA für MetaTrader 5. Sie baut den benutzerdefinierten Indikator neu auf, indem die klassischen Bulls Power- und Bears Power-Oszillatoren mit demselben vierstufigen IIR-Smoothing aus dem Originalcode kombiniert werden. Das resultierende Verhältnis oszilliert zwischen 0 und 1 und spiegelt das Übergewicht von Verkäufern oder Käufern wider. Wenn das Verhältnis auf 0 fällt, gilt der Markt als von Bären ausgewaschen und die Strategie bereitet einen Long-Einstieg vor. Wenn das Verhältnis auf 1 steigt, gilt der Bullendruck als erschöpft und die Strategie sucht nach einem Short-Einstieg. Alle Berechnungen werden nur auf vollständig geschlossenen Kerzen durchgeführt, replicierend die MQL-Implementierung, die custom[1] bei der Geburt jeder neuen Bar auswertete.

Handelslogik

  1. Die konfigurierte Kerzenreihe abonnieren und Bulls Power- und Bears Power-Indikatoren binden.
  2. Bei jeder fertigen Kerze werden die Indikatorwerte durch dieselbe IIR-Smoothing-Kaskade (L0L3) wie der originale EA geführt.
  3. Das Verhältnis CU / (CU + CD) wird berechnet. Eine rein bärische Sequenz macht CU gleich null, während eine rein bullische Sequenz CD auf null zwingt.
  4. Die Strategie speichert das Verhältnis der vorherigen Kerze und verwendet es als handelbares Signal:
    • Vorheriges Verhältnis gleich 0 ⇒ Short-Positionen schließen und Long-Position eröffnen.
    • Vorheriges Verhältnis gleich 1 ⇒ Long-Positionen schließen und Short-Position eröffnen.
    • Zwischenwerte werden ignoriert, um dem Quellcode treu zu bleiben.
  5. Orders werden mit dem aktuellen Volume-Wert gesendet und netten automatisch die entgegengesetzte Position vor dem Öffnen einer neuen.

Risikomanagement

  • Stop Loss / Take Profit – in Pips ausgedrückt, in absolute Preise übersetzt mit Pip-Größenerkennung identisch zur MT5-Implementierung (5- und 3-stellige Instrumente werden über den Schritt-Multiplikator gehandhabt).
  • Trailing Stop / Trailing Step – identische Logik: sobald der Preis um TrailingStop + TrailingStep vorrückt, wird der Stop bewegt, um eine konstante TrailingStop-Distanz vom aktuellen Schluss beizubehalten. Long- und Short-Positionen werden symmetrisch verwaltet.
  • Schutz-Niveaus werden immer dann neu berechnet, wenn sich die Nettoposition ändert, um sicherzustellen, dass der durchschnittliche Positionspreis für weitere Berechnungen verwendet wird.
  • Die Strategie schließt die gesamte Position, wenn ein Schutzniveau innerhalb des aktuellen Kerzenbereichs verletzt wird.

Sitzungsfilter

Der optionale Zeitfilter entspricht den Expertenberater-Eingaben:

  • Use Time Control – aktiviert/deaktiviert den Filter.
  • Start Hour – inklusive Startzeit (0–23).
  • End Hour – exklusive Endzeit (0–23). Wenn die Endzeit kleiner als die Startzeit ist, erstreckt sich die Sitzung über Mitternacht. Während eingeschränkter Stunden enthält sich die Strategie vom Öffnen neuer Positionen, verwaltet aber weiterhin Stops und Trailing für bestehende Trades.

Parameter

Parameter Beschreibung Standard
Period Mittelungslänge für Bulls/Bears Power. 13
Gamma Glättungsfaktor für den vierstufigen Filter (0–1). 0.6
StopLossPips Stop-Loss-Abstand in Pips. 150
TakeProfitPips Take-Profit-Abstand in Pips. 150
TrailingStopPips Trailing-Stop-Abstand in Pips (0 deaktiviert Trailing). 25
TrailingStepPips Minimaler Vorstoß, bevor der Trailing Stop sich bewegen kann. 5
UseTimeControl Aktiviert den Handelssitzungsfilter. true
StartHour Erste Handelsstunde (inklusiv). 10
EndHour Letzte Handelsstunde (exklusiv). 16
CandleType Kerzentyp/Zeitrahmen für die Analyse. 1-Stunden-Kerzen

Zusätzliche Hinweise

  • Die High-Level-API SubscribeCandles().Bind(...) wird verwendet, um die originalen Berechnungen ohne manuelles Kerzensammeln zu replizieren.
  • Indikatorwerte werden erst nach dem Kerzenschluss verarbeitet (CandleStates.Finished).
  • Die Pip-Größenerkennung fällt auf 1 zurück, wenn der Instrumentenschritt nicht verfügbar ist, sodass die Strategie in synthetischen Testumgebungen ausgeführt werden kann.
  • Inline-Kommentare in der C#-Datei erläutern jeden logischen Abschnitt für einfachere Wartung und Vergleich mit der MQL-Quelle.
using System;
using System.Collections.Generic;

using Ecng.Common;

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

namespace StockSharp.Samples.Strategies;

public class BullsBearsEyesEaStrategy : Strategy
{
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;
	private readonly StrategyParam<int> _stopLossPoints;
	private readonly StrategyParam<int> _takeProfitPoints;

	private ExponentialMovingAverage _fast;
	private ExponentialMovingAverage _slow;

	private decimal _prevFast;
	private decimal _prevSlow;
	private decimal _entryPrice;
	private int _cooldown;

	public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
	public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
	public int StopLossPoints { get => _stopLossPoints.Value; set => _stopLossPoints.Value = value; }
	public int TakeProfitPoints { get => _takeProfitPoints.Value; set => _takeProfitPoints.Value = value; }

	public BullsBearsEyesEaStrategy()
	{
		_fastPeriod = Param(nameof(FastPeriod), 14).SetGreaterThanZero().SetDisplay("Fast Period", "Fast EMA period", "Indicator");
		_slowPeriod = Param(nameof(SlowPeriod), 50).SetGreaterThanZero().SetDisplay("Slow Period", "Slow EMA period", "Indicator");
		_stopLossPoints = Param(nameof(StopLossPoints), 200).SetNotNegative().SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk");
		_takeProfitPoints = Param(nameof(TakeProfitPoints), 400).SetNotNegative().SetDisplay("Take Profit", "Take-profit in price steps", "Risk");
	}

	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		yield return (Security, TimeSpan.FromMinutes(5).TimeFrame());
	}

	protected override void OnReseted()
	{
		base.OnReseted();
		_fast = null; _slow = null;
		_prevFast = 0; _prevSlow = 0; _entryPrice = 0; _cooldown = 0;
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_fast = new ExponentialMovingAverage { Length = FastPeriod };
		_slow = new ExponentialMovingAverage { Length = SlowPeriod };
		var subscription = SubscribeCandles(TimeSpan.FromMinutes(5).TimeFrame());
		subscription.Bind(_fast, _slow, ProcessCandle);
		subscription.Start();
	}

	private void ProcessCandle(ICandleMessage candle, decimal fastValue, decimal slowValue)
	{
		if (candle.State != CandleStates.Finished) return;
		if (!_fast.IsFormed || !_slow.IsFormed) { _prevFast = fastValue; _prevSlow = slowValue; return; }
		if (_cooldown > 0) { _cooldown--; _prevFast = fastValue; _prevSlow = slowValue; return; }

		var close = candle.ClosePrice;
		var step = Security?.PriceStep ?? 1m;

		if (Position > 0 && _entryPrice > 0)
		{
			if (StopLossPoints > 0 && close <= _entryPrice - StopLossPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
			if (TakeProfitPoints > 0 && close >= _entryPrice + TakeProfitPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
		}
		else if (Position < 0 && _entryPrice > 0)
		{
			if (StopLossPoints > 0 && close >= _entryPrice + StopLossPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
			if (TakeProfitPoints > 0 && close <= _entryPrice - TakeProfitPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
		}

		if (_prevFast <= _prevSlow && fastValue > slowValue && Position <= 0)
		{ if (Position < 0) BuyMarket(); BuyMarket(); _entryPrice = close; _cooldown = 100; }
		else if (_prevFast >= _prevSlow && fastValue < slowValue && Position >= 0)
		{ if (Position > 0) SellMarket(); SellMarket(); _entryPrice = close; _cooldown = 100; }

		_prevFast = fastValue; _prevSlow = slowValue;
	}
}