Как начать работу с MQL5 - страница 29

 
Полная версия индикатора доступна по адресу: Difference Two iMA
 

Закрывайте только прибыльные позиции

Код: Закрыть прибыльную позицию.mq5

проверяет позиции по всем символам и по всем магическим числам.

//+------------------------------------------------------------------+
//|                                    Close Profitable Position.mq5 |
//|                              Copyright © 2020, Vladimir Karputov |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2020, Vladimir Karputov"
#property version   "1.000"
/*
   barabashkakvn Trading engine 3.143
*/
#include <Trade\PositionInfo.mqh>
#include <Trade\Trade.mqh>
//---
CPositionInfo  m_position;             // object of CPositionInfo class
CTrade         m_trade;                // object of CTrade class
//--- input parameters
input double   InpProfitInMoney  = 9;  // Profit in money
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   for(int i=PositionsTotal()-1; i>=0; i--) // returns the number of current positions
      if(m_position.SelectByIndex(i)) // selects the position by index for further access to its properties
        {
         double profit=m_position.Commission()+m_position.Swap()+m_position.Profit();
         if(profit>=InpProfitInMoney)
            m_trade.PositionClose(m_position.Ticket());
        }
  }
//+------------------------------------------------------------------+

Файлы:
 

Пользовательская скользящая средняя как ресурс

Код: Пользовательское скользящее среднее как ресурс.mq5

Часто спрашивают: "Если в эксперте используется пользовательский индикатор, то как правильно написать код эксперта, чтобы он работал на MQL5 VPS?".

Ответ таков: индикатор должен быть создан как ресурс. Смотрите пример ниже:

Обратите внимание: я переместил индикатор 'Custom Moving Average' в корневую папку 'Indicators'.

//+------------------------------------------------------------------+
//|                          Custom Moving Average as a resource.mq5 |
//|                              Copyright © 2021, Vladimir Karputov |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2021, Vladimir Karputov"
#property version   "1.000"
#property description "An example of using the MQL5 VPS: the Expert Advisor uses the 'Custom Moving Average' indicator as a resource"
#resource "\\Indicators\\Custom Moving Average.ex5"
//--- input parameters
input int            InpMAPeriod = 13;          // Period
input int            InpMAShift  = 0;           // Shift
input ENUM_MA_METHOD InpMAMethod = MODE_SMMA;   // Method
input bool           InpPrintLog = true;        // Print log
//---
int      handle_iCustom;                        // variable for storing the handle of the iCustom indicator
datetime m_prev_bars             = 0;           // "0" -> D'1970.01.01 00:00';
bool     m_init_error            = false;       // error on InInit
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- create timer
   EventSetTimer(60);
//--- create handle of the indicator iCustom
   handle_iCustom=iCustom(Symbol(),Period(),"::Indicators\\Custom Moving Average.ex5");
//--- if the handle is not created
   if(handle_iCustom==INVALID_HANDLE)
     {
      //--- tell about the failure and output the error code
      PrintFormat("Failed to create handle of the iCustom indicator for the symbol %s/%s, error code %d",
                  Symbol(),
                  EnumToString(Period()),
                  GetLastError());
      //--- the indicator is stopped early
      m_init_error=true;
      return(INIT_SUCCEEDED);
     }
   Print(__FUNCTION__);
//---
   double array_ma[];
   ArraySetAsSeries(array_ma,true);
   int start_pos=0,count=3;
   if(iGetArray(handle_iCustom,0,start_pos,count,array_ma))
     {
      Print("---");
      Print(TimeToString(m_prev_bars,TIME_DATE|TIME_MINUTES));
      string text="";
      for(int i=0; i<count; i++)
         text=text+IntegerToString(i)+": "+DoubleToString(array_ma[i],Digits()+1)+"\n";
      //---
      Print(text);
     }
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//--- destroy timer
   EventKillTimer();
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
  }
//+------------------------------------------------------------------+
//| Timer function                                                   |
//+------------------------------------------------------------------+
void OnTimer()
  {
//---
   if(m_init_error)
      return;
//--- we work only at the time of the birth of new bar
   datetime time_0=iTime(Symbol(),Period(),0);
   if(time_0==m_prev_bars)
      return;
   m_prev_bars=time_0;
//---
   double array_ma[];
   ArraySetAsSeries(array_ma,true);
   int start_pos=0,count=3;
   if(!iGetArray(handle_iCustom,0,start_pos,count,array_ma))
     {
      m_prev_bars=0;
      return;
     }
   Print("---");
   Print(__FUNCTION__);
   Print(TimeToString(m_prev_bars,TIME_DATE|TIME_MINUTES));
   string text="";
   for(int i=0; i<count; i++)
      text=text+IntegerToString(i)+": "+DoubleToString(array_ma[i],Digits()+1)+"\n";
   Print(text);
//---
  }
//+------------------------------------------------------------------+
//| Get value of buffers                                             |
//+------------------------------------------------------------------+
bool iGetArray(const int handle,const int buffer,const int start_pos,
               const int count,double &arr_buffer[])
  {
   bool result=true;
   if(!ArrayIsDynamic(arr_buffer))
     {
      if(InpPrintLog)
         PrintFormat("ERROR! EA: %s, FUNCTION: %s, this a no dynamic array!",__FILE__,__FUNCTION__);
      return(false);
     }
   ArrayFree(arr_buffer);
//--- reset error code
   ResetLastError();
//--- fill a part of the iBands array with values from the indicator buffer
   int copied=CopyBuffer(handle,buffer,start_pos,count,arr_buffer);
   if(copied!=count)
     {
      //--- if the copying fails, tell the error code
      if(InpPrintLog)
         PrintFormat("ERROR! EA: %s, FUNCTION: %s, amount to copy: %d, copied: %d, error code %d",
                     __FILE__,__FUNCTION__,count,copied,GetLastError());
      //--- quit with zero result - it means that the indicator is considered as not calculated
      return(false);
     }
   return(result);
  }
//+------------------------------------------------------------------+


Я скомпилировал индикатор и советник. Советник прикрепил его к графику и выполнил миграцию. Результат работы на MQL5 VPS:

Пользовательское скользящее среднее как ресурс

Как видите, все работает отлично!

 

Добавление индикатора 'iSAR' на график

Код: iSAR ChartIndicatorAdd.mq5

//+------------------------------------------------------------------+
//|                                       iSAR ChartIndicatorAdd.mq5 |
//|                              Copyright © 2021, Vladimir Karputov |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2021, Vladimir Karputov"
#property version   "1.00"
//--- input parameters
input group             "SAR"
input double               Inp_SAR_step         = 0.02;     // SAR: price increment step - acceleration factor
input double               Inp_SAR_maximum      = 0.2;      // SAR: maximum value of step
//---
int      handle_iSAR;               // variable for storing the handle of the iSAR indicator
bool     m_init_error   = false;    // error on InInit
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- create handle of the indicator iSAR
   handle_iSAR=iSAR(Symbol(),Period(),Inp_SAR_step,Inp_SAR_maximum);
//--- if the handle is not created
   if(handle_iSAR==INVALID_HANDLE)
     {
      //--- tell about the failure and output the error code
      PrintFormat("Failed to create handle of the iSAR indicator for the symbol %s/%s, error code %d",
                  Symbol(),
                  EnumToString(Period()),
                  GetLastError());
      //--- the indicator is stopped early
      m_init_error=true;
      return(INIT_SUCCEEDED);
     }
//---
   int debug         = MQLInfoInteger(MQL_DEBUG);
   int profiler      = MQLInfoInteger(MQL_PROFILER);
   int tester        = MQLInfoInteger(MQL_TESTER);
   int forward       = MQLInfoInteger(MQL_FORWARD);
   int optimization  = MQLInfoInteger(MQL_OPTIMIZATION);
   int visual_mode   = MQLInfoInteger(MQL_VISUAL_MODE);
   /*
      Print("MQL_DEBUG: ",debug,", ",
            "MQL_PROFILER: ",profiler,", ",
            "MQL_TESTER: ",tester,", ",
            "MQL_FORWARD: ",forward,", ",
            "MQL_OPTIMIZATION: ",optimization,", ",
            "MQL_VISUAL_MODE: ",visual_mode);
   */
   /*
      F5          -> MQL_DEBUG: 1, MQL_PROFILER: 0, MQL_TESTER: 0, MQL_FORWARD: 0, MQL_OPTIMIZATION: 0, MQL_VISUAL_MODE: 0
      Ctrl + F5   -> MQL_DEBUG: 1, MQL_PROFILER: 0, MQL_TESTER: 1, MQL_FORWARD: 0, MQL_OPTIMIZATION: 0, MQL_VISUAL_MODE: 1
      Online      -> MQL_DEBUG: 0, MQL_PROFILER: 0, MQL_TESTER: 0, MQL_FORWARD: 0, MQL_OPTIMIZATION: 0, MQL_VISUAL_MODE: 0
   */
//---
   if((debug==1 && tester==0) || (debug==0 && tester==0)) // F5 OR Online
     {
      int windows_total=(int)ChartGetInteger(0,CHART_WINDOWS_TOTAL);
      for(int i=windows_total-1; i>=0; i--)
        {
         for(int j=ChartIndicatorsTotal(0,i)-1; j>=0; j--)
           {
            string name=ChartIndicatorName(0,i,j);
            Print(__FUNCSIG__,", windows ",i,", indicator# ",j,", indicator name ",name);
            if(name=="SAR("+DoubleToString(Inp_SAR_step,2)+","+DoubleToString(Inp_SAR_maximum,2)+")")
               ChartIndicatorDelete(0,i,name);
           }
        }
      //---
      bool add=ChartIndicatorAdd(ChartID(),0,handle_iSAR);
      Print("Result Chart Indicator Add 'SAR': ",((add)?"true":"false"));
     }
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---
   if(handle_iSAR!=INVALID_HANDLE)
      IndicatorRelease(handle_iSAR);
   int debug         = MQLInfoInteger(MQL_DEBUG);
   int profiler      = MQLInfoInteger(MQL_PROFILER);
   int tester        = MQLInfoInteger(MQL_TESTER);
   int forward       = MQLInfoInteger(MQL_FORWARD);
   int optimization  = MQLInfoInteger(MQL_OPTIMIZATION);
   int visual_mode   = MQLInfoInteger(MQL_VISUAL_MODE);
   /*
      Print("MQL_DEBUG: ",debug,", ",
            "MQL_PROFILER: ",profiler,", ",
            "MQL_TESTER: ",tester,", ",
            "MQL_FORWARD: ",forward,", ",
            "MQL_OPTIMIZATION: ",optimization,", ",
            "MQL_VISUAL_MODE: ",visual_mode);
   */
   /*
      F5          -> MQL_DEBUG: 1, MQL_PROFILER: 0, MQL_TESTER: 0, MQL_FORWARD: 0, MQL_OPTIMIZATION: 0, MQL_VISUAL_MODE: 0
      Ctrl + F5   -> MQL_DEBUG: 1, MQL_PROFILER: 0, MQL_TESTER: 1, MQL_FORWARD: 0, MQL_OPTIMIZATION: 0, MQL_VISUAL_MODE: 1
      Online      -> MQL_DEBUG: 0, MQL_PROFILER: 0, MQL_TESTER: 0, MQL_FORWARD: 0, MQL_OPTIMIZATION: 0, MQL_VISUAL_MODE: 0
   */
//---
   if((debug==1 && tester==0) || (debug==0 && tester==0)) // F5 OR Online
     {
      int windows_total=(int)ChartGetInteger(0,CHART_WINDOWS_TOTAL);
      for(int i=windows_total-1; i>=0; i--)
        {
         for(int j=ChartIndicatorsTotal(0,i)-1; j>=0; j--)
           {
            string name=ChartIndicatorName(0,i,j);
            Print(__FUNCTION__,", windows ",i,", indicator# ",j,", indicator name ",name);
            if(name=="SAR("+DoubleToString(Inp_SAR_step,2)+","+DoubleToString(Inp_SAR_maximum,2)+")")
               ChartIndicatorDelete(0,i,name);
           }
        }
     }
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   if(m_init_error)
      return;
  }
//+------------------------------------------------------------------+


Результат:

У нас есть график с двумя индикаторами: iMA в главном окне и iMACD в подокне.

iSAR ChartIndicatorAdd


Запускаем наш советник:

iSAR ChartIndicatorAdd

и вкладку "Эксперты":

iSAR ChartIndicatorAdd (GBPUSD,M20)     int OnInit(), windows 1, indicator# 0, indicator name MACD(12,26,9)
iSAR ChartIndicatorAdd (GBPUSD,M20)     int OnInit(), windows 0, indicator# 0, indicator name MA(13)
iSAR ChartIndicatorAdd (GBPUSD,M20)     Result Chart Indicator Add 'SAR': true


При переключении таймфрейма:

iSAR ChartIndicatorAdd

проверить: смотрит на все индикаторы

iSAR ChartIndicatorAdd

и вкладка "Эксперты":

iSAR ChartIndicatorAdd (GBPUSD,M20)     OnDeinit, windows 1, indicator# 0, indicator name MACD(12,26,9)
iSAR ChartIndicatorAdd (GBPUSD,M20)     OnDeinit, windows 0, indicator# 1, indicator name SAR(0.02,0.20)
iSAR ChartIndicatorAdd (GBPUSD,M20)     OnDeinit, windows 0, indicator# 0, indicator name MA(13)
iSAR ChartIndicatorAdd (GBPUSD,H4)      int OnInit(), windows 1, indicator# 0, indicator name MACD(12,26,9)
iSAR ChartIndicatorAdd (GBPUSD,H4)      int OnInit(), windows 0, indicator# 0, indicator name MA(13)
iSAR ChartIndicatorAdd (GBPUSD,H4)      Result Chart Indicator Add 'SAR': true


Файлы:
 

Почему окно, когда оно скрыто, возвращает другие параметры, чем когда оно активно?

Ответ прост - все дело в операционной системе Windows. У окна может быть несколько состояний: окно полностью максимизировано, минимизировано и свернуто. Когда окно неактивно, оно находится в свернутом состоянии (если вы не свернули его раньше). Давайте проверим это. Используем индикатор Bar number - он нумерует бары и служебный индикатор 'CHART_FIRST_VISIBLE_BAR.mq5' - индикатор отображает значение

CHART_FIRST_VISIBLE_BAR

Номер первого видимого бара на графике. Индексация баров соответствуетвременным сериям.

int r / o


Вот что происходит: сначала окно полностью максимизируется, затем минимизируется, и после этого мы переключаемся на другой график (который полностью максимизируем)

CHART_FIRST_VISIBLE_BAR



Bar number
Bar number
  • www.mql5.com
Нумерация баров при помощи графических объектов OBJ_TEXT
Файлы:
 

Здравствуйте Владимир,

Огромное спасибо за Ваши усилия по созданию многочисленных кодов и советников, которые помогли нескольким новичкам в программировании на MQL5, таким как я, понять зачатки кодирования на языке MQL5.

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

Например, только одна позиция Sell и одна Buy могут иметь одинаковый размер лота, т.е. для любого конкретного размера лота можно открыть только одну позицию Buy и одну Sell.

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

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

   if(count_positions>0)
     {
      double Ask=NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_ASK),_Digits);
      double Bid=NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_BID),_Digits);
      double max_volume=SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_MAX);
      if(last_position_type==POSITION_TYPE_BUY && m_symbol.Ask()-(TP * _Point) >last_position_price_open)
         m_trade.Buy(last_position_volume*2,m_symbol.Name(),Ask,0,(Ask+TP*_Point),NULL);
      if(last_position_type==POSITION_TYPE_BUY && last_position_price_open > m_symbol.Ask() + (TP * _Point))
         if(count_max_volume==1 && last_position_volume==max_volume)
            m_trade.Sell(last_position_volume*1,m_symbol.Name(),Bid,0,(Bid-TP*_Point),NULL);
      if(last_position_type==POSITION_TYPE_SELL && m_symbol.Bid()+(TP * _Point) <last_position_price_open)
         m_trade.Sell(last_position_volume*2,m_symbol.Name(),Bid,0,(Bid-TP*_Point),NULL);
      if(last_position_type==POSITION_TYPE_SELL && last_position_price_open < m_symbol.Bid() - (TP * _Point))
         if(count_max_volume==1 && last_position_volume==max_volume)
            m_trade.Buy(last_position_volume*1,m_symbol.Name(),Ask,0,(Ask+TP*_Point),NULL);
     }
   if(count_positions==0 && count_pending_orders==0)
     {
      double Ask=NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_ASK),_Digits);
      double Bid=NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_BID),_Digits);
      m_trade.Sell(InpLot,m_symbol.Name(),Bid,0,(Bid-TP*_Point),NULL);
      m_trade.Buy(InpLot,m_symbol.Name(),Ask,0,(Ask+TP*_Point),NULL);
      return;
     }

 
CodeFx # :


Попробуйте этот код:

   if(count_positions>0)
     {
      string Name       = m_symbol.Name();
      double Ask        = m_symbol.Ask();
      double Bid        = m_symbol.Bid();
      double LotsMax    = m_symbol.LotsMax();
      if(last_position_type==POSITION_TYPE_BUY && (Ask-m_take_profit>last_position_price_open))
        {
         m_trade.Buy(last_position_volume*2.0,Name,Ask,0.0,m_symbol.NormalizePrice(Ask+m_take_profit)));
         return;
        }
      if(last_position_type==POSITION_TYPE_BUY && (last_position_price_open>Ask+m_take_profit))
        {
         if(count_max_volume==1 && last_position_volume==LotsMax)
           {
            m_trade.Sell(last_position_volume*1.0,Name,Bid,0.0,m_symbol.NormalizePrice(Bid-m_take_profit));
            return;
           }
        }
      if(last_position_type==POSITION_TYPE_SELL && (Bid+m_take_profit<last_position_price_open))
        {
         m_trade.Sell(last_position_volume*2.0,Name,Bid,0.0,m_symbol.NormalizePrice(Bid-m_take_profit));
         return;
        }
      if(last_position_type==POSITION_TYPE_SELL && (last_position_price_open<Bid-m_take_profit))
        {
         if(count_max_volume==1 && last_position_volume==LotsMax)
           {
            m_trade.Buy(last_position_volume*1.0,Name,Ask,0,m_symbol.NormalizePrice(Ask+m_take_profit));
            return;
           }
        }
     }
   if(count_positions==0 && count_pending_orders==0)
     {
      m_trade.Sell(InpLot,Name,Bid,0.0,m_symbol.NormalizePrice(Bid-m_take_profit));
      m_trade.Buy(InpLot,Name,Ask,0.0,m_symbol.NormalizePrice(Ask+m_take_profit));
      return;
     }
 
Vladimir Karputov #:

Попробуйте этот код:

Большое спасибо за помощь. Я попробовал код, как советовали, но обнаружил, что при бэктесте в течение года было открыто максимум 7 позиций, в то время как в некоторые другие годы открывалось только 2 позиции. Пожалуйста, посмотрите полный код ниже:

***

 
CodeFx # :

Большое спасибо за помощь. Я попробовал код, как советовали, но обнаружил, что при бэктесте в течение года было открыто максимум 7 позиций, в то время как в некоторые другие годы открывалось только 2 позиции. Пожалуйста, посмотрите полный код ниже:

***

Пожалуйста, никогда не вставляйте код в виде листа текста.

Вам нужно сделать следующее: вставить текст с помощью кнопки Код и добавить код с помощью кнопки Прикрепить файл...

 
Vladimir Karputov #:

Никогда не вставляйте код в виде листа текста.

Нужно сделать так: вставить текст с помощью кнопки и добавить код с помощью кнопки ...

Большое спасибо за исправление и извинения за ошибку. Пожалуйста, посмотрите полный код, основанный на вашем совете, который открыл максимум 7 позиций в течение года при бэктестинге, в то время как в некоторые другие годы было открыто только 2 позиции:

//+------------------------------------------------------------------+
//|                                                 New edition).mq5 |
//|                                              Copyright © 2021,   |
//|                                          |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2021"
#property link      "CodeFx"
#property version   "1.000"
//---
#include <Trade\PositionInfo.mqh>
#include <Trade\Trade.mqh>
#include <Trade\SymbolInfo.mqh>  
#include <Trade\OrderInfo.mqh>

CPositionInfo  m_position;                   // trade position object
CTrade         m_trade;                      // trading object
CSymbolInfo    m_symbol;                     // symbol info object
COrderInfo     m_order;                      // pending orders object
//--- input parameters
input ushort   InpStep           = 10;
input double   InpLot            = 0.01;
ulong          m_magic           = 12345;    // magic number
ulong          m_slippage=30;                // slippage
//---
double         ExtStep=0.0;
double         m_adjusted_point;             // point value adjusted for 3 or 5 points
input int      PF                = 10;       // Incremental Profit To Close All Trades
input int      DEP               = 1000;     // Deposit or Start Balance 
double         Previous_balance  = AccountInfoDouble (ACCOUNT_BALANCE); // Balance at start of each algorithm  
double         m_take_profit     = 250;

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
 
   Comment("????? ????????? ",TimeToString(TimeCurrent(),TIME_DATE|TIME_MINUTES|TIME_SECONDS));
//---
   if(!m_symbol.Name(Symbol())) // sets symbol name
      return(INIT_FAILED);
   RefreshRates();

   string err_text="";
   if(!CheckVolumeValue(InpLot,err_text))
     {
      Print(err_text);
      return(INIT_PARAMETERS_INCORRECT);
     }
//---
   m_trade.SetExpertMagicNumber(m_magic);
//---
   if(IsFillingTypeAllowed(m_symbol.Name(),SYMBOL_FILLING_FOK))
      m_trade.SetTypeFilling(ORDER_FILLING_FOK);
   else if(IsFillingTypeAllowed(m_symbol.Name(),SYMBOL_FILLING_IOC))
      m_trade.SetTypeFilling(ORDER_FILLING_IOC);
   else
      m_trade.SetTypeFilling(ORDER_FILLING_RETURN);
//---
   m_trade.SetDeviationInPoints(m_slippage);
//--- tuning for 3 or 5 digits
   int digits_adjust=1;
   if(m_symbol.Digits()==3 || m_symbol.Digits()==5)
      digits_adjust=10;
   m_adjusted_point=m_symbol.Point()*digits_adjust;

   ExtStep=InpStep*m_adjusted_point;
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---

  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
 {
   datetime             last_position_time         = 0;
   double               last_position_price_open   = 0.0;
   double               last_position_volume       = 0.0;
   ENUM_POSITION_TYPE   last_position_type         = -1;
   int                  count_positions            = 0;    
   int                  count_max_volume           = 0;
   double               total_profit               = 0;

   for(int i=PositionsTotal()-1;i>=0;i--)
      if(m_position.SelectByIndex(i)) // selects the position by index for further access to its properties
         if(m_position.Symbol()==m_symbol.Name() && m_position.Magic()==m_magic)
           {
            if(m_position.Time()>last_position_time)
              {
               last_position_time         = m_position.Time();
               last_position_price_open   = m_position.PriceOpen();
               last_position_volume       = m_position.Volume();
               last_position_type         = m_position.PositionType();               
              }
            count_positions++;
            count_max_volume++;           
            total_profit=total_profit+m_position.Commission()+m_position.Swap()+m_position.Profit();
           }
           
   int count_pending_orders=0;
   for(int i=OrdersTotal()-1;i>=0;i--) // returns the number of current orders
      if(m_order.SelectByIndex(i)) // selects the pending order by index for further access to its properties
         if(m_order.Symbol()==m_symbol.Name() && m_order.Magic()==m_magic)
            count_pending_orders++;

if (PositionsTotal()==0)
{Previous_balance = AccountInfoDouble (ACCOUNT_BALANCE);} 

double equity    = AccountInfoDouble (ACCOUNT_EQUITY);
if(equity > Previous_balance + PF) 
     {
      Print("Closing on profit");
      CloseAllPositions();
      return;
     } 

   if(!RefreshRates())
      return;

if(count_positions>0)
     {
      string Name       = m_symbol.Name();
      double Ask        = m_symbol.Ask();
      double Bid        = m_symbol.Bid();
      double LotsMax    = m_symbol.LotsMax();
      
      if(last_position_type==POSITION_TYPE_BUY && (Ask-m_take_profit>last_position_price_open))
        {
         m_trade.Buy(last_position_volume*2.0,Name,Ask,0.0,m_symbol.NormalizePrice(Ask+m_take_profit));
         return;
        }
        
      if(last_position_type==POSITION_TYPE_BUY && (last_position_price_open>Ask+m_take_profit))
        {
         if(count_max_volume==1 && last_position_volume==LotsMax)
           {
            m_trade.Sell(last_position_volume*1.0,Name,Bid,0.0,m_symbol.NormalizePrice(Bid-m_take_profit));
            return;
           }
        }
        
      if(last_position_type==POSITION_TYPE_SELL && (Bid+m_take_profit<last_position_price_open))
        {
         m_trade.Sell(last_position_volume*2.0,Name,Bid,0.0,m_symbol.NormalizePrice(Bid-m_take_profit));
         return;
        }
        
      if(last_position_type==POSITION_TYPE_SELL && (last_position_price_open<Bid-m_take_profit))
        {
         if(count_max_volume==1 && last_position_volume==LotsMax)
           {
            m_trade.Buy(last_position_volume*1.0,Name,Ask,0,m_symbol.NormalizePrice(Ask+m_take_profit));
            return;
           }
        }
     }
     
   if(count_positions==0 && count_pending_orders==0)
     {
      string Name       = m_symbol.Name();
      double Ask        = m_symbol.Ask();
      double Bid        = m_symbol.Bid();
      m_trade.Sell(InpLot,Name,Bid,0.0,m_symbol.NormalizePrice(Bid-m_take_profit));
      m_trade.Buy(InpLot,Name,Ask,0.0,m_symbol.NormalizePrice(Ask+m_take_profit));
      return;
     }


   if(count_positions>0 && count_pending_orders>0)
      DeleteAllOrders();
//---
   return;
  }
//+------------------------------------------------------------------+
//| Refreshes the symbol quotes data                                 |
//+------------------------------------------------------------------+
bool RefreshRates()
  {
//--- refresh rates
   if(!m_symbol.RefreshRates())
      return(false);
//--- protection against the return value of "zero"
   if(m_symbol.Ask()==0 || m_symbol.Bid()==0)
      return(false);
//---
   return(true);
  }
  
//+------------------------------------------------------------------+
//| Check the correctness of the order volume                        |
//+------------------------------------------------------------------+
bool CheckVolumeValue(double volume,string &error_description)
  {
//--- minimal allowed volume for trade operations
// double min_volume=m_symbol.LotsMin();
   double min_volume=SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_MIN);
   if(volume<min_volume)
     {
      error_description=StringFormat("Volume is less than the minimal allowed SYMBOL_VOLUME_MIN=%.2f",min_volume);
      return(false);
     }

//--- maximal allowed volume of trade operations
// double max_volume=m_symbol.LotsMax();
   double max_volume=SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_MAX);
   if(volume>max_volume)
     {
      error_description=StringFormat("Volume is greater than the maximal allowed SYMBOL_VOLUME_MAX=%.2f",max_volume);
      return(false);
     }

//--- get minimal step of volume changing
// double volume_step=m_symbol.LotsStep();
   double volume_step=SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_STEP);

   int ratio=(int)MathRound(volume/volume_step);
   if(MathAbs(ratio*volume_step-volume)>0.0000001)
     {
      error_description=StringFormat("Volume is not a multiple of the minimal step SYMBOL_VOLUME_STEP=%.2f, the closest correct volume is %.2f",
                                     volume_step,ratio*volume_step);
      return(false);
     }
   error_description="Correct volume value";
   return(true);
  }
//+------------------------------------------------------------------+ 
//| Checks if the specified filling mode is allowed        .          | 
//+------------------------------------------------------------------+ 
bool IsFillingTypeAllowed(string symbol,int fill_type)
  {
//--- Obtain the value of the property that describes allowed filling modes 
   int filling=(int)SymbolInfoInteger(symbol,SYMBOL_FILLING_MODE);
//--- Return true, if mode fill_type is allowed 
   return((filling & fill_type)==fill_type);
  }
//+------------------------------------------------------------------+
//| Close all positions                                              |
//+------------------------------------------------------------------+
void CloseAllPositions()
  { 
   for(int i=PositionsTotal()-1;i>=0;i--) // returns the number of current positions
      if(m_position.SelectByIndex(i))     // selects the position by index for further access to its properties
         if(m_position.Symbol()==m_symbol.Name() && m_position.Magic()==m_magic)
            m_trade.PositionClose(m_position.Ticket()); // close a position by the specified symbol
  }
//+------------------------------------------------------------------+
//| Delete all pendingA rders                                         |
//+------------------------------------------------------------------+
void DeleteAllOrders()
  {
   for(int i=OrdersTotal()-1;i>=0;i--) // returns the number of current orders
      if(m_order.SelectByIndex(i))     // selects the pending order by index for further access to its properties
         if(m_order.Symbol()==m_symbol.Name() && m_order.Magic()==m_magic)
            m_trade.OrderDelete(m_order.Ticket());
  }
//+------------------------------------------------------------------+


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

//+------------------------------------------------------------------+
//|                                                 New edition).mq5 |
//|                                              Copyright © 2021,   |
//|                                          |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2021"
#property link      "CodeFx"
#property version   "1.000"
//---
#include <Trade\PositionInfo.mqh>
#include <Trade\Trade.mqh>
#include <Trade\SymbolInfo.mqh>  
#include <Trade\OrderInfo.mqh>

CPositionInfo  m_position;                   // trade position object
CTrade         m_trade;                      // trading object
CSymbolInfo    m_symbol;                     // symbol info object
COrderInfo     m_order;                      // pending orders object
//--- input parameters
input ushort   InpStep           = 10;
input double   InpLot            = 0.01;
ulong          m_magic           = 12345;    // magic number
ulong          m_slippage        = 30;       // slippage
//---
double         ExtStep           = 0.0;
double         m_adjusted_point;             // point value adjusted for 3 or 5 points
input int      PF                = 10;       // Incremental Profit To Close All Trades
input int      DEP               = 1000;     // Deposit or Start Balance 
input int      TP                = 250;      // TakeProfit
double         Previous_balance  = AccountInfoDouble (ACCOUNT_BALANCE); // Balance at start of each algorithm  

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
 
   Comment("????? ????????? ",TimeToString(TimeCurrent(),TIME_DATE|TIME_MINUTES|TIME_SECONDS));
//---
   if(!m_symbol.Name(Symbol())) // sets symbol name
      return(INIT_FAILED);
   RefreshRates();

   string err_text="";
   if(!CheckVolumeValue(InpLot,err_text))
     {
      Print(err_text);
      return(INIT_PARAMETERS_INCORRECT);
     }
//---
   m_trade.SetExpertMagicNumber(m_magic);
//---
   if(IsFillingTypeAllowed(m_symbol.Name(),SYMBOL_FILLING_FOK))
      m_trade.SetTypeFilling(ORDER_FILLING_FOK);
   else if(IsFillingTypeAllowed(m_symbol.Name(),SYMBOL_FILLING_IOC))
      m_trade.SetTypeFilling(ORDER_FILLING_IOC);
   else
      m_trade.SetTypeFilling(ORDER_FILLING_RETURN);
//---
   m_trade.SetDeviationInPoints(m_slippage);
//--- tuning for 3 or 5 digits
   int digits_adjust=1;
   if(m_symbol.Digits()==3 || m_symbol.Digits()==5)
      digits_adjust=10;
   m_adjusted_point=m_symbol.Point()*digits_adjust;

   ExtStep=InpStep*m_adjusted_point;
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---

  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
   datetime             last_position_time         = 0;
   double               last_position_price_open   = 0.0;
   double               last_position_volume       = 0.0;
   ENUM_POSITION_TYPE   last_position_type         = -1;
   int                  count_positions            = 0;    
   int                  count_max_volume           = 0;
   double               total_profit               = 0;

   for(int i=PositionsTotal()-1;i>=0;i--)
      if(m_position.SelectByIndex(i)) // selects the position by index for further access to its properties
         if(m_position.Symbol()==m_symbol.Name() && m_position.Magic()==m_magic)
           {
            if(m_position.Time()>last_position_time)
              {
               last_position_time         = m_position.Time();
               last_position_price_open   = m_position.PriceOpen();
               last_position_volume       = m_position.Volume();
               last_position_type         = m_position.PositionType();               
              }
            count_positions++;
            count_max_volume++;           
            total_profit=total_profit+m_position.Commission()+m_position.Swap()+m_position.Profit();
           }
   int count_pending_orders=0;
   for(int i=OrdersTotal()-1;i>=0;i--) // returns the number of current orders
      if(m_order.SelectByIndex(i)) // selects the pending order by index for further access to its properties
         if(m_order.Symbol()==m_symbol.Name() && m_order.Magic()==m_magic)
            count_pending_orders++;

if (PositionsTotal()==0)
{Previous_balance = AccountInfoDouble (ACCOUNT_BALANCE);} 

double equity    = AccountInfoDouble (ACCOUNT_EQUITY);
if(equity > Previous_balance + PF) 
     {
      Print("Closing on profit");
      CloseAllPositions();
      return;
     } 

   if(!RefreshRates())
      return;

   if(count_positions>0)
     {
       double Ask=NormalizeDouble (SymbolInfoDouble (_Symbol,SYMBOL_ASK),_Digits);
       double Bid=NormalizeDouble (SymbolInfoDouble (_Symbol,SYMBOL_BID),_Digits); 
       double max_volume=SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_MAX);
       
       if(last_position_type==POSITION_TYPE_BUY && m_symbol.Ask()-(TP * _Point) >last_position_price_open )                  
         m_trade.Buy(last_position_volume*2,m_symbol.Name(),Ask,0,(Ask+TP*_Point),NULL);
                                     
       if(last_position_type==POSITION_TYPE_BUY && last_position_price_open > m_position.PriceCurrent() + (TP * _Point) )                                 
       if(count_max_volume==1 && last_position_volume==max_volume) 
           m_trade.Sell(last_position_volume*1,m_symbol.Name(),Bid,0,(Bid-TP*_Point),NULL); 
                              
       if(last_position_type==POSITION_TYPE_SELL && m_symbol.Bid()+(TP * _Point) <last_position_price_open )       
         m_trade.Sell(last_position_volume*2,m_symbol.Name(),Bid,0,(Bid-TP*_Point),NULL);  
        
       if(last_position_type==POSITION_TYPE_SELL && last_position_price_open < m_position.PriceCurrent() - (TP * _Point) )                                                  
       if(count_max_volume==1 && last_position_volume==max_volume) 
           m_trade.Buy(last_position_volume*1,m_symbol.Name(),Ask,0,(Ask+TP*_Point),NULL);                                                                                                                   
               }

   if(count_positions==0 && count_pending_orders==0)
     {
      double Ask=NormalizeDouble (SymbolInfoDouble (_Symbol,SYMBOL_ASK),_Digits);
      double Bid=NormalizeDouble (SymbolInfoDouble (_Symbol,SYMBOL_BID),_Digits);     
      m_trade.Sell(InpLot,m_symbol.Name(),Bid,0,(Bid-TP*_Point),NULL);                 
      m_trade.Buy(InpLot,m_symbol.Name(),Ask,0,(Ask+TP*_Point),NULL);      
      return;
     }

   if(count_positions>0 && count_pending_orders>0)
      DeleteAllOrders();
//---
   return;
  }
//+------------------------------------------------------------------+
//| Refreshes the symbol quotes data                                 |
//+------------------------------------------------------------------+
bool RefreshRates()
  {
//--- refresh rates
   if(!m_symbol.RefreshRates())
      return(false);
//--- protection against the return value of "zero"
   if(m_symbol.Ask()==0 || m_symbol.Bid()==0)
      return(false);
//---
   return(true);
  }
  
//+------------------------------------------------------------------+
//| Check the correctness of the order volume                        |
//+------------------------------------------------------------------+
bool CheckVolumeValue(double volume,string &error_description)
  {
//--- minimal allowed volume for trade operations
// double min_volume=m_symbol.LotsMin();
   double min_volume=SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_MIN);
   if(volume<min_volume)
     {
      error_description=StringFormat("Volume is less than the minimal allowed SYMBOL_VOLUME_MIN=%.2f",min_volume);
      return(false);
     }

//--- maximal allowed volume of trade operations
// double max_volume=m_symbol.LotsMax();
   double max_volume=SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_MAX);
   if(volume>max_volume)
     {
      error_description=StringFormat("Volume is greater than the maximal allowed SYMBOL_VOLUME_MAX=%.2f",max_volume);
      return(false);
     }

//--- get minimal step of volume changing
// double volume_step=m_symbol.LotsStep();
   double volume_step=SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_STEP);

   int ratio=(int)MathRound(volume/volume_step);
   if(MathAbs(ratio*volume_step-volume)>0.0000001)
     {
      error_description=StringFormat("Volume is not a multiple of the minimal step SYMBOL_VOLUME_STEP=%.2f, the closest correct volume is %.2f",
                                     volume_step,ratio*volume_step);
      return(false);
     }
   error_description="Correct volume value";
   return(true);
  }
//+------------------------------------------------------------------+ 
//| Checks if the specified filling mode is allowed        .          | 
//+------------------------------------------------------------------+ 
bool IsFillingTypeAllowed(string symbol,int fill_type)
  {
//--- Obtain the value of the property that describes allowed filling modes 
   int filling=(int)SymbolInfoInteger(symbol,SYMBOL_FILLING_MODE);
//--- Return true, if mode fill_type is allowed 
   return((filling & fill_type)==fill_type);
  }
//+------------------------------------------------------------------+
//| Close all positions                                              |
//+------------------------------------------------------------------+
void CloseAllPositions()
  { 
   for(int i=PositionsTotal()-1;i>=0;i--) // returns the number of current positions
      if(m_position.SelectByIndex(i))     // selects the position by index for further access to its properties
         if(m_position.Symbol()==m_symbol.Name() && m_position.Magic()==m_magic)
            m_trade.PositionClose(m_position.Ticket()); // close a position by the specified symbol
  }
//+------------------------------------------------------------------+
//| Delete all pendingA rders                                         |
//+------------------------------------------------------------------+
void DeleteAllOrders()
  {
   for(int i=OrdersTotal()-1;i>=0;i--) // returns the number of current orders
      if(m_order.SelectByIndex(i))     // selects the pending order by index for further access to its properties
         if(m_order.Symbol()==m_symbol.Name() && m_order.Magic()==m_magic)
            m_trade.OrderDelete(m_order.Ticket());
  }
//+------------------------------------------------------------------+


Пожалуйста, помогите, спасибо.

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