2016年3月2日水曜日

[MT4インジケータ]前方移動平均を利用して支持線・抵抗線を描画するプログラム

■前方移動平均を利用した支持線・抵抗線の描画

以前の記事で、前方移動平均と後方移動平均を利用すると、過去のデータにおいては、かなり正確なトレンド転換点を描画できることを示しました。

その時に作成した前方移動平均を利用した支持線・抵抗線の描画プログラムです。

https://mt4program.blogspot.jp/2016/01/mt4_29.html
https://mt4program.blogspot.jp/2016/02/blog-post.html

過去にトレンド転換があったラインが描画されます。トレンド転換があったということは、そのあたりに損を抱えているポジションが存在しやすいはずです。

そのことよりラインが集中している個所においては抵抗を受けやすく、空いている場所は抵抗なく価格が遷移しやすいという仮定ができそうです。

P.S.
ううう・・風邪引いてしまいました。今日はTwitterお休みです。

前方移動平均を利用した抵抗線・支持線を描画する
前方移動平均 抵抗線・支持線
前方移動平均 抵抗線・支持線 | fx-on.com

MT4開発日記で公開している無料インジケータは、こちらの一覧から。
インジケータ一覧

Twitterもよろしくお願いします。
https://twitter.com/mt4program

ブログランキングにご協力よろしくお願いします。m(._.)m
にほんブログ村 為替ブログ FX テクニカルトレード派へ
にほんブログ村

お約束ですが、本ブログは、投資に対する利益を約束する物ではありません。最終的には自己責任によるご判断よろしくお願いいたします。



//------------------------------------------------------------------
// 前方移動平均 水平線描つき
#property copyright "Copyright 2016,  Daisuke"
#property link      "http://mt4program.blogspot.jp/"
#property version   "1.10"
#property strict
#property indicator_chart_window

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

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

#property indicator_label1  "beforeMa"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrAqua
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1

#property indicator_label2  "beforeMa un fix"
#property indicator_type2   DRAW_LINE
#property indicator_color2  clrIndianRed
#property indicator_style2  STYLE_SOLID
#property indicator_width2  1

#property indicator_label3  "normal ma"
#property indicator_type3   DRAW_LINE
#property indicator_color3  clrYellow
#property indicator_style3  STYLE_SOLID
#property indicator_width3  1

input int MaPeriod = 41;                           //移動平均種別
input ENUM_MA_METHOD MaMethod = MODE_EMA;          //移動平均種別
input ENUM_APPLIED_PRICE MaPrice = PRICE_CLOSE;    //適用価格

input bool IsShowMaLine = true;  // 移動平均線を表示するかどうか

input int MaShift = 0;           // 表示シフト
input bool AutoShift = true;     // 進み量が0になるように自動シフトする場合true

input bool IsDrawHLine = true;   // 水平線ラインを描画するかどうか
input int DrawHLineCount = 20;   // 水平線ラインの最大本数(支持線・抵抗線それぞれ)
input color RegistColor = clrIndianRed;   // 支持線
input color SupportColor = clrAliceBlue;  // 抵抗線

//オブジェクト名
#define OBJECT_NAME "BEFORE_MA_HLINE"

//バッファー
double beforeMa[];
double maUnFix[];
double ma[];

// 未確定期間
int unFixPeriod = 0;

double alfa = 0.0;

// シフト量
int shiftCount = 0 ;

//------------------------------------------------------------------
//初期化
int OnInit()
{
   //インジケーターバッファを初期化する。
   SetIndexBuffer(0,beforeMa);
   SetIndexBuffer(1,maUnFix);
   SetIndexBuffer(2,ma);

   if( !IsShowMaLine )
   {
      SetIndexStyle(0, DRAW_NONE, EMPTY, EMPTY, clrNONE);
      SetIndexStyle(1, DRAW_NONE, EMPTY, EMPTY, clrNONE);
      SetIndexStyle(2, DRAW_NONE, EMPTY, EMPTY, clrNONE);
   }

   string short_name = "BMA";
   IndicatorShortName(short_name);
   
   alfa = 0.0 ;
   unFixPeriod = MaPeriod ;
   
   if( MaMethod == MODE_SMMA )
   {
      //SmoothMAは 1/n EMA
      alfa = 1 / (double)MaPeriod;
   }
   if( MaMethod == MODE_EMA )
   {
      alfa = 2 / (double)( MaPeriod + 1);
   }
   
   if( alfa > 0.0 )
   {
      unFixPeriod = (int)(MathLog(0.01) / MathLog(1 - alfa));
   }
   if( alfa > 1 || alfa < 0 ) return INIT_PARAMETERS_INCORRECT;
   if( unFixPeriod == 0 )  return INIT_PARAMETERS_INCORRECT;
   
   shiftCount = MaShift;
   // 自動シフト量計算
   if( AutoShift )
   {
      if( MaMethod == MODE_SMA )
      {
         shiftCount = (MaPeriod - 1) / 2 + MaShift;
      }
      else if( MaMethod == MODE_LWMA)
      {
         shiftCount = (MaPeriod - 1) / 3 + MaShift;
      }
      else if( MaMethod == MODE_EMA || MaMethod == MODE_SMMA )
      {
         shiftCount = (int)((2 / alfa - 1) / 2.88) + MaShift;
      }
   }
   
   SetIndexShift(0, shiftCount);
   SetIndexShift(1, shiftCount);

   return INIT_SUCCEEDED;
}

//------------------------------------------------------------------
//終了処理
void OnDeinit(const int reason)
{
   DeleteAllObject();
}

//------------------------------------------------------------------
//計算イベント
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[])            //スプレット
{
   for( int i = 0; i < rates_total - prev_calculated && !IsStopped(); i++ )
   {
      double result = 0 ;
      
      ma[i] = iMA(Symbol(), PERIOD_CURRENT, MaPeriod, 0, MaMethod, MaPrice, i);
      
      if( MaMethod == MODE_SMA )
      {
         double sum = 0;
         int count = 0 ;
         for( int j = 0; j < MaPeriod && (i - j) >= 0; j++  )
         {
            int index = i - j;
            sum += GetPrice(open[index], close[index], high[index], low[index], MaPrice);
            count ++ ;
         }
         if( count > 0 )
         {
            result = sum / count;
         }
      }
      else if( MaMethod == MODE_LWMA)
      {
         double sum = 0;
         int count = 0 ;
         for( int j = 0; j < MaPeriod && (i - j) >= 0; j++  )
         {
            int index = i - j;
            int weight = MaPeriod - j;
            sum += GetPrice(open[index], close[index], high[index], low[index], MaPrice) * weight;
            count += weight ;
         }
         if( count > 0 )
         {
            result = sum / count;
         }
      }
      else if( MaMethod == MODE_EMA || MaMethod == MODE_SMMA )
      {
         double price = GetPrice(open[i], close[i], high[i], low[i], MaPrice);
         
         // 最新値を起点にEMAを計算する。
         if( i == 0 )
         {
            result = iMA(Symbol(), PERIOD_CURRENT, unFixPeriod / 4, 0, MODE_SMA, MaPrice, i);
         }
         else if( i <= unFixPeriod )
         {
            // iがunFixPriod間は、maUnFixから値を取得する。
            result = alfa * price + ( 1 - alfa ) * maUnFix[ i - 1 ];
         }
         else
         {
            result = alfa * price + ( 1 - alfa ) * beforeMa[ i - 1 ];
         }

         beforeMa[i] = result;
         maUnFix[i] = i >= unFixPeriod ? EMPTY_VALUE : result;
      }
   }
   
      // 新しいバーが生成されたとき
   if( IsDrawHLine && rates_total - unFixPeriod - 1 != prev_calculated )
   {
      DeleteAllObject();
      int i = unFixPeriod + 1 - shiftCount;
      int registCount = 0 ;
      int supportCount = 0 ;
      int objectCount = 0 ;
      while( i < rates_total - shiftCount - 1)
      {
         // デッドクロス
         if( registCount < DrawHLineCount && beforeMa[i + shiftCount] > ma[i] && beforeMa[i + shiftCount - 1] < ma[i - 1] )
         {
            CreateHLineObject((ma[i] + ma[i - 1]) / 2, RegistColor, objectCount++);
            registCount++;
         }
         // ゴールデンクロス
         if( supportCount < DrawHLineCount && beforeMa[i + shiftCount] < ma[i] && beforeMa[i + shiftCount - 1] > ma[i - 1] )
         {
            CreateHLineObject((ma[i] + ma[i - 1]) / 2, SupportColor, objectCount++);
            supportCount++;
         }
         if( registCount >= DrawHLineCount && supportCount >= DrawHLineCount ) break ;
         i++; 
      }
   }
   
   //元となる値を計算する。unFix期間は計算し続ける。
   return(rates_total - unFixPeriod - 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;
}

//------------------------------------------------------------------
//オブジェクトを描画する
bool CreateHLineObject(
   double price,    // 表示終了時間
   color lineColor, // 色
   int index        // インデックス
)
{
   //オブジェクトを作成する。
   long chartId = ChartID();
   string name = OBJECT_NAME + IntegerToString(index);

   if( ObjectFind(chartId, name) >= 0 ) return true;
   
   if( !ObjectCreate(chartId, name, OBJ_HLINE, 0, 0, price) )
   {
      return false;
   }
   // 背景色を設定する。
   ObjectSetInteger(chartId, name, OBJPROP_COLOR, lineColor);
   ObjectSetInteger(chartId, name, OBJPROP_READONLY, true);
   return true;
}


//------------------------------------------------------------------
//オブジェクトを削除する。
void DeleteAllObject()
{
   long chartId = ChartID();

   int total = ObjectsTotal(chartId);
   //生成したオブジェクトを削除する。
   //0から削除するとインデックス位置がずれて
   //正しく削除できないため、後ろから削除するようにする。
   for( int i = total - 1; i >= 0 ; i--)
   {
      string name = ObjectName(chartId, i);
      
      // 先頭文字列がOBJECT_NAMEと一致する場合、削除する。
      if( StringFind(name, OBJECT_NAME) == 0 )
      {
         ObjectDelete(chartId, name);
      }
   }
}