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
Die konfigurierte Kerzenreihe abonnieren und Bulls Power- und Bears Power-Indikatoren binden.
Bei jeder fertigen Kerze werden die Indikatorwerte durch dieselbe IIR-Smoothing-Kaskade (L0 – L3) wie der originale EA geführt.
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.
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.
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;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class bulls_bears_eyes_ea_strategy(Strategy):
def __init__(self):
super(bulls_bears_eyes_ea_strategy, self).__init__()
self._fast_period = self.Param("FastPeriod", 14) \
.SetDisplay("Fast Period", "Fast MA period", "Indicator")
self._slow_period = self.Param("SlowPeriod", 50) \
.SetDisplay("Slow Period", "Slow MA period", "Indicator")
self._stop_loss_points = self.Param("StopLossPoints", 200) \
.SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk")
self._take_profit_points = self.Param("TakeProfitPoints", 400) \
.SetDisplay("Take Profit", "Take-profit in price steps", "Risk")
self._fast = None
self._slow = None
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
self._cooldown = 0
@property
def fast_period(self):
return self._fast_period.Value
@property
def slow_period(self):
return self._slow_period.Value
@property
def stop_loss_points(self):
return self._stop_loss_points.Value
@property
def take_profit_points(self):
return self._take_profit_points.Value
def OnReseted(self):
super(bulls_bears_eyes_ea_strategy, self).OnReseted()
self._fast = None
self._slow = None
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
self._cooldown = 0
def OnStarted2(self, time):
super(bulls_bears_eyes_ea_strategy, self).OnStarted2(time)
self._fast = ExponentialMovingAverage()
self._fast.Length = self.fast_period
self._slow = ExponentialMovingAverage()
self._slow.Length = self.slow_period
subscription = self.SubscribeCandles(DataType.TimeFrame(TimeSpan.FromMinutes(5)))
subscription.Bind(self._fast, self._slow, self._process_candle)
subscription.Start()
def _process_candle(self, candle, fast_value, slow_value):
if candle.State != CandleStates.Finished:
return
fast_val = float(fast_value)
slow_val = float(slow_value)
if not self._fast.IsFormed or not self._slow.IsFormed:
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self._cooldown > 0:
self._cooldown -= 1
self._prev_fast = fast_val
self._prev_slow = slow_val
return
close = float(candle.ClosePrice)
step = float(self.Security.PriceStep) if self.Security is not None and self.Security.PriceStep is not None else 1.0
if self.Position > 0 and self._entry_price > 0:
if self.stop_loss_points > 0 and close <= self._entry_price - self.stop_loss_points * step:
self.SellMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self.take_profit_points > 0 and close >= self._entry_price + self.take_profit_points * step:
self.SellMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
elif self.Position < 0 and self._entry_price > 0:
if self.stop_loss_points > 0 and close >= self._entry_price + self.stop_loss_points * step:
self.BuyMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self.take_profit_points > 0 and close <= self._entry_price - self.take_profit_points * step:
self.BuyMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self._prev_fast <= self._prev_slow and fast_val > slow_val and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
self._entry_price = close
self._cooldown = 100
elif self._prev_fast >= self._prev_slow and fast_val < slow_val and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._entry_price = close
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
def CreateClone(self):
return bulls_bears_eyes_ea_strategy()