Quaisquer perguntas de recém-chegados sobre MQL4 e MQL5, ajuda e discussão sobre algoritmos e códigos - página 599

 
Nikolay Gaylis:

Olá!

Você pode me dizer como mover o cursor para, digamos, a linha 7 em um documento de texto, para extrair um substrato desta posição...

O que é mais rápido - vários arquivos de texto com uma linha ou um arquivo com mais linhas?

Você precisa saber quantos bytes estão em uma linha e mover o ponteiro para 6 desses valores desde o início do arquivo.

FileSeek - Файловые операции - Справочник MQL4
FileSeek - Файловые операции - Справочник MQL4
  • docs.mql4.com
Если выставить позицию за "правую границу" файла (больше, чем размер файла), то последующая запись в файл будет будет произведена не с конца файла, а с выставленной позиции. При этом между предыдущим концом файла и выставленной позицией будут записаны неопределенные значения...
 
Nikolay Gaylis:

Olá!

O que é mais rápido - muitos arquivos de texto com uma linha ou um arquivo com muitas linhas?

Depende da implementação específica do algoritmo e do problema a ser resolvido. Talvez no seu caso, a primeira opção seja mais rápida, mas eu não pensaria no desempenho em seu lugar.

Nikolay Gaylis:

Diga-me como mover o cursor, digamos, na 7ª linha de um documento de texto, para extrair o substrato já desta posição...

Leia a documentação padrão. A seção deoperações de arquivos. Por exemplo, você pode ler um arquivo linha por linha com FileReadString, um exemplo é diretamente da documentação:

//--- покажем окно входных параметров при запуске скрипта 
#property script_show_inputs 
//--- параметры для чтения данных 
input string InpFileName="Trend.bin"; // имя файла 
input string InpDirectoryName="Data"; // имя директории 
//+------------------------------------------------------------------+ 
//| Script program start function                                    | 
//+------------------------------------------------------------------+ 
void OnStart() 
  { 
//--- откроем файл 
   ResetLastError(); 
   int file_handle=FileOpen(InpDirectoryName+"//"+InpFileName,FILE_READ|FILE_BIN|FILE_ANSI);
    if(file_handle!=INVALID_HANDLE) 
     { 
      PrintFormat("Файл %s открыт для чтения",InpFileName); 
      PrintFormat("Путь к файлу: %s\\Files\\",TerminalInfoString(TERMINAL_DATA_PATH));
       //--- вспомогательные переменные 
      int    str_size; 
      string str; 
      //--- прочитаем данные из файла 
      while(!FileIsEnding(file_handle)) 
        { 
         //--- узнаем сколько символов использовано для записи времени 
         str_size=FileReadInteger(file_handle,INT_VALUE); 
         //--- прочитаем строку 
         str=FileReadString(file_handle,str_size); 
         //--- распечатаем строку 
         PrintFormat(str); 
        } 
      //--- закроем файл 
      FileClose(file_handle); 
      PrintFormat("Данные прочитаны, файл %s закрыт",InpFileName); 
     } 
   else 
      PrintFormat("Не удалось открыть файл %s, Код ошибки = %d",InpFileName,GetLastError());
   }
 

Você pode me dizer como converter o valor de um clique do mouse sobre um gráfico em um valor de preço ou vice-versa?

int OnInit()
  {
   ChartGetInteger(0,CHART_EVENT_MOUSE_MOVE,true);
   

   return(INIT_SUCCEEDED);
  }
//-------------------------------------------------------
void OnChartEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
  {
   int klik = CHARTEVENT_CLICK;
   Print("ID: ",id," Lparam(X): ",lparam," Dparam(Y): ",dparam," Sparam: ",sparam);
   if(id==klik)sto = true;
   si = lparam;
   Print("'",sparam,"klik ","si = ",si);
   
  }
 
 
Galim_V:

Diga-me como converter o valor de um clique do mouse sobre um gráfico em um valor de preço ou vice-versa.

Use a função ChartXYToTimePrice. Veja "Operações com gráficos" na documentação.

 
Vasiliy Sokolov:

Use a função ChartXYToTimePrice. Veja "Operações com gráficos" na documentação.

Obrigado.

 
Vasiliy Sokolov:

Então, eles cometeram um erro com o CArrayObj. Ao invés de: CArrayObj test_objects; Eles escreveram: CArrayObj* test_objects, mas esqueceram de fazer um destruidor para ele; Talvez tenham configurado incorretamente o modelo de memória para trabalhar com o CArrayObj. Talvez os programadores simplesmente o exageraram com indicações. O diagnóstico é claro: o uso de indicadores onde eles não são necessários muitas vezes causa vazamentos.

Há uma função em alguma classe. Declaro um conjunto de objetos CArrayObj nele. Adiciono objetos de classe global a ela. Quando a função termina, o conjunto de objetos em si não é necessário. Os objetos são necessários, é claro.

Se eu criar o array como um ponteiro CArrayObj *test_objects, recebo objetos não selecionados no log, o que causará um erro fora da memória no final.

