CCI(商品チャネル指数)は、相場の「買われすぎ・売られすぎ」を数値で判断できる人気のオシレーター系インジケーターです。MQL4ではiCCI関数を使うことで、EA(自動売買)の中から簡単にCCIの値を取得できます。
この記事では、iCCI関数の基本的な使い方からパラメータの意味、そしてCCIのクロスを利用した実践的なEAの作成方法まで、ステップバイステップで解説していきます。
CCI(商品チャネル指数)とは?
CCIは1980年にドナルド・ランバート氏が開発したモメンタム系オシレーターです。もともとは商品先物市場向けに作られましたが、現在ではFXや株式など幅広い市場で使われています。
CCIの特徴は、RSIやストキャスティクスのように0〜100の範囲に収まるのではなく、上下に制限なく動く点です。一般的には以下の基準で判断します。
- +100を上回る:買われすぎ(上昇トレンドが強い)
- -100を下回る:売られすぎ(下降トレンドが強い)
- 0ライン:トレンドの方向転換の目安
CCIの計算式
CCIの計算式は以下の通りです。
CCI = (TP - MA) / (0.015 × MD)
// TP(ティピカルプライス)= (高値 + 安値 + 終値) / 3
// MA = TPの単純移動平均(期間N)
// MD = TPと移動平均の平均偏差
// 0.015 = CCI値の約70〜80%が±100以内に収まるように設定された定数
計算式を覚える必要はありませんが、TPをベースにしていることは頭に入れておきましょう。iCCI関数のapplied_priceパラメータに関わってきます。
iCCI関数の構文
MQL4でCCIの値を取得するには、iCCI関数を使います。構文は以下の通りです。
double iCCI(
string symbol, // 通貨ペア名
int timeframe, // 時間足
int period, // 平均期間
int applied_price, // 適用価格
int shift // シフト(何本前の足か)
);
パラメータ一覧
| パラメータ | 型 | 説明 |
|---|---|---|
| symbol | string | 通貨ペア名。現在のチャートならNULLまたはSymbol() |
| timeframe | int | 時間足。0で現在のチャートの時間足。PERIOD_H1など定数も使用可能 |
| period | int | CCIの計算期間。一般的には14や20がよく使われる |
| applied_price | int | 計算に使う価格の種類 |
| shift | int | 何本前のローソク足のCCI値を取得するか。0が現在の足、1が1本前の確定足 |
applied_price(適用価格)の定数一覧
CCIの計算に使用する価格タイプを指定します。デフォルトのCCIではティピカルプライスが使われます。
| 定数名 | 値 | 説明 |
|---|---|---|
| PRICE_CLOSE | 0 | 終値 |
| PRICE_OPEN | 1 | 始値 |
| PRICE_HIGH | 2 | 高値 |
| PRICE_LOW | 3 | 安値 |
| PRICE_MEDIAN | 4 | 中央値(高値+安値)/ 2 |
| PRICE_TYPICAL | 5 | ティピカルプライス(高値+安値+終値)/ 3 |
| PRICE_WEIGHTED | 6 | 加重終値(高値+安値+終値×2)/ 4 |
チャート上にCCIインジケーターを表示して比較する場合は、applied_priceを同じ設定にしないと値がずれるので注意してください。標準のCCIはPRICE_TYPICALを使用しています。
基本的な使い方
まずは最もシンプルな使い方を見てみましょう。1本前の確定足のCCI値を取得してコメントに表示する例です。
void OnTick()
{
// 1本前の確定足のCCI(期間14、ティピカルプライス)を取得
double cciValue = iCCI(NULL, 0, 14, PRICE_TYPICAL, 1);
// チャート上にCCI値を表示
Comment("CCI(14) = ", DoubleToString(cciValue, 2));
}
ポイント:shiftに1を指定して確定足の値を使うのが基本です。0(現在の足)はティックごとに値が変動するため、売買シグナルの判定には向きません。
CCIクロスで売買するEAを作ろう
ここからが本番です。CCIが-100を下から上にクロスしたら買い、+100を上から下にクロスしたら売り、0ラインクロスで決済するEAを作成します。
トレードロジックの整理
- 買いエントリー:CCI(1本前)が-100以上 かつ CCI(2本前)が-100未満 → -100を上抜け
- 売りエントリー:CCI(1本前)が+100以下 かつ CCI(2本前)が+100超 → +100を下抜け
- 買いポジション決済:CCIが0を下回った時
- 売りポジション決済:CCIが0を上回った時
完全なEAコード
//+------------------------------------------------------------------+
//| CCI Cross EA |
//+------------------------------------------------------------------+
#property strict
// 入力パラメータ
input int CCI_Period = 14; // CCI期間
input double LotSize = 0.1; // ロットサイズ
input int StopLoss = 100; // ストップロス(pips)
input int TakeProfit = 200; // テイクプロフィット(pips)
input int MagicNumber = 20240101; // マジックナンバー
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
// CCI値を取得(確定足を使用)
double cci1 = iCCI(NULL, 0, CCI_Period, PRICE_TYPICAL, 1); // 1本前
double cci2 = iCCI(NULL, 0, CCI_Period, PRICE_TYPICAL, 2); // 2本前
// 現在のポジション状態を確認
int buyCount = CountPositions(OP_BUY);
int sellCount = CountPositions(OP_SELL);
// --- 決済ロジック ---
// 買いポジション保有中:CCIが0を下回ったら決済
if(buyCount > 0 && cci1 < 0)
{
ClosePositions(OP_BUY);
}
// 売りポジション保有中:CCIが0を上回ったら決済
if(sellCount > 0 && cci1 > 0)
{
ClosePositions(OP_SELL);
}
// --- エントリーロジック ---
// ポジションがない場合のみエントリー
if(buyCount == 0 && sellCount == 0)
{
// 買いシグナル:CCIが-100を下から上にクロス
if(cci2 < -100 && cci1 >= -100)
{
double sl = (StopLoss > 0) ? Ask - StopLoss * Point * 10 : 0;
double tp = (TakeProfit > 0) ? Ask + TakeProfit * Point * 10 : 0;
int ticket = OrderSend(Symbol(), OP_BUY, LotSize, Ask, 30, sl, tp,
"CCI Buy", MagicNumber, 0, clrBlue);
if(ticket < 0)
Print("Buy OrderSend error: ", GetLastError());
}
// 売りシグナル:CCIが+100を上から下にクロス
if(cci2 > 100 && cci1 <= 100)
{
double sl = (StopLoss > 0) ? Bid + StopLoss * Point * 10 : 0;
double tp = (TakeProfit > 0) ? Bid - TakeProfit * Point * 10 : 0;
int ticket = OrderSend(Symbol(), OP_SELL, LotSize, Bid, 30, sl, tp,
"CCI Sell", MagicNumber, 0, clrRed);
if(ticket < 0)
Print("Sell OrderSend error: ", GetLastError());
}
}
}
//+------------------------------------------------------------------+
//| 指定タイプのポジション数をカウント |
//+------------------------------------------------------------------+
int CountPositions(int type)
{
int count = 0;
for(int i = OrdersTotal() - 1; i >= 0; i--)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber && OrderType() == type)
count++;
}
}
return count;
}
//+------------------------------------------------------------------+
//| 指定タイプのポジションを全て決済 |
//+------------------------------------------------------------------+
void ClosePositions(int type)
{
for(int i = OrdersTotal() - 1; i >= 0; i--)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber && OrderType() == type)
{
double closePrice = (type == OP_BUY) ? Bid : Ask;
if(!OrderClose(OrderTicket(), OrderLots(), closePrice, 30, clrYellow))
Print("OrderClose error: ", GetLastError());
}
}
}
}
コードのポイント解説
① MagicNumberの活用
MagicNumberを使うことで、このEAが出した注文だけを識別できます。手動注文や他のEAの注文を誤って決済してしまう事故を防げます。
② 確定足(shift=1, 2)でクロスを検出
2本前と1本前の確定足を比較してクロスを検出しています。現在の足(shift=0)を使うと、ティックごとに値が変わるためシグナルが不安定になります。
③ 決済を逆方向ではなく0ラインで行う
CCIが0ラインをクロスした時点で決済することで、利益の取りこぼしを減らす設計になっています。もちろん、SL/TPによる自動決済も併用しています。
応用テクニック:マルチタイムフレーム分析
iCCI関数の第2引数(timeframe)を変えるだけで、上位足のCCIをフィルターとして使うことができます。例えば、日足のCCIの方向に合わせてエントリーを絞り込む手法です。
// 上位足(日足)のCCIでトレンド方向を判定
double cciDaily = iCCI(NULL, PERIOD_D1, 14, PRICE_TYPICAL, 1);
// 現在の時間足のCCIでエントリータイミングを判定
double cciCurrent1 = iCCI(NULL, 0, 14, PRICE_TYPICAL, 1);
double cciCurrent2 = iCCI(NULL, 0, 14, PRICE_TYPICAL, 2);
// 日足CCIが0以上(上昇傾向)の時だけ買いエントリー
if(cciDaily > 0 && cciCurrent2 < -100 && cciCurrent1 >= -100)
{
// 買いエントリー処理
}
// 日足CCIが0以下(下降傾向)の時だけ売りエントリー
if(cciDaily < 0 && cciCurrent2 > 100 && cciCurrent1 <= 100)
{
// 売りエントリー処理
}
上位足のトレンド方向に逆らわないことで、ダマシのシグナルを大幅に減らすことが期待できます。
iCCI関数を使う際の注意点
1. applied_priceの不一致に注意
チャート上に表示しているCCIインジケーターと、iCCI関数で指定したapplied_priceが異なると、値がずれます。検証時は必ず同じ設定にしましょう。標準のCCIはPRICE_TYPICALです。
2. レンジ相場での連続シグナルに注意
CCIはモメンタム指標なので、レンジ相場では±100ラインを頻繁に行き来し、ダマシが多発します。移動平均線やADXなどのトレンドフィルターを組み合わせることをおすすめします。
3. 計算に必要なバー数
CCIの計算には、指定した期間分のローソク足データが必要です。チャートのバー数が少ないと正確な値が得られません。バックテスト時は十分なヒストリカルデータを用意してください。
まとめ
今回はMQL4のiCCI関数の使い方を、基本から実践的なEA作成まで解説しました。
- iCCI関数は5つのパラメータでCCIの値を簡単に取得できる
- ±100ラインのクロスをエントリーシグナルに、0ラインクロスを決済シグナルに使うのが王道的な手法
- 確定足(shift=1以上)を使ってシグナル判定するのが安定した運用のコツ
- マルチタイムフレーム分析で上位足のトレンド方向にフィルターをかけると精度が向上する
- applied_priceはチャート上のインジケーターと合わせることを忘れずに
CCIはシンプルながら奥が深いインジケーターです。まずはサンプルEAをストラテジーテスターで動かしてみて、パラメータを変えながらCCIの振る舞いを体感してみてください!

