Собственный тип свечей
S# позволяет расширить возможности построения свечей, давая возможность работать с произвольными типами свечей. Это полезно в тех случаях, когда требуется работать со свечами, не поддерживаемыми в данный момент S#. Ниже описан план действия по добавлению тиковых свечей (свечи, которые формируются по количеству сделок).
Реализация тиковых свечей
В начале необходимо создать свой тип свечи. Тип должен наследоваться от класса Candle:
Caution
Тиковые свечи поддерживаются S# стандартно и данный шаг представлен лишь в качестве примера.
/// <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; } }
Дополнительно, необходимо создать свой тип сообщения свечи. Подробнее, о сообщениях. Тип должен наследоваться от класса CandleMessage:
/// <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; } }
Далее требуется создать построителя свечей, для нового типа свечей. Для этого необходимо создать реализацию CandleBuilder<TCandleMessage>. В метод CandleBuilder<TCandleMessage>.ProcessValue(StockSharp.Algo.Candles.Compression.ICandleBuilderSubscription subscription, StockSharp.Algo.Candles.Compression.ICandleBuilderValueTransform transform ) будет поступать значение типа ICandleBuilderValueTransform. В зависимости от настроек может содержать данные как о тиковой сделке TickCandleBuilderValueTransform, так и о стакане QuoteCandleBuilderValueTransform.
Метод CandleBuilder<TCandleMessage>.ProcessValue(StockSharp.Algo.Candles.Compression.ICandleBuilderSubscription subscription, StockSharp.Algo.Candles.Compression.ICandleBuilderValueTransform transform ) должен возвратить или новую свечу (если новые данные привели к формированию свечи), или обновить переданную (если данных пока недостаточно для создания новой свечи). Если метод CandleBuilder<TCandleMessage>.ProcessValue(StockSharp.Algo.Candles.Compression.ICandleBuilderSubscription subscription, StockSharp.Algo.Candles.Compression.ICandleBuilderValueTransform transform ) возвращает новую свечу, то CandleBuilder<TCandleMessage> вызывает его еще раз, передав в метод то же самое значение ICandleBuilderValueTransform. Метод будет вызываться до тех пор, пока CandleBuilder<TCandleMessage>.ProcessValue(StockSharp.Algo.Candles.Compression.ICandleBuilderSubscription subscription, StockSharp.Algo.Candles.Compression.ICandleBuilderValueTransform transform ) не вернет переданную свечу. Это сделано для тех случаев, когда по одному входящему значению ICandleBuilderValueTransform может быть сформировано несколько свечей:
/// <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++; } }
Затем необходимо получить CandleBuilderProvider из подключения и добавить в него TickCandleBuilder:
Caution
TickCandleBuilder, как источник свечей, стандартно присутствует в CandleBuilderProvider. Данный шаг представлен лишь в качестве примера.
private Connector _connector; ... _connector.Adapter.CandleBuilderProvider.Register(new TickCandleBuilder());
Создать CandleSeries и запросить по ней данные:
var series = new CandleSeries(typeof(TickCandle), _security, 1000); ... _connector.SubscribeCandles(series);