Questions sur la POO dans MQL5 - page 28

 
Dmitry Fedoseev:

Et si vous n'utilisez pas de classes, vous vous fatiguez à écrire constamment quelque chose comme SymbolInfoDouble(_Symbol,MODE_BID). Cela danse à chaque fois - à la fois les parenthèses et le soulignement, et vous ne savez pas si vous devez appuyer sur la touche de verrouillage des majuscules (et ensuite, sans regarder ailleurs, taper toute une chaîne en majuscules et la retaper) ou garder la manette enfoncée. C'est du moins là que la POO est utile. Si l'on fait au moins des classes pour toutes ces fonctions, alors oui - elles sont énormes. Si vous l'écrivez pour vous-même, ce n'est pas un problème. En ce qui concerne le travail avec les commandes, il n'y a pas tant de fonctions fréquemment utilisées, nous pouvons simplement mettre quelques fonctions dans une bibliothèque. Mais en général, une approche idéale n'a pas encore été trouvée.

Voici ma vision de la classe qui peut ouvrir/fermer/définir le stop loss et plus tard afficher lestatut de l'ordre.

class CConstVolume
{
protected:
   static const double  VolumeMAX;
   static const double  VolumeMIN;
   static const double  VolumeSTEP;
   static const double  ZerroPrice;
   static const int     VolumeDIGITS;
   static int           GetDigitsInVolumeStep(); };
//___________________________________________________________________________
static int CConstVolume::GetDigitsInVolumeStep()
{  int result = 0;
   long i = 10000000, k = long(::SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP) / 0.0000001);
   while(result < 7 && k % i > 0)
   {  i /= 10;
      result++; }
   return(result); }
//____________________________________________________________________
static const double CConstVolume::VolumeMAX = ::SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);
//____________________________________________________________________
static const double CConstVolume::VolumeMIN = ::SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
//____________________________________________________________________
static const double CConstVolume::VolumeSTEP = ::SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);
static const double CConstVolume::ZerroPrice = ::NormalizeDouble(0.0, _Digits);
//____________________________________________________________________
static const int CConstVolume::VolumeDIGITS = CConstVolume::GetDigitsInVolumeStep();
//____________________________________________________________________




//+------------------------------------------------------------------+
//|   class COrder                                                   |
//+------------------------------------------------------------------+
class COrder : private CConstVolume
{
private:
   SOrderInfo        m_info;        //структура для инициализации класса, и хранения информации о ордере, тип, цена отркытия, лот, и состояние ордера
   CError            error;         //класс с описание ошибок на 2-х языках
   int               sl_error_count;//счетчик ошибок установки стоплосса/тейка
   bool              m_needstoploss;//флаг для установки стоплосса, сбросим когда все ОК
   bool              CheckMarginRequirements();
   bool              ServerDisable();
   int               Ordersend();
   int               CheckOrderByMagicnumber(int magic_);   //метод нужен для поиска открытого ордера по магику, использую в конструкторе
   void              SetStoploss();
   void              NULLOrder()             { ZeroMemory(m_info); m_info.cmd = -1; m_info.status = ErrorOrder; m_needstoploss = false;   }
   void              PrintError(string func) { Print(func); error.GetLastError();                                                         }
public:
                     COrder():m_needstoploss(false) { NULLOrder();                                                                        }
                     COrder(SOrderInfo &ordersetting);
   SOrderInfo        GetOrderInfo(); 
   bool              Orderclose();};
//________________________________

et notez l'utilisation sur un symbole - spécialement une classe statique à utiliser

dans l'ensemble, tout fonctionne comme prévu.... mais je n'aime pas ça, comme je l'ai écrit plus haut c'est encombrant et superflu

 
Dmitry Fedoseev:

Et si vous n'utilisez pas de classes, vous en aurez assez d'écrire constamment quelque chose comme SymbolInfoDouble(_Symbol,SYMBOL_BID). Cela danse à chaque fois...

Vous pourriez faire des enveloppes plus pratiques et plus concises pour ces fonctions, tout en les gardant dans le style procédural. Surtout en tenant compte du fait que dans les constructions récentes, ils ont finalement ajouté l'espace de noms, tout est génial. Avant, vous deviez les mettre en œuvre comme des méthodes statiques, mais maintenant tout est beaucoup plus facile :

namespace SymbolInfo
{
  double Bid(string symbol) { return SymbolInfoDouble(symbol, SYMBOL_BID); }
  double Ask(string symbol) { return SymbolInfoDouble(symbol, SYMBOL_ASK); }
};
 
Alexey Navoykov:

Vous pouvez créer des enveloppes plus pratiques et plus concises pour ces fonctions, tout en restant dans le style procédural. Surtout depuis qu'ils ont enfin ajouté l'espace de noms dans les dernières versions, c'est génial. Avant, vous deviez les implémenter comme des méthodes statiques, mais maintenant tout est beaucoup plus simple :

Est-il important de rester dans les limites ? S'il est important de rester dans les limites, vous pouvez également écrire des fonctions.

 
Igor Makanu:

Eh bien, pas beaucoup, je dirais qu'il y a beaucoup d'actions pour définir un ordre, voici ma vision d'une classe qui sait comment ouvrir/fermer/définir le stoploss/et ensuite sortir le statut de l'ordre.

et notez l'utilisation sur un symbole - spécialement une classe statique à utiliser

dans l'ensemble, tout fonctionne comme prévu.... mais je n'aime pas ça, comme je l'ai écrit plus haut c'est encombrant et superflu

Oui, voici une autre question qui revient sans cesse et qui n'a pas de réponse univoque. Lorsque vous devez hériter de votre propre classe, qu'est-ce qui est le mieux à faire, en hériter ou écrire une nouvelle version étendue de votre classe.

 
Alexey Navoykov:

Il est possible de faire des enveloppes plus pratiques et plus concises pour ces fonctions, tout en restant dans le style procédural. D'autant plus qu'ils ont finalement ajouté l'espace de noms dans les dernières versions, c'est génial. Avant, vous deviez les implémenter comme des méthodes statiques, maintenant les choses sont beaucoup plus simples :

Vous n'avez pas de notation succincte, s'il n'y a pas de contrôles, il est plus facile d'écrire tel quel :

#define  Ask SymbolInfoDouble(_Symbol,SYMBOL_ASK)
#define  Bid SymbolInfoDouble(_Symbol,SYMBOL_BID)

void OnStart()
  {
   Print("Ask = ",Ask);
   Print("Bid = ",Bid);
  }
 
Igor Makanu:

et notez que pour être utilisé sur un seul caractère - spécifiquement une classe statique utilisée

Qu'est-ce qui vous empêche de passer le nom du symbole au constructeur, rendant ainsi la classe flexible et polyvalente ? Vous n'envisagez pas par principe la possibilité de faire du trading de portefeuille ?
 
Igor Makanu:

Votre entrée n'est pas laconique, s'il n'y a pas de contrôles, il est plus facile d'écrire tel quel :

Il y a beaucoup de fonctions comme SymbolInfoDouble. En les regroupant en classes, vous n'avez pas à vous soucier de l'unicité des noms.

 

J'ai le circuit suivant où je n'ai eu aucun problème.

  1. J'écris TC seulement pour Testeur. Pas de journaux, de gestionnaires d'erreurs ou d'autres conneries. Le code est très concis, compréhensible et modifiable, s'il est fait par le biais de la POO (mais pas fondamental). J'ai déjà posté l'exemple dans KB. Le bonus est l'optimisation rapide.
  2. L'essentiel est qu'il soit disponible pour le testeur et dans des blocs indépendants. La génération de signaux de trading - un bloc. Le commerce des signaux - un autre bloc.
  3. Le transfert vers le compte réel se fait toujours en plusieurs fois. Le TS est placé dans un environnement virtuel sans aucune modification du code. Plusieurs TS peuvent être placés dans un seul environnement ou chaque TS dans son propre environnement, alors la POO devient particulièrement pratique. Ensuite, nous prenons un copieur (le marché en est rempli, les gens sont donc doués pour la logique du copieur), qui copie simplement les transactions/commandes de l'environnement virtuel à l'environnement réel.
  4. Avec ce système, la rédaction de TS est rapide et facile. Le transfert vers le réel (qui est rare en fait) se fait toujours de manière uniforme, rapide et claire.
 
Igor Makanu:

vous n'avez pas une entrée concise, s'il n'y a pas de contrôles, il est plus facile d'écrire tel quel :

Ce n'est pas comme ça que ça se passe. Vous devez au moins appeler à la fois Bid() et Ask(). Votre entrée ressemble à une simple variable, donnant l'apparence que sa valeur est inchangée, alors qu'en réalité ce n'est pas le cas.
 
Alexey Navoykov:
Qu'est-ce qui vous empêche de passer le nom du symbole au constructeur, rendant ainsi la classe flexible et polyvalente ? Ne considérez-vous pas fondamentalement la possibilité de faire du trading de portefeuille ?

Ce qui gêne, c'est que la plupart des EA sont écrites en un seul caractère, et que passer un symbole serait une action inutile (et épuisante)) dans la plupart des cas. Une autre possibilité est de faire en sorte que le symbole du graphique soit automatiquement sélectionné par défaut, et si nécessaire, vous pouvez remplacer le symbole pendant un certain temps. Mais une fois encore, la question se pose de savoir ce qui est le mieux : utiliser une instance de la classe et remplacer le symbole si nécessaire, ou créer une instance distincte pour chaque symbole.