KI’s blog

中年男性によるFXとMQL5のメモ

KaiNew.mq5

先日FXのニュースサイトで気になる見出しがあり、そのリンク先をみたら面白い記事を見つけました。

www.home.saxo

海外のSAXOで英語ですがブラウザのアドオンで翻訳して読んでます。
このサイトで日銀の為替介入について書かれている部分があって、そこには下記のようにありました。


To gauge the risk of intervention, consider the following metrics:
・A 10 yen/USD move within one month.
・A 4% depreciation in the yen over two weeks.


 介入のリスクを評価するには、次の指標を考慮してください。
・1ヶ月以内に1ドル10円の動き。
・2週間で4%の円安。


1か月に10円は要人発言であったっけ?
自分は前日終値から当日高値の上昇率と、前回介入あとの最安値から当日高値の上昇率を計算してたけどしっくりきませんでしたが、この2つがシンプルでいいなと思ったのでMT5のインジケーターにしてみました。

KaiNew

ドル円の日足にセットして、サブウインドウに折れ線と点線を表示します。紫色は当日から過去1か月以内で一番大きな価格差を表示、緑色は当日から過去2週間以内で一番大きな上昇率を表示します。それを過去に向かってとりあえず1000日分計算しています。
それぞれの折れ線が同色の点線に近づくと介入の可能性が高そうだとなりますが、介入があった日をみると4%の方はほぼ超えているものの、10円の方は一度も超えていないです。

まぁでも介入の目安にはなるかなということで円安が進むたびに見てみると面白いかもしれないです。なお、特定の期間の価格差や比なので、円安進んでるのに価格差も上昇率も前と変わらないってのはよくあります。


ソースコードを下記に公開するので興味がある方はご自由にお使いください。
そんなに変化するものではないので、日足でのみ動作・15分に一度、15分足の更新と同じタイミングで処理するようにしてます。使いづらかったら書き換えてください。あと、1か月は20日間・2週間は10日間で換算しているので日数が違うようであれば変更してください。


プログラムの注意点として EventSetTimer() を OnInit() ではないところで呼び出してます。簡単な方法が思いつかなかったのでこのやり方にしてます。
EventSetTimer - イベント操作 - MQL5 リファレンス - MetaTrader 5 のためのアルゴリズムの/自動化されたトレーディング言語のリファレンス


それでは良い一日を!

//+------------------------------------------------------------------+
//|                                                       KaiNew.mq5 |
//|                                                   Copyright K.I. |
//|                              https://keita-isuzu.hatenablog.com/ |
//+------------------------------------------------------------------+
#property copyright  "K.I."
#property link       "https://keita-isuzu.hatenablog.com/"
#property version    "1.00"
#property description "ドル円の日足のサブチャートに価格差と上昇率を表示"

// 入力パラメーター
#property indicator_separate_window // サブウィンドウ表示
#property indicator_buffers 2
#property indicator_plots   2

// 指標バッファの描画パラメーター
#property indicator_label1 "1Month"
#property indicator_type1  DRAW_LINE
#property indicator_color1 clrPurple
#property indicator_style1 STYLE_SOLID
#property indicator_width1 1

#property indicator_label2 "2Weeks"
#property indicator_type2  DRAW_LINE
#property indicator_color2 clrGreen
#property indicator_style2 STYLE_SOLID
#property indicator_width2 1

// 指標バッファの水平線レベル
#property indicator_level1 4.0
#property indicator_level2 10.0
#property indicator_levelstyle STYLE_DOT
#property indicator_levelwidth 1

// 動的配列
double monthBuffer[];   // 1カ月以内の価格差
double weekBuffer[];    // 2週間の上昇率

// グローバル変数
bool mainSkipFlag=0; // 値が1のときメインの処理をスキップ
int firstTime=0;     // 初回のタイマー設定秒数

// マクロ代入
#define candlestickTotal 1000 // 処理するローソク足の数
#define setTime 900           // タイマー関数の設定秒数(900秒→15分)

// 変更できる値
input int candlestick1Month=20;     // 1か月分のローソク足の数
input int candlestick2Weeks=10;     // 2週間分のローソク足の数

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
{
   // チャートが日足以外なら終了(チャートに残るが動作しない)
   if(!(ChartPeriod()==PERIOD_D1)) {printf("日足で実行してください"); return(INIT_FAILED);} // INIT_FAILEDを返す

   // 配列と指標バッファを関連付け
   SetIndexBuffer(0,monthBuffer,INDICATOR_DATA);   // 関連付け
   ArraySetAsSeries(monthBuffer,true);             // 時系列に並び変え
   PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0.0);     // 空の値を0.0に設定

   SetIndexBuffer(1,weekBuffer,INDICATOR_DATA);    // 関連付け
   ArraySetAsSeries(weekBuffer,true);              // 時系列に並び変え
   PlotIndexSetDouble(1,PLOT_EMPTY_VALUE,0.0);     // 空の値を0.0に設定

   // サブウィンドウの最大値と最小値を設定する
   IndicatorSetDouble(INDICATOR_MAXIMUM,15);
   IndicatorSetDouble(INDICATOR_MINIMUM,0);

   // 水平線レベルの設定
   IndicatorSetString(INDICATOR_LEVELTEXT,0,"4% - 2Weeks Risk Line");   // チャートに表示するテキスト
   IndicatorSetInteger(INDICATOR_LEVELCOLOR,0,clrGreen);                // 色

   IndicatorSetString(INDICATOR_LEVELTEXT,1,"10yen - 1Month Risk Line");
   IndicatorSetInteger(INDICATOR_LEVELCOLOR,1,clrPurple);

   // タイマー設定(初回のみ計算値)
   datetime date=TimeLocal(); // PC内部の時間
   MqlDateTime pcTime;
   TimeToStruct(date, pcTime);
   firstTime = setTime-(((pcTime.min*60)+pcTime.sec)%setTime); // (900秒までの秒数 = 900秒 - 現在の分と秒数を900秒で割った余り)
   EventSetTimer(firstTime); // タイマー設定

   // 初期化完了。ゼロ値を返す
   return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
   EventKillTimer(); // タイマー削除
   
   ArrayFree(monthBuffer); // 指標バッファ解放
   ArrayFree(weekBuffer);
}
//+------------------------------------------------------------------+
//| OnTimer function                                                 |
//+------------------------------------------------------------------+
void OnTimer()
{
   if(firstTime == setTime) // タイマーの初回設定値が setTime と同じとき
   {
      mainSkipFlag=0;   // メインスキップフラグを0にする
      return;           // OnTimer()の終了
   }
   else
   {
      firstTime = setTime;    // 値を同じにして次からメインスキップフラグを0にする処理へ分岐させる
      EventKillTimer();       // 念のためタイマー削除
      EventSetTimer(setTime); // 本来の秒数で設定
   }
}
//+------------------------------------------------------------------+
//| 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[])      // スプレッド
{   
   // メインスキップフラグが1で、初回実行時以外はreturn(OnTimer()とフラグを使って15分に1回だけ処理をさせる)
   if(mainSkipFlag && (prev_calculated>0)) return(rates_total);

   // 初期化はOnCalculate()でする。価格が変なタイミングで更新されるとprev_calculatedが0になり変な値が入ることがあるため。
   if(prev_calculated==0)
   {
      ArrayInitialize(monthBuffer, 0.0);
      ArrayInitialize(weekBuffer, 0.0);
   }

   // 時系列に並び変え
   ArraySetAsSeries(high,true);
   ArraySetAsSeries(low,true);

   // 日足で1か月分の中から価格差の大きいものを検索(1か月=20本分)
   double monthPriceMin=0.0; // 1か月間の最安値
   for(int i=0; i<candlestickTotal-candlestick1Month-1; i++)      // 最新の足からチェック開始
   {
      monthPriceMin = low[ArrayMinimum(low, i, candlestick1Month)];   // iから古い方に向かって1か月以内の最安値を取得
      monthBuffer[i] = high[i]-monthPriceMin;                         // 価格差計算
   }

   // 日足で2週間分の中から上昇率の大きいものを検索(2週間=10本分)
   double weekPriceMin=0.0; // 2週間の最安値
   for(int i=0; i<candlestickTotal-candlestick2Weeks-1; i++)      // 最新の足からチェック開始
   {
      weekPriceMin = low[ArrayMinimum(low, i, candlestick2Weeks)];   // iから古い方に向かって2週間以内の最安値を取得
      weekBuffer[i] = ((high[i]-weekPriceMin)/weekPriceMin)*100;     // 上昇率計算。*100 はチャート画面で見えるようにするため
   }

   // メインスキップフラグを1にする
   mainSkipFlag=1;

   // 次の呼び出しのために prev_calculated の値を返す
   return(rates_total);
}
//+------------------------------------------------------------------+