Ver no GitHub

RPM5 BullsBearsEyes Strategy

Overview

The RPM5 BullsBearsEyes Strategy is a C# port of the MetaTrader 4 expert Rpm5_mt4v1. The advisor rebuilt the custom BullsBearsEyes oscillator from Bulls Power and Bears Power readings and opened a single position that followed the prevailing bias. This StockSharp version reproduces the same behaviour using the high-level API while keeping the original risk parameters, trailing logic, and signal thresholds.

Indicator reconstruction

  • Two classic oscillators – Bulls Power and Bears Power – are calculated on the configured candle series.
  • Their sum is passed through the identical four-stage IIR smoother used by the MT4 indicator. The smoothing factor (Gamma) controls how fast the oscillator reacts.
  • The filtered output is transformed into a value between 0 and 1. Values above the central threshold signal bullish dominance, values below it point to bearish control. Exact zero or one appear when either side is completely exhausted, matching the original indicator edge cases.

Trading rules

  1. The strategy subscribes to the selected timeframe (5 minutes by default) and waits for completed candles only.
  2. When flat, it evaluates the BullsBearsEyes ratio:
    • Long entry – current value strictly above the Threshold (default 0.5).
    • Short entry – current value strictly below the Threshold.
    • The algorithm keeps at most one open position. Opposite signals are ignored until the active position is fully closed by risk management.
  3. Once in a trade, the position is left untouched until a stop-loss, take-profit or trailing stop event occurs.

Risk management

  • Stop-loss / take-profit distances are recreated from the original 25 / 150 pip settings. They are recomputed using the instrument PriceStep (pip) each time a new position is opened.
  • ATR trailing: on every finished candle the Average True Range (period AtrPeriod, default 5) is evaluated. The trailing distance equals one pip plus AtrMultiplier × ATR. When the close advances beyond that distance, the protective stop is tightened to maintain the gap, identical to the MQL logic that repeatedly called OrderModify.
  • Protective levels are checked before processing new signals, ensuring that exits are always prioritised over fresh entries just like in the source EA.

Parameters

Name Default Description
Bulls/Bears Period 13 Averaging period for the Bulls Power and Bears Power indicators.
Gamma 0.5 Four-stage IIR smoothing ratio for the BullsBearsEyes oscillator.
Threshold 0.5 Divider between bullish (> threshold) and bearish (< threshold) zones.
ATR Period 5 Lookback used for the ATR-based trailing stop.
ATR Multiplier 1.5 Multiplier applied to ATR when deriving the trailing distance.
Stop Loss (pips) 25 Protective stop distance, converted from pips to price.
Take Profit (pips) 150 Profit target distance, converted from pips to price.
Trade Volume 1 Market order volume used for every new position.
Candle Type 5 minute candles Timeframe processed by the strategy.

Notes

  • The port does not draw the visual daily channel objects that were present in MT4 because they were cosmetic only.
  • All comments inside the code are written in English as requested.
  • Tests are unchanged; run the existing solution level checks if validation is required.
using System;
using System.Collections.Generic;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// RPM5 Bulls Bears Eyes strategy using Bull/Bear power with EMA filter.
/// Buy when bull power is positive and bear power crosses above threshold.
/// Sell when bear power is negative and bull power crosses below threshold.
/// </summary>
public class Rpm5BullsBearsEyesStrategy : Strategy
{
	private readonly StrategyParam<int> _emaPeriod;
	private readonly StrategyParam<int> _powerPeriod;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _prevBull;
	private decimal _prevBear;
	private bool _hasPrev;

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

	public Rpm5BullsBearsEyesStrategy()
	{
		_emaPeriod = Param(nameof(EmaPeriod), 13)
			.SetDisplay("EMA Period", "EMA trend period", "Indicators");

		_powerPeriod = Param(nameof(PowerPeriod), 13)
			.SetDisplay("Power Period", "Bulls/Bears power period", "Indicators");

		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Candle timeframe", "General");
	}

	/// <inheritdoc />
	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		return [(Security, CandleType)];
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();

		_prevBull = 0m;
		_prevBear = 0m;
		_hasPrev = false;
	}

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		_hasPrev = false;

		var ema = new ExponentialMovingAverage { Length = EmaPeriod };
		var bulls = new BullPower { Length = PowerPeriod };
		var bears = new BearPower { Length = PowerPeriod };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(ema, bulls, bears, ProcessCandle)
			.Start();
	}

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

		if (!_hasPrev)
		{
			_prevBull = bullValue;
			_prevBear = bearValue;
			_hasPrev = true;
			return;
		}

		// Long: price above EMA, bull power positive, bear power crossing from negative to less negative
		var longSignal = candle.ClosePrice > emaValue && bullValue > 0 && _prevBear < 0 && bearValue > _prevBear;
		// Short: price below EMA, bear power negative, bull power crossing from positive to less positive
		var shortSignal = candle.ClosePrice < emaValue && bearValue < 0 && _prevBull > 0 && bullValue < _prevBull;

		if (Position <= 0 && longSignal)
		{
			if (Position < 0)
				BuyMarket();
			BuyMarket();
		}
		else if (Position >= 0 && shortSignal)
		{
			if (Position > 0)
				SellMarket();
			SellMarket();
		}

		_prevBull = bullValue;
		_prevBear = bearValue;
	}
}