C
GUI
MQL4
MT4
Dialog
2
どのような問題がありますか?

投稿日

更新日

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

はじめに

ここでは、GUIでストップ狩りを回避するラインを実装します。
GitHubにソースを公開しました。細かい修正は、こちらをご覧下さい。
GitHub : KEG_Qiita_EA
GitHub : KEG_Qiita_EA 差分
前回までの記事を理解しているのが前提です。
【MQL4 : MT4】GUI で ストップ狩りを回避するライン を実装した EA を作る。②
作成手順としては、以下の通りです。

  1. ComboBoxにライン作成Listを追加
  2. 2本のライン作成処理
  3. GUIを拡張(横スクロールできる予定)
  4. ライン情報( pips, 損益, RR )を表示
  5. 仕掛けに対して、ラインで決済できる処理
  6. 細かい修正etc...
    今回は、5. 仕掛けに対して、ラインで決済できる処理 を実装します。
    ※ネーミングセンスはありません。なるだけ分かりやすくしているつもりです!
    いろいろと初心者な為、至らない部分もありますが、宜しくお願いします。
    フォルダ構造のアドバイスなどを頂けると助かります。
  • Experts/
    • Sample/
      • Common/
        • CMD.mqh     
        • Common.mqh   
      • Plugin/        
        • ExitCurrency.mqh  
        • LineOrder.mqh   ←今回のメインファイルです。
      • guiwindow.mq4
      • AppWindow.mqh
      • Event.mqh

実行結果

Screenshot_5.png
ラインを作り、Buyボタンを押すと、同じ場所に決済用のラインが作られます。
Screenshot_6.png
今回は、移動して確認します。
現在のプライスと比較して、条件があったら決済します。
Screenshot_8.png

仕掛けに対して、ラインで決済できる処理

LineOrder.mqh

LineOrder.mqh
#include "../Common/Common.mqh"
class CLineOrder
{
   public:
      bool  check();
      bool  GetLine();
      
      bool  create( string str_name, double d_param );
      bool  reCreate( string str_name, int i_type );
      
      bool  exitCheck();
      bool  exit( int i_ticket );
};
bool CLineOrder::check()      // --- 1
{
   if( ObjectFind( ChartID(), "LineOrder0" ) != -1 )
      b_check0 = true;
   else
      b_check0 = false;
   
   if( ObjectFind( ChartID(), "LineOrder1" ) != -1 )
      b_check1 = true;
   else
      b_check1 = false;
   
   return true;
}
~
中略
~
bool CLineOrder::reCreate( string str_name, int i_type ) // --- 2
{
   double d_line0 = ObjectGet( str_name, OBJPROP_PRICE1 );
   ObjectDelete( ChartID(), str_name );
      
   string str_type;
     
   if( i_type == 0 )
   {
      if( d_line0 > Close[0] )
         str_type = "LongProfit";
      else
         str_type = "LongLoss";
   }else{
      if( d_line0 < Close[0] )
         str_type = "SellProfit";
      else
         str_type = "SellLoss";   
   }
   
   if( OrderSelect( OrdersTotal() - 1, SELECT_BY_POS, MODE_TRADES ) )
   {
      string str_exName = "KEG_" + Symbol() + "_" + (string)OrderTicket() + "_" + str_type;
      if( !ObjectCreate( ChartID(), str_exName, OBJ_HLINE, 0, 0, d_line0 ) ) return false;
   }else{
      return false;
   }
   
   return true;
}
bool CLineOrder::exitCheck()    // --- 3
{
   string objGet[];
   
   if( ObjectsTotal() >= 1 )
   {
      for( int i = 0; i < ObjectsTotal(); i++ )
      {
         if( StringSplit( ObjectName( i ), '_', objGet ) != 0 && objGet[0] == "KEG" )
         {
            double objPrice = NormalizeDouble( ObjectGet( ObjectName( i ), OBJPROP_PRICE1 ), Digits() );
            
            if( ( objGet[3] == "LongLoss" && objPrice >= Close[ 0 ] ) || ( objGet[3] == "LongProfit" && objPrice <= Close[ 0 ] ) || 
                ( objGet[3] == "SellLoss" && objPrice <= Close[ 0 ] ) || ( objGet[3] == "SellProfit" && objPrice >= Close[ 0 ] ) )
            {
               if( !exit( (int)objGet[2] ) ) return false;
               ObjectsDeleteAll( ChartID(), objGet[0] + "_" + objGet[1] + "_" + objGet[2] ); 
            }
         }
      }
   }
   
   return true;
}
bool CLineOrder::exit( int i_ticket )     // --- 4
{
   for( int i = OrdersTotal() - 1; i >= 0; i-- )
   {
      if( !OrderSelect( i, SELECT_BY_POS, MODE_TRADES ) ) continue;
      if( OrderSymbol() != Symbol() ) continue;
      if( OrderTicket() != i_ticket ) continue;
      if( !OrderClose( OrderTicket(), OrderLots(), OrderClosePrice(), 0 ) ) return false;
   }
   Sleep( 500 );
   
   return true;
}

LineOrder.mqh の ソースコード詳細

1. check関数

bool CLineOrder::check()
{
   if( ObjectFind( ChartID(), "LineOrder0" ) != -1 )
      b_check0 = true;
   else
      b_check0 = false;
   
   if( ObjectFind( ChartID(), "LineOrder1" ) != -1 )
      b_check1 = true;
   else
      b_check1 = false;
   
   return true;
}

Pipsなどを取得するラインが存在するかのチェック関数です。
if( ObjectFind( ChartID(), "LineOrder0" ) != -1 )
ラインの名前は、LineOrder0 と固定しているので、名前で検索します。
戻り値は、見つかったら、チャートID
     見つからなかったら、負数 ( -1 )
b_check0 = true;
bool型で、ラインの有無を確認します。

2. reCreate関数

bool CLineOrder::reCreate( string str_name, int i_type )
{
   double d_line0 = ObjectGet( str_name, OBJPROP_PRICE1 );
   ObjectDelete( ChartID(), str_name );
   string str_type;
   if( i_type == 0 )
   {
      if( d_line0 > Close[0] )
         str_type = "LongProfit";
      else
         str_type = "LongLoss";
   }else{
      if( d_line0 < Close[0] )
         str_type = "SellProfit";
      else
         str_type = "SellLoss";   
   }
   if( OrderSelect( OrdersTotal() - 1, SELECT_BY_POS, MODE_TRADES ) )
   {
      string str_exName = "KEG_" + Symbol() + "_" + (string)OrderTicket() + "_" + str_type;
      if( !ObjectCreate( ChartID(), str_exName, OBJ_HLINE, 0, 0, d_line0 ) ) return false;
   }else{
      return false;
   }
   return true;
}

ラインの有無をチェックし、Buyボタンか、Sellボタンを押したら、
決済用のラインを作ります
if( i_type == 0 )
0 = Buy
且つ
if( d_line0 > Close[0] )
現在の価格よりも、LineOrder0 が 上にあったら、
LongProfitと入れときます。
if( OrderSelect( OrdersTotal() - 1, SELECT_BY_POS, MODE_TRADES ) )
OrderSelectで最新の注文の情報を取得します。
string str_exName = "KEG_" + Symbol() + "_" + (string)OrderTicket() + "_" + str_type;
決済ラインの名前を、KEG_USDJPY_59486548_LongProfitにします。
アンダーバーで、区切っていて、決済の判断に使います。
※KEG_という名前に意味はありません。
if( !ObjectCreate( ChartID(), str_exName, OBJ_HLINE, 0, 0, d_line0 ) ) return false;
先ほどの名前と、プライスで ラインを作ります。

3. exitCheck関数

bool CLineOrder::exitCheck()    // --- 3
{
   string objGet[];
   if( ObjectsTotal() >= 1 )
   {
      for( int i = 0; i < ObjectsTotal(); i++ )
      {
         if( StringSplit( ObjectName( i ), '_', objGet ) != 0 && objGet[0] == "KEG" )
         {
            double objPrice = NormalizeDouble( ObjectGet( ObjectName( i ), OBJPROP_PRICE1 ), Digits() );
            if( ( objGet[3] == "LongLoss" && objPrice >= Close[ 0 ] ) || ( objGet[3] == "LongProfit" && objPrice <= Close[ 0 ] ) || 
                ( objGet[3] == "SellLoss" && objPrice <= Close[ 0 ] ) || ( objGet[3] == "SellProfit" && objPrice >= Close[ 0 ] ) )
            {
               if( !exit( (int)objGet[2] ) ) return false;
               ObjectsDeleteAll( ChartID(), objGet[0] + "_" + objGet[1] + "_" + objGet[2] ); 
            }
         }
      }
   }
   return true;
}

いよいよ決済処理です。
全体的な流れとしては、

  1. オブジェクトを全検索
  2. オブジェクトの名前を、アンダーバーで分割
  3. KEGという名前があるなら、そのラインの価格を取得
  4. 例:買いのストップロスが現在の価格より上にいったら
  5. 決済処理の関数に、価格を渡す
  6. 決済が完了したら、ライン削除
    for( int i = 0; i < ObjectsTotal(); i++ )
    オブジェクトの数だけ回します。
    if( StringSplit( ObjectName( i ), '_', objGet ) != 0 && objGet[0] == "KEG" )
    StringSplitで、 '_'で分割し、objGetの配列に入れます。
    例:KEG_USDJPY_59486548_LongProfit
    objGet[0] = KEG;
    objGet[1] = USDJPY;    ←通貨ペア
    objGet[2] = 59486548;   ←チケットナンバー
    objGet[3] = LongProfit;  ←ラインのタイプ
    そして、objGet[0]に KEG が入っていたら、以下に進みます。
    double objPrice = NormalizeDouble( ObjectGet( ObjectName( i ), OBJPROP_PRICE1 ), Digits() );
    ObjectNameで、ラインの名前を返してくれるので、
    ObjectGetでラインの価格を取得してます。
    if( ( objGet[3] == "LongLoss" && objPrice >= Close[ 0 ] ) || ...
    objGet[3] が LongLoss 且つ ラインのプライスが、現在プライスよりも、大きかったら以下の決済処理に。
    if( !exit( (int)objGet[2] ) ) return false;
    exit関数にチケットナンバーを渡して、検索数を削減します。
    もし、決済に失敗したら、return false; で戻され、エラーが表示されます。
    ObjectsDeleteAll( ChartID(), objGet[0] + "_" + objGet[1] + "_" + objGet[2] );
    決済に成功したら、接頭詞で、オブジェクトを削除します。

4. exit関数

bool CLineOrder::exit( int i_ticket ) 
{
   for( int i = OrdersTotal() - 1; i >= 0; i-- )
   {
      if( !OrderSelect( i, SELECT_BY_POS, MODE_TRADES ) ) continue;
      if( OrderSymbol() != Symbol() ) continue;
      if( OrderTicket() != i_ticket ) continue;
      if( !OrderClose( OrderTicket(), OrderLots(), OrderClosePrice(), 0 ) ) return false;
   }
   Sleep( 500 );
   return true;
}

exitCheck関数から、チケットナンバーを受け取ったので、チケットナンバーが同じ注文を決済します。
if( OrderSymbol() != Symbol() ) continue;
第一の門
 通貨ペアが同じかどうか。
if( OrderTicket() != i_ticket ) continue;
第二の門
 Select中のチケットナンバーと決済するチケットナンバーが同じかどうか。
if( !OrderClose( OrderTicket(), OrderLots(), OrderClosePrice(), 0 ) ) return false;
ここまで通貨した注文は、決済するよ。。。
Sleep( 500 );
エラー防止のSleep 500msec

Event.mqh

Event.mqh
~
略
~
bool CEvent::Order( int i_type, double d_lots ) // --- 5
{
   LineOrder.check();
     
   if( OrderSend( Symbol(), i_type, d_lots, Close[0], 0, 0, 0, "GUISample", 999, 0, clrRed ) == -1 )
   {
      CMD.Error( "Order" );
   }else{
      Alert( "OrderSend Success!!\n Lots = " + (string)d_lots + "\n type = " + (string)i_type );
      
      if( b_check0 )
         LineOrder.reCreate( "LineOrder0", i_type );
      if( b_check1 )
         LineOrder.reCreate( "LineOrder1", i_type );
   }
   return true;
}

Event.mqh の ソースコード詳細

5. Order関数

bool CEvent::Order( int i_type, double d_lots )
{
   LineOrder.check();
     
   if( OrderSend( Symbol(), i_type, d_lots, Close[0], 0, 0, 0, "GUISample", 999, 0, clrRed ) == -1 )
   {
      CMD.Error( "Order" );
   }else{
      Alert( "OrderSend Success!!\n Lots = " + (string)d_lots + "\n type = " + (string)i_type );
      
      if( b_check0 )
         LineOrder.reCreate( "LineOrder0", i_type );
      if( b_check1 )
         LineOrder.reCreate( "LineOrder1", i_type );
   }
   return true;
}

前回までは、ただ注文を出すだけでしたが、ライン決済に対応させました。
LineOrder.check();
Buy,Sellボタンを押下したら、ラインが存在するのかをチェックします。
if( b_check0 )
Line0が表示されてるかをチェックします。
LineOrder.reCreate( "LineOrder0", i_type );
表示されていたら、ラインの名前と、オーダータイプを渡して、決済用のラインを作ってもらいます。

Common.mqh

Common.mqh
#include "../AppWindow.mqh"
#include "CMD.mqh"
CPanelDialog   AppWindow;
CCMD           CMD;
bool b_lineCreate0;
bool b_lineCreate1;
bool b_check0; // --- 6
bool b_check1;

Common.mqh の ソースコード詳細

6. ラインの有無チェック

bool b_check0;
bool b_check1;

ぶっちゃけ、これ無駄じゃないかって思ってます。
次回までに良い方法が思いつけば変えます。

guiwindow.mqh

guiwindow.mqh
~
略
~
void OnTimer()
{
   LineOrder.GetLine();
   LineOrder.exitCheck(); // --- 7
}

guiwindow.mqh の ソースコード詳細

7. OnTimer関数

void OnTimer()
{
   LineOrder.GetLine();
   LineOrder.exitCheck();
}

OnTimer関数で、Pips用のラインと決済用のラインを呼び出してチェックしてます。
このままでは、無駄に重くなるので、ラインが存在するときだけチェックするように変更する予定です。

さいごに

今回は、5. 仕掛けに対して、ラインで決済できる処理 を実装します
次回は、6. 細かい修正 を実装します。
GitHubにソースを公開しました。細かい修正は、こちらをご覧下さい。
2年振りぐらいなので、いろいろと覚えてなかった。。。
GitHub : KEG_Qiita_EA
GitHub : KEG_Qiita_EA 差分
メインの部分はできたので、次回はデザイン、コードの簡略化、整理などをします。
出来るだけ分かりやすく、簡略化したですね。
YoutubeでLive配信しながら作ってます。
https://www.youtube.com/channel/UCcTw_iVgpLfrep9f94KxwLg?sub_confirmation=1
チャンネル登録お願いします:relaxed:
Twitterでは毎日呟いています。
https://twitter.com/IceSeed_bz
フォローお願いします:relaxed:
お疲れ様。:eye::eye:

新規登録して、もっと便利にQiitaを使ってみよう

  1. ユーザーやタグをフォローできます
  2. 便利な情報をストックできます
  3. 記事の編集提案をすることができます
ログインすると使える機能について
IceSeed
何か始めようとして取りあえず作った。 youtube :【https://www.youtube.com/channel/UCcTw_iVgpLfrep9f94KxwLg?sub_confirmation=1】

コメント

この記事にコメントはありません。
あなたもコメントしてみませんか :)
新規登録
すでにアカウントを持っている方はログイン
2
どのような問題がありますか?
新規登録して、Qiitaをもっと便利に使ってみませんか

この機能を利用するにはログインする必要があります。ログインするとさらに下記の機能が使えます。

  1. ユーザーやタグのフォロー機能であなたにマッチした記事をお届け
  2. ストック機能で便利な情報を後から効率的に読み返せる
新規登録ログイン
ストックするカテゴリー