Перейти к содержанию

Расширенные операции с индикаторами

Эта статья дополняет наш обширный список примеров кода индикаторов. Мы расширяем некоторые концепции, упомянутые в этих примерах кода, и обсуждаем несколько расширенных функций, которые вы можете реализовать при создании новых индикаторов.

Атрибут облака

Вы, вероятно, видели прозрачные облака на торговых графиках.

Image title

Вы можете добавить облака к выходным данным вашего индикатора, используя атрибут класса CloudAttribute, как показано в примере ниже:

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

Конструктор CloudAttribute принимает два имени выходных линий. После этого он автоматически строит облако, соответствующее пространству между этими двумя выходами.

Вы также можете установить непрозрачность облака, используя свойство Opacity. Чтобы настроить цвет облака, используйте свойство FirstColor. По умолчанию цвет облака будет соответствовать цвету первой линии в выходных данных индикатора.

Работа с цветами

Algo API включает enum Color, который можно использовать для настройки цветов объектов Chart, элементов управления графиком и выходных данных.

Значения enum Color представляют часто используемые цвета. Вы можете использовать их без необходимости работать с шестнадцатеричными кодами или кодами цветов ARGB.

При настройке выходных данных вы можете установить их цвета, используя строковое свойство LineColor. Как показано ниже, оно принимает как именованные цвета, так и шестнадцатеричные коды цветов.

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

Примечание

Цвета также могут рассматриваться как настраиваемые параметры. Чтобы позволить пользователям выбирать пользовательские цвета (например, цвета линий, нарисованных индикатором), объявите параметр типа Color.

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

В приведенном ниже примере мы создаем простой индикатор (максимум минус минимум), который при инициализации отображает текст на торговом графике, к которому он прикреплен.

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

Типы выходных данных

Для пользовательских индикаторов доступно несколько различных типов выходных данных:

  • Line - непрерывная линия.
  • DiscontinuousLine - прерывистая линия, которая полезна в случаях, когда ваш индикатор не всегда имеет вычисленное значение.
  • Points - точка или точка для каждого бара.
  • Histogram - серия вертикальных столбцов. При использовании этого типа установите свойство IsOverlay вашего индикатора в false.

Чтобы установить тип выходных данных, используйте свойство PlotType, как показано ниже.

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

Параметры Enum

Тип enum необходим для создания параметров, которые имеют несколько предопределенных опций, из которых пользователи могут выбирать. Мы используем тип enum в следующем примере:

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

Если вы добавите этот параметр к индикатору или сиБоту, вы увидите интерактивное меню с несколькими опциями, позволяющее выбрать одно из указанных значений enum.

Работа со временем

Время платформы и сервера

Вы можете получить текущее время сервера, обратившись к свойствам Server.Time или Server.TimeInUtc.

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

Свойство Server.Time представляет текущее время в часовом поясе вашего индикатора или сиБота, установленном через свойство TimeZone.

Время открытия бара

Используйте коллекцию Bars.OpenTime, чтобы получить время открытия баров. Часовой пояс будет основан на часовом поясе, который вы указали в атрибуте класса TimeZone.

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

Смещение времени платформы

Используйте свойство Application.UserTimeOffset, чтобы получить часовой пояс платформы пользователя. Это в основном используется для преобразования времени вашего индикатора в часовой пояс пользователя.

1
var userPlatformTimeOffset = Application.UserTimeOffset;

Свойство Application.UserTimeOffset возвращает объект TimeSpan, представляющий смещение времени, установленное пользователем на его платформе cTrader, по сравнению со временем UTC.

Вы также можете получать уведомления, когда пользователь изменяет смещение времени своей платформы. Для этого используйте событие 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;
}

Получение времени с параметром

cTrader поддерживает специальные типы параметров даты и времени, которые позволяют получать строго типизированные значения даты и времени в качестве входных данных для ваших алгоритмов вместо использования типа параметра string.

Используя новые типы параметров даты и времени, вы можете получать значения в часовом поясе вашего алгоритма со встроенной проверкой минимальных и максимальных значений и полной поддержкой оптимизации, как и для других типов параметров.

Чтобы получить определенное значение времени через настраиваемый параметр, вы можете использовать следующие типы C#:

  • DateTime
  • DateOnly
  • TimeSpan

Ниже приведен пример того, как это можно сделать:

 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