MQL5 配列関数 完全ガイド|ArrayResize・ArraySort・ArrayCopy・CopyBuffer実践解説

MQL5の配列関数を完全網羅。ArrayResize・ArraySort・ArrayCopy・CopyBufferなど、EA開発で必須の配列操作をコード付きで解説します。動的配列の管理、インジケーターバッファの取得、データのソート・検索まで、実践的なパターンを豊富に紹介。MQL4との違いも併記しています。

目次

MQL5配列の基礎知識

MQL5の配列は、EA開発において最も頻繁に使用するデータ構造です。インジケーター値の格納、価格データの管理、取引履歴の保存など、あらゆる場面で配列操作の知識が必要になります。

静的配列と動的配列

// 静的配列(サイズ固定・コンパイル時に決定)
double fixedArray[100];    // 100要素の固定配列
int    matrix[10][5];      // 2次元配列(10行5列)

// 動的配列(サイズ可変・実行時に変更可能)
double dynamicArray[];     // サイズ未定
ArrayResize(dynamicArray, 50);  // 50要素に拡張

// CopyBufferに渡す配列は必ず動的配列
double buffer[];           // 動的配列で宣言
ArraySetAsSeries(buffer, true);
CopyBuffer(handle, 0, 0, 100, buffer);  // OK

// 静的配列もCopyBufferに渡せる(自動リサイズはされない)
double fixedBuf[100];
CopyBuffer(handle, 0, 0, 100, fixedBuf);  // OK(100要素以内ならコピーされる)
重要

CopyBuffer()は動的配列・静的配列どちらでも使えます。動的配列は自動リサイズされるため推奨です。静的配列を使う場合は、要素数が十分か確認してください。不足するとERR_SMALL_ARRAY(4007)エラーが発生します。

MQL4とMQL5の配列の違い

項目MQL4MQL5
配列宣言同じ構文同じ構文
ArrayResize利用可能第3引数でreserve指定可
ArraySort多次元ソート対応、sort_dir指定多次元対応(第1次元でソート)、昇順固定
ArrayCopyRates利用可能(MqlRates配列へ)廃止(CopyRatesを使用)
ArraySetAsSeries同じ同じ(CopyBuffer前に必須)
ArrayCompare対応利用可能
ArrayFill対応利用可能
ArrayPrintなし利用可能(デバッグに便利)

ArrayResize — 動的配列のサイズ変更

動的配列の要素数を変更します。EA開発で最も頻繁に使う配列関数の一つです。

int ArrayResize(
   void&  array[],          // 対象の動的配列
   int    new_size,         // 新しいサイズ
   int    reserve_size = 0  // メモリ予約サイズ(MQL5のみ)
);
// 戻り値: 新しいサイズ(失敗時 -1)

第3引数のreserve_sizeは、頻繁にリサイズする場合にメモリ再割り当てを減らすための予約サイズです。例えばArrayResize(arr, 100, 1000)とすると、1000要素分のメモリを確保しつつ、論理サイズは100になります。ループ内で1要素ずつ追加する場合に特に有効です。

// パターン1: ティックデータの動的収集
double tickPrices[];
int tickCount = 0;

void OnTick()
  {
   double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);

   tickCount++;
   ArrayResize(tickPrices, tickCount, 1000);  // 1000単位で予約
   tickPrices[tickCount - 1] = bid;

   // 最新1000ティックだけ保持
   if(tickCount > 1000)
     {
      // 古いデータを削除して前に詰める
      ArrayRemove(tickPrices, 0, tickCount - 1000);
      tickCount = 1000;
     }
  }

// パターン2: 条件を満たすバーのインデックスを収集
int FindBullishBars(int count)
  {
   int bullBars[];
   int found = 0;

   MqlRates rates[];
   ArraySetAsSeries(rates, true);
   if(CopyRates(_Symbol, PERIOD_CURRENT, 0, count, rates) < count)
      return 0;

   for(int i = 1; i < count; i++)  // [0]は未確定
     {
      if(rates[i].close > rates[i].open)  // 陽線
        {
         found++;
         ArrayResize(bullBars, found, 100);
         bullBars[found - 1] = i;
        }
     }

   Print("直近", count, "本中、陽線: ", found, "本");
   return found;
  }

ArrayFree — 動的配列のメモリ解放

動的配列のメモリを完全に解放し、サイズを0にします。大量のデータを扱った後のクリーンアップに使用します。

void ArrayFree(
   void&  array[]  // 解放する動的配列
);

// 使用例:大量データ処理後のメモリ解放
void ProcessHistoricalData()
  {
   MqlRates rates[];
   ArraySetAsSeries(rates, true);

   // 10万本のバーデータを取得
   int copied = CopyRates(_Symbol, PERIOD_M1, 0, 100000, rates);
   if(copied <= 0) return;

   // ... データ処理 ...

   // 処理完了後、メモリを解放
   ArrayFree(rates);
   Print("配列サイズ: ", ArraySize(rates));  // 0
  }

ArrayFree()は動的配列にのみ有効です。静的配列に対して呼び出しても何も起こりません。OnDeinit()内で大きな配列を解放するのは良い習慣です。

ArraySort — 配列のソート

配列を昇順にソートします。MQL5では1次元配列のみ対応で、常に昇順です。

// MQL5
bool ArraySort(
   void&  array[]  // ソートする配列(多次元も可、第1次元でソート)
);
// 戻り値: 成功でtrue

// MQL4(より柔軟)
int ArraySort(
   void&  array[],
   int    count = WHOLE_ARRAY,
   int    start = 0,
   int    sort_dir = MODE_ASCEND  // MODE_ASCEND or MODE_DESCEND
);
項目MQL4MQL5
ソート方向昇順/降順を指定可昇順のみ
対応次元多次元(最初の次元でソート)多次元対応(第1次元でソート)
部分ソートstart, countで範囲指定可配列全体のみ
// 例1: 直近N本の終値を取得してソートし中央値を計算
double GetMedianPrice(int period)
  {
   double closes[];
   ArraySetAsSeries(closes, false);  // ソート前にfalseに戻す
   ArrayResize(closes, period);

   // 終値をコピー
   double closeBuffer[];
   ArraySetAsSeries(closeBuffer, true);
   if(CopyClose(_Symbol, PERIOD_CURRENT, 1, period, closeBuffer) < period)
      return 0;

   ArrayCopy(closes, closeBuffer);
   ArraySort(closes);  // 昇順ソート

   // 中央値
   if(period % 2 == 0)
      return (closes[period/2 - 1] + closes[period/2]) / 2.0;
   else
      return closes[period/2];
  }

// 例2: 降順ソートの実現(MQL5)
void SortDescending(double &arr[])
  {
   ArraySort(arr);  // まず昇順ソート
   // 逆順にコピー
   int size = ArraySize(arr);
   double temp[];
   ArrayResize(temp, size);
   for(int i = 0; i < size; i++)
      temp[i] = arr[size - 1 - i];
   ArrayCopy(arr, temp);
  }

// 例3: 利益額のソートでベスト/ワースト取引を特定
void AnalyzeTrades()
  {
   double profits[];
   HistorySelect(0, TimeCurrent());
   int total = HistoryDealsTotal();
   int count = 0;
   for(int i = 0; i < total; i++)
     {
      ulong ticket = HistoryDealGetTicket(i);
      if(HistoryDealGetInteger(ticket, DEAL_ENTRY) == DEAL_ENTRY_OUT)
        {
         count++;
         ArrayResize(profits, count, 100);
         profits[count-1] = HistoryDealGetDouble(ticket, DEAL_PROFIT);
        }
     }

   if(count > 0)
     {
      ArraySort(profits);
      Print("最大損失: ", profits[0]);
      Print("最大利益: ", profits[count-1]);
      Print("中央値: ", profits[count/2]);
     }
  }

ArrayCopy — 配列のコピー

配列間でデータをコピーします。部分コピーにも対応しており、データの移動・結合に不可欠な関数です。

int ArrayCopy(
   void&  dst_array[],          // コピー先
   const void&  src_array[],    // コピー元
   int    dst_start = 0,        // コピー先開始位置
   int    src_start = 0,        // コピー元開始位置
   int    count = WHOLE_ARRAY   // コピー要素数
);
// 戻り値: コピーされた要素数
// 例1: 移動平均の直近N本をバックアップ
double maBackup[];

void BackupMAValues(int handle, int count)
  {
   double buffer[];
   ArraySetAsSeries(buffer, true);
   if(CopyBuffer(handle, 0, 0, count, buffer) < count) return;

   ArrayResize(maBackup, count);
   ArrayCopy(maBackup, buffer, 0, 0, count);
  }

// 例2: 2つの配列を結合
void MergeArrays(double &result[], const double &arr1[], const double &arr2[])
  {
   int size1 = ArraySize(arr1);
   int size2 = ArraySize(arr2);
   ArrayResize(result, size1 + size2);

   ArrayCopy(result, arr1, 0, 0, size1);         // 前半にarr1
   ArrayCopy(result, arr2, size1, 0, size2);      // 後半にarr2
  }

// 例3: リングバッファ(古いデータを捨てて新しいデータを追加)
double ringBuffer[];
int    ringSize = 100;

int OnInit()
  {
   ArrayResize(ringBuffer, ringSize);
   ArrayInitialize(ringBuffer, 0);
   return INIT_SUCCEEDED;
  }

void AddToRing(double value)
  {
   // 先頭を1つ前にずらし、末尾に新しい値を追加
   ArrayCopy(ringBuffer, ringBuffer, 0, 1, ringSize - 1);
   ringBuffer[ringSize - 1] = value;
  }

ArrayMaximum / ArrayMinimum — 最大・最小値の検索

配列内で最大値・最小値を持つ要素のインデックスを返します。高値・安値の検索やインジケーター値の極値検出に使用します。

int ArrayMaximum(
   const void&  array[],          // 検索対象の配列
   int          start = 0,        // 検索開始位置
   int          count = WHOLE_ARRAY  // 検索要素数
);

int ArrayMinimum(
   const void&  array[],
   int          start = 0,
   int          count = WHOLE_ARRAY
);
// 戻り値: 最大/最小値のインデックス(失敗時 -1)
// 直近N本の最高値・最安値を取得(ブレイクアウト判定に使用)
input int BreakoutPeriod = 20;

void CheckBreakout()
  {
   double high[], low[];
   ArraySetAsSeries(high, true);
   ArraySetAsSeries(low, true);

   if(CopyHigh(_Symbol, PERIOD_CURRENT, 1, BreakoutPeriod, high) < BreakoutPeriod) return;
   if(CopyLow(_Symbol, PERIOD_CURRENT, 1, BreakoutPeriod, low) < BreakoutPeriod) return;

   int highIdx = ArrayMaximum(high, 0, BreakoutPeriod);
   int lowIdx  = ArrayMinimum(low, 0, BreakoutPeriod);

   double highestPrice = high[highIdx];
   double lowestPrice  = low[lowIdx];
   double currentBid   = SymbolInfoDouble(_Symbol, SYMBOL_BID);
   double currentAsk   = SymbolInfoDouble(_Symbol, SYMBOL_ASK);

   if(currentAsk > highestPrice)
      Print("上方ブレイクアウト! 最高値=", highestPrice, " 現在Ask=", currentAsk);

   if(currentBid < lowestPrice)
      Print("下方ブレイクアウト! 最安値=", lowestPrice, " 現在Bid=", currentBid);
  }

// ATRの最大値を使ったボラティリティフィルター
void CheckVolatility(int atrHandle)
  {
   double atr[];
   ArraySetAsSeries(atr, true);
   if(CopyBuffer(atrHandle, 0, 0, 50, atr) < 50) return;

   int maxIdx = ArrayMaximum(atr, 0, 50);
   int minIdx = ArrayMinimum(atr, 0, 50);

   Print("ATR最大: ", atr[maxIdx], " (", maxIdx, "本前)");
   Print("ATR最小: ", atr[minIdx], " (", minIdx, "本前)");
   Print("ATR比率: ", atr[0] / atr[minIdx]);  // 現在のATR / 最小ATR
  }

ArrayInitialize — 配列の一括初期化

配列のすべての要素を指定した値で初期化します。

void ArrayInitialize(
   void&   array[],  // 初期化する配列
   double  value     // 初期値
);

// 使用例
double prices[];
ArrayResize(prices, 100);
ArrayInitialize(prices, 0.0);  // 全要素を0.0に

// フラグ配列の初期化
int flags[];
ArrayResize(flags, 50);
ArrayInitialize(flags, -1);    // 全要素を-1に(未使用マーク)

// インジケーターバッファの初期化(OnInit内で使用)
double ExtBuffer[];
ArrayInitialize(ExtBuffer, EMPTY_VALUE);  // 空値で初期化

ArrayFill — 配列の部分初期化

配列の指定範囲を特定の値で埋めます。ArrayInitializeが全体初期化なのに対し、ArrayFillは範囲を指定できます。

void ArrayFill(
   void&  array[],   // 対象の配列
   int    start,     // 開始インデックス
   int    count,     // 埋める要素数
   void   value      // 埋める値
);

// 使用例: 配列の後半だけリセット
double data[];
ArrayResize(data, 100);
ArrayFill(data, 50, 50, 0.0);  // インデックス50〜99を0.0に

// 使用例: セクション別に異なる値で初期化
int zones[];
ArrayResize(zones, 30);
ArrayFill(zones, 0, 10, 1);    // 0-9: ゾーン1
ArrayFill(zones, 10, 10, 2);   // 10-19: ゾーン2
ArrayFill(zones, 20, 10, 3);   // 20-29: ゾーン3

ArraySetAsSeries — 時系列インデックスの設定

配列のインデックス方向を変更します。trueに設定すると、[0]が最新のバーを指すようになります。EA開発では必須の設定です。

bool ArraySetAsSeries(
   void&  array[],     // 対象の配列
   bool   flag         // true=最新が[0]、false=最古が[0]
);

// デフォルト(flag=false): [0]=最古, [1]=次, ... [N-1]=最新
// AsSeries(flag=true):    [0]=最新, [1]=1本前, ... [N-1]=最古

// 典型的な使用パターン
void OnTick()
  {
   double ma[];
   ArraySetAsSeries(ma, true);  // CopyBufferの前に設定

   if(CopyBuffer(maHandle, 0, 0, 10, ma) < 10) return;

   // ma[0] = 現在のバー(形成中)
   // ma[1] = 1本前(確定済み)← エントリー判定に使う
   // ma[2] = 2本前(確定済み)← クロス判定に使う
  }
重要

ArraySetAsSeries()CopyBuffer()を呼ぶ前に設定してください。CopyBuffer後に設定しても動作しますが、コードの可読性のために事前設定が推奨されます。また、ArraySort()を使用する場合は事前にArraySetAsSeries(arr, false)に戻す必要があります。

ArraySize / ArrayRange — 配列サイズの取得

配列の要素数や特定の次元のサイズを取得します。

int ArraySize(
   const void&  array[]  // 対象の配列
);
// 戻り値: 全要素数(多次元の場合は全次元の積)

int ArrayRange(
   const void&  array[],  // 対象の配列
   int          rank_index // 取得する次元(0=第1次元、1=第2次元...)
);
// 戻り値: 指定次元のサイズ

// 使用例
double arr1[];
ArrayResize(arr1, 50);
Print(ArraySize(arr1));    // 50

double arr2[][3];
ArrayResize(arr2, 10);     // 第1次元を10に
Print(ArraySize(arr2));    // 30(10 × 3)
Print(ArrayRange(arr2, 0)); // 10(第1次元)
Print(ArrayRange(arr2, 1)); // 3(第2次元)

ArrayIsSeries / ArrayIsDynamic — 配列の属性確認

bool ArrayIsSeries(
   const void&  array[]  // チェックする配列
);
// 戻り値: 時系列フラグがtrueならtrue

bool ArrayIsDynamic(
   const void&  array[]
);
// 戻り値: 動的配列ならtrue

// 使用例: 関数に渡された配列の属性チェック
void SafeProcess(double &arr[])
  {
   if(!ArrayIsDynamic(arr))
     {
      Print("警告: 静的配列です。リサイズできません。");
      return;
     }

   bool wasSeries = ArrayIsSeries(arr);
   ArraySetAsSeries(arr, false);  // 処理中は通常インデックス

   // ... 処理 ...

   ArraySetAsSeries(arr, wasSeries);  // 元に戻す
  }

ArrayCompare — 配列の比較

2つの配列の内容を比較します。要素ごとに比較を行い、最初に異なる要素が見つかった時点で結果を返します。

int ArrayCompare(
   const void&  array1[],          // 配列1
   const void&  array2[],          // 配列2
   int          start1 = 0,        // 配列1の開始位置
   int          start2 = 0,        // 配列2の開始位置
   int          count = WHOLE_ARRAY // 比較要素数
);
// 戻り値: 0=等しい、-1=array1が小さい、1=array1が大きい、-2=エラー

// 使用例: インジケーター値が変化したか検出
double prevMA[], currMA[];

void OnTick()
  {
   double ma[];
   ArraySetAsSeries(ma, true);
   if(CopyBuffer(maHandle, 0, 0, 5, ma) < 5) return;

   if(ArraySize(prevMA) > 0)
     {
      if(ArrayCompare(prevMA, ma) != 0)
         Print("MA値に変化がありました");
     }

   ArrayResize(currMA, 5);
   ArrayCopy(currMA, ma);
   ArrayResize(prevMA, 5);
   ArrayCopy(prevMA, currMA);
  }

ArrayBsearch — バイナリサーチ(二分探索)

ソート済み配列に対してバイナリサーチを行います。完全一致しない場合は最も近い要素のインデックスを返します。

int ArrayBsearch(
   const double&  array[],  // ソート済み配列
   double         value     // 検索する値
);
// 戻り値: 見つかった(または最も近い)要素のインデックス

// 使用例: 価格レベルの最近接サポート/レジスタンスを検索
double supportLevels[];

void FindNearestSupport(double currentPrice)
  {
   // サポートレベルがソート済みであることが前提
   ArraySort(supportLevels);

   int idx = ArrayBsearch(supportLevels, currentPrice);

   Print("最も近いサポートレベル: ", supportLevels[idx]);

   // 現在価格より下で最も近いレベル
   if(supportLevels[idx] >= currentPrice && idx > 0)
      idx--;

   Print("直下のサポート: ", supportLevels[idx]);
  }

ArrayBsearch()ソート済み配列にのみ使用してください。ソートされていない配列に対して使用すると、正しい結果が得られません。事前にArraySort()を呼び出すか、データが昇順であることを確認してください。

ArrayPrint — 配列のデバッグ出力

配列の内容をエキスパートログに整形出力します。デバッグに非常に便利な関数です。

void ArrayPrint(
   const void&  array[],           // 出力する配列
   int          digits = _Digits,  // 小数点以下桁数
   const string separator = " ",   // 区切り文字
   ulong        start = 0,         // 開始位置
   ulong        count = WHOLE_ARRAY, // 出力数
   ulong        flags = ARRAYPRINT_HEADER | ARRAYPRINT_INDEX | ARRAYPRINT_LIMIT | ARRAYPRINT_ALIGN
);

// 基本使用例
double values[] = {1.23456, 2.34567, 3.45678};
ArrayPrint(values, 5);
// 出力: [0] 1.23456 [1] 2.34567 [2] 3.45678

// MqlRates構造体配列の出力(デバッグに最適)
MqlRates rates[];
ArraySetAsSeries(rates, true);
CopyRates(_Symbol, PERIOD_H1, 0, 5, rates);
ArrayPrint(rates);
// 時刻、OHLCV、スプレッドなどが表形式で出力される

// MqlTick配列の出力
MqlTick ticks[];
CopyTicks(_Symbol, ticks, COPY_TICKS_ALL, 0, 10);
ArrayPrint(ticks);  // bid, ask, last, volumeなどが整形出力

ArrayPrint()はMQL5のみの機能です。MQL4ではforループとPrint()で代用する必要があります。構造体配列もそのまま出力できるため、デバッグ時の強力なツールになります。

CopyBuffer — インジケーターバッファのコピー

インジケーターハンドルからバッファデータを配列にコピーします。MQL5のインジケーター関数は直接値を返さないため、この関数は必須です。

// オーバーロード1: バー番号指定(最も一般的)
int CopyBuffer(
   int       indicator_handle,  // インジケーターハンドル
   int       buffer_num,        // バッファ番号(0から)
   int       start_pos,         // 開始バー(0=最新)
   int       count,             // コピーするバー数
   double    buffer[]           // 受け取り配列(動的配列)
);

// オーバーロード2: 日時指定
int CopyBuffer(
   int       indicator_handle,
   int       buffer_num,
   datetime  start_time,        // 開始日時
   int       count,
   double    buffer[]
);

// オーバーロード3: 日時範囲指定
int CopyBuffer(
   int       indicator_handle,
   int       buffer_num,
   datetime  start_time,        // 開始日時
   datetime  stop_time,         // 終了日時
   double    buffer[]
);
// 戻り値: コピーされた要素数(失敗時 -1)
インジケーターbuffer_num = 0buffer_num = 1buffer_num = 2
iMAMA値--
iRSIRSI値--
iBandsBASE(中央線)UPPER(上限)LOWER(下限)
iMACDMAIN(MACD線)SIGNAL(シグナル線)-
iStochasticMAIN(%K)SIGNAL(%D)-
iADXMAIN(ADX)PLUSDI(+DI)MINUSDI(-DI)
iAlligatorGATORJAW(顎)GATORTEETH(歯)GATORLIPS(唇)
// パターン1: 複数バッファの取得(ボリンジャーバンド)
int bbHandle;

