Для изменения размера нажмите или перетащите

Собственный тип свечей

S# позволяет расширить возможности построения свечей, давая возможность работать с произвольными типами свечей. Это полезно в тех случаях, когда требуется работать со свечами, не поддерживаемыми в данный момент S#. Ниже описан план действия по добавлению тиковых свечей (свечи, которые формируются по количеству сделок).

Реализация тиковых свечей

  1. В начале необходимо создать свой тип свечи. Тип должен наследоваться от класса Candle:

    Внимание Внимание
    Тиковые свечи поддерживаются S# стандартно и данный шаг представлен лишь в качестве примера.
    C#
    /// <summary>
    /// Свеча, группируемая по количеству сделок.
    /// </summary>
    public class TickCandle : Candle
    {
        /// <summary>
        /// Параметр свечи.
        /// </summary>
        public override object Arg
        {
            get
            {
                return this.TradeCount;
            }
            set
            {
                this.TradeCount = (int) value;
            }
        }
    
        /// <summary>
        /// Максимальное количество сделок, которое может содержать свеча.
        /// </summary>
        public int TradeCount { get; set; }
    }
  2. Дополнительно, необходимо создать свой тип сообщения свечи. Подробнее, о сообщениях. Тип должен наследоваться от класса CandleMessage:

    C#
    /// <summary>
    /// Свеча, группируемая по количеству сделок.
    /// </summary>
    public class TickCandleMessage : CandleMessage
    {
        public TickCandleMessage()
            : base(MessageTypes.CandleTick)
        {
        }
    
        /// <summary>
        /// Максимальное количество сделок, которое может содержать свеча.
        /// </summary>
        public int MaxTradeCount { get; set; }
    
        /// <summary>
        /// Создать копию <see cref="TickCandleMessage"/>.
        /// </summary>
        /// <returns>Копия.</returns>
        public override Message Clone()
        {
            return CopyTo(new TickCandleMessage
            {
                MaxTradeCount = MaxTradeCount
            });
        }
    
        /// <summary>
        /// Параметр свечи.
        /// </summary>
        public override object Arg
        {
            get => MaxTradeCount;
            set => MaxTradeCount = (int)value;
        }
    }
  3. Далее требуется создать построителя свечей, для нового типа свечей. Для этого необходимо создать реализацию CandleBuilderTCandleMessage. В метод ProcessValue будет поступать значение типа ICandleBuilderValueTransform. В зависимости от настроек может содержать данные как о тиковой сделке TickCandleBuilderValueTransform, так и о стакане QuoteCandleBuilderValueTransform.

    Метод ProcessValue должен возвратить или новую свечу (если новые данные привели к формированию свечи), или обновить переданную (если данных пока недостаточно для создания новой свечи). Если метод ProcessValue возвращает новую свечу, то CandleBuilderTCandleMessage вызывает его еще раз, передав в метод то же самое значение ICandleBuilderValueTransform. Метод будет вызываться до тех пор, пока ProcessValue не вернет переданную свечу. Это сделано для тех случаев, когда по одному входящему значению ICandleBuilderValueTransform может быть сформировано несколько свечей:

    C#
    /// <summary>
    /// Построитель свечей типа <see cref="T:StockSharp.Algo.Candles.TickCandle" />.
    /// </summary>
    public class TickCandleBuilder : CandleBuilder<TickCandleMessage>
    {
        /// <summary>
        /// Создать <see cref="T:StockSharp.Algo.Candles.Compression.TickCandleBuilder" />.
        /// </summary>
        public TickCandleBuilder()
        {
        }
    
        /// <summary>
        /// Создать <see cref="T:StockSharp.Algo.Candles.Compression.TickCandleBuilder" />.
        /// </summary>
        public TickCandleBuilder()
        {
        }
    
        /// <summary>
        /// Создать новую свечу.
        /// </summary>
        /// <param name="series">Серия свечей.</param>
        /// <param name="transform">Данные, с помощью которых необходимо создать новую свечу.</param>
        /// <returns>Созданная свеча.</returns>
        protected override TickCandle CreateCandle(CandleSeries series, ICandleBuilderValueTransform transform)
        {
            var candle = new TickCandleMessage
            {
                TradeCount = (int)series.Arg,
                OpenTime = transform.Time,
                CloseTime = transform.Time
            };
            return this.FirstInitCandle(series, candle, transform);
        }
    
        /// <summary>
        /// Получить временные диапазоны, для которых у данного источника для передаваемой серии свечей есть данные.
        /// </summary>
        /// <param name="series">Серия свечей.</param>
        /// <returns>Временные диапазоны.</returns>
        public override IEnumerable<Range<DateTime>> GetSupportedRanges(CandleSeries series)
        {
            IEnumerable<Range<DateTime>> supportedRanges = base.GetSupportedRanges(series);
            if (!supportedRanges.IsEmpty<Range<DateTime>>())
            {
                if (!(series.Arg is int))
                {
                    throw new ArgumentException();
                }
                if (((int) series.Arg) <= 0)
                {
                    throw new ArgumentOutOfRangeException();
                }
            }
            return supportedRanges;
        }
    
        /// <summary>
        /// Сформирована ли свеча до добавления данных.
        /// </summary>
        /// <param name="series">Серия свечей.</param>
        /// <param name="candle">Свеча.</param>
        /// <param name="transform">Данные, с помощью которых принимается решение о необходимости окончания формирования текущей свечи.</param>
        /// <returns>True, если свечу необходимо закончить. Иначе, false.</returns>
        protected override bool IsCandleFinishedBeforeChange(CandleSeries series, TickCandleMessage candle, ICandleBuilderValueTransform transform)
        {
            return candle.TotalTicks != null && candle.TotalTicks.Value >= candle.MaxTradeCount;
        }
    
        /// <summary>
        /// Обновить свечу данными.
        /// </summary>
        /// <param name="series">Серия свечей.</param>
        /// <param name="candle">Свеча.</param>
        /// <param name="transform">Данные.</param>
        protected override void UpdateCandle(CandleSeries series, TickCandleMessage candle, ICandleBuilderValueTransform transform)
        {
            base.UpdateCandle(series, candle, transform);
            candle.TotalTicks++;
        }
    }
  4. Затем необходимо получить CandleBuilderProvider из подключения и добавить в него TickCandleBuilder:

    Внимание Внимание
    TickCandleBuilder, как источник свечей, стандартно присутствует в CandleBuilderProvider. Данный шаг представлен лишь в качестве примера.
    C#
    private Connector _connector;
    
    ...
    
    _connector.Adapter.CandleBuilderProvider.Register(new TickCandleBuilder());
  5. Создать CandleSeries и запросить по ней данные:

    C#
    var series = new CandleSeries(typeof(TickCandle), _security, 1000);
    
    ...
    
    _connector.SubscribeCandles(series);