線形回帰(チャネル)ラインの価格帯の取得方法

EA
スポンサーリンク

概要

MT4の線形回帰(チャネル)について、価格をプログラム(MQL4)で取得する場合どうしたらいいかについて記載しています。

基本的にObjectGetValueByTime()で取得するのですが、少し取得するにあたってお作法みたいな手順がありましたので、線形回帰やその他のライン系の価格帯が取得できない方は参考にして頂ければと思います。

ObjectGetValueByTime()で線形回帰の価格帯が取得できない?

まず、線形回帰の価格帯を取得する場合、ObjectGetValueByTime()で取得する事ができます。

「MT4でEA自作しちゃお~」さんのサイトを見てもObjectGetValueByTime()の解説に線形回帰が出てきているので取れそうです。が、ObjectGetValueByTime()を使って実際にソースコードを組んで動かしてみたんですが、0が返ってきて全く取れる気配がありませんでした。

あーだこーだ検索しているうちに、「Nisai FX」さんの記事で2度目のOnTickで価格帯を取得できたという内容を発見しました。

なので、線形回帰を描画するOnTickでは価格帯を取得せず、線形回帰を描画し終わった次のOnTickで取得してみると・・・

うまく価格を取得できました!!!
※OnTickではなくint startでも同様に取得できます

以下にサンプルソースを交えて解説します。

サンプルソースコード

サンプルのソースコードは単純に線形回帰を引くEAを作り、その価格帯をObjectGetValueByTime()で取得し操作履歴に出力しています。

画像下段の赤枠を見ると分かりますが、最初はObjectGetValueByTime()で取得すると価格が0になっている事がわかります。

//+------------------------------------------------------------------+
//|                                                         test.mq4 |
//|                        Copyright 2020, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2020, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property strict

datetime prevtime;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---
   
  }
  
// エントリー関数
void OnTick()
{
   string obj_name = "testobj";
   int    chart_id = 0;
   
   //新しい足ができた時に1度だけ線形回帰を再描画
   if(Time[0] != prevtime){
      prevtime = Time[0];
      Print("描画準備中(このメッセージが出た時は値が取得できない)");
      ObjectDelete(chart_id,obj_name);
      
      ObjectCreate(chart_id,obj_name,OBJ_REGRESSION,0,Time[40],0,Time[10],0);
       
      ObjectSetInteger(chart_id,obj_name,OBJPROP_COLOR,clrYellow);    // ラインの色設定
      ObjectSetInteger(chart_id,obj_name,OBJPROP_STYLE,STYLE_SOLID);  // ラインのスタイル設定
      ObjectSetInteger(chart_id,obj_name,OBJPROP_WIDTH,1);              // ラインの幅設定
      ObjectSetInteger(chart_id,obj_name,OBJPROP_BACK,false);           // オブジェクトの背景表示設定
      ObjectSetInteger(chart_id,obj_name,OBJPROP_SELECTABLE,true);     // オブジェクトの選択可否設定
      ObjectSetInteger(chart_id,obj_name,OBJPROP_SELECTED,true);       // オブジェクトの選択状態
      ObjectSetInteger(chart_id,obj_name,OBJPROP_HIDDEN,true);         // オブジェクトリスト表示設定
      ObjectSetInteger(chart_id,obj_name,OBJPROP_ZORDER,0);             // オブジェクトのチャートクリックイベント優先順位
      ObjectSetInteger(chart_id,obj_name,OBJPROP_RAY_RIGHT,true);      // ラインの延長線(右)
      
   }

   int windowNumber=ObjectFind(chart_id,obj_name);
   
   if(windowNumber<0){
      
   }else{
   
      //オブジェクトの値を取得する
      long obj_time = ObjectGetInteger(0,obj_name,OBJPROP_TIME,0);
      double Sh_T = ObjectGetValueByTime(0,obj_name,obj_time,0);
      
      Print("時間:",TimeToStr(obj_time), " 価格:",Sh_T);

   }
   
}

ソースコードの解説

線形回帰を引くサンプルソースの解説です。

まず線形回帰は以下の箇所で引いています。ローソク足を生成した時(一番最初)だけ描画し、次のローソク足ができるまでは線形回帰を再描画しないようにしています。

   //新しい足ができた時に1度だけ線形回帰を再描画
   if(Time[0] != prevtime){
      prevtime = Time[0];
      Print("描画準備中(このメッセージが出た時は値が取得できない)");
      ObjectDelete(chart_id,obj_name);
      
      ObjectCreate(chart_id,obj_name,OBJ_REGRESSION,0,Time[40],0,Time[10],0);
       
      ObjectSetInteger(chart_id,obj_name,OBJPROP_COLOR,clrYellow);    // ラインの色設定
      ObjectSetInteger(chart_id,obj_name,OBJPROP_STYLE,STYLE_SOLID);  // ラインのスタイル設定
      ObjectSetInteger(chart_id,obj_name,OBJPROP_WIDTH,1);              // ラインの幅設定
      ObjectSetInteger(chart_id,obj_name,OBJPROP_BACK,false);           // オブジェクトの背景表示設定
      ObjectSetInteger(chart_id,obj_name,OBJPROP_SELECTABLE,true);     // オブジェクトの選択可否設定
      ObjectSetInteger(chart_id,obj_name,OBJPROP_SELECTED,true);       // オブジェクトの選択状態
      ObjectSetInteger(chart_id,obj_name,OBJPROP_HIDDEN,true);         // オブジェクトリスト表示設定
      ObjectSetInteger(chart_id,obj_name,OBJPROP_ZORDER,0);             // オブジェクトのチャートクリックイベント優先順位
      ObjectSetInteger(chart_id,obj_name,OBJPROP_RAY_RIGHT,true);      // ラインの延長線(右)
      
   }

続いて線形回帰の価格帯を取得及び操作履歴に出力する箇所ですが、ObjectFind()を使い線形回帰が見つからない場合は操作履歴に出力しないようにしています。

   int windowNumber=ObjectFind(chart_id,obj_name);
   
   if(windowNumber<0){
      
   }else{
   
      //オブジェクトの値を取得する
      long obj_time = ObjectGetInteger(0,obj_name,OBJPROP_TIME,0);
      double Sh_T = ObjectGetValueByTime(0,obj_name,obj_time,0);
      
      Print("時間:",TimeToStr(obj_time), " 価格:",Sh_T);

   }

バックテスト時の注意点

バックテストで確認する際は、モデルを『始値のみ』にすると線形回帰の値は取れないので、『全ティック』または『コントロールポイント』で確認しましょう。

線形回帰の価格帯がとれる部分はここ

線形回帰の価格帯を取得及び操作履歴に表示の部分を以下のように書き換えて、線形回帰の価格帯がとれる部分を洗い出しました。

      //オブジェクトの値を取得する
      long obj_time = ObjectGetInteger(0,obj_name,OBJPROP_TIME,0);
      double Sh_T = ObjectGetValueByTime(0,obj_name,obj_time,0);
      double Sh_M = ObjectGetValueByTime(0,obj_name,obj_time,1);
      double Sh_B = ObjectGetValueByTime(0,obj_name,obj_time,2);
      
      Print("時間:",TimeToStr(obj_time), " 価格:",Sh_T);
      Print("時間:",TimeToStr(obj_time), " 価格:",Sh_M);
      Print("時間:",TimeToStr(obj_time), " 価格:",Sh_B);

      obj_time = ObjectGetInteger(0,obj_name,OBJPROP_TIME,1);
      Sh_T = ObjectGetValueByTime(0,obj_name,obj_time,0);
      Sh_M = ObjectGetValueByTime(0,obj_name,obj_time,1);
      Sh_B = ObjectGetValueByTime(0,obj_name,obj_time,2);
      
      Print("時間:",TimeToStr(obj_time), " 価格:",Sh_T);
      Print("時間:",TimeToStr(obj_time), " 価格:",Sh_M);
      Print("時間:",TimeToStr(obj_time), " 価格:",Sh_B);  

取れる箇所は、始点(2023.04.25 14:00)と終点(2023.04.25 21:00)の値です。

またミドルラインの値、上段の値、下段の値という感じで取れる事がわかります。

線形回帰の描画だけでは最新の値(現在時間の値)は取得できない

おまけ

線形回帰の最新の値(現在時間の値)を取りたい場合は、線形回帰上にトレンドラインを引けばOKです。

線形回帰の情報を元に取得してきます。こんな感じ。

      //オブジェクトの値を取得する
      long obj_time = ObjectGetInteger(0,obj_name,OBJPROP_TIME,0);
      double Sh_M = ObjectGetValueByTime(0,obj_name,obj_time,0);
      double Sh_T = ObjectGetValueByTime(0,obj_name,obj_time,1);
      double Sh_B = ObjectGetValueByTime(0,obj_name,obj_time,2);

      obj_time = ObjectGetInteger(0,obj_name,OBJPROP_TIME,1);
      double Sh2_M = ObjectGetValueByTime(0,obj_name,obj_time,0);
      double Sh2_T = ObjectGetValueByTime(0,obj_name,obj_time,1);
      double Sh2_B = ObjectGetValueByTime(0,obj_name,obj_time,2);


      //トレンドラインの描画
       obj_name = "Trendline_DUMY_M";
       chart_id = 0;
      
      ObjectDelete(chart_id,obj_name);
      ObjectCreate(chart_id,obj_name,OBJ_TREND,0,Time[200], Sh_M, Time[10], Sh2_M);    

      // トレンドラインのプロパティを設定する
      ObjectSetInteger(chart_id,obj_name,OBJPROP_COLOR,clrYellow);    // ラインの色設定
      ObjectSetInteger(chart_id,obj_name,OBJPROP_STYLE,STYLE_SOLID);  // ラインのスタイル設定
      ObjectSetInteger(chart_id,obj_name,OBJPROP_WIDTH,2);              // ラインの幅設定
      ObjectSetInteger(chart_id,obj_name,OBJPROP_BACK,false);           // オブジェクトの背景表示設定
      ObjectSetInteger(chart_id,obj_name,OBJPROP_SELECTABLE,true);     // オブジェクトの選択可否設定
      ObjectSetInteger(chart_id,obj_name,OBJPROP_SELECTED,true);       // オブジェクトの選択状態
      ObjectSetInteger(chart_id,obj_name,OBJPROP_HIDDEN,true);         // オブジェクトリスト表示設定
      ObjectSetInteger(chart_id,obj_name,OBJPROP_ZORDER,0);     // オブジェクトのチャートクリックイベント優先順位
      ObjectSetInteger(chart_id,obj_name,OBJPROP_RAY_RIGHT,true);      // ラインの延長線(右)

      //トレンドライン(上2)ポイントの描画
       obj_name = "Trendline_DUMY_U";
       chart_id = 0;
      
      ObjectDelete(chart_id,obj_name);
      ObjectCreate(chart_id,obj_name,OBJ_TREND,0,Time[200], Sh_T, Time[10], Sh2_T);    

      // トレンドラインのプロパティを設定する
      ObjectSetInteger(chart_id,obj_name,OBJPROP_COLOR,clrYellow);    // ラインの色設定
      ObjectSetInteger(chart_id,obj_name,OBJPROP_STYLE,STYLE_SOLID);  // ラインのスタイル設定
      ObjectSetInteger(chart_id,obj_name,OBJPROP_WIDTH,2);              // ラインの幅設定
      ObjectSetInteger(chart_id,obj_name,OBJPROP_BACK,false);           // オブジェクトの背景表示設定
      ObjectSetInteger(chart_id,obj_name,OBJPROP_SELECTABLE,true);     // オブジェクトの選択可否設定
      ObjectSetInteger(chart_id,obj_name,OBJPROP_SELECTED,true);       // オブジェクトの選択状態
      ObjectSetInteger(chart_id,obj_name,OBJPROP_HIDDEN,true);         // オブジェクトリスト表示設定
      ObjectSetInteger(chart_id,obj_name,OBJPROP_ZORDER,0);     // オブジェクトのチャートクリックイベント優先順位
      ObjectSetInteger(chart_id,obj_name,OBJPROP_RAY_RIGHT,true);      // ラインの延長線(右)


      //トレンドライン(下2)ポイントの描画
       obj_name = "Trendline_DUMY_B";
       chart_id = 0;
      
      ObjectDelete(chart_id,obj_name);
      ObjectCreate(chart_id,obj_name,OBJ_TREND,0,Time[200], Sh_B, Time[10], Sh2_B);    

      // トレンドラインのプロパティを設定する
      ObjectSetInteger(chart_id,obj_name,OBJPROP_COLOR,clrYellow);    // ラインの色設定
      ObjectSetInteger(chart_id,obj_name,OBJPROP_STYLE,STYLE_SOLID);  // ラインのスタイル設定
      ObjectSetInteger(chart_id,obj_name,OBJPROP_WIDTH,2);              // ラインの幅設定
      ObjectSetInteger(chart_id,obj_name,OBJPROP_BACK,false);           // オブジェクトの背景表示設定
      ObjectSetInteger(chart_id,obj_name,OBJPROP_SELECTABLE,true);     // オブジェクトの選択可否設定
      ObjectSetInteger(chart_id,obj_name,OBJPROP_SELECTED,true);       // オブジェクトの選択状態
      ObjectSetInteger(chart_id,obj_name,OBJPROP_HIDDEN,true);         // オブジェクトリスト表示設定
      ObjectSetInteger(chart_id,obj_name,OBJPROP_ZORDER,0);     // オブジェクトのチャートクリックイベント優先順位
      ObjectSetInteger(chart_id,obj_name,OBJPROP_RAY_RIGHT,true);      // ラインの延長線(右)

      obj_name = "Trendline_DUMY_U";    //線形回帰トレンドライン(上)
      double senkeikaiki_T = NormalizeDouble(ObjectGetValueByShift(obj_name, 1),5);
      double senkeikaiki_T2 = NormalizeDouble(ObjectGetValueByShift(obj_name, 2),5);
      
      obj_name = "Trendline_DUMY_M";    //線形回帰トレンドライン(真ん中)
      double senkeikaiki_M = NormalizeDouble(ObjectGetValueByShift(obj_name, 1),5);
      
      obj_name = "Trendline_DUMY_B";    //線形回帰トレンドライン(下)
      double senkeikaiki_B = NormalizeDouble(ObjectGetValueByShift(obj_name, 1),5);
      double senkeikaiki_B2 = NormalizeDouble(ObjectGetValueByShift(obj_name, 2),5);

//オブジェクトの値を取得する の箇所で線形回帰の値を取得し、それ以降でトレンドラインを3本描画しています。

さいごに

以上が、『線形回帰(チャネル)ラインの価格帯の取得方法』です。

MT5だとうまくとれるかもしれないですが、MT4の場合は描画を行ったOnTickではObjectGetValueByTime()を使って値を取れない事がわかりました。

ライン系で値が取得できない場合は、次のOnTickで取るという事をするとうまく取れるかもしれませんね。

※ MT4・EAが使えるFX会社のおすすめ

※ EAのサンプルソースを一覧表にまとめました


コメント