Открыть на GitHub

Стратегия Big Bar Sound

Общее описание

Big Bar Sound Strategy воспроизводит работу экспертного советника MetaTrader «BigBarSound». Стратегия отслеживает завершённые свечи выбранного таймфрейма и сообщает, когда диапазон свечи становится достаточно большим. Вместо воспроизведения WAV-файла стратегия записывает подробные сообщения в журнал, откуда их можно направить в любую систему уведомлений StockSharp.

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

Логика работы

  1. Стратегия подписывается на поток свечей, указанный в параметре Candle Type.
  2. Для каждой закрывшейся свечи рассчитывается её размер в соответствии с параметром Difference Mode:
    • OpenClose – абсолютная разница между ценами закрытия и открытия.
    • HighLow – абсолютный диапазон между максимумом и минимумом свечи.
  3. Полученное значение сравнивается с порогом, вычисленным как произведение Point Threshold и шага цены инструмента (PriceStep). Если размер свечи больше или равен порогу, стратегия записывает в лог сообщение о «проигрывании» выбранного звукового файла.
  4. При включённом флаге Show Alert дополнительно записывается отдельное уведомление, имитирующее всплывающее окно Alert из оригинала.

Обработка только завершённых свечей гарантирует, что каждая свеча вызовет оповещение не более одного раза, как и в изначальном MQL-скрипте с одноразовым триггером.

Параметры

  • Point Threshold (BarPoint) – минимальное количество шагов цены, необходимое для срабатывания сигнала. Значение по умолчанию 200 соответствует исходному советнику. Для удобства задан диапазон оптимизации 50–500 с шагом 50.
  • Difference Mode (DifferenceMode) – способ измерения размера свечи: по разнице цены открытия/закрытия или по диапазону high/low.
  • Sound File (SoundFile) – имя WAV-файла, который должен проигрываться. В портированной версии значение выводится только в лог, чтобы сохранить кроссплатформенность.
  • Show Alert (ShowAlert) – при активации в лог добавляется дополнительное сообщение-напоминание.
  • Candle Type (CandleType) – тип (таймфрейм) свечей, на которые оформляется подписка. По умолчанию используются минутные свечи.

Уведомления и журналирование

Для основного сообщения используется LogInfo, а для дополнительного предупреждения – AddInfoLog. Логи содержат идентификатор инструмента, время свечи и фактический размер диапазона, что упрощает интеграцию с просмоторщиком логов StockSharp или внешними системами уведомлений.

Если подключённый источник данных не передаёт корректный PriceStep, стратегия применяет резервное значение 1. В этом случае скорректируйте Point Threshold так, чтобы он соответствовал реальному минимальному изменению цены.

Рекомендации по применению

  • Подключайте стратегию к любому инструменту, для которого доступен поток свечей: валютные пары, фьючерсы, акции или криптовалюты.
  • Используйте логи стратегии в комплексных торговых решениях или расширяйте класс, чтобы передавать события в собственные обработчики.
  • Так как стратегия не совершает сделок, параметры объёма и управления позицией не используются.
  • Для воспроизведения реального звука подключите к логам StockSharp аудио-уведомитель или добавьте в код обращение к аудио-API операционной системы.

Отличия от оригинального советника MQL

  • В оригинале отслеживались тики и самостоятельно определялся момент начала новой свечи. В StockSharp-версии анализируются уже завершённые свечи, поэтому дополнительный флаг одноразового срабатывания не требуется.
  • Проигрывание звука заменено логами, что делает поведение одинаковым на любых платформах.
  • Названия параметров приведены к стилю StockSharp, но полностью сохраняют смысл оригинала: порог в пунктах, режим расчёта, опциональное уведомление и название звукового файла.

Требования

Дополнительные индикаторы не нужны. Главное – убедиться, что выбранный CandleType поддерживается подключённым источником данных и стратегия получает завершённые свечи для анализа.

using System;
using System.Linq;
using System.Collections.Generic;

using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Strategy that trades when a candle exceeds a configurable size threshold.
/// Based on the BigBarSound MetaTrader EA concept - trades in the direction of
/// large candles with ATR-based stop-loss and take-profit.
/// </summary>
public class BigBarSoundStrategy : Strategy
{
	/// <summary>
	/// Defines how the candle size is calculated.
	/// </summary>
	public enum BigBarDifferenceModes
	{
		/// <summary>
		/// Measure the difference between close and open prices.
		/// </summary>
		OpenClose,

		/// <summary>
		/// Measure the distance between the high and low of the candle.
		/// </summary>
		HighLow,
	}

	private readonly StrategyParam<int> _barPoint;
	private readonly StrategyParam<BigBarDifferenceModes> _differenceMode;
	private readonly StrategyParam<int> _atrPeriod;
	private readonly StrategyParam<decimal> _atrStopMultiplier;
	private readonly StrategyParam<decimal> _atrTpMultiplier;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _stopPrice;
	private decimal _takeProfitPrice;
	private int _direction;

	/// <summary>
	/// Number of price steps required to trigger the alert.
	/// </summary>
	public int BarPoint
	{
		get => _barPoint.Value;
		set => _barPoint.Value = value;
	}

	/// <summary>
	/// Defines how the candle size is calculated.
	/// </summary>
	public BigBarDifferenceModes DifferenceMode
	{
		get => _differenceMode.Value;
		set => _differenceMode.Value = value;
	}

	/// <summary>
	/// ATR period for stop/take-profit calculations.
	/// </summary>
	public int AtrPeriod
	{
		get => _atrPeriod.Value;
		set => _atrPeriod.Value = value;
	}

	/// <summary>
	/// ATR multiplier for stop-loss distance.
	/// </summary>
	public decimal AtrStopMultiplier
	{
		get => _atrStopMultiplier.Value;
		set => _atrStopMultiplier.Value = value;
	}

	/// <summary>
	/// ATR multiplier for take-profit distance.
	/// </summary>
	public decimal AtrTpMultiplier
	{
		get => _atrTpMultiplier.Value;
		set => _atrTpMultiplier.Value = value;
	}

	/// <summary>
	/// Candle type used to monitor the market.
	/// </summary>
	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	/// <summary>
	/// Initializes a new instance of the <see cref="BigBarSoundStrategy"/> class.
	/// </summary>
	public BigBarSoundStrategy()
	{
		_barPoint = Param(nameof(BarPoint), 180)
			.SetGreaterThanZero()
			.SetDisplay("Point Threshold", "Number of price steps required to trigger entry", "General")
			.SetOptimize(50, 500, 50);

		_differenceMode = Param(nameof(DifferenceMode), BigBarDifferenceModes.OpenClose)
			.SetDisplay("Difference Mode", "How the candle size is calculated", "General");

		_atrPeriod = Param(nameof(AtrPeriod), 14)
			.SetGreaterThanZero()
			.SetDisplay("ATR Period", "Period for ATR calculation", "Indicators")
			.SetOptimize(7, 28, 7);

		_atrStopMultiplier = Param(nameof(AtrStopMultiplier), 2m)
			.SetGreaterThanZero()
			.SetDisplay("ATR Stop Mult", "ATR multiplier for stop-loss", "Risk")
			.SetOptimize(1m, 3m, 0.5m);

		_atrTpMultiplier = Param(nameof(AtrTpMultiplier), 3m)
			.SetGreaterThanZero()
			.SetDisplay("ATR TP Mult", "ATR multiplier for take-profit", "Risk")
			.SetOptimize(1m, 4m, 0.5m);

		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(15).TimeFrame())
			.SetDisplay("Candle Type", "Type of candles to monitor", "Data");
	}

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

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_stopPrice = 0m;
		_takeProfitPrice = 0m;
		_direction = 0;
	}

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

		var atr = new AverageTrueRange { Length = AtrPeriod };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(atr, ProcessCandle)
			.Start();

		var area = CreateChartArea();
		if (area != null)
		{
			DrawCandles(area, subscription);
			DrawIndicator(area, atr);
			DrawOwnTrades(area);
		}
	}

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

		// Manage existing position
		if (Position > 0 && _direction > 0)
		{
			if (candle.LowPrice <= _stopPrice || candle.HighPrice >= _takeProfitPrice)
			{
				SellMarket(Position);
				_direction = 0;
				_stopPrice = 0m;
				_takeProfitPrice = 0m;
			}
		}
		else if (Position < 0 && _direction < 0)
		{
			if (candle.HighPrice >= _stopPrice || candle.LowPrice <= _takeProfitPrice)
			{
				BuyMarket(Math.Abs(Position));
				_direction = 0;
				_stopPrice = 0m;
				_takeProfitPrice = 0m;
			}
		}

		if (!IsFormedAndOnlineAndAllowTrading())
			return;

		if (Position != 0)
			return;

		if (atrValue <= 0m)
			return;

		// Calculate candle size
		var difference = DifferenceMode == BigBarDifferenceModes.OpenClose
			? Math.Abs(candle.ClosePrice - candle.OpenPrice)
			: candle.HighPrice - candle.LowPrice;

		var priceStep = Security?.PriceStep;
		var step = priceStep is null or <= 0m ? 1m : priceStep.Value;
		var threshold = step * BarPoint;

		if (difference < threshold)
			return;

		var isBullish = candle.ClosePrice > candle.OpenPrice;
		var stopDist = atrValue * AtrStopMultiplier;
		var tpDist = atrValue * AtrTpMultiplier;

		if (isBullish)
		{
			BuyMarket(Volume);
			_direction = 1;
			_stopPrice = candle.ClosePrice - stopDist;
			_takeProfitPrice = candle.ClosePrice + tpDist;
		}
		else
		{
			SellMarket(Volume);
			_direction = -1;
			_stopPrice = candle.ClosePrice + stopDist;
			_takeProfitPrice = candle.ClosePrice - tpDist;
		}
	}
}