Questions on OOP in MQL5 - page 28

 
Dmitry Fedoseev:

And if you don't use classes, you get tired of constantly writing something like SymbolInfoDouble(_Symbol,MODE_BID). Such dances every time - both brackets and underscore, and you don't know whether to press the capslock (and then somewhere else without looking, type an entire capitalized string and retype it) or keep the shifter pressed. At least that's where OOP is useful. If at least make classes for all these functions, then yes - they are huge. If you write it for yourself, it's not a problem. As for working with orders, there are not so many frequently used functions, we can simply put a few functions into a library. But in general, an ideal approach has not yet been found.

Here is my vision of the class which can open/close/set stop loss and later displayorder status

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();};
//________________________________

and note the use on one symbol - specially a static class to use

all in all, everything works as intended.... but i don't like it, as i wrote above it is cumbersome and superfluous

 
Dmitry Fedoseev:

And if you don't use classes, you'll get tired of constantly writing something like SymbolInfoDouble(_Symbol,SYMBOL_BID). This dances every time ...

You could make more convenient and concise wrappers for these functions, while keeping them in procedural style. Especially taking into account the fact that in recent builds they finally added namespace, everything is great. Before you had to implement them as static methods, but now everything is much easier:

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

You can make more convenient and concise wrappers for these functions, while still staying within the procedural style. Especially since they finally added namespace in the latest builds, that's great. Before, you had to implement them as static methods, but now everything is much simpler:

Is it really important to stay within limits? If it is important to stay within boundaries, you can write functions, too.

 
Igor Makanu:

well, not much, i would say quite a lot of actions to set an order, here's my vision for a class that knows how to open/close/set stoploss/and further output order status

and note the use on one symbol - specially a static class to use

all in all, everything works as intended.... but i do not like it, as i wrote above it is cumbersome and superfluous

Yes, here's another question that keeps coming up and doesn't have an unambiguous answer. When you need to inherit your own class - what's better to do, inherit it or write a new extended version of your class.

 
Alexey Navoykov:

It is possible to make more convenient and concise wrappers for these functions, while still staying within the procedural style. Especially since they finally added namespace in the latest builds, that's great. Before, you had to implement them as static methods, now things are much simpler:

You don't have a succinct notation, if there are no checks, it's easier to write as is:

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

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

and note that to be used on a single character - specifically a static class used

What prevents you from passing the symbol name to the constructor, making the class flexible and versatile? You don't consider the possibility of portfolio trading as a matter of principle?
 
Igor Makanu:

Your entry is not succinct, if there are no checks, it's easier to write as is:

There are a lot of functions like SymbolInfoDouble. It's a hassle to come up with short names for all of them. By assembling them into classes, you don't have to worry about uniqueness of names at all.

 

I have the following circuit where I have had no problems.

  1. I write TC only for Tester. No logs, error handlers or any other crap. The code is very concise, understandable and amenable to edit, if done through OOP (but not fundamental). I have already posted the example in KB. The bonus is the fast optimization.
  2. The main thing is that it should be available for the tester and in independent blocks. The generation of trading signals - one block. Signal trading - another block.
  3. The transfer to the real account is always done in several one and the same moves. The TS is placed in a virtual environment without any code changes. Several TS may be placed in one environment or each TS in its own environment, then the OOP becomes especially convenient. Then we take a copier (the Market is full of them, so people are good at copier-logic), which simply copies deals/orders from the virtual environment to the real one.
  4. With this scheme, writing TS is quick and easy. The transfer to real (which is rare in fact) is always done in a uniform, quick and clear manner.
 
Igor Makanu:

your entry is not succinct, if there are no checks, it is easier to write it as it is:

That's not how it's done. You need at least to call both Bid() and Ask(). Your entry looks like just a variable, giving the appearance that its value is unchanged, when in reality it is not.
 
Alexey Navoykov:
What prevents you from passing the name of the symbol to the constructor, making the class flexible and versatile? Do you fundamentally not consider the possibility of portfolio trading?

What hinders this is that mostly one-character EAs are written, and passing a symbol would be an unnecessary (and exhausting))) action in most cases. Another thing is to make it so that the chart symbol is automatically selected by default, and if necessary, you can override the symbol for a while. But again the question arises, which is better - to use one instance of the class and override the symbol as needed, or to create a separate instance for each symbol.