Table of Contents

Работа с графиком в стратегии

В StockSharp класс Strategy предоставляет удобный интерфейс для визуализации торговой активности на графике. В этой статье мы рассмотрим, как получить доступ к графику из стратегии, как создавать области (ChartArea), добавлять различные элементы (свечи, индикаторы, сделки) и отрисовывать данные.

Получение доступа к графику

Метод GetChart

Для получения доступа к графику из стратегии используется метод Strategy.GetChart():

protected override void OnStarted(DateTimeOffset time)
{
    base.OnStarted(time);
    
    // Получение графика
    _chart = GetChart();
    
    // Проверка доступности графика
    if (_chart != null)
    {
        // Инициализация графика
        InitializeChart();
    }
    else
    {
        // График недоступен, например, при запуске в консольном режиме
        LogInfo("График недоступен. Визуализация отключена.");
    }
}

Метод GetChart() возвращает интерфейс IChart, который предоставляет доступ к функциям графика. Важно проверять результат на null, так как график может быть недоступен, например, при запуске стратегии в консольном режиме или в облачном тестировании.

Метод SetChart

В некоторых случаях график может быть установлен извне. Для этого используется метод Strategy.SetChart:

// Установка графика из внешнего источника
public void ConfigureVisualization(IChart chart)
{
    SetChart(chart);
    
    if (chart != null)
    {
        InitializeChart();
    }
}

Создание областей графика (ChartArea)

После получения доступа к графику можно создать одну или несколько областей для отображения различных данных. Для этого используется метод CreateChartArea:

private void InitializeChart()
{
    // Создание основной области для свечей и индикаторов
    _mainArea = CreateChartArea();
    
    // Создание дополнительной области для объема
    _volumeArea = CreateChartArea();
    
    // Настройка областей и добавление элементов
    ConfigureChartElements();
}

Также можно использовать метод IChart.AddArea напрямую:

private void InitializeChart()
{
    // Очистка существующих областей, если необходимо
    foreach (var area in _chart.Areas.ToArray())
        _chart.RemoveArea(area);
    
    // Создание основной области для свечей и индикаторов
    _mainArea = _chart.AddArea();
    
    // Создание дополнительной области для объема
    _volumeArea = _chart.AddArea();
    
    // Настройка областей и добавление элементов
    ConfigureChartElements();
}

Добавление элементов на график

После создания областей графика можно добавить различные элементы для отображения данных. StockSharp поддерживает различные типы элементов, такие как свечи, индикаторы, сделки и заявки.

Добавление свечей

Для отображения свечей используется метод AddCandles области графика:

private void ConfigureChartElements()
{
    // Добавление элемента для отображения свечей в основной области
    _candleElement = _mainArea.AddCandles();
    
    // Настройка отображения свечей
    _candleElement.DrawStyle = ChartCandleDrawStyles.CandleStick; // Японские свечи
    _candleElement.AntiAliasing = true; // Сглаживание
    _candleElement.UpFillColor = Color.Green; // Цвет тела растущей свечи
    _candleElement.DownFillColor = Color.Red; // Цвет тела падающей свечи
    _candleElement.UpBorderColor = Color.DarkGreen; // Цвет границы растущей свечи
    _candleElement.DownBorderColor = Color.DarkRed; // Цвет границы падающей свечи
    _candleElement.StrokeThickness = 1; // Толщина линии
    _candleElement.ShowAxisMarker = true; // Показывать маркер на оси Y
}

Интерфейс IChartCandleElement предоставляет множество свойств для настройки отображения свечей:

  • DrawStyle - стиль отображения свечей:

    • CandleStick - японские свечи
    • Ohlc - бары
    • LineOpen/LineHigh/LineLow/LineClose - линии по соответствующей цене
    • BoxVolume - объемные боксы
    • ClusterProfile - кластерный профиль
    • Area - область
    • PnF - график типа крестики-нолики
  • Цветовые настройки:

    • UpFillColor/DownFillColor - цвет тела растущей/падающей свечи
    • UpBorderColor/DownBorderColor - цвет границы растущей/падающей свечи
    • LineColor - цвет линии для линейных типов графиков
    • AreaColor - цвет области для типа Area
  • Другие настройки:

    • StrokeThickness - толщина линии
    • AntiAliasing - сглаживание
    • ShowAxisMarker - показывать маркер на оси Y

Добавление индикаторов

Для отображения индикаторов используется метод DrawIndicator:

// Создание индикаторов
_sma = new SimpleMovingAverage { Length = SmaLength };
_bollinger = new BollingerBands
{
    Length = BollingerLength,
    Deviation = BollingerDeviation
};

// Добавление индикаторов в коллекцию стратегии
Indicators.Add(_sma);
Indicators.Add(_bollinger);

// Визуализация индикаторов
_smaElement = DrawIndicator(_mainArea, _sma, Color.Blue);
_bollingerUpperElement = DrawIndicator(_mainArea, _bollinger, Color.Purple);
_bollingerLowerElement = DrawIndicator(_mainArea, _bollinger, Color.Purple);
_bollingerMiddleElement = DrawIndicator(_mainArea, _bollinger, Color.Gray);

Метод DrawIndicator автоматически создает элемент индикатора и добавляет его в указанную область графика. Можно указать цвет и дополнительный цвет для отображения.

Также можно добавить элемент индикатора напрямую через метод AddIndicator области графика:

// Добавление SMA непосредственно через область графика
var smaElement = _mainArea.AddIndicator(_sma);
smaElement.Color = Color.Blue;
smaElement.StrokeThickness = 2;
smaElement.DrawStyle = DrawStyles.Line;
smaElement.AntiAliasing = true;
smaElement.ShowAxisMarker = true;
smaElement.AutoAssignYAxis = true; // Автоматически назначить ось Y

Интерфейс IChartIndicatorElement предоставляет следующие свойства для настройки:

  • Color - основной цвет индикатора
  • AdditionalColor - дополнительный цвет (для индикаторов с двумя линиями)
  • StrokeThickness - толщина линии
  • AntiAliasing - сглаживание
  • DrawStyle - стиль рисования (линия, точки, гистограмма и т.д.)
  • ShowAxisMarker - показывать маркер на оси Y
  • AutoAssignYAxis - автоматически назначить ось Y

Добавление сделок

Для отображения сделок используется метод DrawOwnTrades:

// Добавление элемента для отображения сделок
_tradesElement = DrawOwnTrades(_mainArea);

// Настройка отображения сделок
_tradesElement.BuyBrush = Color.Green;  // Цвет покупок
_tradesElement.SellBrush = Color.Red;   // Цвет продаж
_tradesElement.PointSize = 10;          // Размер точки

Добавление заявок

Для отображения заявок используется метод DrawOrders:

// Добавление элемента для отображения заявок
_ordersElement = DrawOrders(_mainArea);

// Настройка отображения заявок
_ordersElement.ActiveBrush = Color.Blue;     // Цвет активных заявок
_ordersElement.CanceledBrush = Color.Gray;   // Цвет отмененных заявок
_ordersElement.DoneBrush = Color.Green;      // Цвет исполненных заявок
_ordersElement.ErrorColor = Color.Red;       // Цвет ошибок
_ordersElement.PointSize = 8;                // Размер точки

Интерфейс IChartOrderElement предоставляет следующие свойства для настройки:

  • ActiveBrush - цвет активных заявок
  • CanceledBrush - цвет отмененных заявок
  • DoneBrush - цвет исполненных заявок
  • ErrorColor - цвет ошибок
  • ErrorStrokeColor - цвет обводки ошибок
  • Filter - фильтр отображения заявок

Отрисовка данных на графике

После настройки всех элементов графика можно приступить к отрисовке данных. Для этого используются различные методы в зависимости от типа данных.

Отрисовка свечей и индикаторов

Наиболее эффективный способ отрисовки данных — использование метода IChart.Draw с объектом IChartDrawData:

private void ProcessCandle(ICandleMessage candle)
{
    // Обработка свечи в индикаторах
    var smaValue = _sma.Process(candle);
    var bollingerValue = _bollinger.Process(candle);
    
    // Если график недоступен, пропускаем отрисовку
    if (_chart == null)
        return;
    
    // Создаем данные для отрисовки
    var drawData = _chart.CreateData();
    
    // Группируем данные по времени свечи
    var group = drawData.Group(candle.OpenTime);
    
    // Добавляем свечу
    group.Add(_candleElement, 
        candle.DataType, 
        candle.SecurityId, 
        candle.OpenPrice, 
        candle.HighPrice, 
        candle.LowPrice, 
        candle.ClosePrice, 
        candle.PriceLevels, 
        candle.State);
    
    // Добавляем значения индикаторов
    group.Add(_smaElement, smaValue);
    
    if (bollingerValue != null)
    {
        group.Add(_bollingerUpperElement, bollingerValue);
        group.Add(_bollingerMiddleElement, bollingerValue);
        group.Add(_bollingerLowerElement, bollingerValue);
    }
    
    // Отрисовываем данные на графике
    _chart.Draw(drawData);
}

Метод IChart.CreateData создает объект IChartDrawData, который используется для группировки и добавления данных для разных элементов графика. Группировка данных производится по временной метке с помощью метода Group.

Для добавления данных разного типа используются различные перегрузки метода Add объекта IChartDrawDataItem.

Отрисовка сделок и заявок

Для отрисовки сделок и заявок обычно используется автоматический механизм, который срабатывает при получении новых сделок или изменении заявок. Однако, если требуется отрисовать их вручную, можно использовать следующий код:

// Отрисовка сделки
var tradeDrawData = _chart.CreateData();
var tradeGroup = tradeDrawData.Group(trade.Time);
tradeGroup.Add(_tradesElement, trade.Id, trade.StringId, trade.Side, trade.Price, trade.Volume);
_chart.Draw(tradeDrawData);

// Отрисовка заявки
var orderDrawData = _chart.CreateData();
var orderGroup = orderDrawData.Group(order.Time);
orderGroup.Add(_ordersElement, order.Id, order.StringId, order.Side, order.Price, order.Volume);
_chart.Draw(orderDrawData);

Полный пример отрисовки графика в стратегии

Ниже приведен полный пример стратегии с настройкой и отрисовкой графика:

public class SmaStrategy : Strategy
{
    private readonly StrategyParam<int> _smaLength;
    private readonly StrategyParam<int> _bollingerLength;
    private readonly StrategyParam<decimal> _bollingerDeviation;
    
    private SimpleMovingAverage _sma;
    private BollingerBands _bollinger;
    
    private IChart _chart;
    private IChartArea _mainArea;
    private IChartArea _volumeArea;
    
    private IChartCandleElement _candleElement;
    private IChartIndicatorElement _smaElement;
    private IChartIndicatorElement _bollingerUpperElement;
    private IChartIndicatorElement _bollingerMiddleElement;
    private IChartIndicatorElement _bollingerLowerElement;
    private IChartOrderElement _ordersElement;
    private IChartTradeElement _tradesElement;
    
    public SmaStrategy()
    {
        _smaLength = Param(nameof(SmaLength), 20);
        _bollingerLength = Param(nameof(BollingerLength), 20);
        _bollingerDeviation = Param(nameof(BollingerDeviation), 2m);
    }
    
    public int SmaLength
    {
        get => _smaLength.Value;
        set => _smaLength.Value = value;
    }
    
    public int BollingerLength
    {
        get => _bollingerLength.Value;
        set => _bollingerLength.Value = value;
    }
    
    public decimal BollingerDeviation
    {
        get => _bollingerDeviation.Value;
        set => _bollingerDeviation.Value = value;
    }
    
    protected override void OnStarted(DateTimeOffset time)
    {
        base.OnStarted(time);
        
        // Создание индикаторов
        _sma = new SimpleMovingAverage { Length = SmaLength };
        _bollinger = new BollingerBands
        {
            Length = BollingerLength,
            Deviation = BollingerDeviation
        };
        
        // Добавление индикаторов в коллекцию стратегии
        Indicators.Add(_sma);
        Indicators.Add(_bollinger);
        
        // Получение графика
        _chart = GetChart();
        
        // Инициализация графика, если он доступен
        if (_chart != null)
        {
            InitializeChart();
        }
        
        // Подписка на свечи
        var subscription = new Subscription(
            DataType.TimeFrame(TimeSpan.FromMinutes(5)),
            Security);
        
        subscription
            .WhenCandlesFinished(this)
            .Do(ProcessCandle)
            .Apply(this);
        
        Subscribe(subscription);
    }
    
    private void InitializeChart()
    {
        // Очистка существующих областей
        foreach (var area in _chart.Areas.ToArray())
            _chart.RemoveArea(area);
        
        // Создание основной области для свечей и индикаторов
        _mainArea = _chart.AddArea();
        
        // Создание дополнительной области для объема
        _volumeArea = _chart.AddArea();
        
        // Настройка элементов графика
        ConfigureChartElements();
    }
    
    private void ConfigureChartElements()
    {
        // Добавление элемента для отображения свечей
        _candleElement = _mainArea.AddCandles();
        _candleElement.DrawStyle = ChartCandleDrawStyles.CandleStick;
        _candleElement.AntiAliasing = true;
        _candleElement.UpFillColor = Color.Green;
        _candleElement.DownFillColor = Color.Red;
        _candleElement.UpBorderColor = Color.DarkGreen;
        _candleElement.DownBorderColor = Color.DarkRed;
        _candleElement.StrokeThickness = 1;
        _candleElement.ShowAxisMarker = true;
        
        // Добавление элементов для индикаторов
        _smaElement = _mainArea.AddIndicator(_sma);
        _smaElement.Color = Color.Blue;
        _smaElement.StrokeThickness = 2;
        
        _bollingerUpperElement = _mainArea.AddIndicator(_bollinger);
        _bollingerUpperElement.Color = Color.Purple;
        _bollingerUpperElement.StrokeThickness = 1;
        
        _bollingerMiddleElement = _mainArea.AddIndicator(_bollinger);
        _bollingerMiddleElement.Color = Color.Gray;
        _bollingerMiddleElement.StrokeThickness = 1;
        
        _bollingerLowerElement = _mainArea.AddIndicator(_bollinger);
        _bollingerLowerElement.Color = Color.Purple;
        _bollingerLowerElement.StrokeThickness = 1;
        
        // Добавление элементов для заявок и сделок
        _ordersElement = DrawOrders(_mainArea);
        _tradesElement = DrawOwnTrades(_mainArea);
    }
    
    private void ProcessCandle(ICandleMessage candle)
    {
        // Обработка свечи индикаторами
        var smaValue = _sma.Process(candle);
        var bollingerValue = _bollinger.Process(candle);
        
        // Если график недоступен, пропускаем отрисовку
        if (_chart == null)
            return;
        
        // Отрисовка данных на графике
        var drawData = _chart.CreateData();
        var group = drawData.Group(candle.OpenTime);
        
        // Добавление свечи
        group.Add(_candleElement, 
            candle.DataType, 
            candle.SecurityId, 
            candle.OpenPrice, 
            candle.HighPrice, 
            candle.LowPrice, 
            candle.ClosePrice, 
            candle.PriceLevels, 
            candle.State);
        
        // Добавление значений индикаторов
        group.Add(_smaElement, smaValue);
        
        if (bollingerValue != null)
        {
            group.Add(_bollingerUpperElement, bollingerValue);
            group.Add(_bollingerMiddleElement, bollingerValue);
            group.Add(_bollingerLowerElement, bollingerValue);
        }
        
        // Отрисовка данных на графике
        _chart.Draw(drawData);
        
        // Торговая логика
        if (!IsFormed)
            return;
            
        // ... реализация торговой логики ...
    }
}

Заключение

Использование графиков в стратегиях StockSharp позволяет визуализировать торговую активность, что значительно упрощает разработку, отладку и мониторинг торговых стратегий. Класс Strategy предоставляет множество методов для работы с графиками, позволяющих легко добавлять различные элементы и отрисовывать данные.

При разработке стратегии с графическим интерфейсом всегда следует учитывать, что график может быть недоступен, например, при запуске в консольном режиме или в облачном тестировании. Поэтому важно проверять результат метода GetChart() на null и предусматривать альтернативный сценарий работы стратегии без визуализации.

См. также