Saltar a contenido

Objetos de gráfico y trazados

Los objetos de gráfico (trazados) permiten dibujar líneas o formas geométricas en los gráficos de cTrader. Al usarlos, puede dibujar patrones o mostrar ciertos eventos en los gráficos basados en los datos de su cBot o indicador.

Los objetos del gráfico utilizan coordenadas X e Y para el posicionamiento.

  • El eje X representa el tiempo del gráfico o los índices de barras.
  • El eje Y es el precio del símbolo.

Todos los objetos del gráfico se derivan de la clase base ChartObject, lo que significa que todos ellos heredan ciertas características base.

Ejemplos de código de objetos del gráfico

Dibujar dentro de las ventanas de indicadores

Al crear objetos del gráfico, no está limitado al gráfico principal del símbolo. De hecho, puede dibujar objetos del gráfico dentro de cualquier ventana que contenga salidas de indicadores.

La clase Chart tiene la colección IndicatorAreas. Contiene todas las ventanas no superpuestas o separadas en las que los indicadores pueden mostrar sus salidas.

También puede acceder a su área de indicador actual utilizando la propiedad IndicatorArea de su clase 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)
        {
        }
    }
}

Cuando ejecute una instancia del indicador anterior, debería ver una línea roja en una ventana de indicador separada. Al crear gráficos en áreas de indicadores separadas, puede utilizar todos los métodos de dibujo, ya que tanto Chart como IndicatorArea heredan de la clase base ChartArea.

Texto estático

En lugar de utilizar coordenadas X e Y para el posicionamiento, el texto estático utiliza alineaciones horizontales y verticales estáticas. Para mostrar o dibujar un texto estático, utilice el método DrawStaticText().

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

Si adjunta este objeto del gráfico a un indicador y ejecuta una instancia, verá el siguiente texto en el gráfico principal.

Image title

Línea vertical

Utilice el método DrawVerticalLine() para dibujar una línea 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);

Línea horizontal

Utilice el método DrawHorizontalLine() para dibujar una línea 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);

Línea de tendencia

Una línea de tendencia comienza desde un punto determinado en el gráfico y termina en otro punto. Las líneas de tendencia son útiles para crear diferentes formas o patrones complejos.

Para dibujar una línea de tendencia, utilice el 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);

Rectángulo

Utilice el método DrawRectangle() para dibujar un rectá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

Utilice el método DrawTriangle() para dibujar un 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);

Otros objetos del gráfico

Por razones de brevedad, no mencionamos varios otros objetos del gráfico en los fragmentos de código anteriores. Estos objetos incluyen, pero no se limitan a los siguientes:

  • Elipse
  • Icono
  • Horquilla de Andrews
  • Canal equidistante
  • Expansión de Fibonacci
  • Abanico de Fibonacci
  • Retroceso de Fibonacci

Todos estos objetos se pueden dibujar utilizando métodos Draw...() con nombres similares que aceptan parámetros similares.

Riesgo-recompensa

La interfaz ChartRiskReward proporciona tipos que le permiten crear y gestionar objetos de riesgo-recompensa programáticamente en los gráficos.

El código a continuación le muestra cómo crear un indicador que dibuja un objeto de riesgo-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)
        {
        }
    }
}

Configuraciones clave de objetos

Nombrar objetos del gráfico

Siempre que intente dibujar un objeto del gráfico, debe proporcionar su nombre como argumento para el método de dibujo.

Todos los nombres de objetos del gráfico deben ser únicos. Si no se cumple este requisito, se corre el riesgo de que los objetos del gráfico sobrescriban objetos del gráfico con los mismos nombres dependiendo de sus tiempos de ejecución. Puede utilizar el valor del índice de barra actual o el tiempo actual para generar nombres únicos para cada objeto.

Acceder a objetos del gráfico

Todos los objetos del gráfico están contenidos dentro de la colección Objects. Esta colección incluye objetos dibujados por el usuario. Como resultado, se puede acceder a la colección Objects para eliminar objetos de los gráficos o modificar sus propiedades.

El ejemplo a continuación accede a los miembros de la colección 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

Los objetos del gráfico tienen varios eventos que puede utilizar para saber qué objetos se dibujan, actualizan o eliminan:

  • ObjectsAdded - se activa cuando se añaden uno o más objetos del gráfico a un gráfico.
  • ObjectsRemoved - se activa cuando se eliminan uno o más objetos del gráfico de un gráfico.
  • ObjectsUpdated - se activa cuando se actualizan uno o más objetos del gráfico (una de sus propiedades es cambiada por el usuario o el indicador o cBot activo).
  • ObjectsSelectionChanged - se activa cuando el usuario selecciona uno o más objetos del gráfico.
  • ObjectHoverChanged - se activa cuando el cursor del ratón se desplaza sobre un objeto del gráfico.

