Emulation of ticks from an EA/indicator

 

For a long time I have aimed to implement automatic emulation of ticks from Expert Advisor/indicator (i.e. to enable it to "tick" itself), without using self-written DLL or scripts. Purely sporting interest, so to speak :) Although, maybe it will be very useful for someone, if his aim is not to overstep a MQL file, but to avoid loops (indicators in particular).

I have to use some machine code, because I cannot do it using usual methods. Below is the final variant of the code.

The Expert Advisor sets a timer that generates a tick in its own chart at specified intervals.

#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);
}
 
how is your code better than the "ticker" from the period_converter script ?
 
IgorM:
How is your code better than the "ticker" from the period_converter script?
Because it is not looped and can therefore be used in indicators.
 

I did this:

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

in the log once:

11:02:31 test USDCHF,H1: loaded successfully
11:02:31 test USDCHF,H1: initialized
11:02:31 test USDCHF,H1: cycle completed....

comment left: i = 0

something is wrong ((((

 

That's a lot of code! One line is enough for an indicator.

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

That's a lot of code! One line is enough for an indicator.

First of all, your code does not merely emulate a tick; it forcibly updates the chart with the corresponding history at every tick. Do you even look into the log at least once in a while? Have a look at it at your leisure and see what's going on there. And estimate what will be there in a day or so. Not to mention load on your system and Internet channel.

If instead of updating the chart in your code you emulate the tick, it will lead to loops (i.e., the indicator will start without stopping) and, accordingly, the terminal hangs.

IgorM, my Print is output every second, as it should be. I don't know why you have it only once... May be because of different operating systems... I have XP.

Is there any error in the logbook? And check if your PostMsgAddr is not zero?

 
Meat:

IgorM, my Print is output every second, as it should be. I don't know why you have only one time... Maybe because of different operating systems... I have XP.

Is there any error in the logbook? And check if your PostMsgAddr is not zero?


I have win7, no error in the log, busy at the moment, maybe I'll reboot to xr later - I have 2 operating systems
 

Don't bother, I've just run the 7 (Ultimate) myself. Everything works fine on it, so I don't know why it doesn't work for you...

 
Meat:

Don't bother, I've just run the 7 (Ultimate) myself. Everything works fine on it, so I don't know why it doesn't work for you...

in hr works: prints every second, but in win7 max with updates to date does not work, so don't know why it works for you....
 
IgorM:
...so not sure why it works for you....


So we need to hear someone else's feedback on sevens to finally decide who's right and who's wrong :)

By the way, what about the PostMsgAddr I wrote about above? Isn't it equal to zero?

 
Meat: By the way, what about the PostMsgAddr I wrote about above? Is it not equal to zero?

put it after.

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[];
the log received:

23:39:01 test EURUSD,H1: loaded successfully
23:39:01 test EURUSD,H1: PostMsgAddr =1977398342
23:39:01 test EURUSD,H1: initialized
23:39:01 test EURUSD,H1: cycle completed....