コンテンツにスキップ

cTraderでの並列注文実行

cTraderを際立たせる機能の1つは、同期および非同期プログラミングを使用して注文を実行できることです。 同期プログラミングを使用して、注文実行の結果を待ってから次のステップに進む必要がある戦略を実装できます。一方、非同期プログラミングは、複数の注文を同時に送信できる高速戦略を作成する際に最適です。

このビデオとその対応する記事では、同期実行と非同期実行の違いを説明し、新しい注文を実行するためにこれらのアプローチを両方使用する方法を示します。

同期 vs 非同期注文実行

基本的な流れ

同期注文実行は、簡単な図を使用して説明できます。 新しい注文を同期実行する場合、cBotは1つの注文が実行されるのを待ってから次の指示に従う必要があります。 言い換えると、cTraderは注文をサーバーに送信し、応答を待ってから次のコード行の実行を開始します。

flowchart LR
  A([注文 1、100 ms]) --> B([注文 2、70 ms]) --> C([注文 3、80 ms]) --> D([後続の指示]) 

上記の注文を同期実行すると、cBotはOrder 3の後に指定された指示に進む前に合計250 msを費やす必要があります。

一方、非同期実行では、cTraderはサーバーからの応答を待たずに複数の注文を並列で送信できます。 非同期プログラミングを使用することで、戦略は複数の注文を実行するために必要な総時間を最小限に抑えることができます。

flowchart LR
  subgraph Orders
    direction TB
    A([注文 1、100 ms]) --- B([注文 2、70 ms]) --- C([注文 3、80 ms])
  end
  D([後続の指示])
  Orders --> D

上記の図では、3つの注文がすべて同時に送信され、cBotはその実行結果を待たずに次の指示に進みます。

コード例

同期実行がどのように機能するかを示すために、コードを使用することもできます。

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を実行すると、ログには各ポジションが実行された後にのみポジション数が増加していることが表示されます。 コードは、次の注文を実行するリクエストを送信する前に、各注文が実行されるのを待っています。

非同期注文実行に変更するには、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のままでした。 確認はすべての注文がサーバーに送信された数ミリ秒後に到着し、ログに印刷されました。

コールバック注文を使用する

ここで、ソースコードに戻り、非同期実行のもう1つの貴重な機能、つまり注文実行が完了するとすぐに呼び出されるコールバックメソッドを使用するオプションをデモンストレーションできます。 Positions.Openedイベントのハンドラを削除し、注文が実行されると確認を印刷するコールバックメソッドを実装します。

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

以前のアプローチとは対照的に、コールバックメソッドは取引が成功したかどうかに関係なく呼び出されるため、非成功の取引についても通知され、それに応じて行動できます。

非同期実行のステータスを監視する

cTraderは、非同期取引のステータスを追跡するための使いやすいツールも提供します。 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がビルドされたら、デモ口座でその動作をテストできます。 ログでは、タイマーが非同期実行のステータスに関する定期的な更新を印刷するはずです。

概要

非同期実行は、同期プログラミングと比較して自動注文配置をはるかに迅速にする強力なツールです。 ただし、次のステップに進む前に取引の結果を知る必要がある場合は、同期実行を使用できます。 一方、非同期実行は、遅延なく複数の注文を並列で送信する必要がある場合に最適です。