ข้ามไปที่เนื้อหา

การดำเนินการคำสั่งแบบขนานใน cTrader

หนึ่งในคุณสมบัติที่ทำให้ cTrader โดดเด่นคือความสามารถในการใช้การเขียนโปรแกรมแบบซิงโครนัสและอะซิงโครนัสเพื่อดำเนินการคำสั่งของคุณ คุณสามารถใช้การเขียนโปรแกรมแบบซิงโครนัสเพื่อใช้กลยุทธ์ที่ต้องรอผลการดำเนินการคำสั่งก่อนที่จะดำเนินการต่อไป หรือการเขียนโปรแกรมแบบอะซิงโครนัสจะเหมาะที่สุดเมื่อสร้างกลยุทธ์ความเร็วสูงที่สามารถส่งคำสั่งหลายรายการพร้อมกันได้

ในวิดีโอนี้และบทความที่เกี่ยวข้อง เราจะอธิบายความแตกต่างระหว่างการดำเนินการแบบซิงโครนัสและอะซิงโครนัส และเราจะแสดงวิธีการใช้แนวทางทั้งสองนี้เพื่อวางคำสั่งใหม่

การดำเนินการคำสั่งซื้อแบบ Sync เทียบกับ Async

ขั้นตอนพื้นฐาน

การดำเนินการคำสั่งซื้อแบบ Synchronous สามารถอธิบายได้โดยใช้แผนภาพง่ายๆ เมื่อส่งคำสั่งซื้อใหม่แบบ Synchronous cBot จะต้องรอให้คำสั่งหนึ่งดำเนินการเสร็จสิ้นก่อนจึงจะทำตามคำสั่งอื่นๆ กล่าวคือ cTrader จะส่งคำสั่งไปยังเซิร์ฟเวอร์ รอการตอบรับ และหลังจากนั้นจึงเริ่มดำเนินการบรรทัดถัดไปของโค้ด

flowchart LR
  A([ออร์เดอร์ 1, 100 ms]) --> B([ออร์เดอร์ 2, 70 ms]) --> C([ออร์เดอร์ 3, 80 ms]) --> D([คำสั่งถัดไป]) 

เมื่อส่งคำสั่งข้างต้นแบบ Synchronous cBot ของคุณจะต้องใช้เวลาทั้งหมด 250 ms ก่อนที่จะดำเนินการตามคำสั่งที่ระบุหลังจาก Order 3

ในทางกลับกัน การดำเนินการแบบ Async อนุญาตให้ cTrader ส่งคำสั่งหลายรายการพร้อมกันโดยไม่ต้องรอการตอบรับจากเซิร์ฟเวอร์ โดยใช้การเขียนโปรแกรมแบบ Async กลยุทธ์สามารถลดเวลาทั้งหมดที่จำเป็นสำหรับการดำเนินการคำสั่งหลายรายการ

flowchart LR
  subgraph Orders
    direction TB
    A([ออร์เดอร์ 1, 100 ms]) --- B([ออร์เดอร์ 2, 70 ms]) --- C([ออร์เดอร์ 3, 80 ms])
  end
  D([คำสั่งถัดไป])
  Orders --> D

ในแผนภาพข้างต้น คำสั่งทั้งสามรายการจะถูกส่งในเวลาเดียวกันและ cBot จะไม่รอผลการดำเนินการก่อนที่จะดำเนินการตามคำสั่งถัดไป

ตัวอย่างโค้ด

เรายังสามารถใช้โค้ดเพื่อแสดงวิธีการทำงานของการดำเนินการแบบ Sync

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

หากเราเรียกใช้ cBot ด้วยโค้ดนี้ บันทึกจะแสดงว่าจำนวนตำแหน่งเพิ่มขึ้นหลังจากแต่ละตำแหน่งถูกดำเนินการเสร็จสิ้น โค้ดจะรอให้แต่ละคำสั่งดำเนินการเสร็จสิ้นก่อนที่จะส่งคำขอเพื่อดำเนินการคำสั่งถัดไป

เพื่อเปลี่ยนเป็นการดำเนินการคำสั่งซื้อแบบ Async เราสามารถใช้เมธอด 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); 
    }
}

เรายังจะเพิ่มตัวจัดการเหตุการณ์เพื่อฟังเหตุการณ์ 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); 
    }
}

ในตัวจัดการเหตุการณ์ของเรา เราจะพิมพ์ข้อความในบันทึกทันทีที่ตำแหน่งเปิดขึ้น รวมถึงจำนวนตำแหน่งที่เปิดอยู่ในขณะนั้น

หากเราเรียกใช้ cBot ด้วยโค้ดนี้และดูบันทึก เราจะเห็นว่าคำสั่งทั้งหมดถูกส่งโดยไม่ได้รับการยืนยันเกี่ยวกับผลลัพธ์ของคำสั่งก่อนหน้า ตัวนับตำแหน่งยังคงอยู่ที่ 0 ตลอดเวลา การยืนยันมาถึงและถูกพิมพ์ในบันทึกหลังจากส่งคำสั่งทั้งหมดไปยังเซิร์ฟเวอร์แล้วไม่กี่มิลลิวินาที

ใช้คำสั่ง Callback

ตอนนี้เราสามารถกลับไปที่ซอร์สโค้ดของเราและแสดงคุณสมบัติที่มีค่าอีกอย่างของการดำเนินการแบบ Async นั่นคือตัวเลือกในการใช้เมธอด Callback ที่จะถูกเรียกทันทีที่การดำเนินการคำสั่งเสร็จสิ้น เราจะลบตัวจัดการเหตุการณ์ Positions.Opened และนำเมธอด Callback ที่พิมพ์การยืนยันเมื่อคำสั่งถูกดำเนินการเสร็จสิ้นมาใช้

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

เราจะส่งเมธอดนี้เป็นอาร์กิวเมนต์ไปยังเมธอด ExecuteMarketOrderAsync

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

ในทางตรงกันข้ามกับวิธีก่อนหน้า เมธอด Callback จะถูกเรียกไม่ว่าการเทรดจะสำเร็จหรือไม่ ซึ่งหมายความว่าคุณจะได้รับแจ้งเกี่ยวกับการเทรดที่ไม่สำเร็จและสามารถดำเนินการได้ตามนั้น

ติดตามสถานะของการดำเนินการแบบ Async

cTrader ยังมีเครื่องมือที่ใช้ง่ายสำหรับติดตามสถานะของการเทรดแบบ Async เมธอด ExecuteMarketOrderAsync จะคืนค่าอ็อบเจ็กต์ TradeOperation ที่มีข้อมูลเกี่ยวกับว่าคำสั่งยังคงดำเนินการอยู่หรือไม่

เราสามารถเริ่มต้นด้วยการประกาศฟิลด์ใหม่

1
TradeOperation _tradeOperation;

เราจะลบลูป for ของเรา และกำหนดผลลัพธ์ของการดำเนินการคำสั่งไปยังฟิลด์ใหม่

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

เรายังจะเพิ่มตัวจับเวลาไปยัง cBot ของเรา ตัวจับเวลาจะตรวจสอบสถานะของการดำเนินการทุกๆ 100 มิลลิวินาที

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

หากการดำเนินการยังคงดำเนินการอยู่ ตัวจับเวลาจะพิมพ์สิ่งนี้ในบันทึก

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

หลังจากสร้าง cBot เสร็จสิ้น เราสามารถทดสอบการทำงานบนบัญชีทดลองได้ ในบันทึก ตัวจับเวลาควรพิมพ์การอัปเดตสถานะของการดำเนินการแบบ Async เป็นประจำ

สรุป

การดำเนินการแบบ Async เป็นเครื่องมือที่มีประสิทธิภาพที่สามารถทำให้การส่งคำสั่งซื้ออัตโนมัติเร็วขึ้นมากเมื่อเทียบกับการเขียนโปรแกรมแบบ Synchronous อย่างไรก็ตาม การดำเนินการแบบ Synchronous ยังสามารถใช้ได้ในกรณีที่คุณจำเป็นต้องทราบผลลัพธ์ของการเทรดก่อนที่จะดำเนินการขั้นตอนถัดไป ในทางกลับกัน การดำเนินการแบบ Async เหมาะที่สุดเมื่อคุณต้องการส่งคำสั่งหลายรายการพร้อมกันโดยไม่มีการล่าช้า