El siguiente ejemplo utiliza los 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 interactivos y no interactivos

Al trabajar con objetos interactivos, los usuarios pueden cambiar sus propiedades como la posición del objeto, el color, el comentario, etc. Todos los objetos dibujados por el usuario son interactivos por defecto.

Nota

La propiedad ChartStaticText no se puede cambiar independientemente de si su objeto relacionado es interactivo.

Para hacer que un objeto sea interactivo, establezca su propiedad IsInteractive en true como se muestra a continuación:

 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 los objetos del gráfico tienen la propiedad IsInteractive. Su valor predeterminado es false.

Si un objeto del gráfico es interactivo, no se eliminará cuando se elimine o detenga una instancia de indicador o cBot. Por el contrario, los objetos no interactivos se eliminan automáticamente cuando un indicador o cBot deja de funcionar.

Para evitar el desorden, asegúrese de limpiar los objetos interactivos después de que se elimine su instancia relacionada utilizando los métodos Destroy del indicador o OnStop del cBot.

Si un objeto del gráfico no es interactivo, también será invisible en las listas y colecciones de objetos del gráfico.

Objetos bloqueados y desbloqueados

Bloquear un objeto del gráfico impide que el usuario lo modifique o actualice. Puede hacerlo a través del cuadro Trader (Propiedades del gráfico) o estableciendo la propiedad IsLocked en true. El valor predeterminado es false.

Puede utilizar el bloqueo para hacer que un objeto sea interactivo pero al mismo tiempo impedir que el usuario lo actualice. El siguiente ejemplo bloquea un objeto de línea 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 y ocultar

Puede dibujar un objeto en el gráfico y, posteriormente, ocultarlo. Aunque el objeto seguirá presente en el gráfico, será completamente invisible.

Para hacerlo, establezca la propiedad IsHidden en 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)
        {
        }
    }
}

El uso de recursos es la consideración principal para utilizar esta función. Si hay un objeto que debe aparecer con frecuencia en el gráfico (pero no todo el tiempo), es mejor ocultarlo en lugar de eliminarlo y volver a dibujarlo cada vez que se necesite.

Selección de objetos e índice de apariencia (ZIndex)

Naturalmente, puede haber casos en los que varios objetos se intersecten entre sí en un gráfico, lo que dificulta o imposibilita la selección de un objeto específico. Solo el objeto que se dibujó en último lugar será seleccionable al pasar el cursor del ratón sobre un grupo de objetos del gráfico que se intersectan.

Para cambiar este comportamiento, puede utilizar la propiedad ZIndex. Puede ser útil cuando se intenta mostrar patrones complejos de objetos del 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)
        {
        }
    }
}

Una vez adjunto a un gráfico, el indicador anterior mostrará una línea vertical roja en lugar de una amarilla. Como el valor de la propiedad ZIndex de la primera línea es mayor que el valor correspondiente de la segunda línea, tiene prioridad sobre la segunda línea (amarilla).

En otras palabras, la propiedad ZIndex determina qué objetos del gráfico se muestran primero cuando se superponen. A todos los objetos del gráfico dibujados se les asigna automáticamente un valor determinado para la propiedad ZIndex.

Saber si un objeto ha sido eliminado

Todos los objetos del gráfico heredan la propiedad IsAlive de la clase base ChartObject. El valor de esta propiedad es true mientras un objeto esté presente en el gráfico (independientemente de si es visible o invisible). El valor se establece en false tan pronto como se elimina un objeto del gráfico.

Si guarda una referencia a un objeto del gráfico y el usuario elimina este objeto, puede comprobar la propiedad IsAlive para verificar si un objeto está vivo o muerto.

 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 ejecuta una instancia de este indicador, haga clic con el botón derecho en la línea roja y elimínela. El registro debería mostrar entonces el mensaje "Object reference removed".

Si mantiene una referencia a un objeto de gráfico (muerto), se producirá una fuga de memoria. Durante la recolección de basura, su objeto seguirá considerándose vivo, lo que significa que sobrevivirá al proceso de recolección.

Para evitar este problema, utilice el evento ObjectsRemoved en combinación con la propiedad IsAlive.

Índice de barra o tiempo

Al codificar objetos de gráfico, puede utilizar el tiempo del gráfico o el índice de barra para el eje X.

En nuestra opinión, el tiempo del gráfico es la mejor opción. Al utilizar índices de barra, no puede planificar valores futuros (porque los índices requeridos aún no existen) ni tener en cuenta los espacios entre barras. Sin embargo, los índices de barra pueden ser más fáciles de usar, especialmente en el caso de objetos de gráfico relativamente simples.

Todos los métodos Chart.Draw tienen diferentes sobrecargas para índices de barra y tiempo de gráfico.