2017年12月5日火曜日

[MT4インジケータ]通貨強弱その5・・・って(笑)


■通貨強弱・・・その5(笑)

Tiwtterのフォロアーさんで、週の頭からの変動率でトレードされている方から、週の頭をベースにした通貨強弱インジケータほしーなーとかリクエストをいただきましたので、、、軽くできるかなと思っていたら、思ったより苦労しました。

画像はLSMA+通貨強弱です。LSMAも少々手間がかかったので500円で販売しています。
ダウンロード
線形回帰をベースにした移動平均で、なかなか優秀で活用しています。

おっとちょっとCM挟んでしまいました。

日、週、月の頭を基準にした、価格に対する変動量を通貨毎に算出してまとめてグラフ化したものです。

チャートを出す際は、日足、週足、月足の履歴を見ます。
一度も出したことない時間足のチャートがあると、正しくインジケータが表示されませんのでご注意ください。
デフォルトの設定ですと、EURUSD、GBPUSD、AUDUSD、NZDUSD、USDCAD、USDCHF、USDJPYの日足、週足、月足のチャートを一度は表示する必要があります。
(一度表示して、適当に過去にさかのぼったら、そのチャートは閉じてもらって大丈夫です)

おまけで、分散の1σと2σのラインを表示しています。
日頭設定チャートだとなんの役にも立ってなさそうです(^^;
週頭の設定だとそれなりに参考になるラインとなるように思われます。全然検証してないですが、水曜日の段階で2σを超えている所は、利食いして、反対方向に動き始めたところで逆張り仕掛けても良さそうに思えます。

・・まぁポンドは暴れん坊ですが・・(汗

チャート時間補正しての表示などは対応していません。
素直にアメリカ夏冬時間GTM+2/+3の業者で使用されることをおすすめします。

なんか、このインジで有用なトレードアイデアあれば、ぜひ教えてください〜。情報お待ちしています。

ソースコードは記事の最後です。


[MT4インジケータ]通貨の強弱をUSDを基準に表示する。その1

[MT4インジケータ]通貨の強弱をUSDを基準に表示する。その2
[MT4インジケータ]通貨の強弱をUSDを基準に表示する。その3
[MT4インジケータ]通貨の強弱をUSDを基準にその4とFX-ONへのアップロード

「MT4でFXを勝ち抜く研究をするブログ」で公開している無料インジケータは、こちらの一覧から。
インジケータ一覧

Twitterもよろしくお願いします。
https://twitter.com/mt4program
Trading View プロフィール

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

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



//------------------------------------------------------------------
// 通貨強弱 インデックス比較インジケータ(N本前開始)
#property copyright "Copyright 2017,  Daisuke"
#property link      "http://mt4program.blogspot.jp/"
#property version   "1.00"
#property strict
#property indicator_separate_window
#property indicator_level1 100 

#include <Arrays/ArrayString.mqh>

//インデックス開始位置タイプ
enum ENUM_INDEX_TYPE
{
   // 前日終値
   IDX_TYPE_DAY,

   // 前週終値
   IDX_TYPE_WEEKEND,

   // 前月終値
   IDX_TYPE_MONTHEND,
};

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

input string sep00 = "";            //【通貨】
input string Currency1 = "EUR";     // 対象通貨1
input color Color1 = clrDodgerBlue; // 対象通貨1色

input string Currency2 = "GBP";     // 対象通貨2
input color Color2 = clrMagenta;    // 対象通貨2色

input string Currency3 = "AUD";     // 対象通貨3
input color Color3 = clrGreen ;     // 対象通貨3色

input string Currency4 = "NZD";     // 対象通貨4
input color Color4 = clrSilver;     // 対象通貨4色

input string Currency5 = "USD";     // 対象通貨5
input color Color5 = clrAqua;       // 対象通貨5色

input string Currency6 = "CAD";     // 対象通貨6
input color Color6 = clrPink;       // 対象通貨6色

input string Currency7 = "CHF";     // 対象通貨7
input color Color7 = clrPaleGreen;  // 対象通貨7色

input string Currency8 = "JPY";     // 対象通貨8
input color Color8 = clrRed;        // 対象通貨8色

input string sep10 = "";            //【計算設定】
input ENUM_INDEX_TYPE IndexType = IDX_TYPE_WEEKEND;   // インデックス開始位置タイプ
input int StdPeriod = 6;            // 標準偏差期間

input string sep20 = "";            //【その他】
input string CurrencyPrefix = "";   // 通貨ペア名の前に付く文字列
input string CurrencyPostfix = "";  // 通貨ペア名の後に付く文字列
input int LabelDistance = 3;        // 通貨名ラベル描画スペース

//バッファ
double m_buffer1[];
double m_buffer2[];
double m_buffer3[];
double m_buffer4[];
double m_buffer5[];
double m_buffer6[];
double m_buffer7[];
double m_buffer8[];

double m_buffer9[];
double m_buffer10[];
double m_buffer11[];
double m_buffer12[];

//通貨一覧
CArrayString m_currencies;

//通貨ペア一覧
CArrayString m_currencyPairs;

//USDインデックス
int m_usdIndex = -1;

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

//色配列
color m_colors[8];

// 基礎タイムフレーム
ENUM_TIMEFRAMES baseTimeFrame  = PERIOD_CURRENT;

//------------------------------------------------------------------
// 初期化
int OnInit()
{
   ClearObjects();

   IndicatorBuffers(12);

   int count = 0 ;
   SetIndexStyle(count, DRAW_LINE, STYLE_SOLID, 1, Color1);
   SetIndexBuffer(count++, m_buffer1);
   
   SetIndexStyle(count, DRAW_LINE, STYLE_SOLID, 1, Color2);
   SetIndexBuffer(count++, m_buffer2);

   SetIndexStyle(count, DRAW_LINE, STYLE_SOLID, 1, Color3);
   SetIndexBuffer(count++, m_buffer3);

   SetIndexStyle(count, DRAW_LINE, STYLE_SOLID, 1, Color4);
   SetIndexBuffer(count++, m_buffer4);

   SetIndexStyle(count, DRAW_LINE, STYLE_SOLID, 1, Color5);
   SetIndexBuffer(count++, m_buffer5);

   SetIndexStyle(count, DRAW_LINE, STYLE_SOLID, 1, Color6);
   SetIndexBuffer(count++, m_buffer6);

   SetIndexStyle(count, DRAW_LINE, STYLE_SOLID, 1, Color7);
   SetIndexBuffer(count++, m_buffer7);

   SetIndexStyle(count, DRAW_LINE, STYLE_SOLID, 1, Color8);
   SetIndexBuffer(count++, m_buffer8);
   
   //標準偏差
   SetIndexStyle(count, DRAW_LINE, STYLE_DOT, 1, clrWhiteSmoke);
   SetIndexBuffer(count++, m_buffer9);
   SetIndexStyle(count, DRAW_LINE, STYLE_DOT, 1, clrWhiteSmoke);
   SetIndexBuffer(count++, m_buffer10);
   SetIndexStyle(count, DRAW_LINE, STYLE_DOT, 1, clrWhiteSmoke);
   SetIndexBuffer(count++, m_buffer11);
   SetIndexStyle(count, DRAW_LINE, STYLE_DOT, 1, clrWhiteSmoke);
   SetIndexBuffer(count++, m_buffer12);
   
   m_currencies.Add(Currency1);
   m_currencies.Add(Currency2);
   m_currencies.Add(Currency3);
   m_currencies.Add(Currency4);
   m_currencies.Add(Currency5);
   m_currencies.Add(Currency6);
   m_currencies.Add(Currency7);
   m_currencies.Add(Currency8);
   
   m_colors[0] = Color1;
   m_colors[1] = Color2;
   m_colors[2] = Color3;
   m_colors[3] = Color4;
   m_colors[4] = Color5;
   m_colors[5] = Color6;
   m_colors[6] = Color7;
   m_colors[7] = Color8;

   m_usdIndex = -1;
   for( int i = 0; i < m_currencies.Total(); i++)
   {
      if(m_currencies.At(i) == "USD")
      {
         m_usdIndex = i;
         break;
      }
   }
   if( m_usdIndex < 0 )
   {
      //USDが見つからない場合、パラメータ異常
      return INIT_PARAMETERS_INCORRECT;
   }

   //USDに対する通貨ペアを生成する。   
   for( int i = 0; i < m_currencies.Total(); i++)
   {
      if( m_currencies.At(i) == "" )
      {
         m_currencyPairs.Add("");
         continue;
      }
      
      if( i < m_usdIndex )
      {
         m_currencyPairs.Add(CurrencyPrefix + m_currencies.At(i) + "USD" + CurrencyPostfix);
      }
      else if( i > m_usdIndex )
      {
         m_currencyPairs.Add(CurrencyPrefix + "USD" + m_currencies.At(i) + CurrencyPostfix);
      }
      else
      {
         m_currencyPairs.Add("USDUSD");
      }
      //線のラベルを設定する。
      SetIndexLabel(i, m_currencies.At(i));
   }
   
   ChartSetInteger(0, CHART_SHIFT, true);
   ChartSetDouble(0, CHART_SHIFT_SIZE, 12);
   
   if( IndexType == IDX_TYPE_DAY )
   {
      baseTimeFrame =PERIOD_D1;
   }
   else if( IndexType == IDX_TYPE_WEEKEND)
   {
      baseTimeFrame =PERIOD_W1;
   }
   else
   {
      baseTimeFrame =PERIOD_MN1;
   }

   return(INIT_SUCCEEDED);
}

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

//------------------------------------------------------------------
//計算イベント
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[])            //スプレット
{
   int total = m_currencyPairs.Total();
   //通貨の中心地をとるためにいったんの確保用配列を用意する。
   double currentValues[];
   ArrayResize(currentValues, total);

   // 特定の区切りをタイミングとする場合
   // 日にち区切りの場合、1時間足以下の必要あり。
   if( IndexType == IDX_TYPE_DAY && Period() > 60 ) return 0;
   // 週区切りの場合、日足以下の必要あり。
   if( IndexType == IDX_TYPE_WEEKEND && Period() > 60 * 24 ) return 0;
   
   //GMT補正とかは考えない・・。
   for( int i = rates_total - prev_calculated - 1; i >= 0; i-- )
   {
      if( i >= rates_total - 2) continue;
   
      //開始位置のインデックスを取得する。
      int baseIndex = GetBaseIndex(time[i], baseTimeFrame);
      if( i == baseIndex )
      {
         for( int j = 0; j < total; j++)
         {
            SetValue(j, EMPTY_VALUE, i);
         }
         CalcurateSTD(time[i], baseTimeFrame, i);
         continue;
      }
      
      // 標準偏差値をコピー
      m_buffer9[i] = m_buffer9[i + 1];
      m_buffer10[i] = m_buffer10[i + 1];
      m_buffer11[i] = m_buffer11[i + 1];
      m_buffer12[i] = m_buffer12[i + 1];
      
      SetValue(0, baseIndex, i);
      SetValue(1, i, i);
   
      double average = 0;
      for( int j = 0; j < total; j++)
      {
         string pair = m_currencyPairs.At(j);
         if(pair == "USDUSD" )
         {
            currentValues[j] = 100;
         }
         else
         {
            double baseValue = iOpen( pair, PERIOD_CURRENT, baseIndex);
            double targetValue = iClose( pair, PERIOD_CURRENT, i );

            if( j < m_usdIndex )
            {
               if( baseValue != 0 && baseValue != EMPTY_VALUE )
               {
                  currentValues[j] = targetValue / baseValue * 100;
               }
            }
            else
            {
               if( targetValue != 0 && targetValue != EMPTY_VALUE )
               {
                  currentValues[j] = baseValue / targetValue * 100;
               }
            }
         }
         average += currentValues[j];
      }
      average /= total;
      if( average > 0 )
      {
         //平均値をベースに再度値を計算しなおす(割合ベース)
         for( int j = 0; j < total; j++)
         {
            SetValue(j, currentValues[j] / average * 100.0, i);
         }
      }
   }    

   
   DrawCurrencyLabels();

   return rates_total - 1;
}

//------------------------------------------------------------------
//標準偏差を計算してバッファに設定する。
void CalcurateSTD(datetime currentTime, ENUM_TIMEFRAMES period, int shift)
{
   int total = m_currencyPairs.Total();
   double currentValues[];
   double calcValues[];
   ArrayResize(currentValues, total);
   ArrayResize(calcValues, total * StdPeriod);
   
   //標準偏差の算出
   int stdBaseIndex = iBarShift(NULL, baseTimeFrame, currentTime) + 1;
   for( int k = 0; k < StdPeriod; k++ )
   {
      double average = 0;

      for( int j = 0; j < total; j++)
      {
         string pair = m_currencyPairs.At(j);
         if(pair == "USDUSD" )
         {
            currentValues[j] = 100;
         }
         else
         {
            double baseValue = iClose(pair, baseTimeFrame, stdBaseIndex + k);
            double targetValue = iOpen(pair, baseTimeFrame, stdBaseIndex + k);

            if( j < m_usdIndex )
            {
               if( baseValue != 0 && baseValue != EMPTY_VALUE )
               {
                  currentValues[j] = targetValue / baseValue * 100;
               }
            }
            else
            {
               if( targetValue != 0 && targetValue != EMPTY_VALUE )
               {
                  currentValues[j] = baseValue / targetValue * 100;
               }
            }
         }
         average += currentValues[j];
      } 
      average /= total;
      if( average > 0 )
      {
         //平均値をベースに再度値を計算しなおす(割合ベース)
         for( int j = 0; j < total; j++)
         {
            calcValues[j + k * total] = currentValues[j] / average * 100.0;
         }
      }
   }
   double stdAverage = 0;
   double std = StdDev(calcValues, stdAverage, StdPeriod * total, 0);
   
   m_buffer9[shift] = stdAverage + 2 * std;
   m_buffer10[shift] = stdAverage +  std;
   m_buffer11[shift] = stdAverage -  std;
   m_buffer12[shift] = stdAverage - 2 * std;
}

//------------------------------------------------------------------
//標準偏差を求める。
// return 標準偏差
double StdDev(
   const double &values[],      //元となる配列
   double &avg,                 //平均値(出力)
   int count,                   //計算対象数
   int shift                    //シフト
)
{
   avg = 0 ;
   if( (count + shift) > ArraySize(values) ) return 0;

   avg = 0 ;
   double mu = 0 ;
   for( int i = shift; i < shift + count; i++ )
   {
      avg += values[i];
   }
   avg = avg / count;

   for( int i = shift; i < shift + count; i++ )
   {
      mu += MathPow(values[i] - avg, 2);
   }

   // 標準偏差
   return MathSqrt(mu / count);
}
//------------------------------------------------------------------
//基準位置のバーを取得する。
int GetBaseIndex(datetime currentTime, ENUM_TIMEFRAMES period)
{
   //上位バーのiShiftBarで値をとっても正しい値がなぜか取れない・・・。意味不明。   
   datetime baseTime = iTime(NULL, period, iBarShift(NULL, period, currentTime));
   
   // 週を挟むときだけ-1する・・・Alpariだけの問題??
   return iBarShift(NULL, PERIOD_CURRENT, baseTime) - (period == PERIOD_W1 ? 1 : 0);
}

//------------------------------------------------------------------
//通貨ラベルを描画する。
void DrawCurrencyLabels()
{
   //ソート行う。
   //とりあえずバブルソート
   int index[8];
   double rates[8];
   ArrayInitialize(index, 0);
   ArrayInitialize(rates, 0);

   int total = m_currencyPairs.Total();

   for( int i = 0 ; i < total; i++ )
   {
      index[i] = i;
      rates[i] = GetValue(i, 0);
   }
   
   //ソート行う。
   //とりあえずバブルソート
   for( int b = 1 ; b < total; b++ )
   {
      for( int j = 0; j < total - b; j++ )
      {
         if( rates[j] > rates[j + 1]  )
         {
            double work = rates[j + 1];
            rates[j + 1] = rates[j];
            rates[j] = work;
            
            int indexWork = index[j + 1];
            index[j + 1] = index[j];
            index[j] = indexWork;
         }
      }
   }

   //通貨ラベルを更新する。
   ClearObjects();
   int sub = WindowOnDropped();

   double max = ChartGetDouble(0, CHART_PRICE_MAX, sub);
   double min = ChartGetDouble(0, CHART_PRICE_MIN, sub);
   
   double distance = ( max - min ) / (total + 2);
   datetime writeTime = iTime(NULL, PERIOD_CURRENT, 0) + PeriodSeconds() * LabelDistance ;

   for( int j = 0; j < total; j++)
   {
      //描画対象通貨(インデックス)
      int currencyIndex = (int)index[j];
   
      //価格テキストを追加する。
      string objectName = StringFormat("%s_TXT_%d_%d", OBJECT_NAME, sub, j);

      if( ObjectCreate(0, objectName, OBJ_TEXT, WindowOnDropped(),writeTime , min + distance * (j + 1)) )
      {
         // 表示文字列
         ObjectSetString(0, objectName, OBJPROP_TEXT, m_currencies.At(currencyIndex));
         
         // アンカー
         ObjectSetInteger(0, objectName, OBJPROP_ANCHOR, ANCHOR_BOTTOM);
         
         ObjectSetInteger(0, objectName, OBJPROP_COLOR, m_colors[currencyIndex]);
      }
   }
}

//------------------------------------------------------------------
//値を設定する。
void SetValue(
   int i,            //配列番号0~7
   double value,     //値
   int shift)        //シフト
{
   switch(i)
   {
      case 0:
         m_buffer1[shift] = value;
         break;
      case 1:
         m_buffer2[shift] = value;
         break;
      case 2:
         m_buffer3[shift] = value;
         break;
      case 3:
         m_buffer4[shift] = value;
         break;
      case 4:
         m_buffer5[shift] = value;
         break;
      case 5:
         m_buffer6[shift] = value;
         break;
      case 6:
         m_buffer7[shift] = value;
         break;
      case 7:
         m_buffer8[shift] = value;
         break;
   }
}

//------------------------------------------------------------------
//値を取得する。
double GetValue(
   int i,            //配列番号0~7
   int shift)        //シフト
{
   switch(i)
   {
      case 0:
         return m_buffer1[shift];
      case 1:
         return m_buffer2[shift];
      case 2:
         return m_buffer3[shift];
      case 3:
         return m_buffer4[shift];
      case 4:
         return m_buffer5[shift];
      case 5:
         return m_buffer6[shift];
      case 6:
         return m_buffer7[shift];
      case 7:
         return m_buffer8[shift];
   }
   return EMPTY_VALUE;
}

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