MQLの配列、RSIやボリンジャーバンドの記述方法

MT4, MT5でインジケーターやEA（自動売買プログラム）を作るために、独自の言語であるMQLというものがあるのですが2021年においてとても記述が面倒で忘れそうなのでメモ代わりに書いておきます。
基本的には、公式サイトやヘルプなどを参考にしています。

## 配列

わざわざSetIndexBufferを使って初期化する必要があります。

````
// 宣言部
double rsidata = [];
```

```
int OnInit()
{
 SetIndexBuffer(0, rsidata); // 初期化。複数の配列を使う場合は0のところをインクリメントする。
}
```

## インジケーター
初期化の段階でハンドルを取得し、都度ハンドルを使って値を取得する必要があります。

### RSI

```
// 宣言部
double iRSIBuffer[];
int rsihandle; // ハンドル - これを通して実際の値を取得する
```
```
int OnInit()
{
   SetIndexBuffer(6,iRSIBuffer,INDICATOR_DATA);
   rsihandle=iRSI(NULL,PERIOD_CURRENT, 14,PRICE_CLOSE); // 現在の通貨ペア・時間帯で、14期間、終値ベースのRSIを使うという宣言
   // 失敗時の処理
   if(rsihandle==INVALID_HANDLE) 
   { 
     //--- 失敗した事実とエラーコードを出力する 
    PrintFormat("Failed to create handle of the iRSI indicator for the symbol %s/%s, error code %d", 
                  "current", 
                 EnumToString(period), 
                 GetLastError()); 
    //--- 失敗したという結果を返す 
    return(INIT_FAILED); 
   }
}
```

```
void OnTick()
{
 // 値の数（頭から解析して、データの数が揃うまでは待機しないとエラーになる）
 int calculated=BarsCalculated(rsihandle); 
 if(calculated <= rsiLength)
 { 
   Print("barsCalculated <= 0: OnTick");
   return;
 }
 //--- 配列をiRSI 指標の値で記入 
 //--- FillArrayFromBuffer が false を返した場合、情報の準備が終わっていないので操作を終了する , values_to_copyはintの変数でいくつデータを取得するか？
 if(!FillArrayFromBuffer(iRSIBuffer,rsihandle,values_to_copy)) {
    Print("FillArrayBuffer failed.");
    return;
 }
}
```
実際の処理はこの関数で行います。（公式にあったところからコピペ）

```
//+------------------------------------------------------------------+ 
//| iRSI 指標から指標バッファを記入する                                       | 
//+------------------------------------------------------------------+ 
bool FillArrayFromBuffer(double &rsi_buffer[], // 相対力指数値の指標バッファ 
                        int ind_handle,       // iRSI 指標ハンドル 
                        int amount             // 複製された値の数 
                        )
{ 
   //--- エラーコードをリセットする 
   ResetLastError(); 
   //--- インデックス0 を持つ指標バッファの値で iRSIBuffer 配列の一部を記入する 
  if(CopyBuffer(ind_handle,0,0,amount,rsi_buffer)<0) 
  { 
    //--- 複製が失敗したら、エラーコードを出す 
    PrintFormat("Failed to copy data from the iRSI indicator, error code %d",GetLastError()); 
    //--- ゼロ結果で終了。 指標は計算されていないと見なされる 
    return(false); 
  } 
//  Print("success", rsi_buffer[0]);
  //--- 全てが成功 
  return(true); 
}
```

### ボリンジャーバンド
これも同じように各自処理が必要です。
ここでは2シグマ3シグマ両方を使いたいので定義が長いです。

```
// ハンドル、センター、＋シグマ、-シグマの配列
int bb1handle;
double Mid1Buffer[];
double Up1Buffer[];
double Down1Buffer[];

int bb2handle;
double Mid2Buffer[];
double Up2Buffer[];
double Down2Buffer[];
```

```
int OnInit()
{
 SetIndexBuffer(0,Mid1Buffer);
 SetIndexBuffer(1,Up1Buffer);
 SetIndexBuffer(2,Down1Buffer);
 SetIndexBuffer(3,Mid2Buffer);
 SetIndexBuffer(4,Up2Buffer);
 SetIndexBuffer(5,Down2Buffer);

 bb1handle = iBands(NULL,PERIOD_CURRENT,bbPeriod,0, 1,PRICE_CLOSE);
 bb2handle = iBands(NULL,PERIOD_CURRENT,bbPeriod,0, 2,PRICE_CLOSE);
 // 実際はここもエラー処理が必要かもです。
}
```

```
void OnTick()
{
// この処理より前に、RSIでも書いたBarsCalculatedのチェックを入れてください。
 if(!FillArraysFromBuffers(Mid1Buffer,Up1Buffer,Down1Buffer,bands_shift,bb1handle,values_to_copy)) return;
 if(!FillArraysFromBuffers(Mid2Buffer,Up2Buffer,Down2Buffer,bands_shift,bb2handle,values_to_copy)) return;
}
```
こちらも実際に取得るするための関数。

```
//+------------------------------------------------------------------+
//| iBands 指標から指標バッファを記入する                                     |
//+------------------------------------------------------------------+
bool FillArraysFromBuffers(double &base_values[],     // ボリンジャーバンドの中線の指標バッファ
                          double &upper_values[],   // 上縁の指標バッファ
                          double &lower_values[],   // 下縁の指標バッファ
                          int shift,                 // シフト
                          int ind_handle,           // iBands 指標ハンドル
                          int amount                 // 複製された値の数
                          )
 {
//--- エラーコードをリセットする
  ResetLastError();
//--- インデックス0 を持つ指標バッファの値で MiddleBuffer 配列の一部を記入する
  if(CopyBuffer(ind_handle,0,-shift,amount,base_values)<0)
    {
    //--- 複製が失敗したら、エラーコードを出す
    PrintFormat("Failed to copy data from the iBands indicator, error code %d",GetLastError());
    //--- ゼロ結果で終了。 指標は計算されていないと見なされる
    return(false);
    }
 
//--- インデックス 1 を持つ指標バッファの値で UpperBuffer 配列の一部を記入する
  if(CopyBuffer(ind_handle,1,-shift,amount,upper_values)<0)
    {
    //--- 複製が失敗したら、エラーコードを出す
    PrintFormat("Failed to copy data from the iBands indicator, error code %d",GetLastError());
    //--- ゼロ結果で終了。 指標は計算されていないと見なされる
    return(false);
    }
 
//--- インデックス 2 を持つ指標バッファの値で LowerBuffer 配列の一部を記入する
  if(CopyBuffer(ind_handle,2,-shift,amount,lower_values)<0)
    {
    //--- 複製が失敗したら、エラーコードを出す
    PrintFormat("Failed to copy data from the iBands indicator, error code %d",GetLastError());
    //--- ゼロ結果で終了。 指標は計算されていないと見なされる
    return(false);
    }
//--- 全てが成功
  return(true);
 }
```

これらを使うと配列にそれぞれのデータが格納されるようになります。 0番目が最新のデータになっています。