Domande dai principianti MQL5 MT5 MetaTrader 5 - pagina 728

 

Salve. Scrivevo un Expert Advisor in MetaTraider 4. O meglio, stavo cercando di imparare a scriverlo. Non so molte cose. Ho deciso di portarlo su MetaTraider 5, che si è rivelato un po' diverso. In generale, ho preso un altro Expert Advisor. L'ho smontato. Ho copiato il codice per aprire le scommesse. Non ho errori, ma non funziona come dovrebbe. Aiutami a spostarlo correttamente.

MetaTraider 4:

int  err = 0;            
double Lot = 0.01;       // Лот
double CoofLot = 0;
double Ballance = AccountBalance();
double loss = 100;    
bool nap = true;       //true  - 1
                       //false - 0
int start()
  {  
    if(OrdersTotal()==0)                                
    {
       if(Ballance != AccountBalance())                
       {
        if(AccountBalance() < Ballance )                
        {
            CoofLot++;
            Lot = pow(2, CoofLot) * 0.01;
            if(nap == true)                            
               {
                nap = false;
               }
             else
               {
                nap = true;
               }
         }
         if(AccountBalance() > Ballance)                
           {
             Lot = 0.01;
             CoofLot = 0;
           }
       }
    Ballance = AccountBalance();
    
    int order;
    if(nap == true)                                      
      {
       order = OrderSend(Symbol(),OP_BUY,Lot,Ask,1*Point,Ask-loss*Point,Ask+loss*Point);   // Вверх
      }                  
    else
      {
       order = OrderSend(Symbol(),OP_SELL,Lot,Bid,1*Point,Bid+loss*Point,Bid-loss*Point);    // Вниз
      }
  
       if(order<0)                                
         {
           if (GetLastError()==134)
             {
               err=1;
               Print("NOT ENOGUGHT MONEY!!");
             }
           return (-1);
         }
       }
   return(0);
  }


Ed è così che si è trasferito a MetaTraider 5:

double Lot = 0.01;      
double CoofLot = 0;

double Ballance = ACCOUNT_BALANCE;
double loss = 100;    
bool nap = true;       //true  - 1
                       //false - 0



void OnTick()
{
   MqlTick latest_price;       // Будет использоваться для текущих котировок
   MqlTradeRequest mrequest;   // Будет использоваться для отсылки торговых запросов
   MqlTradeResult mresult;  
   if(OrdersTotal()==0)                                
      {
      if(!SymbolInfoTick(_Symbol,latest_price))
         {
            Alert("Ошибка получения последних котировок - ошибка:",GetLastError(),"!!");
            return;
         }
        
      if(Ballance != ACCOUNT_BALANCE)                
       {
        if(ACCOUNT_BALANCE < Ballance )                
        {
            CoofLot++;
            Lot = pow(2, CoofLot) * 0.01;
            if(nap == true)                            
               {
                nap = false;
               }
             else
               {
                nap = true;
               }
         }
         if(ACCOUNT_BALANCE > Ballance)                
           {
             Lot = 0.01;
             CoofLot = 0;
           }
       }
    Ballance = ACCOUNT_BALANCE;
    int order;
    if(nap == true)                                      
      {
         mrequest.action = TRADE_ACTION_DEAL;                                  // немедленное исполнение
         mrequest.price = NormalizeDouble(latest_price.ask,_Digits);           // последняя цена ask
         mrequest.sl = NormalizeDouble(latest_price.ask - 100*_Point,_Digits); // Stop Loss
         mrequest.tp = NormalizeDouble(latest_price.ask + 100*_Point,_Digits); // Take Profit
         mrequest.symbol = _Symbol;                                            // символ
         mrequest.volume = Lot;                                                // количество лотов для торговли
         mrequest.type = ORDER_TYPE_BUY;                                       // ордер на покупку
         mrequest.type_filling = ORDER_FILLING_FOK;                            // тип исполнения ордера - все или ничего
         mrequest.deviation=100;                                               // проскальзывание от текущей цены
         //--- отсылаем ордер

         order = OrderSend(mrequest,mresult);
      }                  
    else
      {
         mrequest.action = TRADE_ACTION_DEAL;                                  // немедленное исполнение
         mrequest.price = NormalizeDouble(latest_price.bid,_Digits);           // последняя цена Bid
         mrequest.sl = NormalizeDouble(latest_price.bid + 100*_Point,_Digits); // Stop Loss
         mrequest.tp = NormalizeDouble(latest_price.bid - 100*_Point,_Digits); // Take Profit
         mrequest.symbol = _Symbol;                                            // символ
         mrequest.volume = Lot;                                                // количество лотов для торговли
         mrequest.type= ORDER_TYPE_SELL;                                       // ордер на продажу
         mrequest.type_filling = ORDER_FILLING_FOK;                            // тип исполнения ордера - все или ничего
         mrequest.deviation=100;                                               // проскальзывание от текущей цены
         //--- отсылаем ордер

         order = OrderSend(mrequest,mresult);  
      }
      }
   return;
  }
 
DenZell:

Salve. Scrivevo un Expert Advisor in MetaTraider 4. O meglio, stavo cercando di imparare a scriverlo. Non so molte cose. Ho deciso di trasferirlo su MetaTraider 5, che si è rivelato un po' diverso. In generale, ho preso un altro Expert Advisor. L'ho smontato. Ho copiato il codice per aprire le scommesse. Non ho errori, ma non funziona come dovrebbe. Aiutami a trasferire il diritto.


Il codice sarà come questo (ma fate attenzione - c'è un controllo per il numero totale di posizioni sul conto di trading(PositionsTotal):

   if(PositionsTotal()==0)

cioè, non c'è nessun controllo di quante posizioni esattamente per un dato simbolo e un dato Magic (a proposito, Magic non è impostato affatto))

//+------------------------------------------------------------------+
//|                                                       TestEA.mq5 |
//|                              Copyright © 2016, Vladimir Karputov |
//|                                           http://wmua.ru/slesar/ |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2016, Vladimir Karputov"
#property link      "http://wmua.ru/slesar/"
#property version   "1.00"
//---
double         Lot            = 0.01;
double         CoofLot        = 1.0;
double         loss           = 100.0;
bool           nap            = true;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   CoofLot  = 1.0;
   loss     = 100.0;
   nap      = true;
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
   static double         Balance=0.0;
   if(Balance==0.0)
      Balance=AccountInfoDouble(ACCOUNT_BALANCE);

   if(PositionsTotal()==0)
     {
      MqlTick latest_price;                        // Будет использоваться для текущих котировок
      if(!SymbolInfoTick(_Symbol,latest_price))
        {
         Alert("Ошибка получения последних котировок - ошибка:",GetLastError(),"!!");
         return;
        }

      if(Balance!=AccountInfoDouble(ACCOUNT_BALANCE))
        {
         if(AccountInfoDouble(ACCOUNT_BALANCE)<Balance)
           {
            CoofLot++;
            Lot=pow(2,CoofLot)*0.01;
            if(nap==true)
              {
               nap=false;
              }
            else
              {
               nap=true;
              }
           }
         if(AccountInfoDouble(ACCOUNT_BALANCE)>Balance)
           {
            Lot=0.01;
            CoofLot=1.0;
           }
        }
      Balance=AccountInfoDouble(ACCOUNT_BALANCE);

      MqlTradeRequest mrequest;   // Будет использоваться для отсылки торговых запросов
      MqlTradeResult mresult;
      ZeroMemory(mrequest);
      ZeroMemory(mresult);

      bool order=false;
      if(nap==true)
        {
         mrequest.action = TRADE_ACTION_DEAL;                                  // немедленное исполнение
         mrequest.price = NormalizeDouble(latest_price.ask,_Digits);           // последняя цена ask
         mrequest.sl = NormalizeDouble(latest_price.bid - 100*_Point,_Digits); // Stop Loss
         mrequest.tp = NormalizeDouble(latest_price.bid + 100*_Point,_Digits); // Take Profit
         mrequest.symbol = _Symbol;                                            // символ
         mrequest.volume = Lot;                                                // количество лотов для торговли
         mrequest.type = ORDER_TYPE_BUY;                                       // ордер на покупку
         mrequest.type_filling = ORDER_FILLING_FOK;                            // тип исполнения ордера - все или ничего
         mrequest.deviation=100;                                               // проскальзывание от текущей цены
         //--- отсылаем ордер

         order=OrderSend(mrequest,mresult);
        }
      else
        {
         mrequest.action = TRADE_ACTION_DEAL;                                  // немедленное исполнение
         mrequest.price = NormalizeDouble(latest_price.bid,_Digits);           // последняя цена Bid
         mrequest.sl = NormalizeDouble(latest_price.ask + 100*_Point,_Digits); // Stop Loss
         mrequest.tp = NormalizeDouble(latest_price.ask - 100*_Point,_Digits); // Take Profit
         mrequest.symbol = _Symbol;                                            // символ
         mrequest.volume = Lot;                                                // количество лотов для торговли
         mrequest.type= ORDER_TYPE_SELL;                                       // ордер на продажу
         mrequest.type_filling = ORDER_FILLING_FOK;                            // тип исполнения ордера - все или ничего
         mrequest.deviation=100;                                               // проскальзывание от текущей цены
         //--- отсылаем ордер

         order=OrderSend(mrequest,mresult);
        }
     }
   return;
  }
//+------------------------------------------------------------------+

Anche il risultato dell'operazioneOrderSend è ditipo bool.

Ho usato una variabile statica per memorizzare l'equilibrio

   static double         Balance=0.0;
   if(Balance==0.0)
      Balance=AccountInfoDouble(ACCOUNT_BALANCE);

- Significa che la variabile "Balance" non sarà ricreata durante gli arrivi successivi di OnTick(), ma ricorderà il suo valore dal tick precedente.

File:
TestEA.mq5  10 kb
 

Anche se io lo scriverei così:

//+------------------------------------------------------------------+
//|                                                       TestEA.mq5 |
//|                              Copyright © 2017, Vladimir Karputov |
//|                                           http://wmua.ru/slesar/ |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2017, Vladimir Karputov"
#property link      "http://wmua.ru/slesar/"
#property version   "1.001"
#include <Trade\PositionInfo.mqh>
#include <Trade\Trade.mqh>
#include <Trade\SymbolInfo.mqh>  
#include <Trade\AccountInfo.mqh>
CPositionInfo  m_position;                   // trade position object
CTrade         m_trade;                      // trading object
CSymbolInfo    m_symbol;                     // symbol info object
CAccountInfo   m_account;                    // account info wrapper
//---
double         Lot            = 0.01;
double         CoofLot        = 1.0;
double         Loss           = 100.0;
bool           nap            = true;
//---
ulong          m_magic        = 15489;       // magic number
ulong          m_slippage     = 10;          // slippage
double         m_adjusted_point;             // point value adjusted for 3 or 5 points
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   m_symbol.Name(Symbol());                  // sets symbol name
   if(!RefreshRates())
     {
      Print("Error RefreshRates. Bid=",DoubleToString(m_symbol.Bid(),Digits()),
            ", Ask=",DoubleToString(m_symbol.Ask(),Digits()));
      return(INIT_FAILED);
     }
   m_symbol.Refresh();
//---
   m_trade.SetExpertMagicNumber(m_magic);
//---
   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;
//---
   CoofLot  = 1.0;
   Loss     = 100.0;
   nap      = true;
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
   static double         static_Balance=0.0;
   if(static_Balance==0.0)
      static_Balance=m_account.Balance();

   double balance=m_account.Balance();             // локальная переменная для хранения баланса на время OnTick

//--- считаем позиции по символу и по Magic
   int total=0;
   for(int i=PositionsTotal()-1;i>=0;i--) // returns the number of open 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)
            total++;

   if(total==0)
     {
      //--- попытка обновить цены
      if(!RefreshRates())
         return;                          // есил не удалось обновить цены - просто выходим

      if(static_Balance!=balance)
        {
         if(balance<static_Balance)
           {
            CoofLot++;
            double lots=pow(2,CoofLot)*0.01;       // локальная переменная для временных расчётов лота
            //--- проверка корректности лота
            Lot=LotCheck(lots);
            if(Lot==0.0)
               return;
            if(nap)
               nap=false;
            else
               nap=true;
           }
         if(balance>static_Balance)
           {
            Lot=0.01;
            CoofLot=1.0;
           }
        }
      static_Balance=balance;

      if(nap==true)
        {
         double sl=m_symbol.NormalizePrice(m_symbol.Bid() - Loss*m_adjusted_point); // Stop Loss
         double tp=m_symbol.NormalizePrice(m_symbol.Bid() + Loss*m_adjusted_point); // Take Profit

         if(m_trade.Buy(Lot,NULL,m_symbol.Ask(),sl,tp))
           {
            if(m_trade.ResultDeal()==0)
               Print("Buy -> false. Result Retcode: ",m_trade.ResultRetcode(),
                     ", description of result: ",m_trade.ResultRetcodeDescription());
            else
               Print("Buy -> true. Result Retcode: ",m_trade.ResultRetcode(),
                     ", description of result: ",m_trade.ResultRetcodeDescription());
           }
         else
            Print("Buy -> false. Result Retcode: ",m_trade.ResultRetcode(),
                  ", description of result: ",m_trade.ResultRetcodeDescription());
        }
      else
        {
         double sl=m_symbol.NormalizePrice(m_symbol.Ask()+Loss*m_adjusted_point); // Stop Loss
         double tp=m_symbol.NormalizePrice(m_symbol.Ask()-Loss*m_adjusted_point); // Take Profit

         if(m_trade.Sell(Lot,NULL,m_symbol.Ask(),sl,tp))
           {
            if(m_trade.ResultDeal()==0)
               Print("Sell -> false. Result Retcode: ",m_trade.ResultRetcode(),
                     ", description of result: ",m_trade.ResultRetcodeDescription());
            else
               Print("Sell -> true. Result Retcode: ",m_trade.ResultRetcode(),
                     ", description of result: ",m_trade.ResultRetcodeDescription());
           }
         else
            Print("Sell -> false. Result Retcode: ",m_trade.ResultRetcode(),
                  ", description of result: ",m_trade.ResultRetcodeDescription());
        }
     }
   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);
  }
//+------------------------------------------------------------------+
//| Lot Check                                                        |
//+------------------------------------------------------------------+
double LotCheck(double lots)
  {
//--- calculate maximum volume
   double volume=NormalizeDouble(lots,2);
   double stepvol=m_symbol.LotsStep();
   if(stepvol>0.0)
      volume=stepvol*MathFloor(volume/stepvol);
//---
   double minvol=m_symbol.LotsMin();
   if(volume<minvol)
      volume=0.0;
//---
   double maxvol=m_symbol.LotsMax();
   if(volume>maxvol)
      volume=maxvol;
   return(volume);
  }
//+------------------------------------------------------------------+

Qui:

  1. Lo stop loss è impostato in pip "quadrupli" - cioè funzionerà correttamente sia su EURUSD che USDJPY
  2. l'oggetto "m_symbol" della classe commercialeCSymbolInfo è usato per ottenere i prezzi
  3. controlliamo la quantità totale di posizioni per il dato simbolo e il dato Magic
  4. se il lotto viene cambiato, viene controllato e corretto in "LotCheck" prima
  5. le operazioni commerciali sono eseguite utilizzando i metodi dell'oggetto "m_trade" della classe commercialeCTrade
  6. viene controllato il risultato di un'operazione commerciale (due passi - controllo di base e risultato del piazzamento)

Aggiunto:

Ho ottenuto un risultato molto interessante di una singola corsa nel tester di strategia:

Tester


File:
TestEA.mq5  14 kb
 
Vladimir Karputov:

Anche se io lo scriverei così:

A questo punto, non raccomanderei di usare m_symbol.RefreshRates() perché SymbolInfoTick() potrebbe non restituire dati freschi. E, se gli sviluppatori stanno leggendo questo thread, per favore richiamate ancora una volta la loro attenzione sul fatto che SymbolInfoTick() fa schifo, ma è ancora usato nelle classi SB!
 
Ciao, ho deciso di fare un Expert Advisor multivaluta usando la strategia Green-Red Candle in MQL5 per l'autoapprendimento.
La funzionalità di base è implementata, ma continuano ad apparire errori come "Invalid price". Ho aggiunto alcuni controlli aggiuntivi per eliminare le loro possibili cause e li ho impostati su valori certamente corretti, ma gli errori non sono scomparsi. Io stesso non so da che parte andare. Potreste dirmi dove ho sbagliato? Sto allegando il codice sorgente.
File:
 
NickWelder:
Ciao, ho deciso di fare un Expert Advisor multi-valuta basato sulla strategia Green-Red Candle in MQL5 per il mio auto-studio.
Ho implementato la funzionalità di base ma continuo a ricevere errori come "Invalid price". Ho aggiunto ulteriori controlli per eliminare le loro possibili cause e, rispettivamente, li ho impostati su valori noti e corretti, ma gli errori non sono scomparsi. Io stesso non so da che parte andare. Potreste dirmi dove ho sbagliato? Sto allegando il codice sorgente.

È necessario aggiornare i prezzi nell'oggetto CSymbolInfo della classe di commercio prima di fare un'operazione di commercio. Nei miei progetti mono (che hanno solo un simbolo) uso questa funzione:

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

e l'utilizzo - se non si riesce ad aggiornare i prezzi, allora si esce e basta, se si riesce ad aggiornare i prezzi, allora ci sarà un'operazione commerciale:

//--- refresh rates
   if(!m_symbol.RefreshRates())
      return;

   if(m_trade.Buy(lots,NULL,m_symbol.Ask(),sl,tp))
     {
      if(m_trade.ResultDeal()==0)
         Print("Buy -> false. Result Retcode: ",m_trade.ResultRetcode(),
               ", description of result: ",m_trade.ResultRetcodeDescription());
      else
         Print("Buy -> true. Result Retcode: ",m_trade.ResultRetcode(),
               ", description of result: ",m_trade.ResultRetcodeDescription());
     }
   else
      Print("Buy -> false. Result Retcode: ",m_trade.ResultRetcode(),
            ", description of result: ",m_trade.ResultRetcodeDescription(
 
@Vladimir Karputov, Grazie! Tutto ha funzionato con gli ordini di mercato.
 

Qual è una soluzione bella e "facile" per sostituire questo design?

if(iBarShift(_Symbol, _Period, TimeLast)==3) {...}

Ora è così, ma è troppo "pesante" per i miei gusti:

int iBarShift(string symbol,ENUM_TIMEFRAMES tf,datetime time,bool exact=false) {
  if(time<0) return(-1);
   datetime Arr[],time1;
   CopyTime(symbol,tf,0,1,Arr);
   time1=Arr[0];
   if(CopyTime(symbol,tf,time,time1,Arr)>0) {
      if(ArraySize(Arr)>2) return(ArraySize(Arr)-1);
      if(time<time1) return(1);
      else return(0);
     }
   else return(-1);
}
 
Vitaly Muzichenko:

Qual è una soluzione bella e "facile" per sostituire questo design?

if(iBarShift(_Symbol, _Period, TimeLast)==3) {...}

Ora è così, ma è troppo "pesante" per i miei gusti:

int iBarShift(string symbol,ENUM_TIMEFRAMES tf,datetime time,bool exact=false) {
  if(time<0) return(-1);
   datetime Arr[],time1;
   CopyTime(symbol,tf,0,1,Arr);
   time1=Arr[0];
   if(CopyTime(symbol,tf,time,time1,Arr)>0) {
      if(ArraySize(Arr)>2) return(ArraySize(Arr)-1);
      if(time<time1) return(1);
      else return(0);
     }
   else return(-1);
}
Come questo (soluzione di @fxsaber):

//+------------------------------------------------------------------+
//| Возвращает смещение бара по времени                              |
//+------------------------------------------------------------------+
int GetBarShift(const string symbol_name, const ENUM_TIMEFRAMES timeframe, const datetime time) {
   int res=-1;
   datetime last_bar;
   if(SeriesInfoInteger(symbol_name,timeframe,SERIES_LASTBAR_DATE,last_bar)) {
      if(time>last_bar) res=0;
      else {
         const int shift=Bars(symbol_name,timeframe,time,last_bar);
         if(shift>0) res=shift-1;
         }
      }
   return(res);
}
//+------------------------------------------------------------------+
Qualcuno ha scritto da qualche parte che in una linea selezionata si dovrebbe fare così: if (time>=last_bar) res=0;

Non l'ho controllato, ad essere onesti - non lo ricevo sempre. Controlla, scrivi il risultato per favore.
 
Vitaly Muzichenko:

Qual è una soluzione bella e "facile" per sostituire questo design?

if(iBarShift(_Symbol, _Period, TimeLast)==3) {...}

Ora è così, ma è troppo "pesante" per i miei gusti:

int iBarShift(string symbol,ENUM_TIMEFRAMES tf,datetime time,bool exact=false) {
  if(time<0) return(-1);
   datetime Arr[],time1;
   CopyTime(symbol,tf,0,1,Arr);
   time1=Arr[0];
   if(CopyTime(symbol,tf,time,time1,Arr)>0) {
      if(ArraySize(Arr)>2) return(ArraySize(Arr)-1);
      if(time<time1) return(1);
      else return(0);
     }
   else return(-1);
}
Non so quanto sia più "leggera" la mia soluzione, ma provate questa: https://www.mql5.com/ru/forum/160945#comment_4053382
Как получить номер бара по времени входа в позицию?
Как получить номер бара по времени входа в позицию?
  • www.mql5.com
Приветствую! Пишу трейлинг, который проходится по барам начиная от времени входа в позицию...
Motivazione: