Cualquier pregunta de los recién llegados sobre MQL4 y MQL5, ayuda y discusión sobre algoritmos y códigos - página 599

 
Nikolay Gaylis:

¡Hola!

Me pueden decir cómo mover el cursor a, por ejemplo, la línea 7 de un documento de texto, para extraer una subcadena de esta posición...

¿Qué es más rápido: varios archivos de texto con una línea o un archivo con más líneas?

Necesita saber cuántos bytes hay en una línea y mover el puntero a 6 de esos valores desde el principio del archivo.

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

¡Hola!

¿Qué es más rápido, muchos archivos de texto con una línea o un archivo con muchas líneas?

Depende de la implementación específica del algoritmo y del problema a resolver. Quizás en tu caso, la primera opción sea más rápida, pero yo no pensaría en el rendimiento en tu lugar.

Nikolay Gaylis:

Por favor, dígame cómo mover el cursor, digamos, en la 7ª línea de un documento de texto, para extraer la subcadena ya desde esta posición...

Lea la documentación estándar. La sección deoperaciones de archivo. Por ejemplo, puede leer un archivo línea por línea con FileReadString, un ejemplo está directamente en la documentación:

//--- покажем окно входных параметров при запуске скрипта 
#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());
   }
 

¿Pueden decirme cómo convertir el valor de un clic del ratón en un gráfico en un valor de precio o viceversa?

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:

Dime cómo convertir el valor de un clic del ratón en un gráfico en un valor de precio o viceversa.

Utilice la función ChartXYToTimePrice. Véase "Operaciones con gráficos" en la documentación.

 
Vasiliy Sokolov:

Utilice la función ChartXYToTimePrice. Véase "Operaciones con gráficos" en la documentación.

Gracias.

 
Vasiliy Sokolov:

Así que cometieron un error con CArrayObj. En lugar de: CArrayObj test_objects ; Escribieron: CArrayObj* test_objects, pero se olvidaron de hacer un destructor para él; Tal vez configuraron incorrectamente el modelo de memoria para trabajar con CArrayObj. Quizás los programadores simplemente se excedieron con los punteros. El diagnóstico es claro: el uso de punteros donde no son necesarios suele provocar fugas.

Hay una función en alguna clase. Declaro un array de objetos CArrayObj en él. Agrego objetos de clase global en él. Cuando la función finaliza, la matriz de objetos en sí no es necesaria. Los objetos son necesarios, por supuesto.

Si creo el array como un puntero CArrayObj *test_objects, obtendré objetos no borrados en el registro, lo que provocará un error de falta de memoria al final.

Si declaro el array como CArrayObj test_objects, añado objetos a él, entonces resulta que cuando la función termina y los objetos dejan de estar disponibles, porque el array con los objetos está como borrado...

 
Juer:

Si declaro un array como CArrayObj test_objects, añado objetos a él, entonces resulta que cuando la función termina, los objetos no estarán disponibles, porque el array con los objetos está como borrado...

Esto es correcto, porque en este caso, se coloca CArrayObj test_objects en la pila y en el espacio de direcciones de la función. Cuando la función sale, el espacio de direcciones de la función se sobrescribe, incluyendo su CArrayObj test_objects.

Juer:

La función se termina, la matriz de objetos en sí no es necesaria. Los objetos, por supuesto, son necesarios.

Recuerda de una vez por todas que si necesitas objetos dentro de un CArrayObj, también necesitas el propio CArrayObj. CArrayObj es un embalaje obligatorio. No puedes prescindir de él, y punto.

Juer:

Si creo un array como un puntero CArrayObj *test_objects, entonces obtengo objetos no borrados en el registro, lo que eventualmente llevará a un error de falta de memoria.

En este caso se crea un puntero a algún objeto CArrayObj en el heap. El heap es un segmento de memoria del espacio de direcciones del programa en el que la memoria se asigna y elimina manualmente con la ayuda de los correspondientes operadores new y delete. Significa que si escribes nuevo, debe haber su copia espejo de borrado en algún lugar. Además, nuevo y borrar pueden estar ubicados en diferentes partes del programa, por ejemplo, en 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;
}

Si, después de llamar a foo_analize, los objetos siguen siendo necesarios, el operador de borrado puede colocarse en otro lugar, donde se garantice que los objetos son necesarios. Este lugar universal puede ser OnDeinit, por ejemplo, que se llama antes de que se cierre el programa.

Recuerda lo principal, Si hay un operador nuevo, siempre debe haber un operador de eliminación para él. De lo contrario, habrá fugas de memoria. Los operadores new y delete que trabajan sobre el mismo objeto no tienen que estar "uno al lado del otro" en el mismo método. Delete puede estar en cualquier lugar lejos de la asignación de memoria, siempre y cuando delete tenga una referencia al objeto asignado en el heap.

** Aunque esto es cierto, es mejor evitar este tipo de construcciones porque siempre hay que tener mucho cuidado con dónde y bajo qué circunstancias se llama al operador de borrado, lo cual no siempre es obvio. En cambio, sólo hay que aprender a utilizar las clases. La clase permite colocar y eliminar automáticamente objetos en el montón, sin utilizar los operadores new y delete:

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 clase no contiene punteros explícitamente. Por lo tanto, no es necesario utilizar tanto nuevo como borrado. Después de salir del programa, la clase liberará todos los objetos CItem y CArrayObj automáticamente, lo que hace la vida del desarrollador mucho más fácil.

 
Vasiliy Sokolov:

Esto es correcto, porque en este caso se coloca CArrayObj test_objects en la pila, y el espacio de direcciones de la función. Al salir de la función, el espacio de direcciones de la función se sobrescribe, incluyendo su CArrayObj test_objects.

Recuerda de una vez por todas que si necesitas objetos dentro de un CArrayObj, necesitas el propio CArrayObj. CArrayObj es un paquete obligatorio. No se puede prescindir de él, y punto.

En este caso, se crea un puntero a algún objeto CArrayObj en el heap. El heap es un segmento de memoria del espacio de direcciones del programa en el que la memoria se asigna y elimina manualmente con la ayuda de los correspondientes operadores new y delete. Significa que si escribes nuevo, debe haber su copia espejo de borrado en algún lugar. Además, nuevo y borrar pueden estar ubicados en diferentes partes del programa, por ejemplo, en diferentes métodos:

Si, después de llamar a foo_analize, los objetos siguen siendo necesarios, el operador de borrado puede colocarse en otro lugar, donde se garantice que los objetos son necesarios. Este lugar universal puede ser OnDeinit, por ejemplo, que se llama antes de que se cierre el programa.

Recuerda lo principal, si hay un operador nuevo, siempre debe haber un operador de eliminación para él. De lo contrario, habrá fugas de memoria. Los operadores new y delete que trabajan con el mismo objeto no tienen que estar ubicados "uno al lado del otro" en el mismo método. Delete puede estar en cualquier lugar lejos de la asignación de memoria, siempre y cuando delete tenga una referencia al objeto asignado en el heap.

** Aunque esto es cierto, es mejor evitar este tipo de construcciones porque siempre hay que tener mucho cuidado con dónde y bajo qué circunstancias se llama al operador de borrado, lo cual no siempre es obvio. En cambio, sólo hay que aprender a utilizar las clases. La clase permite colocar y eliminar automáticamente objetos en el montón, sin utilizar los operadores new y delete:

Esta clase no contiene punteros explícitamente. Por lo tanto, no es necesario utilizar tanto nuevo como borrado. Después de que el programa salga, la clase liberará automáticamente todos los objetos CItem y CArrayObj, lo que facilita la vida al desarrollador.

Gracias. Pero no he encontrado una respuesta a mi pregunta. Dónde debo poner delete si declaro un puntero. Repito, el objeto CArrayObj está declarado en una función... ¿cómo puedo borrarlo en Deinit()?

Pero antes resolví el problema así. Antes de terminar la función:


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:

Gracias. No pude encontrar una respuesta a mi pregunta exacta. Dónde debo poner delete si declaro un puntero. De nuevo, el objeto CArrayObj está declarado en una función... ¿cómo puedo borrarlo en Deinit()?

Este no es un club de telépatas. No has adjuntado tu código, así que puedes decidir por ti mismo dónde colocar el borrado.

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 ..
  }

No es correcto.

 
Hola. Por favor, ayuda, he configurado el indicador para que envíe mensajes cuando el precio alcance los 400 pips, pero cuando se alcanzan estas condiciones, me envían un montón de mensajes. Cómo hacer que envíe sólo un mensaje. Gracias.
#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ón de la queja: