Emulation von Ticks aus einem EA/Indikator

 

Seit langem habe ich mir vorgenommen, eine automatische Emulation der Ticks von Expert Advisor/Indikator zu implementieren (d.h. ihn in die Lage zu versetzen, selbst zu "ticken"), ohne selbst geschriebene DLL oder Skripte zu verwenden. Rein sportliches Interesse, sozusagen :) Obwohl, vielleicht ist es für jemanden sehr nützlich, wenn sein Ziel nicht ist, eine MQL-Datei zu überschreiten, sondern Schleifen (insbesondere Indikatoren) zu vermeiden.

Ich habe mit etwas Maschinencode gearbeitet, deshalb musste ich es teilweise in Maschinencode schreiben. Nachstehend finden Sie die endgültige Variante des Codes.

Der Expert Advisor setzt einen Timer, der in bestimmten Abständen einen Tick in seinem eigenen Chart erzeugt.

#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);
}
 
Inwiefern ist Ihr Code besser als der "Ticker" aus dem period_converter-Skript?
 
IgorM:
Inwiefern ist Ihr Code besser als der "Ticker" aus dem period_converter-Skript?
Weil er nicht in einer Schleife steckt und daher in Indikatoren verwendet werden kann.
 

Ich habe dies getan:

#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);
}

einmal im Protokoll:

11:02:31 test USDCHF,H1: erfolgreich geladen
11:02:31 test USDCHF,H1: initialisiert
11:02:31 test USDCHF,H1: Zyklus abgeschlossen....

Kommentar links: i = 0

etwas stimmt nicht ((((

 

Das ist eine Menge Code! Eine Zeile reicht für einen Indikator aus.

#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:

Das ist eine Menge Code! Eine Zeile reicht für einen Indikator aus.

Zunächst einmal emuliert Ihr Code nicht einfach nur einen Tick, sondern er aktualisiert den Chart zwangsweise bei jedem Tick mit der entsprechenden Historie. Schauen Sie sich das Log wenigstens ab und zu mal an, um zu sehen, was dort los ist. Und schätzen Sie, was in etwa einem Tag da sein wird. Ganz zu schweigen von der Belastung Ihres Systems und Ihres Internetkanals.

Wenn Sie statt der Aktualisierung des Charts in Ihrem Code den Tick emulieren, führt dies zu Schleifen (d.h. der Indikator startet, ohne zu stoppen) und dementsprechend bleibt das Terminal hängen.

IgorM, mein Print wird jede Sekunde ausgegeben, so wie es sein sollte. Ich weiß nicht, warum Sie es nur einmal haben... Vielleicht liegt es an den unterschiedlichen Betriebssystemen... Ich habe XP.

Gibt es einen Fehler im Logbuch? Und prüfen Sie, ob Ihre PostMsgAddr nicht Null ist?

 
Meat:

IgorM, mein Print wird jede Sekunde ausgegeben, so wie es sein sollte. Ich weiß nicht, warum Sie es nur einmal haben... Vielleicht wegen der verschiedenen Betriebssysteme... Ich habe XP.

Gibt es einen Fehler im Logbuch? Und prüfen Sie, ob Ihre PostMsgAddr nicht Null ist?


Ich habe win7, kein Fehler im Protokoll, im Moment beschäftigt, vielleicht werde ich später auf xr neu starten - ich habe 2 Betriebssysteme
 

Bemühen Sie sich nicht, ich habe gerade die 7 (Ultimate) selbst ausgeführt. Es funktioniert alles einwandfrei, also weiß ich nicht, warum es bei Ihnen nicht funktioniert...

 
Meat:

Bemühen Sie sich nicht, ich habe gerade die 7 (Ultimate) selbst ausgeführt. Es funktioniert alles einwandfrei, also weiß ich nicht, warum es bei Ihnen nicht funktioniert...

in hr funktioniert: druckt jede Sekunde, aber in win7 max mit Updates auf Datum nicht funktioniert, so weiß nicht, warum es für Sie funktioniert....
 
IgorM:
...daher weiß ich nicht, warum es bei Ihnen funktioniert....


Wir müssen also das Feedback von jemand anderem zu den Siebenern hören, um endgültig zu entscheiden, wer Recht hat und wer nicht :)

Übrigens, was ist mit dem PostMsgAddr, über das ich oben geschrieben habe? Ist sie nicht gleich Null?

 
Meat: Übrigens, was ist mit dem PostMsgAddr, über das ich oben geschrieben habe? Ist sie nicht gleich Null?

setzen Sie es danach.

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[];
das empfangene Protokoll:

23:39:01 test EURUSD,H1: erfolgreich geladen
23:39:01 test EURUSD,H1: PostMsgAddr =1977398342
23:39:01 test EURUSD,H1: initialisiert
23:39:01 test EURUSD,H1: Zyklus abgeschlossen....