Aller au contenu

Objets graphiques et dessins

Les objets graphiques (dessins) permettent de tracer des lignes ou des formes géométriques sur les graphiques cTrader. En les utilisant, vous pouvez dessiner des modèles ou afficher certains événements sur les graphiques en fonction des données de votre cBot ou de votre indicateur.

Les objets graphiques utilisent des coordonnées X et Y pour le positionnement.

  • L'axe X représente le temps du graphique ou les indices de barres.
  • L'axe Y est le prix du symbole.

Tous les objets graphiques sont dérivés de la classe de base ChartObject, ce qui signifie qu'ils héritent tous de certaines fonctionnalités de base.

Exemples de code d'objets graphiques

Dessiner dans les fenêtres d'indicateurs

Lors de la création d'objets graphiques, vous n'êtes pas limité au graphique de symboles principal. En fait, vous pouvez dessiner des objets graphiques dans toutes les fenêtres contenant des sorties d'indicateurs.

La classe Chart possède la collection IndicatorAreas. Elle contient toutes les fenêtres non superposées ou séparées dans lesquelles les indicateurs peuvent afficher leurs sorties.

Vous pouvez également accéder à votre zone d'indicateur actuelle en utilisant la propriété IndicatorArea de votre classe 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)
        {
        }
    }
}

Lorsque vous exécutez une instance de l'indicateur ci-dessus, vous devriez voir une ligne rouge dans une fenêtre d'indicateur séparée. Lors de la création de graphiques dans des zones d'indicateurs séparées, vous pouvez utiliser toutes les méthodes de dessin car Chart et IndicatorArea héritent tous deux de la classe de base ChartArea.

Texte statique

Au lieu d'utiliser des coordonnées X et Y pour le positionnement, le texte statique utilise des alignements horizontaux et verticaux statiques. Pour afficher ou dessiner un texte statique, utilisez la méthode DrawStaticText().

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

Si vous attachez cet objet graphique à un indicateur et exécutez une instance, vous verrez le texte suivant dans le graphique principal.

Image title

Ligne verticale

Utilisez la méthode DrawVerticalLine() pour tracer une ligne verticale.

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

Ligne horizontale

Utilisez la méthode DrawHorizontalLine() pour tracer une ligne horizontale.

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);

Ligne de tendance

Une ligne de tendance commence à un certain point du graphique et se termine à un autre point. Les lignes de tendance sont utiles pour créer différentes formes ou modèles complexes.

Pour tracer une ligne de tendance, utilisez la méthode 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);

Rectangle

Utilisez la méthode DrawRectangle() pour tracer un rectangle.

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);

Triangle

Utilisez la méthode DrawTriangle() pour tracer un triangle.

 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);

Autres objets graphiques

Par souci de concision, nous n'avons pas mentionné plusieurs autres objets graphiques dans les extraits de code ci-dessus. Ces objets incluent, sans s'y limiter, les éléments suivants :

  • Ellipse
  • Icône
  • Andrews Pitchfork
  • Canal équidistant
  • Extension de Fibonacci
  • Éventail de Fibonacci
  • Retracement de Fibonacci

Tous ces objets peuvent être dessinés à l'aide de méthodes Draw...() portant des noms similaires et acceptant des paramètres similaires.

Risque-rendement

L'interface ChartRiskReward fournit des types qui vous permettent de créer et de gérer des objets de risque-rendement par programmation sur les graphiques.

Le code ci-dessous vous montre comment créer un indicateur qui dessine un objet de risque-rendement :

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

Paramètres clés des objets

Nommer les objets graphiques

Chaque fois que vous essayez de dessiner un objet graphique, vous devez fournir son nom comme argument pour la méthode de dessin.

Tous les noms d'objets graphiques doivent être uniques. Si cette exigence n'est pas respectée, vous risquez que des objets graphiques remplacent des objets graphiques portant les mêmes noms en fonction de leurs temps d'exécution. Vous pouvez utiliser la valeur de l'indice de barre actuel ou l'heure actuelle pour générer des noms uniques pour chaque objet.

Accéder aux objets graphiques

Tous les objets graphiques sont contenus dans la collection Objects. Cette collection comprend les objets dessinés par l'utilisateur. Par conséquent, la collection Objects peut être consultée pour supprimer des objets des graphiques ou modifier leurs propriétés.

L'exemple ci-dessous accède aux membres de la collection 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)
        {
        }
    }
}

Événements

Les objets graphiques ont plusieurs événements que vous pouvez utiliser pour savoir quels objets sont dessinés, mis à jour ou supprimés :

  • ObjectsAdded - est déclenché lorsqu'un ou plusieurs objets graphiques sont ajoutés à un graphique.
  • ObjectsRemoved - est déclenché lorsqu'un ou plusieurs objets graphiques sont supprimés d'un graphique.
  • ObjectsUpdated - déclenché lorsqu'un ou plusieurs objets graphiques sont mis à jour (l'une de leurs propriétés est modifiée par l'utilisateur ou l'indicateur actif ou le cBot).
  • ObjectsSelectionChanged - déclenché lorsqu'un ou plusieurs objets graphiques sont sélectionnés par l'utilisateur.
  • ObjectHoverChanged - déclenché lorsque le curseur de la souris survole un objet graphique.

