cTrader APIにメソッドを追加する方法

cBots (自動売買)

拡張メソッドは、cTrader API に新しい機能を追加したい場合に非常に重要なツールです。比較的簡単な構文を使用して、SymbolPosition などの事前定義された API クラスに新しい動作を追加できます。拡張メソッドを定義した後は、拡張したクラスのオブジェクトからそれを呼び出すことができます。

拡張メソッドの使用例

まず、拡張メソッドを使用する理由について簡単に説明します。

cBot を使用して、特定のポジションのロット数を取得したいとします。この情報は私たちのトレーディング戦略に直接影響するためです。そのため、Position クラスの変数を初期化し、その Lots() メソッドにアクセスしようとすることができます。

1
2
Position position = Positions.Last();
Print(position.Lots());

単にこのコードを入力すると、API に Lots() アクセサが存在しないことを示すエラーが表示されます。しかし、既存の API メンバーに他の機能を影響させずに新しいメソッドを追加する方法があったとしたらどうでしょうか?

このメソッドが存在するという前提で、すべての現在のポジションのリストを反復し、そのサイズをロット単位でログに出力する単純な cBot を作成することができます。OnBar() メソッドを次のように定義します。

1
2
3
4
5
6
protected override void OnBar()
{
    foreach (var position in Positions) {
        Print(position.Lots());
    }
}

拡張メソッドを使用すると、わずか数行のコードで Lots() 機能を追加し、Position クラスの任意のオブジェクトで再利用することができます。以下にその作成方法を説明し、いくつかのアルゴの例を示します。

拡張メソッドの動作方法

拡張メソッドを使用する際には、以下のルールに注意してください。

  • 拡張メソッドは常に静的です。

静的メソッドを宣言するには、static キーワードを使用するだけです。以下に、空の本体を持つ Lots() メソッドを宣言します。

1
2
3
4
public static class MyExtensions {
    public static double Lots() {}
}
  • 拡張メソッドは任意の数の引数を持つことができますが、最初の引数は常にデータ型/クラスを指定する必要があり、その前に this キーワードが付いています。

Lots() メソッドの最初で唯一の引数として Position クラスのオブジェクトを追加します。Position オブジェクトにはポジションが開かれているシンボルの情報も含まれているため、他の引数は必要ありません。

1
2
3
public static class MyExtensions {
    public static double Lots(this Position position) {}
}
  • 拡張メソッドは、提供された引数に適した任意のロジックを含むことができます。

拡張メソッドの本体を定義するときに特別な構文を使用する必要はありません。他のメソッドと同様に扱うことができるため、次のようにその本体を定義できます。

1
2
3
4
5
public static class MyExtensions {
    public static double Lots(this Position position) {
        return position.VolumeInUnits / position.Symbol.LotSize;
    }
}
  • 拡張メソッドはインスタンスメソッドまたは静的メソッドとして呼び出すことができます。

拡張メソッドを cBot のコードで呼び出す方法は2つあります。

インスタンスメソッド構文を使用する場合、Position 型の任意の適切なオブジェクトからメソッドを呼び出すだけです。

1
2
var position = Positions.Last();
Print(position.Lots());

静的メソッド構文を使用する場合は、対応する静的クラスを完全に指定した後で拡張メソッドを呼び出すことができます。

1
2
var position = Positions.Last();
Print(MyExtensions.Lots(position));

どの呼び出し方法が最も便利かを判断するのはあなた次第です。

メソッドシグネチャ

インスタンス構文を使用する場合、拡張メソッドのシグネチャが組み込みの API メソッド (例: Position.Close()) と同じになる状況を避けてください。これらの状況では、同じシグネチャを持つ拡張メソッドを呼び出そうとすると、毎回組み込みメソッドが呼び出されます。

IntelliSense

拡張メソッドを呼び出そうとすると、IntelliSense はそれを組み込みの API メンバーと区別するために特別なアイコンを使用します。

