Bỏ qua

Thực thi lệnh song song trong cTrader

Một trong những tính năng làm cho cTrader nổi bật là khả năng sử dụng cả lập trình đồng bộ và bất đồng bộ để thực thi các lệnh của bạn. Bạn có thể sử dụng lập trình đồng bộ để triển khai các chiến lược cần đợi kết quả thực thi lệnh trước khi tiếp tục; ngược lại, lập trình bất đồng bộ được sử dụng tốt nhất khi tạo chiến lược tốc độ cao có thể gửi nhiều lệnh cùng một lúc.

Trong video này và bài viết tương ứng, chúng tôi sẽ giải thích sự khác biệt giữa thực thi đồng bộ và bất đồng bộ và chúng tôi sẽ chỉ cho bạn cách sử dụng cả hai phương pháp này để đặt lệnh mới.

Thực thi lệnh đồng bộ và bất đồng bộ

Luồng cơ bản

Thực thi lệnh đồng bộ có thể được giải thích bằng cách sử dụng một sơ đồ đơn giản. Khi đặt lệnh mới một cách đồng bộ, một cBot phải đợi một lệnh được thực thi trước khi nó thực hiện bất kỳ hướng dẫn nào khác. Nói cách khác, cTrader gửi một lệnh đến máy chủ, đợi phản hồi, và chỉ sau đó mới bắt đầu thực thi dòng mã tiếp theo.

flowchart LR
  A([Lệnh 1, 100 ms]) --> B([Lệnh 2, 70 ms]) --> C([Lệnh 3, 80 ms]) --> D([Hướng dẫn tiếp theo]) 

Khi đặt các lệnh trên một cách đồng bộ, cBot của bạn sẽ phải mất tổng cộng 250 ms trước khi tiếp tục với bất kỳ hướng dẫn nào được chỉ định sau Lệnh 3.

Mặt khác, thực thi bất đồng bộ cho phép cTrader gửi nhiều lệnh song song mà không cần đợi phản hồi từ máy chủ. Bằng cách sử dụng lập trình bất đồng bộ, một chiến lược có thể giảm thiểu tổng thời gian cần thiết để thực thi nhiều lệnh.

flowchart LR
  subgraph Orders
    direction TB
    A([Lệnh 1, 100 ms]) --- B([Lệnh 2, 70 ms]) --- C([Lệnh 3, 80 ms])
  end
  D([Hướng dẫn tiếp theo])
  Orders --> D

Trong sơ đồ trên, cả ba lệnh được gửi đi cùng một lúc và cBot không đợi kết quả thực thi của chúng trước khi tiếp tục với các hướng dẫn tiếp theo.

Ví dụ mã

Chúng ta cũng có thể sử dụng mã để minh họa cách thực thi đồng bộ hoạt động.

1
2
3
4
5
6
7
8
9
protected override void OnStart()
{
    for (int i = 0; i < 10; i++)
    {
        ExecuteMarketOrder(TradeType.Buy, SymbolName, 1000);
        Print("Order Sent");
        Print("Positions Count:" + Positions.Count); 
    }
}

Nếu chúng ta chạy một cBot với mã này, nhật ký sẽ cho thấy số lượng vị thế chỉ tăng lên sau khi mỗi vị thế được thực thi. Mã đang đợi mỗi lệnh được thực thi trước khi gửi yêu cầu thực thi lệnh tiếp theo.

Để chuyển sang thực thi lệnh bất đồng bộ, chúng ta có thể sử dụng phương thức ExecuteMarketOrderAsync.

1
2
3
4
5
6
7
8
9
protected override void OnStart()
{
    for (int i = 0; i < 10; i++)
    {
        ExecuteMarketOrderAsync(TradeType.Buy, SymbolName, 1000);
        Print("Order Sent");
        Print("Positions Count:" + Positions.Count); 
    }
}

Chúng ta cũng sẽ thêm một trình xử lý sự kiện để lắng nghe sự kiện Positions.Opened.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
protected override void OnStart()
{
    Positions.Opened += Positions_Opened;
    for (int i = 0; i < 10; i++)
    {
        ExecuteMarketOrderAsync(TradeType.Buy, SymbolName, 1000, PositionOpened);
        Print("Order Sent");
        Print("Positions Count:" + Positions.Count); 
    }
}

Trong trình xử lý sự kiện của chúng ta, chúng ta sẽ in một thông báo vào nhật ký ngay khi một vị thế được mở cũng như số lượng vị thế mở tại thời điểm đó.

Nếu chúng ta chạy một cBot với mã này và xem nhật ký, chúng ta sẽ thấy rằng tất cả các lệnh đã được gửi mà không nhận được xác nhận về kết quả của các hướng dẫn trước đó. Bộ đếm vị thế vẫn ở mức 0 trong suốt thời gian. Các xác nhận đã đến và được in vào nhật ký vài mili giây sau khi tất cả các lệnh được gửi đến máy chủ.

Sử dụng lệnh gọi lại

Bây giờ chúng ta có thể quay lại mã nguồn của mình và minh họa một tính năng quý giá khác của thực thi bất đồng bộ, cụ thể là tùy chọn sử dụng các phương thức gọi lại được gọi ngay khi việc thực thi lệnh hoàn tất. Chúng ta sẽ xóa trình xử lý sự kiện Positions.Opened của chúng ta và triển khai một phương thức gọi lại in ra xác nhận khi một lệnh đã được thực thi.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
private void TradeExecuted(TradeResult tradeResult)
{
    if (tradeResult.IsSuccessful)
    {
        Print("Trade succeeded. Position Opened.");
    }
    else
    {
        Print("Trade failed. Position Not Opened.");
    }
}

Sau đó, chúng ta sẽ truyền phương thức này như một đối số cho phương thức ExecuteMarketOrderAsync.

1
ExecuteMarketOrderAsync(TradeType.Buy, SymbolName, 1000, TradeExecuted);

Trái ngược với cách tiếp cận trước đây của chúng ta, phương thức gọi lại sẽ được gọi bất kể giao dịch có thành công hay không, điều này cũng có nghĩa là bạn được thông báo về các giao dịch không thành công và có thể hành động phù hợp.

Giám sát trạng thái của thực thi bất đồng bộ

cTrader cũng cung cấp một công cụ dễ sử dụng để theo dõi trạng thái của các giao dịch bất đồng bộ. Phương thức ExecuteMarketOrderAsync trả về một đối tượng TradeOperation chứa thông tin về việc lệnh có đang được thực thi hay không.

Chúng ta có thể bắt đầu bằng cách khai báo một trường mới.

1
TradeOperation _tradeOperation;

Sau đó, chúng ta sẽ xóa vòng lặp for của mình và gán kết quả thực thi lệnh cho trường mới.

1
_tradeOperation = ExecuteMarketOrderAsync(TradeType.Buy, SymbolName, 1000, TradeExecuted);

Chúng ta cũng sẽ thêm một bộ đếm thời gian vào cBot của mình. Bộ đếm thời gian sẽ kiểm tra trạng thái của một hoạt động cứ sau 100 mili giây.

1
2
Timer.TimerTick += Timer_TimerTick;
Timer.Start(new System.TimeSpan(0, 0, 0, 0, 100));

Nếu một hoạt động vẫn đang thực thi, bộ đếm thời gian sẽ in điều này vào nhật ký.

1
2
3
4
5
6
7
8
private void Timer_TimerTick()
{
    Print("Tick");
    if (_tradeOperation != null)
    {
        Print("Trade operation is executing: " + _tradeOperation.IsExecuting);
    }
}

Sau khi cBot được xây dựng, chúng ta có thể kiểm tra cách nó hoạt động trên một tài khoản demo. Trong nhật ký, bộ đếm thời gian sẽ in ra các cập nhật thường xuyên về trạng thái thực thi bất đồng bộ.

Tổng quan

Thực thi bất đồng bộ là một công cụ mạnh mẽ có thể giúp việc đặt lệnh tự động nhanh hơn nhiều so với lập trình đồng bộ. Tuy nhiên, thực thi đồng bộ vẫn có thể được sử dụng trong trường hợp bạn cần biết kết quả của một giao dịch trước khi tiến hành bước tiếp theo. Mặt khác, thực thi bất đồng bộ phù hợp nhất khi bạn cần gửi nhiều lệnh song song mà không có bất kỳ độ trễ nào.