Plans de développement pour le testeur de stratégie MetaTrader 5 - page 8

 
Aliaksandr Hryshyn:
Je me demande, combien de personnes utilisent des commentaires pour les fonctions (classes, structures...) en utilisant exactement ce design à gauche ?

Je l'utilise très souvent et de manière dense (il est vrai que je ne le formate pas en "carrés", je l'écris "juste comme ça".

Voici le fichier d'interface de mon historique d'enchères actuel. Et ce n'est pas le nombre maximum de commentaires.

// СTradeHistoryI переносимый интерфейс торговой истории 

// История состоит из компонент-наследников интерфейса CHistoryPosComponentI
// 
// Реально для МТ4 имплементацией интерфейса является объект CMT4TradeHistory, для МТ5 - объект CMT5TradeHistory
// CMT4TradeHistory представляет из себя массив объектов CMT4HistoryOrderInfo, наследников интерфейса CHistoryPosComponentI.
// Фактически это массив исторических МТ4-ордеров.
// CMT5TradeHistory представляет из себя массив объектов CMT5HistoryPositionInfoCore, наследников интерфейса CHistoryPosComponentI.
// Объект CMT5HistoryPositionInfoCore не имеет прямого аналога в МТ5-терминах, это два массива ордеров и сделок, а также структура данных,
// имеющуая идентификатор позиции (m_lPosID или POSITION_IDENTIFIER), тикет магик, вид позиции, и так далее, по аналогии с МТ4-ордером,
// фактически, массивы ордеров и сделок - это аналоги ордеров и сделок обычной неттинговой МТ5-позиции, а структура данных - относится
// к хеджевой позиции, и имеет аналог МТ4-ордера. 
//
// Реально при запросе у позиции компоненты CHistoryPosComponentI в МТ4 мы получаем указатель на ордер (класс CMT4HistoryOrderInfo),
// а в МТ5 - на ядро позиции (класс CMT5HistoryPositionInfoCore) 

#include <MyLib\DebugOrRelease\DebugSupport.mqh>
#include <MyLib\Common\MyObject.mqh>
#include <MyLib\Common\CurSymEnum.mq5>
#include <MyLib\Common\TrendEnums.mqh>
#include <MyLib\Trade\TradePosComponentI.mqh>
#include <MyLib\Trade\SortTradePosComponentT.mqh>

class CTSContainerI;

class CROTradeHistoryI: public CMyObject
{
public:

   void CROTradeHistoryI() {    SetMyObjectType(MOT_TRADE_READONLY_HISTORY_I); };
   virtual void ~CROTradeHistoryI() {};
   
   virtual uint GetTotalComponents() const = 0;  // Получение общего числа компонент
   virtual CHistoryPosComponentI* GetComponent(uint uiComponentIdx) const = 0;
   virtual CHistoryPosComponentI* GetOldestOpenComponent() const = 0; // Может вернуть NULL !!!
   virtual CHistoryPosComponentI* GetNewestCloseComponent() const = 0; // Может вернуть NULL !!!
   
   // Функция ищет внутри истории компоненту с указанным тикетом. 
   // В случае, если ее нет - возвращается false.
   // Если компонента найдена - возвращается true, и uiComponentIdx устанавливается на индекс компоненты внутри позиции.
   virtual bool FindComponentByTicket(long lTicket,uint &uiComponentIdx) const = 0;
   
   // Функция анализирует историю и возвращает символ, по которому совершены сделки.
   // Если все выбранные сделки имеют один и тот же символ - возвращается этот символ.
   // Если сделки имеют разные символы или сделок нет - возвращается CS_CURRENT.
   // Если хотя бы один символ CS_UNKNOWN  - возвращается CS_UNKNOWN
   virtual ECurrencySymbol GetSymbols() const = 0;
};


class CTradeHistoryI: public CROTradeHistoryI
{
public:
   void CTradeHistoryI() {    SetMyObjectType(MOT_TRADE_HISTORY_I); };
   virtual void ~CTradeHistoryI() {};
   
   // Выбор существующей истории. 
   // Указывается магик и символ, по которому выбираются исторические ордера, а также промежуток времени, в котором необходимо искать их.
   // Если ulMagic = 0 - выбираются все позиции по всем магикам.
   // Если ECurrencySymbol = CS_UNKNOWN - выбираются все позиции по всем символам
   // Если ECurrencySymbol = CS_CURRENT - запрашивается функция Symbol(), и выбираются все позиции по этому символу
   // ptcTSContainer - указатель на контейнер таймсерий, по которому можно определять просад для каждой позиции. Может быть NULL, в этом случае просад устанавливается нулевым.
   // Возвращает число компонент позиции внутри истории (может быть нулевым если ничего не найдено) или WRONG_VALUE в случае ошибок
   // NOTE !!! 
   // При выборе - отложенные ордера не учитываются.
   virtual int Select(ulong ulMagic = 0,ECurrencySymbol csSymbol = CS_CURRENT,datetime dtFrom = MIN_DATETIME,datetime dtTill = NEVER_EXPIRES,CTSContainerI* ptcTSContainer = NULL) = 0;

   
   // Расширенный интерфейс
   virtual void Sort(ESortTPCMode stmMode = STM_BY_OPEN_TIME_A) = 0;
};


En général, plus la classe est spécifique, plus elle doit comporter de commentaires.

Eh bien, à moins d'avoir une méga-mémoire, comme Peter Konov, vous pouvez vous passer des commentaires.


 
Nikolai Semko:

Oui, qui aime ce qu'il aime. Personnellement, je ne peux pas voir le code si bien formaté que je ne peux pas voir le code lui-même.

La maîtrise deVisual Studio Code serait peut-être une bonne solution.

Heh heh heh... Je suis confus quand "vous ne pouvez pas voir la forêt pour les arbres".

Rien que dans ce fragment - tout semble être correct, mais sans un seul commentaire, et comme ce "carambolage", sans omissions, bon sang, comme c'est difficile à comprendre...

 
Roman:

Je supprime immédiatement ce genre de commentaires, car ils encombrent les yeux et j'écris ainsi

Là-bas ! Oui.

Pour les fonctions courtes et simples, le style de commentaire le plus normal, à mon avis.

 

Je vais mettre mes cinq cents.

Quant au formatage. Vous devez saisir plusieurs styles. L'un est celui de MQ. Je propose celle-ci :

if(.....)
{
   ..............
}
else
if(.........)
{
   ......
   for(.....)
   {
      .....
   }
)
else   ......
 
Сергей Таболин:

Je vais mettre mes cinq cents.

Quant au formatage. Vous devez saisir plusieurs styles. L'un est celui de MQ. Je propose celle-ci :

Je n'aime pas la plupart des parenthèses dans le style actuel. Je ne comprends pas pourquoi ils les ont déplacés. J'aligne toujours toutes les accolades sur la tabulation, comme dans votre exemple.

 
Georgiy Merts:

Je l'utilise très souvent et de manière dense (il est vrai que je ne le formate pas en "carrés", je l'écris "juste comme ça".

Voici le fichier d'interface de mon historique d'enchères actuel. Et ce n'est pas le nombre maximum de commentaires.


En général, plus une classe est spécifique, plus elle doit comporter de commentaires.

À moins d'avoir une méga-mémoire comme Peter Konov, vous pouvez vous passer des commentaires.


Le mien est similaire, mais avec moins de commentaires :).

//Использование модели
class Catboost
  {
private:
   static int        lng_id;//
public:
   //Правило сплита: предиктор больше указанного значения(true/false)
   struct sSplit_rule
     {
      uint              predictor_id;  //Индекс предиктора
      double            border;        //С чем сравнивается он
     };
   //Набор правил, при соответствии которым получим результат листа leaf
   struct sLeaf
     {
      double            leaf;          //Значение листа
      sSplit_rule       split_rules[]; //Набор правил
     };
   uint              TreeDepth[];      //Глубины деревьев, глубина означает колчиство правил. В каждом правиле используется один бинарный признак.
   uint              TreeSplits[];     //Какие бинарные признаки использует каждое дерево
   uint              BorderCounts[];   //На сколько бинарных признаков будет разбит каждый предиктор
   float             Borders[];        //Пороговые значения для всех предикторов, они определяют значения бинарных признаков(0/1). Если предиктор выше значения в массиве, будет 1, иначе 0.
   double            LeafValues[];     //Результаты деревьев для каждого сочетания используемых бинарных признаков
   uint              features_pos[];   //Откуда взялась бинарная фича.Указывается индекс.

                    ~Catboost(void);
                     Catboost();
   //Создание экземпляра класса (инициализация конкретной модели)
                     Catboost(uint &TreeDepth_[],uint &TreeSplits_[],uint &BorderCounts_[],float &Borders_[],double &LeafValues_[]);
   //Приеменение модели
   //features     -предикторы
   double            ApplyCatboostModel(const double &features[]);
   //Приеменение модели.Модель передаётся через массивы
   static double     ApplyCatboostModel(const double &features[],uint &TreeDepth_[],uint &TreeSplits_[],uint &BorderCounts_[],float &Borders_[],double &LeafValues_[]);
   //Применение модели с сохранением данных о влиянии предикторов на результат
   double            ApplyCatboostModel_data(const double &features[],datetime time);

   long              data_counter;           //Счётчик выполнения функции ApplyCatboostModel_data
   CSV               *csv_tree_rules;        //Сюда сохраняются все сработанные правила, результаты деревьев
   CSV               *csv_model_rules;       //Сюда сохраняются правила, которые сработали во всей модели.перекрывающиеся правила будут удаляться
   //Перобразование модели CatBoost с исходников C++ в MQL
   static bool       CatBoost_model_to_MQL(string input_file_cpp,string output_file_mql);
   //Чтение модели с файла исходника C++
   bool              Model_read_from_file(string input_file_cpp);
   //Получение полного списка правил для каждого листа leaf_rules_out
   void              Get_leaf_rules(sLeaf &leaf_rules_out[]);
  };
int Catboost::lng_id=cLng::Set_users_errors_messages("Catboost",Catboost_lngs,Catboost_strings);

"Le fait d'étaler des commentaires sur toute la liste, comme cela est supposé être le cas, n'est pas à mon goût.

Ce serait bien s'il y avait une option pour désactiver cette fonction :

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+

Pouvez-vous me dire exactement comment vous y mettez des commentaires ? L'éditez-vous manuellement ? Y a-t-il une combinaison secrète ?

 

Voici la situation :

J'optimise dans un testeur de stratégie, à la fin, OnTesterDeinit() est exécuté pour analyser les résultats, ou simplement pour collecter des données. À ce moment, le testeur de stratégie passe à l'état comme si tout était terminé, mais à ce moment, le traitement final des données peut encore avoir lieu en arrière-plan pendant un long moment. Lorsque la fenêtre avec le graphique des symboles est fermée, le conseiller expert sera fermé de force.

Décrivons également la situation où OnTesterDeinit() écrit dans un fichier : en pensant que l'optimisation actuelle est terminée, nous commençons la suivante avec des plages minimales de paramètres qui sont rapidement calculées. Le résultat est que l'exécution précédente n'est pas terminée et que la nouvelle exécution est au même stade, dans notre exemple, cela conduit à une erreur d'accès en écriture aux fichiers, ou simplement à des erreurs dans les fichiers, et visuellement, ce n'est pas traçable, seulement par le gestionnaire de charge ou le fichier..... J'aimerais pouvoir voir dans le testeur que cette opération n'est pas encore terminée.

 
Aliaksandr Hryshyn:

Voici la situation :

J'optimise dans un testeur de stratégie, à la fin, OnTesterDeinit() est exécuté pour analyser les résultats, ou simplement pour collecter des données. À ce moment, le testeur de stratégie passe à l'état comme si tout était terminé, mais à ce moment, le traitement final des données peut encore avoir lieu en arrière-plan pendant un long moment. Lorsque la fenêtre avec le graphique des symboles est fermée, le conseiller expert est fermé de force.

Décrivons également la situation où OnTesterDeinit() écrit dans un fichier : en pensant que l'optimisation actuelle est terminée, nous commençons la suivante avec des plages minimales de paramètres qui sont rapidement calculées. Le résultat est que l'exécution précédente n'est pas terminée et que la nouvelle exécution est au même stade, dans notre exemple, cela conduit à une erreur d'accès en écriture aux fichiers, ou simplement à des erreurs dans les fichiers, et visuellement, ce n'est pas traçable, seulement par le gestionnaire de charge ou le fichier..... Je voudrais pouvoir voir dans le testeur que cette opération n'est pas encore terminée.

Lors de l'optimisation, une nouvelle fenêtre graphique s'ouvre - peut-on utiliser l'identifiant du graphique pour connaître la fin de l'opération ? Il semble qu'il y ait une option pour fermer le graphique, puis après la fin des calculs dans OnTesterDeinit() la fenêtre peut être fermée et finalement nous devons juste surveiller la présence du graphique ouvert au début de l'optimisation, dès qu'il a disparu - le testeur est prêt pour une nouvelle optimisation.

 
Aleksey Vyazmikin:

Lorsque l'optimisation ouvre une nouvelle fenêtre graphique - y a-t-il un moyen de connaître la fin du travail par l'identifiant du graphique ? Il semble qu'il y ait une option pour fermer le graphique, puis après la fin des calculs dans OnTesterDeinit() la fenêtre peut être fermée, et à la fin nous devons juste surveiller la présence du graphique ouvert au début de l'optimisation, quand il a disparu - le testeur est prêt pour une nouvelle optimisation.

Ce code doit donc être modifié, mais que faire si cette possibilité n'existe pas ?

 
Aliaksandr Hryshyn:

Vous devez donc modifier le code, mais si vous ne pouvez pas le faire ?

Alors il n'y a pas de solution. Il s'agit d'une situation controversée : d'une part, l'optimiseur est libre et prêt à poursuivre son travail, mais d'autre part, il peut y avoir un chevauchement - la décision dépend de la situation.