Emulação de carrapatos de um EA/indicador

 

Durante muito tempo, procurei implementar a emulação automática de ticks do Expert Advisor/indicador (ou seja, permitir que ele se "marque") sem usar DLL ou scripts autoescritos. Interesse puramente esportivo, por assim dizer :) Embora, talvez seja muito útil para alguém, se seu objetivo não for ir além do arquivo MQL, mas evitar loops (indicadores em particular).

Tenho que usar algum código de máquina, porque não posso fazê-lo usando os métodos usuais. Abaixo está a variante final do código.

O Expert Advisor estabelece um cronômetro que gera um tique em seu próprio gráfico em 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);
}
 
como seu código é melhor do que o "ticker" do roteiro do period_converter?
 
IgorM:
Como seu código é melhor do que o "ticker" do roteiro do period_converter?
Porque não é looped e pode, portanto, ser usado em indicadores.
 

Eu fiz isso:

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

no diário de bordo uma vez:

11:02:31 teste USDCHF,H1: carregado com sucesso
11:02:31 teste USDCHF,H1: inicializado
11:02:31 teste USDCHF,H1: ciclo completo....

comentário à esquerda: i = 0

algo está errado ((((

 

Isso é um monte de código! Uma linha é suficiente para um 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:

Isso é um monte de código! Uma linha é suficiente para um indicador.

Em primeiro lugar, seu código não apenas emula um carrapato; ele atualiza à força o gráfico com o histórico correspondente a cada carrapato. Você olha para o registro pelo menos de vez em quando? Dê uma olhada no registro a seu bel-prazer e veja o que está acontecendo lá. E estimar o que estará lá em um dia ou algo assim. Para não mencionar a carga em seu sistema e canal de Internet.

Se, em vez de atualizar a tabela em seu código, você emular o tick, isso levará a loops (ou seja, o indicador começará sem parar) e, consequentemente, o terminal ficará pendurado.

IgorM, minha impressão é impressa a cada segundo, como deveria ser. Não sei por que você o tem apenas uma vez... Pode ser por causa de sistemas operacionais diferentes... Eu tenho EXP.

Há algum erro no diário de bordo? E verifique se seu PostMsgAddr não é zero?

 
Meat:

IgorM, minha impressão é exibida a cada segundo, como deveria ser. Não sei por que você o tem apenas uma vez... Talvez por causa de sistemas operacionais diferentes... Eu tenho EXP.

Há algum erro no diário de bordo? E verifique se seu PostMsgAddr não é zero?


Eu ganhei7, nenhum erro no log, ocupado no momento, talvez eu reinicie para xr mais tarde - eu tenho 2 sistemas operacionais
 

Não se preocupe, eu mesmo acabei de dirigir o 7 (Ultimate). Tudo funciona bem nele, por isso não sei por que não funciona para você...

 
Meat:

Não se preocupe, eu mesmo acabei de dirigir o 7 (Ultimate). Tudo funciona bem nele, por isso não sei por que não funciona para você...

em hr works: imprime a cada segundo, mas em win7 max com atualizações até a data não funciona, então não sei porque funciona para você....
 
IgorM:
...então não tenho certeza porque funciona para você....


Portanto, precisamos ouvir o feedback de outra pessoa em sete para finalmente decidir quem está certo e quem está errado :)

A propósito, e quanto ao PostMsgAddr sobre o qual escrevi acima? Não é igual a zero?

 
Meat: A propósito, e quanto ao PostMsgAddr sobre o qual escrevi acima? Não é igual a zero?

coloque depois.

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[];
o registro recebido:

23:39:01 teste EURUSD,H1: carregado com sucesso
23:39:01 teste EURUSD,H1: PostMsgAddr =1977398342
23:39:01 teste EURUSD,H1: inicializado
23:39:01 teste EURUSD,H1: ciclo completo....