Skip to content

Chart Objects/Drawings

Note

For a more detailed understanding, we also provide specific API Reference

Introduction

Chart objects or drawings allows you to draw a line or geometrical shape on a cTrader chart.

By using chart objects you can draw a chart pattern or show something on a chart based on your indicator/cBot data.

Chart objects uses X and Y coordinates for positioning, the X coordinate is chart time or bar index and Y coordinate is the chart symbol price.

You can use chart objects on both cBots and indicators.

All chart objects are derived from ChartObject base class, all of them inherit some common features like being interactive or not from this base class.

We will go trough some of them with some examples but first let's explain some general stuff that are necessary to know before using chart object.

Naming Chart Objects

Whenever you try to draw a chart object the first thing you have to provide for it's draw method is the chart object name.

cTrader uses chart object names to differ them from each other, if you use same name for two chart objects the one that was drawn last will override the first one.

Always try to use unique names for chart objects if you want them to override each other, you can use the current bar index or current time to generate unique names for each object.

Accessing Chart Objects

All objects of a chart is inside it's Objects collection, including user drawn objects and other indicators/cBots.

You can use it to remove an object from chart or modify the properties of them.

Here is an example of using Chart objects collection:

 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 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 object is a trend line we change its Y1/2 properties
                if (chartObject is ChartTrendLine trendLine)
                {
                    trendLine.Y1 = Chart.BottomY;
                    trendLine.Y2 = Chart.TopY;
                }
            }

            // You can also use Linq
            // Here we filter all objects of type ChartRectangle
            var rectangles = from chartObject in Chart.Objects
                             where chartObject is ChartRectangle
                             select chartObject as ChartRectangle;
            // We select only those 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 user can interact with it
            // and it will not be removed when indicator is removed or reloaded
            var interactiveObjects = from chartObject in Chart.Objects
                                     where chartObject.IsInteractive
                                     select chartObject;

            // Removing 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 object name as a parameter
                    Chart.RemoveObject(chartObject.Name);
                }

            }
        }

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

Events

Chart objects have several events that you can use to be aware of what objects are drawn, updated, or removed:

  • ObjectsAdded: This event is triggered when one or more chart objects are added to chart
  • ObjectsRemoved: This event is triggered when one or more chart objects are removed from chart
  • ObjectsUpdated: This event is triggered when one or more chart objects are updated (one of their properties changed by user or indicator/cBot)
  • ObjectsSelectionChanged: This event is triggered when one or more chart objects are selected by user
  • ObjectHoverChanged: This event is triggered when user mouse cursor hover over a chart object

You can use above of the above events like this:

 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)
        {
        }
    }
}

Check references to know how to use their event args.

Interactive / Non-interactive

If a chart object is set to be interactive user can change it's properties like position, color, comment, etc...

The only exception is ChartStaticText, setting it's interactive property to True will now allow the user to interact with it but it will preserve the object if indicator reloaded or removed from the chart.

To make an object interactive you just have to set it's IsInteractive property to 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)
        {
        }
    }
}

All chart objects have the IsInteractive property, when you draw an object from cBot/indicator the default state is non-interactive so it's IsInteractive property is set to False.

Making an object interactive not just allow the user to interact with the object, it also prevent it from getting removed when it's drawn indicator is removed from the chart or it's drawn cBot is stopped.

Non-interactive objects are removed automatically when the indicator or cBot that drew it is removed/stopped.

If you made an object interactive don't forget to clean them when your indicator is removed or your cBot is stopped by using indicator Destroy or cBot OnStop methods.

All user drawn objects are interactive by default.

If your indicator or cBot drawn chart object is not interactive it will not be visible on Chart objects list or other indicators/cBots Chart objects collections.

Locked / Unlocked

Locking a chart object will prevent the user from modifying/updating it, you can lock a chart object from cTrader chart properties box or via code by setting it's IsLocked property to True.

You can use locking when you want to make an object interactive but you don't want to let the user update it unless he unlock the object manually.

The default state of all drawn objects are unlocked, here is an example of locking a vertical line:

 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)
        {
        }
    }
}

Show / Hide

You can draw an object on a chart and later hide it, the object will still be on the chart but you can't see it.

To hide a chart object you set the IsHidden property to 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)
        {
        }
    }
}

You might ask you self why just not remove and re-draw an object instead of hiding it? the reason you might prefer hiding instead of removing and re-drawing is resource usage.

If you have an object the should be on chart frequently it's better to hide it when you don't need it instead of removing it from Chart.

Removing it from chart will make it illegible for GC and re-drawing mean re allocation.

Object Selection/Appearance Index (ZIndex)

When you draw several object which crosses each other you will get into trouble when you want to select one of them.

IF you move your mouse of them you will select the one that is drawn after others or the latest one.

To change this behavior you can use chart objects z index property, it's can be really helpful in situations like drawing complex chart patterns.

Here is an example:

 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)
        {
        }
    }
}

If you attach the above indicator on a chart you will see the red vertical line instead of yellow, because we increased the first line z index by one from second line z index.

Z index also affect which objects you will see on your chart when they overlap, the one that has the greater z index will be the one that you see.

The API itself assigns a z index to all drawn chart objects by using chart objects count.

How to know if an object is removed/dead?

All chart objects inherit the IsAlive property from ChartObject base class, this property value is True as long as the object is on the chart, when it's removed by user or a cBot/indicator this property value will become False.

If you save a reference to a chart object and later that object is removed by user you can check this property of object to know if it's still on the chart or not.

Check this example:

 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 object is removed then we should get ride of it's reference
            // otherwise it will remain on memory and will survive GC
            if (_verticalLine.IsAlive is false)
            {
                _verticalLine = null;

                Print("Object reference removed");
            }
        }

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

Attach the indicator on a chart, it will draw a vertical interactive line on last bar, and it prints true for IsAlive property.

Then remove the line and you will it prints false for IsAlive and then it prints "Object reference removed".

If you keep reference to a dead chart object then it will cause memory leak, because GC will consider the object alive and it will survive the GC.

Be sure to use Chart ObjectsRemoved event with objects IsAlive property to avoid memory leak issue.

Bar Index or Time?

When drawing chart objects you might get confused to use bar indices or time for X coordinate.

It's better to use time because when drawing something that extends to the future there is no valid bar index, or when you draw something that much take into account the space in between bars.

For simple cases use bar index.

All Chart.Draw*** methods have different overloads for both bar index and time.

Now let's give you some examples of drawing chart objects.

Drawing Inside Indicator Window

You are not limited to main chart, you can also draw chart objects inside any of the attached indicator windows on a chart.

Chart has an IndicatorAreas collection, all non-overlay or separate window indicator areas of chart are inside that collection.

You can also access your current indicator area just by using IndicatorArea property of your Indicator class, example:

 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)
        {
        }
    }
}

Same drawing methods are available for indicator areas, as both Chart and IndicatorArea are derived from ChartArea base class, and they inherit same drawing methods.

Static Text

We chose this to be the first because it differs from other chart objects, instead of using X and Y coordinates for positioning it uses static chart horizontal and vertical alignments.

To show or draw a static text object on a chart you use the ChartArea DrawStaticText method:

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

If you compile and attach the above indicator on a cTrader chart you will see this:

Image title

I recommend you to play a little bit with DrawStaticText method parameters, try to change the alignments or color.

Vertical Lines

To draw a vertical line we use Chart DrawVerticalLine method:

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

Horizontal Line

To draw an horizontal line we use Chart DrawHorizontalLine method:

1
2
// We use ten last bars highest high
var horizontalLine = Chart.DrawHorizontalLine("line", Bars.HighPrices.Maximum(10), Color.Red);

Trend Line

A trend line is a line that starts from a point on chart and ends on another, you will use it a lot for creaking different shapes or complex patterns.

To draw an trend line we use Chart DrawTrendLine method:

1
2
3
4
// We draw a line from low of the first visible bar to high 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);
// Or
var trendLine = Chart.DrawTrendLine("line", Bars.OpenTimes[Chart.FirstVisibleBarIndex], Bars.LowPrices[Chart.FirstVisibleBarIndex], Bars.OpenTimes[Chart.LastVisibleBarIndex], Bars.HighPrices[Chart.LastVisibleBarIndex], Color.Red);

Rectangle

To draw rectangle we use Chart DrawRectangle method:

1
2
3
4
5
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 it's current color, we change only the alpha channel
rectangle.IsFilled = true;
rectangle.Color = Color.FromArgb(80, rectangle.Color);

Triangle

To draw a triangle we use Chart DrawTriangle method:

1
2
3
4
5
6
7
8
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
triangle.IsFilled = true;
triangle.Color = Color.FromArgb(80, triangle.Color);

Other Chart Objects

There are other chart objects that we didn't mentioned for the sake of brevity, like:

  • Ellipse
  • Icon
  • Andrews Pitchfork
  • Equidistant Channel
  • Fibonacci Expansion
  • Fibonacci Fan
  • Fibonacci Retracement

We might add more chart objects later, to be updated use the references.

All of them have similar usage, they have a Chart.Draw*** method which will accept similar parameters.


Last update: July 1, 2022

Comments