MetaTraderのチャートで、価格の上下にドットが表示される「パラボリックSAR」を見たことはありませんか?このインジケーターは、トレンドの方向転換を視覚的に捉えるのに非常に優れたツールです。
MQL4ではiSAR()関数を使うことで、パラボリックSARの値をプログラムから簡単に取得できます。この記事では、iSAR()関数の基本的な使い方から、実際に売買シグナルを出すEAの作成まで、ステップバイステップで解説していきます。
パラボリックSARとは?基本的な仕組みを理解しよう
パラボリックSAR(Stop And Reverse)は、J・ウェルズ・ワイルダーが考案したトレンドフォロー型のテクニカル指標です。「SAR」は「Stop And Reverse(ストップ・アンド・リバース)」の略で、ポジションを決済して反転させるポイントを示すという意味があります。
チャート上での見え方
パラボリックSARはチャート上に小さなドットとして表示されます。
- ドットが価格の下にある場合 → 上昇トレンド(買いシグナル)
- ドットが価格の上にある場合 → 下降トレンド(売りシグナル)
ドットが価格の上から下に(または下から上に)切り替わった瞬間が、トレンド転換のシグナルとなります。
計算式の概要
パラボリックSARの計算式は次のとおりです。
SAR = 前の期間のSAR + AF ×(EP − 前の期間のSAR)
ここで使われる2つの重要なパラメーターを押さえておきましょう。
- AF(Acceleration Factor / 加速因数):初期値は通常0.02で、トレンドが続くたびに0.02ずつ増加し、最大値(通常0.2)まで上がります。AFが大きくなるほど、SARは価格に素早く近づきます。
- EP(Extreme Point / 極値):現在のトレンド中の最高値(上昇トレンド時)または最安値(下降トレンド時)です。
ただし、MQL4ではiSAR()関数が自動的に計算してくれるので、計算式を自分でコーディングする必要はありません。パラメーターの意味を理解しておくだけで十分です。
iSAR()関数のシンタックスとパラメーター
iSAR()関数の定義は以下のとおりです。
double iSAR(
string symbol, // 通貨ペア名
int timeframe, // 時間足
double step, // 加速因数のステップ
double maximum, // 加速因数の最大値
int shift // バーのシフト
);
各パラメーターの詳細を表で確認しましょう。
| パラメーター | 型 | 説明 | よく使う値 |
|---|---|---|---|
| symbol | string | 通貨ペア名。NULL で現在のチャートの通貨ペア | NULL, “USDJPY” など |
| timeframe | int | 時間足。0 で現在のチャートの時間足 | 0, PERIOD_H1, PERIOD_D1 など |
| step | double | AFの増加ステップ(初期値にもなる) | 0.02 |
| maximum | double | AFの最大値 | 0.2 |
| shift | int | 取得するバーの位置(0=現在のバー) | 0, 1, 2 |
戻り値はdouble型で、指定したバーにおけるパラボリックSARの値(価格レベル)が返されます。
基本的な使い方:SARの値を取得してみよう
シンプルな値の取得
まずは、現在のバーのパラボリックSAR値を取得して、エキスパートログに出力するシンプルな例です。
void OnTick()
{
// 現在のバー(shift=0)のパラボリックSAR値を取得
double sarValue = iSAR(NULL, 0, 0.02, 0.2, 0);
// ログに出力して確認
Print("現在のSAR値: ", DoubleToString(sarValue, Digits));
}
引数にNULLと0を指定すると、EAが稼働しているチャートの通貨ペアと時間足が自動的に使われます。stepに0.02、maximumに0.2というのがデフォルト設定です。
トレンド方向の判定
パラボリックSARで最もよく使うのが、トレンド方向の判定です。SARの値と現在の価格を比較するだけで簡単に判定できます。
void OnTick()
{
// 1本前の確定バーのSAR値を取得(shift=1)
double sarValue = iSAR(NULL, 0, 0.02, 0.2, 1);
// 1本前のバーの終値を取得
double closePrice = Close[1];
// トレンド方向を判定
if(closePrice > sarValue)
{
// SARが価格の下にある → 上昇トレンド
Print("上昇トレンド中 | Close: ", DoubleToString(closePrice, Digits),
" > SAR: ", DoubleToString(sarValue, Digits));
}
else
{
// SARが価格の上にある → 下降トレンド
Print("下降トレンド中 | Close: ", DoubleToString(closePrice, Digits),
" < SAR: ", DoubleToString(sarValue, Digits));
}
}
ここではshift=1(1本前の確定バー)を使っている点に注目してください。shift=0の現在のバーはまだ確定していないため、シグナルがコロコロ変わってしまう可能性があります。確定したバーで判定するのが基本です。
実践:パラボリックSARで売買するEAを作ろう
ここからが本番です。パラボリックSARのトレンド転換を検出して、実際に売買注文を出すEAを作ってみましょう。
売買ロジックの考え方
SARのトレンド転換は、2本前のバーと1本前のバーのSAR値を比較して検出します。
- 買いシグナル:2本前はSARが価格の上(下降トレンド)→ 1本前はSARが価格の下(上昇トレンド)に変わった
- 売りシグナル:2本前はSARが価格の下(上昇トレンド)→ 1本前はSARが価格の上(下降トレンド)に変わった
フルサンプルEA
//+------------------------------------------------------------------+
//| パラボリックSAR転換EA |
//+------------------------------------------------------------------+
#property copyright "MQL学習サイト"
#property version "1.00"
#property strict
// --- 入力パラメーター ---
input double SarStep = 0.02; // SAR加速因数ステップ
input double SarMaximum = 0.2; // SAR加速因数最大値
input double LotSize = 0.1; // 取引ロット数
input int SlippagePts = 3; // スリッページ(ポイント)
input int MagicNumber = 12345; // マジックナンバー
// --- 新バー判定用のグローバル変数 ---
datetime lastBarTime = 0;
//+------------------------------------------------------------------+
//| 新しいバーが生成されたかを判定する関数 |
//+------------------------------------------------------------------+
bool IsNewBar()
{
datetime currentBarTime = Time[0];
if(currentBarTime != lastBarTime)
{
lastBarTime = currentBarTime;
return true;
}
return false;
}
//+------------------------------------------------------------------+
//| 自分のEAが持つポジション数を取得する関数 |
//+------------------------------------------------------------------+
int CountMyPositions(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)
{
if(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)
{
if(OrderType() == type)
{
double closePrice;
if(type == OP_BUY)
closePrice = Bid;
else
closePrice = Ask;
bool result = OrderClose(OrderTicket(), OrderLots(),
closePrice, SlippagePts, clrNONE);
if(!result)
Print("決済エラー: ", GetLastError());
}
}
}
}
}
//+------------------------------------------------------------------+
//| OnTick - メイン処理 |
//+------------------------------------------------------------------+
void OnTick()
{
// 新しいバーが確定した時だけ処理する
if(!IsNewBar())
return;
// --- パラボリックSARの値を取得 ---
double sar1 = iSAR(NULL, 0, SarStep, SarMaximum, 1); // 1本前のバー
double sar2 = iSAR(NULL, 0, SarStep, SarMaximum, 2); // 2本前のバー
// --- 各バーの終値を取得 ---
double close1 = Close[1]; // 1本前のバーの終値
double close2 = Close[2]; // 2本前のバーの終値
// --- トレンド方向を判定 ---
bool isUpTrend1 = (close1 > sar1); // 1本前:上昇トレンド?
bool isDownTrend1 = (close1 < sar1); // 1本前:下降トレンド?
bool isUpTrend2 = (close2 > sar2); // 2本前:上昇トレンド?
bool isDownTrend2 = (close2 < sar2); // 2本前:下降トレンド?
// --- 買いシグナル:下降→上昇に転換 ---
if(isDownTrend2 && isUpTrend1)
{
// 売りポジションがあれば決済
if(CountMyPositions(OP_SELL) > 0)
ClosePositions(OP_SELL);
// 買いポジションがなければ新規エントリー
if(CountMyPositions(OP_BUY) == 0)
{
int ticket = OrderSend(Symbol(), OP_BUY, LotSize,
Ask, SlippagePts, 0, 0,
"SAR Buy Signal", MagicNumber, 0, clrBlue);
if(ticket < 0)
Print("買い注文エラー: ", GetLastError());
else
Print("買い注文成功 チケット: ", ticket);
}
}
// --- 売りシグナル:上昇→下降に転換 ---
if(isUpTrend2 && isDownTrend1)
{
// 買いポジションがあれば決済
if(CountMyPositions(OP_BUY) > 0)
ClosePositions(OP_BUY);
// 売りポジションがなければ新規エントリー
if(CountMyPositions(OP_SELL) == 0)
{
int ticket = OrderSend(Symbol(), OP_SELL, LotSize,
Bid, SlippagePts, 0, 0,
"SAR Sell Signal", MagicNumber, 0, clrRed);
if(ticket < 0)
Print("売り注文エラー: ", GetLastError());
else
Print("売り注文成功 チケット: ", ticket);
}
}
}
このEAのポイントを整理しましょう。
- IsNewBar()関数で新しいバーが確定したタイミングだけ処理を実行。ティックごとに何度も注文が飛ぶのを防ぎます。
- 2本前と1本前のSAR値を比較して転換を検出。確定バーだけを使うので安定したシグナルになります。
- 転換時に逆方向のポジションを先に決済してから新規エントリーする、ドテン(途転)方式です。
- MagicNumberを使って、このEAのポジションだけを管理しています。他のEAのポジションには干渉しません。
注意点とパフォーマンス向上のTips
加速因数パラメーターの調整
デフォルト値の step=0.02 / maximum=0.2 は万能ではありません。
- stepを小さくする(例:0.01)→ SARの反応が遅くなり、ダマシが減る反面、エントリーが遅れる
- stepを大きくする(例:0.03)→ SARの反応が速くなり、転換を早く捉えるが、ダマシが増える
- maximumを変える→ AFの上限を制御。小さくするとSARが価格に追いつくスピードが制限される
バックテストを繰り返して、対象通貨ペアと時間足に合った値を見つけましょう。
レンジ相場に弱い点を理解しよう
パラボリックSARはトレンドフォロー型の指標なので、レンジ(横ばい)相場では頻繁に転換シグナルが発生し、連続した損失(いわゆる「ダマシ」)が起きやすくなります。
対策としては、以下の方法があります。
- ADXなどのトレンド強度指標と組み合わせる(ADXが25以上のときだけ取引するなど)
- 移動平均線と併用する(移動平均線の方向とSARの方向が一致した場合のみエントリー)
- より長い時間足でトレンド方向を確認する(マルチタイムフレーム分析)
マルチタイムフレームでSARを活用する
異なる時間足のSAR値も、iSAR()関数のtimeframeパラメーターを変えるだけで簡単に取得できます。
void OnTick()
{
// 日足のSAR値を取得(大きなトレンド方向の確認用)
double sarDaily = iSAR(NULL, PERIOD_D1, 0.02, 0.2, 1);
double closeDaily = iClose(NULL, PERIOD_D1, 1);
// 1時間足のSAR値を取得(エントリータイミング用)
double sarH1 = iSAR(NULL, PERIOD_H1, 0.02, 0.2, 1);
double closeH1 = iClose(NULL, PERIOD_H1, 1);
// 日足が上昇トレンド かつ 1時間足も上昇トレンドなら買いを検討
if(closeDaily > sarDaily && closeH1 > sarH1)
{
Print("日足・1時間足ともに上昇トレンド → 買い検討");
}
// 日足が下降トレンド かつ 1時間足も下降トレンドなら売りを検討
if(closeDaily < sarDaily && closeH1 < sarH1)
{
Print("日足・1時間足ともに下降トレンド → 売り検討");
}
}
上位足のトレンド方向に順張りすることで、ダマシを大幅に減らすことができます。
まとめ
この記事で学んだポイントを整理しましょう。
- パラボリックSARは、ドットの位置でトレンド方向と転換点を示すインジケーター
- iSAR()関数は、symbol・timeframe・step・maximum・shiftの5つのパラメーターで値を取得できる
- トレンド判定は、SARの値と価格を比較するだけでシンプルに行える
- 転換シグナルは、2本前と1本前のバーでトレンド方向が変わったかどうかで検出する
- レンジ相場対策として、ADXや移動平均線、マルチタイムフレーム分析との併用が効果的
パラボリックSARは計算ロジックがシンプルなぶん、EA化しやすいインジケーターです。まずは今回のサンプルEAをストラテジーテスターで動かしてみて、パラメーターを調整したり、フィルター条件を追加したりして、自分だけの売買ロジックに育てていきましょう!