int OnInit()
  {
   bbHandle = iBands(_Symbol, PERIOD_CURRENT, 20, 0, 2.0, PRICE_CLOSE);
   if(bbHandle == INVALID_HANDLE) return INIT_FAILED;
   return INIT_SUCCEEDED;
  }

void OnTick()
  {
   double upper[], middle[], lower[];
   ArraySetAsSeries(upper, true);
   ArraySetAsSeries(middle, true);
   ArraySetAsSeries(lower, true);

   // 各バッファを個別にコピー
   if(CopyBuffer(bbHandle, 0, 0, 3, middle) < 3) return;  // BASE
   if(CopyBuffer(bbHandle, 1, 0, 3, upper) < 3) return;   // UPPER
   if(CopyBuffer(bbHandle, 2, 0, 3, lower) < 3) return;   // LOWER

   double bandwidth = upper[1] - lower[1];
   Print("BB幅: ", bandwidth, " pips=", bandwidth / _Point);
  }

// パターン2: CopyBuffer失敗時のリトライ
bool SafeCopyBuffer(int handle, int bufNum, int count, double &buffer[])
  {
   ArraySetAsSeries(buffer, true);
   for(int attempt = 0; attempt < 3; attempt++)
     {
      int copied = CopyBuffer(handle, bufNum, 0, count, buffer);
      if(copied >= count) return true;
      Sleep(100);  // 少し待ってリトライ
     }
   Print("CopyBuffer失敗: handle=", handle, " buffer=", bufNum);
   return false;
  }

// パターン3: 日時範囲でコピー(バックテスト分析)
void AnalyzePeriod(int handle, datetime from, datetime to)
  {
   double values[];
   ArraySetAsSeries(values, false);

   int copied = CopyBuffer(handle, 0, from, to, values);
   if(copied <= 0)
     {
      Print("期間データなし");
      return;
     }

   // 統計計算
   double sum = 0;
   for(int i = 0; i < copied; i++)
      sum += values[i];

   Print("期間平均: ", sum / copied, " (", copied, "本)");
  }

ArrayRemove / ArrayInsert — 要素の削除と挿入

MQL5では配列の要素を削除・挿入する関数が用意されています。動的なデータ管理に便利です。

bool ArrayRemove(
   void&  array[],   // 対象配列
   int    start,     // 削除開始位置
   int    count      // 削除する要素数
);

bool ArrayInsert(
   void&  dst_array[],   // 挿入先配列
   const void& src_array[], // 挿入する配列
   int    dst_start,      // 挿入位置
   int    src_start = 0,  // ソース開始位置
   int    count = WHOLE_ARRAY  // 挿入要素数
);

// 使用例: FIFOキュー(先入れ先出し)
double priceQueue[];
int maxQueueSize = 100;

void EnqueuePrice(double price)
  {
   int size = ArraySize(priceQueue);
   if(size >= maxQueueSize)
      ArrayRemove(priceQueue, 0, 1);  // 最古のデータを削除

   size = ArraySize(priceQueue);
   ArrayResize(priceQueue, size + 1);
   priceQueue[size] = price;
  }

// 使用例: ソート済み配列に挿入(挿入ソート)
void InsertSorted(double &arr[], double value)
  {
   double temp[1];
   temp[0] = value;

   int size = ArraySize(arr);
   int pos = 0;
   for(int i = 0; i < size; i++)
     {
      if(arr[i] > value) break;
      pos = i + 1;
     }

   ArrayInsert(arr, temp, pos, 0, 1);
  }

ArrayReverse / ArraySwap — 配列の反転と交換

bool ArrayReverse(
   void&  array[],           // 対象配列
   int    start = 0,         // 開始位置
   int    count = WHOLE_ARRAY // 反転する要素数
);

bool ArraySwap(
   void&  array1[],  // 配列1
   void&  array2[]   // 配列2
);
// 2つの配列の内容を交換(サイズも含めて完全交換)

// ArrayReverseの使用例: 降順ソート
double prices[];
// ... prices にデータを格納 ...
ArraySort(prices);          // 昇順ソート
ArrayReverse(prices);       // 反転して降順に

// ArraySwapの使用例: ダブルバッファリング
double bufferA[], bufferB[];

void OnTick()
  {
   // 前回のデータをBに退避、新しいデータをAに
   ArraySwap(bufferA, bufferB);   // 瞬時に交換
   ArraySetAsSeries(bufferA, true);
   CopyBuffer(maHandle, 0, 0, 100, bufferA);

   // bufferB = 前回のデータ、bufferA = 最新のデータ
  }

実践パターン:EA開発での配列活用

パターン1:複数インジケーターの一括管理クラス

class CIndicatorManager
  {
private:
   int               m_handles[];      // ハンドル配列
   string            m_names[];        // 名前配列
   int               m_count;

public:
                     CIndicatorManager() : m_count(0) {}
                    ~CIndicatorManager() { ReleaseAll(); }

   // インジケーターを登録
   bool              Add(int handle, string name)
     {
      if(handle == INVALID_HANDLE) return false;
      m_count++;
      ArrayResize(m_handles, m_count);
      ArrayResize(m_names, m_count);
      m_handles[m_count-1] = handle;
      m_names[m_count-1] = name;
      return true;
     }

   // バッファ取得(名前で検索)
   bool              GetBuffer(string name, int bufNum, int count, double &buffer[])
     {
      for(int i = 0; i < m_count; i++)
        {
         if(m_names[i] == name)
           {
            ArraySetAsSeries(buffer, true);
            return CopyBuffer(m_handles[i], bufNum, 0, count, buffer) >= count;
           }
        }
      Print("インジケーター未登録: ", name);
      return false;
     }

   // 全ハンドル解放
   void              ReleaseAll()
     {
      for(int i = 0; i < m_count; i++)
         IndicatorRelease(m_handles[i]);
      ArrayFree(m_handles);
      ArrayFree(m_names);
      m_count = 0;
     }
  };

// 使用例
CIndicatorManager indMgr;

int OnInit()
  {
   indMgr.Add(iMA(_Symbol, PERIOD_CURRENT, 20, 0, MODE_EMA, PRICE_CLOSE), "EMA20");
   indMgr.Add(iMA(_Symbol, PERIOD_CURRENT, 50, 0, MODE_EMA, PRICE_CLOSE), "EMA50");
   indMgr.Add(iRSI(_Symbol, PERIOD_CURRENT, 14, PRICE_CLOSE), "RSI14");
   return INIT_SUCCEEDED;
  }

void OnTick()
  {
   double ema20[], ema50[], rsi[];
   if(!indMgr.GetBuffer("EMA20", 0, 3, ema20)) return;
   if(!indMgr.GetBuffer("EMA50", 0, 3, ema50)) return;
   if(!indMgr.GetBuffer("RSI14", 0, 3, rsi)) return;

   // ロジック...
  }

パターン2:価格データの統計分析

// 標準偏差の計算
double CalcStdDev(double &arr[], int count)
  {
   if(count <= 1) return 0;
   double sum = 0, sumSq = 0;
   for(int i = 0; i < count; i++)
     {
      sum   += arr[i];
      sumSq += arr[i] * arr[i];
     }
   double mean = sum / count;
   return MathSqrt(sumSq / count - mean * mean);
  }

// Zスコアの計算(配列版)
void CalcZScores(const double &values[], double &zscores[], int count)
  {
   ArrayResize(zscores, count);

   double sum = 0;
   for(int i = 0; i < count; i++) sum += values[i];
   double mean = sum / count;

   double sumSq = 0;
   for(int i = 0; i < count; i++) sumSq += MathPow(values[i] - mean, 2);
   double stddev = MathSqrt(sumSq / count);

   if(stddev == 0) { ArrayInitialize(zscores, 0); return; }

   for(int i = 0; i < count; i++)
      zscores[i] = (values[i] - mean) / stddev;
  }

// パーセンタイルの計算
double CalcPercentile(double &arr[], double percentile)
  {
   int size = ArraySize(arr);
   if(size == 0) return 0;

   double sorted[];
   ArrayCopy(sorted, arr);
   ArraySort(sorted);

   double rank = percentile / 100.0 * (size - 1);
   int lower = (int)MathFloor(rank);
   int upper = (int)MathCeil(rank);
   double weight = rank - lower;

   return sorted[lower] * (1 - weight) + sorted[upper] * weight;
  }

パターン3:取引シグナル配列によるマルチシグナル管理

// シグナル構造体
struct TradeSignal
  {
   string            source;      // シグナル源("MA", "RSI"等)
   int               direction;   // 1=Buy, -1=Sell, 0=None
   double            strength;    // シグナル強度(0.0〜1.0)
   datetime          time;        // 発生時刻
  };

TradeSignal signals[];
int signalCount = 0;

// シグナルを追加
void AddSignal(string source, int direction, double strength)
  {
   signalCount++;
   ArrayResize(signals, signalCount, 10);
   signals[signalCount-1].source    = source;
   signals[signalCount-1].direction = direction;
   signals[signalCount-1].strength  = strength;
   signals[signalCount-1].time      = TimeCurrent();
  }

// シグナルの合計スコアを計算
double GetTotalScore()
  {
   double score = 0;
   for(int i = 0; i < signalCount; i++)
      score += signals[i].direction * signals[i].strength;
   return score;
  }

// フレーム:各インジケーターのシグナルを収集して統合判定
void OnTick()
  {
   signalCount = 0;
   ArrayFree(signals);

   // MAクロスシグナル
   double fast[], slow[];
   // ... CopyBuffer ...
   if(fast[1] > slow[1] && fast[2] <= slow[2])
      AddSignal("MACross", 1, 0.8);
   else if(fast[1] < slow[1] && fast[2] >= slow[2])
      AddSignal("MACross", -1, 0.8);

   // RSIシグナル
   double rsi[];
   // ... CopyBuffer ...
   if(rsi[1] < 30)
      AddSignal("RSI", 1, 0.6);
   else if(rsi[1] > 70)
      AddSignal("RSI", -1, 0.6);

   // 統合判定
   double totalScore = GetTotalScore();
   if(totalScore > 1.0)
      Print("強い買いシグナル: score=", totalScore);
   else if(totalScore < -1.0)
      Print("強い売りシグナル: score=", totalScore);
  }

配列関数一覧リファレンス

関数機能MQL4MQL5
ArrayResize動的配列のサイズ変更対応対応(reserve追加)
ArrayFreeメモリ解放対応対応
ArraySortソート多次元・方向指定可1次元・昇順のみ
ArrayCopy配列コピー対応対応
ArrayMaximum最大値インデックス対応対応
ArrayMinimum最小値インデックス対応対応
ArrayInitialize全要素初期化対応対応
ArrayFill部分初期化対応対応
ArraySetAsSeries時系列フラグ設定対応対応
ArraySize全要素数取得対応対応
ArrayRange指定次元サイズ対応対応
ArrayIsSeries時系列フラグ確認対応対応
ArrayIsDynamic動的配列か確認対応対応
ArrayCompare配列比較対応対応
ArrayBsearch二分探索対応対応
ArrayPrintデバッグ出力非対応対応
ArrayRemove要素削除非対応対応
ArrayInsert要素挿入非対応対応
ArrayReverse配列反転非対応対応
ArraySwap配列交換非対応対応
CopyBufferインジケーターバッファコピー非対応(直接値取得)対応(必須)
  • 動的配列はCopyBufferやCopyRatesに必須。静的配列は使用不可
  • ArraySetAsSeries(true)でインデックス[0]を最新バーに設定
  • ArrayResizeの第3引数(reserve)でパフォーマンス最適化
  • ArrayPrintはデバッグの必須ツール。構造体配列も出力可能
  • CopyBufferはインジケーター値取得の唯一の方法。バッファ番号を正確に指定

プロが開発したEAをお探しの方は → シストレ.COM EA一覧

シストレ.COMで実績のあるEAが使い放題!/
無料会員登録はこちら
FX自動売買でEAを探すなら
シストレ.COM
実績あるEAが無料
厳格な審査を乗り越えた実績のあるEAが無料で使えます!
自由な口座選び
有料版を購入し柔軟な口座選びが可能!
フォワードテスト公開
全EAのフォワードテスト結果を公開中!
FX初心者も安心
初心者の方も安心して取引を始められます。
多様なEA選択肢
様々な種別のEAをご用意!自分の手法にあった取引が可能です。
信頼のFX会社と提携
人気のFX会社と提携中!様々なFX会社から選べます。
1分で登録完了!EA探すならシストレ.COM!/
無料会員登録はこちら
【FX自動売買】システムトレード完全ガイド|Forex Guide

この記事が気に入ったら
フォローしてね!

お役立ち情報をシェアする
  • URLをコピーしました!
目次