Przejdź do treści

Zaawansowane operacje ze wskaźnikami

Ten artykuł uzupełnia naszą obszerną listę przykładów kodu wskaźników. Rozwijamy niektóre koncepcje wspomniane w tych przykładach kodu i omawiamy kilka zaawansowanych funkcji, które możesz zaimplementować podczas tworzenia nowych wskaźników.

Atrybut chmury

Prawdopodobnie widziałeś przezroczyste chmury na wykresach handlowych.

Image title

Możesz dodać chmury do wyników swojego wskaźnika, używając atrybutu klasy CloudAttribute, jak pokazano w poniższym przykładzie:

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

Konstruktor CloudAttribute przyjmuje dwie nazwy linii wyjściowych. Następnie automatycznie rysuje chmurę, aby dopasować przestrzeń między tymi dwoma wynikami.

Możesz również ustawić krycie chmury, używając właściwości Opacity. Aby ustawić kolor chmury, użyj właściwości FirstColor. Domyślnie kolor chmury będzie odpowiadał kolorowi pierwszej linii w wyniku wskaźnika.

Pracuj z kolorami

Algo API zawiera enum Color, który może być używany do konfigurowania kolorów dla obiektów Chart, kontrolek wykresu i wyników.

Wartości enum Color reprezentują powszechnie używane kolory. Możesz ich używać bez konieczności zajmowania się szesnastkowymi lub ARGB kodami kolorów.

Podczas dostosowywania wyników możesz ustawić ich kolory, używając właściwości ciągu LineColor. Jak pokazano poniżej, akceptuje ona zarówno nazwane kolory, jak i szesnastkowe kody kolorów.

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

Uwaga

Kolory mogą być również traktowane jako parametry konfigurowalne. Aby umożliwić użytkownikom wybór niestandardowych kolorów (na przykład kolorów linii rysowanych przez wskaźnik), zadeklaruj parametr typu Color.

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

W poniższym przykładzie tworzymy prosty wskaźnik (high minus low), który po zainicjowaniu wyświetla tekst na wykresie handlowym, do którego jest dołączony.

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

Typy wyników

Dostępnych jest kilka różnych typów wyników dla wskaźników niestandardowych:

  • Line - ciągła linia.
  • DiscontinuousLine - linia nieciągła, która jest przydatna w przypadkach, gdy wskaźnik nie zawsze ma wartość obliczeniową.
  • Points - punkt lub kropka dla każdego słupka.
  • Histogram - seria pionowych słupków. Podczas używania tego typu ustaw właściwość IsOverlay swojego wskaźnika na false.

Aby ustawić typ wyniku, użyj właściwości PlotType, jak pokazano poniżej.

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

Parametry enum

Typ enum jest potrzebny do tworzenia parametrów, które mają kilka predefiniowanych opcji, z których użytkownicy mogą wybierać. Używamy typu enum w następującym przykładzie:

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

Jeśli dodasz ten parametr do wskaźnika lub cBota, zobaczysz interaktywne menu wieloopcyjne umożliwiające wybór jednej z określonych wartości enum.

Praca z czasem

Czas platformy i serwera

Możesz uzyskać bieżący czas serwera, uzyskując dostęp do właściwości Server.Time lub Server.TimeInUtc.

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

Właściwość Server.Time reprezentuje bieżący czas w strefie czasowej Twojego wskaźnika lub cBota ustalonej za pomocą właściwości TimeZone.

Czas otwarcia słupka

Użyj kolekcji Bars.OpenTime, aby uzyskać czasy otwarcia słupków. Strefa czasowa będzie oparta na strefie czasowej określonej w atrybucie klasy TimeZone.

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

Przesunięcie czasu platformy

Użyj właściwości Application.UserTimeOffset, aby uzyskać strefę czasową platformy użytkownika. Jest to używane głównie do konwersji czasu wskaźnika na strefę czasową użytkownika.

1
var userPlatformTimeOffset = Application.UserTimeOffset;

Właściwość Application.UserTimeOffset zwraca obiekt TimeSpan reprezentujący przesunięcie czasu ustawione przez użytkownika na jego platformie cTrader w porównaniu do czasu UTC.

Możesz również wybrać otrzymywanie powiadomień, gdy użytkownik zmieni przesunięcie czasu swojej platformy. Aby to zrobić, użyj zdarzenia 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;
}

Uzyskaj czas za pomocą parametru

cTrader obsługuje dedykowane typy parametrów daty i czasu, które pozwalają uzyskać silnie typowane wartości daty i czasu jako dane wejściowe dla Twoich algorytmów zamiast używania typu parametru string.

Używając nowych typów parametrów daty i czasu, możesz uzyskać wartości w strefie czasowej swojego algorytmu z wbudowaną walidacją minimum i maksimum oraz pełną obsługą optymalizacji, tak jak w przypadku innych typów parametrów.

Aby uzyskać określoną wartość czasu za pomocą konfigurowalnego parametru, możesz użyć tych typów C#:

  • DateTime
  • DateOnly
  • TimeSpan

Poniżej znajduje się przykład, jak można to zrobić:

 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