Tutte le domande dei nuovi arrivati su MQL4 e MQL5, aiuto e discussione su algoritmi e codici - pagina 599

 
Nikolay Gaylis:

Ciao!

Potete dirmi come spostare il cursore su, diciamo, la linea 7 in un documento di testo, per estrarre una sottostringa da questa posizione...

Cos'è più veloce: più file di testo con una riga o un file con più righe?

Dovete sapere quanti byte ci sono in una linea e spostare il puntatore a 6 di questi valori dall'inizio del file.

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

Ciao!

Cosa è più veloce: molti file di testo con una riga o un file con molte righe?

Dipende dall'implementazione specifica dell'algoritmo e dal problema da risolvere. Forse nel tuo caso, la prima opzione sarà più veloce, ma non penserei alle prestazioni al tuo posto.

Nikolay Gaylis:

Per favore, ditemi come spostare il cursore, diciamo, sulla settima linea in un documento di testo, per estrarre la sottostringa già da questa posizione...

Leggete la documentazione standard. La sezione delleoperazioni sui file. Per esempio, potete leggere un file riga per riga con FileReadString, un esempio è direttamente dalla documentazione:

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

Potete dirmi come convertire il valore di un clic del mouse su un grafico in un valore di prezzo 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:

Dimmi come convertire il valore di un clic del mouse su un grafico in un valore di prezzo o viceversa.

Usa la funzione ChartXYToTimePrice. Vedere "Operazioni con i grafici" nella documentazione.

 
Vasiliy Sokolov:

Usa la funzione ChartXYToTimePrice. Vedere "Operazioni con i grafici" nella documentazione.

Grazie.

 
Vasiliy Sokolov:

Quindi hanno fatto un errore con CArrayObj. Invece di: CArrayObj test_objects; Hanno scritto: CArrayObj* test_objects, ma hanno dimenticato di fare un distruttore per esso; Forse hanno configurato male il modello di memoria per lavorare con CArrayObj. Forse hanno semplicemente esagerato con i puntatori. La diagnosi è chiara: l'uso di puntatori dove non sono necessari spesso causa perdite.

C'è una funzione in qualche classe. Dichiaro un array di oggetti CArrayObj in esso. Ci aggiungo gli oggetti della classe globale. Quando la funzione è finita, l'array di oggetti in sé non è necessario. Gli oggetti sono necessari, ovviamente.

Se creo l'array come puntatore CArrayObj *test_objects, ottengo oggetti non cancellati nel registro, il che causerà un errore di out of memory alla fine.

Se dichiaro l'array come CArrayObj test_objects, aggiungo oggetti ad esso, poi risulta che quando la funzione finisce e gli oggetti diventano indisponibili, perché l'array con gli oggetti è come cancellato...

 
Juer:

Se dichiaro un array come CArrayObj test_objects, aggiungo degli oggetti ad esso, poi risulta che quando la funzione finisce e gli oggetti diventano indisponibili, perché l'array con gli oggetti viene come cancellato...

Questo è corretto, perché in questo caso, mettete CArrayObj test_objects sullo stack e nello spazio di indirizzi della funzione. Quando la funzione esce, lo spazio degli indirizzi della funzione viene sovrascritto, compresi i vostri CArrayObj test_objects.

Juer:

La funzione è terminata, l'array di oggetti in sé non è necessario. Gli oggetti, ovviamente, sono necessari.

Ricordate una volta per tutte che se avete bisogno di oggetti dentro un CArrayObj, avete anche bisogno del CArrayObj stesso. CArrayObj è un imballaggio obbligatorio. Non puoi farne a meno, punto e basta.

Juer:

Se creo un array come puntatore CArrayObj *test_objects, allora ottengo oggetti non cancellati nel log, che alla fine porteranno ad un errore di out of memory.

In questo caso viene creato un puntatore a qualche oggetto CArrayObj nell'heap. L'heap è un segmento di memoria dello spazio degli indirizzi del programma dove la memoria viene allocata e cancellata manualmente con l'aiuto dei corrispondenti operatori new e delete. Significa che se si scrive new, ci deve essere la sua copia speculare di delete da qualche parte. Inoltre, il nuovo e l'eliminazione possono essere situati in parti diverse del programma, per esempio, in metodi diversi:

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, dopo aver chiamato foo_analize, gli oggetti sono ancora necessari, l'operatore di cancellazione può essere messo da qualche altra parte, dove gli oggetti sono garantiti essere necessari. Un tale luogo universale può essere OnDeinit, per esempio, che viene chiamato prima della chiusura del programma.

Ricordate la cosa principale, se c'è un operatore nuovo, ci deve sempre essere un operatore di cancellazione per esso. Altrimenti ci saranno perdite di memoria. Gli operatori new e delete che lavorano sullo stesso oggetto non devono essere "affiancati" nello stesso metodo. La cancellazione può essere ovunque lontano dall'allocazione di memoria, purché la cancellazione abbia un riferimento all'oggetto allocato nell'heap.

** Anche se questo è vero, è meglio evitare tali costrutti perché dobbiamo sempre stare molto attenti a dove e in quali circostanze viene chiamato l'operatore di cancellazione, che non è sempre ovvio. Invece, devi solo imparare a usare le classi. La classe permette di posizionare e cancellare automaticamente gli oggetti sull'heap, senza usare gli operatori new e 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());
   ...
   ...
}

Questa classe non contiene esplicitamente dei puntatori. Quindi non c'è bisogno di usare sia new che delete. Dopo l'uscita dal programma, la classe rilascerà tutti gli oggetti CItem e CArrayObj automaticamente, il che rende la vita dello sviluppatore molto più facile.

 
Vasiliy Sokolov:

Questo è corretto, perché in questo caso mettete CArrayObj test_objects sullo stack, e lo spazio di indirizzo della funzione. Quando uscite dalla funzione, lo spazio degli indirizzi della funzione viene sovrascritto, compresi i vostri CArrayObj test_objects.

Ricordate una volta per tutte - se avete bisogno di oggetti dentro un CArrayObj, avete bisogno del CArrayObj stesso. CArrayObj è un pacchetto obbligatorio. Non potete farne a meno, punto e basta.

In questo caso, viene creato un puntatore a qualche oggetto CArrayObj nell'heap. L'heap è un segmento di memoria dello spazio degli indirizzi del programma dove la memoria viene allocata e cancellata manualmente con l'aiuto dei corrispondenti operatori new e delete. Significa che se si scrive new, ci deve essere la sua copia speculare di delete da qualche parte. Inoltre, il nuovo e l'eliminazione possono essere situati in parti diverse del programma, per esempio, in metodi diversi:

Se, dopo aver chiamato foo_analize, gli oggetti sono ancora necessari, l'operatore di cancellazione può essere messo da qualche altra parte, dove gli oggetti sono garantiti essere necessari. Un tale luogo universale può essere OnDeinit, per esempio, che viene chiamato prima della chiusura del programma.

Ricordate la cosa principale, Se c'è un operatore nuovo, ci deve sempre essere un operatore di cancellazione per esso. Altrimenti ci saranno perdite di memoria. Gli operatori new e delete che lavorano con lo stesso oggetto non devono essere "affiancati" nello stesso metodo. La cancellazione può essere ovunque lontano dall'allocazione di memoria, purché la cancellazione abbia un riferimento all'oggetto allocato nell'heap.

** Anche se questo è vero, è meglio evitare tali costrutti perché dobbiamo sempre stare molto attenti a dove e in quali circostanze viene chiamato l'operatore di cancellazione, che non è sempre ovvio. Invece, devi solo imparare a usare le classi. La classe permette di posizionare e cancellare automaticamente gli oggetti sull'heap, senza usare gli operatori new e delete:

Questa classe non contiene esplicitamente dei puntatori. Quindi non c'è bisogno di usare sia new che delete. Dopo l'uscita del programma, la classe libererà automaticamente tutti gli oggetti CItem e CArrayObj, il che rende la vita più facile allo sviluppatore.

Grazie. Ma non ho trovato una risposta alla mia domanda. Dove devo mettere la cancellazione se dichiaro un puntatore. Ripeto, l'oggetto CArrayObj è dichiarato in una funzione... come posso cancellarlo in Deinit()?

Ma prima ho risolto il problema in questo modo. Prima di finire la funzione:


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:

Grazie. Non sono riuscito a trovare una risposta alla mia domanda esatta. Dove devo mettere la cancellazione se dichiaro un puntatore. Di nuovo, l'oggetto CArrayObj è dichiarato in una funzione... come posso cancellarlo in Deinit()?

Questo non è un club di telepati. Non hai allegato il tuo codice, quindi puoi decidere da solo dove mettere la cancellazione.

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

Non è corretto.

 
Salve. Per favore aiutatemi, ho configurato l'indicatore per inviare messaggi quando il prezzo raggiunge 400 pips, ma quando queste condizioni vengono raggiunte, mi vengono inviati un mucchio di messaggi. Come fare in modo che invii solo un messaggio. Grazie!
#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);
 }
//+------------------------------------------------------------------+