【MQL4 : MT4】GUI で ストップ狩りを回避するライン を実装した EA を作る。① 【Dialog】

23/09/22追記
note購入者はDMして下されば続きが読めます！
https://note.com/iceseeds/n/nfdae2c5ac2ef

# はじめに
ここでは、GUIでストップ狩りを回避するラインを実装します。


前回までの記事を理解しているのが前提です。
[【MQL4 : MT4】GUI で 全決済、個別決済 を実装した EA を作る。](https://qiita.com/IceSeed/items/0afb15e62a1fd826388f)
作成手順としては、以下の通りです。
1. ComboBoxにライン作成Listを追加
2. 2本のライン作成処理
3. GUIを拡張（横スクロールできる予定）
4. ライン情報（ pips, 損益, RR )を表示
5. 仕掛けに対して、ラインで決済できる処理
6. 細かい修正etc...
今回は、1 と 2 を実装します。
既存のファイルは、ほとんど修正がありません。
また、今後も様々な機能を追加していく予定なので、
Errorなどを別ファイルに分けました。
**※ネーミングセンスはありません。なるだけ分かりやすくしているつもりです！** 
いろいろと初心者な為、至らない部分もありますが、宜しくお願いします。
フォルダ構造のアドバイスなどを頂けると助かります。
- Experts/
    - Sample/
        - Common/
          - CMD.mqh　　　　　←コマンドファイル。エラー、時間取得 ( new )
          - Common.mqh　　　←変数ファイル？ ( new )
        - Plugin/　　　　　　　　
          - ExitCurrency.mqh　　
          - LineOrder.mqh　　　←今回のメインファイルです。( new )
        - guiwindow.mq4
        - AppWindow.mqh
        - Event.mqh
---
## 実行結果
![Screenshot_3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542117/94e18353-6ed4-26ab-80e7-708d747f3763.png)
LineOrderを選択し、Pushをすると、2本のラインが表示されます。
## Commonフォルダ
### CMD.mqh
```CMD.mqh
#include <stderror.mqh>    // --- 1
#include <stdlib.mqh>
class CCMD
{
   public:
      string   GetTimes();
      void     Error( string str_place );
};
string CCMD::GetTimes()    //  --- 2
{
   MqlDateTime times ;
   TimeToStruct( TimeLocal(), times );
   
   return (string)times.year + (string)times.mon + (string)times.day + (string)times.hour + (string)times.min + (string)times.sec;
}
void CCMD::Error( string str_place )   // --- 3
{
   if( GetLastError() != ERR_NO_ERROR && ERR_OBJECT_ALREADY_EXISTS )
      Alert( "Place : " + str_place + "\nErrorCode : " + (string)GetLastError() + "\nDetails : " + ErrorDescription( GetLastError() ) );
}
```
### CMD.mqh の ソースコード詳細
#### 1. Include文
エラーメッセージを詳しく表示させるための標準ファイルです。
```CMD.mqh
#include <stderror.mqh>
#include <stdlib.mqh>
```
#### 2. GetTimes関数
現在時刻を取得するための関数です。
```CMD.mqh
string CCMD::GetTimes()
{
   MqlDateTime times ;
   TimeToStruct( TimeLocal(), times );
   return (string)times.year + (string)times.mon + (string)times.day + (string)times.hour + (string)times.min + (string)times.sec;
}
```
今回は、オブジェクトの名前に使用します。
戻り値の例「20203212213」
`MqlDateTime times ;`
datetime型で現在時刻を取得します。
`TimeToStruct( TimeLocal(), times );`
datetime型の値をMqlDateTime構造体変数に変換してます。
#### 2. Error関数
Errorを表示させる関数です。
```CMD.mqh
void CCMD::Error( string str_place )
{
   if( GetLastError() != ERR_NO_ERROR && ERR_OBJECT_ALREADY_EXISTS )
      Alert( "Place : " + str_place + "\nErrorCode : " + (string)GetLastError() + "\nDetails : " + ErrorDescription( GetLastError() ) );
}
```
引数で、エラー箇所を受け取ります。
`if( GetLastError() != ERR_NO_ERROR && ERR_OBJECT_ALREADY_EXISTS )`
不明なエラー　且つ　既に存在してるオブジェクト　なら
エラー場所、エラーコード、エラー内容　を表示します。

---
### Common.mqh
```Common.mqh
#include "../AppWindow.mqh"
#include "CMD.mqh"
#include "../Plugin/ExitCurrency.mqh"
#include "../Plugin/LineOrder.mqh"
CPanelDialog   AppWindow;
CCMD           CMD;
CExitCurrency  ExitCurrency;
CLineOrder     LineOrder;
```
### Common.mqh の ソースコード詳細
今後追加する際は、ここにinclude文を書きこみます。
このファイルは、ためしでやってみたので、
使い勝手が悪かったら、改造するかもです。
なにかいいアイデアがあれば教えてください。
## 2本のラインを！
### AppWindow.mqh
修正部分の周辺のみ記載します。
```AppWindow.mqh
~略~
bool CPanelDialog::CreateCombCreate()
{
   int widths = ClientAreaWidth() / 5;
   int x1 = 0;
   int y1 = ClientAreaHeight() - 20;
   int x2 = widths * 4;
   int y2 = ClientAreaHeight();
   
   if( !m_combCreate.Create( m_chart_id, m_name + "comboCreate", m_subwin, x1, y1, x2, y2 ) ) return false;
   m_combCreate.AddItem( "All Exit", 0 );
   m_combCreate.AddItem( "This Exit", 1 );
   m_combCreate.AddItem( "Line Order", 2 );           // --- 1
   
   if( !Add( m_combCreate ) ) return false;
   
   return true;
}
~略~
```
### AppWindo.mqh の ソースコード詳細
#### 1. AddItem
ラインを表示するItemを追加しました。
```AppWindow.mqh
m_combCreate.AddItem( "Line Order", 2 );
```
---
### Event.mqh
修正部分の周辺のみ記載します。
```Event.mqh
#include "Common/Common.mqh"
~略~
bool CEvent::combSelect( const int id, const long lparam, const double dparam, const string sparam )
{
   if( ( StringFind( sparam, "btnComb", 4 ) != -1 ) && id == CHARTEVENT_OBJECT_CLICK ) 
   {
      switch( (int)AppWindow.m_combCreate.Value() )
      {
         case 0: // to All Exit
            if( !ExitCurrency.exit() )
               CMD.Error( "combSelect : All Exit" );
            break;
         case 1: // to This Exit
            if( !ExitCurrency.exit( Symbol() ) )
               CMD.Error( "combSelect : This Exit" );
            break;
         case 2: // to Line Order
            if( !LineOrder.lineOrder( CMD.GetTimes() ) )    // --- 2
               CMD.Error( "LineOrder" );
            break;
         default:
            Alert( "not select" );
      }
   }
   
   return true;
}
~略~
```
### Event.mqh の ソースコード詳細
#### 2. combBoxでのswitch文
前回同様、LineOrderを2番に設定したので、その際にLineOrderを呼び出します。
引数には、水平ラインの名前が被らない様に、現在時刻を入れてます。
```Event.mqh
if( !LineOrder.lineOrder( CMD.GetTimes() ) )
   CMD.Error( "LineOrder" );
```
---
### LineOrder.mqh
今回のメインです。
このシリーズは長丁場になりそうなので、無駄なコードがあるかもしれません。
最後の修正で、綺麗にしますのでご了承ください。
```LineOrder.mqh
class CLineOrder
{
   public:
      bool  lineOrder( string str_name );
      bool  check();
   
   private:
      bool create( string str_name );
};
/* MEMO いらないんじゃない？　....いや使いそうかも??? */ 
bool CLineOrder::lineOrder( string str_name )
{
   if( !create( str_name ) )  return false;
   
   return true;
}
bool CLineOrder::create( string str_name )      // --- 3
{
   if( !ObjectCreate( str_name + "LineOrder0", OBJ_HLINE, 0, Time[0], Close[5] ) ) return false;
   
   if( !ObjectCreate( str_name + "LineOrder1", OBJ_HLINE, 0, Time[0], Close[10] ) ) return false;
   
   
   return true;
}
/* TODO ObjectFindで、特定の文字列が含まれていたら。。。
      全Objectを検索対象にする。
*/
bool CLineOrder::check()
{
   if( ObjectFind( ChartID(), "LineOrder0" ) )  return false;
   if( ObjectFind( ChartID(), "LineOrder1" ) )  return false;
      
   return true;
}
```
### LineOrder.mqh の ソースコード詳細
#### 3. ObjectCreate関数
ObjectCreate関数を使って、水平ラインを作成しています。
```AppWindow.mqh
if( !ObjectCreate( str_name + "LineOrder0", OBJ_HLINE, 0, Time[0], Close[5] ) ) return false;
if( !ObjectCreate( str_name + "LineOrder1", OBJ_HLINE, 0, Time[0], Close[10] ) ) return false;
```
**オブジェクトの名前が被らない且つLineOrderで作ったラインだよって印を付けるために、LineOrder0,1 と追加しました。**
`ObjectCreate( ラインの名前, オブジェクトの種類, ウィンド, 作成位置の時間( X軸 ), 作成位置の価格( Y軸 )`
水平ラインなので、作成位置の価格( Y軸 ) に適当な価格を入れてます。
## さいごに
今回は、1, 2. 2本のライン作成を実装しました。
次回は、3. GUIを拡張（横スクロールできる予定 を実装します。

YoutubeでLive配信しながら作ってます。
https://www.youtube.com/channel/UCcTw_iVgpLfrep9f94KxwLg?sub_confirmation=1 
チャンネル登録お願いします:relaxed:
Twitterでは毎日呟いています。
https://twitter.com/IceSeed_bz
フォローお願いします:relaxed:
お疲れ様。:eye::eye: