Открыть на GitHub

Стратегия Bulls & Bears Power Average

Обзор

  • Портирована из 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. Полученный осциллятор сравнивается с предыдущим значением для фиксации изменения импульса.

Расчёты выполняются только на полностью сформированных свечах; новых сделок не будет до закрытия текущей свечи.

Правила входа

  1. Дождаться формирования EMA (не менее MaPeriod свечей).
  2. Для закрывшейся свечи вычислить Bulls Power и Bears Power на основе её High/Low и значения EMA.
  3. Усреднить оба значения и получить текущий импульс.
  4. Сравнить с предыдущим средним:
    • Лонг: предыдущее значение < текущего и текущее < 0. Открывать покупку только при отсутствии позиции.
    • Шорт: предыдущее значение > текущего и текущее > 0. Открывать продажу только при отсутствии позиции.
  5. Закрытие позиции выполняется установленными стоп- и тейк-ордером либо вручную; дополнительных сигналов выхода стратегия не формирует.

Управление рисками

  • StopLossPips: дистанция стоп-лосса в пунктах (0 — без стопа). Переводится в цену через PriceStep инструмента.
  • TakeProfitPips: дистанция тейк-профита в пунктах (0 — без тейка).
  • Защитные заявки выставляются сразу после открытия позиции через StartProtection с рыночным исполнением.

Параметры

Параметр Значение по умолчанию Назначение
OrderVolume 0.1 Объём рыночных заявок.
StopLossPips 15 Стоп-лосс в пунктах. 0 отключает.
TakeProfitPips 95 Тейк-профит в пунктах. 0 отключает.
MaPeriod 5 Длина EMA в расчёте Bulls/Bears Power.
CandleType Таймфрейм 1 час Тип свечей для всех вычислений (измените под свой источник данных).

Рекомендации по использованию

  1. Подключите стратегию к инструменту и убедитесь, что параметр CandleType соответствует желаемому таймфрейму.
  2. Подстройте OrderVolume, StopLossPips и TakeProfitPips под требования брокера.
  3. Запустите стратегию — она автоматически подпишется на свечи, обновит EMA и отправит рыночные заявки при выполнении условий.
  4. Пока позиция открыта, новые сигналы игнорируются до её закрытия стопом/тейком или вручную.
  5. Оригинальный параметр 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;
	}
}