EA/インジケーターからのティックのエミュレーション

 

私は長い間、Expert Advisor/Indicatorからティックの自動エミュレーション(つまり、それ自体を「ティック」できるようにすること)を自作のDLLやスクリプトを使用せずに実装することを目指してきました。 いわば純粋なスポーツ的興味ですが :) もし彼の目的がMQLファイルを超えることではなく、ループ(特に指標)を避けることにあるならば、それは誰かにとって非常に有用であるのかもしれません。

通常の方法ではできないので、何らかのマシンコードを使う必要があります。以下は、最終的なコードのバリエーションです。

Expert Advisorは、指定した間隔で自身のチャートにティックを発生させるタイマーを設定 します。

#import "user32.dll"
  int   RegisterWindowMessageA(string lpString);
  int   SetTimer(int hWnd,int nIDEvent,int uElapse,int& lpTimerFunc[]);
  bool  KillTimer(int hWnd,int uIDEvent);
#import "kernel32.dll"
  int   GetModuleHandleA(string lpModuleName);
  int   GetProcAddress(int hModule,string lpProcName);
  

int TimerId=666;

//----------------------------------------------------------------------

int init()
{
  SetMyTimer(1000);  // интервал в миллисекундах
}
//----------------------------------------------------------------------

int deinit()
{
  KillMyTimer();
}  

//+------------------------------------------------------------------+
//| program start function                                           |
//+------------------------------------------------------------------+
int start()
{
   PlaySound("tick.wav"); 
}
//-------------------------------------------------------------------

int SetMyTimer(int interval)
{    
  int MT4InternalMsg= RegisterWindowMessageA("MetaTrader4_Internal_Message");
  int hWnd= WindowHandle(Symbol(),Period());
  int PostMsgAddr= GetProcAddress(GetModuleHandleA("user32.dll"),"PostMessageA");
  int code[];
  AddBytes(code,0x55);  // push ebp
  AddBytes(code,0x8B);  // move ebp,esp
  AddBytes(code,0xEC);  
  AddBytes(code,0x6A);  // push 01
  AddBytes(code,0x01);
  AddBytes(code,0x6A);  // push 02
  AddBytes(code,0x02);
  AddBytes(code,0x68);  // push MT4InternalMsg
  AddBytes(code,MT4InternalMsg,4);
  AddBytes(code,0x68);  // push hWnd
  AddBytes(code,hWnd,4);
  AddBytes(code,0xB8);  // mov eax, PostMsgAddr
  AddBytes(code,PostMsgAddr,4);
  AddBytes(code,0xFF);  // call eax
  AddBytes(code,0xD0);  
  AddBytes(code,0x33);  // xor eax, eax
  AddBytes(code,0xC0);
  AddBytes(code,0x5D);  // pop ebp
  AddBytes(code,0xC3);  // ret
  
  return (SetTimer(hWnd, TimerId, interval, code) );
}
//---------------------------------------------------

bool KillMyTimer()
{
  return( KillTimer(WindowHandle(Symbol(),Period()), TimerId) );
}
//+------------------------------------------------------------------+

int AddBytes(int& code[], int value, int bytescount=1)
{
  static int pos=0;  // текущая позиция (в байтах)
  if (ArraySize(code)==0) pos=0;
  for (int i=0; i<bytescount; i++, pos++)
  {
    int cell=pos/4;
    if (cell>=ArraySize(code)) ArrayResize(code,cell+1);
    int byte=pos%4;
    code[cell] &= ~(0xFF<<(byte*8));    // обнуляем место под байт
    code[cell] |= value&0xFF<<(byte*8); // записываем байт
    value>>=8;
  }  
  return(pos);
}
 
period_converter スクリプトの "ticker" と比較して、どのように優れたコードですか?
 
IgorM:
このコードはperiod_converterスクリプトの "ticker "よりもどのように優れているのでしょうか?
ループしないため、インジケーターに使用できるため。
 

こんなことをしました。

#property indicator_chart_window

#import "user32.dll"
  int   RegisterWindowMessageA(string lpString);
  int   SetTimer(int hWnd,int nIDEvent,int uElapse,int& lpTimerFunc[]);
  bool  KillTimer(int hWnd,int uIDEvent);
#import "kernel32.dll"
  int   GetModuleHandleA(string lpModuleName);
  int   GetProcAddress(int hModule,string lpProcName);
int TimerId=666;

//+------------------------------------------------------------------+
int init(){
   SetMyTimer(1000);  // интервал в миллисекундах
return(0);
}
//+------------------------------------------------------------------+
int deinit(){
   KillMyTimer();
   Comment("");
return(0);
}
//+------------------------------------------------------------------+
int start(){
   int i,limit;
   limit = 1000;
   for(i=limit; i>=0; i--){
      Comment("i = ",i);
   }
   Print("цикл завершен....");
return(0);
}

int SetMyTimer(int interval)
{    
  int MT4InternalMsg= RegisterWindowMessageA("MetaTrader4_Internal_Message");
  int hWnd= WindowHandle(Symbol(),Period());
  int PostMsgAddr= GetProcAddress(GetModuleHandleA("user32.dll"),"PostMessageA");
  int code[];
  AddBytes(code,0x55);  // push ebp
  AddBytes(code,0x8B);  // move ebp,esp
  AddBytes(code,0xEC);  
  AddBytes(code,0x6A);  // push 01
  AddBytes(code,0x01);
  AddBytes(code,0x6A);  // push 02
  AddBytes(code,0x02);
  AddBytes(code,0x68);  // push MT4InternalMsg
  AddBytes(code,MT4InternalMsg,4);
  AddBytes(code,0x68);  // push hWnd
  AddBytes(code,hWnd,4);
  AddBytes(code,0xB8);  // mov eax, PostMsgAddr
  AddBytes(code,PostMsgAddr,4);
  AddBytes(code,0xFF);  // call eax
  AddBytes(code,0xD0);  
  AddBytes(code,0x33);  // xor eax, eax
  AddBytes(code,0xC0);
  AddBytes(code,0x5D);  // pop ebp
  AddBytes(code,0xC3);  // ret
  
  return (SetTimer(hWnd, TimerId, interval, code) );
}
//---------------------------------------------------

bool KillMyTimer()
{
  return( KillTimer(WindowHandle(Symbol(),Period()), TimerId) );
}
//+------------------------------------------------------------------+

int AddBytes(int& code[], int value, int bytescount=1)
{
  static int pos=0;  // текущая позиция (в байтах)
  if (ArraySize(code)==0) pos=0;
  for (int i=0; i<bytescount; i++, pos++)
  {
    int cell=pos/4;
    if (cell>=ArraySize(code)) ArrayResize(code,cell+1);
    int byte=pos%4;
    code[cell] &= ~(0xFF<<(byte*8));    // обнуляем место под байт
    code[cell] |= value&0xFF<<(byte*8); // записываем байт
    value>>=8;
  }  
  return(pos);
}

を一度だけログに残す。

11:02:31 test USDCHF,H1: ロードに成功しました。
11:02:31 test USDCHF,H1:初期化されました。
11:02:31 test USDCHF,H1:サイクル完了...。

コメント左:i = 0

何かがおかしい(((

 

すごい数のコードですねインジケーターは1行で十分です。

#property indicator_chart_window
#include <WinUser32.mqh>
int nCounter = 0;
void start()
 {
  int hwndChart = WindowHandle(Symbol(), 0);
  SendMessageA(hwndChart, WM_COMMAND, 0x822C, NULL); // <-- Этой строки.
  nCounter++;
  Comment(nCounter);
 }
 
Zhunko:

すごい数のコードですねインジケーターは1行で十分です。

まず、あなたのコードは単にティックをエミュレートしているのではなく、ティックごとに対応する履歴で強制的にチャートを更新しています。 たまにはログも見てみますか? 暇なときにでも見て、そこで何が起こっているのか見てみてください。そして、1日後くらいに何があるか見積もってみてください。システムやインターネット回線への負荷は言うまでもありません。

コード内でチャートを更新する代わりにティックをエミュレートすると、ループが発生し(つまり、インジケータが停止せずに起動し)、それに応じて端末がハングアップします。

IgorM さん、私のPrintは、当然のように1秒ごとに出力されています。なぜ一度しか表示されないのかわからない...OSが違うからかもしれない...。私はXPを持っています。

ログブックに間違いはないか?そして、PostMsgAddrが0でないかを確認する?

 
Meat:

IgorM さん、私のPrintは、当然のように1秒ごとに出力されています。なぜか1回だけなんですよね...OSが違うからでしょうか...。私はXPを持っています。

ログブックに間違いはないか?そして、PostMsgAddrが0でないかを確認する?


私はwin7を持っています、ログにエラーはありません、今は忙しいので、多分後でxrに再起動します - 私は2つのオペレーティングシステムを持っています
 

気にしないでください、自分は7(Ultimate)を実行しただけです。すべて問題なく動作しているのに、なぜかうまくいかない...。

 
Meat:

気にしないでください、自分は7(Ultimate)を実行しただけです。すべて問題なく動作しているのに、なぜかうまくいかない...。

hrでは1秒ごとに印刷されるのですが、win7では最大で日付の更新がうまくいかず、なぜかうまくいかないのです...。
 
IgorM:
...だから、なぜあなたに効果があるのかわからない...。


だから、最終的に誰が正しくて誰が間違っているのかを決めるには、他の人のセブンの感想を聞く必要があるんだ :)

ところで、上に書いたPostMsgAddrはどうでしょうか?ゼロに等しいのでは?

 
Meat: ところで、上に書いたPostMsgAddrはどうでしょうか?ゼロにはならないのでしょうか?

の後に置く。

int SetMyTimer(int interval)
{    
  int MT4InternalMsg= RegisterWindowMessageA("MetaTrader4_Internal_Message");
  int hWnd= WindowHandle(Symbol(),Period());
  int PostMsgAddr= GetProcAddress(GetModuleHandleA("user32.dll"),"PostMessageA");
  Print("PostMsgAddr =",PostMsgAddr);
  int code[];
を受信しました。

23:39:01 test EURUSD,H1: ロードに成功しました。
23:39:01 test EURUSD,H1: PostMsgAddr =1977398342
23:39:01 test EURUSD,H1: 初期化されました。
23:39:01 test EURUSD,H1: サイクル完了...。