Bỏ qua

Các thao tác nâng cao với cBot

Hướng dẫn này chủ yếu được dùng làm bổ sung cho danh sách mẫu mã cBot mở rộng của chúng tôi.

Giao dịch các ký hiệu khác

Bạn có thể phát triển một cBot giao dịch nhiều ký hiệu ngoài ký hiệu được chỉ định khi tạo một trường hợp mới.

Để làm điều này có thể, Symbols là một bộ sưu tập của tất cả các ký hiệu có sẵn cho tài khoản giao dịch của bạn. Bạn có thể lặp qua nó bằng cách sử dụng vòng lặp; ngoài ra, bạn có thể tìm kiếm qua nó để tìm các ký hiệu cụ thể.

Để làm việc chính xác với nhiều ký hiệu, cBot cần biết những thông tin sau:

  • Khối lượng tối thiểu và tối đa được phép
  • Bước khối lượng
  • Kích thước tick pip
  • Giá trị tick pip (giá trị tiền tệ của một pip hoặc tick trong đơn vị tiền gửi của tài khoản)

Dữ liệu này có thể được lấy từ đối tượng Symbol. Trong đoạn mã dưới đây, chúng ta tìm một ký hiệu có tên là "GBPUSD" và sau đó tạo một lệnh thị trường cho nó. Chúng ta cũng sử dụng khối lượng tối thiểu được phép của nó làm khối lượng lệnh.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
[Robot()]
public class Sample_cBot : Robot
{
    protected override void OnStart()
    {
        var symbol = Symbols.GetSymbol("GBPUSD");

        if (symbol is not null)
        {
            ExecuteMarketOrder(TradeType.Sell, symbol.Name, symbol.VolumeInUnitsMin);
        }
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
import clr

clr.AddReference("cAlgo.API")

# Import cAlgo API types
from cAlgo.API import *
from cAlgo.API.Internals import *

# Import trading wrapper functions
from robot_wrapper import *

class Sample_cBot():
    def on_start(self):
        symbol = api.Symbols.GetSymbol("GBPUSD")

        if symbol is not None:
            api.ExecuteMarketOrder(TradeType.Sell, symbol.Name, symbol.VolumeInUnitsMin)

Chuyển đổi pip thành tick

Khi lập trình cBot, rất dễ gặp phải lỗi phát sinh từ việc một số giá trị biến được tính bằng đơn vị trong khi các giá trị khác được tính bằng pip.

Lớp SymbolExtensions dưới đây minh họa cách pip có thể được chuyển đổi thành tick. Nó cũng thể hiện cách pip có thể được thêm vào giá trị giá tuyệt đối.

  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
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
using System;
using cAlgo.API;
using cAlgo.API.Internals;

namespace Samples
{
    [Robot(AccessRights = AccessRights.None)]
    public class Sample : Robot
    {
        protected override void OnStart()
        {
            var spreadInPips = Symbol.NormalizePips(Symbol.ToPips(Symbol.Spread));

            Print(spreadInPips);

            var spreadInTicks = Math.Round(Symbol.ToTicks(Symbol.Spread));

            Print(spreadInTicks);

            /* Calculating a long position stop loss using the
            absolute price value. */
            var stopLossInPips = 60;

            /* We use 'NormalizePips' to avoid the 'invalid decimal places'
            error in case our stop loss value has too many decimals. */
            var stopLossInPrice = Symbol.Ask - (Symbol.NormalizePips(stopLossInPips) * Symbol.PipSize);

            Print(stopLossInPrice);
        }
    }

    public static class SymbolExtensions
    {
        /// <summary>
        /// Returns a symbol pip value
        /// </summary>
        /// <param name="symbol"></param>
        /// <returns>double</returns>
        public static double GetPip(this Symbol symbol)
        {
            return symbol.TickSize / symbol.PipSize * Math.Pow(10, symbol.Digits);
        }

        /// <summary>
        /// Returns a price value in terms of pips
        /// </summary>
        /// <param name="symbol"></param>
        /// <param name="price">The price level</param>
        /// <returns>double</returns>
        public static double ToPips(this Symbol symbol, double price)
        {
            return price * symbol.GetPip();
        }

        /// <summary>
        /// Returns a price value in terms of ticks
        /// </summary>
        /// <param name="symbol"></param>
        /// <param name="price">The price level</param>
        /// <returns>double</returns>
        public static double ToTicks(this Symbol symbol, double price)
        {
            return price * Math.Pow(10, symbol.Digits);
        }

        /// <summary>
        /// Rounds a price level to the number of symbol digits
        /// </summary>
        /// <param name="symbol">The symbol</param>
        /// <param name="price">The price level</param>
        /// <returns>double</returns>
        public static double Round(this Symbol symbol, double price)
        {
            return Math.Round(price, symbol.Digits);
        }

        /// <summary>
        /// Normalize x Pips amount decimal places to something that can be used as a stop loss or take profit for an order.
        /// For example if symbol is EURUSD and you pass to this method 10.456775 it will return back 10.5
        /// </summary>
        /// <param name="symbol">The symbol</param>
        /// <param name="pips">The amount of Pips</param>
        /// <returns>double</returns>
        public static double NormalizePips(this Symbol symbol, double pips)
        {
            var currentPrice = Convert.ToDecimal(symbol.Bid);

            var pipSize = Convert.ToDecimal(symbol.PipSize);

            var pipsDecimal = Convert.ToDecimal(pips);

            var pipsAddedToCurrentPrice = Math.Round((pipsDecimal * pipSize) + currentPrice, symbol.Digits);

            var tickSize = Convert.ToDecimal(symbol.TickSize);

            var result = (pipsAddedToCurrentPrice - currentPrice) * tickSize / pipSize * Convert.ToDecimal(Math.Pow(10, symbol.Digits));

            return decimal.ToDouble(result);
        }
    }
}
 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
import clr
import math

clr.AddReference("cAlgo.API")

from cAlgo.API import *
from robot_wrapper import *


class Sample():
    def on_start(self):
        spreadInPips = SymbolExtensions.normalize_pips(api.Symbol, SymbolExtensions.to_pips(api.Symbol, api.Symbol.Spread))
        print(spreadInPips)

        spreadInTicks = round(SymbolExtensions.to_ticks(api.Symbol, api.Symbol.Spread))
        print(spreadInTicks)

        stopLossInPips = 60

        stopLossInPrice = api.Symbol.Ask - (SymbolExtensions.normalize_pips(api.Symbol, stopLossInPips) * api.Symbol.PipSize)
        print(stopLossInPrice)


class SymbolExtensions:
    @staticmethod
    def get_pip(symbol):
        return symbol.TickSize / symbol.PipSize * math.pow(10, symbol.Digits)

    @staticmethod
    def to_pips(symbol, price):
        return price * SymbolExtensions.get_pip(symbol)

    @staticmethod
    def to_ticks(symbol, price):
        return price * math.pow(10, symbol.Digits)

    @staticmethod
    def round(symbol, price):
        return round(price, symbol.Digits)

    @staticmethod
    def normalize_pips(symbol, pips):
        currentPrice = float(symbol.Bid)
        pipSize = float(symbol.PipSize)
        pipsDecimal = float(pips)

        pipsAddedToCurrentPrice = round((pipsDecimal * pipSize) + currentPrice, symbol.Digits)
        tickSize = float(symbol.TickSize)

        result = (pipsAddedToCurrentPrice - currentPrice) * tickSize / pipSize * math.pow(10, symbol.Digits)
        return round(result, 12)

Lấy chi tiết giao dịch

Transactions chứa các loại cung cấp dữ liệu về nạp tiền và rút tiền cho các tài khoản. Các loại này cho phép bạn truy cập và quản lý chi tiết giao dịch cho tài khoản theo chương trình.

Bạn có thể truy xuất dữ liệu về loại giao dịch (nạp tiền hoặc rút tiền), số tiền, dấu thời gian, ID giao dịch, chi tiết số dư, thuộc tính vốn, v.v.

cBot này truy xuất và in ra chi tiết giao dịch:

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

namespace cAlgo.Robots
{
    [Robot]
    public class TransactionsAPITEST : Robot
    {
        protected override void OnStart()
        {           
            foreach (var transaction in Transactions)
            {
                Print($"Transaction ID: {transaction.Id}, Amount: {transaction.Amount}, Type: {transaction.Type}, Date: {transaction.Time}");
            }
        }
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
import clr

clr.AddReference("cAlgo.API")

# Import cAlgo API types
from cAlgo.API import *
from cAlgo.API.Internals import *

# Import trading wrapper functions
from robot_wrapper import *

class TransactionsAPITEST():
    def on_start(self):
        for transaction in api.Transactions:
            api.Print(
                f"Transaction ID: {transaction.Id}, "
                f"Amount: {transaction.Amount}, "
                f"Type: {transaction.Type}, "
                f"Date: {transaction.Time}"
            )

Lấy dữ liệu lệnh lịch sử

cTrader cung cấp bộ sưu tập HistoricalOrder để cho phép người dùng truy xuất thông tin về lệnh, bao gồm lệnh thị trường đã hoàn thành và lệnh chờ đã được thực hiện hoặc hủy bỏ. Các chi tiết có thể truy xuất bao gồm ID lệnh, loại lệnh, nhãn, giá mục tiêu, thời gian hết hạn, v.v.

Mã cBot dưới đây cho bạn thấy cách lấy chi tiết cho các lệnh lịch sử:

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

namespace cAlgo.Robots
{
    [Robot(AccessRights = AccessRights.None)]
    public class HistoricalOrdersExample : Robot
    {
        protected override void OnStart()
        {
            var historicalOrders = HistoricalOrders;
            foreach (var order in historicalOrders)
            {
                Print($"Order ID: {order.Id}");
                Print($"Type: {order.OrderType}");
                Print($"Volume: {order.VolumeInUnits}");
                Print($"Price: {order.TargetPrice}");
                Print($"Expiration: {order.ExpirationTime}");
                Print($"Comment: {order.Comment}");
                Print($"Label: {order.Label}");
                Print($"Stop Loss: {order.StopLoss}");
                Print($"Take Profit: {order.TakeProfit}");
                Print($"TradeType: {order.TradeType}");
                Print($"Quantity: {order.Quantity}");
                Print($"Label: {order.Label}");
            }
        }
    }
}

Sử dụng dữ liệu giao dịch lịch sử

Khi lập trình cBot, bạn có quyền truy cập vào lịch sử tài khoản của mình. Điều này có nghĩa là bạn có thể lặp qua các giao dịch trong quá khứ của mình và sử dụng dữ liệu của chúng cho bất kỳ mục đích nào bạn có.

Đoạn mã dưới đây tạo một tệp .CSV chứa tất cả các giao dịch trong quá khứ của chúng ta và dữ liệu giao dịch 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
28
29
30
31
32
33
using System;
using cAlgo.API;
using System.Text;
using System.IO;

namespace Samples
{
    /* We provide the access rights required for
    reading and writing in locally stored files. */
    [Robot(AccessRights = AccessRights.FullAccess)]
    public class Sample : Robot
    {
        protected override void OnStart()
        {
            var stringBuilder = new StringBuilder();

            _ = stringBuilder.AppendLine($"PositionId,TradeType,SymbolName,VolumeInUnits,EntryTime,EntryPrice,ClosingTime,ClosingPrice,NetProfit,Balance");

            // All trades are inside the 'History' collection
            foreach (var trade in History)
            {
                _ = stringBuilder.AppendLine($"{trade.PositionId},{trade.TradeType},{trade.SymbolName},{trade.VolumeInUnits},{trade.EntryTime:o},{trade.EntryPrice},{trade.ClosingTime:o},{trade.ClosingPrice},{trade.NetProfit},{trade.Balance}");
            }

            // We will save the CSV file on our desktop
            var desktopPath = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);

            var filePath = Path.Combine(desktopPath, $"{Account.Number}_History.csv");

            File.WriteAllText(filePath, stringBuilder.ToString());
        }
    }
}

Lấy thông tin về các giao dịch

Trong cTrader, các giao dịch thực hiện lệnh và khiến các vị thế được mở hoặc đóng. Tùy thuộc vào thanh khoản thị trường, một lệnh có thể được khớp hoàn toàn bởi một giao dịch duy nhất hoặc từng phần bởi nhiều giao dịch. Xem Vị thế và giao dịch để tìm hiểu thêm.

Mã cBot dưới đây cho bạn thấy cách truy xuất thông tin về nhiều giao dịch tồn tại trong một vị thế duy nhấ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
using System;
using cAlgo.API;

namespace cAlgo.Robots
{
    [Robot(AccessRights = AccessRights.None)]
    public class DealsExample : Robot
    {
        protected override void OnStart()
        {
            var position = ExecuteMarketOrder(TradeType.Buy, "EURUSD", 10000);

            var deals = position.Position.Deals;

            foreach (var deal in deals)
            {
                Print(deal.ExecutionTime + " " + deal.Status + " " + deal.Id);
            }

            ClosePosition(position.Position, 3000);
            ClosePosition(position.Position, 7000);

            var closing_deals = History.FindByPositionId(position.Position.Id);

            foreach (var closing_deal in closing_deals)
            {
                Print(closing_deal.ClosingDeal.ExecutionTime + " " + closing_deal.ClosingDeal.VolumeInUnits);
            }
        }

        protected override void OnStop()
        {
        }
    }
}
 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
import clr

clr.AddReference("cAlgo.API")

# Import cAlgo API types
from cAlgo.API import *
from cAlgo.API.Internals import *

# Import trading wrapper functions
from robot_wrapper import *

class DealsExample():
    def on_start(self):
        position = api.ExecuteMarketOrder(TradeType.Buy, "EURUSD", 10000)

        deals = position.Position.Deals

        for deal in deals:
            api.Print(f"{deal.ExecutionTime} {deal.Status} {deal.Id}")

        api.ClosePosition(position.Position, 3000)
        api.ClosePosition(position.Position, 7000)

        closing_deals = api.History.FindByPositionId(position.Position.Id)

        for closing_deal in closing_deals:
            api.Print(f"{closing_deal.ClosingDeal.ExecutionTime} {closing_deal.ClosingDeal.VolumeInUnits}")

    def on_stop(self):
        pass

Chuyển đổi lot thành đơn vị

Theo mặc định, các thuật toán cTrader tính toán khối lượng bằng đơn vị thay vì lot. Tuy nhiên, trong một số trường hợp, bạn có thể thấy làm việc với lot thuận tiện và quen thuộc hơn.

Bạn có thể chuyển đổi lot thành đơn vị bằng cách sử dụng phương thức Symbol.QuantityToVolumeUnits().

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
using System;
using cAlgo.API;
using System.Text;
using System.IO;

namespace Samples
{
    [Robot(AccessRights = AccessRights.None)]
    public class Sample : Robot
    {
        protected override void OnStart()
        {
            var lots = 2.5;

            var volumeInUnits = Symbol.QuantityToVolumeInUnits(lots);

            ExecuteMarketOrder(TradeType.Sell, SymbolName, volumeInUnits);
        }
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
import clr

clr.AddReference("cAlgo.API")

# Import cAlgo API types
from cAlgo.API import *
from cAlgo.API.Internals import *

# Import trading wrapper functions
from robot_wrapper import *

class Sample():
    def on_start(self):
        lots = 2.5
        volume_in_units = api.Symbol.QuantityToVolumeInUnits(lots)
        api.ExecuteMarketOrder(TradeType.Sell, api.SymbolName, volume_in_units)

Ngoài ra, bạn có thể sử dụng phương thức Symbol.VolumeInUnitsToQuantity() để chuyển đổi đơn vị thành lot.

Làm việc với màu sắc

cBot có thể sử dụng màu sắc tùy chỉnh khi thực hiện các thao tác khác nhau (ví dụ: khi hiển thị văn bản trên biểu đồ giao dịch). Để thêm màu sắc như một tham số có thể tùy chỉnh, hãy thêm mã sau vào khai báo tham số của bạn.

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

Ghi chú

Bạn có thể sử dụng cả mã màu thập lục phân và tên màu (như red") khi xác định DefaultValue của tham số như vậy."

Để minh họa cách hoạt động của tham số màu sắc, chúng ta sẽ tạo một cBot đơn giản mà, khi được khởi động, sẽ viết văn bản trên biểu đồ giao dịch mà nó đang hoạt động. Màu sắc của văn bản này sẽ có thể tùy chỉnh thông qua tham số TextColor.

 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
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.Robots
{
    [Robot(AccessRights = AccessRights.None)]
    public class SampleColorcBot : Robot
    {
        [Parameter("Text Color", DefaultValue = "red")]
        public Color TextColor { get; set; }

        protected override void OnStart()
        {
            var staticText = Chart.DrawStaticText("static", "Sample text to demonstrate how color works", VerticalAlignment.Center, HorizontalAlignment.Center, TextColor);

        }

    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
import clr

clr.AddReference("cAlgo.API")

# Import cAlgo API types
from cAlgo.API import *
from cAlgo.API.Internals import *

# Import trading wrapper functions
from robot_wrapper import *

class SampleColorcBot():
    def on_start(self):
        api.Chart.DrawStaticText(
            "static",
            "Sample text to demonstrate how color works",
            VerticalAlignment.Center,
            HorizontalAlignment.Center,
            api.TextColor
        )