Работа с графикой. Основы

В индикаторе можно переопределить метод OnRender в котором реализовать свою логику отрисовки данных.

Для того, чтобы этот метод начал вызываться, необходимо выставить флаг EnableCustomDrawing в true.

Также необходимо задать перечень слоев, в которых будет производиться отрисовка.

Перечень слоев задается через метод SubscribeToDrawingEvents, которому передаются флаги DrawingLayouts.

Флаги DrawingLayouts могут быть:

  • None - в этом случае ничего отрисовываться не будет
  • Historical - в этом случае перерисовка будет вызываться на каждой новой свечке, при сжатии, перемещении чарта
  • LatestBar - перерисовка вызывается при изменении самого последнего бара. Как правило это происходит на каждом новом тике
  • Final - финальный слой, который прорисовывается при каждой отрисовке графика. Например, при движении мышью.

Без вызова SubscribeToDrawingEvents индикатор будет отрисовываться только при изменении последнего бара.

Пример вызова SubscribeToDrawingEvents, после вызова которого, метод OnRender будет вызываться на каждом новом тике и при финальной отрисовке:

SubscribeToDrawingEvents(DrawingLayouts.Final | DrawingLayouts.LatestBar);

В метод OnRender передаются следующие объекты:

  • RenderContext context - контекст, в котором будет производиться отрисовка
  • DrawingLayouts layout - лейаут, который отрисовывается в настоящий момент

RenderContext.

С помощью данного контекста производится непосредственно отрисовка по GDI+ подобным принципам.

Несколько примеров:

protected virtual void OnRender(RenderContext context, DrawingLayouts layout)
        {
            //Draw Rectangle(width=100;height=200) from point(x=5;y=10)
            context.DrawRectangle(RenderPens.Blue,new Rectangle(5,10,100,200));

            //Fill Rectangle(width=100;height=100) from point(x=0;y=0)
            context.FillRectangle(Color.DarkSalmon, new Rectangle(0, 0, 100, 100));

            //Draw line from point(x=10;y=20) to point(x=50;y=60)
            context.DrawLine(RenderPens.AliceBlue, 10,20,50,60);

            //Draw string at point(x=50;y=60)
            context.DrawString("Sample string", new RenderFont("Arial",15),Color.Black, 50, 60);

            //Draw ellipse inside rectangle
            context.DrawEllipse(new RenderPen(Color.Bisque),new Rectangle(10,10,100,100));
        }

Cистема координат

Начало координат графика находится в левом верхнем углу.

Система координат показана на рисунке ниже

У каждого индикатора есть контейнер(свойство Container), содержащий в себе информацию об области отрисовки(свойство Region).

Через свойство ChartInfo(см.раздел "основные свойства индикатора") можно получать все основные свойства графика, мыши, клавиатуры.


Для удобства доступа к области графика добавлено свойство ChartArea, которое возвращает ChartInfo.ChartContainer.Region


Для удобства доступа к данных о мыши есть свойство MouseLocationInfo, которое возвращает ChartInfo.MouseLocationInfo

Также для ChartInfo есть расширения, позволяющие работать с координатами:

  • GetXByBar(int bar, bool isStartOfBar) - метод возвращает координату X для переданного номера бара. Если isStartOfBar=true, возвращается координата начала бара, иначе координата середины бара
  • GetYByPrice(decimal price, bool isStartOnPriceLevel) - метод возвращает Y координату для переданной цены. Если isStartOnPriceLevel=true, возвращается координата начала ценового уровня, иначе координата середины ценового уровня

Пример индикатора, который рисует перекрестие и выводит объем бара, на который наведена мышка.

public class SampleRendering : Indicator
    {
        public SampleRendering()
        {
            EnableCustomDrawing = true;

            //Subscribing only to drawing on final layout
            SubscribeToDrawingEvents(DrawingLayouts.Final);
        }

        protected override void OnRender(RenderContext context,  DrawingLayouts layout)
        {
            // creating pen, width 4px
            var pen = new RenderPen(Color.BlueViolet, 4);

            //drawing horizontal line
            context.DrawLine(pen, 0, MouseLocationInfo.LastPosition.Y, ChartArea.Width, MouseLocationInfo.LastPosition.Y);

            //drawing vertical line
            context.DrawLine(pen, MouseLocationInfo.LastPosition.X, 0, MouseLocationInfo.LastPosition.X, ChartArea.Height);

            var candle = GetCandle(MouseLocationInfo.BarBelowMouse);

            if (candle != null)
            {
                var font = new RenderFont("Arial", 14);
                var text = $"Total candle volume={candle.Volume}";
                var textSize = context.MeasureString(text, font);
                var textRectangle = new Rectangle(MouseLocationInfo.LastPosition.X + 10, MouseLocationInfo.LastPosition.Y + 10, (int)textSize.Width, (int)textSize.Height);

                context.FillRectangle(Color.CornflowerBlue, textRectangle);
                context.DrawString(text, font, Color.AliceBlue, textRectangle);
            }
        }

        protected override void OnCalculate(int bar, decimal value)
        {
        }
    }

Сервис поддержки клиентов работает на платформе UserEcho