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の配列の違い
| 項目 | MQL4 | MQL5 |
|---|---|---|
| 配列宣言 | 同じ構文 | 同じ構文 |
| 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
}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
);| 項目 | MQL4 | MQL5 |
|---|---|---|
| ソート方向 | 昇順/降順を指定可 | 昇順のみ |
| 対応次元 | 多次元(最初の次元でソート) | 多次元対応(第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: ゾーン3ArraySetAsSeries — 時系列インデックスの設定
配列のインデックス方向を変更します。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などが整形出力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 = 0 | buffer_num = 1 | buffer_num = 2 |
|---|---|---|---|
| iMA | MA値 | - | - |
| iRSI | RSI値 | - | - |
| iBands | BASE(中央線) | UPPER(上限) | LOWER(下限) |
| iMACD | MAIN(MACD線) | SIGNAL(シグナル線) | - |
| iStochastic | MAIN(%K) | SIGNAL(%D) | - |
| iADX | MAIN(ADX) | PLUSDI(+DI) | MINUSDI(-DI) |
| iAlligator | GATORJAW(顎) | 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);
}配列関数一覧リファレンス
| 関数 | 機能 | MQL4 | MQL5 |
|---|---|---|---|
| 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一覧