L'exemple suivant utilise les cinq types d'événements :

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

Objets interactifs et non interactifs

Lorsque vous travaillez avec des objets interactifs, les utilisateurs peuvent modifier leurs propriétés telles que la position de l'objet, la couleur, le commentaire, etc. Tous les objets dessinés par l'utilisateur sont interactifs par défaut.

Remarque

La propriété ChartStaticText ne peut pas être modifiée, que son objet associé soit interactif ou non.

Pour rendre un objet interactif, définissez sa propriété IsInteractive sur true comme indiqué ci-dessous :

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

Tous les objets graphiques ont la propriété IsInteractive. Sa valeur par défaut est false.

Si un objet graphique est interactif, il ne sera pas supprimé lorsqu'une instance d'indicateur ou de cBot est supprimée ou arrêtée. En revanche, les objets non interactifs sont supprimés automatiquement lorsqu'un indicateur ou un cBot cesse de fonctionner.

Pour éviter l'encombrement, assurez-vous de nettoyer les objets interactifs après la suppression de leur instance associée en utilisant la méthode Destroy de l'indicateur ou la méthode OnStop du cBot.

Si un objet graphique n'est pas interactif, il sera également invisible dans les listes et les collections d'objets graphiques.

Objets verrouillés et déverrouillés

Le verrouillage d'un objet graphique empêche l'utilisateur de le modifier ou de le mettre à jour. Vous pouvez le faire via la boîte Trader (propriétés du graphique) ou en définissant la propriété IsLocked sur true. La valeur par défaut est false.

Vous pouvez utiliser le verrouillage pour rendre un objet interactif tout en empêchant l'utilisateur de le mettre à jour. L'exemple suivant verrouille un objet de ligne verticale :

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

Afficher et masquer

Vous pouvez dessiner un objet sur le graphique et, par la suite, le masquer. Bien que l'objet soit toujours présent sur le graphique, il sera complètement invisible.

Pour ce faire, définissez la propriété IsHidden sur 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)
        {
        }
    }
}

L'utilisation des ressources est la principale considération pour l'utilisation de cette fonctionnalité. S'il existe un objet qui doit apparaître fréquemment sur le graphique (mais pas tout le temps), il est préférable de le masquer au lieu de le supprimer et de le redessiner chaque fois qu'il est nécessaire.

Sélection d'objets et indice d'apparence (ZIndex)

Naturellement, il peut y avoir des cas où plusieurs objets se croisent sur un graphique, ce qui rend difficile, voire impossible, la sélection d'un objet spécifique. Seul l'objet qui a été dessiné en dernier sera sélectionnable en survolant votre curseur de souris sur un groupe d'objets graphiques qui se croisent.

Pour modifier ce comportement, vous pouvez utiliser la propriété ZIndex. Elle peut être utile lorsque vous essayez d'afficher des motifs complexes d'objets graphiques.

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

Une fois attaché à un graphique, l'indicateur ci-dessus affichera une ligne verticale rouge plutôt qu'une ligne jaune. Comme la valeur de la propriété ZIndex de la première ligne est supérieure à la valeur correspondante de la deuxième ligne, elle a la priorité sur la deuxième ligne (jaune).

En d'autres termes, la propriété ZIndex détermine quels objets graphiques sont affichés en premier lorsqu'ils se chevauchent. Tous les objets graphiques dessinés se voient attribuer automatiquement une certaine valeur pour la propriété ZIndex.

Savoir si un objet est supprimé

Tous les objets graphiques héritent de la propriété IsAlive de la classe de base ChartObject. La valeur de cette propriété est true tant qu'un objet est présent sur le graphique (qu'il soit visible ou invisible). La valeur est définie sur false dès qu'un objet est supprimé du graphique.

Si vous enregistrez une référence à un objet graphique et que cet objet est supprimé par l'utilisateur, vous pouvez vérifier la propriété IsAlive pour vérifier si un objet est vivant ou mort.

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

Si vous exécutez une instance de cet indicateur, faites un clic droit sur la ligne rouge et supprimez-la. Le journal devrait alors afficher le message "Object reference removed".

Si vous conservez une référence à un objet graphique (mort), une fuite de mémoire se produira. Lors de la collecte des déchets, votre objet sera toujours considéré comme vivant, ce qui signifie qu'il survivra au processus de collecte.

Pour éviter ce problème, utilisez l'événement ObjectsRemoved en combinaison avec la propriété IsAlive.

Indice de barre ou heure

Lors du codage d'objets graphiques, vous pouvez utiliser soit l'heure du graphique, soit l'indice de barre pour l'axe X.

À notre avis, l'heure du graphique est la meilleure option. Lorsque vous utilisez des indices de barre, vous ne pouvez pas planifier de valeurs futures (car les indices requis n'existent pas encore) et ne pouvez pas tenir compte des espaces entre les barres. Cependant, les indices de barre peuvent être plus faciles à utiliser, en particulier dans le cas d'objets graphiques relativement simples.

Toutes les méthodes Chart.Draw ont différentes surcharges pour les indices de barre et l'heure du graphique.