Emulación de ticks de un EA/indicador

 

Durante mucho tiempo he tenido el objetivo de implementar la emulación automática de los ticks de Expert Advisor/indicador (es decir, para permitir que se "tick" a sí mismo) sin utilizar DLL auto-escrito o secuencias de comandos. interés puramente deportivo, por así decirlo :) Aunque, tal vez será muy útil para alguien, si su objetivo no es ir más allá de MQL-archivo, pero para evitar los bucles (indicadores en particular).

Tengo que utilizar algún código máquina, porque no puedo hacerlo con los métodos habituales. A continuación se muestra la variante final del código.

El Asesor Experto establece un temporizador que genera un tick en su propio gráfico a intervalos especificados.

#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);
}
 
¿Cómo es su código mejor que el "ticker" del script period_converter?
 
IgorM:
¿En qué sentido su código es mejor que el "ticker" del script period_converter?
Porque no está en bucle y, por tanto, puede utilizarse en los indicadores.
 

Hice esto:

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

en el registro una vez:

11:02:31 test USDCHF,H1: cargado con éxito
11:02:31 test USDCHF,H1: inicializado
11:02:31 test USDCHF,H1: ciclo completado....

comentario a la izquierda: i = 0

algo está mal ((((

 

¡Eso es un montón de código! Una línea es suficiente para un indicador.

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

¡Eso es un montón de código! Una línea es suficiente para un indicador.

En primer lugar, tu código no se limita a emular un tic, sino que actualiza forzosamente el gráfico con el historial correspondiente en cada tic. ¿Acaso miras el registro de vez en cuando? Échale un vistazo cuando quieras y mira lo que pasa ahí. Y estimar lo que habrá en un día más o menos. Por no hablar de la carga en su sistema y el canal de Internet.

Si en lugar de actualizar el gráfico en tu código emulas el tick, se producirán bucles (es decir, el indicador arrancará sin parar) y, en consecuencia, el terminal se colgará.

IgorM, mi Print sale cada segundo, como debe ser. No sé por qué lo tienes sólo una vez... Puede ser por los diferentes sistemas operativos... Tengo XP.

¿Hay algún error en el cuaderno de bitácora? ¿Y comprobar si su PostMsgAddr no es cero?

 
Meat:

IgorM, mi Print sale cada segundo, como debe ser. No sé por qué sólo tienes una vez... Quizás por los diferentes sistemas operativos... Tengo XP.

¿Hay algún error en el cuaderno de bitácora? ¿Y comprobar si su PostMsgAddr no es cero?


Tengo win7, no hay error en el registro, ocupado en este momento, tal vez voy a reiniciar a xr más tarde - Tengo 2 sistemas operativos
 

No te molestes, yo mismo acabo de ejecutar el 7 (Ultimate). Todo funciona bien en él, así que no sé por qué no te funciona...

 
Meat:

No te molestes, yo mismo acabo de ejecutar el 7 (Ultimate). Todo funciona bien en él, así que no sé por qué no te funciona...

en hr funciona: imprime cada segundo, pero en win7 max con las actualizaciones hasta la fecha no funciona, así que no sé por qué te funciona....
 
IgorM:
...así que no estoy seguro de por qué te funciona....


Así que necesitamos escuchar la opinión de otra persona sobre los sietes para decidir finalmente quién tiene razón y quién no :)

Por cierto, ¿qué pasa con el PostMsgAddr del que escribí arriba? ¿No es igual a cero?

 
Meat: Por cierto, ¿qué pasa con el PostMsgAddr del que escribí arriba? ¿No es igual a cero?

ponlo después.

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[];
el registro recibido:

23:39:01 test EURUSD,H1: cargado con éxito
23:39:01 test EURUSD,H1: PostMsgAddr =1977398342
23:39:01 test EURUSD,H1: inicializado
23:39:01 test EURUSD,H1: ciclo completado....

Razón de la queja: