テクニカル分析でメジャーなインジケーターといえば、移動平均線を思い浮かべるのではないでしょうか。
この移動平均線、MQL5の組み込み関数を使用することで、かんたんにカスタムインジケーターとして作成できますが、平滑化の種類によって、値動きに対する感度が異なってきます。
ここではMQL5で用意されている平滑化の種類について見ていきたいと思います。
平滑化の種類
MQL5では、ENUM_MA_METHOD列挙体にて次の4種類の平滑化がサポートされています。
ID | 和名 | 英語表記 |
---|---|---|
MODE_SMA | 単純移動平均 | Simple Moving Average (SMA) |
MODE_EMA | 指数平滑移動平均 | Exponential Moving Average (EMA) |
MODE_SMMA | 平滑移動平均 | Smoothed Moving Average (SMMA) |
MODE_LWMA | 線形荷重移動平均 | Linear Weighted Moving Average (LWMA) |
単純移動平均(SMA)
単純に、指定した期間内の価格の平均値を算出して利用します。
例えば直近5つの足に対する単純移動平均線を引く場合は次の計算式で算出。
(4つ前の価格 + 3つ前の価格 + 2つ前の価格 + 1つ前の価格 + 直近の価格) ÷ 期間n
ある時点で、過去5つの足の価格が、140円→141円→142円→143円→144円と遷移した場合、
(140 + 141 + 142 + 143 + 144) ÷ 5 = 142.0円。
次の足で価格が150円に遷移した場合、
(141 + 142 + 143 + 144 + 150) ÷ 5 = 144.0円。
というように、それぞれ単純な平均値を算出し、その算出結果を線で結んだものが単純移動平均線となります。
指数平滑移動平均(EMA)
前回の算出結果と、重みをつけた現在の価格を使って平均値を算出して利用するのが指数平滑移動平均。
前回のEMA + 平滑化指数α × (直近の価格 - 前回のEMA)
※平滑化指数α = 2 ÷ (期間n + 1)
計算には「前回のEMA」の算出結果が必要になります。
このため、初回の計算の際には、単純移動平均(SMA)と同様の計算を行なって算出した値を使用します。
平滑化指数αを算出する際に2を積算しているため、直近の価格変化に反応しやすくなります。
ある時点で、過去5つの足の価格が、140円→141円→142円→143円→144円と遷移した場合、
(140 + 141 + 142 + 143 + 144 ) ÷ 5 = 142.0円。
初回の計算はSMAと同一ですが、次の足で価格が150円に遷移した場合、
142 + (2 ÷ (5 + 1)) × (150 – 142) ≒ 144.7円。
少しわかりづらい計算式ですが、SMAよりも直近値に反応していることがわかると思います。
平滑移動平均(SMMA)
価格の変動にすぐ反応しないように調整されたものが平滑移動平均。
突発的な価格変動に対する影響が少ないため、長期的なトレンド判断に活用できます。
((前回のSMMA × (期間n - 1) + 直近の価格) ÷ 期間n
ある時点で、過去5つの足の価格が、140円→141円→142円→143円→144円と遷移した場合、
(140 + 141 + 142 + 143 + 144 ) ÷ 5 = 142.0円。
こちらも初回の計算はSMAと同一。次の足で価格が150円に遷移した場合、
((142 × (5 – 1) + 150) ÷ 5 = 143.6円。
全体的になだらかな(平滑化された)曲線を描きます。
線形荷重移動平均(LWMA)
EMAと同じように、直近の価格に重点を置き、重み(荷重)をかけて平均値を算出するものです。
重みを一定の割合で変化しているため、線形荷重移動平均と呼ばれます。
((直近の価格 × 期間n) + (1つ前の価格 × n-1) + ・・・ + (4つ前の価格 × n-4)) ÷ (n + (n-1) + ・・・ + (n-4))
ある時点で、過去5つの足の価格が、140円→141円→142円→143円→144円と遷移した場合、
((144 × 5) + (143 × (5 – 1)) + (142 × (5 – 2)) + (141 × (5 – 3)) + (140 × (5 – 4))) ÷ (5 + (5 – 1) + (5 – 2) + (5 – 3) + (5 – 4)) ≒ 142.7円。
次の足で価格が150円に遷移した場合、
((150 × 5) + (144 × (5 – 1)) + (143 × (5 – 2)) + (142 × (5 – 3)) + (141 × (5 – 4))) ÷ (5 + (5 – 1) + (5 – 2) + (5 – 3) + (5 – 4)) ≒ 145.3円。
LWMAでは過去の価格に対して一定の荷重をかけるため、一般的にEMAの方が直近の値に対する反応がよいと言われています。
しかし価格の遷移によっては上の例のように逆に反応が遅くなることもあり、一概に言えないので注意が必要です。
平滑化の種類ごとの値の変化
SMA、EMA、SMMA、LWMAの算出結果をそれぞれ並べてみました。
下表のNo.順に価格が遷移した場合、それぞれの平均値の算出結果です。
SMAに対して、EMAやLWMAは現在価格に対して速く反応しているのに対し、SMMAではゆっくりと変化しているのが見てとれます。
No | 価格 | SMA | EMA | SMMA | LWMA |
---|---|---|---|---|---|
1 | 140 | ー | ー | ー | ー |
2 | 145 | ー | ー | ー | ー |
3 | 142 | ー | ー | ー | ー |
4 | 148 | ー | ー | ー | ー |
5 | 150 | 145.0 | 145.0 | 145.0 | 146.5 |
6 | 157 | 148.4 | 149.0 | 147.4 | 150.5 |
7 | 160 | 151.4 | 152.7 | 149.9 | 154.4 |
実際に描画してみると次のようになります。
① の箇所のように、青線であるSMAはほかの平滑化の種類よりも反応が鈍く見えます。
また②の箇所では赤線(SMMA)は他の平滑化の種類よりも緩やかな平均線になっています。
ちなみにこのカスタムインジケーターはこんなプログラムソースでかんたんに作成できます。
#property indicator_buffers 4 // 指標計算に使用するバッファの数を指定(指標バッファ)
#property indicator_plots 4 // 指標のプロット数を指定
// プロット1の定義
#property indicator_type1 DRAW_LINE // 描画タイプ
#property indicator_color1 clrDodgerBlue // 青線
// プロット2の定義
#property indicator_type2 DRAW_LINE // 描画タイプ
#property indicator_color2 clrYellow // 黄線
// プロット3の定義
#property indicator_type3 DRAW_LINE // 描画タイプ
#property indicator_color3 clrRed // 赤線
// プロット4の定義
#property indicator_type4 DRAW_LINE // 描画タイプ
#property indicator_color4 clrWhite // 白線
double m_val1[], m_val2[], m_val3[], m_val4[]; // 指標バッファと紐づける動的配列を宣言
int m_handle1, m_handle2, m_handle3, m_handle4; // 各指標のハンドル
int m_bars_calculated1 = 0;
int m_bars_calculated2 = 0;
int m_bars_calculated3 = 0;
int m_bars_calculated4 = 0;
//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
// 動的配列と指標バッファを紐付け
SetIndexBuffer(0, m_val1, INDICATOR_DATA);
SetIndexBuffer(1, m_val2, INDICATOR_DATA);
SetIndexBuffer(2, m_val3, INDICATOR_DATA);
SetIndexBuffer(3, m_val4, INDICATOR_DATA);
// 動的配列変数を初期化。(0.0を設定)
ArrayInitialize(m_val1, 0.0);
ArrayInitialize(m_val2, 0.0);
ArrayInitialize(m_val3, 0.0);
ArrayInitialize(m_val4, 0.0);
m_handle1 = iMA(_Symbol, PERIOD_CURRENT, 5, 0, MODE_SMA, PRICE_CLOSE);
m_handle2 = iMA(_Symbol, PERIOD_CURRENT, 5, 0, MODE_EMA, PRICE_CLOSE);
m_handle3 = iMA(_Symbol, PERIOD_CURRENT, 5, 0, MODE_SMMA, PRICE_CLOSE);
m_handle4 = iMA(_Symbol, PERIOD_CURRENT, 5, 0, MODE_LWMA, PRICE_CLOSE);
return(INIT_SUCCEEDED);
}
void OnDeinit(const int reason)
{
if (m_handle1 != INVALID_HANDLE){
IndicatorRelease(m_handle1);
}
if (m_handle2 != INVALID_HANDLE){
IndicatorRelease(m_handle2);
}
if (m_handle3 != INVALID_HANDLE){
IndicatorRelease(m_handle3);
}
if (m_handle4 != INVALID_HANDLE){
IndicatorRelease(m_handle4);
}
}
//+------------------------------------------------------------------+
//| Custom indicator iteration function |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
const int prev_calculated,
const datetime &time[],
const double &open[],
const double &high[],
const double &low[],
const double &close[],
const long &tick_volume[],
const long &volume[],
const int &spread[])
{
m_bars_calculated1 = CreateBuffer(rates_total, prev_calculated, m_bars_calculated1, m_handle1, m_val1);
m_bars_calculated2 = CreateBuffer(rates_total, prev_calculated, m_bars_calculated2, m_handle2, m_val2);
m_bars_calculated3 = CreateBuffer(rates_total, prev_calculated, m_bars_calculated3, m_handle3, m_val3);
m_bars_calculated4 = CreateBuffer(rates_total, prev_calculated, m_bars_calculated4, m_handle4, m_val4);
return(rates_total);
}
int CreateBuffer(const int rates_total,
const int prev_calculated,
const int bars_calculated,
const int handle,
double &values[])
{
int result = 0;
int values_to_copy; // iMAから複製された値の数
int calculated = BarsCalculated(handle); // 指標で計算された値の数
if (calculated > 0) {
// 次のいずれかに該当する場合
// 初めてOnCalculated()が実行された(prev_calculated == 0)
// iMA指標の数が変わった(calculated != m_bars_calculated)
// 価格履歴で変動があった(rates_total > prev_calculated+1)
if(prev_calculated == 0 || calculated != bars_calculated || rates_total > prev_calculated+1) {
if (calculated > rates_total) {
values_to_copy = rates_total;
}
else {
values_to_copy = calculated;
}
}
else {
values_to_copy = rates_total - prev_calculated + 1;
}
FillArrayFromBuffer(values, 0, handle, values_to_copy);
result = calculated;
}
return(result);
}
bool FillArrayFromBuffer(double &values[],
const int iShift,
const int iHandle,
const int iCopyAmount)
{
bool bResult = false;
ResetLastError();
if (CopyBuffer(iHandle, 0, -0, iCopyAmount, values) < 0) {
PrintFormat("Failed to copy data from the iMA indicator, error code %d",GetLastError());
}
else {
bResult = true;
}
return(bResult);
}
まとめ
MQL5で使用できる平滑化の種類についてまとめてみました。
短期的に取引するのか、長期的に取引するのか、騙しをどれくらい許容するのかによって、適切な平滑化は異なってきます。
取引スタイルに応じて適切なものを選択しましょう。
また、平滑化の種類は移動平均(Moving Average)だけでなく、次のテクニカル指標でも指定することができます。
テクニカル指標名 | 英名 | MQL5組み込み関数 |
---|---|---|
アリゲーター | Alligator | iAlligator |
チャイキンオシレーター | Chaikin Oscillator | iChaikin |
エンベロープ | Envelopes | iEnvelopes |
勢力指数 | Force Index | iForce |
ゲーターオシレーター | Gator | iGator |
ストキャスティクス | Stochastic Oscillator | iStochastic |
色々とカスタマイズして使ってみましょう。