Ir para o conteúdo

Operações avançadas com indicadores

Este artigo complementa a nossa extensa lista de amostras de código de indicadores. Expandimos alguns conceitos mencionados nestas amostras de código e discutimos várias funcionalidades avançadas que pode implementar ao criar novos indicadores.

O atributo cloud

Provavelmente já viu nuvens transparentes em gráficos de negociação.

Image title

Pode adicionar nuvens às saídas do seu indicador usando o atributo de classe CloudAttribute como mostrado no exemplo abaixo:

 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
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
using cAlgo.API;
using cAlgo.API.Indicators;
using System;

namespace cAlgo
{
    /// <summary>
    /// This indicator shows how to make a built-in cTrader indicator multi time frame and how to use cloud attribute
    /// </summary>
    [Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None), Cloud("Top", "Bottom", Opacity = 0.2)]
    public class BollingerBandsMTFCloudSample : Indicator
    {
        private BollingerBands _bollingerBands;

        private Bars _baseBars;

        [Parameter("Base TimeFrame", DefaultValue = "Daily")]
        public TimeFrame BaseTimeFrame { get; set; }

        [Parameter("Source", DefaultValue = DataSeriesType.Close)]
        public DataSeriesType DataSeriesType { get; set; }

        [Parameter("Periods", DefaultValue = 14, MinValue = 0)]
        public int Periods { get; set; }

        [Parameter("Standard Deviation", DefaultValue = 2, MinValue = 0)]
        public double StandardDeviation { get; set; }

        [Parameter("MA Type", DefaultValue = MovingAverageType.Simple)]
        public MovingAverageType MaType { get; set; }

        [Output("Main", LineColor = "Yellow", PlotType = PlotType.Line, Thickness = 1)]
        public IndicatorDataSeries Main { get; set; }

        [Output("Top", LineColor = "Red", PlotType = PlotType.Line, Thickness = 1)]
        public IndicatorDataSeries Top { get; set; }

        [Output("Bottom", LineColor = "Red", PlotType = PlotType.Line, Thickness = 1)]
        public IndicatorDataSeries Bottom { get; set; }

        protected override void Initialize()
        {
            _baseBars = MarketData.GetBars(BaseTimeFrame);

            var baseSeries = GetBaseSeries();

            _bollingerBands = Indicators.BollingerBands(baseSeries, Periods, StandardDeviation, MaType);
        }

        public override void Calculate(int index)
        {
            var baseIndex = _baseBars.OpenTimes.GetIndexByTime(Bars.OpenTimes[index]);

            Main[index] = _bollingerBands.Main[baseIndex];
            Top[index] = _bollingerBands.Top[baseIndex];
            Bottom[index] = _bollingerBands.Bottom[baseIndex];
        }

        private DataSeries GetBaseSeries()
        {
            switch (DataSeriesType)
            {
                case DataSeriesType.Open:
                    return _baseBars.OpenPrices;

                case DataSeriesType.High:
                    return _baseBars.HighPrices;

                case DataSeriesType.Low:
                    return _baseBars.LowPrices;

                case DataSeriesType.Close:
                    return _baseBars.ClosePrices;
                default:

                    throw new ArgumentOutOfRangeException("DataSeriesType");
            }
        }
    }

    public enum DataSeriesType
    {
        Open,
        High,
        Low,
        Close
    }
}

O construtor CloudAttribute recebe dois nomes de linhas de saída. Depois, ele automaticamente desenha a nuvem para corresponder ao espaço entre estas duas saídas.

Também pode definir a opacidade da nuvem usando a propriedade Opacity. Para definir a cor da nuvem, use a propriedade FirstColor. Por padrão, a cor da nuvem corresponderá à cor da primeira linha na saída do indicador.

Trabalhar com cores

A API Algo inclui o enum Color que pode ser usado para configurar as cores para objetos Chart, controlos de gráfico e saídas.

Os valores do enum Color representam cores comumente usadas. Pode usá-los sem ter que lidar com códigos de cor hexadecimais ou ARGB.

