インジケーターも作ってみよう
cBotに続いてインジケーターも一つ作ってみたいと思います。はじめてのcBotは終わってる前提で進めます。
エンベロープ
エンベロープ(Envelope)というインジケーターをご存じでしょうか。移動平均線とその上下一定距離に平行に線を引いただけの単純なインジケーターです。説明が下手で申し訳ない。見た目としてはバンド幅が一定なボリンジャーバンドみたいなこんなやつです。知らなければ検索してください。
比較的メジャーなインジケーターだと思うのですが、cTraderには標準搭載されてません。なので自分で作ってみましょう。(フリーでダウンロードはできるみたいですが、それはまぁ置いといて。)
パラメータはシンプルに2つだけ。「移動平均線の期間」と「移動平均線から上下ラインの距離」にしときましょう。距離は%(価格の何%か)で指定します。
早速作り始めよう
今回はサクサクいきますよ。
cBotのとき同様にAoutomate画面のIndicatorsタブでNewを押してください。ちゃんとIndicatorsタブが選ばれてますか。cTraderのタブはどっちが選ばれてるかわかりにくいのでご注意ください。
新しいインジケーター作ったら名前を変えます。今回はちゃんと「Envelopes」と名付けましょうか。そして右クリックからVisualStudioで開いてください。
自動でできたソースコード
using System;
using cAlgo.API;
using cAlgo.API.Internals;
using cAlgo.API.Indicators;
using cAlgo.Indicators;
namespace cAlgo
{
[Indicator(IsOverlay = false, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
public class Envelopes : Indicator
{
[Parameter(DefaultValue = 0.0)]
public double Parameter { get; set; }
[Output("Main")]
public IndicatorDataSeries Result { get; set; }
protected override void Initialize()
{
// Initialize and create nested indicators
}
public override void Calculate(int index)
{
// Calculate value at specified index
// Result[index] = ...
}
}
}
cBotのときと似てますね。
(2022/6/5 追記)
インジケーターの動作の仕方
実際に作り始める前にcTraderのインジケーターが動くとき上記コードのどこがどのように実行されるのか説明しておきます。
[Parameter(...)]はcBot同様、ユーザーが設定するパラメータを定義してます。
[Output(...)]はインジケーターとして表示する値の変数を定義してます。プログラム内で計算した値をこのResultに入れてあげればあとは勝手に画面上に表示してくれるということです。
最初にチャート上にインジケーターが設置されるとまずはInitialize()が呼び出されます。インジケーターの初期化処理ですね。
(ちなみにインジケーターは時間足が切り替わるたびに初期化されます。パラメータ以外の各変数の値も初期化されてしまうので注意してください。)
初期化が終わると次はCalculate(index)がローソク足の本数分だけ呼び出されます。引数のindexは0から順番に振られたローソク足の通し番号だと思ってください。
コードで説明するならこんな処理がされてる感じです。
for(int i=0; i<ローソク本数-1; i++){
Calculate(i);
}
ここまでの動作が終わったら、その後は毎Tick、Calculate()が呼ばれるようになります。
ポイントとしてはCalculate内では渡されたindex番号時点での値だけ計算すればいいという部分です。MT4とは異なりますので注意してください。
例えば高値と安値の平均を算出して、上記OutputのResultに入れる場合はこうなります。
Calculate(int index){
Result[index] = (Bars.HighPrices[index] + Bars.LowPrices[index])/2;
}
あくまで計算したいのは「その時点」での値なので[index]で値を参照、代入します。もちろん一つ前の値を使いたいなら[index-1]とすれば参照可能です。
この動作が理解できてればやることもわかりやすいと思います。では早速作っていきましょう。
パラメータ設定
パラメータはcBotのときと同じように準備します。
// 移動平均線の期間
[Parameter(DefaultValue = 25)]
public int Period { get; set; }
// 移動平均線と上下ラインの距離(価格%)
[Parameter(DefaultValue = 1)]
public double Distance { get; set; }
表示用データの準備
表示するデータの入れ物を設定します。
[Output("Main")]
public IndicatorDataSeries Result { get; set; }
この部分を変更します。
画面の表示するデータは[Output]属性をつけてIndicatorDataSeriesという型で用意する必要があります。"Main"は画面表示名、Resultの部分は変数名なので好きに変えてください。
// 移動平均部分
[Output("MA")]
public IndicatorDataSeries Ma { get; set; }
// 上の線
[Output("upper")]
public IndicatorDataSeries Upper { get; set; }
// 下の線
[Output("lower")]
public IndicatorDataSeries Lower { get; set; }
移動平均線と上下であわせて3本の線が必要ですのでデータの入れ物も3つ用意します。[Output]属性の付いたIndicatorDataSeriesは中身のオブジェクトも勝手に用意されるため、初期化は必要ありません。
必要なデータ準備と計算処理
次に移動平均線のメンバを用意しInitialize()で初期化します。cBotのときと同じですね。
//移動平均
private SimpleMovingAverage _ma;
protected override void Initialize()
{
_ma = Indicators.SimpleMovingAverage(Bars.ClosePrices, Period);
}
あとはCalculate()に計算処理を書くだけです。
public override void Calculate(int index)
{
double maVal = _ma.Result[index];
double distance = maVal * Distance / 100;
Ma[index] = maVal;
Upper[index] = maVal + distance;
Lower[index] = maVal - distance;
}
ここはindex番目の値を計算する処理を書きます。MQLのように自分でループを回す必要はありません。
引数としてindexを受け取るため、さっき用意した3つの入れ物のindex番目に計算した値を入れるだけです。
一応計算内容も説明しておきます。Maには移動平均線の値そのまんま、UpperとLowerには移動平均値からDistance%離れた値を入れてます。
MAから(パラメータの)Distance%離れたところに線を引きたいため、現在のMA値(myVal)を元にどのくらい上下に距離を取るか計算してdistance変数に入れてます。
で,上の線の値(Upper[index])には現在のMA値(myVal)+distanceをセット、下の線の値(Lower[index])にはmyVal-distanceをセットしているというだけです。
表示してみる
さて、ではこれで表示させてみます。cBot同様、cTraderのAutomate画面、+ボタンでインスタンスを作成して選択してください。Indicatorはいきなり表示されます。
意図したとおりに・・・なってないですよね。実はインジケーターはデフォルトで別窓に表示される設定になってます。これはテンプレートの10行目
[Indicator(IsOverlay = false, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
ここのIsOverlayで設定可能です。ではここをtrueに変更してビルドしなおして再度見てみましょう。
できました。
コード全体
using System;
using cAlgo.API;
using cAlgo.API.Internals;
using cAlgo.API.Indicators;
using cAlgo.Indicators;
namespace cAlgo
{
[Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
public class Envelopes : Indicator
{
// 移動平均線の期間
[Parameter(DefaultValue = 25)]
public int Period { get; set; }
// 移動平均線と上下ラインの距離(価格%)
[Parameter(DefaultValue = 1)]
public double Distance { get; set; }
// 移動平均部分
[Output("MA")]
public IndicatorDataSeries Ma { get; set; }
// 上の線
[Output("upper")]
public IndicatorDataSeries Upper { get; set; }
// 下の線
[Output("lower")]
public IndicatorDataSeries Lower { get; set; }
//移動平均
private SimpleMovingAverage _ma;
protected override void Initialize()
{
_ma = Indicators.SimpleMovingAverage(Bars.ClosePrices, Period);
}
public override void Calculate(int index)
{
double maVal = _ma.Result[index];
double distance = maVal * Distance / 100;
Ma[index] = maVal;
Upper[index] = maVal + distance;
Lower[index] = maVal - distance;
}
}
}
あとはそのまま使うも改良してみるも自由
自分で作ったときの最大のメリットは自由に中身を作り変えられることです。
単純移動平均線じゃなくてEMAを使ってみたりだとか、同時に2本も3本もエンベロープを表示させたりだとか、自由自在です。
自分で作ってみることの楽しさとメリットが伝わっていれば幸いです。