Port of the MetaTrader 5 expert MySystem.mq5 located in MQL/22016.
Detects momentum reversals by averaging Elder Bulls Power and Bears Power values computed from candle extremes and an EMA.
Enters long when the average increases while still below zero (bearish pressure is fading) and short when the average decreases while still above zero (bullish pressure is fading).
Designed for one open position at a time; stop-loss and take-profit are optional and expressed in pips.
Indicator Logic
Component
Description
Exponential Moving Average (EMA)
Applied to candle close prices. The MaPeriod parameter controls the smoothing window (default 5).
Bulls Power (derived)
Calculated as High - EMA. Measures bullish strength relative to the EMA.
Bears Power (derived)
Calculated as Low - EMA. Measures bearish strength relative to the EMA.
Average Power
(Bulls Power + Bears Power) / 2. This synthetic oscillator is compared with its previous value to detect changes in momentum.
The strategy evaluates the last two finished candles. New trades are only evaluated when a candle is fully completed to avoid intrabar noise.
Entry Rules
Wait for the EMA to be fully formed (i.e., it processed at least MaPeriod candles).
Compute Bulls Power and Bears Power for the just-closed candle using its high/low and the EMA value.
Average both forces to obtain the current oscillator reading.
Compare with the previous average:
Long setup: previous average < current average and current average < 0. Enter long if there is no existing position.
Short setup: previous average > current average and current average > 0. Enter short if flat.
Once in a trade, rely on optional protective orders or manual management. The algorithm does not generate exit signals besides stop-loss/take-profit.
Risk Management
StopLossPips: Optional absolute stop distance in pips (0 disables the stop). Converted using the instrument PriceStep.
TakeProfitPips: Optional absolute profit target in pips (0 disables the target).
Protective orders are registered as soon as the position opens via StartProtection with market execution.
Parameters
Name
Default
Description
OrderVolume
0.1
Order size for market entries.
StopLossPips
15
Stop-loss distance in pips. Set to 0 to disable.
TakeProfitPips
95
Take-profit distance in pips. Set to 0 to disable.
MaPeriod
5
EMA length used for the Bulls/Bears Power calculation.
CandleType
1-hour time frame
Candle series used for all computations (change to match your data feed).
Usage Notes
Attach the strategy to an instrument and ensure the CandleType matches the intended time frame.
Adjust OrderVolume, StopLossPips, and TakeProfitPips to match brokerage requirements.
Run the strategy; it automatically subscribes to candles, updates the EMA, and issues market orders on qualifying signals.
Only one position can exist at a time. When a trade is active, new signals are ignored until the protective orders close the position or it is closed manually.
Because the original MQL version used InpBarCurrent = 1, this port always works on fully closed candles and compares consecutive values; no intrabar recalculation is performed.
Differences vs. Original MQL Expert
Uses StockSharp high-level Strategy API with candle subscriptions and indicator binding instead of manual buffer access.
Automatically derives pips from PriceStep instead of manual digit adjustments.
Skips the original commented-out order management and relies on built-in position protection.
Keeps the single-position constraint of the source by ignoring signals while a position exists.
Testing Recommendations
Backtest on the intended symbol/time frame with historical data that includes high/low prices for accurate Bulls/Bears computation.
Validate protective order behaviour with your broker's tick size and volume step before running live.
Experiment with different MaPeriod values to adapt sensitivity to the instrument volatility.
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>
/// Bulls Bears Power Average strategy. Uses EMA with bulls/bears power crossover.
/// </summary>
public class BullsBearsPowerAverageStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _emaPeriod;
private decimal? _prevPower;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int EmaPeriod { get => _emaPeriod.Value; set => _emaPeriod.Value = value; }
public BullsBearsPowerAverageStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame()).SetDisplay("Candle Type", "Timeframe", "General");
_emaPeriod = Param(nameof(EmaPeriod), 13).SetGreaterThanZero().SetDisplay("EMA Period", "EMA lookback for power calc", "Indicators");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities() => [(Security, CandleType)];
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevPower = null;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevPower = null;
var ema = new ExponentialMovingAverage { Length = EmaPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(ema, ProcessCandle).Start();
var area = CreateChartArea();
if (area != null) { DrawCandles(area, subscription); DrawIndicator(area, ema); DrawOwnTrades(area); }
}
private void ProcessCandle(ICandleMessage candle, decimal emaVal)
{
if (candle.State != CandleStates.Finished) return;
var bullsPower = candle.HighPrice - emaVal;
var bearsPower = candle.LowPrice - emaVal;
var avgPower = (bullsPower + bearsPower) / 2m;
if (!IsFormedAndOnlineAndAllowTrading()) { _prevPower = avgPower; return; }
if (_prevPower == null) { _prevPower = avgPower; return; }
if (_prevPower.Value < 0m && avgPower >= 0m && Position <= 0) { if (Position < 0) BuyMarket(); BuyMarket(); }
else if (_prevPower.Value > 0m && avgPower <= 0m && Position >= 0) { if (Position > 0) SellMarket(); SellMarket(); }
_prevPower = avgPower;
}
}
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_power_average_strategy(Strategy):
"""
Bulls Bears Power Average strategy. Uses EMA with bulls/bears power crossover.
"""
def __init__(self):
super(bulls_bears_power_average_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))) \
.SetDisplay("Candle Type", "Timeframe", "General")
self._ema_period = self.Param("EmaPeriod", 13) \
.SetDisplay("EMA Period", "EMA lookback for power calc", "Indicators")
self._prev_power = None
@property
def candle_type(self):
return self._candle_type.Value
@candle_type.setter
def candle_type(self, value):
self._candle_type.Value = value
@property
def ema_period(self):
return self._ema_period.Value
@ema_period.setter
def ema_period(self, value):
self._ema_period.Value = value
def OnReseted(self):
super(bulls_bears_power_average_strategy, self).OnReseted()
self._prev_power = None
def OnStarted2(self, time):
super(bulls_bears_power_average_strategy, self).OnStarted2(time)
self._prev_power = None
ema = ExponentialMovingAverage()
ema.Length = self.ema_period
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(ema, self.on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, ema)
self.DrawOwnTrades(area)
def on_process(self, candle, ema_val):
if candle.State != CandleStates.Finished:
return
bulls_power = candle.HighPrice - ema_val
bears_power = candle.LowPrice - ema_val
avg_power = (bulls_power + bears_power) / 2.0
if not self.IsFormedAndOnlineAndAllowTrading():
self._prev_power = avg_power
return
if self._prev_power is None:
self._prev_power = avg_power
return
if self._prev_power < 0.0 and avg_power >= 0.0 and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif self._prev_power > 0.0 and avg_power <= 0.0 and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._prev_power = avg_power
def CreateClone(self):
return bulls_bears_power_average_strategy()