Lewati ke isi

Sampel kode plugin

Halaman ini menyediakan beberapa contoh kode Python dan C# untuk membuat plugin asli, termasuk alat untuk trading manual atau algoritmik di cTrader.

Repositori sampel plugin

Sampel kode plugin yang komprehensif, termasuk template siap pakai untuk berbagai area UI dan fungsionalitas, tersedia dalam repositori Python dan C# terpisah di GitHub.

Kiat

Gunakan parameter yang dapat disesuaikan dalam plugin C# dan Python untuk mencapai fleksibilitas yang lebih besar. Parameter yang dapat disesuaikan untuk plugin C# dideklarasikan dalam kode C# biasa, sedangkan plugin Python memerlukan parameter yang dapat disesuaikan dideklarasikan dalam file .cs mereka.

Menampilkan situs web dalam bingkai grafik

Plugin berikut menampilkan situs web Toko cTrader di dalam bingkai grafik terpisah.

 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
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using cAlgo.API;
using cAlgo.API.Collections;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;

namespace cAlgo.Plugins
{
    [Plugin(AccessRights = AccessRights.None)]
    public class ForumExample : Plugin
    {
        private WebView _cTraderWebView;

        protected override void OnStart()
        {
            _cTraderWebView = new WebView();
            _cTraderWebView.Loaded += DisplayForum;

            var webViewFrame = ChartManager.AddCustomFrame("Forum");
            webViewFrame.Child = _cTraderWebView;
            webViewFrame.ChartContainer.Mode = ChartMode.Multi;
            webViewFrame.Attach();
        }


        private void DisplayForum(WebViewLoadedEventArgs args)
        {
            _cTraderWebView.NavigateAsync("https://ctrader.com/forum");
        }
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
import clr
clr.AddReference("cAlgo.API")

from cAlgo.API import *

class ForumExample():
    def on_start(self):
        self.cTraderWebView = WebView()
        self.cTraderWebView.Loaded += self.display_forum

        webViewFrame = api.ChartManager.AddCustomFrame("Forum")
        webViewFrame.Child = self.cTraderWebView
        webViewFrame.ChartContainer.Mode = ChartMode.Multi
        webViewFrame.Attach()

    def display_forum(self, args):
        self.cTraderWebView.NavigateAsync("https://ctrader.com/forum")

Sekali per menit, plugin di bawah ini menyimpan total laba rugi (P&L) akun ke dalam file menggunakan fitur penyimpanan lokal dan timestamp saat ini sebagai nama file. Plugin ini juga menampilkan informasi yang sama dalam bagian terpisah di Panel Simbol Aktif (ASP).

 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
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using cAlgo.API;
using cAlgo.API.Collections;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;

namespace cAlgo.Plugins
{
    [Plugin(AccessRights = AccessRights.None)]
    public class GrossPnL : Plugin
    {
        private TextBlock _textBlock = new TextBlock
        {
            Text = "Starting...",
            FontSize = 15,
            FontWeight = FontWeight.ExtraBold,
            TextAlignment = TextAlignment.Center,
            Padding = new Thickness(5, 5, 5, 5),
        };

        protected override void OnStart()
        {
            var aspBlock = Asp.SymbolTab.AddBlock("Gross P&L");
            aspBlock.Child = _textBlock;
            Timer.Start(TimeSpan.FromMinutes(1));
        }

        protected override void OnTimer()
        {
            var timestamp = Server.TimeInUtc;

            string result = timestamp.ToString("HH mm ss");

            LocalStorage.SetString($"{result}", $"{Account.UnrealizedGrossProfit}", LocalStorageScope.Device);

            _textBlock.Text = $"{result}: {Account.UnrealizedGrossProfit}";
        }

    }
}
 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
import clr
clr.AddReference("cAlgo.API")

from cAlgo.API import *

class GrossPnL():
    def on_start(self):
        self.textBlock = TextBlock()
        self.textBlock.Text = "Starting..."
        self.textBlock.FontSize = 15
        self.textBlock.FontWeight = FontWeight.ExtraBold
        self.textBlock.TextAlignment = TextAlignment.Center
        self.textBlock.Padding = Thickness(5, 5, 5, 5)

        aspBlock = api.Asp.SymbolTab.AddBlock("Gross P&L")
        aspBlock.Child = self.textBlock

        api.Timer.Start(60)

    def on_timer(self):
        timestamp = api.Server.TimeInUtc

        result = timestamp.ToString("HH mm ss")

        api.LocalStorage.SetString(result, f"{api.Account.UnrealizedGrossProfit}", LocalStorageScope.Device)

        self.textBlock.Text = f"{result}: {api.Account.UnrealizedGrossProfit}"

Menampilkan jendela terpisah dengan kontrol kustom

Plugin di bawah ini menambahkan tombol kustom ke jendela terpisah. Saat diklik, kontrol tersebut menambahkan level Take Profit untuk semua posisi terbuka tetapi hanya jika posisi tersebut tidak memiliki Take Profit yang ditetapkan sebelumnya.

 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
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using cAlgo.API;
using cAlgo.API.Collections;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;

namespace cAlgo.Plugins
{
    [Plugin(AccessRights = AccessRights.None)]
    public class ProtectionPlugin : Plugin
    {

        private Button _buttonAddTakeProfit;
        private Window _window;

        protected override void OnStart()
        {
            _buttonAddTakeProfit = new Button
            {
                BackgroundColor = Color.SeaGreen,
                Height = 50,
                Text = "Add Take Profit"
            };

            _buttonAddTakeProfit.Click += AddTakeProfit;
            _window = new Window
            {
                Height = 150,
                Width = 150,
                Padding = new Thickness(5, 10, 10, 5),
            };

            _window.Child = _buttonAddTakeProfit;
            _window.Show();
        }

        private void AddTakeProfit(ButtonClickEventArgs args)
        {
            foreach (var position in Positions)
            {
                if (position.TakeProfit is null)
                {
                    position.ModifyTakeProfitPips(20);
                }
            }
        }
    }
}
 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
import clr
clr.AddReference("cAlgo.API")

from cAlgo.API import *

class ProtectionPlugin():
    def on_start(self):
        self.buttonAddTakeProfit = Button()
        self.buttonAddTakeProfit.BackgroundColor = Color.SeaGreen
        self.buttonAddTakeProfit.Height = 50
        self.buttonAddTakeProfit.Text = "Add Take Profit"

        self.buttonAddTakeProfit.Click += self.On_add_take_profit_click

        self.window = Window()
        self.window.Height = 150
        self.window.Width = 150
        self.window.Padding = Thickness(5, 10, 10, 5)

        self.window.Child = self.buttonAddTakeProfit
        self.window.Show()

    def On_add_take_profit_click(self, args):
        for position in api.Positions:
            if position.TakeProfit is None:
                position.ModifyTakeProfitPips(20)

Menampilkan informasi tentang harga bar di tampilan Pemantau Trading

Ketika dibangun, plugin ini menambahkan tab baru ke panel Pemantau Trading. Tab ini berisi kisi dua kali dua yang menampilkan informasi tentang harga bar terakhir yang diketahui untuk timeframe m1 dan simbol "USDJPY".

 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
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using cAlgo.API;
using cAlgo.API.Collections;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;

namespace cAlgo.Plugins
{
    [Plugin(AccessRights = AccessRights.None)]
    public class BarInfo : Plugin
    {
        private Grid _grid;
        private TextBlock _lowBlock;
        private TextBlock _highBlock;
        private TextBlock _closeBlock;
        private TextBlock _openBlock;
        private Bars _bars;

        protected override void OnStart()
        {
            _bars = MarketData.GetBars(TimeFrame.Minute, "USDJPY");
            _grid = new Grid(2, 2)
            {
                HorizontalAlignment = HorizontalAlignment.Center,
                VerticalAlignment = VerticalAlignment.Center,
                ShowGridLines = true,
                Height = 150,
                Width = 150,
            };

            _lowBlock = new TextBlock
            {
                Text = $"Low: {_bars.LowPrices.LastValue}",
                HorizontalAlignment = HorizontalAlignment.Center,
                VerticalAlignment = VerticalAlignment.Center,
            };

            _highBlock = new TextBlock
            {
                Text = $"High: {_bars.HighPrices.LastValue}",
                HorizontalAlignment = HorizontalAlignment.Center,
                VerticalAlignment = VerticalAlignment.Center,
            };

            _closeBlock = new TextBlock
            {
                Text = $"Low: {_bars.ClosePrices.LastValue}",
                HorizontalAlignment = HorizontalAlignment.Center,
                VerticalAlignment = VerticalAlignment.Center,
            };

            _openBlock = new TextBlock
            {
                Text = $"Open: {_bars.OpenPrices.LastValue}",
                HorizontalAlignment = HorizontalAlignment.Center,
                VerticalAlignment = VerticalAlignment.Center,
            };

            _grid.AddChild(_lowBlock, 0, 0);
            _grid.AddChild(_highBlock, 0, 1);
            _grid.AddChild(_openBlock, 1, 0);
            _grid.AddChild(_closeBlock, 1, 1);

            var TradeWatchTab = TradeWatch.AddTab("Bar Info");
            TradeWatchTab.Child = _grid;
            TradeWatchTab.IsSelected = true;
            _bars.Tick += OnBarsTick;
        }

        private void OnBarsTick(BarsTickEventArgs args)
        {
            _lowBlock.Text = _bars.LowPrices.LastValue.ToString();
            _highBlock.Text = _bars.HighPrices.LastValue.ToString();
            _openBlock.Text = _bars.HighPrices.LastValue.ToString();
            _closeBlock.Text = _bars.HighPrices.LastValue.ToString();
        }
    }
}
 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
import clr
clr.AddReference("cAlgo.API")

from cAlgo.API import *

class BarInfo():
    def on_start(self):
        tradeWatchTab = api.TradeWatch.AddTab("Bar Info")
        tradeWatchTab.IsSelected = True

        grid = Grid(2, 2)
        grid.HorizontalAlignment = HorizontalAlignment.Center
        grid.VerticalAlignment = VerticalAlignment.Center
        grid.ShowGridLines = True
        grid.Height = 150
        grid.Width = 150

        self.bars = api.MarketData.GetBars(TimeFrame.Minute, "USDJPY")

        self.lowBlock = self.get_text_block(f"Low: {self.bars.LowPrices.LastValue}")
        self.highBlock = self.get_text_block(f"High: {self.bars.HighPrices.LastValue}")
        self.openBlock = self.get_text_block(f"Open: {self.bars.OpenPrices.LastValue}")
        self.closeBlock = self.get_text_block(f"Close: {self.bars.ClosePrices.LastValue}")

        grid.AddChild(self.lowBlock, 0, 0)
        grid.AddChild(self.highBlock, 0, 1)
        grid.AddChild(self.openBlock, 1, 0)
        grid.AddChild(self.closeBlock, 1, 1)

        tradeWatchTab.Child = grid

        self.bars.Tick += self.on_bars_Tick

    def on_bars_Tick(self, args):
        self.lowBlock.Text = f"Low: {self.bars.LowPrices.LastValue}"
        self.highBlock.Text = f"High: {self.bars.HighPrices.LastValue}"
        self.openBlock.Text = f"Open: {self.bars.OpenPrices.LastValue}"
        self.closeBlock.Text = f"Close: {self.bars.ClosePrices.LastValue}"

    def get_text_block(self, text):
        textblock = TextBlock()
        textblock.Text = text
        textblock.HorizontalAlignment = HorizontalAlignment.Center
        textblock.VerticalAlignment = VerticalAlignment.Center
        return textblock

Bereaksi terhadap perubahan bingkai aktif

Plugin berikut mendeteksi ChartFrame mana yang saat ini aktif. Di dalam blok kustom di ASP, plugin menunjukkan persentase perbedaan antara harga saat ini dari simbol yang ChartFrame ini dibuka dan harga simbol ini sekitar satu bulan yang lalu.

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

namespace cAlgo.Plugins
{
    [Plugin(AccessRights = AccessRights.None)]
    public class ActiveFrameChangedSample : Plugin
    {

        // Declaring the necessary UI elements
        private Grid _grid;
        private TextBlock _percentageTextBlock;
        private Frame _activeFrame;

        protected override void OnStart()
        {
            // Initialising the grid and the TextBlock
            // displaying the percentage difference
            _grid = new Grid(1, 1);
            _percentageTextBlock = new TextBlock
            {
                HorizontalAlignment = HorizontalAlignment.Center,
                VerticalAlignment = VerticalAlignment.Center,
                Text = "Monthly change: ",
            };

            _grid.AddChild(_percentageTextBlock, 0, 0);

            // Initialising a new block inside the ASP
            // and adding the grid as a child
            var block = Asp.SymbolTab.AddBlock("Monthly Change Plugin");

            block.Child = _grid;

            // Attaching a custom handler to the
            // ActiveFrameChanged event
            ChartManager.ActiveFrameChanged += ChartManager_ActiveFrameChanged;
        }

        private void ChartManager_ActiveFrameChanged(ActiveFrameChangedEventArgs obj)
        {
            if (obj.NewFrame is ChartFrame)
            {
                // Casting the Frame into a ChartFrame
                var newChartFrame = obj.NewFrame as ChartFrame;

                // Attaining market data for the symbol for which
                // the currently active ChartFrame is opened
                var dailySeries = MarketData.GetBars(TimeFrame.Daily, newChartFrame.Symbol.Name);

                // Calculating the monthly change and displaying it
                // inside the TextBlock
                double monthlyChange = (newChartFrame.Symbol.Bid - dailySeries.ClosePrices[dailySeries.ClosePrices.Count - 30]) / 100;
                _percentageTextBlock.Text = $"Monthly change: {monthlyChange}";
            }
        }
    }
}
 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
import clr
clr.AddReference("cAlgo.API")

from cAlgo.API import *

class ActiveFrameChangedSample():
    def on_start(self):
        # Initialising the grid and the TextBlock displaying the percentage difference
        grid = Grid(1, 1)
        self.percentageTextBlock = TextBlock()
        self.percentageTextBlock.HorizontalAlignment = HorizontalAlignment.Center
        self.percentageTextBlock.VerticalAlignment = VerticalAlignment.Center
        self.percentageTextBlock.Text = "Monthly change: "

        grid.AddChild(self.percentageTextBlock, 0, 0)

        # Initialising a new block inside the ASP and adding the grid as a child
        block = api.Asp.SymbolTab.AddBlock("Monthly Change Plugin")
        block.Child = grid

        # Attaching an event handler to the ActiveFrameChanged event
        api.ChartManager.ActiveFrameChanged += self.on_chart_manager_active_frame_changed

    def on_chart_manager_active_frame_changed(self, args):
        if args.NewFrame is None or isinstance(args.NewFrame.__implementation__, ChartFrame) == False:
            return

        newChartFrame = ChartFrame(args.NewFrame)

        # Attaining market data for the symbol for which the currently active ChartFrame is opened
        dailySeries = api.MarketData.GetBars(TimeFrame.Daily, newChartFrame.Symbol.Name)

        # Calculating the monthly change and displaying it inside the TextBlock
        monthlyChange = (newChartFrame.Symbol.Bid - dailySeries.ClosePrices[dailySeries.ClosePrices.Count - 30]) / 100
        self.percentageTextBlock.Text = f"Monthly change: {monthlyChange}"

Image title