「ウィリアムズ%R(Williams’ Percent Range)」というインジケーターをご存知ですか?これはラリー・ウィリアムズ氏が考案したオシレーター系テクニカル指標で、相場の「買われすぎ」「売られすぎ」を判断するのにとても便利なツールです。
MQL4ではiWPR関数を使うことで、このウィリアムズ%Rの値を簡単に取得できます。この記事では、iWPR関数の基本的な使い方から、実践的なEA(自動売買)への応用まで、段階的にわかりやすく解説していきます。
ウィリアムズ%Rとは?
ウィリアムズ%Rは、一定期間における最高値と最安値の範囲のなかで、現在の終値がどの位置にあるかをパーセンテージで示す指標です。
計算式
ウィリアムズ%Rの計算式は以下のとおりです。
// ウィリアムズ%Rの計算式(概念)
// %R = (期間内の最高値 - 現在の終値) / (期間内の最高値 - 期間内の最安値) × (-100)
この計算により、値は常に0 ~ -100の範囲で推移します。ここが他のオシレーターと少し違うポイントで、値がマイナスの範囲で動くことを覚えておきましょう。
値の見方
- 0 に近い(-20より上):買われすぎゾーン → 売りシグナルの候補
- -100 に近い(-80より下):売られすぎゾーン → 買いシグナルの候補
- -50 付近:中立的な状態
ストキャスティクスと非常に似た性質を持っていますが、ウィリアムズ%Rはスケールが反転している点が特徴です。ストキャスティクスでは値が高いほど買われすぎですが、ウィリアムズ%Rでは値が0に近いほど買われすぎとなります。
iWPR関数の構文
MQL4でウィリアムズ%Rの値を取得するには、iWPR関数を使います。構文は以下のとおりです。
double iWPR(
string symbol, // 通貨ペア名
int timeframe, // 時間足
int period, // 計算期間
int shift // シフト(何本前のバーか)
);
引数の詳細
| 引数 | 型 | 説明 | 例 |
|---|---|---|---|
| symbol | string | 通貨ペア名。NULLで現在のチャート | NULL, “USDJPY” |
| timeframe | int | 時間足の定数。0で現在の時間足 | 0, PERIOD_H1 |
| period | int | 計算に使うバーの本数 | 14 |
| shift | int | 取得するバーの位置(0が最新) | 0, 1 |
戻り値はdouble型で、0 ~ -100 の範囲の値が返されます。
基本的な使い方
まずは、iWPR関数で値を取得してログに出力するシンプルな例を見てみましょう。
void OnTick()
{
// 現在のチャート、現在の時間足、期間14、1本前の確定バーのウィリアムズ%Rを取得
double wpr = iWPR(NULL, 0, 14, 1);
// エキスパートログに出力
Print("Williams %%R (1本前) = ", DoubleToString(wpr, 2));
// 買われすぎ・売られすぎの判定
if(wpr > -20)
{
Print("→ 買われすぎゾーン");
}
else if(wpr < -80)
{
Print("→ 売られすぎゾーン");
}
else
{
Print("→ 中立ゾーン");
}
}
ここでshift に 1 を指定している点がポイントです。shift=0 だと現在まだ形成中のバーの値を取得してしまい、リアルタイムで値が変動します。EA開発では、確定したバー(shift=1)の値を使うのが基本です。
サンプル①:買われすぎ・売られすぎの状態をチャートに表示する
次に、ウィリアムズ%Rの状態をチャートのコメントとしてリアルタイム表示するコードを作ってみましょう。
// ウィリアムズ%Rの状態表示スクリプト
extern int WPR_Period = 14; // 計算期間
extern double OverBought = -20.0; // 買われすぎライン
extern double OverSold = -80.0; // 売られすぎライン
void OnTick()
{
double wprCurrent = iWPR(NULL, 0, WPR_Period, 0);
double wprPrev = iWPR(NULL, 0, WPR_Period, 1);
string status = "";
if(wprPrev > OverBought)
status = "★ 買われすぎゾーン(売りに注目)";
else if(wprPrev < OverSold)
status = "★ 売られすぎゾーン(買いに注目)";
else
status = "― 中立ゾーン";
Comment(
"===== Williams %R Monitor =====\n",
"期間: ", WPR_Period, "\n",
"現在値 (形成中): ", DoubleToString(wprCurrent, 2), "\n",
"確定値 (1本前) : ", DoubleToString(wprPrev, 2), "\n",
"状態: ", status, "\n",
"================================"
);
}
このコードをEAとしてチャートにセットすると、左上にウィリアムズ%Rの値と状態がリアルタイムで表示されます。動きを観察しながら指標の特性を学ぶのに最適です。
サンプル②:ゾーン脱出型シグナルのシンプルEA
ウィリアムズ%Rを使ったEAを作る際、単純に「-80以下で買い」とするとダマシが多くなります。そこで、ゾーン脱出型の考え方を取り入れます。
ゾーン脱出型とは、以下のようなロジックです。
- 買いシグナル:売られすぎゾーン(-80以下)に入った後、-80を上回って脱出したとき
- 売りシグナル:買われすぎゾーン(-20以上)に入った後、-20を下回って脱出したとき
これにより、ゾーン内に張り付いたまま反転しないケースのダマシを軽減できます。
// ゾーン脱出型 ウィリアムズ%R EA
extern int WPR_Period = 14;
extern double LotSize = 0.01;
extern double OverBought = -20.0;
extern double OverSold = -80.0;
extern int StopLoss = 100; // ストップロス(pips)
extern int TakeProfit = 200; // テイクプロフィット(pips)
extern int MagicNumber = 12345;
void OnTick()
{
// 新しいバーが確定したときだけ処理する
static datetime lastBarTime = 0;
if(Time[0] == lastBarTime) return;
lastBarTime = Time[0];
// 確定バーと、その1つ前のバーのウィリアムズ%Rを取得
double wpr1 = iWPR(NULL, 0, WPR_Period, 1); // 直近の確定バー
double wpr2 = iWPR(NULL, 0, WPR_Period, 2); // その1つ前
// 既存ポジションの確認
int posCount = 0;
for(int i = OrdersTotal() - 1; i >= 0; i--)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
posCount++;
}
}
// ポジションがない場合のみエントリー判定
if(posCount > 0) return;
double sl, tp;
// 買いシグナル:売られすぎゾーンから脱出
if(wpr2 < OverSold && wpr1 >= OverSold)
{
sl = Ask - StopLoss * Point * 10;
tp = Ask + TakeProfit * Point * 10;
int ticket = OrderSend(Symbol(), OP_BUY, LotSize, Ask, 3, sl, tp,
"WPR Buy Signal", MagicNumber, 0, clrBlue);
if(ticket > 0)
Print("買いエントリー: WPR=", DoubleToString(wpr1, 2));
else
Print("買い注文エラー: ", GetLastError());
}
// 売りシグナル:買われすぎゾーンから脱出
if(wpr2 > OverBought && wpr1 <= OverBought)
{
sl = Bid + StopLoss * Point * 10;
tp = Bid - TakeProfit * Point * 10;
int ticket = OrderSend(Symbol(), OP_SELL, LotSize, Bid, 3, sl, tp,
"WPR Sell Signal", MagicNumber, 0, clrRed);
if(ticket > 0)
Print("売りエントリー: WPR=", DoubleToString(wpr1, 2));
else
Print("売り注文エラー: ", GetLastError());
}
}
このEAのポイントは以下のとおりです。
- 新しいバー確定時のみ判定:static変数でバーの時刻を管理し、同じバーで何度も判定しない
- ゾーン脱出の判定:2本前がゾーン内、1本前がゾーン外になったことで「脱出」を検知
- ポジション制限:同時に1ポジションのみ持つようにしている
サンプル③:移動平均線との組み合わせ(トレンドフィルター付きEA)
オシレーター系指標の弱点は、強いトレンドが発生している局面では買われすぎ・売られすぎの状態が長く続き、シグナルが機能しにくいことです。
これを改善するために、移動平均線によるトレンドフィルターを追加したEAを作ってみましょう。
// トレンドフィルター付き ウィリアムズ%R EA
extern int WPR_Period = 14;
extern int MA_Period = 50; // 移動平均線の期間
extern int MA_Method = MODE_SMA; // 移動平均の種類
extern double LotSize = 0.01;
extern double OverBought = -20.0;
extern double OverSold = -80.0;
extern int StopLoss = 100;
extern int TakeProfit = 200;
extern int MagicNumber = 12346;
void OnTick()
{
// 新しいバー確定時のみ処理
static datetime lastBarTime = 0;
if(Time[0] == lastBarTime) return;
lastBarTime = Time[0];
// ウィリアムズ%Rの値を取得
double wpr1 = iWPR(NULL, 0, WPR_Period, 1);
double wpr2 = iWPR(NULL, 0, WPR_Period, 2);
// 移動平均線の値を取得
double ma1 = iMA(NULL, 0, MA_Period, 0, MA_Method, PRICE_CLOSE, 1);
// 現在の価格と移動平均線の位置関係でトレンドを判定
double closePrice = Close[1];
bool isUpTrend = (closePrice > ma1); // 上昇トレンド
bool isDownTrend = (closePrice < ma1); // 下降トレンド
// 既存ポジションの確認
int posCount = 0;
for(int i = OrdersTotal() - 1; i >= 0; i--)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
posCount++;
}
}
if(posCount > 0) return;
double sl, tp;
// 買いシグナル:上昇トレンド中 + 売られすぎゾーンから脱出
if(isUpTrend && wpr2 < OverSold && wpr1 >= OverSold)
{
sl = Ask - StopLoss * Point * 10;
tp = Ask + TakeProfit * Point * 10;
int ticket = OrderSend(Symbol(), OP_BUY, LotSize, Ask, 3, sl, tp,
"WPR+MA Buy", MagicNumber, 0, clrBlue);
if(ticket > 0)
Print("買いエントリー(トレンドフィルター付き): WPR=",
DoubleToString(wpr1, 2), " MA=", DoubleToString(ma1, 5));
}
// 売りシグナル:下降トレンド中 + 買われすぎゾーンから脱出
if(isDownTrend && wpr2 > OverBought && wpr1 <= OverBought)
{
sl = Bid + StopLoss * Point * 10;
tp = Bid - TakeProfit * Point * 10;
int ticket = OrderSend(Symbol(), OP_SELL, LotSize, Bid, 3, sl, tp,
"WPR+MA Sell", MagicNumber, 0, clrRed);
if(ticket > 0)
Print("売りエントリー(トレンドフィルター付き): WPR=",
DoubleToString(wpr1, 2), " MA=", DoubleToString(ma1, 5));
}
}
このEAでは、以下のフィルタリングを行っています。
- 買いエントリー:価格が移動平均線より上(上昇トレンド)のときだけ、売られすぎからの脱出シグナルを採用
- 売りエントリー:価格が移動平均線より下(下降トレンド)のときだけ、買われすぎからの脱出シグナルを採用
こうすることで、トレンド方向と逆行するエントリーを防ぎ、勝率の向上が期待できます。
iWPR関数を使う際の注意点
1. 値の範囲はマイナスである
ウィリアムズ%Rの値は0 ~ -100です。RSIのように0~100ではないので、条件式を書くときに符号を間違えないよう注意してください。例えば「-80以下」は wpr < -80 と書きます。
2. トレーディングスタイルに合わせた期間設定
ウィリアムズ%Rの計算期間は、トレーディングスタイルに合わせて調整するのがおすすめです。
| スタイル | 推奨期間 | 特徴 |
|---|---|---|
| スキャルピング | 7 | シグナルが敏感、ダマシも多い |
| デイトレード | 14 | バランスが良い(デフォルト) |
| スイングトレード | 21〜28 | シグナルは少ないが信頼性が高い |
3. 強いトレンド相場には注意
オシレーター系指標全般に言えることですが、強い上昇トレンドや下降トレンドでは、ウィリアムズ%Rが買われすぎ・売られすぎゾーンに張り付いたまま動かないことがあります。このような場合、逆張りシグナルが機能しません。サンプル③のようにトレンドフィルターと組み合わせることを強くおすすめします。
4. 確定バーの値を使う
EA開発では、形成中のバー(shift=0)ではなく、確定したバー(shift=1以上)の値を使うのが鉄則です。形成中のバーの値はティックごとに変動するため、シグナルがチラつく原因になります。
まとめ
この記事では、MQL4のiWPR関数を使ってウィリアムズ%Rの値を取得し、EA開発に活用する方法を解説しました。最後にポイントをおさらいしましょう。
- iWPR関数は4つの引数(symbol, timeframe, period, shift)を指定してウィリアムズ%Rの値を取得する
- 値の範囲は0 ~ -100で、-20以上が買われすぎ、-80以下が売られすぎ
- ゾーン脱出型のシグナルにすることで、単純なゾーン判定よりダマシを軽減できる
- 移動平均線などのトレンドフィルターと組み合わせることで、さらに精度を高められる
- EA開発では必ず確定バー(shift=1)の値を使うこと
ウィリアムズ%Rはシンプルな指標ですが、正しく使えばエントリーポイントの精度を上げる強力な武器になります。まずはサンプルコードをストラテジーテスターで動かして、動作を確認するところから始めてみてください!

