Ir para o conteúdo

Objetos e desenhos do gráfico

Os objetos do gráfico (desenhos) permitem desenhar linhas ou formas geométricas nos gráficos do cTrader. Ao utilizá-los, pode desenhar padrões ou mostrar determinados eventos nos gráficos com base nos dados do seu cBot ou indicador.

Os objetos do gráfico utilizam coordenadas X e Y para o posicionamento.

  • O eixo X representa o tempo do gráfico ou os índices das barras.
  • O eixo Y é o preço do símbolo.

Todos os objetos do gráfico são derivados da classe base ChartObject, o que significa que todos eles herdam determinadas características base.

Amostras de código de objetos do gráfico

Desenhar dentro das janelas do indicador

Ao criar objetos do gráfico, não está limitado ao gráfico do símbolo principal. Na verdade, pode desenhar objetos do gráfico dentro de quaisquer janelas que contenham resultados do indicador.

A classe Chart tem a coleção IndicatorAreas. Contém todas as janelas não sobrepostas ou separadas nas quais os indicadores podem exibir os seus resultados.

Também pode aceder à sua área de indicador atual utilizando a propriedade IndicatorArea da sua 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)
        {
        }
    }
}

Quando executa uma instância do indicador acima, deverá ver uma linha vermelha numa janela de indicador separada. Ao criar gráficos em áreas de indicador separadas, pode utilizar todos os métodos de desenho, uma vez que tanto Chart como IndicatorArea herdam da classe base ChartArea.

Texto estático

Em vez de utilizar coordenadas X e Y para o posicionamento, o texto estático utiliza alinhamentos horizontais e verticais estáticos. Para mostrar ou desenhar um texto estático, utilize o método DrawStaticText().

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

Se anexar este objeto do gráfico a um indicador e executar uma instância, verá o seguinte texto no gráfico principal.

Image title

Linha vertical

Utilize o método DrawVerticalLine() para desenhar uma linha vertical.

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

Linha horizontal

Utilize o método DrawHorizontalLine() para desenhar uma linha horizontal.

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

Linha de tendência

Uma linha de tendência começa num determinado ponto do gráfico e termina noutro ponto. As linhas de tendência são úteis para criar diferentes formas ou padrões complexos.

Para desenhar uma linha de tendência, utilize o método 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);

Retângulo

Utilize o método DrawRectangle() para desenhar um retângulo.

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

Triângulo

Utilize o método DrawTriangle() para desenhar um triângulo.

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

Outros objetos do gráfico

Por uma questão de brevidade, não mencionámos vários outros objetos do gráfico nos fragmentos de código acima. Estes objetos incluem, entre outros, os seguintes:

  • Elipse
  • Ícone
  • Garfo de Andrews
  • Canal equidistante
  • Expansão de Fibonacci
  • Leque de Fibonacci
  • Retração de Fibonacci

Todos estes objetos podem ser desenhados utilizando métodos Draw...() com nomes semelhantes que aceitam parâmetros semelhantes.

Risco/recompensa

A interface ChartRiskReward fornece tipos que permitem criar e gerir objetos de risco/recompensa programaticamente nos gráficos.

O código abaixo mostra como criar um indicador que desenha um objeto de risco/recompensa:

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

Definições principais do objeto

Nomear objetos do gráfico

Sempre que tentar desenhar um objeto do gráfico, tem de fornecer o seu nome como argumento para o método de desenho.

Todos os nomes dos objetos do gráfico têm de ser únicos. Se este requisito não for cumprido, corre o risco de os objetos do gráfico substituírem objetos do gráfico com os mesmos nomes, dependendo dos seus tempos de execução. Pode utilizar o valor do índice da barra atual ou a hora atual para gerar nomes únicos para cada objeto.

Aceder a objetos do gráfico

Todos os objetos do gráfico estão contidos na coleção Objects. Esta coleção inclui objetos desenhados pelo utilizador. Como resultado, é possível aceder à coleção Objects para remover objetos dos gráficos ou modificar as suas propriedades.

O exemplo abaixo acede aos membros da coleção 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)
        {
        }
    }
}

Eventos

Os objetos do gráfico têm vários eventos que pode utilizar para saber quais os objetos que são desenhados, atualizados ou removidos:

  • ObjectsAdded - é acionado quando um ou mais objetos do gráfico são adicionados a um gráfico.
  • ObjectsRemoved - é acionado quando um ou mais objetos do gráfico são removidos de um gráfico.
  • ObjectsUpdated - acionado quando um ou mais objetos do gráfico são atualizados (uma das suas propriedades é alterada pelo utilizador ou pelo indicador ou cBot ativo).
  • ObjectsSelectionChanged - acionado quando um ou mais objetos do gráfico são selecionados pelo utilizador.
  • ObjectHoverChanged - acionado quando o cursor do rato passa por cima de um objeto do gráfico.

O exemplo seguinte utiliza os cinco tipos de eventos:

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

Objetos interativos e não interativos

Ao trabalhar com objetos interativos, os utilizadores podem alterar as suas propriedades, como a posição do objeto, cor, comentário, etc. Todos os objetos desenhados pelo utilizador são interativos por predefinição.

Nota

A propriedade ChartStaticText não pode ser alterada, independentemente de o objeto relacionado ser interativo ou não.

Para tornar um objeto interativo, defina a sua propriedade IsInteractive como true, conforme mostrado abaixo:

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

Todos os objetos do gráfico têm a propriedade IsInteractive. O seu valor predefinido é false.

Se um objeto do gráfico for interativo, não será removido quando uma instância de indicador ou cBot for removida ou parada. Por outro lado, os objetos não interativos são removidos automaticamente quando um indicador ou cBot deixa de funcionar.

Para evitar desordem, certifique-se de limpar os objetos interativos após a remoção da instância relacionada, utilizando os métodos Destroy do indicador ou OnStop do cBot.

Se um objeto do gráfico não for interativo, também será invisível em listas e coleções de objetos do gráfico.

Objetos bloqueados e desbloqueados

Bloquear um objeto do gráfico impede que o utilizador o modifique ou atualize. Pode fazê-lo através da caixa Trader (propriedades do gráfico) ou definindo a propriedade IsLocked como true. O valor predefinido é false.

Pode usar o bloqueio para tornar um objeto interativo, mas ao mesmo tempo impedir que o utilizador o atualize. O exemplo seguinte bloqueia um objeto de linha vertical:

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

Mostrar e ocultar

Pode desenhar um objeto no gráfico e, posteriormente, ocultá-lo. Embora o objeto ainda esteja presente no gráfico, ficará completamente invisível.

Para tal, defina a propriedade IsHidden como 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)
        {
        }
    }
}

O uso de recursos é a principal consideração para utilizar esta funcionalidade. Se houver um objeto que deva aparecer frequentemente no gráfico (mas não o tempo todo), é melhor ocultá-lo em vez de removê-lo e redesenhá-lo sempre que for necessário.

Seleção de objetos e índice de aparência (ZIndex)

Naturalmente, podem ocorrer casos em que vários objetos se cruzam no gráfico, tornando difícil ou impossível selecionar um objeto específico. Apenas o objeto que foi desenhado por último será selecionável ao passar o cursor do rato sobre um grupo de objetos do gráfico que se cruzam.

Para alterar este comportamento, pode usar a propriedade ZIndex. Pode ser útil ao tentar exibir padrões complexos de objetos do gráfico.

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

Uma vez anexado a um gráfico, o indicador acima exibirá uma linha vertical vermelha em vez de uma amarela. Como o valor da propriedade ZIndex da primeira linha é maior que o valor correspondente da segunda linha, ela tem precedência sobre a segunda linha (amarela).

Por outras palavras, a propriedade ZIndex determina quais objetos do gráfico são exibidos primeiro quando se sobrepõem. Todos os objetos do gráfico desenhados recebem automaticamente um determinado valor para a propriedade ZIndex.

Saber se um objeto foi removido

Todos os objetos do gráfico herdam a propriedade IsAlive da classe base ChartObject. O valor desta propriedade é true enquanto um objeto estiver presente no gráfico (independentemente de estar visível ou invisível). O valor é definido como false assim que um objeto é removido do gráfico.

Se guardar uma referência a um objeto do gráfico e este objeto for removido pelo utilizador, pode verificar a propriedade IsAlive para saber se um objeto está vivo ou morto.

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

Se executar uma instância deste indicador, clique com o botão direito do rato na linha vermelha e remova-a. O registo deve então exibir a mensagem "Object reference removed".

Se mantiver uma referência a um objeto do gráfico (morto), ocorrerá uma fuga de memória. Durante a recolha de lixo, o seu objeto ainda será considerado vivo, o que significa que sobreviverá ao processo de recolha.

Para evitar este problema, use o evento ObjectsRemoved em combinação com a propriedade IsAlive.

Índice de barra ou tempo

Ao codificar objetos do gráfico, pode usar o tempo do gráfico ou o índice da barra para o eixo X.

Na nossa opinião, o tempo do gráfico é a melhor opção. Ao usar índices de barras, não é possível planear valores futuros (porque os índices necessários ainda não existem) e não é possível contabilizar espaços entre barras. No entanto, os índices de barras podem ser mais fáceis de usar, particularmente no caso de objetos do gráfico relativamente simples.

Todos os métodos Chart.Draw têm diferentes sobrecargas para índices de barras e tempo do gráfico.