English Русский 中文 Español Deutsch Português
DLLを経由したメタトレーダーターミナルの管理

DLLを経由したメタトレーダーターミナルの管理

MetaTrader 4 | 16 10月 2015, 15:05
3 715 0
Sofiia Butenko
Sofiia Butenko

タスクの定義

4つ以上の通知用アドレスを含むクウォーツIDがあります。SendNotification の関数はオプションの通知タブでIDをセットするだけで使えます。MQLを使えば一度に4つまで設定したIDへプッシュメール通知を送ることができます。これを使えるようにしましょう。

設定には2つの方法があります。ターミナルの設定を変えたり標準の関数を利用したりすることでプッシュメール通知機能を開発することができます。最初の方法はとても時間がかかり汎用性を欠いています。したがって2番目の方法を選択しましょう。ターミナルの設定はまた、色々な方法で変えることができます。私の経験上、ユーザーインターフェイスを経由するかプロセスメモリを置き換えるかして設定しています。ウィンドウがフラッシュすることが避けられるのでメモリの働きは良く見えます。しかし、全体のターミナルの機能が僅かなミスで中断されてしまします。UIを経由して稼働している時にウィンドウやボタンが消えてしまう最悪の事態が起こり得ます。

本稿で、補助DLLライブラリを使ったユーザーインターフェイス経由のターミナルを扱いましょう。特に、設定の変更を見ていきます。ターミナルについては通常のやり方でやっていきます。ターミナルについては通常のやり方でやっていきます。それはウィンドウズとコンポーネントを使うということです。ターミナルプロセスの中断はありません。この方法は他の問題を解決することにも使えます。


1. DLLを作る

ここでは主にWinAPIについて見ていきます。どのようにしてダイナミックなライブラリがDelphiで開発できるか手短に試してみましょう。

library Set_Push;

uses
  Windows,
  messages,
  Commctrl,
  System.SysUtils;

var
   windows_name:string;
   class_name:string;
   Hnd:hwnd;


{$R *.res}
{$Warnings off}
{$hints on}

function FindFunc(h:hwnd; L:LPARAM): BOOL; stdcall;
begin
  ...
end;

function FindFuncOK(h:hwnd; L:LPARAM): BOOL; stdcall;
begin
  ...
end;

function Find_Tab(AccountNumber:integer):Hwnd;
begin
  ...
end;


function Set_Check(AccountNumber:integer):boolean; export; stdcall;
var
  HndButton, HndP:HWnd;
  i:integer;
  WChars:array[0..255] of WideChar;
begin
   ...
end;

function Set_MetaQuotesID(AccountNumber:integer; Str_Set:string):boolean; export; stdcall;
begin
  ...
end;

//--------------------------------------------------------------------------/
Exports Set_Check, Set_MetaQuotesID;

begin
end.

ご覧の通り、Set_CheckとSet_MetaQuotesIDがエクスポートされています。FinfFuncは必要なウィンドウ(以下に記述)を探します。Find_Tabは必要なタブを探します。ウィンドウズとメッセージ、コマンドコントロールライブラリはWinAPIを利用することで使えるようになります。


1.1. アプリケーションツール

このタスクを解決する原則はDelphi XE4環境におけるWinAPIを利用することです。WinAPI文法とほとんど同じなので、C++言語も使われます。コンポーネントのネームとクラスの検索は、Visual Studioのデリバリーに含まれるSpy++のユーティリティーの利用か、以下の一覧表によって機能します。


1.2. メタトレーダーウィンドウをの検索

どんなプログラムウィンドウもそのタイトルで探すことができます(図1参照)。

図1. ウィンドウタイトル

図1. ウィンドウタイトル

メタトレーダーウィンドウのタイトルは口座番号を含んでおり、タイトル自体はセレクトされたシンボルや時間軸に基づき変えられています。したがって検索は口座番号のみでなされます。. 後の方でオプションウィンドウについても見ていきます。それは書き換えできないタイトルを持っています。

最初のケースにおいて、全ての利用可能なウィンドウを列挙するEnumWindowsの関数を利用しましょう。列挙されたウィンドウを処理する関数はEnumWindossのパラメーターとしてパスされます。それはFindFunc関数です。

function FindFunc(h:hwnd; L:LPARAM): BOOL; stdcall;
var buff: ARRAY [0..255] OF WideChar;
begin
   result:=true;
   Hnd := 0;
   GetWindowText(h, buff, sizeof(buff));
   if((windows_name='') or (pos(windows_name, StrPas(buff))> 0)) then begin
      GetClassName(h, buff, sizeof(buff));
      if ((class_name='') or (pos(class_name, StrPas(buff))> 0)) then begin
         Hnd := h;
         result:=false;
      end;
   end;
end;

この関数をもっと詳しくみていきましょう。関数のヘッダーは、関数と変数名をのぞいて変えらていません。新しいウィンドウが検知されると、EnumWindows関数が指定の関数を呼び出しそれをウィンドウハンドルに渡します。もし指定の関数がtrueならば、列挙する作業は続きます。そうでなければ、作業は完了します。

受け取ったハンドルを回路にコピーてウィンドウタイトル(GetWindowText)とクラスネーム(GetClassName)を調べます。. 次にウィンドウ抱いとるとクラスを必要としているもの比較します。. もし適合したら、ハンドル(これが最も重要)を記憶しfalseを返して列挙を終了します。

ここで、EnumWindows関数の呼び出しについてみていきます。

windows_name:=IntToStr(AccountNumber);
class_name:='MetaTrader';
EnumWindows(@FindFunc, 0);

必要とするクラスと部分的なウィンドウタイトルの値を割り当てます。. すべての利用可能なウィンドウを列挙する関数を呼び出します。その結果、Hnd グロバール変数で主なウィンドウタイトルを受け取ります。

まだ見つかっていないウィンドウズを探す関数をみていきます。ターミナルの設定を変える必要があるので、適切なオプションメニューを選択し新しいオプションウィンドウをみていかなければなりません。ウィンドウを探す別の方法があります。

hnd:=FindWindow(nil, 'Options');

クラスネームとウィンドウタイトルは関数のパラメーターとして扱われます。返された値は必要なハンドルか見つからなければ0になります。前のケースでは、関数は一連の出現の代わりに正確に適合する名前を探します。


1.3. メニューの稼働

全ての他のコンポーネントと同様に、メニューの稼働は親ハンドル(特定のウィンドウ)が見つかるとスタートします。対応するメニューアイテムとサブアイテムをを探しセレクションを機能させましょう。

注釈: ターミナルメニューアイテムはチャートウィンドウが展開されているかいないかによって変わります(図2参照)。アイテムの列挙は0からスタートします。アイテムの列挙は0からスタートします。

図2メニューアイテムの変更/p>

図2メニューアイテムの変更

メニューアイテムが変更さっると、ツールアイテムのインデックス番号も変更されます。したがって、メニューハンドルがパスされるGetMenuItemCount(Hnd:Hmenu)関数を利用するすべてのポイントを考慮すべきです。

以下の例をみていきましょう。:

function Find_Tab(AccountNumber:integer; Language:integer):Hwnd;
var
  HndMen :HMenu;
  idMen:integer;
  ...
begin
   ...
   //_____working in the menu________
   HndMen:=GetMenu(Hnd);
   if (GetMenuItemCount(HndMen)=7) then
    HndMen:=GetSubMenu(HndMen,4)
 else
    HndMen:=GetSubMenu(HndMen,5);
   idMen:=GetMenuItemID(HndMen,6);
   if idMen<>0 then begin
      PostMessage(Hnd,WM_COMMAND,idMen,0);
      ...

この例では、メインメニューのハンドルをその親ハンドルを経由して探します。次に適切なサブメニューをメニューハンドルで探します。サブメニューインデックス番号はGetSubMenu関数の2番目のパラメーターとして使われます。そして、適切なサブメニューアイテムを探します。選別を機能させるため、適切なメッセージを送る必要があります。メーセージを送った後、オプションウィンドウ待たねばなりません。

for i := 0 to 10000 do 
   hnd:=FindWindow(nil, 'Options');

永久ループを設定することは推奨しません。どんなにプログラムを素早く機能することができてもウィンドウを閉じるとターミナルクラッシュの原因になるからです。


1.4. コンポーネントの検索

オプションウィンドウを得て、次はコンポーネントまたは(WinAPIを使って)子ウィンドウを宣言する必要がります。しかし最初に、それらはハンドルを使って探すべきでしょう。「子ウィンドウ」という言葉は、ウィンドウを探す同じやり方で探すことからそう呼ばれています。

windows_name:='ОК';
class_name:='Button';
EnumChildWindows(HndParent, @FindFunc, 0);

又は

Hnd:=FindWindowEx(HndParent, 0, 'Button', 'OK');

結果、コンポーネントを検索する主な例を得ました。このステージでは、変更した変数名や親ハンドルの追加パスなどの複雑な物事には出会いません。通常、困難なことが現れるのは、検索が行なわれることでコンポーネントの特性を考慮しコンポーネントタイトルやクラスを知る必要があるかどうかの場合です。. そのようなケースでは、Spy++ユーティリティーが助けになります。全ての値をディスプレイすることをフォローして全ての親ウィンドウコンポーネントを列挙することと同じです。これを達成するために、パス関数(FindFunc)を少し変更しなければいけません。すべてのケースで返された値をtrueにセットし、ウィンドウネームとそれたのクラス(例えばファイルに書き込むなどして)保存します。

コンポーネント検索の特徴の一つをみていきましょう。: OKはシステムボタンです。これはボタンテキストは英語バージョンのウィンドウズOSではラテン語で書かれていることを意味します。ロシア語バージョンはキリル文字で書かれています。そのため、この解決策は普遍的なのです。

検索はネームの長さは(少なくともラテン文字とキリル文字が使われる言語では)二つの文字からなっています。これはライブラリをより多様にしてくれます。このコードの検索関数は以下です。:

function FindFuncOK(h:hwnd; L:LPARAM): BOOL; stdcall;
var buff: ARRAY [0..255] OF WideChar;
begin
   result:=true;
   Hnd := 0;
   GetClassName(h, buff, sizeof(buff));
   if (pos('Button', StrPas(buff))> 0) then begin
      GetWindowText(h, buff, sizeof(buff));
      if(Length(StrPas(buff))=2) then  begin
         Hnd := h;
         result:=false;
      end;
   end;
end;

OKボタンの検索は以下の方法です。:

EnumChildWindows(HndParent, @FindFuncOK, 0);


1.5. コンポーネントの稼働

全てのアクションの出力結果として以下のウィンドウを受け取るでしょう。(図3):

図3オプションウィンドウ

図3オプションウィンドウ

タブコントロール

ウィンドウはマルチタブを含んでおり、要求されたものが選ばれているか知ることができません。タブの設定によったコンポーネントはタブコントロールです。このケースでは、そのクラスを示すSysTabControl32です。そのハンドルを探しましょう。オプションウィンドウは親ウィンドウとして使われています。:

Hnd:=FindWindowEx(Hnd, 0, 'SysTabControl32', nil);

次にタブ変更メッセージをこのコンポーネントに送ります。:

SendMessage(Hnd, TCM_SETCURFOCUS, 5, 0);

上の例では、5は必要なタブの索引番号です(通知)。ここで必要なタブを探しましょう。:

Hnd:=GetParent(Hnd);
Hnd:=FindWindowEx(Hnd, 0, '#32770', 'Notifications');

オプションウィンドウはアクティブタブにとって親として扱われます。TabControlハンドルをもっているので、その親ハンドル(ウィンドウ)をもつことができます。その後、要求されたタブの検索が行なわれます。ここではタブのクラスは#32770です。

チェックボックス

オプションウィンドウは「Enable Push Notifications」を持ちます。もちろん、ユーザーが全て正確に設定できるとは思えません。有効化/無効化によるコンポーネントはボタンクラスを持ち、そのコンポーネントのタイプのため特別にデザインされたメーッセージがあります。

最初に、コンポーネントを検索しましょう。通知タブは親として振る舞います。コンポーネントは見つかったら、通知が許可されるかどうか(オプションがチェクされたかどうか)チェックします。チェックされていなければチェックします。全てのオブジェクトとのアクションはメッセージを送ることによって行なわれます。

Hnd:=FindWindowEx(Hnd, 0, 'Button', 'Enable Push Notifications');
if(Hnd<>0) then begin
   if (SendMessage(Hnd,BM_GETCHECK,0,0)<>BST_CHECKED) then
      SendMessage(Hnd,BM_SETCHECK,BST_CHECKED,0);
         ...

エディット

このコンポーネントはメタクウォーツIDのアドレスを入力するためのフィールドです。親は通知タブで、クラスはエディットです。オペレーション規則は同じです。コンポーネントを探しメッセージを送ります。

Hnd:=FindWindowEx(Hnd, 0, 'Edit', nil);
if (Hnd<>0) then begin
   SendMessage(Hnd, WM_Settext,0,Integer(Str_Set));

where Str_Set is a list of string addresses.

ボタン

ここでオプションウィンドウのボタンにおいて、標準のOKボタンをみていきます。このコンポーネントはどのタブにも属していません。つまりその親はウィンドウそれ自体だということです。全ての必要なアクションを終えた後、ボタンを押したメッセージを送ります。

EnumChildWindows(HndParent, @FindFuncOK, 0);
I:=GetDlgCtrlID(HndButton);
if I<>0 then begin
   SendMessage(GetParent(HndButton),WM_Command,MakeWParam(I,BN_CLICKED),HndButton);
   ...


2. MQL4でスクリプトを作成する

ここでの作業の結果は、プッシュメール通知を送り呼び出したリストからメタクウォーツIDを入力させる2つの外部関数、Set_CheckとSet_MetaQuotesIDを使ったDLLです。. 全てのターミナルウィンドウとコンポーネントは関数で見つけることができます。それらはtrueを返します。どのようにスクリプトに使われているかみてみましょう。

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

#import "Set_Push.dll"
bool Set_Check(int);
bool Set_MetaQuotesID(int,string);
#import

extern string text="test";
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OnStart()
  {
   if(StringLen(text)<1)
     {
      Alert("エラー:送れたテキストはありません"); return;
     }
   if(!Set_Check(AccountNumber()))
     {
      Alert("エラー: プッシュを送れませんでした。ターミナル言語をチェックしてください"); return;
     }
   string str_id="1C2F1442,2C2F1442,3C2F1442,4C2F1442";
   if(!Set_MetaQuotesID(AccountNumber(),str_id))
     {
      Alert("エラー:dll実行エラー!プロセス中断の可能性があります"); return;
     }
   if(!SendNotification(text))
     {
      int Err=GetLastError();
      switch(Err)
        {
         case 4250: Alert("注意: プッシュを送れませんでした。", str_id); break;
         case 4251: Alert("エラー:  無効なメッセージテキストです", text); return; break;
         case 4252: Alert("注意:無効なIDリストです。", str_id); break;
         case 4253: Alert("Err: Too frequent requests! "); return; break;
        }
     }
  }
//+------------------------------------------------------------------+


まとめ

DLLを経由したターミナルウィンドウを設定する基本原則についてみてきました。全てのターミナルの機能をより効果的に使えるようになるでしょう。しかし。この方法は、一般的な手法では解決できない場合の最後の手段とするべきです。いくらか欠点があり、選択されたターミナル言語にも依存し、ユーザーの介入や実行の複雑さにも依るからです。もし失敗したら致命的なエラーかさもなくばプログラムのクラッシュを招くことになるでしょう。

MetaQuotes Ltdによってロシア語から翻訳されました。
元の記事: https://www.mql5.com/ru/articles/1903

添付されたファイル |
send_push.mq4 (4.71 KB)
set_push.zip (3.91 KB)
プライスアクション。つつみ線パターンのトレード戦略を自動化するには プライスアクション。つつみ線パターンのトレード戦略を自動化するには
本稿はつつみ線パターンに基づくメタトレーダー4のためのエキスパートアドバイザーを作成する手順について書かれています。パターン認識のルール、待機注文とストップ注文の設定ルールについても書かれています。テストと最適化の結果もあなたの質となるよう提供します。
プライスアクション。はらみ足(Inside Bar)トレード戦略の自動化 プライスアクション。はらみ足(Inside Bar)トレード戦略の自動化
本稿は、はらみ足戦略に基づくメタトレーダー4エキスパートアドバイザーの開発について書かれています。ペンディングとストップオーダーのセッティングルールと、はらみ足と判断する規則についても述べられています。テストと最適化の結果が書かれています。
EA(エキスパートアドバイザー)のテストと最適化 EA(エキスパートアドバイザー)のテストと最適化
この記事は、MT4取引プラットフォームのテスターでの、EAのテストと最適化のプロセスについて書いています。こういった類のデータの必要性と需要を過小評価することはできません。多くのフォーラムの新規ユーザには、EAを使う時に何をどうするべきか想像することが難しいものです。この記事は、彼らにもう少しだけプロフェッショナルなアプローチができるようになる可能性を与えます。
サポートレジスタンス、プライスアクションからトレードセットアップをおこなうには サポートレジスタンス、プライスアクションからトレードセットアップをおこなうには
本稿は、良いタイミングのエントリーをするためのプライスアクションとサポート・レジスタンスレベル(ライン)の観察について書かれています。トレードのセットアップ(エントリー条件)のために、この二つを上手く組み合わせたトレードシステムは何なのか、考えていきます。MQL4のコードには、これらのトレード・コンセプトに基づいたEAに利用されているものがあります。