Портирована из MetaTrader 5 советника MySystem.mq5 из каталога MQL/22016.
Отслеживает смену импульса через усреднение показаний индикаторов Elder Bulls Power и Bears Power, рассчитанных по экстремумам свечи и EMA.
Открывает покупку, когда среднее значение растёт, но остаётся ниже нуля (ослабевает медвежья сила), и продажу, когда среднее падает, но остаётся выше нуля (ослабевает бычья сила).
Одновременно поддерживается только одна позиция; стоп-лосс и тейк-профит задаются в пунктах и могут быть отключены.
Логика индикаторов
Компонент
Описание
Exponential Moving Average (EMA)
Сглаживание по ценам закрытия. Длина задаётся параметром MaPeriod (по умолчанию 5).
Bulls Power (производный)
High - EMA. Показывает силу быков относительно EMA.
Bears Power (производный)
Low - EMA. Показывает силу медведей относительно EMA.
Average Power
(Bulls Power + Bears Power) / 2. Полученный осциллятор сравнивается с предыдущим значением для фиксации изменения импульса.
Расчёты выполняются только на полностью сформированных свечах; новых сделок не будет до закрытия текущей свечи.
Правила входа
Дождаться формирования EMA (не менее MaPeriod свечей).
Для закрывшейся свечи вычислить Bulls Power и Bears Power на основе её High/Low и значения EMA.
Усреднить оба значения и получить текущий импульс.
Сравнить с предыдущим средним:
Лонг: предыдущее значение < текущего и текущее < 0. Открывать покупку только при отсутствии позиции.
Шорт: предыдущее значение > текущего и текущее > 0. Открывать продажу только при отсутствии позиции.
Закрытие позиции выполняется установленными стоп- и тейк-ордером либо вручную; дополнительных сигналов выхода стратегия не формирует.
Управление рисками
StopLossPips: дистанция стоп-лосса в пунктах (0 — без стопа). Переводится в цену через PriceStep инструмента.
TakeProfitPips: дистанция тейк-профита в пунктах (0 — без тейка).
Защитные заявки выставляются сразу после открытия позиции через StartProtection с рыночным исполнением.
Параметры
Параметр
Значение по умолчанию
Назначение
OrderVolume
0.1
Объём рыночных заявок.
StopLossPips
15
Стоп-лосс в пунктах. 0 отключает.
TakeProfitPips
95
Тейк-профит в пунктах. 0 отключает.
MaPeriod
5
Длина EMA в расчёте Bulls/Bears Power.
CandleType
Таймфрейм 1 час
Тип свечей для всех вычислений (измените под свой источник данных).
Рекомендации по использованию
Подключите стратегию к инструменту и убедитесь, что параметр CandleType соответствует желаемому таймфрейму.
Подстройте OrderVolume, StopLossPips и TakeProfitPips под требования брокера.
Запустите стратегию — она автоматически подпишется на свечи, обновит EMA и отправит рыночные заявки при выполнении условий.
Пока позиция открыта, новые сигналы игнорируются до её закрытия стопом/тейком или вручную.
Оригинальный параметр InpBarCurrent = 1 в MQL-версии заменён на работу исключительно с закрытыми свечами, поэтому пересчёта внутри бара нет.
Отличия от исходного MQL
Используется высокоуровневый API StockSharp с подпиской на свечи и привязкой индикаторов вместо ручной работы с буферами.
Пересчёт пунктов выполняется через PriceStep, без ручной нормализации по количеству знаков.
Закомментированный в оригинале код управления ордерами не переносился, применяется стандартная защита позиции.
Сохранено ограничение на одну позицию, что полностью повторяет исходную логику.
Рекомендации по тестированию
Протестируйте на исторических данных выбранного инструмента/таймфрейма с корректными High/Low для надёжного расчёта Bulls/Bears Power.
Убедитесь, что шаг цены и минимальный объём соответствуют требованиям брокера, прежде чем запускать стратегию на реальном счёте.
Экспериментируйте с MaPeriod, чтобы адаптировать чувствительность стратегии к волатильности инструмента.
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()