Ao personalizar saídas, pode definir suas cores usando a propriedade string LineColor. Como mostrado abaixo, ela aceita tanto cores nomeadas quanto códigos de cor hexadecimais.

1
2
3
4
_ = Chart.DrawStaticText("NamedColor", "This is text using Color class color name properties", VerticalAlignment.Center, HorizontalAlignment.Center, Color.Red);
_ = Chart.DrawStaticText("HexadecimalColor", "This is text using Hexadecimal color", VerticalAlignment.Bottom, HorizontalAlignment.Center, Color.FromHex("#FF5733"));
_ = Chart.DrawStaticText("ARGBColor", "This is text using ARGB color", VerticalAlignment.Top, HorizontalAlignment.Center, Color.FromArgb(255, 200, 100, 60));
_ = Chart.DrawStaticText("ParsedNameColor", "This is text using color name by parsing it from string", VerticalAlignment.Center, HorizontalAlignment.Left, Color.FromName("Yellow"));
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
var stackPanel = new StackPanel
{
    Orientation = Orientation.Vertical,
    HorizontalAlignment = HorizontalAlignment.Center,
    VerticalAlignment = VerticalAlignment.Center
};

stackPanel.AddChild(new TextBlock { Text = "Red Color property", BackgroundColor = Color.Red });
stackPanel.AddChild(new TextBlock { Text = "Hexadecimal Color code", BackgroundColor = Color.FromHex("#FF5733") });
stackPanel.AddChild(new TextBlock { Text = "ARGB Color", BackgroundColor = Color.FromArgb(200, 100, 40, 80) });
stackPanel.AddChild(new TextBlock { Text = "Color Name", BackgroundColor = Color.FromName("Green") });

Chart.AddControl(stackPanel);
1
2
3
4
5
[Output("Hexadecimal", LineColor = "#FF5733", PlotType = PlotType.Line, Thickness = 1)]
public IndicatorDataSeries Hexadecimal { get; set; }

[Output("Name", LineColor = "Red", PlotType = PlotType.Line, Thickness = 1)]
public IndicatorDataSeries Name { get; set; }

Nota

As cores também podem ser tratadas como parâmetros personalizáveis. Para permitir que os utilizadores selecionem cores personalizadas (por exemplo, as cores das linhas desenhadas por um indicador), declare um parâmetro do tipo Color.

1
2
[Parameter("Drawing Color", DefaultValue = "#f54242")]
public Color DrawingColor { get; set; }

No exemplo abaixo, criamos um indicador simples (máximo menos mínimo) que, ao ser inicializado, exibe texto no gráfico de negociação ao qual está anexado.

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

namespace cAlgo
{
    [Indicator(IsOverlay = false, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class HighMinusLowColor: Indicator
    {
        [Parameter("Text Color", DefaultValue="#f54242")]
        public Color TextColor { get; set; }

        public override void Initialize()
        {
            var staticText = Chart.DrawStaticText("static", "This text shows how color parameters work", VerticalAlignment.Center, HorizontalAlignment.Center, TextColor);
        }
    }
}

Tipos de saída

Existem vários tipos diferentes de saída disponíveis para indicadores personalizados:

  • Line - uma linha contínua.
  • DiscontinuousLine - uma linha não contínua que é útil para casos em que o seu indicador nem sempre tem um valor de cálculo.
  • Points - um ponto ou um ponto para cada barra.
  • Histogram - uma série de barras verticais. Ao usar este tipo, defina a propriedade IsOverlay do seu indicador como false.

Para definir um tipo de saída, use a propriedade PlotType como demonstrado abaixo.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
[Output("Line", PlotType = PlotType.Line)]
public IndicatorDataSeries Line { get; set; }

[Output("Discontinuous Line", PlotType = PlotType.DiscontinuousLine)]
public IndicatorDataSeries DiscontinuousLine { get; set; }

[Output("Points", PlotType = PlotType.Points)]
public IndicatorDataSeries Points { get; set; }

[Output("Histogram", PlotType = PlotType.Histogram)]
public IndicatorDataSeries Histogram { get; set; }

Parâmetros enum

O tipo enum é necessário para criar parâmetros que têm várias opções predefinidas das quais os utilizadores podem escolher. Usamos o tipo enum no seguinte exemplo:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
public enum Options
{
    First,
    Second,
    Third,
    Fourth
}

[Parameter("Options", DefaultValue = Options.Third)]
public Options OptionsParameter { get; set; }

Se adicionar este parâmetro a um indicador ou cBot, verá um menu interativo com várias opções que permite escolher um dos valores enum especificados.

Trabalhar com tempo

Tempo da plataforma e do servidor

Pode obter o tempo atual do servidor acedendo às propriedades Server.Time ou Server.TimeInUtc.

1
2
var currentServerTimeInIndicatorTimeZone = Server.Time;
var currentServerTimeInUtc = Server.TimeInUtc;

A propriedade Server.Time representa o tempo atual no fuso horário do seu indicador ou cBot estabelecido através da propriedade TimeZone.

Hora de abertura da barra

Utilize a coleção Bars.OpenTime para obter as horas de abertura das barras. O fuso horário será baseado no fuso horário que especificou no atributo da classe TimeZone.

1
2
3
4
public override void Calculate(int index)
{
    var barTime = Bars.OpenTimes[index];
}

Desvio horário da plataforma

Utilize a propriedade Application.UserTimeOffset para obter o fuso horário da plataforma do utilizador. Isto é utilizado principalmente para converter o tempo do seu indicador para o fuso horário do utilizador.

1
var userPlatformTimeOffset = Application.UserTimeOffset;

A propriedade Application.UserTimeOffset retorna um objeto TimeSpan que representa o desvio horário definido pelo utilizador na sua plataforma cTrader em comparação com o tempo UTC.

Também pode optar por ser notificado quando um utilizador altera o desvio horário da sua plataforma. Para tal, utilize o evento Application.UserTimeOffsetChanged.

1
2
3
4
5
6
7
8
9
protected override void Initialize()
{
    Application.UserTimeOffsetChanged += Application_UserTimeOffsetChanged;
}

private void Application_UserTimeOffsetChanged(UserTimeOffsetChangedEventArgs obj)
{
    var platformTimeOffset = obj.UserTimeOffset;
}

Obter tempo com um parâmetro

O cTrader suporta tipos de parâmetros dedicados para data e hora que permitem obter valores de data e hora fortemente tipados como entrada para os seus algos, em vez de utilizar o tipo de parâmetro string.

Ao utilizar os novos tipos de parâmetros de data e hora, pode obter valores no fuso horário do seu algo com validação mínima e máxima integrada e suporte total de otimização, tal como outros tipos de parâmetros.

Para obter um determinado valor de tempo através de um parâmetro personalizável, pode utilizar estes tipos de C#:

  • DateTime
  • DateOnly
  • TimeSpan

Abaixo está um exemplo de como isto pode ser feito:

 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
using cAlgo.API;
using System;

namespace cAlgo
{
    [Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class Sample : Indicator
    {
        [Parameter("DateTime Parameter", MinValue = "1970-01-01T00:00:00", MaxValue = "2025-11-01T00:00:00", DefaultValue = "2025-01-01T10:00:00")]
        public DateTime DateTimeParameter { get; set; }

        [Parameter("DateOnly Parameter", MinValue = "1970-01-01", MaxValue = "2025-11-01", DefaultValue = "2025-01-01")]
        public DateOnly DateOnlyParameter { get; set; }

        [Parameter("TimeSpan Parameter", MinValue = "00:00:00", MaxValue = "23:59:59", DefaultValue = "04:10:20")]
        public TimeSpan TimeSpanParameter { get; set; }

        protected override void Initialize()
        {
            Print($"DateTimeParameter: {DateTimeParameter:o}");
            Print($"DateOnlyParameter: {DateOnlyParameter:o}");
            Print($"TimeSpanParameter: {TimeSpanParameter}");
        }

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

Image title