Emulazione di tick da un EA/indicatore

 

Per molto tempo ho puntato ad implementare l'emulazione automatica dei tick da Expert Advisor/indicatore (cioè a permettergli di "spuntare" se stesso) senza usare DLL o script auto-scritti. Interesse puramente sportivo, per così dire :) Anche se, forse sarà molto utile per qualcuno, se il suo obiettivo non è quello di andare oltre MQL-file, ma di evitare loop (indicatori in particolare).

Devo usare del codice macchina, perché non posso farlo con i soliti metodi. Di seguito la variante finale del codice.

L'Expert Advisor imposta un timer che genera un tick nel proprio grafico a intervalli specificati.

#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);
}
 
In che modo il tuo codice è migliore del "ticker" dello script period_converter?
 
IgorM:
In che modo il tuo codice è migliore del "ticker" dello script period_converter?
Perché non è in loop e quindi può essere utilizzato negli indicatori.
 

Ho fatto questo:

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

nel registro una volta:

11:02:31 test USDCHF,H1: caricato con successo
11:02:31 test USDCHF,H1: inizializzato
11:02:31 test USDCHF,H1: ciclo completato....

commento a sinistra: i = 0

qualcosa non va ((((

 

È un sacco di codice! Una linea è sufficiente per un indicatore.

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

È un sacco di codice! Una linea è sufficiente per un indicatore.

Prima di tutto, il tuo codice non si limita ad emulare un tick; aggiorna forzatamente il grafico con la storia corrispondente ad ogni tick. Almeno una volta ogni tanto dai un'occhiata al log e vedi cosa sta succedendo. E stimare cosa ci sarà tra un giorno o poco più. Per non parlare del carico sul vostro sistema e sul canale Internet.

Se invece di aggiornare il grafico nel vostro codice emulate il tick, questo porterà a dei loop (cioè, l'indicatore partirà senza fermarsi) e, di conseguenza, il terminale si blocca.

IgorM, il mio Print viene emesso ogni secondo, come dovrebbe essere. Non so perché ce l'hai solo una volta... Può essere a causa dei diversi sistemi operativi... Ho XP.

C'è qualche errore nel registro? E controllare se il vostro PostMsgAddr non è zero?

 
Meat:

IgorM, il mio Print viene emesso ogni secondo, come dovrebbe essere. Non so perché hai solo una volta... Forse a causa dei diversi sistemi operativi... Ho XP.

C'è qualche errore nel registro? E controllare se il vostro PostMsgAddr non è zero?


Ho win7, nessun errore nel log, occupato al momento, forse riavvio a xr più tardi - ho 2 sistemi operativi
 

Non preoccupatevi, io stesso ho appena eseguito il 7 (Ultimate). Tutto funziona bene su di esso, quindi non so perché non funziona per te...

 
Meat:

Non preoccupatevi, io stesso ho appena eseguito il 7 (Ultimate). Tutto funziona bene su di esso, quindi non so perché non funziona per te...

in hr funziona: stampa ogni secondo, ma in win7 max con aggiornamenti ad oggi non funziona, quindi non so perché funziona per te....
 
IgorM:
...quindi non sono sicuro del perché funzioni per te....


Quindi abbiamo bisogno di sentire il feedback di qualcun altro su sevens per decidere finalmente chi ha ragione e chi ha torto :)

A proposito, che mi dici del PostMsgAddr di cui ho scritto sopra? Non è uguale a zero?

 
Meat: A proposito, che mi dici del PostMsgAddr di cui ho scritto sopra? Non è uguale a zero?

metterlo dopo.

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[];
il registro ricevuto:

23:39:01 test EURUSD,H1: caricato con successo
23:39:01 test EURUSD,H1: PostMsgAddr =1977398342
23:39:01 test EURUSD,H1: inizializzato
23:39:01 test EURUSD,H1: ciclo completato....