La Estrategia de Sonido de Barra Grande reproduce el comportamiento del asesor experto de MetaTrader "BigBarSound". El algoritmo observa las velas terminadas de un marco temporal configurable y reporta cuando el rango de la vela es lo suficientemente amplio como para considerarse una "barra grande". En lugar de reproducir un archivo de audio, escribe mensajes de registro detallados que pueden enrutarse a cualquier subsistema de notificación compatible con StockSharp.
La estrategia es puramente informativa – no envía órdenes ni gestiona posiciones. Está diseñada para usarse como componente de alerta dentro de un flujo de trabajo de trading automatizado o discrecional más amplio.
Comportamiento
La estrategia se suscribe a la serie de velas especificada por el parámetro Tipo de vela.
Para cada vela completada mide el tamaño de la barra según el Modo de diferencia seleccionado:
OpenClose – diferencia absoluta entre el precio de cierre y el de apertura.
HighLow – diferencia absoluta entre el máximo y el mínimo de la barra.
El valor medido se compara con el Umbral de puntos multiplicado por el PriceStep del instrumento. Cuando el tamaño de la barra es mayor o igual a este umbral, la estrategia registra una entrada de log que simula reproducir el archivo de sonido configurado.
Si Mostrar alerta está activado, se escribe un mensaje de alerta adicional para destacar el evento.
Dado que la implementación solo procesa velas terminadas, cada barra puede disparar como máximo una vez, replicando el comportamiento de disparo único del asesor experto MQL original.
Parámetros
Umbral de puntos (BarPoint) – número de pasos de precio que deben superarse antes de que se dispare una alerta. El valor predeterminado de 200 coincide con el script original. Se proporcionan límites de optimización (50–500 con paso 50) para mayor comodidad.
Modo de diferencia (DifferenceMode) – selecciona cómo se mide el tamaño de la vela: distancia apertura/cierre o rango completo máximo/mínimo.
Archivo de sonido (SoundFile) – nombre del archivo WAV que debería reproducirse. La estrategia solo registra este valor para emular la llamada PlaySound de MetaTrader.
Mostrar alerta (ShowAlert) – cuando está activado, la estrategia emite un mensaje de log adicional para imitar el popup opcional Alert de la versión MQL.
Tipo de vela (CandleType) – tipo de datos de vela (marco temporal) al que suscribirse. Por defecto la estrategia usa velas de 1 minuto.
Alertas y registro
La estrategia usa LogInfo para anunciar que el archivo de sonido habría sido reproducido y AddInfoLog para proporcionar un mensaje de alerta separado. Estas entradas contienen el identificador del instrumento, la marca de tiempo de la vela y el tamaño medido de la barra, facilitando la integración con los visores de registro o receptores de notificaciones de StockSharp.
Si el broker no proporciona un PriceStep válido, se usa un valor de reserva de 1 para que la estrategia permanezca operativa. Ajuste el Umbral de puntos en consecuencia para reflejar el tamaño real del tick del instrumento.
Notas de uso
Adjunte la estrategia a cualquier instrumento que exponga datos de velas. La alerta funciona igualmente bien en forex, futuros, acciones o activos cripto.
Combínela con otras estrategias de trading suscribiéndose a su salida de log o extendiendo la clase para reenviar eventos a manejadores personalizados.
Dado que la implementación no genera órdenes, Volume y los parámetros relacionados con la posición se ignoran.
Para producir notificaciones audibles, conecte el subsistema de registro de StockSharp a un notificador de sonido o extienda el código para llamar a APIs de audio específicas de la plataforma.
Diferencias con el asesor experto MQL original
El script original operaba con datos de ticks y rastreaba los cambios de barra manualmente. El port de StockSharp procesa directamente las velas terminadas, lo que garantiza exactamente una alerta por barra sin mantener un indicador de disparo separado.
La reproducción de audio es reemplazada por mensajes de log para que el comportamiento permanezca multiplataforma dentro del entorno StockSharp.
Los nombres de parámetros siguen las convenciones de StockSharp pero retienen la misma semántica: tamaño umbral en puntos, modo de medición, alerta opcional y nombre de sonido.
Requisitos
No se requieren indicadores adicionales. Simplemente asegúrese de que el CandleType seleccionado sea compatible con la fuente de datos conectada para que la estrategia reciba velas completadas para procesar.
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;
}
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Math
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import AverageTrueRange
from StockSharp.Algo.Strategies import Strategy
OPEN_CLOSE = 0
HIGH_LOW = 1
class big_bar_sound_strategy(Strategy):
def __init__(self):
super(big_bar_sound_strategy, self).__init__()
self._bar_point = self.Param("BarPoint", 180)
self._difference_mode = self.Param("DifferenceMode", OPEN_CLOSE)
self._atr_period = self.Param("AtrPeriod", 14)
self._atr_stop_multiplier = self.Param("AtrStopMultiplier", 2.0)
self._atr_tp_multiplier = self.Param("AtrTpMultiplier", 3.0)
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(15)))
self._stop_price = 0.0
self._take_profit_price = 0.0
self._direction = 0
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
def OnReseted(self):
super(big_bar_sound_strategy, self).OnReseted()
self._stop_price = 0.0
self._take_profit_price = 0.0
self._direction = 0
def OnStarted2(self, time):
super(big_bar_sound_strategy, self).OnStarted2(time)
self._stop_price = 0.0
self._take_profit_price = 0.0
self._direction = 0
atr = AverageTrueRange()
atr.Length = int(self._atr_period.Value)
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(atr, self.OnProcess).Start()
def OnProcess(self, candle, atr_value):
if candle.State != CandleStates.Finished:
return
pos = float(self.Position)
if pos > 0 and self._direction > 0:
if float(candle.LowPrice) <= self._stop_price or float(candle.HighPrice) >= self._take_profit_price:
self.SellMarket(pos)
self._direction = 0
self._stop_price = 0.0
self._take_profit_price = 0.0
elif pos < 0 and self._direction < 0:
if float(candle.HighPrice) >= self._stop_price or float(candle.LowPrice) <= self._take_profit_price:
self.BuyMarket(abs(pos))
self._direction = 0
self._stop_price = 0.0
self._take_profit_price = 0.0
if not self.IsFormedAndOnlineAndAllowTrading():
return
if self.Position != 0:
return
atr_v = float(atr_value)
if atr_v <= 0:
return
close = float(candle.ClosePrice)
open_p = float(candle.OpenPrice)
high = float(candle.HighPrice)
low = float(candle.LowPrice)
if int(self._difference_mode.Value) == OPEN_CLOSE:
difference = abs(close - open_p)
else:
difference = high - low
sec = self.Security
step = float(sec.PriceStep) if sec is not None and sec.PriceStep is not None and sec.PriceStep > 0 else 1.0
threshold = step * float(self._bar_point.Value)
if difference < threshold:
return
is_bullish = close > open_p
stop_dist = atr_v * float(self._atr_stop_multiplier.Value)
tp_dist = atr_v * float(self._atr_tp_multiplier.Value)
vol = float(self.Volume)
if is_bullish:
self.BuyMarket(vol)
self._direction = 1
self._stop_price = close - stop_dist
self._take_profit_price = close + tp_dist
else:
self.SellMarket(vol)
self._direction = -1
self._stop_price = close + stop_dist
self._take_profit_price = close - tp_dist
def CreateClone(self):
return big_bar_sound_strategy()