Toute question des nouveaux arrivants sur MQL4 et MQL5, aide et discussion sur les algorithmes et les codes. - page 600

 
Vasiliy Sokolov:

Ce n'est pas un club de télépathie. Vous n'avez pas joint votre code, c'est donc à vous de décider où placer la suppression.

Faux.

Eh bien, voici le code, de quoi avez-vous besoin d'autre ? Et si elle est incorrecte ?

Merci.

 
Artyom Trishkin:

Vous avez tout mélangé. Une mauvaise planification de la tâche est exactement ce qui conduit à ces conséquences.

Si des objets sont créés dans une classe, celle-ci doit les supprimer dans son destructeur à la fin du processus. D'autres classes, en revanche, avant d'obtenir un pointeur sur un objet, doivent vérifier sa validité. Et en principe, il ne devrait pas y avoir une telle relation entre les deux. C'est un peu un enchevêtrement. Compliqué n'est pas synonyme de qualité. Tout doit être transparent et traçable. D'abord et avant tout, pour vous.

Montrons le code à la place.

Ici, je lis quelques données d'un fichier au début du programme.

CCandlesOneRules candles_one_rules;

while(!FileIsEnding(file_handle))
     {
      CCandleCondition *candle_cond=new CCandleCondition();
      string_num++;      
      string str=FileReadString(file_handle);
      int len=StringLen(str);
      if(len<=0)
         continue;
      string cand_num_str="";
      string rule_str="";
      string rule_descr="";
      string shift_str="";
      string value_int_str="";
      string value_enum_str="";
      string status_str="";
      int start_ind=0;
      int status_ind=-1;
      //--- status
      for(int i=start_ind;i<len;i++)
        {
         ushort ch=StringGetCharacter(str,i);
         if(ch==Separator)
           {
            start_ind=i+1;
            break;
           }
         status_str+=CharToString((uchar)ch);
         status_ind=i;
        }      
      int status=(int)StringToInteger(status_str);
      if(!init_flag && status!=0)
         continue;
      //--- candle number
      for(int i=start_ind;i<len;i++)
        {
         ushort ch=StringGetCharacter(str,i);
         if(ch==Separator)
           {
            start_ind=i+1;
            break;
           }
         cand_num_str+=CharToString((uchar)ch);
        }      
      //--- rule    
      for(int i=start_ind;i<len;i++)
        {
         ushort ch=StringGetCharacter(str,i);
         if(ch==Separator)
           {
            start_ind=i+1;
            break;
           }
         rule_str+=CharToString((uchar)ch);
        }
      //--- shift
      for(int i=start_ind;i<len;i++)
        {
         ushort ch=StringGetCharacter(str,i);
         if(ch==Separator)
           {
            start_ind=i+1;
            break;
           }
         shift_str+=CharToString((uchar)ch);
        }
      //--- value
      for(int i=start_ind;i<len;i++)
        {
         ushort ch=StringGetCharacter(str,i);
         if(ch==Separator)
           {
            start_ind=i+1;
            break;
           }
         value_int_str+=CharToString((uchar)ch);
        }
      //--- rule description
      for(int i=start_ind;i<len;i++)
        {
         ushort ch=StringGetCharacter(str,i);
         if(ch==Separator)
           {
            start_ind=i+1;
            break;
           }
         rule_descr+=CharToString((uchar)ch);
        }
      //--- enum value 
      for(int i=start_ind;i<len;i++)
        {
         ushort ch=StringGetCharacter(str,i);
         if(ch==Separator)
           {
            start_ind=i+1;
            break;
           }
         value_enum_str+=CharToString((uchar)ch);
        }                  
      int candN=(int)StringToInteger(cand_num_str);
      int ruleN=(int)StringToInteger(rule_str);
      int shift=(int)StringToInteger(shift_str);
      candle_cond.Create(candN,ruleN,shift,value_int_str,rule_descr);
      if(CheckPointer(candle_cond))
        {
         if(candles_one_rules.AddCondition(GetPointer(candle_cond)))
           {
            if(StringToInteger(value_int_str)>0)
              {
               Print(__FUNCTION__+": candle one #: ",candle_cond.GetCandNumber(),", rule: ",candle_cond.GetRuleNumber(),", shift: ",candle_cond.GetShift(),", description: ",candle_cond.GetDescription(),", value: ",candle_cond.GetValueStr());
              }
            Print(__FUNCTION__+": size of condition: ",sizeof(candle_cond));
           }           
        }
     ...
    } 

Autrement dit, je crée un objet CCandleCondition *candle_cond à l'itération, puis je l'ajoute à la collection candles_one_rules.

Voici la méthode AddCondition de la classe CCandlesOneRules :

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool CCandlesOneRules::AddCondition(CCandleCondition *cond)
  {
   for(int i=0;i<Total();i++)
     {
      CCandleOneRules *candle_one_r=At(i);
      if(!CheckPointer(candle_one_r))
         continue;
      if(cond.GetCandNumber()!=candle_one_r.GetCandOneNumber())
         continue;
//--- if candle one rules object with the same candle one number as the new condition is found         
      for(int j=0;j<candle_one_r.Total();j++)
        {
         CCandleRule *candle_rule=candle_one_r.At(j);
         if(!CheckPointer(candle_rule))
            continue;            
         if(candle_rule.GetRuleNumber()!=cond.GetRuleNumber())
            continue;
//--- if candle rule with the same rule number as the new condition is found            
         for(int k=0;k<candle_rule.Total();k++)         
           {
            CCandleCondition *rule_cond=candle_rule.At(k);
            if(!CheckPointer(rule_cond))
               continue;
            if(rule_cond.GetShift()!=cond.GetShift())
               continue;
//--- if rule condition with the same shift as the new condition is found
//--- update rule condition               
            return candle_rule.Update(k,GetPointer(cond));
           }
//--- if rule condition with the same shift as the new condition not found
//--- add the new condition
         return candle_rule.Add(GetPointer(cond));
        }
//--- if rule with the same rule number as the new condition not found        
//--- create new rule
      CCandleRule *new_rule=new CCandleRule(cond.GetCandNumber(),cond.GetRuleNumber());
      new_rule.Add(GetPointer(cond));
      return candle_one_r.Add(GetPointer(new_rule));
     }
//--- if candle one rules object with the same candle one number as the new condition not found
//--- create new candle one rule object
   if(cond.GetCandNumber()>m_candles_one_total)
      m_candles_one_total=cond.GetCandNumber();
   CCandleOneRules *new_cand_one_r=new CCandleOneRules(cond.GetCandNumber());
   CCandleRule *new_rule=new CCandleRule(cond.GetCandNumber(),cond.GetRuleNumber());
   new_rule.Add(GetPointer(cond));
   new_cand_one_r.Add(GetPointer(new_rule));
   return Add(GetPointer(new_cand_one_r));
//--- 
  }

CCandleRule est juste une classe conteneur pour les conditions. J'ajoute des conditions aux règles et des règles à CCandlesOneRules, qui à son tour, à CCandlesOneRules.....

Mais cette boucle while échoue au démarrage et se bloque avec une erreur de mémoire insuffisante. Et ces conditions ne sont pas très nombreuses, seules 7 sont lues avant de s'arrêter. Si nous réduisons le nombre de données dans le fichier lu, il fonctionne, sans aucune erreur, sans objets non supprimés, etc.

 
Excusez-moi. Nombre d'objets CCandleCondition (classe simple héritée de CObject) 91831. Après ça, plus de mémoire.
 
Juer:

Voyons un peu mieux le code.

Je commence à perdre patience.

new_cand_one_r.Add(GetPointer(new_rule));
return Add(GetPointer(new_cand_one_r));

Où se trouve la définition de la méthode Add ?

A en juger par le code, vous ne comprenez absolument pas ce que vous faites.

 
Vasiliy Sokolov:

Je commence à perdre patience.

Où se trouve la définition de la méthode Add ?

À en juger par le code, vous ne comprenez pas du tout ce que vous faites.

CCandleOneRules, CCandlesOneRules, CCandleRule sont toutes des classes héritées de CArrayObj.

A en juger par vos réponses génériques, vous ne comprenez pas mes questions. En ce qui concerne le tableau avec CArrayObj, vous n'avez toujours pas répondu correctement. Une fois de plus, je vais répéter ce problème. Il existe une classe, dans la méthode class, les objets globaux de la classe sont ajoutés au tableau (objet de type CArrayObj), qui est déclaré là dans cette méthode. Dans cette méthode, certaines actions sont effectuées dans ce tableau. A la fin, l'objet tableau n'est pas nécessaire, ce sont les membres du tableau qui sont nécessaires. Comment se débarrasser correctement de cet objet tableau, en conservant les membres du tableau ? Si vous ne vous en débarrassez pas, vous obtiendrez un message du type "objets non supprimés" dans le journal. Je vous ai donné ma solution, vous l'avez mal formulée. Comment est-ce correct ? Comment puis-je placer la suppression dans OnDeinit (ou dans la méthode Deinit de la classe qui sera appelée depuis OnDeinit), si cet objet tableau n'est visible que dans la méthode de la classe ?

De plus, si les objets ne sont supprimés que dans OnDeinit, vous pouvez également vous retrouver à court de mémoire...

 

Bonjour chers collègues.

Veuillez m'aider à répondre à cette question. Où dois-je utiliser la fonction ArraySetAsSeries() pour spécifier l'ordre de numérotation des éléments dans le tampon de l'indicateur ? Dans les indicateurs, qui sont préinstallés dans le terminal, j'ai souvent observé qu'il est utilisé à l'intérieur de OnCalculate(). Mais le tampon indicateur est déclaré globalement. N'est-il pas logique d'utiliser ArraySetAsSeries() dans OnInit() pour un appel unique dans ce cas ? Ou bien, en raison du réapprovisionnement du tampon de l'indicateur avec de nouveaux éléments, l'ordre de numération peut être perdu et il est nécessaire d'appeler ArraySetAsSeries() à chaque fois dans OnCalculate() ? Je veux écrire un code optimal sans appels de fonctions inutiles, quand ce n'est pas nécessaire. Je serai reconnaissant pour toute aide.

 
Oleg Remizov:

Bonjour chers collègues.

Veuillez m'aider à répondre à cette question. Où dois-je utiliser la fonction ArraySetAsSeries() pour spécifier l'ordre de numérotation des éléments dans le tampon de l'indicateur ? Dans les indicateurs, qui sont préinstallés dans le terminal, j'ai souvent observé qu'il est utilisé à l'intérieur de OnCalculate(). Mais le tampon indicateur est déclaré globalement. N'est-il pas logique d'utiliser ArraySetAsSeries() dans OnInit() pour un appel unique dans ce cas ? Ou bien, en raison du réapprovisionnement du tampon de l'indicateur avec de nouveaux éléments, l'ordre de numération peut être perdu et il est nécessaire d'appeler ArraySetAsSeries() à chaque fois dans OnCalculate() ? Je veux écrire un code optimal sans appels de fonctions inutiles, quand ce n'est pas nécessaire. Je vous serai reconnaissant de m'aider.

IMHO, j'écrirais des indicateurs sans ces fonctions du tout (si à partir de zéro, bien sûr). Pour les tampons - dans OnInit(), pour les séries chronologiques - dans OnCalculate().

Et, afin de parler de code optimal, vous devez savoir combien de temps cette fonction prend pour s'exécuter. Ainsi, le profileur devrait passer en premier, et seulement ensuite les questions de performance.

 
Alexey Kozitsyn:

À mon avis, j'écrirais des indicateurs sans ces fonctions du tout (en partant de zéro, bien sûr). Mais pour les tampons - dans OnInit(), pour les séries chronologiques - dans OnCalculate().

Et, afin de parler de code optimal, vous devez savoir combien de temps cette fonction prend pour s'exécuter. Ainsi, le profileur devrait passer en premier, et seulement ensuite les questions de performance.

C'est la conclusion vers laquelle je tendais. Merci pour le conseil.

 

Bon après-midi. J'ai une question : pourquoi, lorsque j'applique les barres de bolinger au MACD, je prends les valeurs de la ligne de signal et non l'histogramme lui-même ?

 
Виктор:

Bon après-midi. J'ai une question : pourquoi lorsque j'applique les barres de bolinger à MACD, je prends les valeurs de la ligne de signal et non l'histogramme lui-même ?

Avez-vous la possibilité de spécifier le tampon graphique à utiliser pour le calcul ?

Raison: