Перейти к содержанию

Объекты графика и рисунки

Объекты графика (рисунки) позволяют рисовать линии или геометрические фигуры на графиках cTrader. Используя их, вы можете рисовать паттерны или показывать определенные события на графиках на основе данных вашего сиБота или индикатора.

Объекты графика используют координаты X и Y для позиционирования.

  • Ось X представляет время графика или индексы баров.
  • Ось Y — это цена инструмента.

Все объекты графика являются производными от базового класса ChartObject, что означает, что все они наследуют определенные базовые функции.

Примеры кода объектов графика

Рисование внутри окон индикаторов

При создании объектов графика вы не ограничены основным графиком инструмента. Фактически, вы можете рисовать объекты графика внутри любых окон, содержащих выходные данные индикаторов.

Класс Chart имеет коллекцию IndicatorAreas. Она содержит все неналоженные или отдельные окна, в которых индикаторы могут отображать свои выходные данные.

Вы также можете получить доступ к текущей области индикатора, используя свойство IndicatorArea вашего класса Indicator.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
using cAlgo.API;

namespace NewIndicator
{
    [Indicator(IsOverlay = false, AccessRights = AccessRights.None)]
    public class NewIndicator : Indicator
    {
        protected override void Initialize()
        {
            var verticalLine = IndicatorArea.DrawVerticalLine("line", Chart.LastVisibleBarIndex, Color.Red);
        }

        public override void Calculate(int index)
        {
        }
    }
}

Когда вы запустите экземпляр вышеуказанного индикатора, вы должны увидеть красную линию в отдельном окне индикатора. При создании графиков в отдельных областях индикаторов вы можете использовать все методы рисования, поскольку и Chart, и IndicatorArea наследуются от базового класса ChartArea.

Статический текст

Вместо использования координат X и Y для позиционирования статический текст использует статическое горизонтальное и вертикальное выравнивание. Чтобы показать или нарисовать статический текст, используйте метод DrawStaticText().

1
var staticText = Chart.DrawStaticText("static", "This is the text that will be shown", VerticalAlignment.Center, HorizontalAlignment.Center, Color.Red);

Если вы прикрепите этот объект графика к индикатору и запустите экземпляр, вы увидите следующий текст на основном графике.

Image title

Вертикальная линия

Используйте метод DrawVerticalLine() для рисования вертикальной линии.

1
2
3
var verticalLine = Chart.DrawVerticalLine("line", Chart.LastVisibleBarIndex, Color.Red);
// Or
var verticalLine = Chart.DrawVerticalLine("line", Bars.OpenTimes[Chart.LastVisibleBarIndex], Color.Red);

Горизонтальная линия

Используйте метод DrawHorizontalLine() для рисования горизонтальной линии.

1
2
3
/* We use the maximum of the high prices
of the last ten bars as the Y coordinate. */ 
var horizontalLine = Chart.DrawHorizontalLine("line", Bars.HighPrices.Maximum(10), Color.Red);

Линия Тренда

Линия Тренда начинается с определенной точки на графике и заканчивается в другой точке. Линии Тренда полезны для создания различных форм или сложных паттернов.

Чтобы нарисовать линию Тренда, используйте метод DrawTrendLine().

1
2
3
4
5
6
7
/* We draw a line from the low price
 of the first visible bar to the high price
 of the last visible bar on the chart. */
var trendLine = Chart.DrawTrendLine("line", Chart.FirstVisibleBarIndex, Bars.LowPrices[Chart.FirstVisibleBarIndex], Chart.LastVisibleBarIndex, Bars.HighPrices[Chart.LastVisibleBarIndex], Color.Red);

// Alternatively, consider the following.
var trendLine = Chart.DrawTrendLine("line", Bars.OpenTimes[Chart.FirstVisibleBarIndex], Bars.LowPrices[Chart.FirstVisibleBarIndex], Bars.OpenTimes[Chart.LastVisibleBarIndex], Bars.HighPrices[Chart.LastVisibleBarIndex], Color.Red);

Прямоугольник

Используйте метод DrawRectangle() для рисования прямоугольника.

1
2
3
4
5
6
7
var rectangle = Chart.DrawRectangle("rectangle", Chart.FirstVisibleBarIndex + 1, Bars.LowPrices[Chart.FirstVisibleBarIndex + 1], Chart.LastVisibleBarIndex, Bars.HighPrices[Chart.LastVisibleBarIndex], Color.Red);

/* We fill the rectangle with a transparent color.
By using its current color, we only change the alpha
channel. */
rectangle.IsFilled = true;
rectangle.Color = Color.FromArgb(80, rectangle.Color);

Треугольник

Используйте метод DrawTriangle() для рисования треугольника.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
var middleX = Chart.FirstVisibleBarIndex + (Chart.LastVisibleBarIndex - Chart.FirstVisibleBarIndex) / 2;
var middleY = Bars.LowPrices[Chart.FirstVisibleBarIndex] + (Bars.HighPrices[Chart.LastVisibleBarIndex] - Bars.LowPrices[Chart.FirstVisibleBarIndex]) / 2;

var triangle = Chart.DrawTriangle("triangle", Chart.FirstVisibleBarIndex, Bars.LowPrices[Chart.FirstVisibleBarIndex], middleX, middleY, Chart.LastVisibleBarIndex, Bars.LowPrices[Chart.FirstVisibleBarIndex], Color.Red);

// We fill the triangle with a transparent color
// by using it's current color, we change only the alpha channel

/* We fill the triangle with a transparent color.
By using its current color, we only change the alpha
channel. */
triangle.IsFilled = true;
triangle.Color = Color.FromArgb(80, triangle.Color);

Другие объекты графика

Для краткости мы не упомянули несколько других объектов графика в приведенных выше фрагментах кода. Эти объекты включают, помимо прочего, следующие:

  • Эллипс
  • Значок
  • Вилы Эндрюса
  • Канал с равноудаленной ценой
  • Расширение Фибоначчи
  • Веер Фибоначчи
  • Уровни коррекции Фибоначчи

Все эти объекты можно нарисовать, используя методы Draw...() с аналогичными названиями, принимающие аналогичные параметры.

Риск и доход

Интерфейс ChartRiskReward предоставляет типы, которые позволяют программно создавать объекты риска и дохода на графиках и управлять ими.

Приведенный ниже код показывает, как создать индикатор, который рисует объект риска и дохода:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
using System;
using cAlgo.API;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;

namespace cAlgo
{
    [Indicator(AccessRights = AccessRights.None, IsOverlay = true)]
    public class SimpleRiskReward : Indicator
    {
        protected override void Initialize()
        {
            var type = new ChartRiskRewardFixedRiskType(
                ChartRiskRewardAmountType.BalancePercentage, 
                1                                            
            );
            var tradeType = TradeType.Buy;
            var orderType = OrderType.Market;

            var entryPrice = Chart.Bars.LastBar.Close;
            var time1 = Chart.LastVisibleBarIndex - 20; 
            var time2 = Chart.LastVisibleBarIndex;      

            var rr = Chart.DrawRiskReward(
                "SimpleRR",     
                time1,           
                time2,            
                entryPrice,       
                orderType,        
                tradeType,        
                type              
            );

            rr.IsInteractive = true;

            rr.RiskColor = Color.Yellow;
            rr.RiskLineStyle = LineStyle.DotsRare;
            rr.RiskThickness = 3;

            rr.RewardColor = Color.Blue;
            rr.RewardLineStyle = LineStyle.LinesDots;
            rr.RewardThickness = 2;

            PrintRRInfo(rr);
        }

        private void PrintRRInfo(ChartRiskReward rr)
        {
            Print($"Name: {rr.Name} | Type: {rr.Type.GetType().Name} | Order Type: {rr.OrderType} | Trade Type: {rr.TradeType} | Time 1: {rr.Time1:o} | Time 2: {rr.Time2:o} | Entry: {rr.EntryPrice} | SL: {rr.StopLossPrice} | TP: {rr.TakeProfitPrice} | RR: {rr.RiskRewardRatio} | Volume: {rr.VolumeInUnits}");
        }

        public override void Calculate(int index)
        {
        }
    }
}

Ключевые настройки объектов

Именование объектов графика

Всякий раз, когда вы пытаетесь нарисовать объект графика, вы должны указать его имя в качестве аргумента для метода рисования.

Все имена объектов графика должны быть уникальными. Если это требование не выполняется, вы рискуете тем, что объекты графика будут переопределять объекты графика с одинаковыми именами в зависимости от времени их выполнения. Вы можете использовать значение индекса текущего бара или текущее время для генерации уникальных имен для каждого объекта.

Доступ к объектам графика

Все объекты графика содержатся в коллекции Objects. Эта коллекция включает объекты, нарисованные пользователем. В результате к коллекции Objects можно получить доступ для удаления объектов с графиков или изменения их свойств.

В приведенном ниже примере осуществляется доступ к элементам коллекции Objects:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
using cAlgo.API;
using System.Linq;
namespace NewIndicator
{
    [Indicator(IsOverlay = true, AccessRights = AccessRights.None)]
    public class NewIndicator : Indicator
    {
        protected override void Initialize()
        {
            foreach (var chartObject in Chart.Objects)
            {
                /* If the object is a trend line 
                we change its Y1/2 properties */
                if (chartObject is ChartTrendLine trendLine)
                {
                    trendLine.Y1 = Chart.BottomY;
                    trendLine.Y2 = Chart.TopY;
                }
            }

            /* Here, we filter all objects of the 'ChartRectangle'
            type. */
            var rectangles = from chartObject in Chart.Objects
                             where chartObject is ChartRectangle
                             select chartObject as ChartRectangle;

            /* We select only the chart objects with a name that
            begins with "MyObjects". */
            var myObjects = from chartObject in Chart.Objects
                            where chartObject.Name.StartsWith("MyObjects", System.StringComparison.OrdinalIgnoreCase)
                            select chartObject;

            /* We select only interactive objects. If an object
            is interactive, it will not be removed when the 
            indicator is removed or reloaded. */
            var interactiveObjects = from chartObject in Chart.Objects
                                     where chartObject.IsInteractive
                                     select chartObject;

            /* We remove all objects with a name 
            that begins with "ToRemove". */
            var chartObjectsCopy = Chart.Objects.ToArray();

            foreach (var chartObject in chartObjectsCopy)
            {
                if (chartObject.Name.StartsWith("ToRemove", System.StringComparison.OrdinalIgnoreCase))
                {
                    /* Chart 'RemoveObject' gets the object name
                    as a parameter. */
                    Chart.RemoveObject(chartObject.Name);
                }

            }
        }

        public override void Calculate(int index)
        {
        }
    }
}

События

Объекты графика имеют несколько событий, которые вы можете использовать, чтобы узнать, какие объекты нарисованы, обновлены или удалены:

  • ObjectsAdded — срабатывает, когда один или несколько объектов графика добавляются на график.
  • ObjectsRemoved — срабатывает, когда один или несколько объектов графика удаляются с графика.
  • ObjectsUpdated — срабатывает, когда один или несколько объектов графика обновляются (одно из их свойств изменяется пользователем или активным индикатором или сиБотом).
  • ObjectsSelectionChanged — срабатывает, когда один или несколько объектов графика выбираются пользователем.
  • ObjectHoverChanged — срабатывает, когда курсор мыши наводится на объект графика.

В следующем примере используются все пять типов событий:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
using cAlgo.API;

namespace NewIndicator
{
    [Indicator(IsOverlay = true, AccessRights = AccessRights.None)]
    public class NewIndicator : Indicator
    {
        protected override void Initialize()
        {
            Chart.ObjectsAdded += Chart_ObjectsAdded;
            Chart.ObjectsRemoved += Chart_ObjectsRemoved;
            Chart.ObjectsUpdated += Chart_ObjectsUpdated;
            Chart.ObjectsSelectionChanged += Chart_ObjectsSelectionChanged;
            Chart.ObjectHoverChanged += Chart_ObjectHoverChanged;
        }

        private void Chart_ObjectHoverChanged(ChartObjectHoverChangedEventArgs obj) => throw new System.NotImplementedException();

        private void Chart_ObjectsSelectionChanged(ChartObjectsSelectionChangedEventArgs obj) => throw new System.NotImplementedException();

        private void Chart_ObjectsUpdated(ChartObjectsUpdatedEventArgs obj) => throw new System.NotImplementedException();

        private void Chart_ObjectsRemoved(ChartObjectsRemovedEventArgs obj) => throw new System.NotImplementedException();

        private void Chart_ObjectsAdded(ChartObjectsAddedEventArgs obj) => throw new System.NotImplementedException();

        public override void Calculate(int index)
        {
        }
    }
}

Интерактивные и неинтерактивные объекты

При работе с интерактивными объектами пользователи могут изменять их свойства, такие как положение объекта, цвет, комментарий и т. д. Все объекты, нарисованные пользователем, по умолчанию являются интерактивными.

Примечание

Свойство ChartStaticText не может быть изменено независимо от того, является ли связанный с ним объект интерактивным.

Чтобы сделать объект интерактивным, установите его свойство IsInteractive в значение true, как показано ниже:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
using cAlgo.API;

namespace NewIndicator
{
    [Indicator(IsOverlay = true, AccessRights = AccessRights.None)]
    public class NewIndicator : Indicator
    {
        protected override void Initialize()
        {
            var verticalLine = Chart.DrawVerticalLine("line", Chart.LastVisibleBarIndex, Color.Red);

            verticalLine.IsInteractive = true;
        }

        public override void Calculate(int index)
        {
        }
    }
}

Все объекты графика имеют свойство IsInteractive. Его значение по умолчанию — false.

Если объект графика интерактивен, он не будет удален при удалении или остановке экземпляра индикатора или сиБота. Напротив, неинтерактивные объекты удаляются автоматически, когда индикатор или сиБот прекращает работу.

Чтобы избежать беспорядка, обязательно очищайте интерактивные объекты после удаления связанного с ними экземпляра, используя методы индикатора Destroy или сиБота OnStop.

Если объект графика не является интерактивным, он также будет невидим в списках и коллекциях объектов графика.

Заблокированные и разблокированные объекты

Блокировка объекта графика не позволяет пользователю изменять или обновлять его. Вы можете сделать это через окно Трейдера (свойства графика) или установив свойство IsLocked в значение true. Значение по умолчанию — false.

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

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
using cAlgo.API;

namespace NewIndicator
{
    [Indicator(IsOverlay = true, AccessRights = AccessRights.None)]
    public class NewIndicator : Indicator
    {
        protected override void Initialize()
        {
            var verticalLine = Chart.DrawVerticalLine("line", Chart.LastVisibleBarIndex, Color.Red);

            verticalLine.IsLocked = true;
        }

        public override void Calculate(int index)
        {
        }
    }
}

Показать и скрыть

Вы можете нарисовать объект на графике и впоследствии скрыть его. Хотя объект по-прежнему будет присутствовать на графике, он будет полностью невидимым.

Для этого установите свойство IsHidden в значение true.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
using cAlgo.API;

namespace NewIndicator
{
    [Indicator(IsOverlay = true, AccessRights = AccessRights.None)]
    public class NewIndicator : Indicator
    {
        protected override void Initialize()
        {
            var verticalLine = Chart.DrawVerticalLine("line", Chart.LastVisibleBarIndex, Color.Red);

            verticalLine.IsHidden = true;
        }

        public override void Calculate(int index)
        {
        }
    }
}

Использование ресурсов — основное соображение при использовании этой функции. Если объект должен часто появляться на графике (но не постоянно), лучше скрыть его, чем удалять и перерисовывать каждый раз, когда он нужен.

Выбор объекта и индекс отображения (ZIndex)

Естественно, могут возникнуть случаи, когда несколько объектов пересекаются друг с другом на графике, что затрудняет или делает невозможным выбор одного конкретного объекта. При наведении курсора мыши на группу пересекающихся объектов графика можно будет выбрать только тот объект, который был нарисован последним.

Чтобы изменить это поведение, вы можете использовать свойство ZIndex. Оно может быть полезно при попытке отобразить сложные паттерны объектов графика.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
using cAlgo.API;

namespace NewIndicator
{
    [Indicator(IsOverlay = true, AccessRights = AccessRights.None)]
    public class NewIndicator : Indicator
    {
        protected override void Initialize()
        {
            var firstVerticalLine = Chart.DrawVerticalLine("line1", Chart.LastVisibleBarIndex, Color.Red);

            firstVerticalLine.IsInteractive = true;

            var secondVerticalLine = Chart.DrawVerticalLine("line2", Chart.LastVisibleBarIndex, Color.Yellow);

            secondVerticalLine.IsInteractive = true;

            firstVerticalLine.ZIndex = secondVerticalLine.ZIndex + 1;
        }

        public override void Calculate(int index)
        {
        }
    }
}

После добавления на график вышеуказанный индикатор отобразит красную вертикальную линию, а не желтую. Поскольку значение свойства ZIndex первой линии выше, чем соответствующее значение второй линии, она имеет приоритет над второй (желтой) линией.

Другими словами, свойство ZIndex определяет, какие объекты графика отображаются первыми при наложении. Всем нарисованным объектам графика автоматически присваивается определенное значение свойства ZIndex.

Узнать, удален ли объект

Все объекты графика наследуют свойство IsAlive от базового класса ChartObject. Значение этого свойства равно true, пока объект присутствует на графике (независимо от того, видимый он или невидимый). Значение устанавливается в false, как только объект удаляется с графика.

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

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
using cAlgo.API;

namespace NewIndicator
{
    [Indicator(IsOverlay = true, AccessRights = AccessRights.None)]
    public class NewIndicator : Indicator
    {
        private ChartVerticalLine _verticalLine;

        protected override void Initialize()
        {
            _verticalLine = Chart.DrawVerticalLine("line1", Chart.LastVisibleBarIndex, Color.Red);
            _verticalLine.IsInteractive = true;

            Chart.ObjectsRemoved += Chart_ObjectsRemoved;

            Print(_verticalLine.IsAlive);
        }

        private void Chart_ObjectsRemoved(ChartObjectsRemovedEventArgs obj)
        {
            Print(_verticalLine.IsAlive);

            /* If the object is removed, we should rid of its
            reference. Otherwise, it will remain in memory. */
            if (_verticalLine.IsAlive is false)
            {
                _verticalLine = null;

                Print("Object reference removed");
            }
        }

        public override void Calculate(int index)
        {
        }
    }
}

Если вы запустите экземпляр этого индикатора, щелкните правой кнопкой мыши по красной линии и удалите ее. В журнале должно появиться сообщение "Object reference removed".

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

Чтобы избежать этой проблемы, используйте событие ObjectsRemoved в сочетании со свойством IsAlive.

Индекс бара или время

При кодировании объектов графика вы можете использовать либо время графика, либо индекс бара для оси X.

По нашему мнению, время графика — лучший вариант. При использовании индексов баров вы не можете планировать будущие значения (потому что необходимые индексы еще не существуют) и не можете учитывать пробелы между барами. Однако индексы баров могут быть проще в использовании, особенно в случае относительно простых объектов графика.

Все методы Chart.Draw имеют разные перегрузки для индексов баров и времени графика.