Trade/Trade.mqh - страница 2

 
Aleksandr Klapatyuk:

вот ваш код с Stop Loss и Take Profit (всё работает)


так стоп и тейк не ставятся, если у меня инет пропадет, то робот позиции не сможет закрыть. и стопы с тейками у мня ставятся 50% дневного атр тейк, и 16% атр стоп. в вашем коде меняла эти значения ничего не изменилось.

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

//----------------------------ПОКУПКИ-------------------------------------------------
 //         
         
   if (!PositionSelect(_Symbol))      //если нет открытой позиции
   {
     if (TC == TCtime)               //если время равно 10:01:00 
      {  
        if (cl>op)                 //если открыти 1ой свечи > закрытия 1ой свечи
        {
         trader.Buy(Lots);     //то вход в лонг                                             
        }
      }       
   }
   else
   {
      if (PositionGetInteger(POSITION_TYPE)== POSITION_TYPE_BUY)
      {  pointlo = (SymbolInfoDouble(_Symbol,SYMBOL_LAST) - PositionGetDouble(POSITION_PRICE_OPEN)); //когда цена идет вверх
         pointhr = (PositionGetDouble(POSITION_PRICE_OPEN) - SymbolInfoDouble(_Symbol,SYMBOL_LAST)); //когда цена идет вниз
          
          if (pointlo>=TP)              // закрытие по стопу и тейку, с расчетом от % атр
          {
             trader.PositionClose(_Symbol);             //закрытие позы
          }
          if (pointhr>=SL)
          {
             trader.PositionClose(_Symbol);  
          }
      }     
   }           
 
Возможно это из за несоответствия цены шагу цены. Нужно нормализоввывать ее на шаг цены (размер тика) и точность _Digits

double Tick_value=SymbolInfoDouble(_Symb,SYMBOL_TRADE_TICK_SIZE);
long Dig=SymbolInfoInteger(_Symb,SYMBOL_DIGITS);

void CSLTP::NormalizeLvl(double &Lvl)
  {
   Lvl/= Tick_value;
   Lvl = NormalizeDouble(Lvl,0);
   Lvl*=Tick_value;
   Lvl=NormalizeDouble(Lvl,0);
   Lvl=NormalizeDouble(Lvl,(int)Dig);
  }
 

Это минимум для открытия позиции:

//+------------------------------------------------------------------+
//|                                                          1ый.mq5 |
//|                        Copyright 2019, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2019, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
//---
#include <Trade\PositionInfo.mqh>
#include <Trade\Trade.mqh>
#include <Trade\SymbolInfo.mqh>  
CPositionInfo  m_position;                   // trade position object
CTrade         m_trade;                      // trading object
CSymbolInfo    m_symbol;                     // symbol info object
//--- input parameters
input double   Lots  = 1.0;
input int      TPpr  = 50;
input int      SLpr  = 10;
input int      DDpr=40;       // цена прошла 40% запрет входа
//---
int      ATRy;                // указатель на индикато атр
double   ATRm[];              // массив для атр
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   if(!m_symbol.Name(Symbol())) // sets symbol name
      return(INIT_FAILED);
   RefreshRates();
//---
   ATRy=iATR(m_symbol.Name(),PERIOD_D1,5);
   if(ATRy==INVALID_HANDLE)
     {
      Print("не удалось создать описатель индикатора XLO");
      return(INIT_FAILED);
     }
   ArraySetAsSeries(ATRm,true);
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {

   IndicatorRelease(ATRy);
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
   MqlDateTime STimeCurrent;  // структура для хранения времени
   TimeToStruct(TimeCurrent(),STimeCurrent);
//---
   MqlRates rates[];
   ArraySetAsSeries(rates,true);
   if(CopyRates(m_symbol.Name(),Period(),0,3,rates)!=3)
      return;
   if(CopyBuffer(ATRy,0,0,3,ATRm)!=3)
      return;

   double cl   = rates[1].close;
   double op   = rates[1].open;
   double high = rates[0].high;
   double low  = rates[0].low;

   double ATR  = ATRm[1];        // значение дневного АТР вчерашнего дня
   double TP   = ATR/100*TPpr;   //
   double SL   = ATR/100*SLpr;   // значение от атр 50% 
   double DD   = ATR/100*DDpr;   //

   int count=0;
   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())
           {
            count++;
            double PR=m_position.PriceOpen();
            if(m_position.PositionType()==POSITION_TYPE_BUY)
              {

              }
            else
              {

              }
           }
//---
   if(count==0) //если нет открытой позиции
     {
      if(STimeCurrent.hour==10 && STimeCurrent.min==01) //если время равно 10:01:00 
        {
         if(!RefreshRates()) // получаем текущие цены
            return;
         //--- ПОКУПКИ      
         if(cl>op) //если открыти 1ой свечи > закрытия 1ой свечи
           {
            double SL_BUY=m_symbol.Ask()-SL; // цена для стопа лонга
            double TP_BUY=m_symbol.Ask()+TP; // цена для тейка лонга
            m_trade.Buy(Lots,m_symbol.Name(),m_symbol.Ask(),
                        m_symbol.NormalizePrice(SL_BUY),
                        m_symbol.NormalizePrice(TP_BUY));     // то вход в лонг                                             
           }
         //--- ПРОДАЖИ
         else if(cl<op) //если закрытие 1ой свечи < открытия 1ой свечи
           {
            double SL_SELL=m_symbol.Bid()+SL; // цена для стопа шорта
            double TP_SELL=m_symbol.Bid()-TP; // цена для тейка шорта
            m_trade.Sell(Lots,m_symbol.Name(),m_symbol.Bid(),
                         m_symbol.NormalizePrice(SL_SELL),
                         m_symbol.NormalizePrice(TP_SELL));     // то вход в шорт                                                
           }
        }
     }
  }
//+------------------------------------------------------------------+
//| Refreshes the symbol quotes data                                 |
//+------------------------------------------------------------------+
bool RefreshRates(void)
  {
//--- refresh rates
   if(!m_symbol.RefreshRates())
     {
      Print("RefreshRates error");
      return(false);
     }
//--- protection against the return value of "zero"
   if(m_symbol.Ask()==0 || m_symbol.Bid()==0)
      return(false);
//---
   return(true);
  }
//+------------------------------------------------------------------+


Чтобы не путаться, сначала рассчитывайте Стоп лосс, а потом Тейк профит (у вас изначально было наоборот и я даже попался на этом - дело в том, что CTrade отдаёт торговый приказ в формате ***, Стоп лосс, Тейк профит).


Пришлось добавить класс CSymbolInfo - для получения текущей цены и (главное!) - для нормализации цен подставляемых в Стоп лосс и Тейк профит.

Файлы:
Test1.mq5  11 kb
 
Vladimir Karputov:

Это минимум для открытия позиции:


Чтобы не путаться, сначала рассчитывайте Стоп лосс, а потом Тейк профит (у вас изначально было наоборот и я даже попался на этом - дело в том, что CTrade отдаёт торговый приказ в формате ***, Стоп лосс, Тейк профит).


Пришлось добавить класс CSymbolInfo - для получения текущей цены и (главное!) - для нормализации цен подставляемых в Стоп лосс и Тейк профит.

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

 
sofi563:

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

Да. Распишу по каждой строчке.

 
Vladimir Karputov:

Да. Распишу по каждой строчке

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

//+------------------------------------------------------------------+
//|                                                          1ый.mq5 |
//|                        Copyright 2019, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2019, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
//---
#include <Trade\PositionInfo.mqh>
#include <Trade\Trade.mqh>
#include <Trade\SymbolInfo.mqh>  
CPositionInfo  m_position;                   // trade position object
CTrade         m_trade;                      // trading object
CSymbolInfo    m_symbol;                     // symbol info object
//--- input parameters
input double   Lots  = 1.0;
input int      TPpr  = 50;
input int      SLpr  = 10;
input int      DDpr=40;       // цена прошла 40% запрет входа
//---
int      ATRy;                // указатель на индикато атр
double   ATRm[];              // массив для атр
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   if(!m_symbol.Name(Symbol())) // sets symbol name 1. не могу понять этой иницилизации. ЕСЛИ НЕТ СИМВОЛА ТО
      return(INIT_FAILED);      //ПРЕКРАЩАЕМ РАБОТУ. так что ли? 
   RefreshRates();              //иницилизация функции bool RefreshRates(void)
   
   ATRy=iATR(m_symbol.Name(),PERIOD_D1,5); // 2. m_symbol.Name()? ПОЧЕМУ НЕ NULL?
   if(ATRy==INVALID_HANDLE)
     {
      Print("не удалось создать описатель индикатора XLO");
      return(INIT_FAILED);
     }
   ArraySetAsSeries(ATRm,true);  // МАССИВЫ ТОЖЕ НАДО ИНИЦИЛИЗИРОВАТЬ?
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {

   IndicatorRelease(ATRy);
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  { 
   MqlDateTime STimeCurrent;  /* структура для хранения времени. НАКОНЕЦ ТО ПОНЯЛА КАК ЭТО ЕДЯТ)))), ТИПА ИСПОЛЬЗОВАНИЕ
    КЛАССА ПОЛУЧАЕТСЯ. STimeCurrent И БЕРЕМ ИЗ СТРУКТУРЫ ЧТО НУЖНО. STimeCurrent.hour ТАК? ТОКА НЕ СОВСЕМ ПОНЯТНО ЗАЧЕМ 
    НУЖНО КОНВЕРТАЦИЯ TimeToStruct. В МОЕМ ПОНИМАНИИ ИЗ СТРУКТУРЫ МОЖНО  ВЫТАЩИТЬ ЧТО ХОЧЕШЬ */
   TimeToStruct(TimeCurrent(),STimeCurrent); //  конвертация текущего времени, и результат вносится в STimeCurrent,
//---                                          
   MqlRates rates[];                                    //присваивание название массиву 
   ArraySetAsSeries(rates,true);
   if(CopyRates(m_symbol.Name(),Period(),0,3,rates)!=3)  //  4. если CopyRates не равен 3 то возврат. почему 3? 
      return;           //потому что в массиве 3 элемента. плохо понимаю принцип. return? понимаю что это возврат, но прям 
                                         //точного понятие нет,  что, куда возвращает? 
   if(CopyBuffer(ATRy,0,0,3,ATRm)!=3) // 5. если меньше 3, почему не меньше 0?
      return;

   double cl   = rates[1].close;
   double op   = rates[1].open;
   double high = rates[0].high;
   double low  = rates[0].low;

   double ATR  = ATRm[1];        // значение дневного АТР вчерашнего дня
   double TP   = ATR/100*TPpr;   //
   double SL   = ATR/100*SLpr;   // значение от атр 50% 
   double DD   = ATR/100*DDpr;   //

   int count=0;
   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()) //если символ позиции равен имени инструмента 
           {
            count++;                                           //то+1, значит есть открытая позиция
            double PR=m_position.PriceOpen();                  //PR правниваем цену открытия
            if(m_position.PositionType()==POSITION_TYPE_BUY)    // если позиция  бай
              {
                  // а тут чего? у меня тут было закрытие позы по рынку при достижении цены TP, SL. мне для примера?
              }
            else
              {
                       
              }
           }
//---
   if(count==0) //если нет открытой позиции
     {
      if(STimeCurrent.hour==10 && STimeCurrent.min==01) //если время равно 10:01:00 
        {
         if(!RefreshRates()) // получаем текущие цены ЕСЛИ ПОЛУЧИЛИ ТЕКУЩИЕ ЦЕНЫ. КСТАТИ ЗАЧЕМ ЭТА ПРОВЕРКА?
            return;
         //--- ПОКУПКИ      
         if(cl>op) //если открыти 1ой свечи > закрытия 1ой свечи
           {
            double SL_BUY=m_symbol.Ask()-SL; // цена для стопа лонга. ПОЧЕМУ ОТ АСК, А НЕ ОТ ЦЕНЫ ОТКРЫТИЯ ПОЗИЦИИ?
            double TP_BUY=m_symbol.Ask()+TP; // цена для тейка лонга. НАПРИМЕР TP_BUY=m_position.PriceOpen()+TP 
            m_trade.Buy(Lots,m_symbol.Name(),m_symbol.Ask(),
                        m_symbol.NormalizePrice(SL_BUY),
                        m_symbol.NormalizePrice(TP_BUY));     // то вход в лонг                                             
           }
         //--- ПРОДАЖИ
         else if(cl<op) //если закрытие 1ой свечи < открытия 1ой свечи
           {
            double SL_SELL=m_symbol.Bid()+SL; // цена для стопа шорта
            double TP_SELL=m_symbol.Bid()-TP; // цена для тейка шорта
            m_trade.Sell(Lots,m_symbol.Name(),m_symbol.Bid(),
                         m_symbol.NormalizePrice(SL_SELL),                    //ТОЛЬКО НЕ ПОНЯЛА КАК ОН ЕЕ НОРМАЛИЗУЕТ
                         m_symbol.NormalizePrice(TP_SELL));     // то вход в шорт                                                
           }
        }
     }
  }
//+------------------------------------------------------------------+
//| Refreshes the symbol quotes data                                 |
//+------------------------------------------------------------------+
bool RefreshRates(void)
  {
//--- refresh rates
   if(!m_symbol.RefreshRates())          // если нет обновления котировок
     {
      Print("RefreshRates error");        // то выводим в журнал ошибку
      return(false);                      // и возвращаем ложь
     }
//--- protection against the return value of "zero"
   if(m_symbol.Ask()==0 || m_symbol.Bid()==0)      //НЕПОНЯТНО ЧТО ТУТ ДЕЛАЕТСЯ. если аск или бид равен 0     
      return(false);                                // то возвращаем ложь. если вернет ложь то сова перестанет работать?
//---
   return(true);
  }
//+------------------------------------------------------------------+
 
sofi563:

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

Начну с конца: если позиций нет, то и понятия «Цена позиции» не существует. Это надеюсь понятно?

А раз не позиции, то и «Цены позиции» тоже нет - значит для расчёта Стоп лосс и Тейк профит нужно получить текущие цены.
 
   if(!m_symbol.Name(Symbol())) // sets symbol name 1. не могу понять этой иницилизации. ЕСЛИ НЕТ СИМВОЛА ТО
      return(INIT_FAILED);      //ПРЕКРАЩАЕМ РАБОТУ. так что ли?

Не совсем так: если вдруг не прошла инициализация текущим символом - тогда выходим


ArraySetAsSeries(ATRm,true);  // МАССИВЫ ТОЖЕ НАДО ИНИЦИЛИЗИРОВАТЬ?

Это не инициализация, а установка флага AS_SERIES динамическому массиву, индексация элементов массива будет производиться как в таймсериях - в общем после этого в массиве элемент с индексом [0] будет соответствовать самому правому бару на графике.


   int count=0;
   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()) //если символ позиции равен имени инструмента 
           {
            count++;                                           //то+1, значит есть открытая позиция
            double PR=m_position.PriceOpen();                  //PR правниваем цену открытия
            if(m_position.PositionType()==POSITION_TYPE_BUY)    // если позиция  бай
              {
                  // а тут чего? у меня тут было закрытие позы по рынку при достижении цены TP, SL. мне для примера?
              }
            else
              {
                       
              }
           }

Это заготовка для правильного обхода списка позиций (ДАЖЕ ЕСЛИ ЕСТЬ ВСЕГО ОДНО ПОЗИЦИЯ) и модификации


         if(!RefreshRates()) // получаем текущие цены ЕСЛИ ПОЛУЧИЛИ ТЕКУЩИЕ ЦЕНЫ. КСТАТИ ЗАЧЕМ ЭТА ПРОВЕРКА?
            return;
         //--- ПОКУПКИ      
         if(cl>op) //если открыти 1ой свечи > закрытия 1ой свечи
           {
            double SL_BUY=m_symbol.Ask()-SL; // цена для стопа лонга. ПОЧЕМУ ОТ АСК, А НЕ ОТ ЦЕНЫ ОТКРЫТИЯ ПОЗИЦИИ?
            double TP_BUY=m_symbol.Ask()+TP; // цена для тейка лонга. НАПРИМЕР TP_BUY=m_position.PriceOpen()+TP 
            m_trade.Buy(Lots,m_symbol.Name(),m_symbol.Ask(),
                        m_symbol.NormalizePrice(SL_BUY),
                        m_symbol.NormalizePrice(TP_BUY));     // то вход в лонг                                             
           }
         //--- ПРОДАЖИ
         else if(cl<op) //если закрытие 1ой свечи < открытия 1ой свечи
           {
            double SL_SELL=m_symbol.Bid()+SL; // цена для стопа шорта
            double TP_SELL=m_symbol.Bid()-TP; // цена для тейка шорта
            m_trade.Sell(Lots,m_symbol.Name(),m_symbol.Bid(),
                         m_symbol.NormalizePrice(SL_SELL),                    //ТОЛЬКО НЕ ПОНЯЛА КАК ОН ЕЕ НОРМАЛИЗУЕТ
                         m_symbol.NormalizePrice(TP_SELL));     // то вход в шорт                                                
           }

"ЕСЛИ ПОЛУЧИЛИ ТЕКУЩИЕ ЦЕНЫ. КСТАТИ ЗАЧЕМ ЭТА ПРОВЕРКА?" - это проверка того, что: удалось ли обновить текущие цены. Если не удалось - то в цикл открытия позиции не входим

 
Vladimir Karputov:

Не совсем так: если вдруг не прошла инициализация текущим символом - тогда выходим


Это не инициализация, а установка флага AS_SERIES динамическому массиву, индексация элементов массива будет производиться как в таймсериях - в общем после этого в массиве элемент с индексом [0] будет соответствовать самому правому бару на графике.


Это заготовка для правильного обхода списка позиций (ДАЖЕ ЕСЛИ ЕСТЬ ВСЕГО ОДНО ПОЗИЦИЯ) и модификации


"ЕСЛИ ПОЛУЧИЛИ ТЕКУЩИЕ ЦЕНЫ. КСТАТИ ЗАЧЕМ ЭТА ПРОВЕРКА?" - это проверка того, что: удалось ли обновить текущие цены. Если не удалось - то в цикл открытия позиции не вхоспасибо

спасибо, много понятно стало. 

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

input double   Lots  = 1.0;
input int      TPpr  = 50;
input int      SLpr  = 16;
input int      DDpr=40;    
Файлы:
 
sofi563:

спасибо, много понятно стало. 

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

Если Вы просто изменили входные параметры (input) во файле mq5 и скомпилировала его - эти новые параметры НЕ ИЗМЕНЯТСЯ В ТЕСТЕРЕ. Хотите изменений - в тестере правый клик и параметры по умолчанию

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