Вопросы по ООП в MQL5 - страница 28

 
Dmitry Fedoseev:

А если не использовать классы, то замучаешься от постоянного написания чего-нибудь типа SymbolInfoDouble(_Symbol,MODE_BID). Такое вытанцовывание каждый раз - и скобки и подчеркивание и не знаешь, нажимать ли капслок (а потом где-то в другом месте не глядя набрать целую строку заглавными буквами и перепечатывать ее) или держать шифт прижатый. Хотя бы в этом ООП полезен. Если, как минимум, сделать классы для всех этих функция, то да - они громадные. Если для себя писать, то не проблема. По работе с ордерами - часто используемых функция не так уж много, можно  просто несколько функций в библиотеку сложить. Но в общем, пока никак не складывается идеальный подход.  

ну как бы не совсем и не много, я бы сказал довольно прилично нужно выполнить действий для установки ордера, вот мое видение для класа который умеет открыть/закрыть/выставить стоплосс/и в дальнейшем выдавать состояние ордера

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

и заметьте, что чтобы для использования на одном символе - специально статический класс испольную

в целом все работает как задумано.... но не нравится мне это, как писал выше по моему громоздко и лишнего нет

 
Dmitry Fedoseev:

А если не использовать классы, то замучаешься от постоянного написания чего-нибудь типа SymbolInfoDouble(_Symbol,SYMBOL_BID). Такое вытанцовывание каждый раз ...

Можно же сделать более удобные и лаконичные обёртки для этих функций, оставаясь при этом в рамках процедурного стиля.  Особенно с учётом того, что в последних билдах наконец добавили namespace, то вообще ляпота.  Раньше приходилось реализовывать в виде статических методов, теперь всё значительно упростилось:

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

Можно же сделать более удобные и лаконичные обёртки для этих функций, оставаясь при этом в рамках процедурного стиля.  Особенно с учётом того, что в последних билдах наконец добавили namespace, то вообще ляпота.  Раньше приходилось реализовывать в виде статических методов, теперь всё значительно упростилось:

А это принципиально важно - оставаться в каких-то рамках? Если важно оставаться в рамках - то можно и функции написать. 

 
Igor Makanu:

ну как бы не совсем и не много, я бы сказал довольно прилично нужно выполнить действий для установки ордера, вот мое видение для класа который умеет открыть/закрыть/выставить стоплосс/и в дальнейшем выдавать состояние ордера

и заметьте, что чтобы для использования на одном символе - специально статический класс испольную

в целом все работает как задумано.... но не нравится мне это, как писал выше по моему громоздко и лишнего нет

Да, тут вот еще один вопрос постоянно возникающий и не имеющий однозначного ответа. Когда возникает необходимость наследовать собственный класс - что лучше сделать, наследовать его или написать новую расширенную версию своего класса.

 
Alexey Navoykov:

Можно же сделать более удобные и лаконичные обёртки для этих функций, оставаясь при этом в рамках процедурного стиля.  Особенно с учётом того, что в последних билдах наконец добавили namespace, то вообще ляпота.  Раньше приходилось реализовывать в виде статических методов, теперь всё значительно упростилось:

у Вас не лаконичная запись, если проверок нет, то проще писать как есть:

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

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

и заметьте, что чтобы для использования на одном символе - специально статический класс испольную

Что мешает передавать в конструктор название символа, сделав класс гибким и универсальным?  Возможность портфельной торговли принципиально не рассматриваете?
 
Igor Makanu:

у Вас не лаконичная запись, если проверок нет, то проще писать как есть:

Функций типа SymbolInfoDouble очень много. Замучаешься придумывать короткие имена для всех.  Собирая их в классы, совсем не нужно беспокоиться об уникальности имен.

 

У меня следующая схема, где проблем не испытывал.

  1. Пишу ТС только для Тестера. Логи, обработчики ошибок и прочая муть отсутствуют. Код получается очень лаконичный, понятный и поддатливый на правки, если делать через ООП (но не принципиально). В КБ пример выкладывал. Бонус - быстрая оптимизация.
  2. Главное, чтобы для Тестера и чтобы по независимым блокам было раскинуто. Формирование торговых сигналов - один блок. Проторговка сигнала - другой.
  3. Перевод на реал делается всегда в несколько одних и тех же движений. ТС без правки кода помещается в виртуальное окружение. Можно сразу несколько ТС в одно окружение или каждую ТС в свое, тогда ООП становится особенно удобен. Далее берется копир (в Маркете их полно, так что народ руку набил на копир-логике), который просто копирует сделки/ордера с виртуалки в реал.
  4. При такой схеме написание ТС - быстрое и понятное занятие. Перевод на реал (а это редкость на самом деле) делается всегда однообразно, быстро и четко.
 
Igor Makanu:

у Вас не лаконичная запись, если проверок нет, то проще писать как есть:

Так не делается. Нужно как минимум вызывать как Bid() и Ask().  У вас выглядит как просто переменная, создавая видимость что её значение сохраняется неизменным, хотя в реальности это не так.
 
Alexey Navoykov:
Что мешает передавать в конструктор название символа, сделав класс гибким и универсальным?  Возможность портфельной торговли принципиально не рассматриваете?

Мешает то, что в основном пишутся односимвольные советники, а передача символа - это будет лишним (и изнуряющим))) действием в большинстве случаев. Другое дело - сделать так, что бы по умолчанию автоматически выбирался символ графика, а при необходимости можно было на время переопределить символ. Но опять возникает вопрос, что лучше - использовать один экземпляр класса и по необходимости переопределять символ, или для каждого символа создавать свой экземляр.

Причина обращения: