Recopila estadísticas detalladas para el diferencial de oferta y demanda del instrumento seleccionado y notifica cuando el diferencial supera un límite configurable. La estrategia escucha continuamente las actualizaciones de Nivel 1, rastrea la dispersión máxima, mínima y promedio en puntos y registra un resumen una vez que se detiene. Es útil para investigar las condiciones de liquidez antes de ejecutar sistemas sensibles a la latencia u optimizar las ventanas de negociación en el Probador de estrategias.
Detalles
Fuente de datos: cotizaciones de mejor oferta y mejor demanda de nivel 1.
Estadísticas capturadas:
Marcas de tiempo de inicio y finalización del período de observación.
Difusión máxima y hora en la que ocurrió.
Spread mínimo y hora en que ocurrió.
Spread promedio calculado en todas las muestras de Nivel 1 observadas.
Alertas:
Alerta opcional cuando el diferencial (en puntos) supera el umbral configurado MaxSpreadPoints.
La frecuencia de las alertas está limitada por AlertIntervalSeconds para evitar enviar spam al registro.
Las alertas sólo se activan cuando el diferencial cruza el umbral desde abajo.
Registro:
Las alertas en tiempo real se escriben a través de LogInfo.
El resumen de estadísticas finales se emite durante OnStopped.
Valores predeterminados:
MaxSpreadPoints = 0 (alertas deshabilitadas).
AlertIntervalSeconds = 0 (sin limitación).
Parámetros
Nombre
Descripción
Predeterminado
Notas
MaxSpreadPoints
Spread máximo permitido en puntos. Establezca en 0 para desactivar las alertas.
0
Los puntos se calculan utilizando el paso del precio del instrumento.
AlertIntervalSeconds
Tiempo mínimo entre alertas consecutivas.
0
Evita alertas duplicadas cuando la propagación sigue siendo amplia.
Notas de uso
Adjunte la estrategia a un instrumento y asegúrese de que los datos de Nivel 1 estén disponibles.
Configure MaxSpreadPoints según la extensión aceptable para el instrumento.
Opcionalmente, aumente AlertIntervalSeconds para suprimir notificaciones repetidas durante períodos volátiles.
Detenga la estrategia para revisar las estadísticas registradas en la salida del terminal.
namespace StockSharp.Samples.Strategies;
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
/// <summary>
/// Spread Informer strategy: CCI momentum crossover.
/// Buys when CCI crosses above zero, sells when crosses below zero.
/// </summary>
public class SpreadInformerStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _cciPeriod;
private readonly StrategyParam<decimal> _cciLevel;
private readonly StrategyParam<int> _signalCooldownCandles;
private decimal _prevCci;
private int _candlesSinceTrade;
private bool _hasPrev;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int CciPeriod { get => _cciPeriod.Value; set => _cciPeriod.Value = value; }
public decimal CciLevel { get => _cciLevel.Value; set => _cciLevel.Value = value; }
public int SignalCooldownCandles { get => _signalCooldownCandles.Value; set => _signalCooldownCandles.Value = value; }
public SpreadInformerStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
_cciPeriod = Param(nameof(CciPeriod), 30)
.SetGreaterThanZero()
.SetDisplay("CCI Period", "CCI period", "Indicators");
_cciLevel = Param(nameof(CciLevel), 100m)
.SetDisplay("CCI Level", "CCI threshold for crossover", "Signals");
_signalCooldownCandles = Param(nameof(SignalCooldownCandles), 4)
.SetGreaterThanZero()
.SetDisplay("Signal Cooldown", "Bars to wait between trades", "Trading");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevCci = 0;
_candlesSinceTrade = SignalCooldownCandles;
_hasPrev = false;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevCci = 0;
_candlesSinceTrade = SignalCooldownCandles;
_hasPrev = false;
var cci = new CommodityChannelIndex { Length = CciPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(cci, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, decimal cciValue)
{
if (candle.State != CandleStates.Finished) return;
if (_candlesSinceTrade < SignalCooldownCandles)
_candlesSinceTrade++;
if (_hasPrev)
{
if (_prevCci < -CciLevel && cciValue >= -CciLevel && Position <= 0 && _candlesSinceTrade >= SignalCooldownCandles)
{
BuyMarket();
_candlesSinceTrade = 0;
}
else if (_prevCci > CciLevel && cciValue <= CciLevel && Position >= 0 && _candlesSinceTrade >= SignalCooldownCandles)
{
SellMarket();
_candlesSinceTrade = 0;
}
}
_prevCci = cciValue;
_hasPrev = true;
}
}