Bỏ qua

Mẫu mã chỉ báo

Trang này cung cấp một số ví dụ mã Python và C# để tạo các chỉ báo kỹ thuật được sử dụng cho giao dịch thủ công hoặc thuật toán.

Kho lưu trữ mẫu chỉ báo

Các mẫu mã chỉ báo toàn diện, bao gồm các mẫu sẵn sàng chạy cho các loại chỉ báo và công cụ phân tích kỹ thuật khác nhau, có sẵn trong các kho lưu trữ PythonC# riêng biệt trên GitHub.

Chỉ báo đơn giản

Chỉ báo cao trừ thấp tính toán sự chênh lệch giữa giá cao và giá thấp của thanh hiện tại và hiển thị nó trong một chuỗi đầu ra. Chuỗi này được vẽ trên biểu đồ dưới dạng một đường nối các giá trị kết quả ở mỗi thanh.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
[Indicator(IsOverlay = false, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None, ScalePrecision = 5)]
public class HighMinusLow : Indicator
{
    [Output("Main", LineColor = "Orange")]
    public IndicatorDataSeries Result { get; set; }

    public override void Calculate(int index)
    {
        Result[index] = Bars.HighPrices[index] - Bars.LowPrices[index];
    }
}

Ghi chú

Các chỉ báo Python sử dụng các tham số có thể tùy chỉnh được khai báo trong các tệp .cs của chúng.

1
2
3
4
5
6
7
from System import Action

class HighMinusLow():
    def calculate(self, index):
        # In Python you have to declare parameters and outputs in your algo C# file like C# algos
        # So Result here is already declared in C# file of this indicator and here we can use it
        api.Result[index] = api.Bars.HighPrices[index] - api.Bars.LowPrices[index]

Khai báo [Indicator...] bao gồm một số tham số được định nghĩa như sau:

  • IsOverlay - một boolean xác định liệu đường sẽ được xếp chồng lên biểu đồ hay hiển thị trong một bảng UI riêng biệt.
  • TimeZone - một trường lớp TimeZones chỉ định múi giờ của dữ liệu chỉ báo và thời gian máy chủ.
  • AccessRights - một trường lớp AccessRights xác định quyền truy cập được cấp cho chỉ báo của bạn.
  • ScalePrecision - một int thiết lập độ chính xác của tỷ lệ đầu ra chỉ báo.

Như bạn đã học trước đây khi chỉnh sửa mã chỉ báo, thuộc tính Output được khai báo để đánh dấu một thuộc tính là đầu ra chỉ báo. Thuộc tính này nên là public để có thể được tham chiếu bởi các lớp khác.

Đầu ra chỉ báo luôn phải thuộc loại dữ liệu IndicatorDataSeries là một danh sách các số double có thể được lập chỉ mục như một mảng. Do đó, giá trị tại mỗi [index] trong danh sách Result có thể được gán trong phương thức Calculate như sau.

1
2
3
4
public override void Calculate(int index)
{
   Result[index] = Bars.HighPrices[index] - Bars.LowPrices[index];
}
1
2
def calculate(self, index):
    api.Result[index] = api.Bars.HighPrices[index] - api.Bars.LowPrices[index]

Chỉ báo có tham số

Trong hầu hết các trường hợp, kết quả đầu ra của chỉ báo có thể thay đổi tùy thuộc vào dữ liệu đầu vào của người dùng. Cách thiết lập các tham số có thể tùy chỉnh cho chỉ báo tương tự như cách thực hiện cho cBot.

Chỉ báo trung bình động đơn giản dưới đây được thiết kế để chấp nhận nguồn giá và khoảng thời gian làm tham số có thể tùy chỉnh. Các tham số như vậy (SourcePeriods trong ví dụ cụ thể này) phải được đặt trước bởi thuộc tính Parameter.

Tương tự như các thuộc tính [Indicator()][Output()] đã thảo luận trước đó, thuộc tính [Parameter()] có thể xác định một số đặc điểm áp dụng cho dữ liệu đầu vào của người dùng.

1
[Parameter("MA Periods", DefaultValue = 14, MinValue = 1, MaxValue = 20)]

Ghi chú

Các chỉ báo Python sử dụng các tham số có thể tùy chỉnh được khai báo trong các tệp .cs của chúng.

Ở trên, chúng ta chỉ định các đặc điểm sau:

  • Tên hiển thị để biểu thị tham số này trong giao diện người dùng cTrader ("MA Periods").
  • Giá trị mặc định của tham số; nó có thể được thay đổi bởi người dùng khi tùy chỉnh một phiên bản (DefaultValue = 14)
  • Giá trị tối thiểu và tối đa của tham số (MinValue = 1, MaxValue = 20)

Trong đoạn mã dưới đây, chúng ta thể hiện cách tích hợp các tham số có thể tùy chỉnh vào mã chỉ báo.

 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
[Indicator(IsOverlay = false, ScalePrecision = 5)]
public class SimpleMovingAverage : Indicator
{
    [Parameter("Price")]
    public DataSeries Source { get; set; }

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

    [Parameter("MA Periods", DefaultValue = 14, MinValue = 1, MaxValue = 20)]
    public int Periods { get; set; }

    [Parameter("Message", DefaultValue = true)]
    public bool DisplayChartMessage { get; set; }

    [Output("Main", LineColor = "Red")]
    public IndicatorDataSeries Result { get; set; }

    public override void Calculate(int index)
    {
        double sum = 0;

        for (var i = index - Periods + 1; i <= index; i++)
        {
            sum += Source[i];
        }
        Result[index] = sum / Periods;
    }
}

Ghi chú

Các chỉ báo Python sử dụng các tham số có thể tùy chỉnh được khai báo trong các tệp .cs của chúng.

1
2
3
4
5
6
7
8
class SimpleMovingAverage():
    def calculate(self, index):
        sum = 0
        # Periods, Source and Result are declared in the C# file
        for i in range(index - api.Periods + 1, index):
            sum += api.Source[i]

        api.Result[index] = sum / api.Periods

Chỉ báo lồng nhau

Chỉ báo lồng nhau được định nghĩa là các chỉ báo mà giá trị của chúng phụ thuộc vào kết quả tính toán của các chỉ báo khác. Chúng hữu ích khi viết một số loại tiện ích mở rộng nhất định như chỉ báo DeMark 9. Hãy xem xét đoạn mã mẫu sau:

 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
[Indicator(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
public class SampleDeMarker : Indicator
{
    [Parameter(DefaultValue = 14)]
    public int Periods { get; set; }

    [Output("DMark", Color = Colors.Turquoise)]
    public IndicatorDataSeries DMark { get; set; }

    private IndicatorDataSeries deMin;
    private IndicatorDataSeries deMax;
    private MovingAverage deMinMA;
    private MovingAverage deMaxMA;

    protected override void Initialize()
    {
        deMin = CreateDataSeries();
        deMax = CreateDataSeries();
        deMinMA = Indicators.MovingAverage(deMin, Periods, MovingAverageType.Simple);
        deMaxMA = Indicators.MovingAverage(deMax, Periods, MovingAverageType.Simple);
    }

    public override void Calculate(int index)
    {
        deMin[index] = Math.Max(Bars.LowPrices[index - 1] - Bars.LowPrices[index], 0);
        deMax[index] = Math.Max(Bars.HighPrices[index] - Bars.HighPrices[index - 1], 0);

        var min = deMinMA.Result[index];
        var max = deMaxMA.Result[index];

        DMark[index] = max / (min + max);
    }
}

Ghi chú

Các chỉ báo Python sử dụng các tham số có thể tùy chỉnh được khai báo trong các tệp .cs của chúng.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
class SampleDeMarker():
    def initialize(self):
        self.deMin = api.CreateDataSeries()
        self.deMax = api.CreateDataSeries()
        # Periods is declared in the C# file
        self.deMinMA = api.Indicators.MovingAverage(self.deMin, api.Periods, MovingAverageType.Simple)
        self.deMaxMA = api.Indicators.MovingAverage(self.deMax, api.Periods, MovingAverageType.Simple)

    def calculate(self, index):
        self.deMin[index] = max(api.Bars.LowPrices[index - 1] - api.Bars.LowPrices[index], 0)
        self.deMax[index] = max(api.Bars.HighPrices[index] - api.Bars.HighPrices[index - 1], 0)

        minValue = self.deMinMA.Result[index]
        maxValue = self.deMaxMA.Result[index]

        # DMark Output is declared in the C# file
        api.DMark[index] = maxValue / (minValue + maxValue)

Trong ví dụ trên, deMinMAdeMaxMA là hai biến được sử dụng để tính toán giá trị của chỉ báo DeMarker của chúng ta.

Các chỉ báo lồng nhau cần được định nghĩa trong phương thức Initialize(). Ví dụ, deMinMA được định nghĩa là trung bình động đơn giản của chuỗi deMin.

1
deMinMA = Indicators.MovingAverage(deMin, Periods, MovingAverageType.Simple);
1
self.deMinMA = api.Indicators.MovingAverage(self.deMin, api.Periods, MovingAverageType.Simple)

deMin, đến lượt nó, được định nghĩa trong phương thức Calculate() là giá trị lớn nhất của hai giá thấp nhất gần đây nhất.

1
deMin[index] = Math.Max(Bars.LowPrices[index - 1] - Bars.LowPrices[index], 0);
1
self.deMin[index] = max(api.Bars.LowPrices[index - 1] - api.Bars.LowPrices[index], 0)

Để đơn giản hóa việc làm việc với các chỉ báo lồng nhau, IntelliSense tự động điền danh sách tất cả các chỉ báo tích hợp sẵn khi bạn nhập Indicators theo sau là dấu chấm vào trình soạn thảo mã. Nó cũng sẽ hiển thị tất cả các tham số đầu vào liên quan khi bạn chọn một chỉ báo nhất định từ danh sách này.

Image title

Tải lười biếng

cTrader Algo sử dụng tải lười biếng khi bạn sử dụng các chỉ báo được tham chiếu. Các giá trị được cung cấp bởi chỉ báo được tham chiếu không được tính toán cho đến khi mã của bạn bắt đầu sử dụng chúng một cách tích cực.

Nếu bạn truy cập dữ liệu Outputs của một chỉ báo được tham chiếu, cTrader sẽ bắt đầu tải dữ liệu chỉ báo bằng cách gọi phương thức Calculate() của nó trên các nến quá khứ và tương lai. Trong mọi trường hợp khác, chỉ báo được tham chiếu sẽ vẫn ở trạng thái không hoạt động và do đó sẽ không tiêu tốn bất kỳ tài nguyên hệ thống nào.

Điều này cũng có nghĩa là nếu chỉ báo của bạn không có bất kỳ Output nào hoặc nếu bạn cố gắng truy cập bất kỳ thuộc tính công khai nào của nó, bạn sẽ nhận được giá trị mặc định của thuộc tính đó. Để giải quyết vấn đề này, hãy gọi phương thức Calculate() của chỉ báo tùy chỉnh của bạn từ phương thức Calculate() của chỉ báo hiện tại.

Dao động kế và thuộc tính levels

Thuật ngữ "dao động kế" bao gồm tất cả các chỉ báo dao động quanh một biến không đổi nhất định.

Khi tạo dao động kế, việc đầu tiên vẽ một đường ngang hoặc đường "mức" tại giá trị không đổi đó là hữu ích; chỉ báo sau đó sẽ dao động quanh đường này. Trong nhiều trường hợp, giá trị không đổi bằng không.

Trong ví dụ dưới đây, chúng ta định nghĩa một dao động kế động lượng. Nó thường dao động quanh giá trị 100. Chúng ta thêm một đường mức tại giá trị này bằng cách sử dụng thuộc tính Levels được khai báo trước các thuộc tính chỉ báo.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
[Levels(100)]
[Indicator()]
public class MomentumOscillator : Indicator
{
    [Parameter()]
    public DataSeries Source { get; set; }

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

    [Output("Main", LineColor = "Green")]
    public IndicatorDataSeries Result { get; set; }

    public override void Calculate(int index)
    {
        Result[index] = 100 * Source[index] / Source[index - Periods];
    }
}

Ghi chú

Các chỉ báo Python sử dụng các tham số có thể tùy chỉnh được khai báo trong các tệp .cs của chúng.

1
2
3
4
class MomentumOscillator():
    def calculate(self, index):
        # Result, Source, and Periods are declared in the C# file
        api.Result[index] = 100 * api.Source[index] / api.Source[index - api.Periods]

Lưu ý rằng thuộc tính Levels chỉ có thể được sử dụng nếu chỉ báo không được xếp chồng lên biểu đồ, nghĩa là thuộc tính IsOverlay không được đặt thành true. Theo mặc định, giá trị của IsOverlayfalse. Nếu thuộc tính này bị bỏ qua trong mã của bạn, Levels sẽ hoạt động bình thường.

Nếu bạn cần thiết lập nhiều đường "mức", hãy thêm một danh sách các giá trị được phân tách bằng dấu phẩy trong dấu ngoặc đơn như hiển thị bên dưới.

1
[Levels(0, 50, 100)] 
1
[Levels(50.5, 50.75)] 
1
[Levels(0.001, 0.002)] 

Levels trong Chỉ báo Python

Trong Python, bạn khai báo Levels trong tệp chỉ báo C# của mình giống như các chỉ báo C#.

Thuộc tính IsLastBar

Trong một số trường hợp, bạn có thể muốn tạo một chỉ báo chỉ cần được tính toán cho nến cuối cùng trong biểu đồ giao dịch. Đơn giản hóa điều này, thuộc tính IsLastBar có thể được sử dụng để kiểm tra xem tham số chỉ mục của phương thức Calculate() có phải là của nến cuối cùng hay không.

Chỉ báo dưới đây dựa trên thời gian UTC; tuy nhiên, nó có thể hiển thị thời gian mở cửa cuối cùng ở New York và Tokyo.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
[Indicator(IsOverlay = true, TimeZone = TimeZones.UTC)]
public class TimeInDifferentParts : Indicator
{
    public override void Calculate(int index)
    {
        if (IsLastBar)
            DisplayTime(index);
    }

    protected void DisplayTime(int index)
    {
        var nyDateTime = Bars.OpenTimes[index].AddHours(-5);
        var tokyoDateTime = Bars.OpenTimes[index].AddHours(7);

        var nyTime = nyDateTime.ToShortTimeString();
        var tokyoTime = tokyoDateTime.ToShortTimeString();

        Chart.DrawStaticText("Title", "Last Bar OpenTime \n NY " + nyTime + "\n" + "Tokyo " + tokyoTime, VerticalAlignment.Top, HorizontalAlignment.Left, Color.Lime);
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
class TimeInDifferentParts():
    def calculate(self, index):
        if api.IsLastBar:
            self.display_time(index)

    def display_time(self, index):
        nyDateTime = api.Bars.OpenTimes[index].AddHours(-5)
        tokyoDateTime = api.Bars.OpenTimes[index].AddHours(7)

        nyTime = nyDateTime.ToShortTimeString()
        tokyoTime = tokyoDateTime.ToShortTimeString()

        api.Chart.DrawStaticText("Title", f"Last Bar OpenTime\nNY {nyTime}\nTokyo {tokyoTime}", VerticalAlignment.Top, HorizontalAlignment.Left, Color.Lime)

Kết hợp các chỉ báo

cTrader cho phép kết hợp nhiều chỉ báo trong cùng một bảng điều khiển hoặc trong cùng một biểu đồ.

Chỉ báo sau đây kết hợp các chỉ báo Aroon, RSI và hệ thống chuyển động có hướng trong một.

 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
[Indicator(IsOverlay = false, TimeZone = TimeZones.UTC, ScalePrecision = 5)]
public class Aroon_RSI_DMS : Indicator
{
    private Aroon aroon;
    private RelativeStrengthIndex rsi;
    private DirectionalMovementSystem dms;

    [Parameter()]
    public DataSeries Source { get; set; }

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

    [Output("Aroon Up", LineColor = "LightSkyBlue")]
    public IndicatorDataSeries AroonUp { get; set; }

    [Output("Aroon Down", LineColor = "Red")]
    public IndicatorDataSeries AroonDn { get; set; }

    [Output("Rsi", LineColor = "Green")]
    public IndicatorDataSeries Rsi { get; set; }

    [Output("DI Plus", LineColor = "DarkGreen")]
    public IndicatorDataSeries DmsDIPlus { get; set; }

    [Output("DI Minus", LineColor = "DarkRed")]
    public IndicatorDataSeries DmsDIMinus { get; set; }

    [Output("ADX", LineColor = "Blue")]
    public IndicatorDataSeries DmsADX { get; set; }

    protected override void Initialize()
    {
        // Initialize and create nested indicators
        aroon = Indicators.Aroon(Periods);
        rsi = Indicators.RelativeStrengthIndex(Source, Periods);
        dms = Indicators.DirectionalMovementSystem(Periods);
    }

    public override void Calculate(int index)
    {
        AroonUp[index] = aroon.Up[index];
        AroonDn[index] = aroon.Down[index];

        Rsi[index] = rsi.Result[index];

        DmsADX[index] = dms.ADX[index];
        DmsDIMinus[index] = dms.DIMinus[index];
        DmsDIPlus[index] = dms.DIPlus[index];
    }
}

Ghi chú

Các chỉ báo Python sử dụng các tham số có thể tùy chỉnh được khai báo trong các tệp .cs của chúng.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
class Aroon_RSI_DMS():
    def initialize(self):
        # Initialize and create nested indicators
        # Periods and Source parameters are declared in the C# file
        self.aroon = api.Indicators.Aroon(Periods)
        self.rsi = api.Indicators.RelativeStrengthIndex(Source, Periods)
        self.dms = api.Indicators.DirectionalMovementSystem(Periods)

    def calculate(self, index):
        # AroonUp, AroonDn, Rsi, DmsADX, DmsDIMinus, and DmsDIPlus
        # outputs are declared in the C# file
        api.AroonUp[index] = self.aroon.Up[index]
        api.AroonDn[index] = self.aroon.Down[index]

        api.Rsi[index] = self.rsi.Result[index]

        api.DmsADX[index] = self.dms.ADX[index]
        api.DmsDIMinus[index] = self.dms.DIMinus[index]
        api.DmsDIPlus[index] = self.dms.DIPlus[index]

Nhiều khung thời gian

  • Sử dụng nhiều khung thời gian

    Ví dụ sau đây hiển thị chỉ báo Moving Averages trên các khung thời gian khác nhau.

     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
    [Indicator(IsOverlay = true, TimeZone = TimeZones.UTC)]
    public class MultiTF_MA : Indicator
    {
        [Parameter(DefaultValue = 50)]
        public int Period { get; set; }
    
        [Output("MA", LineColor = "Yellow")]
        public IndicatorDataSeries MA { get; set; }
    
        [Output("MA5", LineColor = "Orange")]
        public IndicatorDataSeries MA5 { get; set; }
    
        [Output("MA10", LineColor = "Red")]
        public IndicatorDataSeries MA10 { get; set; }
    
        private Bars bars5;
        private Bars bars10;
    
        private MovingAverage ma;
        private MovingAverage ma5;
        private MovingAverage ma10;
    
        protected override void Initialize()
        {
            bars5 = MarketData.GetBars(TimeFrame.Minute5);
            bars10 = MarketData.GetBars(TimeFrame.Minute10);
    
            ma = Indicators.MovingAverage(Bars.ClosePrices, Period, MovingAverageType.Triangular);
            ma5 = Indicators.MovingAverage(bars5.ClosePrices, Period, MovingAverageType.Triangular);
            ma10 = Indicators.MovingAverage(bars10.ClosePrices, Period, MovingAverageType.Triangular);
        }
    
        public override void Calculate(int index)
        {
            MA[index] = ma.Result[index];
    
            var index5 = bars5.OpenTimes.GetIndexByTime(Bars.OpenTimes[index]);
            if (index5 != -1)
                MA5[index] = ma5.Result[index5];
    
            var index10 = bars10.OpenTimes.GetIndexByTime(Bars.OpenTimes[index]);
    
            if (index10 != -1)
                MA10[index] = ma10.Result[index10];
        }
    }
    

    Ghi chú

    Các chỉ báo Python sử dụng các tham số có thể tùy chỉnh được khai báo trong các tệp .cs của chúng.

     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
    class MultiTF_MA():
        def initialize(self):
            self.bars5 = api.MarketData.GetBars(TimeFrame.Minute5)
            self.bars10 = api.MarketData.GetBars(TimeFrame.Minute10)
    
            # Period is declared as a parameter in the C# file 
            # We use indicator time frame bars for this moving average
            self.ma = Indicators.MovingAverage(api.Bars.ClosePrices, api.Period, MovingAverageType.Triangular)
    
            # We use other two time frame bars that we created previously
            # for these two moving averages
            self.ma5 = Indicators.MovingAverage(self.bars5.ClosePrices, api.Period, MovingAverageType.Triangular)
            self.ma10 = Indicators.MovingAverage(self.bars10.ClosePrices, api.Period, MovingAverageType.Triangular)
    
        def calculate(self, index):
            # MA, MA5, and MA10 are outputs we declared in the C# file
            api.MA[index] = self.ma.Result[index]
    
            index5 = self.bars5.OpenTimes.GetIndexByTime(api.Bars.OpenTimes[index])
    
            if index5 > -1:
                api.MA5[index] = self.ma5.Result[index5]
    
            index10 = self.bars10.OpenTimes.GetIndexByTime(api.Bars.OpenTimes[index])
    
            if index10 > -1:
                api.MA10[index] = self.ma10.Result[index10]
    
  • Sử dụng nhiều khung thời gian và cặp tiền tệ

    Ví dụ sau đây hiển thị chỉ báo Moving Averages trên nhiều khung thời gian và biểu tượng.

     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
    [Indicator(IsOverlay = true, TimeZone = TimeZones.UTC)]
    public class MultiSymbolMA : Indicator
    {
        private MovingAverage ma1, ma2, ma3;
        private Bars bars2, bars3;
        private Symbol symbol2, symbol3;
    
        [Parameter(DefaultValue = "EURCHF")]
        public string Symbol2 { get; set; }
    
        [Parameter(DefaultValue = "EURCAD")]
        public string Symbol3 { get; set; }
    
        [Parameter(DefaultValue = 14)]
        public int Period { get; set; }
    
        [Parameter(DefaultValue = MovingAverageType.Simple)]
        public MovingAverageType MaType { get; set; }
    
        [Output("MA Symbol 1", LineColor = "Magenta")]
        public IndicatorDataSeries Result1 { get; set; }
    
        [Output("MA Symbol 2", LineColor = "Magenta")]
        public IndicatorDataSeries Result2 { get; set; }
    
        [Output("MA Symbol 3", LineColor = "Magenta")]
        public IndicatorDataSeries Result3 { get; set; }
    
        protected override void Initialize()
        {
            symbol2 = Symbols.GetSymbol(Symbol2);
            symbol3 = Symbols.GetSymbol(Symbol3);
    
            bars2 = MarketData.GetBars(TimeFrame, symbol2.Name);
            bars3 = MarketData.GetBars(TimeFrame, symbol3.Name);
    
            ma1 = Indicators.MovingAverage(Bars.ClosePrices, Period, MaType);
            ma2 = Indicators.MovingAverage(bars2.ClosePrices, Period, MaType);
            ma3 = Indicators.MovingAverage(bars3.ClosePrices, Period, MaType);
        }
    
        public override void Calculate(int index)
        {
            ShowOutput(Symbol, Result1, ma1, Bars, index);
            ShowOutput(symbol2, Result2, ma2, bars2, index);
            ShowOutput(symbol3, Result3, ma3, bars3, index);
        }
    
        private void ShowOutput(Symbol symbol, IndicatorDataSeries result, MovingAverage movingAverage, Bars bars, int index)
        {
            var index2 = bars.OpenTimes.GetIndexByTime(Bars.OpenTimes[index]);
            result[index] = movingAverage.Result[index2];
    
            string text = string.Format("{0} {1}", symbol.Name, Math.Round(result[index], symbol.Digits));
            Chart.DrawStaticText(symbol.Name, text, VerticalAlignment.Top, HorizontalAlignment.Right, Color.Yellow);
        }
    }
    

    Ghi chú

    Các chỉ báo Python sử dụng các tham số có thể tùy chỉnh được khai báo trong các tệp .cs của chúng.

     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
    class MultiSymbolMA():
        def initialize(self):
            # Symbol2 and Symbol3 are declared as parameters in the C# file
            self.symbol2 = api.Symbols.GetSymbol(api.Symbol2)
            self.symbol3 = api.Symbols.GetSymbol(api.Symbol3)
    
            self.bars2 = api.MarketData.GetBars(api.TimeFrame, self.symbol2.Name)
            self.bars3 = api.MarketData.GetBars(api.TimeFrame, self.symbol3.Name)
    
            self.ma1 = api.Indicators.MovingAverage(api.Bars.ClosePrices, api.Period, api.MaType)
            self.ma2 = api.Indicators.MovingAverage(self.bars2.ClosePrices, api.Period, api.MaType)
            self.ma3 = api.Indicators.MovingAverage(self.bars3.ClosePrices, api.Period, api.MaType)
    
        def calculate(self, index):
            # Result1, Result2, and Result3 are declared as outputs in the C# file
            self.show_output(api.Symbol, api.Result1, self.ma1, api.Bars, index)
            self.show_output(self.symbol2, api.Result2, self.ma2, self.bars2, index)
            self.show_output(self.symbol3, api.Result3, self.ma3, self.bars3, index)
    
        def show_output(self, symbol, result, movingAverage, bars, index):
            index2 = bars.OpenTimes.GetIndexByTime(api.Bars.OpenTimes[index])
    
            result[index] = movingAverage.Result[index2]
    
            text = f"{symbol.Name} {round(result[index], symbol.Digits)}"
    
            api.Chart.DrawStaticText(symbol.Name, text, VerticalAlignment.Top, HorizontalAlignment.Right, Color.Yellow)
    

Image title