Suscripciones de alto nivel

Descripción general

La clase Strategy proporciona un conjunto de métodos de suscripción a datos de mercado de alto nivel: SubscribeCandles, SubscribeTicks, SubscribeLevel1 y SubscribeOrderBook. Estos métodos devuelven un objeto ISubscriptionHandler<T> que permite vincular controladores de datos e indicadores con un estilo fluido y cómodo.

A diferencia de crear manualmente un objeto Subscription y llamar a Subscribe(), los métodos de alto nivel:

  • Crean automáticamente una suscripción con los parámetros correctos
  • Proporcionan un ISubscriptionHandler<T> tipado para vincular controladores
  • Se integran con el sistema de indicadores mediante métodos Bind
  • Admiten renderizado automático en gráficos
  • Gestionan correctamente el ciclo de vida de la suscripción

Métodos de suscripción

SubscribeCandles

Se suscribe a velas. Acepta un marco temporal o DataType:

// Suscribirse por marco temporal
ISubscriptionHandler<ICandleMessage> SubscribeCandles(
    TimeSpan tf,
    bool isFinishedOnly = true,
    Security security = default);

// Suscribirse por DataType (admite todos los tipos de velas)
ISubscriptionHandler<ICandleMessage> SubscribeCandles(
    DataType dt,
    bool isFinishedOnly = true,
    Security security = default);

// Suscribirse con un objeto Subscription listo
ISubscriptionHandler<ICandleMessage> SubscribeCandles(Subscription subscription);

El parámetro isFinishedOnly es true de forma predeterminada -- el controlador recibe solo velas completadas.

SubscribeTicks

Se suscribe a operaciones tick:

ISubscriptionHandler<ITickTradeMessage> SubscribeTicks(Security security = null);
ISubscriptionHandler<ITickTradeMessage> SubscribeTicks(Subscription subscription);

SubscribeLevel1

Se suscribe a datos Level1 (mejores precios bid/ask, última operación y otros campos):

ISubscriptionHandler<Level1ChangeMessage> SubscribeLevel1(Security security = null);
ISubscriptionHandler<Level1ChangeMessage> SubscribeLevel1(Subscription subscription);

SubscribeOrderBook

Se suscribe al libro de órdenes:

ISubscriptionHandler<IOrderBookMessage> SubscribeOrderBook(Security security = null);
ISubscriptionHandler<IOrderBookMessage> SubscribeOrderBook(Subscription subscription);

Si no se especifica el parámetro security, se usa el Security de la estrategia.

Interfaz ISubscriptionHandler

El objeto ISubscriptionHandler<T> proporciona los siguientes métodos:

Start / Stop

Inicio y parada de la suscripción:

handler.Start();   // llama a Subscribe
handler.Stop();    // llama a UnSubscribe

Bind (sin indicadores)

Vincular un controlador de datos simple:

handler.Bind(Action<T> callback);

Bind (con indicadores)

Vincular un controlador con uno o más indicadores. El indicador procesa automáticamente los datos entrantes y el controlador recibe el valor ya calculado:

// Un indicador -- valor decimal
handler.Bind(IIndicator indicator, Action<T, decimal> callback);

// Dos indicadores
handler.Bind(IIndicator ind1, IIndicator ind2, Action<T, decimal, decimal> callback);

// Hasta ocho indicadores
handler.Bind(ind1, ind2, ind3, ..., callback);

// Array de indicadores
handler.Bind(IIndicator[] indicators, Action<T, decimal[]> callback);

El controlador con Bind se llama solo cuando todos los indicadores han devuelto un valor no vacío.

BindWithEmpty

Similar a Bind, pero el controlador se llama incluso si el indicador devolvió un valor vacío. Los valores se representan como decimal?:

handler.BindWithEmpty(IIndicator indicator, Action<T, decimal?> callback);

BindEx

Proporciona acceso al objeto IIndicatorValue completo en lugar del decimal extraído:

handler.BindEx(IIndicator indicator, Action<T, IIndicatorValue> callback, bool allowEmpty = false);

Ejemplo: estrategia con indicadores

public class SmaStrategy : Strategy
{
    private readonly StrategyParam<int> _shortPeriod;
    private readonly StrategyParam<int> _longPeriod;
    private readonly StrategyParam<DataType> _candleType;

    public int ShortPeriod
    {
        get => _shortPeriod.Value;
        set => _shortPeriod.Value = value;
    }

    public int LongPeriod
    {
        get => _longPeriod.Value;
        set => _longPeriod.Value = value;
    }

    public DataType CandleType
    {
        get => _candleType.Value;
        set => _candleType.Value = value;
    }

    public SmaStrategy()
    {
        _shortPeriod = Param(nameof(ShortPeriod), 10);
        _longPeriod = Param(nameof(LongPeriod), 20);
        _candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame());
    }

    protected override void OnStarted2(DateTime time)
    {
        base.OnStarted2(time);

        var shortSma = new SimpleMovingAverage { Length = ShortPeriod };
        var longSma = new SimpleMovingAverage { Length = LongPeriod };

        var subscription = SubscribeCandles(CandleType);

        // Vincular dos indicadores -- se llama al controlador
        // cuando ambos indicadores están formados
        subscription
            .Bind(shortSma, longSma, (candle, shortValue, longValue) =>
            {
                if (!IsFormedAndOnlineAndAllowTrading())
                    return;

                if (shortValue > longValue && Position <= 0)
                    BuyMarket(Volume + Math.Abs(Position));
                else if (shortValue < longValue && Position >= 0)
                    SellMarket(Volume + Math.Abs(Position));
            })
            .Start();

        // Configuración del gráfico
        var area = CreateChartArea();
        if (area != null)
        {
            DrawCandles(area, subscription);
            DrawIndicator(area, shortSma);
            DrawIndicator(area, longSma);
            DrawOwnTrades(area);
        }
    }
}

Ejemplo: suscripción a ticks

protected override void OnStarted2(DateTime time)
{
    base.OnStarted2(time);

    SubscribeTicks()
        .Bind(tick =>
        {
            if (!IsFormedAndOnlineAndAllowTrading())
                return;

            this.AddInfoLog("Tick: precio={0}, volumen={1}", tick.Price, tick.Volume);
        })
        .Start();
}

Ejemplo: suscripción al libro de órdenes

protected override void OnStarted2(DateTime time)
{
    base.OnStarted2(time);

    SubscribeOrderBook()
        .Bind(book =>
        {
            var bestBid = book.GetBestBid();
            var bestAsk = book.GetBestAsk();

            if (bestBid != null && bestAsk != null)
            {
                var spread = bestAsk.Price - bestBid.Price;
                this.AddInfoLog("Spread: {0}", spread);
            }
        })
        .Start();
}

Diferencias frente a la creación manual de suscripciones

Aspecto Suscripción manual Método de alto nivel
Creación new Subscription(DataType, Security) SubscribeCandles(tf)
Manejo de datos Suscripción a eventos del conector Bind(callback)
Indicadores Llamada manual a indicator.Process() Automáticamente mediante Bind(indicator, callback)
Registro de indicadores Adición manual a Indicators Automáticamente al usar Bind
Renderizado en gráfico Integración manual con IChart DrawCandles, DrawIndicator

Los métodos de alto nivel se recomiendan para la mayoría de las estrategias, ya que reducen significativamente la cantidad de código y disminuyen la probabilidad de errores.