2015年12月5日土曜日

[MT4インジケータ]S/RオシレータをTEMAで平滑化してみる。

・S/Rオシレータ TEMA平滑化付きと平滑化なしの比較

相場は重力に縛られるのか?S/Rオシレータを作ってみた。
http://mt4program.blogspot.com/2015/10/sr_8.html

S/Rオシレータですが、私もちょくちょく参考にしています。ただClose値を計算値のベースにているため細かい値動きでラインが動いてしまいシグナルとして使うとだましが多くなります。そこでClose値をTEMAに置き換えてみました。平滑化効果が表れます。

画像でいくと、上がTEMAで平滑化したS/Rオシレータ、下がClose値ベースのS/Rオシレータです。単純なWSROと比較すると、レジストを表す赤の線とサポートを表す青の線が平滑化されているのがわかるかと思います。

EURUSD 1Hによるわかりやすい区間(2010/1~2014/12)だけ比較すると、こんな感じです。

・WSROによる単純売買



・TEMA付きWSROによる単純売買

TEMA平滑化したほうがよさそうですね。
S/Rオシレータの特徴としてトレンド時コテンパンにされますので、その点は注意です。コテンパンにされる回数がTEMAのほうが少し減った感じになっています。


ソースコードはこちらから

//------------------------------------------------------------------
// ウィドナー博士のサポートレジスタンス オシレーター Close値TEMA化
#property copyright "Copyright 2015,  Daisuke"
#property link      "http://mt4program.blogspot.jp/"
#property version   "1.00"
#property strict

#include <arrays/arraydouble.mqh>

#property indicator_separate_window
#property indicator_minimum    0
#property indicator_maximum    100

//バッファーを指定する。
#property indicator_buffers 6

//プロット数を指定する。
#property indicator_plots   2

//サポートオシレータ情報
#property indicator_label1  "Support"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrAqua
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1

//レジスタンスオシレータ
#property indicator_label2  "Resistance"
#property indicator_type2   DRAW_LINE
#property indicator_color2  clrIndianRed
#property indicator_style2  STYLE_SOLID
#property indicator_width2  1

#property indicator_type3   DRAW_NONE
#property indicator_type4   DRAW_NONE
#property indicator_type5   DRAW_NONE
#property indicator_type6   DRAW_NONE

input int Period = 6;//期間

input int HLPeriod = 9;//HL期間(奇数)

input double Alfa = 0.1;//指数係数

input ENUM_APPLIED_PRICE MaPrice = PRICE_CLOSE;//適用価格

// TEMA
double tema[];

// EMA
double ema1[];

// EMA EMA
double ema2[];

// EMA EMA EMA
double ema3[];

//インジケーター バッファ
double wsoBuffer[];
double wroBuffer[];

//S1-Sn
CArrayDouble supports;
//R1-Rn
CArrayDouble registances;

//------------------------------------------------------------------
//初期化
int OnInit()
{
   if( HLPeriod % 2 == 0 || HLPeriod < 5) return (INIT_PARAMETERS_INCORRECT);
   if( Period < 3 ) return (INIT_PARAMETERS_INCORRECT);

   //インジケーターバッファを初期化する。
   SetIndexBuffer(0,wsoBuffer);
   SetIndexBuffer(1,wroBuffer);
   SetIndexBuffer(2,tema);
   SetIndexBuffer(3,ema1);
   SetIndexBuffer(4,ema2);
   SetIndexBuffer(5,ema3);
   
 SetIndexDrawBegin(0, HLPeriod + 1);
 SetIndexDrawBegin(1, HLPeriod + 1);
 
 
 supports.Clear();
 supports.Resize(Period);
 registances.Clear();
 registances.Resize(Period);
 
 string short_name = "T_WSRO( " + IntegerToString(Period)+" , "+  IntegerToString(HLPeriod) + " )";
 IndicatorShortName(short_name);

 
   return(INIT_SUCCEEDED);
}


//------------------------------------------------------------------
//計算イベント
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[])            //スプレット
{
   // 最終計算時間
   static datetime lastCalculate = 0;
   
   //元となる値を計算する。
   for( int i = (rates_total - prev_calculated - 1); i>=0 ; i-- )
   {
      double price = GetPrice(open[i], close[i], high[i], low[i], MaPrice);
      if( i == (rates_total - 1) )
      {
         ema1[i] = price;
         ema2[i] = price;
         ema3[i] = price;
         tema[i] = price;
      }
   
      if( i >=  rates_total - Period - 2 )
      {
         wsoBuffer[i] = 0 ;
         wroBuffer[i] = 0 ;
         continue;
      }
      ema1[i] = Alfa * price + ( 1 - Alfa ) * ema1[i + 1];
      ema2[i] = Alfa * ema1[i] + ( 1 - Alfa ) * ema2[i + 1];
      ema3[i] = Alfa * ema2[i] + ( 1 - Alfa ) * ema3[i + 1];
      tema[i] = ema1[i] * 3 - ema2[i] * 3 + ema3[i];
      
      // 同一時間足の値は再計算不要
      if( lastCalculate != time[i] )
      {
         lastCalculate = time[i];
         int centerIndex =  i + 1 + (HLPeriod - 1) / 2;
   
         //サポート
         //if Low( four days back ) = Min(lows of previous nine days) then SL=Low(four days back)
         if( iLowest(NULL, PERIOD_CURRENT, MODE_LOW, HLPeriod, i + 1) == centerIndex ) 
         {
            // 新しいサポートが構築された場合、Period数保持する。
            if( supports.Total() >= Period )
            {
               supports.Delete(supports.Total() - 1);
            }
            supports.Insert(iLow(NULL, PERIOD_CURRENT, centerIndex), 0);
         }
         
         //レジスタンス
         //if High( four days back ) = Max(high of previous nine days) then RL=High(four days back)
         if( iHighest(NULL, PERIOD_CURRENT, MODE_HIGH, HLPeriod, i + 1) == centerIndex ) 
         {
            // 新しいレジスタンスが構築された場合、Period数保持する。
            if( registances.Total() >= Period )
            {
               registances.Delete(registances.Total() - 1);
            }
            registances.Insert(iHigh(NULL, PERIOD_CURRENT, centerIndex), 0);
         }
      }

      //つまりHLPeriodの期間内の中央値-1が高値・安値だった場合サポート・レジストラインとして登録する。
      //ここで単純に価格で比較すると、最新の値が行ったり来たりすると
      //過去のサポート・レジスタンスが次々更新される症状が発生してしまう。
      
      double closeDiv = tema[i];
      
      //wsoの計算 1 - ((int)S1/C + (int)S2/C +(int)S3/C +(int)S4/C +(int)S5/C +(int)S6/C) / 6
      if( closeDiv!= 0 && supports.Total() == Period )
      {
         double wso = 0 ;
         for( int j = 0 ; j < supports.Total(); j++ )
         {
            wso += (int) (supports.At(j) / closeDiv);
         }
         wsoBuffer[i] = (1 - wso / supports.Total()) * 100;
      }
      else
      {
         wsoBuffer[i] = 0;
      }
      
      if( closeDiv!= 0 && registances.Total() == Period )
      {
         //wroの計算 1 - ((int)R1/C + (int)R2/C +(int)R3/C +(int)R4/C +(int)R5/C +(int)R6/C) / 6
         double wro = 0 ;
         for( int j = 0 ; j < registances.Total(); j++ )
         {
            wro += (int) ( registances.At(j) / closeDiv);
         }
         wroBuffer[i] = (1 - wro / registances.Total()) * 100;
      }
      else
      {
         wroBuffer[i] = 0;
      }
   }

   return(rates_total - 1);
}

//------------------------------------------------------------------
// 価格を計算する。
// return 対象価格
double GetPrice(
   double open,   // オープン値
   double close,  // クローズ値
   double high,   // 高値
   double low,    // 安値
   ENUM_APPLIED_PRICE maPrice    //取得価格
   )
{
   double price = 0;

   switch( maPrice )
   {
      case PRICE_CLOSE:
         price = close;
         break;
      case PRICE_OPEN:
         price = open;
         break;
      case PRICE_HIGH:
         price = high;
         break;
      case PRICE_LOW:
         price = low;
         break;
      case PRICE_MEDIAN:
         price = (high + low) / 2;
         break;
      case PRICE_TYPICAL:
         price = (high + low + close) / 3;
         break;
      case PRICE_WEIGHTED:
         price = (high + low + close + close) / 4;
         break;
   }
   return price;
}