Se eu declarar o array como CArrayObj test_objects, adicionar objetos a ele, então acontece que quando a função termina e os objetos ficam indisponíveis, porque o array com objetos é meio que apagado...

 
Juer:

Se eu declarar um array como CArrayObj test_objects, adicionar objetos a ele, então acontece que quando a função termina e os objetos ficam indisponíveis, porque o array com objetos é meio que apagado...

Isto é correto, porque, neste caso, você coloca CArrayObj test_objects na pilha e no espaço de endereço da função. Quando a função sai, o espaço de endereço da função é sobrescrito, incluindo seus CArrayObj test_objects.

Juer:

A função é terminada, a matriz de objetos em si não é necessária. Os objetos, é claro, são necessários.

Lembre-se de uma vez por todas, se você precisa de objetos dentro de um CArrayObj, você também precisa do próprio CArrayObj. O CArrayObj é uma embalagem obrigatória. Não se pode passar sem isso, ponto final.

Juer:

Se eu criar um array como um ponteiro CArrayObj *test_objects, então eu recebo objetos não selecionados no log, o que eventualmente levará a um erro fora da memória.

Neste caso, é criado um ponteiro para algum objeto CArrayObj na pilha. A pilha é um segmento da memória do espaço de endereçamento do programa onde a memória é alocada e apagada manualmente com a ajuda dos operadores novos e apagados correspondentes. Isso significa que se você escrever novo, deve haver em algum lugar sua cópia espelhada de exclusão. Além disso, novos e apagados podem ser localizados em diferentes partes do programa, por exemplo, em diferentes métodos:

CArrayObj* foo_create()
{
  //-- Выделили память в куче, под объект CArrayObj и создали его
  CArrayObj* obj_array = new CArrayObj();
  //-- Заполняем obj_array полезной нагрузкой
  obj_array.Add(new CItem());
  ...
  ...

  //-- Выходим из функции. При этом объект CArrayObj и память под него не затирается.
  //-- Он по-прежнему доступен по указателю. Единственный указатель, который ведет
  //-- к нему это obj_array. Возвращаем его вызвавшей функции
  return obj_array;
}

void foo_analize()
{
   //-- Получили указатель obj_array из foo_create
   //-- здесь он будет под именем obj_analize
   CArrayObj* obj_analize = foo_create();
   //-- Проанализировали объекты внутри obj_analize
   ...
   ...
   ...
   //-- Здесь объект obj_analize и его элементы больше не нужены
   //-- Удаляем объект и все его элементы. Отдельно удалять элементы
   //-- не нужно. CArrayObj сделает все автоматически.
   delete obj_analize;
}

Se, após a chamada foo_analize, ainda forem necessários objetos, o operador de eliminação pode ser colocado em outro lugar, onde os objetos são garantidamente necessários. Tal lugar universal pode ser OnDeinit, por exemplo, que é chamado antes do programa ser fechado.

Lembre-se do principal, se houver um novo operador, deve haver sempre um operador de exclusão para ele. Caso contrário, haverá vazamentos de memória. Os operadores novos e eliminados que trabalham no mesmo objeto não precisam estar "lado a lado" no mesmo método. O Delete pode estar em qualquer lugar longe da alocação de memória, desde que o Delete tenha uma referência ao objeto alocado na pilha.

** Embora isto seja verdade, é melhor evitar tais construções porque sempre temos que ter muito cuidado com onde e sob quais circunstâncias o operador de eliminação é chamado, o que nem sempre é óbvio. Ao invés disso, basta aprender a usar as aulas. A classe permite colocar e apagar objetos automaticamente na pilha, sem utilizar operadores novos e apagados:

class CMyCalculation
{
private:
   //-- Содержит объекты, над которыми нужно провести некоторые мат. операции
   CArrayObj m_obj_array;
   void CreateObj();
public:
   void Calc();
};
//-- Считает массив объектов CArrayObj
void CMyCalculation::Calc()
{
  //-- Если объектов нет, создаем их
  if(m_obj_array.Total() == 0)
     CreateObj();
  //-- Рассчитываем нужные нам значения на данных
  for(int i = 0; i < m_obj_array.Total(); i++)
  {
     CItem* item = m_obj_array.At(i);
     //-- обсчитывает item как нам нужно
     ...
     ...
  }
}
//-- Создает массив объектов CItem
void CMyCalculation::CreateObj()
{
   m_obj_array.Add(new CItem());
   m_obj_array.Add(new CItem());
   ...
   ...
}

Esta classe não contém indicações explícitas. Portanto, você não precisa usar tanto o novo como o apagado. Após sair do programa, a classe liberará automaticamente todos os objetos CItem e CArrayObj, o que torna a vida do desenvolvedor muito mais fácil.

 
Vasiliy Sokolov:

Isto é correto, porque neste caso você coloca CArrayObj test_objects na pilha, e o espaço de endereço da função. Ao sair da função, o espaço de endereço da função é sobrescrito, incluindo seus CArrayObj test_objects.

Lembre-se de uma vez por todas - se você precisa de objetos dentro de um CArrayObj, você precisa do próprio CArrayObj. O CArrayObj é um pacote obrigatório. Não se pode passar sem isso, ponto final.

Neste caso, é criado um ponteiro para algum objeto CArrayObj na pilha. A pilha é um segmento da memória do espaço de endereçamento do programa onde a memória é alocada e apagada manualmente com a ajuda dos operadores novos e apagados correspondentes. Isso significa que se você escrever novo, deve haver em algum lugar sua cópia espelhada de exclusão. Além disso, novos e apagados podem ser localizados em diferentes partes do programa, por exemplo, em diferentes métodos:

Se, após a chamada foo_analize, ainda forem necessários objetos, o operador de eliminação pode ser colocado em outro lugar, onde os objetos são garantidamente necessários. Tal lugar universal pode ser OnDeinit, por exemplo, que é chamado antes do programa ser fechado.

Lembre-se do principal, se houver um novo operador, deve haver sempre um operador de exclusão para ele. Caso contrário, haverá vazamentos de memória. Os operadores novos e eliminados que trabalham com o mesmo objeto não precisam ser localizados "lado a lado" no mesmo método. O Delete pode estar em qualquer lugar longe da alocação de memória, desde que o Delete tenha uma referência ao objeto alocado na pilha.

** Embora isto seja verdade, é melhor evitar tais construções porque sempre temos que ter muito cuidado com onde e sob quais circunstâncias o operador de eliminação é chamado, o que nem sempre é óbvio. Ao invés disso, basta aprender a usar as aulas. A classe permite colocar e apagar objetos automaticamente na pilha, sem utilizar operadores novos e apagados:

Esta classe não contém indicações explícitas. Portanto, você não precisa usar tanto o novo como o apagado. Após a saída do programa, a classe liberará automaticamente todos os objetos CItem e CArrayObj, o que facilita a vida do desenvolvedor.

Obrigado. Mas ainda não encontrei uma resposta para minha pergunta. Onde devo colocar apagar se eu declarar um ponteiro. Repito, o objeto CArrayObj é declarado em uma função... como posso apagá-lo em Deinit()?

Mas antes resolvi o problema desta maneira. Antes de terminar a função:


CClass func()
  {
   CArrayObj test_objects;
   test_objects.Add(m_object1);
   test_objects.Add(m_object2);
   ....

   for(int i=0;i<test_objects.Total();i++)
     {
      test_objects.Detach(i);
     }
   return ..
  }
 
Juer:

Obrigado. Eu simplesmente não consegui encontrar uma resposta para minha pergunta exata. Onde devo colocar apagar se eu declarar um ponteiro. Novamente, o objeto CArrayObj é declarado em uma função... como posso apagá-lo em Deinit()?

Este não é um clube de telepatas. Você não anexou seu código, então você pode decidir por si mesmo onde colocar a exclusão.

CClass func()
  {
   CArrayObj test_objects;
   test_objects.Add(m_object1);
   test_objects.Add(m_object2);
   ....

   for(int i=0;i<test_objects.Total();i++)
     {
      test_objects.Detach(i);
     }
   return ..
  }

Incorreto.

 
Olá. Por favor, ajude-me, configurei o indicador para enviar mensagens quando o preço chega a 400 pips, mas quando estas condições são atingidas, um monte de mensagens é enviado para mim. Como fazer para que envie apenas uma mensagem. Obrigado!
#property indicator_chart_window
extern int    font_size = 10;
extern color  ColorBull = DodgerBlue;
extern color  ColorBeer = Red;
extern string font_name = "rs";
//+------------------------------------------------------------------+

int start()
 {
   double k=(WindowPriceMax()-WindowPriceMin())/20;
   for(int i=WindowFirstVisibleBar(); i>=0; i--)
   {
      double rs = (NormalizeDouble(Open[i],Digits)-NormalizeDouble(Close[i],Digits))/Point;
      if (rs<0) drawtext(i, High[i]+k, DoubleToStr(rs*(-1),0), ColorBull);
      if (rs>0) drawtext(i, Low[i]-Point, DoubleToStr(rs,0), ColorBeer);
   }
   if (rs<-400) 
   {
     SendNotification ("Появился сигнал1: " + Symbol() + ", " + IntegerToString(Period()));
     Print("Сигнал отправлен!");
   }
   if (rs>400)
   {
     SendNotification("Появился сигнал2: " + Symbol() + ", " + IntegerToString(Period()));
     Print("Сигнал отправлен!");
   }
   
}
//+------------------------------------------------------------------+
int deinit()
{
   ObjectsDeleteAll(0,OBJ_TEXT);
   return(0);  
}
//+------------------------------------------------------------------+
int drawtext(int n, double Y1, string l,color c)
 {
   string Name=TimeToStr(Time[n],TIME_DATE|TIME_MINUTES);
   ObjectDelete (Name);
   ObjectCreate (Name, OBJ_TEXT,0,Time[n],Y1,0,0,0,0);
   ObjectSetText(Name, l,font_size,font_name);
   ObjectSet    (Name, OBJPROP_COLOR, c);
 }
//+------------------------------------------------------------------+
Razão: