Учёба. Классы. Нужна помощь. - страница 7

 
lynxntech #:

если код не одностраничный, то классы всегда в Include описывают, 

Можете дать пример такого инклудника с одним единственным классом. Пусть в нём будет всего 1 функция сложения 2 чисел.

 
Vitaly Murlenko #:

Можете дать пример такого инклудника с одним единственным классом. Пусть в нём будет всего 1 функция сложения 2 чисел.

Как раз в одном файле *.mqh (инклуднике) желательно объявлять или только один класс (с данными и методами), или только функции. Поэтому можно написать так:

class CSummator {
public:

   int Sum(int a, int b) { return a + b; }
}; 

А затем подключив этот файл к основной программе использовать метод класса CSummator:

void OnInit() {
    CSummator s;
    
    int res = s.Sum(3, 5);
    Print(res); // 8
}

Но для такой задачи использовать класс нет необходимости, поскольку нам не нужно запоминать никакие  значения, которые могут понадобится для последующих вызовов Sum(). Если каждый вызов функции использует только данные, передаваемые через параметры функции, то её нет необходимости делать методом какого-то класса. Поэтому вполне можно было обойтись таким включаемым файлом:

int Sum(int a, int b) { return a + b; }

И использовать его так:

void OnInit() {
   int res = Sum(3, 5);
   Print(res);
}

А вот если немного изменить задачу: написать функцию, которая возвращает кумулятивную сумму всех чисел, которые ей передавали, то уже появляется необходимость помнить последнюю вычисленную сумму, чтобы можно было найти следующую. Тут уже можно можно и класс написать:

class CSummator {
   int s; // Предыдущая сумма
public:
   // Конструктор
   CSummator() 
        : s(0) // Инициализируем 0 поле s создаваемого объекта класса 
        {}

   int Sum(int a) { 
      s += a; 
      return s; 
   }
};

И затем его использовать:

void OnInit() {
   CSummator s;
    
   s.Sum(3);

   int res = s.Sum(5);
   Print(res); // 8
 
   res = s.Sum(9);
   Print(res); // 17
}

В конечном счёте желательно писать код так, чтобы можно было его эффективно повторно использовать и было проще его понять. У каждого тут могут быть свои предпочтения. Но практика показывает, что использование ООП позволит легче реализовать в коде более сложные вещи.

 
Огромное спасибо. Вечером приду домой и меня ждёт приятное, мною ещё непаханное поле :)
 

Приветствую! В индикаторе 6буферов

#property copyright   "2005-2014, MetaQuotes Software Corp."
#property link        "http://www.mql4.com"
#property description "Stochastic_W"
#property strict
#define inp
#property indicator_separate_window
#property indicator_minimum    0
#property indicator_maximum    100
#property indicator_buffers    6
#property indicator_color1     LightSeaGreen
#property indicator_color2     Red
#property indicator_color3     clrLawnGreen
#property indicator_color4     clrDodgerBlue
#property indicator_color5     clrMediumVioletRed
#property indicator_color6     clrSeaGreen
#property indicator_level1     20.0
#property indicator_level2     80.0
#property indicator_levelcolor clrSilver
#property indicator_levelstyle STYLE_DOT
//--- input parameters
inp bool mal=true;
inp ENUM_MA_METHOD  mode;
input int InpKPeriod=5; // K Period
input int InpDPeriod=3; // D Period
input int InpSlowing=3; // Slowing
//---------------------------------------
input ENUM_TIMEFRAMES Wod=15;
inp ENUM_MA_METHOD  Wmode;
input int InpWKPeriod=5; // WK Period
input int InpWDPeriod=3; // WD Period
input int InpWSlowing=3; // WSlowing
//-------------------------------------------
input ENUM_TIMEFRAMES Hod=60;
inp ENUM_MA_METHOD  Hmode;
inp int InpHKPeriod=5; // HK Period
inp int InpHDPeriod=3; // HD Period
inp int InpHSlowing=3; // HSlowing
//------------------------------------
bool StochW=true;
//     minStoch=true;
//--- buffers
double MainBuffer[];
double SignalBuffer[];
double MainWbuffer[];
double SignalWbuffer[];
double MainHBuffer[];
double SignalHBuffer[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit(void)
  {
   string short_name;
//--- 2 additional buffers are used for counting.
   IndicatorBuffers(6);
//--- indicator lines
   SetIndexStyle(0,DRAW_LINE);
   SetIndexBuffer(0, MainBuffer);
   SetIndexLabel(0,"StochM00");
   SetIndexStyle(1,DRAW_LINE);
   SetIndexBuffer(1, SignalBuffer);
   SetIndexLabel(1,"StochaS00");
   SetIndexStyle(2,DRAW_LINE);
   SetIndexBuffer(2,MainWbuffer);
   SetIndexLabel(2,"StochaW");
   SetIndexStyle(3,DRAW_LINE);
   SetIndexBuffer(3,SignalWbuffer);
   SetIndexLabel(3,"StochaW");
   SetIndexStyle(4,DRAW_LINE);
   SetIndexBuffer(4,MainHBuffer);
   SetIndexLabel(4,"StochaH");
   SetIndexStyle(5,DRAW_LINE);
   SetIndexBuffer(5,SignalHBuffer);
   SetIndexLabel(5,"StochaH");
   
//--- name for DataWindow and indicator subwindow label
   short_name="StoWPure("+IntegerToString(InpKPeriod)+","+IntegerToString(InpDPeriod)+","+IntegerToString(InpSlowing)+")";
   IndicatorShortName(short_name);
   SetIndexLabel(0,short_name);
//--- initialization done
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Stochastic oscillator                                            |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {
   int   pos,per=0;
   double delta=0,res=0;
//--- check for bars count
   if(rates_total<=InpKPeriod+InpDPeriod+InpSlowing)
      return(0);
//--- counting from 0 to rates_total
   ArraySetAsSeries(MainBuffer,true);
   ArraySetAsSeries(SignalBuffer,true);
   ArraySetAsSeries(MainWbuffer,true);
   ArraySetAsSeries(SignalWbuffer,true);
   ArraySetAsSeries(MainHBuffer,true);
   ArraySetAsSeries(SignalHBuffer,true);
   per=_Period;
//--- signal--------------------------------------------------------
   pos=rates_total-prev_calculated;
   if(prev_calculated<=0)
      pos=rates_total-1;
   for(int i=0; i<=pos && !IsStopped(); i++)
     {
      if(mal==true)
        {
         MainBuffer[i]=iStochastic(Symbol(),per,InpKPeriod,InpDPeriod,InpSlowing,mode,0,MODE_MAIN,i);
         SignalBuffer[i]=iStochastic(Symbol(),per,InpKPeriod,InpDPeriod,InpSlowing,mode,0,MODE_SIGNAL,i);
        }
      if(per<=Wod)
        {
         MainWbuffer[i]=iStochastic(Symbol(),per,InpWKPeriod*Wod/per,InpWDPeriod*Wod/per,InpWSlowing*Wod/per,Wmode,0,MODE_MAIN,i);
         SignalWbuffer[i]=iStochastic(Symbol(),per,InpWKPeriod*Wod/per,InpWDPeriod*Wod/per,InpWSlowing*Wod/per,Wmode,0,MODE_SIGNAL,i);
        }
      if(per<=Hod)
        {
         MainHBuffer[i]=iStochastic(Symbol(),per,InpHKPeriod*Hod/per,InpHDPeriod*Hod/per,InpHSlowing*Hod/per,Hmode,0,MODE_MAIN,i);
         SignalHBuffer[i]=iStochastic(Symbol(),per,InpHKPeriod*Hod/per,InpHDPeriod*Hod/per,InpHSlowing*Hod/per,Hmode,0,MODE_SIGNAL,i);
        }
     }
//--- OnCalculate done. Return new prev_calculated.
   return(rates_total);
  }

Чтобы найти пики и впадины двух из них, в сове делаю так

int HonkStochSignW()
{
  int res=0;
    for(int i=ArraySize(signW)-1; i>=0; i--)
     {
       if(signW[i]>sign_up)
         {
          sign_up=signW[i];
          timsign_up=Time[i];
          sign_do=sign_up;
         }
       else
         {
          timsign_up=0;
          GetPeakSign(i);
         }
       if(signW[i]<sign_do)
         {
          sign_do=signW[i];
          timsign_do=Time[i];
          sign_up=sign_do;
         }
       else
         {
          timsign_do=0;
          GetDentSign(i);
         }
//-----------------------------------------------------------      
      if(mainW[i]>main_up)
        {
         main_up=mainW[i];
         timmain_up=Time[i];
         main_do=main_up;
        }
      else
        {
         timmain_up=0;
         if(GetPeak(i))
         if(mainW[i]<=signW[i])
          res=-1;
        }
      if(mainW[i]<main_do)
        {
         main_do=mainW[i];
         timmain_do=Time[i];
         main_up=main_do;
        }
      else
        {
         timmain_do=0;
        if(GetDent(i))
       if(mainW[i]>=signW[i])
         res=1;
        }
  //      Print("i = ",i);
      }  
  return res;
} 
//+------------------------------------------------------------------+
bool GetPeak(int schift)
  {
   int size=ArraySize(mainW);
   if(schift==1)
      for(int i=1; i<size-2; i++)
        {
         if(mainW[i]>mainW[i+1]&&mainW[i]>mainW[i-1])
           {
            Print("GetPeak = ",mainW[i]);
            return true;
           }
        }
   return false;
  }
//+------------------------------------------------------------------+
bool GetPeakSign(int schift)
  {
   int size=ArraySize(signW);
   if(schift==1)
      for(int i=1; i<size-2; i++)
        {
         if(signW[i]>signW[i+1]&&signW[i]>signW[i-1])
           {
            Print("GetPeakSign = ",signW[i]);
            return true;
           }
        }
   return false;
  }
//------------------------------------------------
bool GetDent(int schift)
  {
   int size=ArraySize(mainW);
   if(schift==1)
      for(int i=1; i<size-2; i++)
        {
         if(mainW[i]<mainW[i+1]&&mainW[i]<mainW[i-1])
           {
            Print("GetDent = ",mainW[i]);
            return true;
           }
        }
   return false;
  } 

Получается шесть раз придется использовать ту же схему. Как это можно решить с ООП? Схематично хотя бы.

 
Dmi3 #:

А у меня, с функциональным программированием, отдельный робот индивидуален и автономен. Есть какие-то общие функции, вынесенные в #include файл, все остальное в алгоритме свое. Есть к нему файл csv, содержащий символы для операций, необходимые наборы параметров и сохраняющий все необходимые для рестарта значения и немного аналитики результатов. Строк может быть любое количество. Каждая строка может быть отдельным алгоритмом или частью облака параметров для отдельного алгоритма или комбинацией этих вариантов.

А, ну и да, переделать тоже давно все хочется, но у меня для этого не хватает квалификации. А местные программисты почему-то считают, что более одного алгоритма на инструменте работать не может и так далее...

Функциональное на императивном MQL5? Месье понимает толк в половых извращениях! 

 
Alexey Volchanskiy #:

Функциональное на императивном MQL5? Месье понимает толк в половых извращениях! 

Функциональное, процедурное - какая, хрен, разница ))

 
JRandomTrader #:

Функциональное, процедурное - какая, хрен, разница ))

Это как сказать:«Спать с бабой, мужиком, какая нахрен разница» )) Вот что ИИ написал, корректировать не стал, на 90% все верно.

MQL5 в первую очередь предназначен для императивного стиля программирования. Функциональный стиль программирования в MQL5 возможен, однако его реализация может быть ограничена и неудобна по сравнению с языками, специально предназначенными для функционального программирования, такими как F#.

Возможности функционального стиля в MQL5:

  1. Высшие порядковые функции: MQL5 поддерживает функции высшего порядка, что позволяет передавать функции в качестве аргументов другим функциям и возвращать их в результате вызова.
  2. Рекурсия: Рекурсивные функции возможны в MQL5, что является одним из ключевых элементов функционального подхода.
  3. Лямбда-функции: Хотя лямбды официально не поддерживаются, можно имитировать их поведение с помощью функций обратного вызова ( callback ) и структур данных.

Ограничения и сложности:

  1. Отсутствие встроенной поддержки функциональных конструкций: MQL5 не имеет встроенного синтаксиса для удобного определения и применения функциональных концепций, таких как каррирование, частичное применение функций и композиция функций.
  2. Ориентация на императивный стиль: Основная направленность языка — на выполнение конкретных инструкций шаг за шагом, что делает функциональный подход менее естественным и удобным.
  3. Производительность: Из-за отсутствия оптимизаций, характерных для чисто функциональных языков, функциональные конструкции в MQL5 могут работать медленнее, чем эквивалентные императивные решения.

Сравнение с F#:

F# — это функциональный язык программирования на платформе .NET, который активно использует концепции функционального программирования. В отличие от MQL5, F# обладает следующими преимуществами:

  1. Язык изначально спроектирован для функционального стила: Встроенная поддержка карринга, композиции функций, алгебраических типов данных и других функциональных механизмов делает разработку на F# значительно проще и удобнее.
  2. Типобезопасность и чистая функциональность: F# обеспечивает строгие гарантии типобезопасности и чистый функциональный стиль, что помогает избежать многих ошибок и повышает надежность кода.
  3. Интеграция с экосистемой .NET: Благодаря тому, что F# является частью платформы .NET, разработчики имеют доступ к обширной библиотеке классов и фреймворков, что расширяет возможности для создания сложных приложений.

Заключение:

Хотя функциональный стиль программирования возможен в MQL5, его реализация будет ограниченной и неудобной. Для полноценного использования функционального стиля лучше выбрать специализированный язык, такой как F#, который предоставляет все необходимые механизмы и оптимизирован для этого подхода.

 
Alexey Volchanskiy #:

Это как сказать:«Спать с бабой, мужиком, какая нахрен разница» )) 

Я ж прикалываюсь, что по названию можно и перепутать, кто не знаком (но знаком с Пасцал).
 
Мне нужно было вычислить данные активов (см. скрин) для одного алгоритма ММ. 

Кусок кода (см. вложение) для их вычисления привожу здесь, как пример реальной задачи, которая просто решается только через ООП.


Пример использования.

#include <MT4Orders.mqh> // https://www.mql5.com/ru/code/16006

#include "Currencies.mqh" // https://www.mql5.com/ru/forum/475738/page7#comment_55200109

void OnStart()
{
  // Распечатали все позиции/ордера.
  for (uint i = OrdersTotal(); (bool)i--;)
    if (OrderSelect(i, SELECT_BY_POS))
      OrderPrint();
  
  // Распечатали все нетто-позиции.
  NETTO Netto;
  Netto.Calc();
  Print(Netto.ToString());

  // Распечатали все активы.
  CURRENCIES Currencies;
  Currencies.Calc();
  Print(Currencies.ToString());
}


Результат.

// Распечатали все позиции/ордера.
#3080418385 2024.11.22 19:44:29.970 buy 2.34 AUDUSD 0.64998 0.00000 0.00000 0.64979 0.00 0.00 -42.67 0
#3080387579 2024.11.22 19:35:20.114 buy 8.08 EURJPY 161.063 0.000 0.000 161.224 0.00 0.00 806.88 0
#3080327456 2024.11.22 19:15:41.027 buy 11.92 EURUSD 1.04071 0.00000 0.00000 1.04190 0.00 0.00 1361.44 0
#3080313429 2024.11.22 19:12:05.867 buy 2.00 USDJPY 154.782 0.000 0.000 154.748 0.00 0.00 -42.18 0
#3080286883 2024.11.22 19:03:54.485 sell 8.54 EURAUD 1.60138 0.00000 0.00000 1.60346 0.00 0.00 -1107.80 0

// Распечатали все нетто-позиции.
EURAUD = -8.54
USDJPY = 2.0
EURUSD = 11.92
EURJPY = 8.08
AUDUSD = 2.34

// Распечатали все активы.
JPY = -9.998950162486663
USD = -11.459748783503196
AUD = 9.998550066745898
EUR = 11.460148879243961

Возможно, на такой реальной задаче можно будет лучше оценить удобство ООП.


ЗЫ Для решения своей ММ-задачи дальше наследовался от выложенного класса.

Файлы:
 
fxsaber #:
Мне нужно было вычислить данные активов (см. скрин) для одного алгоритма ММ. 

Кусок кода (см. вложение) для их вычисления привожу здесь, как пример реальной задачи, которая просто решается только через ООП.


Пример использования.


Результат.

Возможно, на такой реальной задаче можно будет лучше оценить удобство ООП.


ЗЫ Для решения своей ММ-задачи дальше наследовался от выложенного класса.

Прикольная строка 

for (uint i = OrdersTotal(); (bool)i--;)

 Но 95% пацанов не поймет юмора с bool)))