コンテンツにスキップ

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

拡張メソッドは、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を作成できます。 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を作成してみます。 各バーで、このアルゴリズムは現在オープンしているポジションのリストを確認し、それらの損切り水準をブレイクイーブンポイントに調整します。 そのために、PositionクラスにBreakEven()拡張メソッドを作成する必要があります。

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

1
2
3
public static class MyExtensions {

}

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

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()メソッド以外は使用する必要はありません。 各バーで、cBotに簡単な操作を実行するよう指示します。具体的には、Positionsコレクションを反復処理し、その中の各要素に対して新しいBreakEven()メソッドを呼び出します。

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

cBotをビルドして起動すると、その動作を確認できます。 特に多くのオープンポジションを管理する際に、便利な取引アシスタントとなります。

インジケーターで拡張メソッドを使用する

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

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

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に新しい機能を追加する再利用可能なコードを作成したい場合に、価値のあるツールです。 拡張メソッドを使用すると、アルゴリズムをより効率的かつ保守しやすくすることができるため、ぜひ実験してみることをお勧めします。