cBotのライフサイクル

この記事とそれに対応するビデオでは、コード構造を順を追って説明し、cTrader cBotのイベントとライフサイクルの背後にあるロジックを解説します。

念のため、cBotはcTraderの「Algo」アプリケーションでアクセスできます。新しいcBotを作成するには、「新しいcBot」ボタンをクリックするか、以下に示すドロップダウンメニューからこのオプションを選択します。

基本テンプレートの解釈方法

新しいcBotを作成すると、コードエディタウィンドウに次の基本構造が表示されます。

 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
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 NewcBot : Robot
    {
        [Parameter(DefaultValue = "Hello world!")]
        public string Message { get; set; }

        protected override void OnStart()
        {
            // To learn more about cTrader Algo visit our Help Center:
            // https://help.ctrader.com/ctrader-algo

            Print(Message);
        }

        protected override void OnTick()
        {
            // Handle price updates here
        }

        protected override void OnStop()
        {
            // Handle cBot stop here
        }
    }
}

基本テンプレートには、OnStart()OnTick()OnStop()の3つのイベントが表示されています。後で2つの追加メソッド(OnBar()およびOnException())を追加し、それらがどのように機能するかを説明します。まずは、OnStart()メソッドについて説明します。

OnStart()メソッドの使用方法

OnStart()メソッドは、cBotが最初に開始されたときにトリガーされます。このメソッドは、インジケーター、カウンター、イベントハンドラー、タイマーなど、cBotで使用する予定の変数を初期化するために使用されます。

初期コードテンプレート

初期コードテンプレートには、cBotが開始されたときにメッセージをログに出力するコード文が既に含まれています。ご覧のように、cBotにはMessageパラメーターがあり、OnStart()メソッドはこのパラメーターの値をPrint()メソッドに渡します。

cBotインスタンスを「トレード」アプリケーションで開始し、ログタブを開くことで、OnStart()メソッドの動作をデモンストレーションできます。

いつでもcBotを停止し、「パラメーター」タブでMessageパラメーターの値を変更し、インスタンスを再起動することができます。開始時には、新しいメッセージがログに出力されます。

OnTick()メソッドの使用方法

OnTick()メソッドは、シンボルのビッドまたはアスク価格が変更されるたびにトリガーされます。このメソッドの中で、通常はポジションのエントリおよびエグジット条件をプログラムしたり、新しいティックデータが到着したときに実行する必要がある他の補助機能をプログラムしたりします。

次のコードをOnTick()メソッドに追加し、ログにメッセージを出力するようにします。

1
Print("OnTick. Bid: ", Symbol.Bid, ", Ask: ", Symbol.Ask);

以下のように、cBotは価格が変更されるたびにビッドおよびアスク価格をログに出力するようになりました。

OnBar()メソッドの使用方法

OnBar()メソッドは、デフォルトのcBotコードテンプレートには含まれていないため、次のコードスニペットを追加して追加します。

1
2
3
4
protected override void OnBar() 
{
    Print("OnBar");
}

OnBar()メソッドは、新しいバーやキャンドルがcBotにアタッチされたチャートに描画されるたびにトリガーされます。OnTick()メソッドと同様に、OnBar()メソッドを使用して、ポジションのエントリおよびエグジット条件をプログラムしたり、新しいバーの形成時に実行する必要があるロジックを実行したりできます。

OnBar()メソッドのトリガー方法

たとえば、H1チャートでは、新しいバーが1時間ごとに形成されるため、OnBar()メソッドは1時間ごとに呼び出されます。m1チャートでは、同じメソッドが1分ごとに呼び出されます。

私たちのOnBar()メソッドは、新しいバーやキャンドルが形成されるたびに"OnBar"を出力します。これがどのように機能するかをデモンストレーションするために、cBotをm1チャートにアタッチし、ログを確認します。

OnStop()メソッドの使用方法

OnStopメソッドは、ユーザーまたはコードによってcBotが停止されたときに呼び出され、このときにOnStopメソッド内のコードが実行されます。これを使用して、ポジションのクローズなどの最終操作を実行できます。

次のコードをOnStop()メソッドに追加し、cBotが停止されたときにMessageパラメーターの値を出力するようにします。

1
Print(Message);

以下のスクリーンショットで、cBotのインスタンスを起動して停止させ、その動作を示します。

OnException()メソッドの使用方法

OnException()メソッドイベントは、cBotのフォルトトレランスの一種で、未処理の例外をキャプチャし、それに対処する方法を決定することができます。デフォルトのコードテンプレートには含まれていないため、次のスニペットを使用して追加します。

1
2
3
4
protected override void OnException(Exception exception) 
{
    Print("Ooops, unhandled exception! No worries, cBot still alive");            
}

例外が発生したときにOnException()メソッドをトリガーするために、存在しないトレードの情報にアクセスしようとすると発生する例外をキャプチャするコードを書きます。次のコードをOnStart()メソッドに追加します。

1
ExecuteMarketOrder(TradeType.Buy, SymbolName, 1000, "my label");

上記のコードは、次の構成可能なパラメーターを使用して市場注文を実行します。

  • トレードタイプは買い注文になります。
  • トレードは、cBotがアタッチされたチャートの現在のシンボルに対して実行されます。
  • 注文のボリュームは1,000ユニットです。
  • 注文に付けられる一意のラベルは「my label」です。

次のコードもOnTick()メソッドに追加します。

1
2
3
var position = Positions.Find("my label");
if (Positions.Find("my label") != null) Print("PositionId: ", position.Id);
Print("Message below");

OnTick()メソッドで記述したコードは、OnStart()メソッドで開かれたポジションをラベル名「my label」を使用して見つけます。

同じラベルのポジションが見つかると、そのポジションのIDをログに出力します。また、「Message below」という別のメッセージも次の行で出力します。

cBotが起動され、OnTick()メソッドが呼び出されて注文が見つかると、cBotは注文IDをログに出力し、その後に「Message below」メッセージを出力します。

ご覧の通り、例外は発生せず、cBotは完璧に動作しています。

しかし、今度はcBotが開いたポジションを手動でクローズし、必ず例外が発生するようにコードを少し変更します。OnStart()メソッドでは、注文のラベルを「cTrader」に変更します。OnTick()メソッドでは、「my label」ラベルを持つポジションが存在するかどうかを確認する条件文をコメントアウトします。

最終的なcBotのコードは次の通りです。このコードは必ず例外をトリガーします。

 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
namespace cAlgo.Robots
{
    [Robot(AccessRights = AccessRights.None)]
    public class LifecycleTest : Robot
    {
        [Parameter(DefaultValue = "cTrader rocks!")]
        public string Message { get; set; }

        protected override void OnStart()
        {
            ExecuteMarketOrder(TradeType.Buy, SymbolName, 1000, "cTrader");
        }

        protected override void OnTick()
        {
            var position = Positions.Find("my label");
            //if (Positions.Find("my label") != null) 
            Print("PositionId: ", position.Id);
            Print("Message below");
        }

        protected override void OnStop()
        {
            Print(Message);
        }

        protected override void OnException(Exception exception) 
        {
            Print("Ooops, unhandled exception! No worries, cBot still alive");            
        }
    }
}

再度cBotを実行し、何が起こるかを見てみましょう。

起こったことは、新しい市場注文がcBotの起動時に作成され、その注文には"cTrader"のラベルが付けられました。OnTick()メソッドでは、my labelというラベルを持つポジションを取得しようとし、その条件文をコメントアウトしました。その後、ログにポジションIDを出力しようとしました。

これにより、通常のcTraderの以前のバージョンではcBotが停止していた例外エラーが発生しましたが、新しいOnException()メソッドにより、このエラーをキャプチャして処理することができるようになりました。cBotは実行を続け、エラーをログに記録して修正することができます。

まとめ

要約すると、cBotのライフサイクルは、OnStart()OnTick()OnStop()OnBar()、およびOnException()メソッドを通じて主要なイベントを処理することができます。これらの方法をカスタマイズすることで、アルゴリズムが予期した通りに動作するようにすることができます。