新しいメソッドを実際に動作させるために、スタート時に3つの注文を異なるボリュームで配置する cBot を作成できます。バーごとに、現在開いているすべてのポジションのボリュームをロット単位でログに出力します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
protected override void OnStart()
{
    ExecuteMarketOrder(TradeType.Buy, SymbolName, 10000);
    ExecuteMarketOrder(TradeType.Buy, SymbolName, 100000);
    ExecuteMarketOrder(TradeType.Buy, SymbolName, 50000);
}
protected override void OnBar()
{
    foreach (var position in Positions) {
        Print(position.Lots());
    }
}

cBot をビルドして起動した後、ログに正しい値が出力されていることを確認する必要があります。

cBot での拡張メソッドの使用

次に、より複雑な cBot を作成します。バーごとに、アルゴは現在開いているポジションのリストを調べ、ストップロスレベルを損益分岐点に調整します。これを行うために、BreakEven() 拡張メソッドを Position クラスに作成します。

新しい cBot を作成し、名前を変更します。その後、不要なコードをすべて削除し、MyExtensions クラスを追加します。

1
2
3
public static class MyExtensions {
}

私たちの BreakEven() メソッドのコードは比較的簡単です。ポジションにストップロスが設定されているか、総利益がゼロより大きいか、現在設定されているストップロスがポジションのエントリ価格と等しくないかを確認します。これらの条件がすべて真の場合、ポジションのストップロスをポジションのエントリ価格に等しくなるように変更します。

1
2
3
4
5
6
7
public static class MyExtensions {
    public static void BreakEven(this Position position) {
        if (position.StopLoss is not null && position.GrossProfit > 0 && position.StopLoss != position.EntryPrice) {
            position.ModifyStopLossPrice(position.EntryPrice);
        }
    }
}

cBot 自体では、OnBar() メソッド以外のメソッドを使用する必要はありません。バーごとに、アルゴに単純な操作を実行させます。つまり、Positions コレクションを反復し、その要素ごとに新しい BreakEven() メソッドを呼び出します。

1
2
3
4
5
6
protected override void OnBar() 
{
    foreach (var position in Positions) {
        position.BreakEven();
    }
}

ボットをビルドして起動した後、実際の動作を確認できます。多くのポジションを管理する際には特に便利なトレーディングアシスタントになるでしょう。

インジケーターでの拡張メソッドの使用

拡張メソッドに依存する便利なインジケーターも作成します。このインジケーターは、シンボルの価格が各バーの始値に対してどれだけ変動したかをパーセンテージでプロットすることでボラティリティを測定します。

そのために、新しいインジケーターを作成して名前を変更します。コードエディタウィンドウで、MyExtensions クラスを作成して Bar クラスを拡張します。

1
2
3
public static class MyExtensions {
}

PercentageChange() メソッドも追加します。priceChange 変数では、バーのクローズ価格からオープン価格を引きます。メソッドは、価格変動をオープン価格で割り、100を掛けた値を返します。

1
2
3
4
5
6
7
8
public static class MyExtensions 
{
    public static double PercentageChange(this Bar bar) 
    {
        var priceChange = bar.Open - bar.Close;
        return priceChange / bar.Open * 100;
    }
}

インジケーターのコード自体では、Initialize() メソッドや不要なパラメーターは必要ありません。Calculate() メソッドの本体では、各バーで新しい PercentageChange() メソッドを呼び出すだけです。

1
2
3
4
5
6
7
8
[Output("Main")]
public IndicatorDataSeries Result { get; set; }
public override void Calculate(int index)
{
    Result[index] = Bars[index].PercentageChange();
}

その後、インジケーターを保存してビルドします。インジケーターのインスタンスを作成すると、正しいパーセンテージ変化がプロットされているのがわかります。これらは短期および長期のボラティリティを判断するために使用でき、さまざまなトレーディング戦略に役立ちます。

まとめ

最後に、拡張メソッドは cTrader API に新しい機能を追加するための貴重なツールです。アルゴをより効率的で保守しやすくするために、拡張メソッドを試してみることを強くお勧めします。Algo API を使った作業についてもっと知りたい場合は、新しい動画を公開するたびに通知を受け取るために私たちの YouTube チャンネルを購読してください。

目次

このページについて