cTrader Automate【インジケーターの作成】

アクションマップ

カスタム・インジケータの作成と実装のフロー

  1. 新しいインジケーターを追加する
  2. インジケータコードの編集
  3. インジケータの保存と構築
  4. インジケータ・インスタンスの作成とカスタマイズ

新しいインジケータを追加する

検索バーの上にある「インジケーター」タブを開き、「新規」をクリックします。

サンプルコードを含む新しいインディケータが自動的に作成されます。
インジケーターのリストに「New Indicator」という拡張子が追加されているはずです。

新しいインジケーターを選択し、F2 キーを押すと名前を変更できます。または、新しい拡張子を右クリックし、「名前の変更」を選択します。

サンプルコードを編集する

新しいインジケータをクリックして、以下のコードを含むコード・エディタ・ウィンドウを開きます。

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
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
{
    [Indicator(AccessRights = AccessRights.None)]
    public class NewIndicator : Indicator
    {
        [Parameter(DefaultValue = "Hello world!")]
        public string Message { get; set; }

        [Output("Main")]
        public IndicatorDataSeries Result { get; set; }

        protected override void Initialize()
        {
            // To learn more about cTrader Automate visit our Help Center:
            // https://help.ctrader.com/ctrader-automate

            Print(Message);
        }

        public override void Calculate(int index)
        {
            // Calculate value at specified index
            // Result[index] = 
        }
    }
}

インジケータ属性(Indicator)は、TimeZoneやAccessRightsなどのオプション・プロパティと共に、インジケータ・クラス(NewIndicator)宣言の前にあります。

[Output(“OutputName”)]宣言は、インジケータが何を表示するかを定義します。
これを使用したら、次に宣言するプロパティがIndicatorDataSeriesデータ・タイプであることを確認してください。
[Output(“OutputName”)]宣言にもう1つパラメータを追加することで、インジケータ出力のデフォルトの外観をカスタマイズできます。

1
2
3
/* "Main" is the output name while "Orange"
is chosen as the line color. */
[Output("Main", LineColor = "Orange")]

Initialize()メソッドは、インジケータが起動したときに呼び出されます。
これは通常、ネストしたインジケータなどの変数や系列を初期化するために使用されます。
一般的に、このメソッドには、不要なリソースの消費を避けるためにインジケータ起動時に計算する必要のあるすべての変数を含める必要があります。

次に、Calculate() メソッドを使用して、表示させたいインデックスの特定の値を計算します。
このメソッドは、ヒストリカル・バーごとに自動的に呼び出されます。
マルチシンボル/マルチタイムフレーム実装の場合、インジケータが分析を任されている各シンボルの各ティックで呼び出されます。
Calculate()メソッドは、コードの中で実際のインジケータの計算式を実装する場所と考えてください。例えば、ハーフ・トレンド・インジケーターの計算式を使用する場合、移動平均 の交差を定義するために Calculate() メソッドを使用します。

上記2つのメソッドは、すべてのインジケーターの「糧となるもの」であり、省略することはできません。インジケータをコーディングする際に使用できるクラス、メソッド、プロパティの詳細については、リファレンス・ライブラリ(公式英語版)を参照してください。
また、C#と.NET基礎で紹介したように、カスタムメソッドを書くこともできます。

今学んだことと、このドキュメントの他の部分で提供されている例を考慮して、インジケーターのコードを編集してみましょう。

上記の例では、Calculate() メソッドは各バーの高値と安値の差を決定します。
バー自体には、Bars コレクションのインデックスを使用してアクセスします。

名前空間宣言のすぐ下にある以下のコードをコピー・ペーストして、同じインジケータを作成します。

1
2
3
4
5
6
7
8
9
10
11
[Indicator(IsOverlay = false, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
public class HighMinusLow : Indicator
{
  [Output(“Main”, LineColor = “Orange”)]
  public IndicatorDataSeries Result { get; set; }

  public override void Calculate(int index)
  {
    Result[index] = Bars.HighPrices[index] – Bars.LowPrices[index];
  }
}

インディケータを保存し、構築する

コード・エディター・ウィンドウの左上にある「保存」ボタンをクリックして、コードを保存できます。または、Ctrl+Sを押します。
また、コードエディター内の任意の場所で右クリックし、新しく開いたメニューから「保存」を選択することもできます。

cBotと同様に、インジケーターも適用前にビルドする必要があります。
インジケーターをビルドするには、コードエディターの上部またはcBotメニューの「ビルド」アイコンをクリックします。この操作のキーボードショートカットは Ctrl+B です。

ビルドが成功すると、「ビルド結果」 ビューアに新しいメッセージが表示されます。
ビルドに失敗した場合は、このウィンドウにビルド中に発生したすべてのエラーの概要が表示されます。「ビルド結果」ビューアでエラーの説明をクリックすると、そのエラーが発生したコードの正確な場所が表示されます。

前回のビルド以降にコードに変更があった場合は、「ビルド」アイコンの横に赤い ‘*’ 記号が表示されます。この場合、インジケーターを実行する前に再度ビルドしてください。

インジケータインスタンスの作成とカスタマイズ

上記のすべてのアクションを正常に完了した場合、インジケータを展開する準備が整っているはずです。使用を開始するには、以下のいずれかの操作を行って新しいインスタンスを作成します。

  • エクステンション名の右にある「+」アイコンをクリックします。
    表示されるメニューで、取引したいシンボルを選択します。
  • cTraderは、h1をタイムフレームとしてEURUSDシンボルを取引する新しいインスタンスを自動的に作成します。

インジケーターの真下に新しいインスタンスが表示されるはずです。

コードにカスタマイズ可能なパラメータを指定している場合、それらはトレードウォッチ表示の左側にある「パラメーター」タブに表示されます。
「線」パラメータは、視覚化された出力を持つすべてのインジケータに共通です。
また、インジケーターのラインの外観をカスタマイズすることも可能で、インジケーターのコードで以前に指定した設定を上書きします。

cBotとは異なり、ローカルに保存されたファイルから、またはローカルに保存されたファイルにインスタンス・パラメータをインポートまたはエクスポートすることはできません。

NaN演算

簡単に言うと、インジケータは特定のビジュアルを出力するために計算を実行します。
そのため、出力計算のためのフリンジ・ケースや境界条件をコードで正確に 処理することが不可欠です。

デトレンド価格オシレーターを出力するインジケーターから、次のコードを抜粋し てみましょう。

1
2
3
4
5
6
7
8
9
10
11
private MovingAverage movingAverage;

protected override void Initialize()
{
  movingAverage = Indicators.SimpleMovingAverage(Source, Periods);
}

public override void Calculate(int index)
{
  Result[index] = Source[index] – movingAverage.Result[index – Periods / 2 – 1];
}

上記のコードには、計算のための一般的なルールがいくつか含まれますが、特に境界条件が省略されています。

例えば、Periodsの値が10で、indexの値が0~9の範囲にある場合、計算結果はNaN(Not a Number)となります。このインジケータは、負のインデックスを持つ棒グラフに必要な値を計算することができません。この問題に対処するには、次の条件を追加します。

1
2
3
4
5
6
7
public override void Calculate(int index)
{
  if (index >= Periods + Periods / 2 + 1)
  {
    Result[index] = Source[index] - movingAverage.Result[index - Periods / 2 - 1];
  }
}

単純移動平均のコードも、index >= Periods をチェックしなければなりません。
さらに、ネストされたインジケータ(例えば、別のタイプの移動平均)を使用する場合、すべての新しい計算を考慮するため、異なる条件でなければなりません。

境界条件を指定してフリンジ・ケースを調べることもできますが、C# ではこの問題を完全に回避する使いやすい手段がサポートされています。

具体的には、doubleデータ型はNaN(Not a Number)演算を完全にサポートしています。以下の例を使って実証することができます。

1double.NaN + 1.4 == double.NaN

言い換えると、少なくとも 1 つの変数が NaN 型である計算を実行すると、これらの計算の結果は常に NaN になります。

幸いなことに、すべてのカスタム cTrader インジケータは DataSeries 型のデータを操作します。
負のインデックスを持つDataSeriesリストの要素の値を要求すると、常にNaNが返され、値自体は取引チャートに描画されません。

インジケータは例外をスローすることなく、通常通り動作し続けます。
つまり、ほとんどの場合は境界条件を無視して、一般的な計算ルールを実装するだけで問題ありません。

再帰的インジケータ

NaN演算は境界条件での作業を単純化できますが、NaN値を明示的に扱わなければならない状況もあります。そのようなケースの一つとして再帰インジケータがあります。

値を計算する際、再帰インジケータは前の期間に計算された値を基に計算します。
次の指数移動平均の計算例を見てください。

1
2
3
4
5
6
7
8
9
10
11
12
13
public override void Calculate(int index)
{
  var previousValue = Result[index - 1];

  if (double.IsNaN(previousValue))
  {
    Result[index] = Source[index];
  }
  else
  {
    Result[index] = Source[index] * _exp + previousValue * (1 - _exp);
  }
}

インジケータが最初の期間の値を計算する場合、それを明示的に非NaN型に設定する必要があります。
非NaN型に設定しないと、それ以降のすべての期間の計算がNaNとなり、インジケータは機能しなくなります。

上記のコードでは、double.IsNaN(previousValue) メソッドを使用することでこれを実現しています。NaN==x式はxがNaNであっても常にfalseを返すため、==演算子(previousValue==double.IsNan)は使えない点に注意が必要です。